From fc84956ac8b7cd244ef30e7a4d4d38a58dec5904 Mon Sep 17 00:00:00 2001 From: dim Date: Thu, 16 Sep 2010 21:14:28 +0000 Subject: Make vendor/clang/dist exactly the same as upstream's r108428. Some files and directories were already added/removed in the upstream repository, but were not added/removed here, when the previous snapshot was imported. Note: I did not import the file test/Lexer/conflict-marker.c, because it contains merge conflict markers on purpose, which upsets our pre-commit hooks. Approved by: rpaulo (mentor) --- lib/Headers/arm_neon.h | 537 ------------------------------------------------ lib/Headers/arm_neon.td | 341 ------------------------------ 2 files changed, 878 deletions(-) delete mode 100644 lib/Headers/arm_neon.h delete mode 100644 lib/Headers/arm_neon.td (limited to 'lib') diff --git a/lib/Headers/arm_neon.h b/lib/Headers/arm_neon.h deleted file mode 100644 index 4508a27..0000000 --- a/lib/Headers/arm_neon.h +++ /dev/null @@ -1,537 +0,0 @@ -/*===---- arm_neon.h - NEON intrinsics --------------------------------------=== - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - *===-----------------------------------------------------------------------=== - */ - -#ifndef __ARM_NEON_H -#define __ARM_NEON_H - -#ifndef __ARM_NEON__ -#error "NEON support not enabled" -#endif - -// NEON document appears to be specified in terms of stdint types. -#include - -// Define some NEON-specific scalar types for floats and polynomials. -typedef float float32_t; -typedef uint8_t poly8_t; - -// FIXME: probably need a 'poly' attribute or something for correct codegen to -// disambiguate from uint16_t. -typedef uint16_t poly16_t; - -typedef __attribute__(( __vector_size__(8) )) int8_t __neon_int8x8_t; -typedef __attribute__(( __vector_size__(16) )) int8_t __neon_int8x16_t; -typedef __attribute__(( __vector_size__(8) )) int16_t __neon_int16x4_t; -typedef __attribute__(( __vector_size__(16) )) int16_t __neon_int16x8_t; -typedef __attribute__(( __vector_size__(8) )) int32_t __neon_int32x2_t; -typedef __attribute__(( __vector_size__(16) )) int32_t __neon_int32x4_t; -typedef __attribute__(( __vector_size__(8) )) int64_t __neon_int64x1_t; -typedef __attribute__(( __vector_size__(16) )) int64_t __neon_int64x2_t; -typedef __attribute__(( __vector_size__(8) )) uint8_t __neon_uint8x8_t; -typedef __attribute__(( __vector_size__(16) )) uint8_t __neon_uint8x16_t; -typedef __attribute__(( __vector_size__(8) )) uint16_t __neon_uint16x4_t; -typedef __attribute__(( __vector_size__(16) )) uint16_t __neon_uint16x8_t; -typedef __attribute__(( __vector_size__(8) )) uint32_t __neon_uint32x2_t; -typedef __attribute__(( __vector_size__(16) )) uint32_t __neon_uint32x4_t; -typedef __attribute__(( __vector_size__(8) )) uint64_t __neon_uint64x1_t; -typedef __attribute__(( __vector_size__(16) )) uint64_t __neon_uint64x2_t; -typedef __attribute__(( __vector_size__(8) )) uint16_t __neon_float16x4_t; -typedef __attribute__(( __vector_size__(16) )) uint16_t __neon_float16x8_t; -typedef __attribute__(( __vector_size__(8) )) float32_t __neon_float32x2_t; -typedef __attribute__(( __vector_size__(16) )) float32_t __neon_float32x4_t; -typedef __attribute__(( __vector_size__(8) )) poly8_t __neon_poly8x8_t; -typedef __attribute__(( __vector_size__(16) )) poly8_t __neon_poly8x16_t; -typedef __attribute__(( __vector_size__(8) )) poly16_t __neon_poly16x4_t; -typedef __attribute__(( __vector_size__(16) )) poly16_t __neon_poly16x8_t; - -typedef struct __int8x8_t { - __neon_int8x8_t val; -} int8x8_t; - -typedef struct __int8x16_t { - __neon_int8x16_t val; -} int8x16_t; - -typedef struct __int16x4_t { - __neon_int16x4_t val; -} int16x4_t; - -typedef struct __int16x8_t { - __neon_int16x8_t val; -} int16x8_t; - -typedef struct __int32x2_t { - __neon_int32x2_t val; -} int32x2_t; - -typedef struct __int32x4_t { - __neon_int32x4_t val; -} int32x4_t; - -typedef struct __int64x1_t { - __neon_int64x1_t val; -} int64x1_t; - -typedef struct __int64x2_t { - __neon_int64x2_t val; -} int64x2_t; - -typedef struct __uint8x8_t { - __neon_uint8x8_t val; -} uint8x8_t; - -typedef struct __uint8x16_t { - __neon_uint8x16_t val; -} uint8x16_t; - -typedef struct __uint16x4_t { - __neon_uint16x4_t val; -} uint16x4_t; - -typedef struct __uint16x8_t { - __neon_uint16x8_t val; -} uint16x8_t; - -typedef struct __uint32x2_t { - __neon_uint32x2_t val; -} uint32x2_t; - -typedef struct __uint32x4_t { - __neon_uint32x4_t val; -} uint32x4_t; - -typedef struct __uint64x1_t { - __neon_uint64x1_t val; -} uint64x1_t; - -typedef struct __uint64x2_t { - __neon_uint64x2_t val; -} uint64x2_t; - -typedef struct __float16x4_t { - __neon_float16x4_t val; -} float16x4_t; - -typedef struct __float16x8_t { - __neon_float16x8_t val; -} float16x8_t; - -typedef struct __float32x2_t { - __neon_float32x2_t val; -} float32x2_t; - -typedef struct __float32x4_t { - __neon_float32x4_t val; -} float32x4_t; - -typedef struct __poly8x8_t { - __neon_poly8x8_t val; -} poly8x8_t; - -typedef struct __poly8x16_t { - __neon_poly8x16_t val; -} poly8x16_t; - -typedef struct __poly16x4_t { - __neon_poly16x4_t val; -} poly16x4_t; - -typedef struct __poly16x8_t { - __neon_poly16x8_t val; -} poly16x8_t; - -// FIXME: write tool to stamp out the structure-of-array types, possibly gen this whole file. - -// Intrinsics, per ARM document DUI0348B -#define __ai static __attribute__((__always_inline__)) - -#define INTTYPES_WIDE(op, builtin) \ - __ai int16x8_t op##_s8(int16x8_t a, int8x8_t b) { return (int16x8_t){ builtin(a.val, b.val) }; } \ - __ai int32x4_t op##_s16(int32x4_t a, int16x4_t b) { return (int32x4_t){ builtin(a.val, b.val) }; } \ - __ai int64x2_t op##_s32(int64x2_t a, int32x2_t b) { return (int64x2_t){ builtin(a.val, b.val) }; } \ - __ai uint16x8_t op##_u8(uint16x8_t a, uint8x8_t b) { return (uint16x8_t){ builtin(a.val, b.val) }; } \ - __ai uint32x4_t op##_u16(uint32x4_t a, uint16x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; } \ - __ai uint64x2_t op##_u32(uint64x2_t a, uint32x2_t b) { return (uint64x2_t){ builtin(a.val, b.val) }; } - -#define INTTYPES_WIDENING(op, builtin) \ - __ai int16x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int16x8_t){ builtin(a.val, b.val) }; } \ - __ai int32x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int32x4_t){ builtin(a.val, b.val) }; } \ - __ai int64x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int64x2_t){ builtin(a.val, b.val) }; } \ - __ai uint16x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint16x8_t){ builtin(a.val, b.val) }; } \ - __ai uint32x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; } \ - __ai uint64x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint64x2_t){ builtin(a.val, b.val) }; } - -#define INTTYPES_WIDENING_MUL(op, builtin) \ - __ai int16x8_t op##_s8(int16x8_t a, int8x8_t b, int8x8_t c) { return (int16x8_t){ builtin(a.val, b.val, c.val) }; } \ - __ai int32x4_t op##_s16(int32x4_t a, int16x4_t b, int16x4_t c) { return (int32x4_t){ builtin(a.val, b.val, c.val) }; } \ - __ai int64x2_t op##_s32(int64x2_t a, int32x2_t b, int32x2_t c) { return (int64x2_t){ builtin(a.val, b.val, c.val) }; } \ - __ai uint16x8_t op##_u8(uint16x8_t a, uint8x8_t b, uint8x8_t c) { return (uint16x8_t){ builtin(a.val, b.val, c.val) }; } \ - __ai uint32x4_t op##_u16(uint32x4_t a, uint16x4_t b, uint16x4_t c) { return (uint32x4_t){ builtin(a.val, b.val, c.val) }; } \ - __ai uint64x2_t op##_u32(uint64x2_t a, uint32x2_t b, uint32x2_t c) { return (uint64x2_t){ builtin(a.val, b.val, c.val) }; } - -#define INTTYPES_NARROWING(op, builtin) \ - __ai int8x8_t op##_s16(int16x8_t a, int16x8_t b) { return (int8x8_t){ builtin(a.val, b.val) }; } \ - __ai int16x4_t op##_s32(int32x4_t a, int32x4_t b) { return (int16x4_t){ builtin(a.val, b.val) }; } \ - __ai int32x2_t op##_s64(int64x2_t a, int64x2_t b) { return (int32x2_t){ builtin(a.val, b.val) }; } \ - __ai uint8x8_t op##_u16(uint16x8_t a, uint16x8_t b) { return (uint8x8_t){ builtin(a.val, b.val) }; } \ - __ai uint16x4_t op##_u32(uint32x4_t a, uint32x4_t b) { return (uint16x4_t){ builtin(a.val, b.val) }; } \ - __ai uint32x2_t op##_u64(uint64x2_t a, uint64x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } - -#define INTTYPES_ADD_32(op, builtin) \ - __ai int8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){ builtin(a.val, b.val) }; } \ - __ai int16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){ builtin(a.val, b.val) }; } \ - __ai int32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){ builtin(a.val, b.val) }; } \ - __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){ builtin(a.val, b.val) }; } \ - __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){ builtin(a.val, b.val) }; } \ - __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } \ - __ai int8x16_t op##q_s8(int8x16_t a, int8x16_t b) { return (int8x16_t){ builtin(a.val, b.val) }; } \ - __ai int16x8_t op##q_s16(int16x8_t a, int16x8_t b) { return (int16x8_t){ builtin(a.val, b.val) }; } \ - __ai int32x4_t op##q_s32(int32x4_t a, int32x4_t b) { return (int32x4_t){ builtin(a.val, b.val) }; } \ - __ai uint8x16_t op##q_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){ builtin(a.val, b.val) }; } \ - __ai uint16x8_t op##q_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){ builtin(a.val, b.val) }; } \ - __ai uint32x4_t op##q_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; } - -#define INTTYPES_ADD_64(op, builtin) \ - __ai int64x1_t op##_s64(int64x1_t a, int64x1_t b) { return (int64x1_t){ builtin(a.val, b.val) }; } \ - __ai uint64x1_t op##_u64(uint64x1_t a, uint64x1_t b) { return (uint64x1_t){ builtin(a.val, b.val) }; } \ - __ai int64x2_t op##q_s64(int64x2_t a, int64x2_t b) { return (int64x2_t){ builtin(a.val, b.val) }; } \ - __ai uint64x2_t op##q_u64(uint64x2_t a, uint64x2_t b) { return (uint64x2_t){ builtin(a.val, b.val) }; } - -#define FLOATTYPES_CMP(op, builtin) \ - __ai uint32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } \ - __ai uint32x4_t op##q_f32(float32x4_t a, float32x4_t b) { return (uint32x4_t){ builtin(a.val, b.val) }; } - -#define INT_FLOAT_CMP_OP(op, cc) \ - __ai uint8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (uint8x8_t){(__neon_uint8x8_t)(a.val cc b.val)}; } \ - __ai uint16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (uint16x4_t){(__neon_uint16x4_t)(a.val cc b.val)}; } \ - __ai uint32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (uint32x2_t){(__neon_uint32x2_t)(a.val cc b.val)}; } \ - __ai uint32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (uint32x2_t){(__neon_uint32x2_t)(a.val cc b.val)}; } \ - __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){a.val cc b.val}; } \ - __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){a.val cc b.val}; } \ - __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){a.val cc b.val}; } \ - __ai uint8x16_t op##q_s8(int8x16_t a, int8x16_t b) { return (uint8x16_t){(__neon_uint8x16_t)(a.val cc b.val)}; } \ - __ai uint16x8_t op##q_s16(int16x8_t a, int16x8_t b) { return (uint16x8_t){(__neon_uint16x8_t)(a.val cc b.val)}; } \ - __ai uint32x4_t op##q_s32(int32x4_t a, int32x4_t b) { return (uint32x4_t){(__neon_uint32x4_t)(a.val cc b.val)}; } \ - __ai uint32x4_t op##q_f32(float32x4_t a, float32x4_t b) { return (uint32x4_t){(__neon_uint32x4_t)(a.val cc b.val)}; } \ - __ai uint8x16_t op##q_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){a.val cc b.val}; } \ - __ai uint16x8_t op##q_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){a.val cc b.val}; } \ - __ai uint32x4_t op##q_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){a.val cc b.val}; } - -#define INT_UNARY(op, builtin) \ - __ai int8x8_t op##_s8(int8x8_t a) { return (int8x8_t){ builtin(a.val) }; } \ - __ai int16x4_t op##_s16(int16x4_t a) { return (int16x4_t){ builtin(a.val) }; } \ - __ai int32x2_t op##_s32(int32x2_t a) { return (int32x2_t){ builtin(a.val) }; } \ - __ai int8x16_t op##q_s8(int8x16_t a) { return (int8x16_t){ builtin(a.val) }; } \ - __ai int16x8_t op##q_s16(int16x8_t a) { return (int16x8_t){ builtin(a.val) }; } \ - __ai int32x4_t op##q_s32(int32x4_t a) { return (int32x4_t){ builtin(a.val) }; } - -#define FP_UNARY(op, builtin) \ - __ai float32x2_t op##_f32(float32x2_t a) { return (float32x2_t){ builtin(a.val) }; } \ - __ai float32x4_t op##q_f32(float32x4_t a) { return (float32x4_t){ builtin(a.val) }; } - -#define FP_BINARY(op, builtin) \ - __ai float32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (float32x2_t){ builtin(a.val, b.val) }; } \ - __ai float32x4_t op##q_f32(float32x4_t a, float32x4_t b) { return (float32x4_t){ builtin(a.val, b.val) }; } - -#define INT_FP_PAIRWISE_ADD(op, builtin) \ - __ai int8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){ builtin(a.val, b.val) }; } \ - __ai int16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){ builtin(a.val, b.val) }; } \ - __ai int32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){ builtin(a.val, b.val) }; } \ - __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){ builtin(a.val, b.val) }; } \ - __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){ builtin(a.val, b.val) }; } \ - __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){ builtin(a.val, b.val) }; } \ - __ai float32x2_t op##_f32(float32x2_t a, float32x2_t b) { return (float32x2_t){ builtin(a.val, b.val) }; } - -#define INT_LOGICAL_OP(op, lop) \ - __ai int8x8_t op##_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){ a.val lop b.val }; } \ - __ai int16x4_t op##_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){ a.val lop b.val }; } \ - __ai int32x2_t op##_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){ a.val lop b.val }; } \ - __ai int64x1_t op##_s64(int64x1_t a, int64x1_t b) { return (int64x1_t){ a.val lop b.val }; } \ - __ai uint8x8_t op##_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){ a.val lop b.val }; } \ - __ai uint16x4_t op##_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){ a.val lop b.val }; } \ - __ai uint32x2_t op##_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){ a.val lop b.val }; } \ - __ai uint64x1_t op##_u64(uint64x1_t a, uint64x1_t b) { return (uint64x1_t){ a.val lop b.val }; } \ - __ai int8x16_t op##q_s8(int8x16_t a, int8x16_t b) { return (int8x16_t){ a.val lop b.val }; } \ - __ai int16x8_t op##q_s16(int16x8_t a, int16x8_t b) { return (int16x8_t){ a.val lop b.val }; } \ - __ai int32x4_t op##q_s32(int32x4_t a, int32x4_t b) { return (int32x4_t){ a.val lop b.val }; } \ - __ai int64x2_t op##q_s64(int64x2_t a, int64x2_t b) { return (int64x2_t){ a.val lop b.val }; } \ - __ai uint8x16_t op##q_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){ a.val lop b.val }; } \ - __ai uint16x8_t op##q_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){ a.val lop b.val }; } \ - __ai uint32x4_t op##q_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){ a.val lop b.val }; } \ - __ai uint64x2_t op##q_u64(uint64x2_t a, uint64x2_t b) { return (uint64x2_t){ a.val lop b.val }; } - -// vector add -__ai int8x8_t vadd_s8(int8x8_t a, int8x8_t b) { return (int8x8_t){a.val + b.val}; } -__ai int16x4_t vadd_s16(int16x4_t a, int16x4_t b) { return (int16x4_t){a.val + b.val}; } -__ai int32x2_t vadd_s32(int32x2_t a, int32x2_t b) { return (int32x2_t){a.val + b.val}; } -__ai int64x1_t vadd_s64(int64x1_t a, int64x1_t b) { return (int64x1_t){a.val + b.val}; } -__ai float32x2_t vadd_f32(float32x2_t a, float32x2_t b) { return (float32x2_t){a.val + b.val}; } -__ai uint8x8_t vadd_u8(uint8x8_t a, uint8x8_t b) { return (uint8x8_t){a.val + b.val}; } -__ai uint16x4_t vadd_u16(uint16x4_t a, uint16x4_t b) { return (uint16x4_t){a.val + b.val}; } -__ai uint32x2_t vadd_u32(uint32x2_t a, uint32x2_t b) { return (uint32x2_t){a.val + b.val}; } -__ai uint64x1_t vadd_u64(uint64x1_t a, uint64x1_t b) { return (uint64x1_t){a.val + b.val}; } -__ai int8x16_t vaddq_s8(int8x16_t a, int8x16_t b) { return (int8x16_t){a.val + b.val}; } -__ai int16x8_t vaddq_s16(int16x8_t a, int16x8_t b) { return (int16x8_t){a.val + b.val}; } -__ai int32x4_t vaddq_s32(int32x4_t a, int32x4_t b) { return (int32x4_t){a.val + b.val}; } -__ai int64x2_t vaddq_s64(int64x2_t a, int64x2_t b) { return (int64x2_t){a.val + b.val}; } -__ai float32x4_t vaddq_f32(float32x4_t a, float32x4_t b) { return (float32x4_t){a.val + b.val}; } -__ai uint8x16_t vaddq_u8(uint8x16_t a, uint8x16_t b) { return (uint8x16_t){a.val + b.val}; } -__ai uint16x8_t vaddq_u16(uint16x8_t a, uint16x8_t b) { return (uint16x8_t){a.val + b.val}; } -__ai uint32x4_t vaddq_u32(uint32x4_t a, uint32x4_t b) { return (uint32x4_t){a.val + b.val}; } -__ai uint64x2_t vaddq_u64(uint64x2_t a, uint64x2_t b) { return (uint64x2_t){a.val + b.val}; } - -// vector long add -INTTYPES_WIDENING(vaddl, __builtin_neon_vaddl) - -// vector wide add -INTTYPES_WIDE(vaddw, __builtin_neon_vaddw) - -// halving add -// rounding halving add -INTTYPES_ADD_32(vhadd, __builtin_neon_vhadd) -INTTYPES_ADD_32(vrhadd, __builtin_neon_vrhadd) - -// saturating add -INTTYPES_ADD_32(vqadd, __builtin_neon_vqadd) -INTTYPES_ADD_64(vqadd, __builtin_neon_vqadd) - -// add high half -// rounding add high half -INTTYPES_NARROWING(vaddhn, __builtin_neon_vaddhn) -INTTYPES_NARROWING(vraddhn, __builtin_neon_vraddhn) - -// multiply -// mul-poly - -// multiple accumulate -// multiple subtract - -// multiple accumulate long -// multiple subtract long -INTTYPES_WIDENING_MUL(vmlal, __builtin_neon_vmlal) -INTTYPES_WIDENING_MUL(vmlsl, __builtin_neon_vmlsl) - -// saturating doubling multiply high -// saturating rounding doubling multiply high - -// saturating doubling multiply accumulate long -// saturating doubling multiply subtract long - -// long multiply -// long multiply-poly -INTTYPES_WIDENING(vmull, __builtin_neon_vmull) -__ai poly16x8_t vmull_p8(poly8x8_t a, poly8x8_t b) { return (poly16x8_t){ __builtin_neon_vmull(a.val, b.val) }; } - -// saturating doubling long multiply - -// subtract - -// long subtract -INTTYPES_WIDENING(vsubl, __builtin_neon_vsubl) - -// wide subtract -INTTYPES_WIDE(vsubw, __builtin_neon_vsubw) - -// saturating subtract -INTTYPES_ADD_32(vqsub, __builtin_neon_vqsub) -INTTYPES_ADD_64(vqsub, __builtin_neon_vqsub) - -// halving subtract -INTTYPES_ADD_32(vhsub, __builtin_neon_vhsub) - -// subtract high half -// rounding subtract high half -INTTYPES_NARROWING(vsubhn, __builtin_neon_vsubhn) -INTTYPES_NARROWING(vrsubhn, __builtin_neon_vrsubhn) - -// compare eq -// compare ge -// compare le -// compare gt -// compare lt -INT_FLOAT_CMP_OP(vceq, ==) -INT_FLOAT_CMP_OP(vcge, >=) -INT_FLOAT_CMP_OP(vcle, <=) -INT_FLOAT_CMP_OP(vcgt, >) -INT_FLOAT_CMP_OP(vclt, <) - -// compare eq-poly - -// compare abs ge -// compare abs le -// compare abs gt -// compare abs lt -FLOATTYPES_CMP(vcage, __builtin_neon_vcage) -FLOATTYPES_CMP(vcale, __builtin_neon_vcale) -FLOATTYPES_CMP(vcagt, __builtin_neon_vcagt) -FLOATTYPES_CMP(vcalt, __builtin_neon_vcalt) - -// test bits - -// abs diff -INTTYPES_ADD_32(vabd, __builtin_neon_vabd) -FP_BINARY(vabd, __builtin_neon_vabd) - -// abs diff long -INTTYPES_WIDENING(vabdl, __builtin_neon_vabdl) - -// abs diff accumulate -// abs diff accumulate long - -// max -// min -INTTYPES_ADD_32(vmax, __builtin_neon_vmax) -FP_BINARY(vmax, __builtin_neon_vmax) -INTTYPES_ADD_32(vmin, __builtin_neon_vmin) -FP_BINARY(vmin, __builtin_neon_vmin) - -// pairwise add -// pairwise max -// pairwise min -INT_FP_PAIRWISE_ADD(vpadd, __builtin_neon_vpadd) -INT_FP_PAIRWISE_ADD(vpmax, __builtin_neon_vpmax) -INT_FP_PAIRWISE_ADD(vpmin, __builtin_neon_vpmin) - -// long pairwise add -// long pairwise add accumulate - -// recip -// recip sqrt -FP_BINARY(vrecps, __builtin_neon_vrecps) -FP_BINARY(vrsqrts, __builtin_neon_vrsqrts) - -// shl by vec -// saturating shl by vec -// rounding shl by vec -// saturating rounding shl by vec - -// shr by constant -// shl by constant -// rounding shr by constant -// shr by constant and accumulate -// rounding shr by constant and accumulate -// saturating shl by constant -// s->u saturating shl by constant -// narrowing saturating shr by constant -// s->u narrowing saturating shr by constant -// s->u rounding narrowing saturating shr by constant -// narrowing saturating shr by constant -// rounding narrowing shr by constant -// rounding narrowing saturating shr by constant -// widening shl by constant - -// shr and insert -// shl and insert - -// loads and stores, single vector -// loads and stores, lane -// loads, dupe - -// loads and stores, arrays - -// vget,vgetq lane -// vset, vsetq lane - -// vcreate -// vdup, vdupq -// vmov, vmovq -// vdup_lane, vdupq_lane -// vcombine -// vget_high, vget_low - -// vcvt {u,s} <-> f, f <-> f16 -// narrow -// long move (unpack) -// saturating narrow -// saturating narrow s->u - -// table lookup -// extended table lookup - -// mla with scalar -// widening mla with scalar -// widening saturating doubling mla with scalar -// mls with scalar -// widening mls with scalar -// widening saturating doubling mls with scalar -// mul by scalar -// long mul with scalar -// long mul by scalar -// saturating doubling long mul with scalar -// saturating doubling long mul by scalar -// saturating doubling mul high with scalar -// saturating doubling mul high by scalar -// saturating rounding doubling mul high with scalar -// saturating rounding doubling mul high by scalar -// mla with scalar -// widening mla with sclar -// widening saturating doubling mla with scalar -// mls with scalar -// widening mls with scalar -// widening saturating doubling mls with scalar - -// extract - -// endian swap (vrev) - -// negate - -// abs -// saturating abs -// saturating negate -// count leading signs -INT_UNARY(vabs, __builtin_neon_vabs) -FP_UNARY(vabs, __builtin_neon_vabs) -INT_UNARY(vqabs, __builtin_neon_vqabs) -INT_UNARY(vqneg, __builtin_neon_vqneg) -INT_UNARY(vcls, __builtin_neon_vcls) - -// count leading zeroes -// popcount - -// recip_est -// recip_sqrt_est - -// not-poly -// not - -// and -// or -// xor -// andn -// orn -INT_LOGICAL_OP(vand, &) -INT_LOGICAL_OP(vorr, |) -INT_LOGICAL_OP(veor, ^) -INT_LOGICAL_OP(vbic, &~) -INT_LOGICAL_OP(vorn, |~) - -// bitselect - -// transpose elts -// interleave elts -// deinterleave elts - -// vreinterpret - -#endif /* __ARM_NEON_H */ diff --git a/lib/Headers/arm_neon.td b/lib/Headers/arm_neon.td deleted file mode 100644 index 7ffbfb4..0000000 --- a/lib/Headers/arm_neon.td +++ /dev/null @@ -1,341 +0,0 @@ -//===--- arm_neon.td - ARM NEON compiler interface ------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the TableGen definitions from which the ARM NEON header -// file will be generated. See ARM document DUI0348B. -// -//===----------------------------------------------------------------------===// - -class Op; - -def OP_NONE : Op; -def OP_ADD : Op; -def OP_SUB : Op; -def OP_MUL : Op; -def OP_MLA : Op; -def OP_MLS : Op; -def OP_MUL_N : Op; -def OP_MLA_N : Op; -def OP_MLS_N : Op; -def OP_EQ : Op; -def OP_GE : Op; -def OP_LE : Op; -def OP_GT : Op; -def OP_LT : Op; -def OP_NEG : Op; -def OP_NOT : Op; -def OP_AND : Op; -def OP_OR : Op; -def OP_XOR : Op; -def OP_ANDN : Op; -def OP_ORN : Op; -def OP_CAST : Op; -def OP_HI : Op; -def OP_LO : Op; -def OP_CONC : Op; -def OP_DUP : Op; -def OP_SEL : Op; -def OP_REV64 : Op; -def OP_REV32 : Op; -def OP_REV16 : Op; - -class Inst { - string Prototype = p; - string Types = t; - Op Operand = o; - bit isShift = 0; -} - -// Used to generate Builtins.def -class SInst : Inst {} -class IInst : Inst {} -class WInst : Inst {} - -// prototype: return (arg, arg, ...) -// v: void -// t: best-fit integer (int/poly args) -// x: signed integer (int/float args) -// u: unsigned integer (int/float args) -// f: float (int args) -// d: default -// w: double width elements, same num elts -// n: double width elements, half num elts -// h: half width elements, double num elts -// e: half width elements, double num elts, unsigned -// i: constant int -// l: constant uint64 -// s: scalar of element type -// a: scalar of element type (splat to vector type) -// k: default elt width, double num elts -// #: array of default vectors -// p: pointer type -// c: const pointer type - -// sizes: -// c: char -// s: short -// i: int -// l: long -// f: float -// h: half-float - -// size modifiers: -// U: unsigned -// Q: 128b -// P: polynomial - -//////////////////////////////////////////////////////////////////////////////// -// E.3.1 Addition -def VADD : Inst<"ddd", "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUl", OP_ADD>; -def VADDL : SInst<"wdd", "csiUcUsUi">; -def VADDW : SInst<"wwd", "csiUcUsUi">; -def VHADD : SInst<"ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; -def VRHADD : SInst<"ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; -def VQADD : SInst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VADDHN : IInst<"dww", "csiUcUsUi">; -def VRADDHN : IInst<"dww", "csiUcUsUi">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.2 Multiplication -def VMUL : Inst<"ddd", "csifUcUsUiPcQcQsQiQfQUcQUsQUiQPc", OP_MUL>; -def VMLA : Inst<"dddd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_MLA>; -def VMLAL : SInst<"wwdd", "csiUcUsUi">; -def VMLS : Inst<"dddd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_MLS>; -def VMLSL : SInst<"wwdd", "csiUcUsUi">; -def VQDMULH : SInst<"ddd", "siQsQi">; -def VQRDMULH : SInst<"ddd", "siQsQi">; -def VQDMLAL : SInst<"wwdd", "si">; -def VQDMLSL : SInst<"wwdd", "si">; -def VMULL : SInst<"wdd", "csiUcUsUiPc">; -def VQDMULL : SInst<"wdd", "si">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.3 Subtraction -def VSUB : Inst<"ddd", "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUl", OP_SUB>; -def VSUBL : SInst<"wdd", "csiUcUsUi">; -def VSUBW : SInst<"wwd", "csiUcUsUi">; -def VQSUB : SInst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VHSUB : SInst<"ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; -def VSUBHN : IInst<"dww", "csiUcUsUi">; -def VRSUBHN : IInst<"dww", "csiUcUsUi">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.4 Comparison -def VCEQ : Inst<"udd", "csifUcUsUiPcQcQsQiQfQUcQUsQUiQPc", OP_EQ>; -def VCGE : Inst<"udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_GE>; -def VCLE : Inst<"udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_LE>; -def VCGT : Inst<"udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_GT>; -def VCLT : Inst<"udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_LT>; -def VCAGE : IInst<"udd", "fQf">; -def VCALE : IInst<"udd", "fQf">; -def VCAGT : IInst<"udd", "fQf">; -def VCALT : IInst<"udd", "fQf">; -def VTST : WInst<"udd", "csiUcUsUiPcQcQsQiQUcQUsQUiQPc">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.5 Absolute Difference -def VABD : SInst<"ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; -def VABDL : SInst<"wdd", "csiUcUsUi">; -def VABA : SInst<"dddd", "csiUcUsUiQcQsQiQUcQUsQUi">; -def VABAL : SInst<"wwdd", "csiUcUsUi">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.6 Max/Min -def VMAX : SInst<"ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; -def VMIN : SInst<"ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.7 Pairdise Addition -def VPADD : IInst<"ddd", "csiUcUsUif">; -def VPADDL : SInst<"nd", "csiUcUsUiQcQsQiQUcQUsQUi">; -def VPADAL : SInst<"nnd", "csiUcUsUiQcQsQiQUcQUsQUi">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.8-9 Folding Max/Min -def VPMAX : SInst<"ddd", "csiUcUsUif">; -def VPMIN : SInst<"ddd", "csiUcUsUif">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.10 Reciprocal/Sqrt -def VRECPS : IInst<"ddd", "fQf">; -def VRSQRTS : IInst<"ddd", "fQf">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.11 Shifts by signed variable -def VSHL : SInst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VQSHL : SInst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VRSHL : SInst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VQRSHL : SInst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.12 Shifts by constant -let isShift = 1 in { -def VSHR_N : SInst<"ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VSHL_N : IInst<"ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VRSHR_N : SInst<"ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VSRA_N : SInst<"dddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VRSRA_N : SInst<"dddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VQSHL_N : SInst<"ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; -def VQSHLU_N : SInst<"udi", "csilQcQsQiQl">; -def VSHRN_N : IInst<"hki", "silUsUiUl">; -def VQSHRUN_N : SInst<"eki", "sil">; -def VQRSHRUN_N : SInst<"eki", "sil">; -def VQSHRN_N : SInst<"hki", "silUsUiUl">; -def VRSHRN_N : IInst<"hki", "silUsUiUl">; -def VQRSHRN_N : SInst<"hki", "silUsUiUl">; -def VSHLL_N : SInst<"wdi", "csiUcUsUi">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.13 Shifts with insert -def VSRI_N : WInst<"dddi", "csilUcUsUiUlPcPsQcQsQiQlQUcQUsQUiQUlQPcQPs">; -def VSLI_N : WInst<"dddi", "csilUcUsUiUlPcPsQcQsQiQlQUcQUsQUiQUlQPcQPs">; -} - -//////////////////////////////////////////////////////////////////////////////// -// E.3.14 Loads and stores of a single vector -def VLD1 : WInst<"dc", "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VLD1_LANE : WInst<"dci", "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VLD1_DUP : WInst<"dc", "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VST1 : WInst<"vpd", "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VST1_LANE : WInst<"vpdi", "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.15 Loads and stores of an N-element structure -def VLD2 : WInst<"2c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VLD3 : WInst<"3c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VLD4 : WInst<"4c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VLD2_DUP : WInst<"2c", "UcUsUiUlcsilhfPcPs">; -def VLD3_DUP : WInst<"3c", "UcUsUiUlcsilhfPcPs">; -def VLD4_DUP : WInst<"4c", "UcUsUiUlcsilhfPcPs">; -def VLD2_LANE : WInst<"2ci", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; -def VLD3_LANE : WInst<"3ci", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; -def VLD4_LANE : WInst<"4ci", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; -def VST2 : WInst<"vp2", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VST3 : WInst<"vp3", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VST4 : WInst<"vp4", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; -def VST2_LANE : WInst<"vp2i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; -def VST3_LANE : WInst<"vp3i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; -def VST4_LANE : WInst<"vp4i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.16 Extract lanes from a vector -def VGET_LANE : IInst<"sdi", "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.17 Set lanes within a vector -def VSET_LANE : IInst<"dsdi", "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.18 Initialize a vector from bit pattern -def VCREATE: Inst<"dl", "csihfUcUsUiUlPcPsl", OP_CAST>; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.19 Set all lanes to same value -def VDUP_N : Inst<"ds", "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl", OP_DUP>; -def VMOV_N : Inst<"ds", "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl", OP_DUP>; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.20 Combining vectors -def VCOMBINE : Inst<"kdd", "csilhfUcUsUiUlPcPs", OP_CONC>; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.21 Splitting vectors -def VGET_HIGH : Inst<"dk", "csilhfUcUsUiUlPcPs", OP_HI>; -def VGET_LOW : Inst<"dk", "csilhfUcUsUiUlPcPs", OP_LO>; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.22 Converting vectors -def VCVT_S32 : SInst<"xd", "fQf">; -def VCVT_U32 : SInst<"ud", "fQf">; -def VCVT_F16 : SInst<"hk", "f">; -def VCVT_N_S32 : SInst<"xdi", "fQf">; -def VCVT_N_U32 : SInst<"udi", "fQf">; -def VCVT_F32 : SInst<"fd", "iUiQiQUi">; -def VCVT_F32_F16 : SInst<"kh", "f">; -def VCVT_N_F32 : SInst<"fdi", "iUiQiQUi">; -def VMOVN : IInst<"hk", "silUsUiUl">; -def VMOVL : SInst<"wd", "csiUcUsUi">; -def VQMOVN : SInst<"hk", "silUsUiUl">; -def VQMOVUN : SInst<"ek", "sil">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.23-24 Table lookup, Extended table lookup -def VTBL1 : WInst<"ddt", "UccPc">; -def VTBL2 : WInst<"d2t", "UccPc">; -def VTBL3 : WInst<"d3t", "UccPc">; -def VTBL4 : WInst<"d4t", "UccPc">; -def VTBX1 : WInst<"dddt", "UccPc">; -def VTBX2 : WInst<"dd2t", "UccPc">; -def VTBX3 : WInst<"dd3t", "UccPc">; -def VTBX4 : WInst<"dd4t", "UccPc">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.25 Operations with a scalar value -def VMLA_LANE : IInst<"ddddi", "siUsUifQsQiQUsQUiQf">; -def VMLAL_LANE : SInst<"wwddi", "siUsUi">; -def VQDMLAL_LANE : SInst<"wwddi", "si">; -def VMLS_LANE : IInst<"ddddi", "siUsUifQsQiQUsQUiQf">; -def VMLSL_LANE : SInst<"wwddi", "siUsUi">; -def VQDMLSL_LANE : SInst<"wwddi", "si">; -def VMUL_N : Inst<"dds", "sifUsUiQsQiQfQUsQUi", OP_MUL_N>; -def VMULL_N : SInst<"wda", "siUsUi">; -def VMULL_LANE : SInst<"wddi", "siUsUi">; -def VQDMULL_N : SInst<"wda", "si">; -def VQDMULL_LANE : SInst<"wddi", "si">; -def VQDMULH_N : SInst<"dda", "siQsQi">; -def VQDMULH_LANE : SInst<"dddi", "siQsQi">; -def VQRDMULH_N : SInst<"dda", "siQsQi">; -def VQRDMULH_LANE : SInst<"dddi", "siQsQi">; -def VMLA_N : Inst<"ddda", "siUsUifQsQiQUsQUiQf", OP_MLA_N>; -def VMLAL_N : SInst<"wwda", "siUsUi">; -def VQDMLAL_N : SInst<"wwda", "si">; -def VMLS_N : Inst<"ddds", "siUsUifQsQiQUsQUiQf", OP_MLS_N>; -def VMLSL_N : SInst<"wwda", "siUsUi">; -def VQDMLSL_N : SInst<"wwda", "si">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.26 Vector Extract -def VEXT : WInst<"dddi", "cUcPcsUsPsiUilUlQcQUcQPcQsQUsQPsQiQUiQlQUl">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.27 Reverse vector elements (sdap endianness) -def VREV64 : Inst<"dd", "csiUcUsUiPcPsfQcQsQiQUcQUsQUiQPcQPsQf", OP_REV64>; -def VREV32 : Inst<"dd", "csUcUsPcQcQsQUcQUsQPc", OP_REV32>; -def VREV16 : Inst<"dd", "cUcPcQcQUcQPc", OP_REV16>; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.28 Other single operand arithmetic -def VABS : SInst<"dd", "csifQcQsQiQf">; -def VQABS : SInst<"dd", "csiQcQsQi">; -def VNEG : Inst<"dd", "csifQcQsQiQf", OP_NEG>; -def VQNEG : SInst<"dd", "csiQcQsQi">; -def VCLS : SInst<"dd", "csiQcQsQi">; -def VCLZ : IInst<"dd", "csiUcUsUiQcQsQiQUcQUsQUi">; -def VCNT : WInst<"dd", "UccPcQUcQcQPc">; -def VRECPE : SInst<"dd", "fUiQfQUi">; -def VRSQRTE : SInst<"dd", "fUiQfQUi">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.29 Logical operations -def VMVN : Inst<"dd", "csiUcUsUiPcQcQsQiQUcQUsQUiQPc", OP_NOT>; -def VAND : Inst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_AND>; -def VORR : Inst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_OR>; -def VEOR : Inst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_XOR>; -def VBIC : Inst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_ANDN>; -def VORN : Inst<"ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_ORN>; -def VBSL : Inst<"dudd", "csilUcUsUiUlfPcPsQcQsQiQlQUcQUsQUiQUlQfQPcQPs", OP_SEL>; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.30 Transposition operations -def VTRN: WInst<"2dd", "csiUcUsUifPcPsQcQsQiQUcQUsQUiQfQPcQPs">; -def VZIP: WInst<"2dd", "csUcUsfPcPsQcQsQiQUcQUsQUiQfQPcQPs">; -def VUZP: WInst<"2dd", "csiUcUsUifPcPsQcQsQiQUcQUsQUiQfQPcQPs">; - -//////////////////////////////////////////////////////////////////////////////// -// E.3.31 Vector reinterpret cast operations -- cgit v1.1 From 5d5cc59cc77afe655b3707cb0e69e0827b444cad Mon Sep 17 00:00:00 2001 From: dim Date: Fri, 17 Sep 2010 15:48:55 +0000 Subject: Vendor import of llvm r114020 (from the release_28 branch): http://llvm.org/svn/llvm-project/llvm/branches/release_28@114020 Approved by: rpaulo (mentor) --- lib/Analysis/AliasAnalysis.cpp | 233 ++- lib/Analysis/AliasAnalysisCounter.cpp | 20 +- lib/Analysis/AliasAnalysisEvaluator.cpp | 50 +- lib/Analysis/AliasDebugger.cpp | 17 +- lib/Analysis/AliasSetTracker.cpp | 157 +- lib/Analysis/BasicAliasAnalysis.cpp | 584 ++++-- lib/Analysis/CFGPrinter.cpp | 30 +- lib/Analysis/CMakeLists.txt | 3 + lib/Analysis/CaptureTracking.cpp | 2 +- lib/Analysis/ConstantFolding.cpp | 4 +- lib/Analysis/DbgInfoPrinter.cpp | 6 +- lib/Analysis/DebugInfo.cpp | 192 +- lib/Analysis/DomPrinter.cpp | 65 +- lib/Analysis/IPA/CallGraph.cpp | 15 +- lib/Analysis/IPA/CallGraphSCCPass.cpp | 12 +- lib/Analysis/IPA/FindUsedTypes.cpp | 4 +- lib/Analysis/IPA/GlobalsModRef.cpp | 81 +- lib/Analysis/IVUsers.cpp | 39 +- lib/Analysis/InlineCost.cpp | 8 +- lib/Analysis/InstCount.cpp | 6 +- lib/Analysis/IntervalPartition.cpp | 6 +- lib/Analysis/LazyValueInfo.cpp | 583 ++++-- lib/Analysis/LibCallAliasAnalysis.cpp | 14 +- lib/Analysis/LibCallSemantics.cpp | 3 +- lib/Analysis/Lint.cpp | 11 +- lib/Analysis/LiveValues.cpp | 6 +- lib/Analysis/LoopDependenceAnalysis.cpp | 4 +- lib/Analysis/LoopInfo.cpp | 45 +- lib/Analysis/LoopPass.cpp | 16 +- lib/Analysis/MemoryDependenceAnalysis.cpp | 44 +- lib/Analysis/ModuleDebugInfoPrinter.cpp | 7 +- lib/Analysis/PointerTracking.cpp | 55 +- lib/Analysis/PostDominators.cpp | 8 +- lib/Analysis/ProfileEstimatorPass.cpp | 14 +- lib/Analysis/ProfileInfo.cpp | 13 +- lib/Analysis/ProfileInfoLoaderPass.cpp | 14 +- lib/Analysis/ProfileVerifierPass.cpp | 8 +- lib/Analysis/RegionInfo.cpp | 749 ++++++++ lib/Analysis/RegionPrinter.cpp | 186 ++ lib/Analysis/ScalarEvolution.cpp | 743 +++++--- lib/Analysis/ScalarEvolutionAliasAnalysis.cpp | 17 +- lib/Analysis/ScalarEvolutionExpander.cpp | 74 +- lib/Analysis/ScalarEvolutionNormalization.cpp | 114 +- lib/Analysis/TypeBasedAliasAnalysis.cpp | 191 ++ lib/Analysis/ValueTracking.cpp | 238 +-- lib/AsmParser/LLLexer.cpp | 2 +- lib/AsmParser/LLParser.cpp | 161 +- lib/AsmParser/LLParser.h | 14 +- lib/AsmParser/LLToken.h | 4 +- lib/AsmParser/Parser.cpp | 3 +- lib/Bitcode/Reader/BitcodeReader.cpp | 119 +- lib/Bitcode/Reader/BitcodeReader.h | 12 +- lib/Bitcode/Writer/BitcodeWriter.cpp | 136 +- lib/Bitcode/Writer/BitcodeWriterPass.cpp | 2 +- lib/Bitcode/Writer/ValueEnumerator.cpp | 139 +- lib/Bitcode/Writer/ValueEnumerator.h | 9 +- lib/CodeGen/AggressiveAntiDepBreaker.cpp | 32 +- lib/CodeGen/AggressiveAntiDepBreaker.h | 10 +- lib/CodeGen/Analysis.cpp | 4 +- lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 88 +- lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp | 4 +- lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp | 13 +- lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 862 +++++---- lib/CodeGen/AsmPrinter/DwarfDebug.h | 28 +- lib/CodeGen/AsmPrinter/DwarfException.cpp | 2 +- lib/CodeGen/BranchFolding.cpp | 2 +- lib/CodeGen/CMakeLists.txt | 6 +- lib/CodeGen/CalcSpillWeights.cpp | 276 ++- lib/CodeGen/CodePlacementOpt.cpp | 2 +- lib/CodeGen/CriticalAntiDepBreaker.cpp | 27 +- lib/CodeGen/CriticalAntiDepBreaker.h | 7 +- lib/CodeGen/DeadMachineInstructionElim.cpp | 21 +- lib/CodeGen/DwarfEHPrepare.cpp | 282 +-- lib/CodeGen/ELF.h | 120 +- lib/CodeGen/ELFCodeEmitter.cpp | 2 +- lib/CodeGen/ELFWriter.cpp | 30 +- lib/CodeGen/ELFWriter.h | 13 +- lib/CodeGen/GCMetadata.cpp | 12 +- lib/CodeGen/GCStrategy.cpp | 9 +- lib/CodeGen/IfConversion.cpp | 5 +- lib/CodeGen/InlineSpiller.cpp | 118 +- lib/CodeGen/IntrinsicLowering.cpp | 3 +- lib/CodeGen/LLVMTargetMachine.cpp | 81 +- lib/CodeGen/LiveInterval.cpp | 164 +- lib/CodeGen/LiveIntervalAnalysis.cpp | 79 +- lib/CodeGen/LiveStackAnalysis.cpp | 3 +- lib/CodeGen/LiveVariables.cpp | 18 +- lib/CodeGen/LocalStackSlotAllocation.cpp | 354 ++++ lib/CodeGen/LowerSubregs.cpp | 22 +- lib/CodeGen/MachineBasicBlock.cpp | 32 +- lib/CodeGen/MachineCSE.cpp | 41 +- lib/CodeGen/MachineDominators.cpp | 8 +- lib/CodeGen/MachineFunction.cpp | 3 +- lib/CodeGen/MachineFunctionAnalysis.cpp | 4 +- lib/CodeGen/MachineFunctionPrinterPass.cpp | 2 +- lib/CodeGen/MachineInstr.cpp | 33 +- lib/CodeGen/MachineLICM.cpp | 21 +- lib/CodeGen/MachineLoopInfo.cpp | 6 +- lib/CodeGen/MachineModuleInfo.cpp | 15 +- lib/CodeGen/MachineSink.cpp | 138 +- lib/CodeGen/MachineVerifier.cpp | 230 ++- lib/CodeGen/OptimizeExts.cpp | 220 --- lib/CodeGen/OptimizePHIs.cpp | 20 +- lib/CodeGen/PBQP/HeuristicBase.h | 8 +- lib/CodeGen/PBQP/HeuristicSolver.h | 9 + lib/CodeGen/PBQP/Heuristics/Briggs.h | 8 +- lib/CodeGen/PBQP/Solution.h | 31 + lib/CodeGen/PHIElimination.cpp | 36 +- lib/CodeGen/PHIElimination.h | 10 +- lib/CodeGen/PeepholeOptimizer.cpp | 287 +++ lib/CodeGen/PostRASchedulerList.cpp | 7 +- lib/CodeGen/PreAllocSplitting.cpp | 15 +- lib/CodeGen/ProcessImplicitDefs.cpp | 18 +- lib/CodeGen/PrologEpilogInserter.cpp | 243 +-- lib/CodeGen/PrologEpilogInserter.h | 9 +- lib/CodeGen/RegAllocFast.cpp | 136 +- lib/CodeGen/RegAllocLinearScan.cpp | 154 +- lib/CodeGen/RegAllocPBQP.cpp | 47 +- lib/CodeGen/RegisterCoalescer.cpp | 3 +- lib/CodeGen/RegisterScavenging.cpp | 34 +- lib/CodeGen/RenderMachineFunction.cpp | 1014 ++++++++++ lib/CodeGen/RenderMachineFunction.h | 336 ++++ lib/CodeGen/ScheduleDAGInstrs.cpp | 9 +- lib/CodeGen/ScheduleDAGInstrs.h | 4 +- lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 15 +- lib/CodeGen/SelectionDAG/FastISel.cpp | 17 +- lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp | 67 +- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 26 +- lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp | 20 +- lib/CodeGen/SelectionDAG/LegalizeTypes.h | 24 +- lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp | 390 ++-- lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp | 74 +- lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp | 421 ++++- lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp | 5 +- lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 40 +- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 638 ++++--- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h | 37 +- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 44 +- lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp | 2 +- lib/CodeGen/SelectionDAG/TargetLowering.cpp | 182 +- lib/CodeGen/SimpleRegisterCoalescing.cpp | 161 +- lib/CodeGen/SimpleRegisterCoalescing.h | 3 +- lib/CodeGen/SjLjEHPrepare.cpp | 2 +- lib/CodeGen/SlotIndexes.cpp | 3 +- lib/CodeGen/Spiller.cpp | 98 +- lib/CodeGen/Spiller.h | 19 +- lib/CodeGen/SplitKit.cpp | 1097 +++++++++++ lib/CodeGen/SplitKit.h | 321 ++++ lib/CodeGen/Splitter.cpp | 817 ++++++++ lib/CodeGen/Splitter.h | 99 + lib/CodeGen/StackProtector.cpp | 8 +- lib/CodeGen/StackSlotColoring.cpp | 9 +- lib/CodeGen/StrongPHIElimination.cpp | 9 +- lib/CodeGen/TailDuplication.cpp | 19 +- lib/CodeGen/TargetInstrInfoImpl.cpp | 13 - lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 6 +- lib/CodeGen/TwoAddressInstructionPass.cpp | 50 +- lib/CodeGen/UnreachableBlockElim.cpp | 15 +- lib/CodeGen/VirtRegMap.cpp | 3 +- lib/CodeGen/VirtRegMap.h | 7 +- lib/CodeGen/VirtRegRewriter.cpp | 103 +- lib/CompilerDriver/Action.cpp | 13 +- lib/CompilerDriver/BuiltinOptions.cpp | 4 +- lib/CompilerDriver/CompilationGraph.cpp | 289 ++- lib/CompilerDriver/Main.cpp | 123 +- lib/CompilerDriver/Makefile | 36 +- lib/CompilerDriver/Plugin.cpp | 78 - lib/ExecutionEngine/ExecutionEngineBindings.cpp | 4 + lib/ExecutionEngine/JIT/Intercept.cpp | 12 + lib/ExecutionEngine/JIT/JIT.cpp | 10 +- lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp | 10 +- lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp | 440 ----- lib/ExecutionEngine/JIT/JITDwarfEmitter.h | 16 - lib/ExecutionEngine/JIT/JITEmitter.cpp | 307 +-- lib/Linker/LinkModules.cpp | 180 +- lib/MC/CMakeLists.txt | 3 + lib/MC/ELFObjectWriter.cpp | 973 ++++++++++ lib/MC/MCAsmInfo.cpp | 2 + lib/MC/MCAsmInfoDarwin.cpp | 3 + lib/MC/MCAsmStreamer.cpp | 3 +- lib/MC/MCAssembler.cpp | 74 +- lib/MC/MCContext.cpp | 88 +- lib/MC/MCDisassembler/CMakeLists.txt | 7 + lib/MC/MCDisassembler/EDDisassembler.cpp | 402 ++++ lib/MC/MCDisassembler/EDDisassembler.h | 271 +++ lib/MC/MCDisassembler/EDInfo.h | 73 + lib/MC/MCDisassembler/EDInst.cpp | 207 +++ lib/MC/MCDisassembler/EDInst.h | 182 ++ lib/MC/MCDisassembler/EDOperand.cpp | 282 +++ lib/MC/MCDisassembler/EDOperand.h | 91 + lib/MC/MCDisassembler/EDToken.cpp | 206 +++ lib/MC/MCDisassembler/EDToken.h | 139 ++ lib/MC/MCDisassembler/Makefile | 14 + lib/MC/MCDwarf.cpp | 21 + lib/MC/MCELFStreamer.cpp | 408 ++++ lib/MC/MCMachOStreamer.cpp | 277 ++- lib/MC/MCNullStreamer.cpp | 1 + lib/MC/MCObjectStreamer.cpp | 48 + lib/MC/MCParser/AsmLexer.cpp | 28 +- lib/MC/MCParser/AsmParser.cpp | 700 ++++++- lib/MC/MCParser/DarwinAsmParser.cpp | 237 +-- lib/MC/MCParser/ELFAsmParser.cpp | 235 ++- lib/MC/MCParser/MCAsmParser.cpp | 15 +- lib/MC/MCParser/TargetAsmParser.cpp | 2 +- lib/MC/MCStreamer.cpp | 3 +- lib/MC/MachObjectWriter.cpp | 2 +- lib/MC/Makefile | 2 +- lib/MC/WinCOFFObjectWriter.cpp | 737 +++++++- lib/MC/WinCOFFStreamer.cpp | 229 ++- lib/Support/APFloat.cpp | 1 + lib/Support/APInt.cpp | 13 +- lib/Support/CMakeLists.txt | 2 +- lib/Support/ConstantRange.cpp | 124 +- lib/Support/CrashRecoveryContext.cpp | 204 ++ lib/Support/ErrorHandling.cpp | 34 +- lib/Support/FoldingSet.cpp | 89 +- lib/Support/PrettyStackTrace.cpp | 5 +- lib/Support/SlowOperationInformer.cpp | 67 - lib/Support/SmallVector.cpp | 2 +- lib/Support/Statistic.cpp | 14 +- lib/Support/StringRef.cpp | 27 +- lib/Support/SystemUtils.cpp | 10 + lib/Support/Triple.cpp | 243 ++- lib/Support/raw_ostream.cpp | 97 +- lib/System/DynamicLibrary.cpp | 6 + lib/System/Path.cpp | 40 +- lib/System/RWMutex.cpp | 18 +- lib/System/ThreadLocal.cpp | 5 + lib/System/Unix/Path.inc | 12 +- lib/System/Unix/Signals.inc | 44 + lib/System/Unix/ThreadLocal.inc | 1 + lib/System/Win32/Path.inc | 16 +- lib/System/Win32/Signals.inc | 14 + lib/System/Win32/ThreadLocal.inc | 4 + lib/Target/ARM/ARM.h | 60 +- lib/Target/ARM/ARM.td | 76 +- lib/Target/ARM/ARMAddressingModes.h | 20 +- lib/Target/ARM/ARMAsmPrinter.cpp | 1491 +++++++++++++++ lib/Target/ARM/ARMBaseInstrInfo.cpp | 134 +- lib/Target/ARM/ARMBaseInstrInfo.h | 81 +- lib/Target/ARM/ARMBaseRegisterInfo.cpp | 563 +++++- lib/Target/ARM/ARMBaseRegisterInfo.h | 29 +- lib/Target/ARM/ARMCallingConv.td | 4 +- lib/Target/ARM/ARMCodeEmitter.cpp | 72 +- lib/Target/ARM/ARMConstantIslandPass.cpp | 96 +- lib/Target/ARM/ARMExpandPseudoInsts.cpp | 359 +++- lib/Target/ARM/ARMFastISel.cpp | 665 +++++++ lib/Target/ARM/ARMGlobalMerge.cpp | 212 +++ lib/Target/ARM/ARMISelDAGToDAG.cpp | 371 ++-- lib/Target/ARM/ARMISelLowering.cpp | 635 +++++-- lib/Target/ARM/ARMISelLowering.h | 42 +- lib/Target/ARM/ARMInstrFormats.td | 296 +-- lib/Target/ARM/ARMInstrInfo.td | 406 ++-- lib/Target/ARM/ARMInstrNEON.td | 627 +++++-- lib/Target/ARM/ARMInstrThumb.td | 19 +- lib/Target/ARM/ARMInstrThumb2.td | 730 ++++---- lib/Target/ARM/ARMInstrVFP.td | 76 +- lib/Target/ARM/ARMLoadStoreOptimizer.cpp | 139 +- lib/Target/ARM/ARMMCInstLower.cpp | 162 ++ lib/Target/ARM/ARMMCInstLower.h | 56 + lib/Target/ARM/ARMMachineFunctionInfo.h | 11 +- lib/Target/ARM/ARMRegisterInfo.td | 160 +- lib/Target/ARM/ARMSubtarget.cpp | 5 + lib/Target/ARM/ARMSubtarget.h | 22 +- lib/Target/ARM/ARMTargetMachine.cpp | 14 +- lib/Target/ARM/ARMTargetMachine.h | 1 + lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 245 ++- lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp | 1438 --------------- lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp | 66 +- lib/Target/ARM/AsmPrinter/ARMInstPrinter.h | 2 + lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp | 162 -- lib/Target/ARM/AsmPrinter/ARMMCInstLower.h | 56 - lib/Target/ARM/AsmPrinter/CMakeLists.txt | 2 - lib/Target/ARM/CMakeLists.txt | 10 +- lib/Target/ARM/Disassembler/ARMDisassembler.cpp | 13 +- .../ARM/Disassembler/ARMDisassemblerCore.cpp | 183 +- lib/Target/ARM/Disassembler/ARMDisassemblerCore.h | 66 +- .../ARM/Disassembler/ThumbDisassemblerCore.h | 227 ++- lib/Target/ARM/Makefile | 5 +- lib/Target/ARM/NEONMoveFix.cpp | 2 +- lib/Target/ARM/NEONPreAllocPass.cpp | 147 +- lib/Target/ARM/README.txt | 42 +- lib/Target/ARM/Thumb1RegisterInfo.cpp | 279 +-- lib/Target/ARM/Thumb1RegisterInfo.h | 22 +- lib/Target/ARM/Thumb2ITBlockPass.cpp | 68 +- lib/Target/ARM/Thumb2InstrInfo.cpp | 8 +- lib/Target/ARM/Thumb2SizeReduction.cpp | 14 +- lib/Target/Alpha/AlphaBranchSelector.cpp | 2 +- lib/Target/Alpha/AlphaCodeEmitter.cpp | 2 +- lib/Target/Alpha/AlphaISelDAGToDAG.cpp | 4 +- lib/Target/Alpha/AlphaInstrInfo.cpp | 26 - lib/Target/Alpha/AlphaInstrInfo.h | 6 - lib/Target/Alpha/AlphaLLRP.cpp | 2 +- lib/Target/Alpha/AlphaRegisterInfo.cpp | 6 +- lib/Target/Alpha/AlphaRegisterInfo.h | 5 +- lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp | 2 - lib/Target/Blackfin/BlackfinInstrInfo.cpp | 28 - lib/Target/Blackfin/BlackfinInstrInfo.h | 4 - lib/Target/Blackfin/BlackfinRegisterInfo.cpp | 16 +- lib/Target/Blackfin/BlackfinRegisterInfo.h | 7 +- lib/Target/CBackend/CBackend.cpp | 12 +- lib/Target/CellSPU/SPUCallingConv.td | 24 +- lib/Target/CellSPU/SPUISelDAGToDAG.cpp | 44 +- lib/Target/CellSPU/SPUISelLowering.cpp | 105 +- lib/Target/CellSPU/SPUInstrInfo.cpp | 142 -- lib/Target/CellSPU/SPUInstrInfo.h | 6 - lib/Target/CellSPU/SPUInstrInfo.td | 156 +- lib/Target/CellSPU/SPUOperands.td | 6 - lib/Target/CellSPU/SPURegisterInfo.cpp | 11 +- lib/Target/CellSPU/SPURegisterInfo.h | 5 +- lib/Target/CellSPU/SPURegisterInfo.td | 2 +- lib/Target/CppBackend/CPPBackend.cpp | 17 +- lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp | 10 - lib/Target/MBlaze/MBlaze.td | 2 +- lib/Target/MBlaze/MBlazeCallingConv.td | 2 +- lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp | 2 +- lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp | 2 +- lib/Target/MBlaze/MBlazeInstrFPU.td | 2 +- lib/Target/MBlaze/MBlazeInstrFSL.td | 2 +- lib/Target/MBlaze/MBlazeInstrFormats.td | 2 +- lib/Target/MBlaze/MBlazeInstrInfo.cpp | 35 - lib/Target/MBlaze/MBlazeInstrInfo.h | 6 - lib/Target/MBlaze/MBlazeInstrInfo.td | 2 +- lib/Target/MBlaze/MBlazeIntrinsics.td | 12 +- lib/Target/MBlaze/MBlazeRegisterInfo.cpp | 5 +- lib/Target/MBlaze/MBlazeRegisterInfo.h | 5 +- lib/Target/MBlaze/MBlazeRegisterInfo.td | 2 +- lib/Target/MBlaze/MBlazeSchedule.td | 2 +- lib/Target/MSIL/CMakeLists.txt | 3 - lib/Target/MSIL/MSILWriter.cpp | 1706 ----------------- lib/Target/MSIL/MSILWriter.h | 258 --- lib/Target/MSIL/Makefile | 16 - lib/Target/MSIL/README.TXT | 26 - lib/Target/MSIL/TargetInfo/CMakeLists.txt | 6 - lib/Target/MSIL/TargetInfo/MSILTargetInfo.cpp | 26 - lib/Target/MSIL/TargetInfo/Makefile | 15 - lib/Target/MSP430/MSP430BranchSelector.cpp | 7 +- lib/Target/MSP430/MSP430InstrInfo.cpp | 23 +- lib/Target/MSP430/MSP430InstrInfo.h | 4 - lib/Target/MSP430/MSP430RegisterInfo.cpp | 12 +- lib/Target/MSP430/MSP430RegisterInfo.h | 7 +- lib/Target/Mangler.cpp | 3 +- lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp | 20 + lib/Target/Mips/Mips.td | 2 +- lib/Target/Mips/MipsCallingConv.td | 2 +- lib/Target/Mips/MipsDelaySlotFiller.cpp | 2 +- lib/Target/Mips/MipsISelDAGToDAG.cpp | 11 +- lib/Target/Mips/MipsISelLowering.cpp | 8 +- lib/Target/Mips/MipsInstrFPU.td | 2 +- lib/Target/Mips/MipsInstrFormats.td | 2 +- lib/Target/Mips/MipsInstrInfo.cpp | 47 - lib/Target/Mips/MipsInstrInfo.h | 6 - lib/Target/Mips/MipsInstrInfo.td | 9 +- lib/Target/Mips/MipsRegisterInfo.cpp | 6 +- lib/Target/Mips/MipsRegisterInfo.h | 5 +- lib/Target/Mips/MipsRegisterInfo.td | 2 +- lib/Target/Mips/MipsSchedule.td | 2 +- lib/Target/PIC16/CMakeLists.txt | 2 +- lib/Target/PIC16/PIC16.h | 7 +- lib/Target/PIC16/PIC16ISelLowering.cpp | 10 + lib/Target/PIC16/PIC16ISelLowering.h | 5 +- lib/Target/PIC16/PIC16InstrInfo.cpp | 15 - lib/Target/PIC16/PIC16InstrInfo.h | 4 - lib/Target/PIC16/PIC16MemSelOpt.cpp | 2 +- lib/Target/PIC16/PIC16Passes/PIC16Cloner.cpp | 2 +- lib/Target/PIC16/PIC16Passes/PIC16Cloner.h | 2 +- lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp | 5 +- lib/Target/PIC16/PIC16Passes/PIC16Overlay.h | 2 +- lib/Target/PIC16/PIC16RegisterInfo.cpp | 9 +- lib/Target/PIC16/PIC16RegisterInfo.h | 5 +- lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp | 14 + lib/Target/PowerPC/PPCBranchSelector.cpp | 7 +- lib/Target/PowerPC/PPCCallingConv.td | 2 +- lib/Target/PowerPC/PPCCodeEmitter.cpp | 4 +- lib/Target/PowerPC/PPCISelLowering.cpp | 39 +- lib/Target/PowerPC/PPCInstrInfo.cpp | 82 +- lib/Target/PowerPC/PPCInstrInfo.h | 6 - lib/Target/PowerPC/PPCInstrInfo.td | 19 +- lib/Target/PowerPC/PPCRegisterInfo.cpp | 22 +- lib/Target/PowerPC/PPCRegisterInfo.h | 5 +- lib/Target/PowerPC/PPCSubtarget.cpp | 4 + lib/Target/PowerPC/PPCSubtarget.h | 4 + lib/Target/README.txt | 16 + lib/Target/Sparc/DelaySlotFiller.cpp | 2 +- lib/Target/Sparc/FPMover.cpp | 2 +- lib/Target/Sparc/Sparc.td | 2 +- lib/Target/Sparc/SparcISelDAGToDAG.cpp | 8 +- lib/Target/Sparc/SparcInstrInfo.cpp | 40 - lib/Target/Sparc/SparcInstrInfo.h | 6 - lib/Target/Sparc/SparcInstrInfo.td | 12 +- lib/Target/Sparc/SparcRegisterInfo.cpp | 6 +- lib/Target/Sparc/SparcRegisterInfo.h | 5 +- lib/Target/SystemZ/SystemZInstrInfo.cpp | 25 - lib/Target/SystemZ/SystemZInstrInfo.h | 3 - lib/Target/SystemZ/SystemZRegisterInfo.cpp | 9 +- lib/Target/SystemZ/SystemZRegisterInfo.h | 7 +- lib/Target/TargetData.cpp | 62 +- lib/Target/TargetMachine.cpp | 20 +- lib/Target/TargetRegisterInfo.cpp | 14 +- lib/Target/X86/AsmParser/X86AsmParser.cpp | 274 +-- lib/Target/X86/AsmPrinter/CMakeLists.txt | 3 +- lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp | 5 + lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h | 3 + lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp | 680 ------- lib/Target/X86/AsmPrinter/X86AsmPrinter.h | 89 - lib/Target/X86/AsmPrinter/X86InstComments.cpp | 232 +++ lib/Target/X86/AsmPrinter/X86InstComments.h | 25 + lib/Target/X86/AsmPrinter/X86IntelInstPrinter.cpp | 5 + lib/Target/X86/AsmPrinter/X86IntelInstPrinter.h | 4 + lib/Target/X86/AsmPrinter/X86MCInstLower.cpp | 632 ------- lib/Target/X86/AsmPrinter/X86MCInstLower.h | 51 - lib/Target/X86/CMakeLists.txt | 10 +- lib/Target/X86/README-FPStack.txt | 4 +- lib/Target/X86/README-SSE.txt | 42 +- lib/Target/X86/README.txt | 104 +- lib/Target/X86/SSEDomainFix.cpp | 2 +- lib/Target/X86/X86.h | 5 - lib/Target/X86/X86.td | 4 +- lib/Target/X86/X86AsmBackend.cpp | 45 +- lib/Target/X86/X86AsmPrinter.cpp | 727 ++++++++ lib/Target/X86/X86AsmPrinter.h | 89 + lib/Target/X86/X86CallingConv.td | 32 +- lib/Target/X86/X86CodeEmitter.cpp | 119 +- lib/Target/X86/X86FastISel.cpp | 29 +- lib/Target/X86/X86FloatingPoint.cpp | 473 ++++- lib/Target/X86/X86FloatingPointRegKill.cpp | 153 -- lib/Target/X86/X86ISelDAGToDAG.cpp | 37 +- lib/Target/X86/X86ISelLowering.cpp | 1207 ++++++++++-- lib/Target/X86/X86ISelLowering.h | 58 +- lib/Target/X86/X86Instr64bit.td | 156 +- lib/Target/X86/X86InstrFMA.td | 60 + lib/Target/X86/X86InstrFPStack.td | 6 +- lib/Target/X86/X86InstrFormats.td | 33 +- lib/Target/X86/X86InstrFragmentsSIMD.td | 80 +- lib/Target/X86/X86InstrInfo.cpp | 692 +------ lib/Target/X86/X86InstrInfo.h | 30 +- lib/Target/X86/X86InstrInfo.td | 145 +- lib/Target/X86/X86InstrMMX.td | 2 +- lib/Target/X86/X86InstrSSE.td | 1945 +++++++++++++++----- lib/Target/X86/X86MCAsmInfo.cpp | 3 + lib/Target/X86/X86MCCodeEmitter.cpp | 57 +- lib/Target/X86/X86MCInstLower.cpp | 609 ++++++ lib/Target/X86/X86MCInstLower.h | 54 + lib/Target/X86/X86RegisterInfo.cpp | 103 +- lib/Target/X86/X86RegisterInfo.h | 9 +- lib/Target/X86/X86RegisterInfo.td | 17 +- lib/Target/X86/X86ShuffleDecode.h | 155 ++ lib/Target/X86/X86Subtarget.cpp | 10 +- lib/Target/X86/X86Subtarget.h | 8 + lib/Target/X86/X86TargetMachine.cpp | 44 +- lib/Target/XCore/AsmPrinter/XCoreAsmPrinter.cpp | 12 +- lib/Target/XCore/CMakeLists.txt | 2 +- lib/Target/XCore/XCoreISelDAGToDAG.cpp | 21 +- lib/Target/XCore/XCoreInstrInfo.cpp | 29 +- lib/Target/XCore/XCoreInstrInfo.h | 6 - lib/Target/XCore/XCoreInstrInfo.td | 12 +- lib/Target/XCore/XCoreRegisterInfo.cpp | 14 +- lib/Target/XCore/XCoreRegisterInfo.h | 5 +- lib/Transforms/Hello/Hello.cpp | 11 +- lib/Transforms/IPO/ArgumentPromotion.cpp | 13 +- lib/Transforms/IPO/ConstantMerge.cpp | 34 +- lib/Transforms/IPO/DeadArgumentElimination.cpp | 26 +- lib/Transforms/IPO/DeadTypeElimination.cpp | 4 +- lib/Transforms/IPO/ExtractGV.cpp | 157 +- lib/Transforms/IPO/FunctionAttrs.cpp | 12 +- lib/Transforms/IPO/GlobalDCE.cpp | 5 +- lib/Transforms/IPO/GlobalOpt.cpp | 12 +- lib/Transforms/IPO/IPConstantPropagation.cpp | 10 +- lib/Transforms/IPO/InlineAlways.cpp | 6 +- lib/Transforms/IPO/InlineSimple.cpp | 8 +- lib/Transforms/IPO/Inliner.cpp | 12 +- lib/Transforms/IPO/Internalize.cpp | 8 +- lib/Transforms/IPO/LoopExtractor.cpp | 23 +- lib/Transforms/IPO/LowerSetJmp.cpp | 4 +- lib/Transforms/IPO/MergeFunctions.cpp | 658 +++---- lib/Transforms/IPO/PartialInlining.cpp | 10 +- lib/Transforms/IPO/PartialSpecialization.cpp | 46 +- lib/Transforms/IPO/PruneEH.cpp | 6 +- lib/Transforms/IPO/StripDeadPrototypes.cpp | 6 +- lib/Transforms/IPO/StripSymbols.cpp | 36 +- lib/Transforms/IPO/StructRetPromotion.cpp | 26 +- lib/Transforms/InstCombine/InstCombine.h | 2 +- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 46 +- lib/Transforms/InstCombine/InstCombineCalls.cpp | 35 +- lib/Transforms/InstCombine/InstCombineCasts.cpp | 287 ++- lib/Transforms/InstCombine/InstCombineCompares.cpp | 2 +- .../InstCombine/InstCombineLoadStoreAlloca.cpp | 22 +- lib/Transforms/InstCombine/InstCombineSelect.cpp | 28 - lib/Transforms/InstCombine/InstCombineShifts.cpp | 307 ++- .../InstCombine/InstructionCombining.cpp | 4 +- lib/Transforms/Instrumentation/EdgeProfiling.cpp | 6 +- .../Instrumentation/OptimalEdgeProfiling.cpp | 8 +- lib/Transforms/Scalar/ABCD.cpp | 1112 ----------- lib/Transforms/Scalar/ADCE.cpp | 4 +- lib/Transforms/Scalar/BasicBlockPlacement.cpp | 6 +- lib/Transforms/Scalar/CMakeLists.txt | 3 +- lib/Transforms/Scalar/CodeGenPrepare.cpp | 36 +- lib/Transforms/Scalar/ConstantProp.cpp | 6 +- .../Scalar/CorrelatedValuePropagation.cpp | 200 ++ lib/Transforms/Scalar/DCE.cpp | 10 +- lib/Transforms/Scalar/DeadStoreElimination.cpp | 7 +- lib/Transforms/Scalar/GEPSplitter.cpp | 6 +- lib/Transforms/Scalar/GVN.cpp | 15 +- lib/Transforms/Scalar/IndVarSimplify.cpp | 18 +- lib/Transforms/Scalar/JumpThreading.cpp | 217 ++- lib/Transforms/Scalar/LICM.cpp | 728 ++++---- lib/Transforms/Scalar/LoopDeletion.cpp | 7 +- lib/Transforms/Scalar/LoopIndexSplit.cpp | 12 +- lib/Transforms/Scalar/LoopRotation.cpp | 34 +- lib/Transforms/Scalar/LoopStrengthReduce.cpp | 182 +- lib/Transforms/Scalar/LoopUnrollPass.cpp | 21 +- lib/Transforms/Scalar/LoopUnswitch.cpp | 30 +- lib/Transforms/Scalar/LowerAtomic.cpp | 161 ++ lib/Transforms/Scalar/MemCpyOptimizer.cpp | 21 +- lib/Transforms/Scalar/Reassociate.cpp | 5 +- lib/Transforms/Scalar/Reg2Mem.cpp | 8 +- lib/Transforms/Scalar/SCCP.cpp | 41 +- lib/Transforms/Scalar/ScalarReplAggregates.cpp | 49 +- lib/Transforms/Scalar/SimplifyCFGPass.cpp | 10 +- lib/Transforms/Scalar/SimplifyHalfPowrLibCalls.cpp | 6 +- lib/Transforms/Scalar/SimplifyLibCalls.cpp | 27 +- lib/Transforms/Scalar/Sink.cpp | 5 +- lib/Transforms/Scalar/TailDuplication.cpp | 4 +- lib/Transforms/Scalar/TailRecursionElimination.cpp | 68 +- lib/Transforms/Utils/BasicBlockUtils.cpp | 25 +- lib/Transforms/Utils/BasicInliner.cpp | 4 +- lib/Transforms/Utils/BreakCriticalEdges.cpp | 10 +- lib/Transforms/Utils/BuildLibCalls.cpp | 21 +- lib/Transforms/Utils/CMakeLists.txt | 1 - lib/Transforms/Utils/CloneFunction.cpp | 86 +- lib/Transforms/Utils/CloneModule.cpp | 30 +- lib/Transforms/Utils/InlineFunction.cpp | 11 +- lib/Transforms/Utils/InstructionNamer.cpp | 8 +- lib/Transforms/Utils/LCSSA.cpp | 27 +- lib/Transforms/Utils/Local.cpp | 3 + lib/Transforms/Utils/LoopSimplify.cpp | 40 +- lib/Transforms/Utils/LoopUnroll.cpp | 6 + lib/Transforms/Utils/LowerInvoke.cpp | 11 +- lib/Transforms/Utils/LowerSwitch.cpp | 16 +- lib/Transforms/Utils/Mem2Reg.cpp | 7 +- lib/Transforms/Utils/PromoteMemoryToRegister.cpp | 17 +- lib/Transforms/Utils/SSAUpdater.cpp | 40 +- lib/Transforms/Utils/SSI.cpp | 432 ----- lib/Transforms/Utils/SimplifyCFG.cpp | 56 +- lib/Transforms/Utils/UnifyFunctionExitNodes.cpp | 6 +- lib/Transforms/Utils/ValueMapper.cpp | 84 +- lib/Transforms/Utils/ValueMapper.h | 29 - lib/VMCore/AsmWriter.cpp | 167 +- lib/VMCore/AutoUpgrade.cpp | 217 ++- lib/VMCore/CMakeLists.txt | 1 + lib/VMCore/ConstantFold.cpp | 40 - lib/VMCore/Constants.cpp | 121 +- lib/VMCore/ConstantsContext.h | 16 +- lib/VMCore/Core.cpp | 92 +- lib/VMCore/Dominators.cpp | 147 +- lib/VMCore/Globals.cpp | 9 +- lib/VMCore/InlineAsm.cpp | 2 +- lib/VMCore/Instruction.cpp | 4 +- lib/VMCore/Instructions.cpp | 49 +- lib/VMCore/LLVMContext.cpp | 13 +- lib/VMCore/LLVMContextImpl.cpp | 3 - lib/VMCore/LLVMContextImpl.h | 5 - lib/VMCore/Metadata.cpp | 170 +- lib/VMCore/Module.cpp | 23 +- lib/VMCore/Pass.cpp | 293 +-- lib/VMCore/PassManager.cpp | 330 ++-- lib/VMCore/PassRegistry.cpp | 159 ++ lib/VMCore/PrintModulePass.cpp | 18 +- lib/VMCore/Type.cpp | 265 +-- lib/VMCore/TypesContext.h | 72 +- lib/VMCore/Use.cpp | 19 +- lib/VMCore/Value.cpp | 35 +- lib/VMCore/ValueSymbolTable.cpp | 2 - lib/VMCore/Verifier.cpp | 125 +- 574 files changed, 35084 insertions(+), 21488 deletions(-) create mode 100644 lib/Analysis/RegionInfo.cpp create mode 100644 lib/Analysis/RegionPrinter.cpp create mode 100644 lib/Analysis/TypeBasedAliasAnalysis.cpp create mode 100644 lib/CodeGen/LocalStackSlotAllocation.cpp delete mode 100644 lib/CodeGen/OptimizeExts.cpp create mode 100644 lib/CodeGen/PeepholeOptimizer.cpp create mode 100644 lib/CodeGen/RenderMachineFunction.cpp create mode 100644 lib/CodeGen/RenderMachineFunction.h create mode 100644 lib/CodeGen/SplitKit.cpp create mode 100644 lib/CodeGen/SplitKit.h create mode 100644 lib/CodeGen/Splitter.cpp create mode 100644 lib/CodeGen/Splitter.h delete mode 100644 lib/CompilerDriver/Plugin.cpp create mode 100644 lib/MC/ELFObjectWriter.cpp create mode 100644 lib/MC/MCDisassembler/CMakeLists.txt create mode 100644 lib/MC/MCDisassembler/EDDisassembler.cpp create mode 100644 lib/MC/MCDisassembler/EDDisassembler.h create mode 100644 lib/MC/MCDisassembler/EDInfo.h create mode 100644 lib/MC/MCDisassembler/EDInst.cpp create mode 100644 lib/MC/MCDisassembler/EDInst.h create mode 100644 lib/MC/MCDisassembler/EDOperand.cpp create mode 100644 lib/MC/MCDisassembler/EDOperand.h create mode 100644 lib/MC/MCDisassembler/EDToken.cpp create mode 100644 lib/MC/MCDisassembler/EDToken.h create mode 100644 lib/MC/MCDisassembler/Makefile create mode 100644 lib/MC/MCDwarf.cpp create mode 100644 lib/MC/MCELFStreamer.cpp create mode 100644 lib/Support/CrashRecoveryContext.cpp delete mode 100644 lib/Support/SlowOperationInformer.cpp create mode 100644 lib/Target/ARM/ARMAsmPrinter.cpp create mode 100644 lib/Target/ARM/ARMFastISel.cpp create mode 100644 lib/Target/ARM/ARMGlobalMerge.cpp create mode 100644 lib/Target/ARM/ARMMCInstLower.cpp create mode 100644 lib/Target/ARM/ARMMCInstLower.h delete mode 100644 lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp delete mode 100644 lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp delete mode 100644 lib/Target/ARM/AsmPrinter/ARMMCInstLower.h delete mode 100644 lib/Target/MSIL/CMakeLists.txt delete mode 100644 lib/Target/MSIL/MSILWriter.cpp delete mode 100644 lib/Target/MSIL/MSILWriter.h delete mode 100644 lib/Target/MSIL/Makefile delete mode 100644 lib/Target/MSIL/README.TXT delete mode 100644 lib/Target/MSIL/TargetInfo/CMakeLists.txt delete mode 100644 lib/Target/MSIL/TargetInfo/MSILTargetInfo.cpp delete mode 100644 lib/Target/MSIL/TargetInfo/Makefile delete mode 100644 lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp delete mode 100644 lib/Target/X86/AsmPrinter/X86AsmPrinter.h create mode 100644 lib/Target/X86/AsmPrinter/X86InstComments.cpp create mode 100644 lib/Target/X86/AsmPrinter/X86InstComments.h delete mode 100644 lib/Target/X86/AsmPrinter/X86MCInstLower.cpp delete mode 100644 lib/Target/X86/AsmPrinter/X86MCInstLower.h create mode 100644 lib/Target/X86/X86AsmPrinter.cpp create mode 100644 lib/Target/X86/X86AsmPrinter.h delete mode 100644 lib/Target/X86/X86FloatingPointRegKill.cpp create mode 100644 lib/Target/X86/X86InstrFMA.td create mode 100644 lib/Target/X86/X86MCInstLower.cpp create mode 100644 lib/Target/X86/X86MCInstLower.h create mode 100644 lib/Target/X86/X86ShuffleDecode.h delete mode 100644 lib/Transforms/Scalar/ABCD.cpp create mode 100644 lib/Transforms/Scalar/CorrelatedValuePropagation.cpp create mode 100644 lib/Transforms/Scalar/LowerAtomic.cpp delete mode 100644 lib/Transforms/Utils/SSI.cpp delete mode 100644 lib/Transforms/Utils/ValueMapper.h create mode 100644 lib/VMCore/PassRegistry.cpp (limited to 'lib') diff --git a/lib/Analysis/AliasAnalysis.cpp b/lib/Analysis/AliasAnalysis.cpp index 503fbbd..1f2528f 100644 --- a/lib/Analysis/AliasAnalysis.cpp +++ b/lib/Analysis/AliasAnalysis.cpp @@ -65,10 +65,127 @@ void AliasAnalysis::copyValue(Value *From, Value *To) { } AliasAnalysis::ModRefResult -AliasAnalysis::getModRefInfo(CallSite CS1, CallSite CS2) { - // FIXME: we can do better. +AliasAnalysis::getModRefInfo(ImmutableCallSite CS, + const Value *P, unsigned Size) { + // Don't assert AA because BasicAA calls us in order to make use of the + // logic here. + + ModRefBehavior MRB = getModRefBehavior(CS); + if (MRB == DoesNotAccessMemory) + return NoModRef; + + ModRefResult Mask = ModRef; + if (MRB == OnlyReadsMemory) + Mask = Ref; + else if (MRB == AliasAnalysis::AccessesArguments) { + bool doesAlias = false; + for (ImmutableCallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end(); + AI != AE; ++AI) + if (!isNoAlias(*AI, ~0U, P, Size)) { + doesAlias = true; + break; + } + + if (!doesAlias) + return NoModRef; + } + + // If P points to a constant memory location, the call definitely could not + // modify the memory location. + if ((Mask & Mod) && pointsToConstantMemory(P)) + Mask = ModRefResult(Mask & ~Mod); + + // If this is BasicAA, don't forward. + if (!AA) return Mask; + + // Otherwise, fall back to the next AA in the chain. But we can merge + // in any mask we've managed to compute. + return ModRefResult(AA->getModRefInfo(CS, P, Size) & Mask); +} + +AliasAnalysis::ModRefResult +AliasAnalysis::getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) { + // Don't assert AA because BasicAA calls us in order to make use of the + // logic here. + + // If CS1 or CS2 are readnone, they don't interact. + ModRefBehavior CS1B = getModRefBehavior(CS1); + if (CS1B == DoesNotAccessMemory) return NoModRef; + + ModRefBehavior CS2B = getModRefBehavior(CS2); + if (CS2B == DoesNotAccessMemory) return NoModRef; + + // If they both only read from memory, there is no dependence. + if (CS1B == OnlyReadsMemory && CS2B == OnlyReadsMemory) + return NoModRef; + + AliasAnalysis::ModRefResult Mask = ModRef; + + // If CS1 only reads memory, the only dependence on CS2 can be + // from CS1 reading memory written by CS2. + if (CS1B == OnlyReadsMemory) + Mask = ModRefResult(Mask & Ref); + + // If CS2 only access memory through arguments, accumulate the mod/ref + // information from CS1's references to the memory referenced by + // CS2's arguments. + if (CS2B == AccessesArguments) { + AliasAnalysis::ModRefResult R = NoModRef; + for (ImmutableCallSite::arg_iterator + I = CS2.arg_begin(), E = CS2.arg_end(); I != E; ++I) { + R = ModRefResult((R | getModRefInfo(CS1, *I, UnknownSize)) & Mask); + if (R == Mask) + break; + } + return R; + } + + // If CS1 only accesses memory through arguments, check if CS2 references + // any of the memory referenced by CS1's arguments. If not, return NoModRef. + if (CS1B == AccessesArguments) { + AliasAnalysis::ModRefResult R = NoModRef; + for (ImmutableCallSite::arg_iterator + I = CS1.arg_begin(), E = CS1.arg_end(); I != E; ++I) + if (getModRefInfo(CS2, *I, UnknownSize) != NoModRef) { + R = Mask; + break; + } + if (R == NoModRef) + return R; + } + + // If this is BasicAA, don't forward. + if (!AA) return Mask; + + // Otherwise, fall back to the next AA in the chain. But we can merge + // in any mask we've managed to compute. + return ModRefResult(AA->getModRefInfo(CS1, CS2) & Mask); +} + +AliasAnalysis::ModRefBehavior +AliasAnalysis::getModRefBehavior(ImmutableCallSite CS) { + // Don't assert AA because BasicAA calls us in order to make use of the + // logic here. + + ModRefBehavior Min = UnknownModRefBehavior; + + // Call back into the alias analysis with the other form of getModRefBehavior + // to see if it can give a better response. + if (const Function *F = CS.getCalledFunction()) + Min = getModRefBehavior(F); + + // If this is BasicAA, don't forward. + if (!AA) return Min; + + // Otherwise, fall back to the next AA in the chain. But we can merge + // in any result we've managed to compute. + return std::min(AA->getModRefBehavior(CS), Min); +} + +AliasAnalysis::ModRefBehavior +AliasAnalysis::getModRefBehavior(const Function *F) { assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!"); - return AA->getModRefInfo(CS1, CS2); + return AA->getModRefBehavior(F); } @@ -77,87 +194,63 @@ AliasAnalysis::getModRefInfo(CallSite CS1, CallSite CS2) { //===----------------------------------------------------------------------===// AliasAnalysis::ModRefResult -AliasAnalysis::getModRefInfo(LoadInst *L, Value *P, unsigned Size) { - return alias(L->getOperand(0), getTypeStoreSize(L->getType()), - P, Size) ? Ref : NoModRef; +AliasAnalysis::getModRefInfo(const LoadInst *L, const Value *P, unsigned Size) { + // Be conservative in the face of volatile. + if (L->isVolatile()) + return ModRef; + + // If the load address doesn't alias the given address, it doesn't read + // or write the specified memory. + if (!alias(L->getOperand(0), getTypeStoreSize(L->getType()), P, Size)) + return NoModRef; + + // Otherwise, a load just reads. + return Ref; } AliasAnalysis::ModRefResult -AliasAnalysis::getModRefInfo(StoreInst *S, Value *P, unsigned Size) { - // If the stored address cannot alias the pointer in question, then the - // pointer cannot be modified by the store. +AliasAnalysis::getModRefInfo(const StoreInst *S, const Value *P, unsigned Size) { + // Be conservative in the face of volatile. + if (S->isVolatile()) + return ModRef; + + // If the store address cannot alias the pointer in question, then the + // specified memory cannot be modified by the store. if (!alias(S->getOperand(1), getTypeStoreSize(S->getOperand(0)->getType()), P, Size)) return NoModRef; // If the pointer is a pointer to constant memory, then it could not have been // modified by this store. - return pointsToConstantMemory(P) ? NoModRef : Mod; -} - -AliasAnalysis::ModRefBehavior -AliasAnalysis::getModRefBehavior(CallSite CS, - std::vector *Info) { - if (CS.doesNotAccessMemory()) - // Can't do better than this. - return DoesNotAccessMemory; - ModRefBehavior MRB = getModRefBehavior(CS.getCalledFunction(), Info); - if (MRB != DoesNotAccessMemory && CS.onlyReadsMemory()) - return OnlyReadsMemory; - return MRB; -} - -AliasAnalysis::ModRefBehavior -AliasAnalysis::getModRefBehavior(Function *F, - std::vector *Info) { - if (F) { - if (F->doesNotAccessMemory()) - // Can't do better than this. - return DoesNotAccessMemory; - if (F->onlyReadsMemory()) - return OnlyReadsMemory; - if (unsigned id = F->getIntrinsicID()) - return getModRefBehavior(id); - } - return UnknownModRefBehavior; -} + if (pointsToConstantMemory(P)) + return NoModRef; -AliasAnalysis::ModRefBehavior AliasAnalysis::getModRefBehavior(unsigned iid) { -#define GET_INTRINSIC_MODREF_BEHAVIOR -#include "llvm/Intrinsics.gen" -#undef GET_INTRINSIC_MODREF_BEHAVIOR + // Otherwise, a store just writes. + return Mod; } AliasAnalysis::ModRefResult -AliasAnalysis::getModRefInfo(CallSite CS, Value *P, unsigned Size) { - ModRefBehavior MRB = getModRefBehavior(CS); - if (MRB == DoesNotAccessMemory) +AliasAnalysis::getModRefInfo(const VAArgInst *V, const Value *P, unsigned Size) { + // If the va_arg address cannot alias the pointer in question, then the + // specified memory cannot be accessed by the va_arg. + if (!alias(V->getOperand(0), UnknownSize, P, Size)) return NoModRef; - - ModRefResult Mask = ModRef; - if (MRB == OnlyReadsMemory) - Mask = Ref; - else if (MRB == AliasAnalysis::AccessesArguments) { - bool doesAlias = false; - for (CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end(); - AI != AE; ++AI) - if (!isNoAlias(*AI, ~0U, P, Size)) { - doesAlias = true; - break; - } - if (!doesAlias) - return NoModRef; - } + // If the pointer is a pointer to constant memory, then it could not have been + // modified by this va_arg. + if (pointsToConstantMemory(P)) + return NoModRef; - if (!AA) return Mask; + // Otherwise, a va_arg reads and writes. + return ModRef; +} - // If P points to a constant memory location, the call definitely could not - // modify the memory location. - if ((Mask & Mod) && AA->pointsToConstantMemory(P)) - Mask = ModRefResult(Mask & ~Mod); - return ModRefResult(Mask & AA->getModRefInfo(CS, P, Size)); +AliasAnalysis::ModRefBehavior +AliasAnalysis::getIntrinsicModRefBehavior(unsigned iid) { +#define GET_INTRINSIC_MODREF_BEHAVIOR +#include "llvm/Intrinsics.gen" +#undef GET_INTRINSIC_MODREF_BEHAVIOR } // AliasAnalysis destructor: DO NOT move this to the header file for @@ -206,12 +299,12 @@ bool AliasAnalysis::canInstructionRangeModify(const Instruction &I1, const Value *Ptr, unsigned Size) { assert(I1.getParent() == I2.getParent() && "Instructions not in same basic block!"); - BasicBlock::iterator I = const_cast(&I1); - BasicBlock::iterator E = const_cast(&I2); + BasicBlock::const_iterator I = &I1; + BasicBlock::const_iterator E = &I2; ++E; // Convert from inclusive to exclusive range. for (; I != E; ++I) // Check every instruction in range - if (getModRefInfo(I, const_cast(Ptr), Size) & Mod) + if (getModRefInfo(I, Ptr, Size) & Mod) return true; return false; } @@ -220,7 +313,7 @@ bool AliasAnalysis::canInstructionRangeModify(const Instruction &I1, /// function. bool llvm::isNoAliasCall(const Value *V) { if (isa(V) || isa(V)) - return CallSite(const_cast(cast(V))) + return ImmutableCallSite(cast(V)) .paramHasAttr(0, Attribute::NoAlias); return false; } diff --git a/lib/Analysis/AliasAnalysisCounter.cpp b/lib/Analysis/AliasAnalysisCounter.cpp index 1053955..b178041 100644 --- a/lib/Analysis/AliasAnalysisCounter.cpp +++ b/lib/Analysis/AliasAnalysisCounter.cpp @@ -34,7 +34,7 @@ namespace { Module *M; public: static char ID; // Class identification, replacement for typeinfo - AliasAnalysisCounter() : ModulePass(&ID) { + AliasAnalysisCounter() : ModulePass(ID) { No = May = Must = 0; NoMR = JustRef = JustMod = MR = 0; } @@ -87,8 +87,8 @@ namespace { /// an analysis interface through multiple inheritance. If needed, it /// should override this to adjust the this pointer as needed for the /// specified pass info. - virtual void *getAdjustedAnalysisPointer(const PassInfo *PI) { - if (PI->isPassID(&AliasAnalysis::ID)) + virtual void *getAdjustedAnalysisPointer(AnalysisID PI) { + if (PI == &AliasAnalysis::ID) return (AliasAnalysis*)this; return this; } @@ -103,17 +103,18 @@ namespace { AliasResult alias(const Value *V1, unsigned V1Size, const Value *V2, unsigned V2Size); - ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size); - ModRefResult getModRefInfo(CallSite CS1, CallSite CS2) { + ModRefResult getModRefInfo(ImmutableCallSite CS, + const Value *P, unsigned Size); + ModRefResult getModRefInfo(ImmutableCallSite CS1, + ImmutableCallSite CS2) { return AliasAnalysis::getModRefInfo(CS1,CS2); } }; } char AliasAnalysisCounter::ID = 0; -static RegisterPass -X("count-aa", "Count Alias Analysis Query Responses", false, true); -static RegisterAnalysisGroup Y(X); +INITIALIZE_AG_PASS(AliasAnalysisCounter, AliasAnalysis, "count-aa", + "Count Alias Analysis Query Responses", false, true, false); ModulePass *llvm::createAliasAnalysisCounterPass() { return new AliasAnalysisCounter(); @@ -146,7 +147,8 @@ AliasAnalysisCounter::alias(const Value *V1, unsigned V1Size, } AliasAnalysis::ModRefResult -AliasAnalysisCounter::getModRefInfo(CallSite CS, Value *P, unsigned Size) { +AliasAnalysisCounter::getModRefInfo(ImmutableCallSite CS, + const Value *P, unsigned Size) { ModRefResult R = getAnalysis().getModRefInfo(CS, P, Size); const char *MRString; diff --git a/lib/Analysis/AliasAnalysisEvaluator.cpp b/lib/Analysis/AliasAnalysisEvaluator.cpp index 37ee9fc..ce363cb 100644 --- a/lib/Analysis/AliasAnalysisEvaluator.cpp +++ b/lib/Analysis/AliasAnalysisEvaluator.cpp @@ -50,7 +50,7 @@ namespace { public: static char ID; // Pass identification, replacement for typeid - AAEval() : FunctionPass(&ID) {} + AAEval() : FunctionPass(ID) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); @@ -74,8 +74,8 @@ namespace { } char AAEval::ID = 0; -static RegisterPass -X("aa-eval", "Exhaustive Alias Analysis Precision Evaluator", false, true); +INITIALIZE_PASS(AAEval, "aa-eval", + "Exhaustive Alias Analysis Precision Evaluator", false, true); FunctionPass *llvm::createAAEvalPass() { return new AAEval(); } @@ -107,6 +107,15 @@ PrintModRefResults(const char *Msg, bool P, Instruction *I, Value *Ptr, } } +static inline void +PrintModRefResults(const char *Msg, bool P, CallSite CSA, CallSite CSB, + Module *M) { + if (P) { + errs() << " " << Msg << ": " << *CSA.getInstruction() + << " <-> " << *CSB.getInstruction() << '\n'; + } +} + static inline bool isInterestingPointer(Value *V) { return V->getType()->isPointerTy() && !isa(V); @@ -126,8 +135,7 @@ bool AAEval::runOnFunction(Function &F) { if (I->getType()->isPointerTy()) // Add all pointer instructions. Pointers.insert(&*I); Instruction &Inst = *I; - CallSite CS = CallSite::get(&Inst); - if (CS) { + if (CallSite CS = cast(&Inst)) { Value *Callee = CS.getCalledValue(); // Skip actual functions for direct function calls. if (!isa(Callee) && isInterestingPointer(Callee)) @@ -137,6 +145,7 @@ bool AAEval::runOnFunction(Function &F) { AI != AE; ++AI) if (isInterestingPointer(*AI)) Pointers.insert(*AI); + CallSites.insert(CS); } else { // Consider all operands. for (Instruction::op_iterator OI = Inst.op_begin(), OE = Inst.op_end(); @@ -144,8 +153,6 @@ bool AAEval::runOnFunction(Function &F) { if (isInterestingPointer(*OI)) Pointers.insert(*OI); } - - if (CS.getInstruction()) CallSites.insert(CS); } if (PrintNoAlias || PrintMayAlias || PrintMustAlias || @@ -197,13 +204,13 @@ bool AAEval::runOnFunction(Function &F) { PrintModRefResults("NoModRef", PrintNoModRef, I, *V, F.getParent()); ++NoModRef; break; case AliasAnalysis::Mod: - PrintModRefResults(" Mod", PrintMod, I, *V, F.getParent()); + PrintModRefResults("Just Mod", PrintMod, I, *V, F.getParent()); ++Mod; break; case AliasAnalysis::Ref: - PrintModRefResults(" Ref", PrintRef, I, *V, F.getParent()); + PrintModRefResults("Just Ref", PrintRef, I, *V, F.getParent()); ++Ref; break; case AliasAnalysis::ModRef: - PrintModRefResults(" ModRef", PrintModRef, I, *V, F.getParent()); + PrintModRefResults("Both ModRef", PrintModRef, I, *V, F.getParent()); ++ModRef; break; default: errs() << "Unknown alias query result!\n"; @@ -211,6 +218,29 @@ bool AAEval::runOnFunction(Function &F) { } } + // Mod/ref alias analysis: compare all pairs of calls + for (SetVector::iterator C = CallSites.begin(), + Ce = CallSites.end(); C != Ce; ++C) { + for (SetVector::iterator D = CallSites.begin(); D != Ce; ++D) { + if (D == C) + continue; + switch (AA.getModRefInfo(*C, *D)) { + case AliasAnalysis::NoModRef: + PrintModRefResults("NoModRef", PrintNoModRef, *C, *D, F.getParent()); + ++NoModRef; break; + case AliasAnalysis::Mod: + PrintModRefResults("Just Mod", PrintMod, *C, *D, F.getParent()); + ++Mod; break; + case AliasAnalysis::Ref: + PrintModRefResults("Just Ref", PrintRef, *C, *D, F.getParent()); + ++Ref; break; + case AliasAnalysis::ModRef: + PrintModRefResults("Both ModRef", PrintModRef, *C, *D, F.getParent()); + ++ModRef; break; + } + } + } + return false; } diff --git a/lib/Analysis/AliasDebugger.cpp b/lib/Analysis/AliasDebugger.cpp index bc2d9c55..b9fe646 100644 --- a/lib/Analysis/AliasDebugger.cpp +++ b/lib/Analysis/AliasDebugger.cpp @@ -39,7 +39,7 @@ namespace { public: static char ID; // Class identification, replacement for typeinfo - AliasDebugger() : ModulePass(&ID) {} + AliasDebugger() : ModulePass(ID) {} bool runOnModule(Module &M) { InitializeAliasAnalysis(this); // set up super class @@ -83,8 +83,8 @@ namespace { /// an analysis interface through multiple inheritance. If needed, it /// should override this to adjust the this pointer as needed for the /// specified pass info. - virtual void *getAdjustedAnalysisPointer(const PassInfo *PI) { - if (PI->isPassID(&AliasAnalysis::ID)) + virtual void *getAdjustedAnalysisPointer(AnalysisID PI) { + if (PI == &AliasAnalysis::ID) return (AliasAnalysis*)this; return this; } @@ -99,12 +99,14 @@ namespace { return AliasAnalysis::alias(V1, V1Size, V2, V2Size); } - ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size) { + ModRefResult getModRefInfo(ImmutableCallSite CS, + const Value *P, unsigned Size) { assert(Vals.find(P) != Vals.end() && "Never seen value in AA before"); return AliasAnalysis::getModRefInfo(CS, P, Size); } - ModRefResult getModRefInfo(CallSite CS1, CallSite CS2) { + ModRefResult getModRefInfo(ImmutableCallSite CS1, + ImmutableCallSite CS2) { return AliasAnalysis::getModRefInfo(CS1,CS2); } @@ -126,9 +128,8 @@ namespace { } char AliasDebugger::ID = 0; -static RegisterPass -X("debug-aa", "AA use debugger", false, true); -static RegisterAnalysisGroup Y(X); +INITIALIZE_AG_PASS(AliasDebugger, AliasAnalysis, "debug-aa", + "AA use debugger", false, true, false); Pass *llvm::createAliasDebugger() { return new AliasDebugger(); } diff --git a/lib/Analysis/AliasSetTracker.cpp b/lib/Analysis/AliasSetTracker.cpp index 02aff50..e74543b 100644 --- a/lib/Analysis/AliasSetTracker.cpp +++ b/lib/Analysis/AliasSetTracker.cpp @@ -22,7 +22,6 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/InstIterator.h" -#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -35,6 +34,7 @@ void AliasSet::mergeSetIn(AliasSet &AS, AliasSetTracker &AST) { // Update the alias and access types of this set... AccessTy |= AS.AccessTy; AliasTy |= AS.AliasTy; + Volatile |= AS.Volatile; if (AliasTy == MustAlias) { // Check that these two merged sets really are must aliases. Since both @@ -111,11 +111,11 @@ void AliasSet::addPointer(AliasSetTracker &AST, PointerRec &Entry, *PtrListEnd = &Entry; PtrListEnd = Entry.setPrevInList(PtrListEnd); assert(*PtrListEnd == 0 && "End of list is not null?"); - addRef(); // Entry points to alias set... + addRef(); // Entry points to alias set. } void AliasSet::addCallSite(CallSite CS, AliasAnalysis &AA) { - CallSites.push_back(CS); + CallSites.push_back(CS.getInstruction()); AliasAnalysis::ModRefBehavior Behavior = AA.getModRefBehavior(CS); if (Behavior == AliasAnalysis::DoesNotAccessMemory) @@ -140,7 +140,7 @@ bool AliasSet::aliasesPointer(const Value *Ptr, unsigned Size, assert(CallSites.empty() && "Illegal must alias set!"); // If this is a set of MustAliases, only check to see if the pointer aliases - // SOME value in the set... + // SOME value in the set. PointerRec *SomePtr = getSomePointer(); assert(SomePtr && "Empty must-alias set??"); return AA.alias(SomePtr->getValue(), SomePtr->getSize(), Ptr, Size); @@ -155,8 +155,7 @@ bool AliasSet::aliasesPointer(const Value *Ptr, unsigned Size, // Check the call sites list and invoke list... if (!CallSites.empty()) { for (unsigned i = 0, e = CallSites.size(); i != e; ++i) - if (AA.getModRefInfo(CallSites[i], const_cast(Ptr), Size) - != AliasAnalysis::NoModRef) + if (AA.getModRefInfo(CallSites[i], Ptr, Size) != AliasAnalysis::NoModRef) return true; } @@ -167,10 +166,11 @@ bool AliasSet::aliasesCallSite(CallSite CS, AliasAnalysis &AA) const { if (AA.doesNotAccessMemory(CS)) return false; - for (unsigned i = 0, e = CallSites.size(); i != e; ++i) - if (AA.getModRefInfo(CallSites[i], CS) != AliasAnalysis::NoModRef || - AA.getModRefInfo(CS, CallSites[i]) != AliasAnalysis::NoModRef) + for (unsigned i = 0, e = CallSites.size(); i != e; ++i) { + if (AA.getModRefInfo(getCallSite(i), CS) != AliasAnalysis::NoModRef || + AA.getModRefInfo(CS, getCallSite(i)) != AliasAnalysis::NoModRef) return true; + } for (iterator I = begin(), E = end(); I != E; ++I) if (AA.getModRefInfo(CS, I.getPointer(), I.getSize()) != @@ -200,14 +200,15 @@ void AliasSetTracker::clear() { AliasSet *AliasSetTracker::findAliasSetForPointer(const Value *Ptr, unsigned Size) { AliasSet *FoundSet = 0; - for (iterator I = begin(), E = end(); I != E; ++I) - if (!I->Forward && I->aliasesPointer(Ptr, Size, AA)) { - if (FoundSet == 0) { // If this is the first alias set ptr can go into. - FoundSet = I; // Remember it. - } else { // Otherwise, we must merge the sets. - FoundSet->mergeSetIn(*I, *this); // Merge in contents. - } + for (iterator I = begin(), E = end(); I != E; ++I) { + if (I->Forward || !I->aliasesPointer(Ptr, Size, AA)) continue; + + if (FoundSet == 0) { // If this is the first alias set ptr can go into. + FoundSet = I; // Remember it. + } else { // Otherwise, we must merge the sets. + FoundSet->mergeSetIn(*I, *this); // Merge in contents. } + } return FoundSet; } @@ -226,15 +227,15 @@ bool AliasSetTracker::containsPointer(Value *Ptr, unsigned Size) const { AliasSet *AliasSetTracker::findAliasSetForCallSite(CallSite CS) { AliasSet *FoundSet = 0; - for (iterator I = begin(), E = end(); I != E; ++I) - if (!I->Forward && I->aliasesCallSite(CS, AA)) { - if (FoundSet == 0) { // If this is the first alias set ptr can go into. - FoundSet = I; // Remember it. - } else if (!I->Forward) { // Otherwise, we must merge the sets. - FoundSet->mergeSetIn(*I, *this); // Merge in contents. - } - } - + for (iterator I = begin(), E = end(); I != E; ++I) { + if (I->Forward || !I->aliasesCallSite(CS, AA)) + continue; + + if (FoundSet == 0) // If this is the first alias set ptr can go into. + FoundSet = I; // Remember it. + else if (!I->Forward) // Otherwise, we must merge the sets. + FoundSet->mergeSetIn(*I, *this); // Merge in contents. + } return FoundSet; } @@ -247,22 +248,24 @@ AliasSet &AliasSetTracker::getAliasSetForPointer(Value *Pointer, unsigned Size, bool *New) { AliasSet::PointerRec &Entry = getEntryFor(Pointer); - // Check to see if the pointer is already known... + // Check to see if the pointer is already known. if (Entry.hasAliasSet()) { Entry.updateSize(Size); // Return the set! return *Entry.getAliasSet(*this)->getForwardedTarget(*this); - } else if (AliasSet *AS = findAliasSetForPointer(Pointer, Size)) { - // Add it to the alias set it aliases... + } + + if (AliasSet *AS = findAliasSetForPointer(Pointer, Size)) { + // Add it to the alias set it aliases. AS->addPointer(*this, Entry, Size); return *AS; - } else { - if (New) *New = true; - // Otherwise create a new alias set to hold the loaded pointer... - AliasSets.push_back(new AliasSet()); - AliasSets.back().addPointer(*this, Entry, Size); - return AliasSets.back(); } + + if (New) *New = true; + // Otherwise create a new alias set to hold the loaded pointer. + AliasSets.push_back(new AliasSet()); + AliasSets.back().addPointer(*this, Entry, Size); + return AliasSets.back(); } bool AliasSetTracker::add(Value *Ptr, unsigned Size) { @@ -305,28 +308,27 @@ bool AliasSetTracker::add(CallSite CS) { return true; // doesn't alias anything AliasSet *AS = findAliasSetForCallSite(CS); - if (!AS) { - AliasSets.push_back(new AliasSet()); - AS = &AliasSets.back(); - AS->addCallSite(CS, AA); - return true; - } else { + if (AS) { AS->addCallSite(CS, AA); return false; } + AliasSets.push_back(new AliasSet()); + AS = &AliasSets.back(); + AS->addCallSite(CS, AA); + return true; } bool AliasSetTracker::add(Instruction *I) { - // Dispatch to one of the other add methods... + // Dispatch to one of the other add methods. if (LoadInst *LI = dyn_cast(I)) return add(LI); - else if (StoreInst *SI = dyn_cast(I)) + if (StoreInst *SI = dyn_cast(I)) return add(SI); - else if (CallInst *CI = dyn_cast(I)) + if (CallInst *CI = dyn_cast(I)) return add(CI); - else if (InvokeInst *II = dyn_cast(I)) + if (InvokeInst *II = dyn_cast(I)) return add(II); - else if (VAArgInst *VAAI = dyn_cast(I)) + if (VAArgInst *VAAI = dyn_cast(I)) return add(VAAI); return true; } @@ -343,23 +345,23 @@ void AliasSetTracker::add(const AliasSetTracker &AST) { // Loop over all of the alias sets in AST, adding the pointers contained // therein into the current alias sets. This can cause alias sets to be // merged together in the current AST. - for (const_iterator I = AST.begin(), E = AST.end(); I != E; ++I) - if (!I->Forward) { // Ignore forwarding alias sets - AliasSet &AS = const_cast(*I); - - // If there are any call sites in the alias set, add them to this AST. - for (unsigned i = 0, e = AS.CallSites.size(); i != e; ++i) - add(AS.CallSites[i]); - - // Loop over all of the pointers in this alias set... - AliasSet::iterator I = AS.begin(), E = AS.end(); - bool X; - for (; I != E; ++I) { - AliasSet &NewAS = addPointer(I.getPointer(), I.getSize(), - (AliasSet::AccessType)AS.AccessTy, X); - if (AS.isVolatile()) NewAS.setVolatile(); - } + for (const_iterator I = AST.begin(), E = AST.end(); I != E; ++I) { + if (I->Forward) continue; // Ignore forwarding alias sets + + AliasSet &AS = const_cast(*I); + + // If there are any call sites in the alias set, add them to this AST. + for (unsigned i = 0, e = AS.CallSites.size(); i != e; ++i) + add(AS.CallSites[i]); + + // Loop over all of the pointers in this alias set. + bool X; + for (AliasSet::iterator ASI = AS.begin(), E = AS.end(); ASI != E; ++ASI) { + AliasSet &NewAS = addPointer(ASI.getPointer(), ASI.getSize(), + (AliasSet::AccessType)AS.AccessTy, X); + if (AS.isVolatile()) NewAS.setVolatile(); } + } } /// remove - Remove the specified (potentially non-empty) alias set from the @@ -435,11 +437,11 @@ bool AliasSetTracker::remove(Instruction *I) { // Dispatch to one of the other remove methods... if (LoadInst *LI = dyn_cast(I)) return remove(LI); - else if (StoreInst *SI = dyn_cast(I)) + if (StoreInst *SI = dyn_cast(I)) return remove(SI); - else if (CallInst *CI = dyn_cast(I)) + if (CallInst *CI = dyn_cast(I)) return remove(CI); - else if (VAArgInst *VAAI = dyn_cast(I)) + if (VAArgInst *VAAI = dyn_cast(I)) return remove(VAAI); return true; } @@ -455,12 +457,17 @@ void AliasSetTracker::deleteValue(Value *PtrVal) { AA.deleteValue(PtrVal); // If this is a call instruction, remove the callsite from the appropriate - // AliasSet. - CallSite CS = CallSite::get(PtrVal); - if (CS.getInstruction()) - if (!AA.doesNotAccessMemory(CS)) - if (AliasSet *AS = findAliasSetForCallSite(CS)) - AS->removeCallSite(CS); + // AliasSet (if present). + if (CallSite CS = PtrVal) { + if (!AA.doesNotAccessMemory(CS)) { + // Scan all the alias sets to see if this call site is contained. + for (iterator I = begin(), E = end(); I != E; ++I) { + if (I->Forward) continue; + + I->removeCallSite(CS); + } + } + } // First, look up the PointerRec for this pointer. PointerMapType::iterator I = PointerMap.find(PtrVal); @@ -510,7 +517,7 @@ void AliasSetTracker::copyValue(Value *From, Value *To) { //===----------------------------------------------------------------------===// void AliasSet::print(raw_ostream &OS) const { - OS << " AliasSet[" << format("0x%p", (void*)this) << "," << RefCount << "] "; + OS << " AliasSet[" << (void*)this << ", " << RefCount << "] "; OS << (AliasTy == MustAlias ? "must" : "may") << " alias, "; switch (AccessTy) { case NoModRef: OS << "No access "; break; @@ -536,7 +543,7 @@ void AliasSet::print(raw_ostream &OS) const { OS << "\n " << CallSites.size() << " Call Sites: "; for (unsigned i = 0, e = CallSites.size(); i != e; ++i) { if (i) OS << ", "; - WriteAsOperand(OS, CallSites[i].getCalledValue()); + WriteAsOperand(OS, CallSites[i]); } } OS << "\n"; @@ -580,7 +587,7 @@ namespace { AliasSetTracker *Tracker; public: static char ID; // Pass identification, replacement for typeid - AliasSetPrinter() : FunctionPass(&ID) {} + AliasSetPrinter() : FunctionPass(ID) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); @@ -600,5 +607,5 @@ namespace { } char AliasSetPrinter::ID = 0; -static RegisterPass -X("print-alias-sets", "Alias Set Printer", false, true); +INITIALIZE_PASS(AliasSetPrinter, "print-alias-sets", + "Alias Set Printer", false, true); diff --git a/lib/Analysis/BasicAliasAnalysis.cpp b/lib/Analysis/BasicAliasAnalysis.cpp index 4f53a6d..113c72b 100644 --- a/lib/Analysis/BasicAliasAnalysis.cpp +++ b/lib/Analysis/BasicAliasAnalysis.cpp @@ -18,6 +18,7 @@ #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" +#include "llvm/GlobalAlias.h" #include "llvm/GlobalVariable.h" #include "llvm/Instructions.h" #include "llvm/IntrinsicInst.h" @@ -30,6 +31,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/GetElementPtrTypeIterator.h" #include using namespace llvm; @@ -137,8 +139,8 @@ namespace { /// struct NoAA : public ImmutablePass, public AliasAnalysis { static char ID; // Class identification, replacement for typeinfo - NoAA() : ImmutablePass(&ID) {} - explicit NoAA(void *PID) : ImmutablePass(PID) { } + NoAA() : ImmutablePass(ID) {} + explicit NoAA(char &PID) : ImmutablePass(PID) { } virtual void getAnalysisUsage(AnalysisUsage &AU) const { } @@ -152,16 +154,20 @@ namespace { return MayAlias; } - virtual void getArgumentAccesses(Function *F, CallSite CS, - std::vector &Info) { - llvm_unreachable("This method may not be called on this function!"); + virtual ModRefBehavior getModRefBehavior(ImmutableCallSite CS) { + return UnknownModRefBehavior; + } + virtual ModRefBehavior getModRefBehavior(const Function *F) { + return UnknownModRefBehavior; } virtual bool pointsToConstantMemory(const Value *P) { return false; } - virtual ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size) { + virtual ModRefResult getModRefInfo(ImmutableCallSite CS, + const Value *P, unsigned Size) { return ModRef; } - virtual ModRefResult getModRefInfo(CallSite CS1, CallSite CS2) { + virtual ModRefResult getModRefInfo(ImmutableCallSite CS1, + ImmutableCallSite CS2) { return ModRef; } @@ -169,11 +175,11 @@ namespace { virtual void copyValue(Value *From, Value *To) {} /// getAdjustedAnalysisPointer - This method is used when a pass implements - /// an analysis interface through multiple inheritance. If needed, it should - /// override this to adjust the this pointer as needed for the specified pass - /// info. - virtual void *getAdjustedAnalysisPointer(const PassInfo *PI) { - if (PI->isPassID(&AliasAnalysis::ID)) + /// an analysis interface through multiple inheritance. If needed, it + /// should override this to adjust the this pointer as needed for the + /// specified pass info. + virtual void *getAdjustedAnalysisPointer(const void *ID) { + if (ID == &AliasAnalysis::ID) return (AliasAnalysis*)this; return this; } @@ -182,15 +188,279 @@ namespace { // Register this pass... char NoAA::ID = 0; -static RegisterPass -U("no-aa", "No Alias Analysis (always returns 'may' alias)", true, true); - -// Declare that we implement the AliasAnalysis interface -static RegisterAnalysisGroup V(U); +INITIALIZE_AG_PASS(NoAA, AliasAnalysis, "no-aa", + "No Alias Analysis (always returns 'may' alias)", + true, true, false); ImmutablePass *llvm::createNoAAPass() { return new NoAA(); } //===----------------------------------------------------------------------===// +// GetElementPtr Instruction Decomposition and Analysis +//===----------------------------------------------------------------------===// + +namespace { + enum ExtensionKind { + EK_NotExtended, + EK_SignExt, + EK_ZeroExt + }; + + struct VariableGEPIndex { + const Value *V; + ExtensionKind Extension; + int64_t Scale; + }; +} + + +/// GetLinearExpression - Analyze the specified value as a linear expression: +/// "A*V + B", where A and B are constant integers. Return the scale and offset +/// values as APInts and return V as a Value*, and return whether we looked +/// through any sign or zero extends. The incoming Value is known to have +/// IntegerType and it may already be sign or zero extended. +/// +/// Note that this looks through extends, so the high bits may not be +/// represented in the result. +static Value *GetLinearExpression(Value *V, APInt &Scale, APInt &Offset, + ExtensionKind &Extension, + const TargetData &TD, unsigned Depth) { + assert(V->getType()->isIntegerTy() && "Not an integer value"); + + // Limit our recursion depth. + if (Depth == 6) { + Scale = 1; + Offset = 0; + return V; + } + + if (BinaryOperator *BOp = dyn_cast(V)) { + if (ConstantInt *RHSC = dyn_cast(BOp->getOperand(1))) { + switch (BOp->getOpcode()) { + default: break; + case Instruction::Or: + // X|C == X+C if all the bits in C are unset in X. Otherwise we can't + // analyze it. + if (!MaskedValueIsZero(BOp->getOperand(0), RHSC->getValue(), &TD)) + break; + // FALL THROUGH. + case Instruction::Add: + V = GetLinearExpression(BOp->getOperand(0), Scale, Offset, Extension, + TD, Depth+1); + Offset += RHSC->getValue(); + return V; + case Instruction::Mul: + V = GetLinearExpression(BOp->getOperand(0), Scale, Offset, Extension, + TD, Depth+1); + Offset *= RHSC->getValue(); + Scale *= RHSC->getValue(); + return V; + case Instruction::Shl: + V = GetLinearExpression(BOp->getOperand(0), Scale, Offset, Extension, + TD, Depth+1); + Offset <<= RHSC->getValue().getLimitedValue(); + Scale <<= RHSC->getValue().getLimitedValue(); + return V; + } + } + } + + // Since GEP indices are sign extended anyway, we don't care about the high + // bits of a sign or zero extended value - just scales and offsets. The + // extensions have to be consistent though. + if ((isa(V) && Extension != EK_ZeroExt) || + (isa(V) && Extension != EK_SignExt)) { + Value *CastOp = cast(V)->getOperand(0); + unsigned OldWidth = Scale.getBitWidth(); + unsigned SmallWidth = CastOp->getType()->getPrimitiveSizeInBits(); + Scale.trunc(SmallWidth); + Offset.trunc(SmallWidth); + Extension = isa(V) ? EK_SignExt : EK_ZeroExt; + + Value *Result = GetLinearExpression(CastOp, Scale, Offset, Extension, + TD, Depth+1); + Scale.zext(OldWidth); + Offset.zext(OldWidth); + + return Result; + } + + Scale = 1; + Offset = 0; + return V; +} + +/// DecomposeGEPExpression - If V is a symbolic pointer expression, decompose it +/// into a base pointer with a constant offset and a number of scaled symbolic +/// offsets. +/// +/// The scaled symbolic offsets (represented by pairs of a Value* and a scale in +/// the VarIndices vector) are Value*'s that are known to be scaled by the +/// specified amount, but which may have other unrepresented high bits. As such, +/// the gep cannot necessarily be reconstructed from its decomposed form. +/// +/// When TargetData is around, this function is capable of analyzing everything +/// that Value::getUnderlyingObject() can look through. When not, it just looks +/// through pointer casts. +/// +static const Value * +DecomposeGEPExpression(const Value *V, int64_t &BaseOffs, + SmallVectorImpl &VarIndices, + const TargetData *TD) { + // Limit recursion depth to limit compile time in crazy cases. + unsigned MaxLookup = 6; + + BaseOffs = 0; + do { + // See if this is a bitcast or GEP. + const Operator *Op = dyn_cast(V); + if (Op == 0) { + // The only non-operator case we can handle are GlobalAliases. + if (const GlobalAlias *GA = dyn_cast(V)) { + if (!GA->mayBeOverridden()) { + V = GA->getAliasee(); + continue; + } + } + return V; + } + + if (Op->getOpcode() == Instruction::BitCast) { + V = Op->getOperand(0); + continue; + } + + const GEPOperator *GEPOp = dyn_cast(Op); + if (GEPOp == 0) + return V; + + // Don't attempt to analyze GEPs over unsized objects. + if (!cast(GEPOp->getOperand(0)->getType()) + ->getElementType()->isSized()) + return V; + + // If we are lacking TargetData information, we can't compute the offets of + // elements computed by GEPs. However, we can handle bitcast equivalent + // GEPs. + if (TD == 0) { + if (!GEPOp->hasAllZeroIndices()) + return V; + V = GEPOp->getOperand(0); + continue; + } + + // Walk the indices of the GEP, accumulating them into BaseOff/VarIndices. + gep_type_iterator GTI = gep_type_begin(GEPOp); + for (User::const_op_iterator I = GEPOp->op_begin()+1, + E = GEPOp->op_end(); I != E; ++I) { + Value *Index = *I; + // Compute the (potentially symbolic) offset in bytes for this index. + if (const StructType *STy = dyn_cast(*GTI++)) { + // For a struct, add the member offset. + unsigned FieldNo = cast(Index)->getZExtValue(); + if (FieldNo == 0) continue; + + BaseOffs += TD->getStructLayout(STy)->getElementOffset(FieldNo); + continue; + } + + // For an array/pointer, add the element offset, explicitly scaled. + if (ConstantInt *CIdx = dyn_cast(Index)) { + if (CIdx->isZero()) continue; + BaseOffs += TD->getTypeAllocSize(*GTI)*CIdx->getSExtValue(); + continue; + } + + uint64_t Scale = TD->getTypeAllocSize(*GTI); + ExtensionKind Extension = EK_NotExtended; + + // If the integer type is smaller than the pointer size, it is implicitly + // sign extended to pointer size. + unsigned Width = cast(Index->getType())->getBitWidth(); + if (TD->getPointerSizeInBits() > Width) + Extension = EK_SignExt; + + // Use GetLinearExpression to decompose the index into a C1*V+C2 form. + APInt IndexScale(Width, 0), IndexOffset(Width, 0); + Index = GetLinearExpression(Index, IndexScale, IndexOffset, Extension, + *TD, 0); + + // The GEP index scale ("Scale") scales C1*V+C2, yielding (C1*V+C2)*Scale. + // This gives us an aggregate computation of (C1*Scale)*V + C2*Scale. + BaseOffs += IndexOffset.getZExtValue()*Scale; + Scale *= IndexScale.getZExtValue(); + + + // If we already had an occurrance of this index variable, merge this + // scale into it. For example, we want to handle: + // A[x][x] -> x*16 + x*4 -> x*20 + // This also ensures that 'x' only appears in the index list once. + for (unsigned i = 0, e = VarIndices.size(); i != e; ++i) { + if (VarIndices[i].V == Index && + VarIndices[i].Extension == Extension) { + Scale += VarIndices[i].Scale; + VarIndices.erase(VarIndices.begin()+i); + break; + } + } + + // Make sure that we have a scale that makes sense for this target's + // pointer size. + if (unsigned ShiftBits = 64-TD->getPointerSizeInBits()) { + Scale <<= ShiftBits; + Scale >>= ShiftBits; + } + + if (Scale) { + VariableGEPIndex Entry = {Index, Extension, Scale}; + VarIndices.push_back(Entry); + } + } + + // Analyze the base pointer next. + V = GEPOp->getOperand(0); + } while (--MaxLookup); + + // If the chain of expressions is too deep, just return early. + return V; +} + +/// GetIndexDifference - Dest and Src are the variable indices from two +/// decomposed GetElementPtr instructions GEP1 and GEP2 which have common base +/// pointers. Subtract the GEP2 indices from GEP1 to find the symbolic +/// difference between the two pointers. +static void GetIndexDifference(SmallVectorImpl &Dest, + const SmallVectorImpl &Src) { + if (Src.empty()) return; + + for (unsigned i = 0, e = Src.size(); i != e; ++i) { + const Value *V = Src[i].V; + ExtensionKind Extension = Src[i].Extension; + int64_t Scale = Src[i].Scale; + + // Find V in Dest. This is N^2, but pointer indices almost never have more + // than a few variable indexes. + for (unsigned j = 0, e = Dest.size(); j != e; ++j) { + if (Dest[j].V != V || Dest[j].Extension != Extension) continue; + + // If we found it, subtract off Scale V's from the entry in Dest. If it + // goes to zero, remove the entry. + if (Dest[j].Scale != Scale) + Dest[j].Scale -= Scale; + else + Dest.erase(Dest.begin()+j); + Scale = 0; + break; + } + + // If we didn't consume this entry, add it to the end of the Dest list. + if (Scale) { + VariableGEPIndex Entry = { V, Extension, -Scale }; + Dest.push_back(Entry); + } + } +} + +//===----------------------------------------------------------------------===// // BasicAliasAnalysis Pass //===----------------------------------------------------------------------===// @@ -220,10 +490,10 @@ namespace { /// derives from the NoAA class. struct BasicAliasAnalysis : public NoAA { static char ID; // Class identification, replacement for typeinfo - BasicAliasAnalysis() : NoAA(&ID) {} + BasicAliasAnalysis() : NoAA(ID) {} - AliasResult alias(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size) { + virtual AliasResult alias(const Value *V1, unsigned V1Size, + const Value *V2, unsigned V2Size) { assert(Visited.empty() && "Visited must be cleared after use!"); assert(notDifferentParent(V1, V2) && "BasicAliasAnalysis doesn't support interprocedural queries."); @@ -232,19 +502,33 @@ namespace { return Alias; } - ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size); - ModRefResult getModRefInfo(CallSite CS1, CallSite CS2); + virtual ModRefResult getModRefInfo(ImmutableCallSite CS, + const Value *P, unsigned Size); + + virtual ModRefResult getModRefInfo(ImmutableCallSite CS1, + ImmutableCallSite CS2) { + // The AliasAnalysis base class has some smarts, lets use them. + return AliasAnalysis::getModRefInfo(CS1, CS2); + } /// pointsToConstantMemory - Chase pointers until we find a (constant /// global) or not. - bool pointsToConstantMemory(const Value *P); + virtual bool pointsToConstantMemory(const Value *P); + + /// getModRefBehavior - Return the behavior when calling the given + /// call site. + virtual ModRefBehavior getModRefBehavior(ImmutableCallSite CS); + + /// getModRefBehavior - Return the behavior when calling the given function. + /// For use when the call site is not known. + virtual ModRefBehavior getModRefBehavior(const Function *F); /// getAdjustedAnalysisPointer - This method is used when a pass implements - /// an analysis interface through multiple inheritance. If needed, it should - /// override this to adjust the this pointer as needed for the specified pass - /// info. - virtual void *getAdjustedAnalysisPointer(const PassInfo *PI) { - if (PI->isPassID(&AliasAnalysis::ID)) + /// an analysis interface through multiple inheritance. If needed, it + /// should override this to adjust the this pointer as needed for the + /// specified pass info. + virtual void *getAdjustedAnalysisPointer(const void *ID) { + if (ID == &AliasAnalysis::ID) return (AliasAnalysis*)this; return this; } @@ -275,11 +559,9 @@ namespace { // Register this pass... char BasicAliasAnalysis::ID = 0; -static RegisterPass -X("basicaa", "Basic Alias Analysis (default AA impl)", false, true); - -// Declare that we implement the AliasAnalysis interface -static RegisterAnalysisGroup Y(X); +INITIALIZE_AG_PASS(BasicAliasAnalysis, AliasAnalysis, "basicaa", + "Basic Alias Analysis (default AA impl)", + false, true, true); ImmutablePass *llvm::createBasicAliasAnalysisPass() { return new BasicAliasAnalysis(); @@ -295,16 +577,50 @@ bool BasicAliasAnalysis::pointsToConstantMemory(const Value *P) { // global to be marked constant in some modules and non-constant in others. // GV may even be a declaration, not a definition. return GV->isConstant(); - return false; + + return NoAA::pointsToConstantMemory(P); } +/// getModRefBehavior - Return the behavior when calling the given call site. +AliasAnalysis::ModRefBehavior +BasicAliasAnalysis::getModRefBehavior(ImmutableCallSite CS) { + if (CS.doesNotAccessMemory()) + // Can't do better than this. + return DoesNotAccessMemory; + + ModRefBehavior Min = UnknownModRefBehavior; + + // If the callsite knows it only reads memory, don't return worse + // than that. + if (CS.onlyReadsMemory()) + Min = OnlyReadsMemory; + + // The AliasAnalysis base class has some smarts, lets use them. + return std::min(AliasAnalysis::getModRefBehavior(CS), Min); +} + +/// getModRefBehavior - Return the behavior when calling the given function. +/// For use when the call site is not known. +AliasAnalysis::ModRefBehavior +BasicAliasAnalysis::getModRefBehavior(const Function *F) { + if (F->doesNotAccessMemory()) + // Can't do better than this. + return DoesNotAccessMemory; + if (F->onlyReadsMemory()) + return OnlyReadsMemory; + if (unsigned id = F->getIntrinsicID()) + return getIntrinsicModRefBehavior(id); + + return NoAA::getModRefBehavior(F); +} /// getModRefInfo - Check to see if the specified callsite can clobber the /// specified memory object. Since we only look at local properties of this /// function, we really can't say much about this query. We do, however, use /// simple "address taken" analysis on local objects. AliasAnalysis::ModRefResult -BasicAliasAnalysis::getModRefInfo(CallSite CS, Value *P, unsigned Size) { +BasicAliasAnalysis::getModRefInfo(ImmutableCallSite CS, + const Value *P, unsigned Size) { assert(notDifferentParent(CS.getInstruction(), P) && "AliasAnalysis query involving multiple functions!"); @@ -316,7 +632,7 @@ BasicAliasAnalysis::getModRefInfo(CallSite CS, Value *P, unsigned Size) { // the current function not to the current function, and a tail callee // may reference them. if (isa(Object)) - if (CallInst *CI = dyn_cast(CS.getInstruction())) + if (const CallInst *CI = dyn_cast(CS.getInstruction())) if (CI->isTailCall()) return NoModRef; @@ -327,7 +643,7 @@ BasicAliasAnalysis::getModRefInfo(CallSite CS, Value *P, unsigned Size) { isNonEscapingLocalObject(Object)) { bool PassedAsArg = false; unsigned ArgNo = 0; - for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end(); + for (ImmutableCallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end(); CI != CE; ++CI, ++ArgNo) { // Only look at the no-capture pointer arguments. if (!(*CI)->getType()->isPointerTy() || @@ -338,7 +654,7 @@ BasicAliasAnalysis::getModRefInfo(CallSite CS, Value *P, unsigned Size) { // is impossible to alias the pointer we're checking. If not, we have to // assume that the call could touch the pointer, even though it doesn't // escape. - if (!isNoAlias(cast(CI), ~0U, P, ~0U)) { + if (!isNoAlias(cast(CI), UnknownSize, P, UnknownSize)) { PassedAsArg = true; break; } @@ -349,127 +665,76 @@ BasicAliasAnalysis::getModRefInfo(CallSite CS, Value *P, unsigned Size) { } // Finally, handle specific knowledge of intrinsics. - IntrinsicInst *II = dyn_cast(CS.getInstruction()); - if (II == 0) - return AliasAnalysis::getModRefInfo(CS, P, Size); - - switch (II->getIntrinsicID()) { - default: break; - case Intrinsic::memcpy: - case Intrinsic::memmove: { - unsigned Len = ~0U; - if (ConstantInt *LenCI = dyn_cast(II->getArgOperand(2))) - Len = LenCI->getZExtValue(); - Value *Dest = II->getArgOperand(0); - Value *Src = II->getArgOperand(1); - if (isNoAlias(Dest, Len, P, Size)) { - if (isNoAlias(Src, Len, P, Size)) - return NoModRef; - return Ref; - } - break; - } - case Intrinsic::memset: - // Since memset is 'accesses arguments' only, the AliasAnalysis base class - // will handle it for the variable length case. - if (ConstantInt *LenCI = dyn_cast(II->getArgOperand(2))) { - unsigned Len = LenCI->getZExtValue(); + const IntrinsicInst *II = dyn_cast(CS.getInstruction()); + if (II != 0) + switch (II->getIntrinsicID()) { + default: break; + case Intrinsic::memcpy: + case Intrinsic::memmove: { + unsigned Len = UnknownSize; + if (ConstantInt *LenCI = dyn_cast(II->getArgOperand(2))) + Len = LenCI->getZExtValue(); Value *Dest = II->getArgOperand(0); - if (isNoAlias(Dest, Len, P, Size)) + Value *Src = II->getArgOperand(1); + if (isNoAlias(Dest, Len, P, Size)) { + if (isNoAlias(Src, Len, P, Size)) + return NoModRef; + return Ref; + } + break; + } + case Intrinsic::memset: + // Since memset is 'accesses arguments' only, the AliasAnalysis base class + // will handle it for the variable length case. + if (ConstantInt *LenCI = dyn_cast(II->getArgOperand(2))) { + unsigned Len = LenCI->getZExtValue(); + Value *Dest = II->getArgOperand(0); + if (isNoAlias(Dest, Len, P, Size)) + return NoModRef; + } + break; + case Intrinsic::atomic_cmp_swap: + case Intrinsic::atomic_swap: + case Intrinsic::atomic_load_add: + case Intrinsic::atomic_load_sub: + case Intrinsic::atomic_load_and: + case Intrinsic::atomic_load_nand: + case Intrinsic::atomic_load_or: + case Intrinsic::atomic_load_xor: + case Intrinsic::atomic_load_max: + case Intrinsic::atomic_load_min: + case Intrinsic::atomic_load_umax: + case Intrinsic::atomic_load_umin: + if (TD) { + Value *Op1 = II->getArgOperand(0); + unsigned Op1Size = TD->getTypeStoreSize(Op1->getType()); + if (isNoAlias(Op1, Op1Size, P, Size)) + return NoModRef; + } + break; + case Intrinsic::lifetime_start: + case Intrinsic::lifetime_end: + case Intrinsic::invariant_start: { + unsigned PtrSize = + cast(II->getArgOperand(0))->getZExtValue(); + if (isNoAlias(II->getArgOperand(1), PtrSize, P, Size)) return NoModRef; + break; } - break; - case Intrinsic::atomic_cmp_swap: - case Intrinsic::atomic_swap: - case Intrinsic::atomic_load_add: - case Intrinsic::atomic_load_sub: - case Intrinsic::atomic_load_and: - case Intrinsic::atomic_load_nand: - case Intrinsic::atomic_load_or: - case Intrinsic::atomic_load_xor: - case Intrinsic::atomic_load_max: - case Intrinsic::atomic_load_min: - case Intrinsic::atomic_load_umax: - case Intrinsic::atomic_load_umin: - if (TD) { - Value *Op1 = II->getArgOperand(0); - unsigned Op1Size = TD->getTypeStoreSize(Op1->getType()); - if (isNoAlias(Op1, Op1Size, P, Size)) + case Intrinsic::invariant_end: { + unsigned PtrSize = + cast(II->getArgOperand(1))->getZExtValue(); + if (isNoAlias(II->getArgOperand(2), PtrSize, P, Size)) return NoModRef; + break; + } } - break; - case Intrinsic::lifetime_start: - case Intrinsic::lifetime_end: - case Intrinsic::invariant_start: { - unsigned PtrSize = cast(II->getArgOperand(0))->getZExtValue(); - if (isNoAlias(II->getArgOperand(1), PtrSize, P, Size)) - return NoModRef; - break; - } - case Intrinsic::invariant_end: { - unsigned PtrSize = cast(II->getArgOperand(1))->getZExtValue(); - if (isNoAlias(II->getArgOperand(2), PtrSize, P, Size)) - return NoModRef; - break; - } - } // The AliasAnalysis base class has some smarts, lets use them. return AliasAnalysis::getModRefInfo(CS, P, Size); } -AliasAnalysis::ModRefResult -BasicAliasAnalysis::getModRefInfo(CallSite CS1, CallSite CS2) { - // If CS1 or CS2 are readnone, they don't interact. - ModRefBehavior CS1B = AliasAnalysis::getModRefBehavior(CS1); - if (CS1B == DoesNotAccessMemory) return NoModRef; - - ModRefBehavior CS2B = AliasAnalysis::getModRefBehavior(CS2); - if (CS2B == DoesNotAccessMemory) return NoModRef; - - // If they both only read from memory, just return ref. - if (CS1B == OnlyReadsMemory && CS2B == OnlyReadsMemory) - return Ref; - - // Otherwise, fall back to NoAA (mod+ref). - return NoAA::getModRefInfo(CS1, CS2); -} - -/// GetIndiceDifference - Dest and Src are the variable indices from two -/// decomposed GetElementPtr instructions GEP1 and GEP2 which have common base -/// pointers. Subtract the GEP2 indices from GEP1 to find the symbolic -/// difference between the two pointers. -static void GetIndiceDifference( - SmallVectorImpl > &Dest, - const SmallVectorImpl > &Src) { - if (Src.empty()) return; - - for (unsigned i = 0, e = Src.size(); i != e; ++i) { - const Value *V = Src[i].first; - int64_t Scale = Src[i].second; - - // Find V in Dest. This is N^2, but pointer indices almost never have more - // than a few variable indexes. - for (unsigned j = 0, e = Dest.size(); j != e; ++j) { - if (Dest[j].first != V) continue; - - // If we found it, subtract off Scale V's from the entry in Dest. If it - // goes to zero, remove the entry. - if (Dest[j].second != Scale) - Dest[j].second -= Scale; - else - Dest.erase(Dest.begin()+j); - Scale = 0; - break; - } - - // If we didn't consume this entry, add it to the end of the Dest list. - if (Scale) - Dest.push_back(std::make_pair(V, -Scale)); - } -} - /// aliasGEP - Provide a bunch of ad-hoc rules to disambiguate a GEP instruction /// against another pointer. We know that V1 is a GEP, but we don't know /// anything about V2. UnderlyingV1 is GEP1->getUnderlyingObject(), @@ -488,13 +753,14 @@ BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size, return MayAlias; int64_t GEP1BaseOffset; - SmallVector, 4> GEP1VariableIndices; + SmallVector GEP1VariableIndices; // If we have two gep instructions with must-alias'ing base pointers, figure // out if the indexes to the GEP tell us anything about the derived pointer. if (const GEPOperator *GEP2 = dyn_cast(V2)) { // Do the base pointers alias? - AliasResult BaseAlias = aliasCheck(UnderlyingV1, ~0U, UnderlyingV2, ~0U); + AliasResult BaseAlias = aliasCheck(UnderlyingV1, UnknownSize, + UnderlyingV2, UnknownSize); // If we get a No or May, then return it immediately, no amount of analysis // will improve this situation. @@ -507,7 +773,7 @@ BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size, DecomposeGEPExpression(GEP1, GEP1BaseOffset, GEP1VariableIndices, TD); int64_t GEP2BaseOffset; - SmallVector, 4> GEP2VariableIndices; + SmallVector GEP2VariableIndices; const Value *GEP2BasePtr = DecomposeGEPExpression(GEP2, GEP2BaseOffset, GEP2VariableIndices, TD); @@ -523,7 +789,7 @@ BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size, // Subtract the GEP2 pointer from the GEP1 pointer to find out their // symbolic difference. GEP1BaseOffset -= GEP2BaseOffset; - GetIndiceDifference(GEP1VariableIndices, GEP2VariableIndices); + GetIndexDifference(GEP1VariableIndices, GEP2VariableIndices); } else { // Check to see if these two pointers are related by the getelementptr @@ -531,10 +797,10 @@ BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size, // pointer, we know they cannot alias. // If both accesses are unknown size, we can't do anything useful here. - if (V1Size == ~0U && V2Size == ~0U) + if (V1Size == UnknownSize && V2Size == UnknownSize) return MayAlias; - AliasResult R = aliasCheck(UnderlyingV1, ~0U, V2, V2Size); + AliasResult R = aliasCheck(UnderlyingV1, UnknownSize, V2, V2Size); if (R != MustAlias) // If V2 may alias GEP base pointer, conservatively returns MayAlias. // If V2 is known not to alias GEP base pointer, then the two values @@ -578,8 +844,8 @@ BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size, // provides an offset of 4 bytes (assuming a <= 4 byte access). for (unsigned i = 0, e = GEP1VariableIndices.size(); i != e && GEP1BaseOffset;++i) - if (int64_t RemovedOffset = GEP1BaseOffset/GEP1VariableIndices[i].second) - GEP1BaseOffset -= RemovedOffset*GEP1VariableIndices[i].second; + if (int64_t RemovedOffset = GEP1BaseOffset/GEP1VariableIndices[i].Scale) + GEP1BaseOffset -= RemovedOffset*GEP1VariableIndices[i].Scale; // If our known offset is bigger than the access size, we know we don't have // an alias. @@ -782,8 +1048,8 @@ BasicAliasAnalysis::aliasCheck(const Value *V1, unsigned V1Size, // If the size of one access is larger than the entire object on the other // side, then we know such behavior is undefined and can assume no alias. if (TD) - if ((V1Size != ~0U && isObjectSmallerThan(O2, V1Size, *TD)) || - (V2Size != ~0U && isObjectSmallerThan(O1, V2Size, *TD))) + if ((V1Size != UnknownSize && isObjectSmallerThan(O2, V1Size, *TD)) || + (V2Size != UnknownSize && isObjectSmallerThan(O1, V2Size, *TD))) return NoAlias; // FIXME: This isn't aggressively handling alias(GEP, PHI) for example: if the @@ -810,7 +1076,7 @@ BasicAliasAnalysis::aliasCheck(const Value *V1, unsigned V1Size, if (const SelectInst *S1 = dyn_cast(V1)) return aliasSelect(S1, V1Size, V2, V2Size); - return MayAlias; + return NoAA::alias(V1, V1Size, V2, V2Size); } // Make sure that anything that uses AliasAnalysis pulls in this file. diff --git a/lib/Analysis/CFGPrinter.cpp b/lib/Analysis/CFGPrinter.cpp index e06704b..617a362 100644 --- a/lib/Analysis/CFGPrinter.cpp +++ b/lib/Analysis/CFGPrinter.cpp @@ -25,7 +25,7 @@ using namespace llvm; namespace { struct CFGViewer : public FunctionPass { static char ID; // Pass identifcation, replacement for typeid - CFGViewer() : FunctionPass(&ID) {} + CFGViewer() : FunctionPass(ID) {} virtual bool runOnFunction(Function &F) { F.viewCFG(); @@ -41,13 +41,12 @@ namespace { } char CFGViewer::ID = 0; -static RegisterPass -V0("view-cfg", "View CFG of function", false, true); +INITIALIZE_PASS(CFGViewer, "view-cfg", "View CFG of function", false, true); namespace { struct CFGOnlyViewer : public FunctionPass { static char ID; // Pass identifcation, replacement for typeid - CFGOnlyViewer() : FunctionPass(&ID) {} + CFGOnlyViewer() : FunctionPass(ID) {} virtual bool runOnFunction(Function &F) { F.viewCFGOnly(); @@ -63,15 +62,14 @@ namespace { } char CFGOnlyViewer::ID = 0; -static RegisterPass -V1("view-cfg-only", - "View CFG of function (with no function bodies)", false, true); +INITIALIZE_PASS(CFGOnlyViewer, "view-cfg-only", + "View CFG of function (with no function bodies)", false, true); namespace { struct CFGPrinter : public FunctionPass { static char ID; // Pass identification, replacement for typeid - CFGPrinter() : FunctionPass(&ID) {} - explicit CFGPrinter(void *pid) : FunctionPass(pid) {} + CFGPrinter() : FunctionPass(ID) {} + explicit CFGPrinter(char &pid) : FunctionPass(pid) {} virtual bool runOnFunction(Function &F) { std::string Filename = "cfg." + F.getNameStr() + ".dot"; @@ -97,14 +95,14 @@ namespace { } char CFGPrinter::ID = 0; -static RegisterPass -P1("dot-cfg", "Print CFG of function to 'dot' file", false, true); +INITIALIZE_PASS(CFGPrinter, "dot-cfg", "Print CFG of function to 'dot' file", + false, true); namespace { struct CFGOnlyPrinter : public FunctionPass { static char ID; // Pass identification, replacement for typeid - CFGOnlyPrinter() : FunctionPass(&ID) {} - explicit CFGOnlyPrinter(void *pid) : FunctionPass(pid) {} + CFGOnlyPrinter() : FunctionPass(ID) {} + explicit CFGOnlyPrinter(char &pid) : FunctionPass(pid) {} virtual bool runOnFunction(Function &F) { std::string Filename = "cfg." + F.getNameStr() + ".dot"; errs() << "Writing '" << Filename << "'..."; @@ -128,9 +126,9 @@ namespace { } char CFGOnlyPrinter::ID = 0; -static RegisterPass -P2("dot-cfg-only", - "Print CFG of function to 'dot' file (with no function bodies)", false, true); +INITIALIZE_PASS(CFGOnlyPrinter, "dot-cfg-only", + "Print CFG of function to 'dot' file (with no function bodies)", + false, true); /// viewCFG - This function is meant for use from the debugger. You can just /// say 'call F->viewCFG()' and a ghostview window should pop up from the diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index d9b670d..6a2ab68 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -38,12 +38,15 @@ add_llvm_library(LLVMAnalysis ProfileInfoLoader.cpp ProfileInfoLoaderPass.cpp ProfileVerifierPass.cpp + RegionInfo.cpp + RegionPrinter.cpp ScalarEvolution.cpp ScalarEvolutionAliasAnalysis.cpp ScalarEvolutionExpander.cpp ScalarEvolutionNormalization.cpp SparsePropagation.cpp Trace.cpp + TypeBasedAliasAnalysis.cpp ValueTracking.cpp ) diff --git a/lib/Analysis/CaptureTracking.cpp b/lib/Analysis/CaptureTracking.cpp index 0478258..90eae20 100644 --- a/lib/Analysis/CaptureTracking.cpp +++ b/lib/Analysis/CaptureTracking.cpp @@ -69,7 +69,7 @@ bool llvm::PointerMayBeCaptured(const Value *V, switch (I->getOpcode()) { case Instruction::Call: case Instruction::Invoke: { - CallSite CS = CallSite::get(I); + CallSite CS(I); // Not captured if the callee is readonly, doesn't return a copy through // its return value and doesn't unwind (a readonly function can leak bits // by throwing an exception or not depending on the input value). diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp index 13d8f4d..0bf7967 100644 --- a/lib/Analysis/ConstantFolding.cpp +++ b/lib/Analysis/ConstantFolding.cpp @@ -778,9 +778,9 @@ Constant *llvm::ConstantFoldInstOperands(unsigned Opcode, const Type *DestTy, case Instruction::ICmp: case Instruction::FCmp: assert(0 && "Invalid for compares"); case Instruction::Call: - if (Function *F = dyn_cast(Ops[CallInst::ArgOffset ? 0:NumOps-1])) + if (Function *F = dyn_cast(Ops[NumOps - 1])) if (canConstantFoldCallTo(F)) - return ConstantFoldCall(F, Ops+CallInst::ArgOffset, NumOps-1); + return ConstantFoldCall(F, Ops, NumOps - 1); return 0; case Instruction::PtrToInt: // If the input is a inttoptr, eliminate the pair. This requires knowing diff --git a/lib/Analysis/DbgInfoPrinter.cpp b/lib/Analysis/DbgInfoPrinter.cpp index 3532b05..0567750 100644 --- a/lib/Analysis/DbgInfoPrinter.cpp +++ b/lib/Analysis/DbgInfoPrinter.cpp @@ -40,7 +40,7 @@ namespace { void printVariableDeclaration(const Value *V); public: static char ID; // Pass identification - PrintDbgInfo() : FunctionPass(&ID), Out(outs()) {} + PrintDbgInfo() : FunctionPass(ID), Out(errs()) {} virtual bool runOnFunction(Function &F); virtual void getAnalysisUsage(AnalysisUsage &AU) const { @@ -48,8 +48,8 @@ namespace { } }; char PrintDbgInfo::ID = 0; - static RegisterPass X("print-dbginfo", - "Print debug info in human readable form"); + INITIALIZE_PASS(PrintDbgInfo, "print-dbginfo", + "Print debug info in human readable form", false, false); } FunctionPass *llvm::createDbgInfoPrinterPass() { return new PrintDbgInfo(); } diff --git a/lib/Analysis/DebugInfo.cpp b/lib/Analysis/DebugInfo.cpp index c8d0d22..5ca89c6 100644 --- a/lib/Analysis/DebugInfo.cpp +++ b/lib/Analysis/DebugInfo.cpp @@ -13,7 +13,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/DebugInfo.h" -#include "llvm/Target/TargetMachine.h" // FIXME: LAYERING VIOLATION! #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Intrinsics.h" @@ -22,6 +21,8 @@ #include "llvm/Module.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/raw_ostream.h" @@ -32,7 +33,22 @@ using namespace llvm::dwarf; // DIDescriptor //===----------------------------------------------------------------------===// -StringRef +DIDescriptor::DIDescriptor(const DIFile F) : DbgNode(F.DbgNode) { +} + +DIDescriptor::DIDescriptor(const DISubprogram F) : DbgNode(F.DbgNode) { +} + +DIDescriptor::DIDescriptor(const DILexicalBlock F) : DbgNode(F.DbgNode) { +} + +DIDescriptor::DIDescriptor(const DIVariable F) : DbgNode(F.DbgNode) { +} + +DIDescriptor::DIDescriptor(const DIType F) : DbgNode(F.DbgNode) { +} + +StringRef DIDescriptor::getStringField(unsigned Elt) const { if (DbgNode == 0) return StringRef(); @@ -60,7 +76,8 @@ DIDescriptor DIDescriptor::getDescriptorField(unsigned Elt) const { return DIDescriptor(); if (Elt < DbgNode->getNumOperands()) - return DIDescriptor(dyn_cast_or_null(DbgNode->getOperand(Elt))); + return + DIDescriptor(dyn_cast_or_null(DbgNode->getOperand(Elt))); return DIDescriptor(); } @@ -73,6 +90,15 @@ GlobalVariable *DIDescriptor::getGlobalVariableField(unsigned Elt) const { return 0; } +Constant *DIDescriptor::getConstantField(unsigned Elt) const { + if (DbgNode == 0) + return 0; + + if (Elt < DbgNode->getNumOperands()) + return dyn_cast_or_null(DbgNode->getOperand(Elt)); + return 0; +} + Function *DIDescriptor::getFunctionField(unsigned Elt) const { if (DbgNode == 0) return 0; @@ -109,6 +135,7 @@ bool DIDescriptor::isDerivedType() const { case dwarf::DW_TAG_restrict_type: case dwarf::DW_TAG_member: case dwarf::DW_TAG_inheritance: + case dwarf::DW_TAG_friend: return true; default: // CompositeTypes are currently modelled as DerivedTypes. @@ -161,7 +188,8 @@ bool DIDescriptor::isSubprogram() const { /// isGlobalVariable - Return true if the specified tag is legal for /// DIGlobalVariable. bool DIDescriptor::isGlobalVariable() const { - return DbgNode && getTag() == dwarf::DW_TAG_variable; + return DbgNode && (getTag() == dwarf::DW_TAG_variable || + getTag() == dwarf::DW_TAG_constant); } /// isGlobal - Return true if the specified tag is legal for DIGlobal. @@ -233,9 +261,8 @@ unsigned DIArray::getNumElements() const { } /// replaceAllUsesWith - Replace all uses of debug info referenced by -/// this descriptor. After this completes, the current debug info value -/// is erased. -void DIDerivedType::replaceAllUsesWith(DIDescriptor &D) { +/// this descriptor. +void DIType::replaceAllUsesWith(DIDescriptor &D) { if (!DbgNode) return; @@ -249,7 +276,7 @@ void DIDerivedType::replaceAllUsesWith(DIDescriptor &D) { const MDNode *DN = D; const Value *V = cast_or_null(DN); Node->replaceAllUsesWith(const_cast(V)); - Node->destroy(); + MDNode::deleteTemporary(Node); } } @@ -277,6 +304,16 @@ bool DIType::Verify() const { return true; } +/// Verify - Verify that a basic type descriptor is well formed. +bool DIBasicType::Verify() const { + return isBasicType(); +} + +/// Verify - Verify that a derived type descriptor is well formed. +bool DIDerivedType::Verify() const { + return isDerivedType(); +} + /// Verify - Verify that a composite type descriptor is well formed. bool DICompositeType::Verify() const { if (!DbgNode) @@ -327,7 +364,7 @@ bool DIGlobalVariable::Verify() const { if (!Ty.Verify()) return false; - if (!getGlobal()) + if (!getGlobal() && !getConstant()) return false; return true; @@ -355,7 +392,7 @@ bool DIVariable::Verify() const { bool DILocation::Verify() const { if (!DbgNode) return false; - + return DbgNode->getNumOperands() == 4; } @@ -378,7 +415,7 @@ uint64_t DIDerivedType::getOriginalTypeSize() const { Tag == dwarf::DW_TAG_const_type || Tag == dwarf::DW_TAG_volatile_type || Tag == dwarf::DW_TAG_restrict_type) { DIType BaseType = getTypeDerivedFrom(); - // If this type is not derived from any type then take conservative + // If this type is not derived from any type then take conservative // approach. if (!BaseType.isValid()) return getSizeInBits(); @@ -387,17 +424,17 @@ uint64_t DIDerivedType::getOriginalTypeSize() const { else return BaseType.getSizeInBits(); } - + return getSizeInBits(); } -/// isInlinedFnArgument - Return trule if this variable provides debugging +/// isInlinedFnArgument - Return true if this variable provides debugging /// information for an inlined function arguments. bool DIVariable::isInlinedFnArgument(const Function *CurFn) { assert(CurFn && "Invalid function"); if (!getContext().isSubprogram()) return false; - // This variable is not inlined function argument if its scope + // This variable is not inlined function argument if its scope // does not describe current function. return !(DISubprogram(getContext()).describes(CurFn)); } @@ -416,7 +453,7 @@ bool DISubprogram::describes(const Function *F) { return false; } -unsigned DISubprogram::isOptimized() const { +unsigned DISubprogram::isOptimized() const { assert (DbgNode && "Invalid subprogram descriptor!"); if (DbgNode->getNumOperands() == 16) return getUnsignedField(15); @@ -426,7 +463,7 @@ unsigned DISubprogram::isOptimized() const { StringRef DIScope::getFilename() const { if (!DbgNode) return StringRef(); - if (isLexicalBlock()) + if (isLexicalBlock()) return DILexicalBlock(DbgNode).getFilename(); if (isSubprogram()) return DISubprogram(DbgNode).getFilename(); @@ -445,7 +482,7 @@ StringRef DIScope::getFilename() const { StringRef DIScope::getDirectory() const { if (!DbgNode) return StringRef(); - if (isLexicalBlock()) + if (isLexicalBlock()) return DILexicalBlock(DbgNode).getDirectory(); if (isSubprogram()) return DISubprogram(DbgNode).getDirectory(); @@ -899,7 +936,26 @@ DICompositeType DIFactory::CreateCompositeType(unsigned Tag, ConstantInt::get(Type::getInt32Ty(VMContext), RuntimeLang), ContainingType }; - return DICompositeType(MDNode::get(VMContext, &Elts[0], 13)); + + MDNode *Node = MDNode::get(VMContext, &Elts[0], 13); + // Create a named metadata so that we do not lose this enum info. + if (Tag == dwarf::DW_TAG_enumeration_type) { + NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.enum"); + NMD->addOperand(Node); + } + return DICompositeType(Node); +} + + +/// CreateTemporaryType - Create a temporary forward-declared type. +DIType DIFactory::CreateTemporaryType() { + // Give the temporary MDNode a tag. It doesn't matter what tag we + // use here as long as DIType accepts it. + Value *Elts[] = { + GetTagConstant(DW_TAG_base_type) + }; + MDNode *Node = MDNode::getTemporary(VMContext, Elts, array_lengthof(Elts)); + return DIType(Node); } @@ -915,8 +971,8 @@ DICompositeType DIFactory::CreateCompositeTypeEx(unsigned Tag, unsigned Flags, DIType DerivedFrom, DIArray Elements, - unsigned RuntimeLang) { - + unsigned RuntimeLang, + MDNode *ContainingType) { Value *Elts[] = { GetTagConstant(Tag), Context, @@ -929,9 +985,16 @@ DICompositeType DIFactory::CreateCompositeTypeEx(unsigned Tag, ConstantInt::get(Type::getInt32Ty(VMContext), Flags), DerivedFrom, Elements, - ConstantInt::get(Type::getInt32Ty(VMContext), RuntimeLang) + ConstantInt::get(Type::getInt32Ty(VMContext), RuntimeLang), + ContainingType }; - return DICompositeType(MDNode::get(VMContext, &Elts[0], 12)); + MDNode *Node = MDNode::get(VMContext, &Elts[0], 13); + // Create a named metadata so that we do not lose this enum info. + if (Tag == dwarf::DW_TAG_enumeration_type) { + NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.enum"); + NMD->addOperand(Node); + } + return DICompositeType(Node); } @@ -980,8 +1043,8 @@ DISubprogram DIFactory::CreateSubprogram(DIDescriptor Context, } /// CreateSubprogramDefinition - Create new subprogram descriptor for the -/// given declaration. -DISubprogram DIFactory::CreateSubprogramDefinition(DISubprogram &SPDeclaration) { +/// given declaration. +DISubprogram DIFactory::CreateSubprogramDefinition(DISubprogram &SPDeclaration){ if (SPDeclaration.isDefinition()) return DISubprogram(SPDeclaration); @@ -1046,6 +1109,38 @@ DIFactory::CreateGlobalVariable(DIDescriptor Context, StringRef Name, return DIGlobalVariable(Node); } +/// CreateGlobalVariable - Create a new descriptor for the specified constant. +DIGlobalVariable +DIFactory::CreateGlobalVariable(DIDescriptor Context, StringRef Name, + StringRef DisplayName, + StringRef LinkageName, + DIFile F, + unsigned LineNo, DIType Ty,bool isLocalToUnit, + bool isDefinition, llvm::Constant *Val) { + Value *Elts[] = { + GetTagConstant(dwarf::DW_TAG_variable), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + Context, + MDString::get(VMContext, Name), + MDString::get(VMContext, DisplayName), + MDString::get(VMContext, LinkageName), + F, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNo), + Ty, + ConstantInt::get(Type::getInt1Ty(VMContext), isLocalToUnit), + ConstantInt::get(Type::getInt1Ty(VMContext), isDefinition), + Val + }; + + Value *const *Vs = &Elts[0]; + MDNode *Node = MDNode::get(VMContext,Vs, 12); + + // Create a named metadata so that we do not lose this mdnode. + NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.gv"); + NMD->addOperand(Node); + + return DIGlobalVariable(Node); +} /// CreateVariable - Create a new descriptor for the specified variable. DIVariable DIFactory::CreateVariable(unsigned Tag, DIDescriptor Context, @@ -1073,10 +1168,10 @@ DIVariable DIFactory::CreateVariable(unsigned Tag, DIDescriptor Context, char One = '\1'; if (FName.startswith(StringRef(&One, 1))) FName = FName.substr(1); - NamedMDNode *FnLocals = M.getNamedMetadata(Twine("llvm.dbg.lv.", FName)); - if (!FnLocals) - FnLocals = NamedMDNode::Create(VMContext, Twine("llvm.dbg.lv.", FName), - NULL, 0, &M); + + SmallString<32> Out; + NamedMDNode *FnLocals = + M.getOrInsertNamedMetadata(Twine("llvm.dbg.lv.", FName).toStringRef(Out)); FnLocals->addOperand(Node); } return DIVariable(Node); @@ -1089,7 +1184,7 @@ DIVariable DIFactory::CreateComplexVariable(unsigned Tag, DIDescriptor Context, const std::string &Name, DIFile F, unsigned LineNo, - DIType Ty, + DIType Ty, SmallVector &addr) { SmallVector Elts; Elts.push_back(GetTagConstant(Tag)); @@ -1107,14 +1202,19 @@ DIVariable DIFactory::CreateComplexVariable(unsigned Tag, DIDescriptor Context, /// CreateBlock - This creates a descriptor for a lexical block with the /// specified parent VMContext. DILexicalBlock DIFactory::CreateLexicalBlock(DIDescriptor Context, - unsigned LineNo, unsigned Col) { + DIFile F, unsigned LineNo, + unsigned Col) { + // Defeat MDNode uniqing for lexical blocks. + static unsigned int unique_id = 0; Value *Elts[] = { GetTagConstant(dwarf::DW_TAG_lexical_block), Context, ConstantInt::get(Type::getInt32Ty(VMContext), LineNo), - ConstantInt::get(Type::getInt32Ty(VMContext), Col) + ConstantInt::get(Type::getInt32Ty(VMContext), Col), + F, + ConstantInt::get(Type::getInt32Ty(VMContext), unique_id++) }; - return DILexicalBlock(MDNode::get(VMContext, &Elts[0], 4)); + return DILexicalBlock(MDNode::get(VMContext, &Elts[0], 6)); } /// CreateNameSpace - This creates new descriptor for a namespace @@ -1174,7 +1274,7 @@ Instruction *DIFactory::InsertDeclare(Value *Storage, DIVariable D, // If this block already has a terminator then insert this intrinsic // before the terminator. - if (TerminatorInst *T = InsertAtEnd->getTerminator()) + if (TerminatorInst *T = InsertAtEnd->getTerminator()) return CallInst::Create(DeclareFn, Args, Args+2, "", T); else return CallInst::Create(DeclareFn, Args, Args+2, "", InsertAtEnd);} @@ -1203,7 +1303,7 @@ Instruction *DIFactory::InsertDbgValueIntrinsic(Value *V, uint64_t Offset, if (!ValueFn) ValueFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_value); - Value *Args[] = { MDNode::get(V->getContext(), &V, 1), + Value *Args[] = { MDNode::get(V->getContext(), &V, 1), ConstantInt::get(Type::getInt64Ty(V->getContext()), Offset), D }; return CallInst::Create(ValueFn, Args, Args+3, "", InsertAtEnd); @@ -1221,21 +1321,21 @@ void DebugInfoFinder::processModule(Module &M) { ++BI) { if (DbgDeclareInst *DDI = dyn_cast(BI)) processDeclare(DDI); - + DebugLoc Loc = BI->getDebugLoc(); if (Loc.isUnknown()) continue; - + LLVMContext &Ctx = BI->getContext(); DIDescriptor Scope(Loc.getScope(Ctx)); - + if (Scope.isCompileUnit()) addCompileUnit(DICompileUnit(Scope)); else if (Scope.isSubprogram()) processSubprogram(DISubprogram(Scope)); else if (Scope.isLexicalBlock()) processLexicalBlock(DILexicalBlock(Scope)); - + if (MDNode *IA = Loc.getInlinedAt(Ctx)) processLocation(DILocation(IA)); } @@ -1380,7 +1480,7 @@ static Value *findDbgGlobalDeclare(GlobalVariable *V) { return 0; for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { - DIDescriptor DIG(cast_or_null(NMD->getOperand(i))); + DIDescriptor DIG(cast(NMD->getOperand(i))); if (!DIG.isGlobalVariable()) continue; if (DIGlobalVariable(DIG).getGlobal() == V) @@ -1393,16 +1493,16 @@ static Value *findDbgGlobalDeclare(GlobalVariable *V) { /// It looks through pointer casts too. static const DbgDeclareInst *findDbgDeclare(const Value *V) { V = V->stripPointerCasts(); - + if (!isa(V) && !isa(V)) return 0; - + const Function *F = NULL; if (const Instruction *I = dyn_cast(V)) F = I->getParent()->getParent(); else if (const Argument *A = dyn_cast(V)) F = A->getParent(); - + for (Function::const_iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) for (BasicBlock::const_iterator BI = (*FI).begin(), BE = (*FI).end(); BI != BE; ++BI) @@ -1460,10 +1560,10 @@ DISubprogram llvm::getDISubprogram(const MDNode *Scope) { DIDescriptor D(Scope); if (D.isSubprogram()) return DISubprogram(Scope); - + if (D.isLexicalBlock()) return getDISubprogram(DILexicalBlock(Scope).getContext()); - + return DISubprogram(); } @@ -1471,9 +1571,9 @@ DISubprogram llvm::getDISubprogram(const MDNode *Scope) { DICompositeType llvm::getDICompositeType(DIType T) { if (T.isCompositeType()) return DICompositeType(T); - + if (T.isDerivedType()) return getDICompositeType(DIDerivedType(T).getTypeDerivedFrom()); - + return DICompositeType(); } diff --git a/lib/Analysis/DomPrinter.cpp b/lib/Analysis/DomPrinter.cpp index d95c376..9f34094 100644 --- a/lib/Analysis/DomPrinter.cpp +++ b/lib/Analysis/DomPrinter.cpp @@ -86,99 +86,100 @@ namespace { struct DomViewer : public DOTGraphTraitsViewer { static char ID; - DomViewer() : DOTGraphTraitsViewer("dom", &ID){} + DomViewer() : DOTGraphTraitsViewer("dom", ID){} }; struct DomOnlyViewer : public DOTGraphTraitsViewer { static char ID; - DomOnlyViewer() : DOTGraphTraitsViewer("domonly", &ID){} + DomOnlyViewer() : DOTGraphTraitsViewer("domonly", ID){} }; struct PostDomViewer : public DOTGraphTraitsViewer { static char ID; PostDomViewer() : - DOTGraphTraitsViewer("postdom", &ID){} + DOTGraphTraitsViewer("postdom", ID){} }; struct PostDomOnlyViewer : public DOTGraphTraitsViewer { static char ID; PostDomOnlyViewer() : - DOTGraphTraitsViewer("postdomonly", &ID){} + DOTGraphTraitsViewer("postdomonly", ID){} }; } // end anonymous namespace char DomViewer::ID = 0; -RegisterPass A("view-dom", - "View dominance tree of function"); +INITIALIZE_PASS(DomViewer, "view-dom", + "View dominance tree of function", false, false); char DomOnlyViewer::ID = 0; -RegisterPass B("view-dom-only", - "View dominance tree of function " - "(with no function bodies)"); +INITIALIZE_PASS(DomOnlyViewer, "view-dom-only", + "View dominance tree of function (with no function bodies)", + false, false); char PostDomViewer::ID = 0; -RegisterPass C("view-postdom", - "View postdominance tree of function"); +INITIALIZE_PASS(PostDomViewer, "view-postdom", + "View postdominance tree of function", false, false); char PostDomOnlyViewer::ID = 0; -RegisterPass D("view-postdom-only", - "View postdominance tree of function " - "(with no function bodies)"); +INITIALIZE_PASS(PostDomOnlyViewer, "view-postdom-only", + "View postdominance tree of function " + "(with no function bodies)", + false, false); namespace { struct DomPrinter : public DOTGraphTraitsPrinter { static char ID; - DomPrinter() : DOTGraphTraitsPrinter("dom", &ID) {} + DomPrinter() : DOTGraphTraitsPrinter("dom", ID) {} }; struct DomOnlyPrinter : public DOTGraphTraitsPrinter { static char ID; - DomOnlyPrinter() : DOTGraphTraitsPrinter("domonly", &ID) {} + DomOnlyPrinter() : DOTGraphTraitsPrinter("domonly", ID) {} }; struct PostDomPrinter : public DOTGraphTraitsPrinter { static char ID; PostDomPrinter() : - DOTGraphTraitsPrinter("postdom", &ID) {} + DOTGraphTraitsPrinter("postdom", ID) {} }; struct PostDomOnlyPrinter : public DOTGraphTraitsPrinter { static char ID; PostDomOnlyPrinter() : - DOTGraphTraitsPrinter("postdomonly", &ID) {} + DOTGraphTraitsPrinter("postdomonly", ID) {} }; } // end anonymous namespace char DomPrinter::ID = 0; -RegisterPass E("dot-dom", - "Print dominance tree of function " - "to 'dot' file"); +INITIALIZE_PASS(DomPrinter, "dot-dom", + "Print dominance tree of function to 'dot' file", + false, false); char DomOnlyPrinter::ID = 0; -RegisterPass F("dot-dom-only", - "Print dominance tree of function " - "to 'dot' file " - "(with no function bodies)"); +INITIALIZE_PASS(DomOnlyPrinter, "dot-dom-only", + "Print dominance tree of function to 'dot' file " + "(with no function bodies)", + false, false); char PostDomPrinter::ID = 0; -RegisterPass G("dot-postdom", - "Print postdominance tree of function " - "to 'dot' file"); +INITIALIZE_PASS(PostDomPrinter, "dot-postdom", + "Print postdominance tree of function to 'dot' file", + false, false); char PostDomOnlyPrinter::ID = 0; -RegisterPass H("dot-postdom-only", - "Print postdominance tree of function " - "to 'dot' file " - "(with no function bodies)"); +INITIALIZE_PASS(PostDomOnlyPrinter, "dot-postdom-only", + "Print postdominance tree of function to 'dot' file " + "(with no function bodies)", + false, false); // Create methods available outside of this file, to use them // "include/llvm/LinkAllPasses.h". Otherwise the pass would be deleted by diff --git a/lib/Analysis/IPA/CallGraph.cpp b/lib/Analysis/IPA/CallGraph.cpp index 65c7c6e..b363528 100644 --- a/lib/Analysis/IPA/CallGraph.cpp +++ b/lib/Analysis/IPA/CallGraph.cpp @@ -42,7 +42,7 @@ class BasicCallGraph : public ModulePass, public CallGraph { public: static char ID; // Class identification, replacement for typeinfo - BasicCallGraph() : ModulePass(&ID), Root(0), + BasicCallGraph() : ModulePass(ID), Root(0), ExternalCallingNode(0), CallsExternalNode(0) {} // runOnModule - Compute the call graph for the specified module. @@ -86,8 +86,8 @@ public: /// an analysis interface through multiple inheritance. If needed, it should /// override this to adjust the this pointer as needed for the specified pass /// info. - virtual void *getAdjustedAnalysisPointer(const PassInfo *PI) { - if (PI->isPassID(&CallGraph::ID)) + virtual void *getAdjustedAnalysisPointer(AnalysisID PI) { + if (PI == &CallGraph::ID) return (CallGraph*)this; return this; } @@ -145,8 +145,8 @@ private: for (Function::iterator BB = F->begin(), BBE = F->end(); BB != BBE; ++BB) for (BasicBlock::iterator II = BB->begin(), IE = BB->end(); II != IE; ++II) { - CallSite CS = CallSite::get(II); - if (CS.getInstruction() && !isa(II)) { + CallSite CS(cast(II)); + if (CS && !isa(II)) { const Function *Callee = CS.getCalledFunction(); if (Callee) Node->addCalledFunction(CS, getOrInsertFunction(Callee)); @@ -172,9 +172,8 @@ private: } //End anonymous namespace static RegisterAnalysisGroup X("Call Graph"); -static RegisterPass -Y("basiccg", "Basic CallGraph Construction", false, true); -static RegisterAnalysisGroup Z(Y); +INITIALIZE_AG_PASS(BasicCallGraph, CallGraph, "basiccg", + "Basic CallGraph Construction", false, true, true); char CallGraph::ID = 0; char BasicCallGraph::ID = 0; diff --git a/lib/Analysis/IPA/CallGraphSCCPass.cpp b/lib/Analysis/IPA/CallGraphSCCPass.cpp index 0c01ee5..b7a27cb 100644 --- a/lib/Analysis/IPA/CallGraphSCCPass.cpp +++ b/lib/Analysis/IPA/CallGraphSCCPass.cpp @@ -45,7 +45,7 @@ class CGPassManager : public ModulePass, public PMDataManager { public: static char ID; explicit CGPassManager(int Depth) - : ModulePass(&ID), PMDataManager(Depth) { } + : ModulePass(ID), PMDataManager(Depth) { } /// run - Execute all of the passes scheduled for execution. Keep track of /// whether any of the passes modifies the module, and if so, return true. @@ -209,7 +209,7 @@ bool CGPassManager::RefreshCallGraph(CallGraphSCC &CurSCC, // If the call edge is not from a call or invoke, then the function // pass RAUW'd a call with another value. This can happen when // constant folding happens of well known functions etc. - CallSite::get(I->first).getInstruction() == 0) { + !CallSite(I->first)) { assert(!CheckingMode && "CallGraphSCCPass did not update the CallGraph correctly!"); @@ -245,8 +245,8 @@ bool CGPassManager::RefreshCallGraph(CallGraphSCC &CurSCC, for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { - CallSite CS = CallSite::get(I); - if (!CS.getInstruction() || isa(I)) continue; + CallSite CS(cast(I)); + if (!CS || isa(I)) continue; // If this call site already existed in the callgraph, just verify it // matches up to expectations and remove it from CallSites. @@ -582,9 +582,9 @@ namespace { public: static char ID; - PrintCallGraphPass() : CallGraphSCCPass(&ID), Out(dbgs()) {} + PrintCallGraphPass() : CallGraphSCCPass(ID), Out(dbgs()) {} PrintCallGraphPass(const std::string &B, raw_ostream &o) - : CallGraphSCCPass(&ID), Banner(B), Out(o) {} + : CallGraphSCCPass(ID), Banner(B), Out(o) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); diff --git a/lib/Analysis/IPA/FindUsedTypes.cpp b/lib/Analysis/IPA/FindUsedTypes.cpp index c4fb0b9..8eed9d6 100644 --- a/lib/Analysis/IPA/FindUsedTypes.cpp +++ b/lib/Analysis/IPA/FindUsedTypes.cpp @@ -23,8 +23,8 @@ using namespace llvm; char FindUsedTypes::ID = 0; -static RegisterPass -X("print-used-types", "Find Used Types", false, true); +INITIALIZE_PASS(FindUsedTypes, "print-used-types", + "Find Used Types", false, true); // IncorporateType - Incorporate one type and all of its subtypes into the // collection of used types. diff --git a/lib/Analysis/IPA/GlobalsModRef.cpp b/lib/Analysis/IPA/GlobalsModRef.cpp index f13deea..6759b0a 100644 --- a/lib/Analysis/IPA/GlobalsModRef.cpp +++ b/lib/Analysis/IPA/GlobalsModRef.cpp @@ -47,14 +47,15 @@ namespace { /// GlobalInfo - Maintain mod/ref info for all of the globals without /// addresses taken that are read or written (transitively) by this /// function. - std::map GlobalInfo; + std::map GlobalInfo; /// MayReadAnyGlobal - May read global variables, but it is not known which. bool MayReadAnyGlobal; - unsigned getInfoForGlobal(GlobalValue *GV) const { + unsigned getInfoForGlobal(const GlobalValue *GV) const { unsigned Effect = MayReadAnyGlobal ? AliasAnalysis::Ref : 0; - std::map::const_iterator I = GlobalInfo.find(GV); + std::map::const_iterator I = + GlobalInfo.find(GV); if (I != GlobalInfo.end()) Effect |= I->second; return Effect; @@ -71,23 +72,23 @@ namespace { class GlobalsModRef : public ModulePass, public AliasAnalysis { /// NonAddressTakenGlobals - The globals that do not have their addresses /// taken. - std::set NonAddressTakenGlobals; + std::set NonAddressTakenGlobals; /// IndirectGlobals - The memory pointed to by this global is known to be /// 'owned' by the global. - std::set IndirectGlobals; + std::set IndirectGlobals; /// AllocsForIndirectGlobals - If an instruction allocates memory for an /// indirect global, this map indicates which one. - std::map AllocsForIndirectGlobals; + std::map AllocsForIndirectGlobals; /// FunctionInfo - For each function, keep track of what globals are /// modified or read. - std::map FunctionInfo; + std::map FunctionInfo; public: static char ID; - GlobalsModRef() : ModulePass(&ID) {} + GlobalsModRef() : ModulePass(ID) {} bool runOnModule(Module &M) { InitializeAliasAnalysis(this); // set up super class @@ -107,39 +108,39 @@ namespace { // AliasResult alias(const Value *V1, unsigned V1Size, const Value *V2, unsigned V2Size); - ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size); - ModRefResult getModRefInfo(CallSite CS1, CallSite CS2) { - return AliasAnalysis::getModRefInfo(CS1,CS2); + ModRefResult getModRefInfo(ImmutableCallSite CS, + const Value *P, unsigned Size); + ModRefResult getModRefInfo(ImmutableCallSite CS1, + ImmutableCallSite CS2) { + return AliasAnalysis::getModRefInfo(CS1, CS2); } /// getModRefBehavior - Return the behavior of the specified function if /// called from the specified call site. The call site may be null in which /// case the most generic behavior of this function should be returned. - ModRefBehavior getModRefBehavior(Function *F, - std::vector *Info) { + ModRefBehavior getModRefBehavior(const Function *F) { if (FunctionRecord *FR = getFunctionInfo(F)) { if (FR->FunctionEffect == 0) return DoesNotAccessMemory; else if ((FR->FunctionEffect & Mod) == 0) return OnlyReadsMemory; } - return AliasAnalysis::getModRefBehavior(F, Info); + return AliasAnalysis::getModRefBehavior(F); } /// getModRefBehavior - Return the behavior of the specified function if /// called from the specified call site. The call site may be null in which /// case the most generic behavior of this function should be returned. - ModRefBehavior getModRefBehavior(CallSite CS, - std::vector *Info) { - Function* F = CS.getCalledFunction(); - if (!F) return AliasAnalysis::getModRefBehavior(CS, Info); + ModRefBehavior getModRefBehavior(ImmutableCallSite CS) { + const Function* F = CS.getCalledFunction(); + if (!F) return AliasAnalysis::getModRefBehavior(CS); if (FunctionRecord *FR = getFunctionInfo(F)) { if (FR->FunctionEffect == 0) return DoesNotAccessMemory; else if ((FR->FunctionEffect & Mod) == 0) return OnlyReadsMemory; } - return AliasAnalysis::getModRefBehavior(CS, Info); + return AliasAnalysis::getModRefBehavior(CS); } virtual void deleteValue(Value *V); @@ -149,8 +150,8 @@ namespace { /// an analysis interface through multiple inheritance. If needed, it /// should override this to adjust the this pointer as needed for the /// specified pass info. - virtual void *getAdjustedAnalysisPointer(const PassInfo *PI) { - if (PI->isPassID(&AliasAnalysis::ID)) + virtual void *getAdjustedAnalysisPointer(AnalysisID PI) { + if (PI == &AliasAnalysis::ID) return (AliasAnalysis*)this; return this; } @@ -158,8 +159,9 @@ namespace { private: /// getFunctionInfo - Return the function info for the function, or null if /// we don't have anything useful to say about it. - FunctionRecord *getFunctionInfo(Function *F) { - std::map::iterator I = FunctionInfo.find(F); + FunctionRecord *getFunctionInfo(const Function *F) { + std::map::iterator I = + FunctionInfo.find(F); if (I != FunctionInfo.end()) return &I->second; return 0; @@ -175,9 +177,9 @@ namespace { } char GlobalsModRef::ID = 0; -static RegisterPass -X("globalsmodref-aa", "Simple mod/ref analysis for globals", false, true); -static RegisterAnalysisGroup Y(X); +INITIALIZE_AG_PASS(GlobalsModRef, AliasAnalysis, + "globalsmodref-aa", "Simple mod/ref analysis for globals", + false, true, false); Pass *llvm::createGlobalsModRefPass() { return new GlobalsModRef(); } @@ -409,7 +411,7 @@ void GlobalsModRef::AnalyzeCallGraph(CallGraph &CG, Module &M) { FunctionEffect |= CalleeFR->FunctionEffect; // Incorporate callee's effects on globals into our info. - for (std::map::iterator GI = + for (std::map::iterator GI = CalleeFR->GlobalInfo.begin(), E = CalleeFR->GlobalInfo.end(); GI != E; ++GI) FR.GlobalInfo[GI->first] |= GI->second; @@ -477,13 +479,13 @@ AliasAnalysis::AliasResult GlobalsModRef::alias(const Value *V1, unsigned V1Size, const Value *V2, unsigned V2Size) { // Get the base object these pointers point to. - Value *UV1 = const_cast(V1->getUnderlyingObject()); - Value *UV2 = const_cast(V2->getUnderlyingObject()); + const Value *UV1 = V1->getUnderlyingObject(); + const Value *UV2 = V2->getUnderlyingObject(); // If either of the underlying values is a global, they may be non-addr-taken // globals, which we can answer queries about. - GlobalValue *GV1 = dyn_cast(UV1); - GlobalValue *GV2 = dyn_cast(UV2); + const GlobalValue *GV1 = dyn_cast(UV1); + const GlobalValue *GV2 = dyn_cast(UV2); if (GV1 || GV2) { // If the global's address is taken, pretend we don't know it's a pointer to // the global. @@ -503,12 +505,12 @@ GlobalsModRef::alias(const Value *V1, unsigned V1Size, // so, we may be able to handle this. First check to see if the base pointer // is a direct load from an indirect global. GV1 = GV2 = 0; - if (LoadInst *LI = dyn_cast(UV1)) + if (const LoadInst *LI = dyn_cast(UV1)) if (GlobalVariable *GV = dyn_cast(LI->getOperand(0))) if (IndirectGlobals.count(GV)) GV1 = GV; - if (LoadInst *LI = dyn_cast(UV2)) - if (GlobalVariable *GV = dyn_cast(LI->getOperand(0))) + if (const LoadInst *LI = dyn_cast(UV2)) + if (const GlobalVariable *GV = dyn_cast(LI->getOperand(0))) if (IndirectGlobals.count(GV)) GV2 = GV; @@ -530,16 +532,17 @@ GlobalsModRef::alias(const Value *V1, unsigned V1Size, } AliasAnalysis::ModRefResult -GlobalsModRef::getModRefInfo(CallSite CS, Value *P, unsigned Size) { +GlobalsModRef::getModRefInfo(ImmutableCallSite CS, + const Value *P, unsigned Size) { unsigned Known = ModRef; // If we are asking for mod/ref info of a direct call with a pointer to a // global we are tracking, return information if we have it. - if (GlobalValue *GV = dyn_cast(P->getUnderlyingObject())) + if (const GlobalValue *GV = dyn_cast(P->getUnderlyingObject())) if (GV->hasLocalLinkage()) - if (Function *F = CS.getCalledFunction()) + if (const Function *F = CS.getCalledFunction()) if (NonAddressTakenGlobals.count(GV)) - if (FunctionRecord *FR = getFunctionInfo(F)) + if (const FunctionRecord *FR = getFunctionInfo(F)) Known = FR->getInfoForGlobal(GV); if (Known == NoModRef) @@ -558,7 +561,7 @@ void GlobalsModRef::deleteValue(Value *V) { // any AllocRelatedValues for it. if (IndirectGlobals.erase(GV)) { // Remove any entries in AllocsForIndirectGlobals for this global. - for (std::map::iterator + for (std::map::iterator I = AllocsForIndirectGlobals.begin(), E = AllocsForIndirectGlobals.end(); I != E; ) { if (I->second == GV) { diff --git a/lib/Analysis/IVUsers.cpp b/lib/Analysis/IVUsers.cpp index 2c997da..cdf667a 100644 --- a/lib/Analysis/IVUsers.cpp +++ b/lib/Analysis/IVUsers.cpp @@ -21,7 +21,6 @@ #include "llvm/Analysis/Dominators.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" -#include "llvm/Assembly/AsmAnnotationWriter.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -29,8 +28,7 @@ using namespace llvm; char IVUsers::ID = 0; -static RegisterPass -X("iv-users", "Induction Variable Users", false, true); +INITIALIZE_PASS(IVUsers, "iv-users", "Induction Variable Users", false, true); Pass *llvm::createIVUsersPass() { return new IVUsers(); @@ -39,27 +37,31 @@ Pass *llvm::createIVUsersPass() { /// isInteresting - Test whether the given expression is "interesting" when /// used by the given expression, within the context of analyzing the /// given loop. -static bool isInteresting(const SCEV *S, const Instruction *I, const Loop *L) { - // Anything loop-invariant is interesting. - if (!isa(S) && S->isLoopInvariant(L)) - return true; - +static bool isInteresting(const SCEV *S, const Instruction *I, const Loop *L, + ScalarEvolution *SE) { // An addrec is interesting if it's affine or if it has an interesting start. if (const SCEVAddRecExpr *AR = dyn_cast(S)) { // Keep things simple. Don't touch loop-variant strides. if (AR->getLoop() == L) return AR->isAffine() || !L->contains(I); - // Otherwise recurse to see if the start value is interesting. - return isInteresting(AR->getStart(), I, L); + // Otherwise recurse to see if the start value is interesting, and that + // the step value is not interesting, since we don't yet know how to + // do effective SCEV expansions for addrecs with interesting steps. + return isInteresting(AR->getStart(), I, L, SE) && + !isInteresting(AR->getStepRecurrence(*SE), I, L, SE); } - // An add is interesting if any of its operands is. + // An add is interesting if exactly one of its operands is interesting. if (const SCEVAddExpr *Add = dyn_cast(S)) { + bool AnyInterestingYet = false; for (SCEVAddExpr::op_iterator OI = Add->op_begin(), OE = Add->op_end(); OI != OE; ++OI) - if (isInteresting(*OI, I, L)) - return true; - return false; + if (isInteresting(*OI, I, L, SE)) { + if (AnyInterestingYet) + return false; + AnyInterestingYet = true; + } + return AnyInterestingYet; } // Nothing else is interesting here. @@ -85,7 +87,7 @@ bool IVUsers::AddUsersIfInteresting(Instruction *I) { // If we've come to an uninteresting expression, stop the traversal and // call this a user. - if (!isInteresting(ISE, I, L)) + if (!isInteresting(ISE, I, L, SE)) return false; SmallPtrSet UniqueUsers; @@ -141,7 +143,7 @@ IVStrideUse &IVUsers::AddUser(Instruction *User, Value *Operand) { } IVUsers::IVUsers() - : LoopPass(&ID) { + : LoopPass(ID) { } void IVUsers::getAnalysisUsage(AnalysisUsage &AU) const { @@ -176,9 +178,6 @@ void IVUsers::print(raw_ostream &OS, const Module *M) const { } OS << ":\n"; - // Use a default AssemblyAnnotationWriter to suppress the default info - // comments, which aren't relevant here. - AssemblyAnnotationWriter Annotator; for (ilist::const_iterator UI = IVUses.begin(), E = IVUses.end(); UI != E; ++UI) { OS << " "; @@ -192,7 +191,7 @@ void IVUsers::print(raw_ostream &OS, const Module *M) const { OS << ")"; } OS << " in "; - UI->getUser()->print(OS, &Annotator); + UI->getUser()->print(OS); OS << '\n'; } } diff --git a/lib/Analysis/InlineCost.cpp b/lib/Analysis/InlineCost.cpp index b1df517..3e550f3 100644 --- a/lib/Analysis/InlineCost.cpp +++ b/lib/Analysis/InlineCost.cpp @@ -152,14 +152,14 @@ void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB) { if (isa(II) || isa(II)) { if (isa(II)) continue; // Debug intrinsics don't count as size. - - CallSite CS = CallSite::get(const_cast(&*II)); - + + ImmutableCallSite CS(cast(II)); + // If this function contains a call to setjmp or _setjmp, never inline // it. This is a hack because we depend on the user marking their local // variables as volatile if they are live across a setjmp call, and they // probably won't do this in callers. - if (Function *F = CS.getCalledFunction()) { + if (const Function *F = CS.getCalledFunction()) { if (F->isDeclaration() && (F->getName() == "setjmp" || F->getName() == "_setjmp")) callsSetJmp = true; diff --git a/lib/Analysis/InstCount.cpp b/lib/Analysis/InstCount.cpp index bb2cf53..dcbcac0 100644 --- a/lib/Analysis/InstCount.cpp +++ b/lib/Analysis/InstCount.cpp @@ -51,7 +51,7 @@ namespace { } public: static char ID; // Pass identification, replacement for typeid - InstCount() : FunctionPass(&ID) {} + InstCount() : FunctionPass(ID) {} virtual bool runOnFunction(Function &F); @@ -64,8 +64,8 @@ namespace { } char InstCount::ID = 0; -static RegisterPass -X("instcount", "Counts the various types of Instructions", false, true); +INITIALIZE_PASS(InstCount, "instcount", + "Counts the various types of Instructions", false, true); FunctionPass *llvm::createInstCountPass() { return new InstCount(); } diff --git a/lib/Analysis/IntervalPartition.cpp b/lib/Analysis/IntervalPartition.cpp index 1f17b77..1c9e148 100644 --- a/lib/Analysis/IntervalPartition.cpp +++ b/lib/Analysis/IntervalPartition.cpp @@ -16,8 +16,8 @@ using namespace llvm; char IntervalPartition::ID = 0; -static RegisterPass -X("intervals", "Interval Partition Construction", true, true); +INITIALIZE_PASS(IntervalPartition, "intervals", + "Interval Partition Construction", true, true); //===----------------------------------------------------------------------===// // IntervalPartition Implementation @@ -91,7 +91,7 @@ bool IntervalPartition::runOnFunction(Function &F) { // distinguish it from a copy constructor. Always pass in false for now. // IntervalPartition::IntervalPartition(IntervalPartition &IP, bool) - : FunctionPass(&ID) { + : FunctionPass(ID) { assert(IP.getRootInterval() && "Cannot operate on empty IntervalPartitions!"); // Pass false to intervals_begin because we take ownership of it's memory diff --git a/lib/Analysis/LazyValueInfo.cpp b/lib/Analysis/LazyValueInfo.cpp index ff9026b..e32dbc4 100644 --- a/lib/Analysis/LazyValueInfo.cpp +++ b/lib/Analysis/LazyValueInfo.cpp @@ -19,16 +19,18 @@ #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Target/TargetData.h" #include "llvm/Support/CFG.h" +#include "llvm/Support/ConstantRange.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ValueHandle.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" using namespace llvm; char LazyValueInfo::ID = 0; -static RegisterPass -X("lazy-value-info", "Lazy Value Information Analysis", false, true); +INITIALIZE_PASS(LazyValueInfo, "lazy-value-info", + "Lazy Value Information Analysis", false, true); namespace llvm { FunctionPass *createLazyValueInfoPass() { return new LazyValueInfo(); } @@ -50,12 +52,15 @@ class LVILatticeVal { enum LatticeValueTy { /// undefined - This LLVM Value has no known value yet. undefined, + /// constant - This LLVM Value has a specific constant value. constant, - /// notconstant - This LLVM value is known to not have the specified value. notconstant, + /// constantrange + constantrange, + /// overdefined - This instruction is not known to be constant, and we know /// it has a value. overdefined @@ -63,42 +68,62 @@ class LVILatticeVal { /// Val: This stores the current lattice value along with the Constant* for /// the constant if this is a 'constant' or 'notconstant' value. - PointerIntPair Val; + LatticeValueTy Tag; + Constant *Val; + ConstantRange Range; public: - LVILatticeVal() : Val(0, undefined) {} + LVILatticeVal() : Tag(undefined), Val(0), Range(1, true) {} static LVILatticeVal get(Constant *C) { LVILatticeVal Res; - Res.markConstant(C); + if (ConstantInt *CI = dyn_cast(C)) + Res.markConstantRange(ConstantRange(CI->getValue(), CI->getValue()+1)); + else if (!isa(C)) + Res.markConstant(C); return Res; } static LVILatticeVal getNot(Constant *C) { LVILatticeVal Res; - Res.markNotConstant(C); + if (ConstantInt *CI = dyn_cast(C)) + Res.markConstantRange(ConstantRange(CI->getValue()+1, CI->getValue())); + else + Res.markNotConstant(C); + return Res; + } + static LVILatticeVal getRange(ConstantRange CR) { + LVILatticeVal Res; + Res.markConstantRange(CR); return Res; } - bool isUndefined() const { return Val.getInt() == undefined; } - bool isConstant() const { return Val.getInt() == constant; } - bool isNotConstant() const { return Val.getInt() == notconstant; } - bool isOverdefined() const { return Val.getInt() == overdefined; } + bool isUndefined() const { return Tag == undefined; } + bool isConstant() const { return Tag == constant; } + bool isNotConstant() const { return Tag == notconstant; } + bool isConstantRange() const { return Tag == constantrange; } + bool isOverdefined() const { return Tag == overdefined; } Constant *getConstant() const { assert(isConstant() && "Cannot get the constant of a non-constant!"); - return Val.getPointer(); + return Val; } Constant *getNotConstant() const { assert(isNotConstant() && "Cannot get the constant of a non-notconstant!"); - return Val.getPointer(); + return Val; + } + + ConstantRange getConstantRange() const { + assert(isConstantRange() && + "Cannot get the constant-range of a non-constant-range!"); + return Range; } /// markOverdefined - Return true if this is a change in status. bool markOverdefined() { if (isOverdefined()) return false; - Val.setInt(overdefined); + Tag = overdefined; return true; } @@ -110,9 +135,9 @@ public: } assert(isUndefined()); - Val.setInt(constant); + Tag = constant; assert(V && "Marking constant with NULL"); - Val.setPointer(V); + Val = V; return true; } @@ -128,9 +153,29 @@ public: else assert(isUndefined()); - Val.setInt(notconstant); + Tag = notconstant; assert(V && "Marking constant with NULL"); - Val.setPointer(V); + Val = V; + return true; + } + + /// markConstantRange - Return true if this is a change in status. + bool markConstantRange(const ConstantRange NewR) { + if (isConstantRange()) { + if (NewR.isEmptySet()) + return markOverdefined(); + + bool changed = Range == NewR; + Range = NewR; + return changed; + } + + assert(isUndefined()); + if (NewR.isEmptySet()) + return markOverdefined(); + + Tag = constantrange; + Range = NewR; return true; } @@ -147,20 +192,39 @@ public: isa(RHS.getNotConstant())) return markOverdefined(); return false; - } - if (isConstant()) { + } else if (isConstant()) { if (getConstant() == RHS.getNotConstant() || isa(RHS.getNotConstant()) || isa(getConstant())) return markOverdefined(); return markNotConstant(RHS.getNotConstant()); + } else if (isConstantRange()) { + return markOverdefined(); } assert(isUndefined() && "Unexpected lattice"); return markNotConstant(RHS.getNotConstant()); } + if (RHS.isConstantRange()) { + if (isConstantRange()) { + ConstantRange NewR = Range.unionWith(RHS.getConstantRange()); + if (NewR.isFullSet()) + return markOverdefined(); + else + return markConstantRange(NewR); + } else if (!isUndefined()) { + return markOverdefined(); + } + + assert(isUndefined() && "Unexpected lattice"); + return markConstantRange(RHS.getConstantRange()); + } + // RHS must be a constant, we must be undef, constant, or notconstant. + assert(!isConstantRange() && + "Constant and ConstantRange cannot be merged."); + if (isUndefined()) return markConstant(RHS.getConstant()); @@ -191,6 +255,9 @@ raw_ostream &operator<<(raw_ostream &OS, const LVILatticeVal &Val) { if (Val.isNotConstant()) return OS << "notconstant<" << *Val.getNotConstant() << '>'; + else if (Val.isConstantRange()) + return OS << "constantrange<" << Val.getConstantRange().getLower() << ", " + << Val.getConstantRange().getUpper() << '>'; return OS << "constant<" << *Val.getConstant() << '>'; } } @@ -206,17 +273,41 @@ namespace { public: /// BlockCacheEntryTy - This is a computed lattice value at the end of the /// specified basic block for a Value* that depends on context. - typedef std::pair BlockCacheEntryTy; + typedef std::pair, LVILatticeVal> BlockCacheEntryTy; /// ValueCacheEntryTy - This is all of the cached block information for /// exactly one Value*. The entries are sorted by the BasicBlock* of the /// entries, allowing us to do a lookup with a binary search. - typedef std::vector ValueCacheEntryTy; + typedef std::map, LVILatticeVal> ValueCacheEntryTy; private: + /// LVIValueHandle - A callback value handle update the cache when + /// values are erased. + struct LVIValueHandle : public CallbackVH { + LazyValueInfoCache *Parent; + + LVIValueHandle(Value *V, LazyValueInfoCache *P) + : CallbackVH(V), Parent(P) { } + + void deleted(); + void allUsesReplacedWith(Value* V) { + deleted(); + } + + LVIValueHandle &operator=(Value *V) { + return *this = LVIValueHandle(V, Parent); + } + }; + /// ValueCache - This is all of the cached information for all values, /// mapped from Value* to key information. - DenseMap ValueCache; + std::map ValueCache; + + /// OverDefinedCache - This tracks, on a per-block basis, the set of + /// values that are over-defined at the end of that block. This is required + /// for cache updating. + std::set, Value*> > OverDefinedCache; + public: /// getValueInBlock - This is the query interface to determine the lattice @@ -226,29 +317,23 @@ namespace { /// getValueOnEdge - This is the query interface to determine the lattice /// value for the specified Value* that is true on the specified edge. LVILatticeVal getValueOnEdge(Value *V, BasicBlock *FromBB,BasicBlock *ToBB); - }; -} // end anonymous namespace - -namespace { - struct BlockCacheEntryComparator { - static int Compare(const void *LHSv, const void *RHSv) { - const LazyValueInfoCache::BlockCacheEntryTy *LHS = - static_cast(LHSv); - const LazyValueInfoCache::BlockCacheEntryTy *RHS = - static_cast(RHSv); - if (LHS->first < RHS->first) - return -1; - if (LHS->first > RHS->first) - return 1; - return 0; - } - bool operator()(const LazyValueInfoCache::BlockCacheEntryTy &LHS, - const LazyValueInfoCache::BlockCacheEntryTy &RHS) const { - return LHS.first < RHS.first; + /// threadEdge - This is the update interface to inform the cache that an + /// edge from PredBB to OldSucc has been threaded to be from PredBB to + /// NewSucc. + void threadEdge(BasicBlock *PredBB,BasicBlock *OldSucc,BasicBlock *NewSucc); + + /// eraseBlock - This is part of the update interface to inform the cache + /// that a block has been deleted. + void eraseBlock(BasicBlock *BB); + + /// clear - Empty the cache. + void clear() { + ValueCache.clear(); + OverDefinedCache.clear(); } }; -} +} // end anonymous namespace //===----------------------------------------------------------------------===// // LVIQuery Impl @@ -267,78 +352,87 @@ namespace { /// This is the current value being queried for. Value *Val; + /// This is a pointer to the owning cache, for recursive queries. + LazyValueInfoCache &Parent; + /// This is all of the cached information about this value. ValueCacheEntryTy &Cache; + /// This tracks, for each block, what values are overdefined. + std::set, Value*> > &OverDefinedCache; + /// NewBlocks - This is a mapping of the new BasicBlocks which have been /// added to cache but that are not in sorted order. - DenseMap NewBlockInfo; + DenseSet NewBlockInfo; + public: - LVIQuery(Value *V, ValueCacheEntryTy &VC) : Val(V), Cache(VC) { + LVIQuery(Value *V, LazyValueInfoCache &P, + ValueCacheEntryTy &VC, + std::set, Value*> > &ODC) + : Val(V), Parent(P), Cache(VC), OverDefinedCache(ODC) { } ~LVIQuery() { // When the query is done, insert the newly discovered facts into the // cache in sorted order. if (NewBlockInfo.empty()) return; - - // Grow the cache to exactly fit the new data. - Cache.reserve(Cache.size() + NewBlockInfo.size()); - // If we only have one new entry, insert it instead of doing a full-on - // sort. - if (NewBlockInfo.size() == 1) { - BlockCacheEntryTy Entry = *NewBlockInfo.begin(); - ValueCacheEntryTy::iterator I = - std::lower_bound(Cache.begin(), Cache.end(), Entry, - BlockCacheEntryComparator()); - assert((I == Cache.end() || I->first != Entry.first) && - "Entry already in map!"); - - Cache.insert(I, Entry); - return; + for (DenseSet::iterator I = NewBlockInfo.begin(), + E = NewBlockInfo.end(); I != E; ++I) { + if (Cache[*I].isOverdefined()) + OverDefinedCache.insert(std::make_pair(*I, Val)); } - - // TODO: If we only have two new elements, INSERT them both. - - Cache.insert(Cache.end(), NewBlockInfo.begin(), NewBlockInfo.end()); - array_pod_sort(Cache.begin(), Cache.end(), - BlockCacheEntryComparator::Compare); - } LVILatticeVal getBlockValue(BasicBlock *BB); LVILatticeVal getEdgeValue(BasicBlock *FromBB, BasicBlock *ToBB); private: - LVILatticeVal &getCachedEntryForBlock(BasicBlock *BB); + LVILatticeVal getCachedEntryForBlock(BasicBlock *BB); }; } // end anonymous namespace -/// getCachedEntryForBlock - See if we already have a value for this block. If -/// so, return it, otherwise create a new entry in the NewBlockInfo map to use. -LVILatticeVal &LVIQuery::getCachedEntryForBlock(BasicBlock *BB) { - - // Do a binary search to see if we already have an entry for this block in - // the cache set. If so, find it. - if (!Cache.empty()) { - ValueCacheEntryTy::iterator Entry = - std::lower_bound(Cache.begin(), Cache.end(), - BlockCacheEntryTy(BB, LVILatticeVal()), - BlockCacheEntryComparator()); - if (Entry != Cache.end() && Entry->first == BB) - return Entry->second; +void LazyValueInfoCache::LVIValueHandle::deleted() { + for (std::set, Value*> >::iterator + I = Parent->OverDefinedCache.begin(), + E = Parent->OverDefinedCache.end(); + I != E; ) { + std::set, Value*> >::iterator tmp = I; + ++I; + if (tmp->second == getValPtr()) + Parent->OverDefinedCache.erase(tmp); } - // Otherwise, check to see if it's in NewBlockInfo or create a new entry if - // not. - return NewBlockInfo[BB]; + // This erasure deallocates *this, so it MUST happen after we're done + // using any and all members of *this. + Parent->ValueCache.erase(*this); +} + +void LazyValueInfoCache::eraseBlock(BasicBlock *BB) { + for (std::set, Value*> >::iterator + I = OverDefinedCache.begin(), E = OverDefinedCache.end(); I != E; ) { + std::set, Value*> >::iterator tmp = I; + ++I; + if (tmp->first == BB) + OverDefinedCache.erase(tmp); + } + + for (std::map::iterator + I = ValueCache.begin(), E = ValueCache.end(); I != E; ++I) + I->second.erase(BB); +} + +/// getCachedEntryForBlock - See if we already have a value for this block. If +/// so, return it, otherwise create a new entry in the Cache map to use. +LVILatticeVal LVIQuery::getCachedEntryForBlock(BasicBlock *BB) { + NewBlockInfo.insert(BB); + return Cache[BB]; } LVILatticeVal LVIQuery::getBlockValue(BasicBlock *BB) { // See if we already have a value for this block. - LVILatticeVal &BBLV = getCachedEntryForBlock(BB); + LVILatticeVal BBLV = getCachedEntryForBlock(BB); // If we've already computed this block's value, return it. if (!BBLV.isUndefined()) { @@ -350,13 +444,28 @@ LVILatticeVal LVIQuery::getBlockValue(BasicBlock *BB) { // lattice value to overdefined, so that cycles will terminate and be // conservatively correct. BBLV.markOverdefined(); + Cache[BB] = BBLV; - // If V is live into BB, see if our predecessors know anything about it. Instruction *BBI = dyn_cast(Val); if (BBI == 0 || BBI->getParent() != BB) { LVILatticeVal Result; // Start Undefined. - unsigned NumPreds = 0; + // If this is a pointer, and there's a load from that pointer in this BB, + // then we know that the pointer can't be NULL. + bool NotNull = false; + if (Val->getType()->isPointerTy()) { + for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();BI != BE;++BI){ + LoadInst *L = dyn_cast(BI); + if (L && L->getPointerAddressSpace() == 0 && + L->getPointerOperand()->getUnderlyingObject() == + Val->getUnderlyingObject()) { + NotNull = true; + break; + } + } + } + + unsigned NumPreds = 0; // Loop over all of our predecessors, merging what we know from them into // result. for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { @@ -367,11 +476,19 @@ LVILatticeVal LVIQuery::getBlockValue(BasicBlock *BB) { if (Result.isOverdefined()) { DEBUG(dbgs() << " compute BB '" << BB->getName() << "' - overdefined because of pred.\n"); + // If we previously determined that this is a pointer that can't be null + // then return that rather than giving up entirely. + if (NotNull) { + const PointerType *PTy = cast(Val->getType()); + Result = LVILatticeVal::getNot(ConstantPointerNull::get(PTy)); + } + return Result; } ++NumPreds; } + // If this is the entry block, we must be asking about an argument. The // value is overdefined. if (NumPreds == 0 && BB == &BB->getParent()->front()) { @@ -382,24 +499,123 @@ LVILatticeVal LVIQuery::getBlockValue(BasicBlock *BB) { // Return the merged value, which is more precise than 'overdefined'. assert(!Result.isOverdefined()); - return getCachedEntryForBlock(BB) = Result; + return Cache[BB] = Result; } // If this value is defined by an instruction in this block, we have to // process it here somehow or return overdefined. if (PHINode *PN = dyn_cast(BBI)) { - (void)PN; - // TODO: PHI Translation in preds. - } else { + LVILatticeVal Result; // Start Undefined. + // Loop over all of our predecessors, merging what we know from them into + // result. + for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { + Value* PhiVal = PN->getIncomingValueForBlock(*PI); + Result.mergeIn(Parent.getValueOnEdge(PhiVal, *PI, BB)); + + // If we hit overdefined, exit early. The BlockVals entry is already set + // to overdefined. + if (Result.isOverdefined()) { + DEBUG(dbgs() << " compute BB '" << BB->getName() + << "' - overdefined because of pred.\n"); + return Result; + } + } + + // Return the merged value, which is more precise than 'overdefined'. + assert(!Result.isOverdefined()); + return Cache[BB] = Result; } - - DEBUG(dbgs() << " compute BB '" << BB->getName() - << "' - overdefined because inst def found.\n"); + assert(Cache[BB].isOverdefined() && "Recursive query changed our cache?"); + + // We can only analyze the definitions of certain classes of instructions + // (integral binops and casts at the moment), so bail if this isn't one. LVILatticeVal Result; - Result.markOverdefined(); - return getCachedEntryForBlock(BB) = Result; + if ((!isa(BBI) && !isa(BBI)) || + !BBI->getType()->isIntegerTy()) { + DEBUG(dbgs() << " compute BB '" << BB->getName() + << "' - overdefined because inst def found.\n"); + Result.markOverdefined(); + return Result; + } + + // FIXME: We're currently limited to binops with a constant RHS. This should + // be improved. + BinaryOperator *BO = dyn_cast(BBI); + if (BO && !isa(BO->getOperand(1))) { + DEBUG(dbgs() << " compute BB '" << BB->getName() + << "' - overdefined because inst def found.\n"); + + Result.markOverdefined(); + return Result; + } + + // Figure out the range of the LHS. If that fails, bail. + LVILatticeVal LHSVal = Parent.getValueInBlock(BBI->getOperand(0), BB); + if (!LHSVal.isConstantRange()) { + Result.markOverdefined(); + return Result; + } + + ConstantInt *RHS = 0; + ConstantRange LHSRange = LHSVal.getConstantRange(); + ConstantRange RHSRange(1); + const IntegerType *ResultTy = cast(BBI->getType()); + if (isa(BBI)) { + RHS = dyn_cast(BBI->getOperand(1)); + if (!RHS) { + Result.markOverdefined(); + return Result; + } + + RHSRange = ConstantRange(RHS->getValue(), RHS->getValue()+1); + } + + // NOTE: We're currently limited by the set of operations that ConstantRange + // can evaluate symbolically. Enhancing that set will allows us to analyze + // more definitions. + switch (BBI->getOpcode()) { + case Instruction::Add: + Result.markConstantRange(LHSRange.add(RHSRange)); + break; + case Instruction::Sub: + Result.markConstantRange(LHSRange.sub(RHSRange)); + break; + case Instruction::Mul: + Result.markConstantRange(LHSRange.multiply(RHSRange)); + break; + case Instruction::UDiv: + Result.markConstantRange(LHSRange.udiv(RHSRange)); + break; + case Instruction::Shl: + Result.markConstantRange(LHSRange.shl(RHSRange)); + break; + case Instruction::LShr: + Result.markConstantRange(LHSRange.lshr(RHSRange)); + break; + case Instruction::Trunc: + Result.markConstantRange(LHSRange.truncate(ResultTy->getBitWidth())); + break; + case Instruction::SExt: + Result.markConstantRange(LHSRange.signExtend(ResultTy->getBitWidth())); + break; + case Instruction::ZExt: + Result.markConstantRange(LHSRange.zeroExtend(ResultTy->getBitWidth())); + break; + case Instruction::BitCast: + Result.markConstantRange(LHSRange); + break; + + // Unhandled instructions are overdefined. + default: + DEBUG(dbgs() << " compute BB '" << BB->getName() + << "' - overdefined because inst def found.\n"); + Result.markOverdefined(); + break; + } + + return Cache[BB] = Result; } @@ -420,28 +636,57 @@ LVILatticeVal LVIQuery::getEdgeValue(BasicBlock *BBFrom, BasicBlock *BBTo) { // it is. if (BI->getCondition() == Val) return LVILatticeVal::get(ConstantInt::get( - Type::getInt1Ty(Val->getContext()), isTrueDest)); + Type::getInt1Ty(Val->getContext()), isTrueDest)); // If the condition of the branch is an equality comparison, we may be // able to infer the value. - if (ICmpInst *ICI = dyn_cast(BI->getCondition())) - if (ICI->isEquality() && ICI->getOperand(0) == Val && - isa(ICI->getOperand(1))) { + ICmpInst *ICI = dyn_cast(BI->getCondition()); + if (ICI && ICI->getOperand(0) == Val && + isa(ICI->getOperand(1))) { + if (ICI->isEquality()) { // We know that V has the RHS constant if this is a true SETEQ or // false SETNE. if (isTrueDest == (ICI->getPredicate() == ICmpInst::ICMP_EQ)) return LVILatticeVal::get(cast(ICI->getOperand(1))); return LVILatticeVal::getNot(cast(ICI->getOperand(1))); } + + if (ConstantInt *CI = dyn_cast(ICI->getOperand(1))) { + // Calculate the range of values that would satisfy the comparison. + ConstantRange CmpRange(CI->getValue(), CI->getValue()+1); + ConstantRange TrueValues = + ConstantRange::makeICmpRegion(ICI->getPredicate(), CmpRange); + + // If we're interested in the false dest, invert the condition. + if (!isTrueDest) TrueValues = TrueValues.inverse(); + + // Figure out the possible values of the query BEFORE this branch. + LVILatticeVal InBlock = getBlockValue(BBFrom); + if (!InBlock.isConstantRange()) + return LVILatticeVal::getRange(TrueValues); + + // Find all potential values that satisfy both the input and output + // conditions. + ConstantRange PossibleValues = + TrueValues.intersectWith(InBlock.getConstantRange()); + + return LVILatticeVal::getRange(PossibleValues); + } + } } } // If the edge was formed by a switch on the value, then we may know exactly // what it is. if (SwitchInst *SI = dyn_cast(BBFrom->getTerminator())) { - // If BBTo is the default destination of the switch, we don't know anything. - // Given a more powerful range analysis we could know stuff. - if (SI->getCondition() == Val && SI->getDefaultDest() != BBTo) { + if (SI->getCondition() == Val) { + // We don't know anything in the default case. + if (SI->getDefaultDest() == BBTo) { + LVILatticeVal Result; + Result.markOverdefined(); + return Result; + } + // We only know something if there is exactly one value that goes from // BBFrom to BBTo. unsigned NumEdges = 0; @@ -474,7 +719,9 @@ LVILatticeVal LazyValueInfoCache::getValueInBlock(Value *V, BasicBlock *BB) { DEBUG(dbgs() << "LVI Getting block end value " << *V << " at '" << BB->getName() << "'\n"); - LVILatticeVal Result = LVIQuery(V, ValueCache[V]).getBlockValue(BB); + LVILatticeVal Result = LVIQuery(V, *this, + ValueCache[LVIValueHandle(V, this)], + OverDefinedCache).getBlockValue(BB); DEBUG(dbgs() << " Result = " << Result << "\n"); return Result; @@ -488,24 +735,80 @@ getValueOnEdge(Value *V, BasicBlock *FromBB, BasicBlock *ToBB) { DEBUG(dbgs() << "LVI Getting edge value " << *V << " from '" << FromBB->getName() << "' to '" << ToBB->getName() << "'\n"); + LVILatticeVal Result = - LVIQuery(V, ValueCache[V]).getEdgeValue(FromBB, ToBB); + LVIQuery(V, *this, ValueCache[LVIValueHandle(V, this)], + OverDefinedCache).getEdgeValue(FromBB, ToBB); DEBUG(dbgs() << " Result = " << Result << "\n"); return Result; } +void LazyValueInfoCache::threadEdge(BasicBlock *PredBB, BasicBlock *OldSucc, + BasicBlock *NewSucc) { + // When an edge in the graph has been threaded, values that we could not + // determine a value for before (i.e. were marked overdefined) may be possible + // to solve now. We do NOT try to proactively update these values. Instead, + // we clear their entries from the cache, and allow lazy updating to recompute + // them when needed. + + // The updating process is fairly simple: we need to dropped cached info + // for all values that were marked overdefined in OldSucc, and for those same + // values in any successor of OldSucc (except NewSucc) in which they were + // also marked overdefined. + std::vector worklist; + worklist.push_back(OldSucc); + + DenseSet ClearSet; + for (std::set, Value*> >::iterator + I = OverDefinedCache.begin(), E = OverDefinedCache.end(); I != E; ++I) { + if (I->first == OldSucc) + ClearSet.insert(I->second); + } + + // Use a worklist to perform a depth-first search of OldSucc's successors. + // NOTE: We do not need a visited list since any blocks we have already + // visited will have had their overdefined markers cleared already, and we + // thus won't loop to their successors. + while (!worklist.empty()) { + BasicBlock *ToUpdate = worklist.back(); + worklist.pop_back(); + + // Skip blocks only accessible through NewSucc. + if (ToUpdate == NewSucc) continue; + + bool changed = false; + for (DenseSet::iterator I = ClearSet.begin(),E = ClearSet.end(); + I != E; ++I) { + // If a value was marked overdefined in OldSucc, and is here too... + std::set, Value*> >::iterator OI = + OverDefinedCache.find(std::make_pair(ToUpdate, *I)); + if (OI == OverDefinedCache.end()) continue; + + // Remove it from the caches. + ValueCacheEntryTy &Entry = ValueCache[LVIValueHandle(*I, this)]; + ValueCacheEntryTy::iterator CI = Entry.find(ToUpdate); + + assert(CI != Entry.end() && "Couldn't find entry to update?"); + Entry.erase(CI); + OverDefinedCache.erase(OI); + + // If we removed anything, then we potentially need to update + // blocks successors too. + changed = true; + } + + if (!changed) continue; + + worklist.insert(worklist.end(), succ_begin(ToUpdate), succ_end(ToUpdate)); + } +} + //===----------------------------------------------------------------------===// // LazyValueInfo Impl //===----------------------------------------------------------------------===// -bool LazyValueInfo::runOnFunction(Function &F) { - TD = getAnalysisIfAvailable(); - // Fully lazy. - return false; -} - /// getCache - This lazily constructs the LazyValueInfoCache. static LazyValueInfoCache &getCache(void *&PImpl) { if (!PImpl) @@ -513,6 +816,15 @@ static LazyValueInfoCache &getCache(void *&PImpl) { return *static_cast(PImpl); } +bool LazyValueInfo::runOnFunction(Function &F) { + if (PImpl) + getCache(PImpl).clear(); + + TD = getAnalysisIfAvailable(); + // Fully lazy. + return false; +} + void LazyValueInfo::releaseMemory() { // If the cache was allocated, free it. if (PImpl) { @@ -526,6 +838,11 @@ Constant *LazyValueInfo::getConstant(Value *V, BasicBlock *BB) { if (Result.isConstant()) return Result.getConstant(); + else if (Result.isConstantRange()) { + ConstantRange CR = Result.getConstantRange(); + if (const APInt *SingleVal = CR.getSingleElement()) + return ConstantInt::get(V->getContext(), *SingleVal); + } return 0; } @@ -537,6 +854,11 @@ Constant *LazyValueInfo::getConstantOnEdge(Value *V, BasicBlock *FromBB, if (Result.isConstant()) return Result.getConstant(); + else if (Result.isConstantRange()) { + ConstantRange CR = Result.getConstantRange(); + if (const APInt *SingleVal = CR.getSingleElement()) + return ConstantInt::get(V->getContext(), *SingleVal); + } return 0; } @@ -557,6 +879,36 @@ LazyValueInfo::getPredicateOnEdge(unsigned Pred, Value *V, Constant *C, return Unknown; } + if (Result.isConstantRange()) { + ConstantInt *CI = dyn_cast(C); + if (!CI) return Unknown; + + ConstantRange CR = Result.getConstantRange(); + if (Pred == ICmpInst::ICMP_EQ) { + if (!CR.contains(CI->getValue())) + return False; + + if (CR.isSingleElement() && CR.contains(CI->getValue())) + return True; + } else if (Pred == ICmpInst::ICMP_NE) { + if (!CR.contains(CI->getValue())) + return True; + + if (CR.isSingleElement() && CR.contains(CI->getValue())) + return False; + } + + // Handle more complex predicates. + ConstantRange RHS(CI->getValue(), CI->getValue()+1); + ConstantRange TrueValues = ConstantRange::makeICmpRegion(Pred, RHS); + if (CR.intersectWith(TrueValues).isEmptySet()) + return False; + else if (TrueValues.contains(CR)) + return True; + + return Unknown; + } + if (Result.isNotConstant()) { // If this is an equality comparison, we can try to fold it knowing that // "V != C1". @@ -579,4 +931,11 @@ LazyValueInfo::getPredicateOnEdge(unsigned Pred, Value *V, Constant *C, return Unknown; } +void LazyValueInfo::threadEdge(BasicBlock *PredBB, BasicBlock *OldSucc, + BasicBlock* NewSucc) { + if (PImpl) getCache(PImpl).threadEdge(PredBB, OldSucc, NewSucc); +} +void LazyValueInfo::eraseBlock(BasicBlock *BB) { + if (PImpl) getCache(PImpl).eraseBlock(BB); +} diff --git a/lib/Analysis/LibCallAliasAnalysis.cpp b/lib/Analysis/LibCallAliasAnalysis.cpp index 7419659..7f51202 100644 --- a/lib/Analysis/LibCallAliasAnalysis.cpp +++ b/lib/Analysis/LibCallAliasAnalysis.cpp @@ -20,11 +20,8 @@ using namespace llvm; // Register this pass... char LibCallAliasAnalysis::ID = 0; -static RegisterPass -X("libcall-aa", "LibCall Alias Analysis", false, true); - -// Declare that we implement the AliasAnalysis interface -static RegisterAnalysisGroup Y(X); +INITIALIZE_AG_PASS(LibCallAliasAnalysis, AliasAnalysis, "libcall-aa", + "LibCall Alias Analysis", false, true, false); FunctionPass *llvm::createLibCallAliasAnalysisPass(LibCallInfo *LCI) { return new LibCallAliasAnalysis(LCI); @@ -46,7 +43,7 @@ void LibCallAliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { /// vs the specified pointer/size. AliasAnalysis::ModRefResult LibCallAliasAnalysis::AnalyzeLibCallDetails(const LibCallFunctionInfo *FI, - CallSite CS, Value *P, + ImmutableCallSite CS, const Value *P, unsigned Size) { // If we have a function, check to see what kind of mod/ref effects it // has. Start by including any info globally known about the function. @@ -120,13 +117,14 @@ LibCallAliasAnalysis::AnalyzeLibCallDetails(const LibCallFunctionInfo *FI, // specified memory object. // AliasAnalysis::ModRefResult -LibCallAliasAnalysis::getModRefInfo(CallSite CS, Value *P, unsigned Size) { +LibCallAliasAnalysis::getModRefInfo(ImmutableCallSite CS, + const Value *P, unsigned Size) { ModRefResult MRInfo = ModRef; // If this is a direct call to a function that LCI knows about, get the // information about the runtime function. if (LCI) { - if (Function *F = CS.getCalledFunction()) { + if (const Function *F = CS.getCalledFunction()) { if (const LibCallFunctionInfo *FI = LCI->getFunctionInfo(F)) { MRInfo = ModRefResult(MRInfo & AnalyzeLibCallDetails(FI, CS, P, Size)); if (MRInfo == NoModRef) return NoModRef; diff --git a/lib/Analysis/LibCallSemantics.cpp b/lib/Analysis/LibCallSemantics.cpp index e0060c3..81b0f46 100644 --- a/lib/Analysis/LibCallSemantics.cpp +++ b/lib/Analysis/LibCallSemantics.cpp @@ -40,7 +40,8 @@ const LibCallLocationInfo &LibCallInfo::getLocationInfo(unsigned LocID) const { /// getFunctionInfo - Return the LibCallFunctionInfo object corresponding to /// the specified function if we have it. If not, return null. -const LibCallFunctionInfo *LibCallInfo::getFunctionInfo(Function *F) const { +const LibCallFunctionInfo * +LibCallInfo::getFunctionInfo(const Function *F) const { StringMap *Map = getMap(Impl); /// If this is the first time we are querying for this info, lazily construct diff --git a/lib/Analysis/Lint.cpp b/lib/Analysis/Lint.cpp index 9f1b30d..a9d9724 100644 --- a/lib/Analysis/Lint.cpp +++ b/lib/Analysis/Lint.cpp @@ -108,7 +108,7 @@ namespace { raw_string_ostream MessagesStr; static char ID; // Pass identification, replacement for typeid - Lint() : FunctionPass(&ID), MessagesStr(Messages) {} + Lint() : FunctionPass(ID), MessagesStr(Messages) {} virtual bool runOnFunction(Function &F); @@ -167,8 +167,7 @@ namespace { } char Lint::ID = 0; -static RegisterPass -X("lint", "Statically lint-checks LLVM IR", false, true); +INITIALIZE_PASS(Lint, "lint", "Statically lint-checks LLVM IR", false, true); // Assert - We know that cond should be true, if not print an error message. #define Assert(C, M) \ @@ -247,8 +246,7 @@ void Lint::visitCallSite(CallSite CS) { // where nothing is known. if (Formal->hasNoAliasAttr() && Actual->getType()->isPointerTy()) for (CallSite::arg_iterator BI = CS.arg_begin(); BI != AE; ++BI) { - Assert1(AI == BI || - AA->alias(*AI, ~0u, *BI, ~0u) != AliasAnalysis::MustAlias, + Assert1(AI == BI || AA->alias(*AI, *BI) != AliasAnalysis::MustAlias, "Unusual: noalias argument aliases another argument", &I); } @@ -520,6 +518,9 @@ void Lint::visitVAArgInst(VAArgInst &I) { void Lint::visitIndirectBrInst(IndirectBrInst &I) { visitMemoryReference(I, I.getAddress(), ~0u, 0, 0, MemRef::Branchee); + + Assert1(I.getNumDestinations() != 0, + "Undefined behavior: indirectbr with no destinations", &I); } void Lint::visitExtractElementInst(ExtractElementInst &I) { diff --git a/lib/Analysis/LiveValues.cpp b/lib/Analysis/LiveValues.cpp index 23964ff..0225f4f 100644 --- a/lib/Analysis/LiveValues.cpp +++ b/lib/Analysis/LiveValues.cpp @@ -22,10 +22,10 @@ namespace llvm { } char LiveValues::ID = 0; -static RegisterPass -X("live-values", "Value Liveness Analysis", false, true); +INITIALIZE_PASS(LiveValues, "live-values", + "Value Liveness Analysis", false, true); -LiveValues::LiveValues() : FunctionPass(&ID) {} +LiveValues::LiveValues() : FunctionPass(ID) {} void LiveValues::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); diff --git a/lib/Analysis/LoopDependenceAnalysis.cpp b/lib/Analysis/LoopDependenceAnalysis.cpp index e101947..82c02dc 100644 --- a/lib/Analysis/LoopDependenceAnalysis.cpp +++ b/lib/Analysis/LoopDependenceAnalysis.cpp @@ -46,8 +46,8 @@ LoopPass *llvm::createLoopDependenceAnalysisPass() { return new LoopDependenceAnalysis(); } -static RegisterPass -R("lda", "Loop Dependence Analysis", false, true); +INITIALIZE_PASS(LoopDependenceAnalysis, "lda", + "Loop Dependence Analysis", false, true); char LoopDependenceAnalysis::ID = 0; //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/LoopInfo.cpp b/lib/Analysis/LoopInfo.cpp index 818d0a9..46219d1 100644 --- a/lib/Analysis/LoopInfo.cpp +++ b/lib/Analysis/LoopInfo.cpp @@ -38,8 +38,7 @@ VerifyLoopInfoX("verify-loop-info", cl::location(VerifyLoopInfo), cl::desc("Verify loop info (time consuming)")); char LoopInfo::ID = 0; -static RegisterPass -X("loops", "Natural Loop Information", true, true); +INITIALIZE_PASS(LoopInfo, "loops", "Natural Loop Information", true, true); //===----------------------------------------------------------------------===// // Loop implementation @@ -124,14 +123,13 @@ PHINode *Loop::getCanonicalInductionVariable() const { BasicBlock *H = getHeader(); BasicBlock *Incoming = 0, *Backedge = 0; - typedef GraphTraits > InvBlockTraits; - InvBlockTraits::ChildIteratorType PI = InvBlockTraits::child_begin(H); - assert(PI != InvBlockTraits::child_end(H) && + pred_iterator PI = pred_begin(H); + assert(PI != pred_end(H) && "Loop must have at least one backedge!"); Backedge = *PI++; - if (PI == InvBlockTraits::child_end(H)) return 0; // dead loop + if (PI == pred_end(H)) return 0; // dead loop Incoming = *PI++; - if (PI != InvBlockTraits::child_end(H)) return 0; // multiple backedges? + if (PI != pred_end(H)) return 0; // multiple backedges? if (contains(Incoming)) { if (contains(Backedge)) @@ -157,18 +155,6 @@ PHINode *Loop::getCanonicalInductionVariable() const { return 0; } -/// getCanonicalInductionVariableIncrement - Return the LLVM value that holds -/// the canonical induction variable value for the "next" iteration of the -/// loop. This always succeeds if getCanonicalInductionVariable succeeds. -/// -Instruction *Loop::getCanonicalInductionVariableIncrement() const { - if (PHINode *PN = getCanonicalInductionVariable()) { - bool P1InLoop = contains(PN->getIncomingBlock(1)); - return cast(PN->getIncomingValue(P1InLoop)); - } - return 0; -} - /// getTripCount - Return a loop-invariant LLVM value indicating the number of /// times the loop will be executed. Note that this means that the backedge /// of the loop executes N-1 times. If the trip-count cannot be determined, @@ -180,12 +166,12 @@ Instruction *Loop::getCanonicalInductionVariableIncrement() const { Value *Loop::getTripCount() const { // Canonical loops will end with a 'cmp ne I, V', where I is the incremented // canonical induction variable and V is the trip count of the loop. - Instruction *Inc = getCanonicalInductionVariableIncrement(); - if (Inc == 0) return 0; - PHINode *IV = cast(Inc->getOperand(0)); + PHINode *IV = getCanonicalInductionVariable(); + if (IV == 0 || IV->getNumIncomingValues() != 2) return 0; - BasicBlock *BackedgeBlock = - IV->getIncomingBlock(contains(IV->getIncomingBlock(1))); + bool P0InLoop = contains(IV->getIncomingBlock(0)); + Value *Inc = IV->getIncomingValue(!P0InLoop); + BasicBlock *BackedgeBlock = IV->getIncomingBlock(!P0InLoop); if (BranchInst *BI = dyn_cast(BackedgeBlock->getTerminator())) if (BI->isConditional()) { @@ -341,16 +327,12 @@ Loop::getUniqueExitBlocks(SmallVectorImpl &ExitBlocks) const { BasicBlock *current = *BI; switchExitBlocks.clear(); - typedef GraphTraits BlockTraits; - typedef GraphTraits > InvBlockTraits; - for (BlockTraits::ChildIteratorType I = - BlockTraits::child_begin(*BI), E = BlockTraits::child_end(*BI); - I != E; ++I) { + for (succ_iterator I = succ_begin(*BI), E = succ_end(*BI); I != E; ++I) { // If block is inside the loop then it is not a exit block. if (std::binary_search(LoopBBs.begin(), LoopBBs.end(), *I)) continue; - InvBlockTraits::ChildIteratorType PI = InvBlockTraits::child_begin(*I); + pred_iterator PI = pred_begin(*I); BasicBlock *firstPred = *PI; // If current basic block is this exit block's first predecessor @@ -363,8 +345,7 @@ Loop::getUniqueExitBlocks(SmallVectorImpl &ExitBlocks) const { // If a terminator has more then two successors, for example SwitchInst, // then it is possible that there are multiple edges from current block // to one exit block. - if (std::distance(BlockTraits::child_begin(current), - BlockTraits::child_end(current)) <= 2) { + if (std::distance(succ_begin(current), succ_end(current)) <= 2) { ExitBlocks.push_back(*I); continue; } diff --git a/lib/Analysis/LoopPass.cpp b/lib/Analysis/LoopPass.cpp index 2727d2f..15d4db8 100644 --- a/lib/Analysis/LoopPass.cpp +++ b/lib/Analysis/LoopPass.cpp @@ -30,9 +30,9 @@ private: public: static char ID; - PrintLoopPass() : LoopPass(&ID), Out(dbgs()) {} + PrintLoopPass() : LoopPass(ID), Out(dbgs()) {} PrintLoopPass(const std::string &B, raw_ostream &o) - : LoopPass(&ID), Banner(B), Out(o) {} + : LoopPass(ID), Banner(B), Out(o) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); @@ -59,7 +59,7 @@ char PrintLoopPass::ID = 0; char LPPassManager::ID = 0; LPPassManager::LPPassManager(int Depth) - : FunctionPass(&ID), PMDataManager(Depth) { + : FunctionPass(ID), PMDataManager(Depth) { skipThisLoop = false; redoThisLoop = false; LI = NULL; @@ -183,7 +183,7 @@ void LPPassManager::redoLoop(Loop *L) { void LPPassManager::cloneBasicBlockSimpleAnalysis(BasicBlock *From, BasicBlock *To, Loop *L) { for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) { - LoopPass *LP = (LoopPass *)getContainedPass(Index); + LoopPass *LP = getContainedPass(Index); LP->cloneBasicBlockAnalysis(From, To, L); } } @@ -198,7 +198,7 @@ void LPPassManager::deleteSimpleAnalysisValue(Value *V, Loop *L) { } } for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) { - LoopPass *LP = (LoopPass *)getContainedPass(Index); + LoopPass *LP = getContainedPass(Index); LP->deleteAnalysisValue(V, L); } } @@ -240,7 +240,7 @@ bool LPPassManager::runOnFunction(Function &F) { I != E; ++I) { Loop *L = *I; for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) { - LoopPass *P = (LoopPass*)getContainedPass(Index); + LoopPass *P = getContainedPass(Index); Changed |= P->doInitialization(L, *this); } } @@ -254,7 +254,7 @@ bool LPPassManager::runOnFunction(Function &F) { // Run all passes on the current Loop. for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) { - LoopPass *P = (LoopPass*)getContainedPass(Index); + LoopPass *P = getContainedPass(Index); dumpPassInfo(P, EXECUTION_MSG, ON_LOOP_MSG, CurrentLoop->getHeader()->getName()); @@ -320,7 +320,7 @@ bool LPPassManager::runOnFunction(Function &F) { // Finalization for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) { - LoopPass *P = (LoopPass *)getContainedPass(Index); + LoopPass *P = getContainedPass(Index); Changed |= P->doFinalization(); } diff --git a/lib/Analysis/MemoryDependenceAnalysis.cpp b/lib/Analysis/MemoryDependenceAnalysis.cpp index 1f54d74..d18d5ce 100644 --- a/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -46,11 +46,11 @@ STATISTIC(NumCacheCompleteNonLocalPtr, char MemoryDependenceAnalysis::ID = 0; // Register this pass... -static RegisterPass X("memdep", - "Memory Dependence Analysis", false, true); +INITIALIZE_PASS(MemoryDependenceAnalysis, "memdep", + "Memory Dependence Analysis", false, true); MemoryDependenceAnalysis::MemoryDependenceAnalysis() -: FunctionPass(&ID), PredCache(0) { +: FunctionPass(ID), PredCache(0) { } MemoryDependenceAnalysis::~MemoryDependenceAnalysis() { } @@ -120,33 +120,21 @@ getCallSiteDependencyFrom(CallSite CS, bool isReadOnlyCall, Pointer = CI->getArgOperand(0); // calls to free() erase the entire structure PointerSize = ~0ULL; - } else if (isa(Inst) || isa(Inst)) { + } else if (CallSite InstCS = cast(Inst)) { // Debug intrinsics don't cause dependences. if (isa(Inst)) continue; - CallSite InstCS = CallSite::get(Inst); // If these two calls do not interfere, look past it. switch (AA->getModRefInfo(CS, InstCS)) { case AliasAnalysis::NoModRef: - // If the two calls don't interact (e.g. InstCS is readnone) keep - // scanning. + // If the two calls are the same, return InstCS as a Def, so that + // CS can be found redundant and eliminated. + if (isReadOnlyCall && InstCS.onlyReadsMemory() && + CS.getInstruction()->isIdenticalToWhenDefined(Inst)) + return MemDepResult::getDef(Inst); + + // Otherwise if the two calls don't interact (e.g. InstCS is readnone) + // keep scanning. continue; - case AliasAnalysis::Ref: - // If the two calls read the same memory locations and CS is a readonly - // function, then we have two cases: 1) the calls may not interfere with - // each other at all. 2) the calls may produce the same value. In case - // #1 we want to ignore the values, in case #2, we want to return Inst - // as a Def dependence. This allows us to CSE in cases like: - // X = strlen(P); - // memchr(...); - // Y = strlen(P); // Y = X - if (isReadOnlyCall) { - if (CS.getCalledFunction() != 0 && - CS.getCalledFunction() == InstCS.getCalledFunction()) - return MemDepResult::getDef(Inst); - // Ignore unrelated read/read call dependences. - continue; - } - // FALL THROUGH default: return MemDepResult::getClobber(Inst); } @@ -196,8 +184,7 @@ getPointerDependencyFrom(Value *MemPtr, uint64_t MemSize, bool isLoad, // FIXME: This only considers queries directly on the invariant-tagged // pointer, not on query pointers that are indexed off of them. It'd // be nice to handle that at some point. - AliasAnalysis::AliasResult R = - AA->alias(II->getArgOperand(2), ~0U, MemPtr, ~0U); + AliasAnalysis::AliasResult R = AA->alias(II->getArgOperand(2), MemPtr); if (R == AliasAnalysis::MustAlias) { InvariantTag = II->getArgOperand(0); continue; @@ -209,8 +196,7 @@ getPointerDependencyFrom(Value *MemPtr, uint64_t MemSize, bool isLoad, // FIXME: This only considers queries directly on the invariant-tagged // pointer, not on query pointers that are indexed off of them. It'd // be nice to handle that at some point. - AliasAnalysis::AliasResult R = - AA->alias(II->getArgOperand(1), ~0U, MemPtr, ~0U); + AliasAnalysis::AliasResult R = AA->alias(II->getArgOperand(1), MemPtr); if (R == AliasAnalysis::MustAlias) return MemDepResult::getDef(II); } @@ -387,7 +373,7 @@ MemDepResult MemoryDependenceAnalysis::getDependency(Instruction *QueryInst) { MemSize = cast(II->getArgOperand(1))->getZExtValue(); break; default: - CallSite QueryCS = CallSite::get(QueryInst); + CallSite QueryCS(QueryInst); bool isReadOnly = AA->onlyReadsMemory(QueryCS); LocalCache = getCallSiteDependencyFrom(QueryCS, isReadOnly, ScanPos, QueryParent); diff --git a/lib/Analysis/ModuleDebugInfoPrinter.cpp b/lib/Analysis/ModuleDebugInfoPrinter.cpp index 556d4c8..2cc1c2a 100644 --- a/lib/Analysis/ModuleDebugInfoPrinter.cpp +++ b/lib/Analysis/ModuleDebugInfoPrinter.cpp @@ -30,7 +30,7 @@ namespace { DebugInfoFinder Finder; public: static char ID; // Pass identification, replacement for typeid - ModuleDebugInfoPrinter() : ModulePass(&ID) {} + ModuleDebugInfoPrinter() : ModulePass(ID) {} virtual bool runOnModule(Module &M); @@ -42,9 +42,8 @@ namespace { } char ModuleDebugInfoPrinter::ID = 0; -static RegisterPass -X("module-debuginfo", - "Decodes module-level debug info", false, true); +INITIALIZE_PASS(ModuleDebugInfoPrinter, "module-debuginfo", + "Decodes module-level debug info", false, true); ModulePass *llvm::createModuleDebugInfoPrinterPass() { return new ModuleDebugInfoPrinter(); diff --git a/lib/Analysis/PointerTracking.cpp b/lib/Analysis/PointerTracking.cpp index 14df0b7..07f4682 100644 --- a/lib/Analysis/PointerTracking.cpp +++ b/lib/Analysis/PointerTracking.cpp @@ -28,7 +28,7 @@ using namespace llvm; char PointerTracking::ID = 0; -PointerTracking::PointerTracking() : FunctionPass(&ID) {} +PointerTracking::PointerTracking() : FunctionPass(ID) {} bool PointerTracking::runOnFunction(Function &F) { predCache.clear(); @@ -144,6 +144,55 @@ const SCEV *PointerTracking::computeAllocationCount(Value *P, return SE->getCouldNotCompute(); } +Value *PointerTracking::computeAllocationCountValue(Value *P, const Type *&Ty) const +{ + Value *V = P->stripPointerCasts(); + if (AllocaInst *AI = dyn_cast(V)) { + Ty = AI->getAllocatedType(); + // arraySize elements of type Ty. + return AI->getArraySize(); + } + + if (CallInst *CI = extractMallocCall(V)) { + Ty = getMallocAllocatedType(CI); + if (!Ty) + return 0; + Value *arraySize = getMallocArraySize(CI, TD); + if (!arraySize) { + Ty = Type::getInt8Ty(P->getContext()); + return CI->getArgOperand(0); + } + // arraySize elements of type Ty. + return arraySize; + } + + if (GlobalVariable *GV = dyn_cast(V)) { + if (GV->hasDefinitiveInitializer()) { + Constant *C = GV->getInitializer(); + if (const ArrayType *ATy = dyn_cast(C->getType())) { + Ty = ATy->getElementType(); + return ConstantInt::get(Type::getInt32Ty(P->getContext()), + ATy->getNumElements()); + } + } + Ty = cast(GV->getType())->getElementType(); + return ConstantInt::get(Type::getInt32Ty(P->getContext()), 1); + //TODO: implement more tracking for globals + } + + if (CallInst *CI = dyn_cast(V)) { + CallSite CS(CI); + Function *F = dyn_cast(CS.getCalledValue()->stripPointerCasts()); + if (F == reallocFunc) { + Ty = Type::getInt8Ty(P->getContext()); + // realloc allocates arg1 bytes. + return CS.getArgument(1); + } + } + + return 0; +} + // Calculates the number of elements of type Ty allocated for P. const SCEV *PointerTracking::computeAllocationCountForType(Value *P, const Type *Ty) @@ -263,5 +312,5 @@ void PointerTracking::print(raw_ostream &OS, const Module* M) const { } } -static RegisterPass X("pointertracking", - "Track pointer bounds", false, true); +INITIALIZE_PASS(PointerTracking, "pointertracking", + "Track pointer bounds", false, true); diff --git a/lib/Analysis/PostDominators.cpp b/lib/Analysis/PostDominators.cpp index 7354afa..cbe8d18 100644 --- a/lib/Analysis/PostDominators.cpp +++ b/lib/Analysis/PostDominators.cpp @@ -28,8 +28,8 @@ using namespace llvm; char PostDominatorTree::ID = 0; char PostDominanceFrontier::ID = 0; -static RegisterPass -F("postdomtree", "Post-Dominator Tree Construction", true, true); +INITIALIZE_PASS(PostDominatorTree, "postdomtree", + "Post-Dominator Tree Construction", true, true); bool PostDominatorTree::runOnFunction(Function &F) { DT->recalculate(F); @@ -53,8 +53,8 @@ FunctionPass* llvm::createPostDomTree() { // PostDominanceFrontier Implementation //===----------------------------------------------------------------------===// -static RegisterPass -H("postdomfrontier", "Post-Dominance Frontier Construction", true, true); +INITIALIZE_PASS(PostDominanceFrontier, "postdomfrontier", + "Post-Dominance Frontier Construction", true, true); const DominanceFrontier::DomSetType & PostDominanceFrontier::calculate(const PostDominatorTree &DT, diff --git a/lib/Analysis/ProfileEstimatorPass.cpp b/lib/Analysis/ProfileEstimatorPass.cpp index da4ce47..ecc0a18 100644 --- a/lib/Analysis/ProfileEstimatorPass.cpp +++ b/lib/Analysis/ProfileEstimatorPass.cpp @@ -39,7 +39,7 @@ namespace { public: static char ID; // Class identification, replacement for typeinfo explicit ProfileEstimatorPass(const double execcount = 0) - : FunctionPass(&ID), ExecCount(execcount) { + : FunctionPass(ID), ExecCount(execcount) { if (execcount == 0) ExecCount = LoopWeight; } @@ -59,8 +59,8 @@ namespace { /// an analysis interface through multiple inheritance. If needed, it /// should override this to adjust the this pointer as needed for the /// specified pass info. - virtual void *getAdjustedAnalysisPointer(const PassInfo *PI) { - if (PI->isPassID(&ProfileInfo::ID)) + virtual void *getAdjustedAnalysisPointer(AnalysisID PI) { + if (PI == &ProfileInfo::ID) return (ProfileInfo*)this; return this; } @@ -72,13 +72,11 @@ namespace { } // End of anonymous namespace char ProfileEstimatorPass::ID = 0; -static RegisterPass -X("profile-estimator", "Estimate profiling information", false, true); - -static RegisterAnalysisGroup Y(X); +INITIALIZE_AG_PASS(ProfileEstimatorPass, ProfileInfo, "profile-estimator", + "Estimate profiling information", false, true, false); namespace llvm { - const PassInfo *ProfileEstimatorPassID = &X; + char &ProfileEstimatorPassID = ProfileEstimatorPass::ID; FunctionPass *createProfileEstimatorPass() { return new ProfileEstimatorPass(); diff --git a/lib/Analysis/ProfileInfo.cpp b/lib/Analysis/ProfileInfo.cpp index 8d2712f..fc7f286 100644 --- a/lib/Analysis/ProfileInfo.cpp +++ b/lib/Analysis/ProfileInfo.cpp @@ -1076,14 +1076,14 @@ raw_ostream& operator<<(raw_ostream &O, std::pairisPassID(&ProfileInfo::ID)) + virtual void *getAdjustedAnalysisPointer(AnalysisID PI) { + if (PI == &ProfileInfo::ID) return (ProfileInfo*)this; return this; } @@ -1096,10 +1096,7 @@ namespace { char NoProfileInfo::ID = 0; // Register this pass... -static RegisterPass -X("no-profile", "No Profile Information", false, true); - -// Declare that we implement the ProfileInfo interface -static RegisterAnalysisGroup Y(X); +INITIALIZE_AG_PASS(NoProfileInfo, ProfileInfo, "no-profile", + "No Profile Information", false, true, true); ImmutablePass *llvm::createNoProfileInfoPass() { return new NoProfileInfo(); } diff --git a/lib/Analysis/ProfileInfoLoaderPass.cpp b/lib/Analysis/ProfileInfoLoaderPass.cpp index 8ea4ecf..d325b57 100644 --- a/lib/Analysis/ProfileInfoLoaderPass.cpp +++ b/lib/Analysis/ProfileInfoLoaderPass.cpp @@ -45,7 +45,7 @@ namespace { public: static char ID; // Class identification, replacement for typeinfo explicit LoaderPass(const std::string &filename = "") - : ModulePass(&ID), Filename(filename) { + : ModulePass(ID), Filename(filename) { if (filename.empty()) Filename = ProfileInfoFilename; } @@ -67,8 +67,8 @@ namespace { /// an analysis interface through multiple inheritance. If needed, it /// should override this to adjust the this pointer as needed for the /// specified pass info. - virtual void *getAdjustedAnalysisPointer(const PassInfo *PI) { - if (PI->isPassID(&ProfileInfo::ID)) + virtual void *getAdjustedAnalysisPointer(AnalysisID PI) { + if (PI == &ProfileInfo::ID) return (ProfileInfo*)this; return this; } @@ -79,12 +79,10 @@ namespace { } // End of anonymous namespace char LoaderPass::ID = 0; -static RegisterPass -X("profile-loader", "Load profile information from llvmprof.out", false, true); +INITIALIZE_AG_PASS(LoaderPass, ProfileInfo, "profile-loader", + "Load profile information from llvmprof.out", false, true, false); -static RegisterAnalysisGroup Y(X); - -const PassInfo *llvm::ProfileLoaderPassID = &X; +char &llvm::ProfileLoaderPassID = LoaderPass::ID; ModulePass *llvm::createProfileLoaderPass() { return new LoaderPass(); } diff --git a/lib/Analysis/ProfileVerifierPass.cpp b/lib/Analysis/ProfileVerifierPass.cpp index 5d87e14..3f01b2d 100644 --- a/lib/Analysis/ProfileVerifierPass.cpp +++ b/lib/Analysis/ProfileVerifierPass.cpp @@ -59,10 +59,10 @@ namespace llvm { public: static char ID; // Class identification, replacement for typeinfo - explicit ProfileVerifierPassT () : FunctionPass(&ID) { + explicit ProfileVerifierPassT () : FunctionPass(ID) { DisableAssertions = ProfileVerifierDisableAssertions; } - explicit ProfileVerifierPassT (bool da) : FunctionPass(&ID), + explicit ProfileVerifierPassT (bool da) : FunctionPass(ID), DisableAssertions(da) { } @@ -366,8 +366,8 @@ namespace llvm { char ProfileVerifierPassT::ID = 0; } -static RegisterPass -X("profile-verifier", "Verify profiling information", false, true); +INITIALIZE_PASS(ProfileVerifierPass, "profile-verifier", + "Verify profiling information", false, true); namespace llvm { FunctionPass *createProfileVerifierPass() { diff --git a/lib/Analysis/RegionInfo.cpp b/lib/Analysis/RegionInfo.cpp new file mode 100644 index 0000000..abc057a --- /dev/null +++ b/lib/Analysis/RegionInfo.cpp @@ -0,0 +1,749 @@ +//===- RegionInfo.cpp - SESE region detection analysis --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Detects single entry single exit regions in the control flow graph. +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/RegionInfo.h" +#include "llvm/Analysis/RegionIterator.h" + +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Analysis/LoopInfo.h" + +#define DEBUG_TYPE "region" +#include "llvm/Support/Debug.h" + +#include +#include + +using namespace llvm; + +// Always verify if expensive checking is enabled. +#ifdef XDEBUG +static bool VerifyRegionInfo = true; +#else +static bool VerifyRegionInfo = false; +#endif + +static cl::opt +VerifyRegionInfoX("verify-region-info", cl::location(VerifyRegionInfo), + cl::desc("Verify region info (time consuming)")); + +STATISTIC(numRegions, "The # of regions"); +STATISTIC(numSimpleRegions, "The # of simple regions"); + +//===----------------------------------------------------------------------===// +/// PrintStyle - Print region in difference ways. +enum PrintStyle { PrintNone, PrintBB, PrintRN }; + +cl::opt printStyle("print-region-style", cl::Hidden, + cl::desc("style of printing regions"), + cl::values( + clEnumValN(PrintNone, "none", "print no details"), + clEnumValN(PrintBB, "bb", "print regions in detail with block_iterator"), + clEnumValN(PrintRN, "rn", "print regions in detail with element_iterator"), + clEnumValEnd)); +//===----------------------------------------------------------------------===// +/// Region Implementation +Region::Region(BasicBlock *Entry, BasicBlock *Exit, RegionInfo* RInfo, + DominatorTree *dt, Region *Parent) + : RegionNode(Parent, Entry, 1), RI(RInfo), DT(dt), exit(Exit) {} + +Region::~Region() { + // Free the cached nodes. + for (BBNodeMapT::iterator it = BBNodeMap.begin(), + ie = BBNodeMap.end(); it != ie; ++it) + delete it->second; + + // Only clean the cache for this Region. Caches of child Regions will be + // cleaned when the child Regions are deleted. + BBNodeMap.clear(); + + for (iterator I = begin(), E = end(); I != E; ++I) + delete *I; +} + +bool Region::contains(const BasicBlock *B) const { + BasicBlock *BB = const_cast(B); + + assert(DT->getNode(BB) && "BB not part of the dominance tree"); + + BasicBlock *entry = getEntry(), *exit = getExit(); + + // Toplevel region. + if (!exit) + return true; + + return (DT->dominates(entry, BB) + && !(DT->dominates(exit, BB) && DT->dominates(entry, exit))); +} + +bool Region::contains(const Loop *L) const { + // BBs that are not part of any loop are element of the Loop + // described by the NULL pointer. This loop is not part of any region, + // except if the region describes the whole function. + if (L == 0) + return getExit() == 0; + + if (!contains(L->getHeader())) + return false; + + SmallVector ExitingBlocks; + L->getExitingBlocks(ExitingBlocks); + + for (SmallVectorImpl::iterator BI = ExitingBlocks.begin(), + BE = ExitingBlocks.end(); BI != BE; ++BI) + if (!contains(*BI)) + return false; + + return true; +} + +Loop *Region::outermostLoopInRegion(Loop *L) const { + if (!contains(L)) + return 0; + + while (L && contains(L->getParentLoop())) { + L = L->getParentLoop(); + } + + return L; +} + +Loop *Region::outermostLoopInRegion(LoopInfo *LI, BasicBlock* BB) const { + assert(LI && BB && "LI and BB cannot be null!"); + Loop *L = LI->getLoopFor(BB); + return outermostLoopInRegion(L); +} + +bool Region::isSimple() const { + bool isSimple = true; + bool found = false; + + BasicBlock *entry = getEntry(), *exit = getExit(); + + // TopLevelRegion + if (!exit) + return false; + + for (pred_iterator PI = pred_begin(entry), PE = pred_end(entry); PI != PE; + ++PI) { + BasicBlock *Pred = *PI; + if (DT->getNode(Pred) && !contains(Pred)) { + if (found) { + isSimple = false; + break; + } + found = true; + } + } + + found = false; + + for (pred_iterator PI = pred_begin(exit), PE = pred_end(exit); PI != PE; + ++PI) + if (contains(*PI)) { + if (found) { + isSimple = false; + break; + } + found = true; + } + + return isSimple; +} + +std::string Region::getNameStr() const { + std::string exitName; + std::string entryName; + + if (getEntry()->getName().empty()) { + raw_string_ostream OS(entryName); + + WriteAsOperand(OS, getEntry(), false); + entryName = OS.str(); + } else + entryName = getEntry()->getNameStr(); + + if (getExit()) { + if (getExit()->getName().empty()) { + raw_string_ostream OS(exitName); + + WriteAsOperand(OS, getExit(), false); + exitName = OS.str(); + } else + exitName = getExit()->getNameStr(); + } else + exitName = ""; + + return entryName + " => " + exitName; +} + +void Region::verifyBBInRegion(BasicBlock *BB) const { + if (!contains(BB)) + llvm_unreachable("Broken region found!"); + + BasicBlock *entry = getEntry(), *exit = getExit(); + + for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI) + if (!contains(*SI) && exit != *SI) + llvm_unreachable("Broken region found!"); + + if (entry != BB) + for (pred_iterator SI = pred_begin(BB), SE = pred_end(BB); SI != SE; ++SI) + if (!contains(*SI)) + llvm_unreachable("Broken region found!"); +} + +void Region::verifyWalk(BasicBlock *BB, std::set *visited) const { + BasicBlock *exit = getExit(); + + visited->insert(BB); + + verifyBBInRegion(BB); + + for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI) + if (*SI != exit && visited->find(*SI) == visited->end()) + verifyWalk(*SI, visited); +} + +void Region::verifyRegion() const { + // Only do verification when user wants to, otherwise this expensive + // check will be invoked by PassManager. + if (!VerifyRegionInfo) return; + + std::set visited; + verifyWalk(getEntry(), &visited); +} + +void Region::verifyRegionNest() const { + for (Region::const_iterator RI = begin(), RE = end(); RI != RE; ++RI) + (*RI)->verifyRegionNest(); + + verifyRegion(); +} + +Region::block_iterator Region::block_begin() { + return GraphTraits >::nodes_begin(this); +} + +Region::block_iterator Region::block_end() { + return GraphTraits >::nodes_end(this); +} + +Region::const_block_iterator Region::block_begin() const { + return GraphTraits >::nodes_begin(this); +} + +Region::const_block_iterator Region::block_end() const { + return GraphTraits >::nodes_end(this); +} + +Region::element_iterator Region::element_begin() { + return GraphTraits::nodes_begin(this); +} + +Region::element_iterator Region::element_end() { + return GraphTraits::nodes_end(this); +} + +Region::const_element_iterator Region::element_begin() const { + return GraphTraits::nodes_begin(this); +} + +Region::const_element_iterator Region::element_end() const { + return GraphTraits::nodes_end(this); +} + +Region* Region::getSubRegionNode(BasicBlock *BB) const { + Region *R = RI->getRegionFor(BB); + + if (!R || R == this) + return 0; + + // If we pass the BB out of this region, that means our code is broken. + assert(contains(R) && "BB not in current region!"); + + while (contains(R->getParent()) && R->getParent() != this) + R = R->getParent(); + + if (R->getEntry() != BB) + return 0; + + return R; +} + +RegionNode* Region::getBBNode(BasicBlock *BB) const { + assert(contains(BB) && "Can get BB node out of this region!"); + + BBNodeMapT::const_iterator at = BBNodeMap.find(BB); + + if (at != BBNodeMap.end()) + return at->second; + + RegionNode *NewNode = new RegionNode(const_cast(this), BB); + BBNodeMap.insert(std::make_pair(BB, NewNode)); + return NewNode; +} + +RegionNode* Region::getNode(BasicBlock *BB) const { + assert(contains(BB) && "Can get BB node out of this region!"); + if (Region* Child = getSubRegionNode(BB)) + return Child->getNode(); + + return getBBNode(BB); +} + +void Region::transferChildrenTo(Region *To) { + for (iterator I = begin(), E = end(); I != E; ++I) { + (*I)->parent = To; + To->children.push_back(*I); + } + children.clear(); +} + +void Region::addSubRegion(Region *SubRegion) { + assert(SubRegion->parent == 0 && "SubRegion already has a parent!"); + SubRegion->parent = this; + // Set up the region node. + assert(std::find(children.begin(), children.end(), SubRegion) == children.end() + && "Node already exist!"); + children.push_back(SubRegion); +} + + +Region *Region::removeSubRegion(Region *Child) { + assert(Child->parent == this && "Child is not a child of this region!"); + Child->parent = 0; + RegionSet::iterator I = std::find(children.begin(), children.end(), Child); + assert(I != children.end() && "Region does not exit. Unable to remove."); + children.erase(children.begin()+(I-begin())); + return Child; +} + +unsigned Region::getDepth() const { + unsigned Depth = 0; + + for (Region *R = parent; R != 0; R = R->parent) + ++Depth; + + return Depth; +} + +void Region::print(raw_ostream &OS, bool print_tree, unsigned level) const { + if (print_tree) + OS.indent(level*2) << "[" << level << "] " << getNameStr(); + else + OS.indent(level*2) << getNameStr(); + + OS << "\n"; + + + if (printStyle != PrintNone) { + OS.indent(level*2) << "{\n"; + OS.indent(level*2 + 2); + + if (printStyle == PrintBB) { + for (const_block_iterator I = block_begin(), E = block_end(); I!=E; ++I) + OS << **I << ", "; // TODO: remove the last "," + } else if (printStyle == PrintRN) { + for (const_element_iterator I = element_begin(), E = element_end(); I!=E; ++I) + OS << **I << ", "; // TODO: remove the last ", + } + + OS << "\n"; + } + + if (print_tree) + for (const_iterator RI = begin(), RE = end(); RI != RE; ++RI) + (*RI)->print(OS, print_tree, level+1); + + if (printStyle != PrintNone) + OS.indent(level*2) << "} \n"; +} + +void Region::dump() const { + print(dbgs(), true, getDepth()); +} + +void Region::clearNodeCache() { + BBNodeMap.clear(); + for (Region::iterator RI = begin(), RE = end(); RI != RE; ++RI) + (*RI)->clearNodeCache(); +} + +//===----------------------------------------------------------------------===// +// RegionInfo implementation +// + +bool RegionInfo::isCommonDomFrontier(BasicBlock *BB, BasicBlock *entry, + BasicBlock *exit) const { + for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE; ++PI) { + BasicBlock *P = *PI; + if (DT->dominates(entry, P) && !DT->dominates(exit, P)) + return false; + } + return true; +} + +bool RegionInfo::isRegion(BasicBlock *entry, BasicBlock *exit) const { + assert(entry && exit && "entry and exit must not be null!"); + typedef DominanceFrontier::DomSetType DST; + + DST *entrySuccs = &DF->find(entry)->second; + + // Exit is the header of a loop that contains the entry. In this case, + // the dominance frontier must only contain the exit. + if (!DT->dominates(entry, exit)) { + for (DST::iterator SI = entrySuccs->begin(), SE = entrySuccs->end(); + SI != SE; ++SI) + if (*SI != exit && *SI != entry) + return false; + + return true; + } + + DST *exitSuccs = &DF->find(exit)->second; + + // Do not allow edges leaving the region. + for (DST::iterator SI = entrySuccs->begin(), SE = entrySuccs->end(); + SI != SE; ++SI) { + if (*SI == exit || *SI == entry) + continue; + if (exitSuccs->find(*SI) == exitSuccs->end()) + return false; + if (!isCommonDomFrontier(*SI, entry, exit)) + return false; + } + + // Do not allow edges pointing into the region. + for (DST::iterator SI = exitSuccs->begin(), SE = exitSuccs->end(); + SI != SE; ++SI) + if (DT->properlyDominates(entry, *SI) && *SI != exit) + return false; + + + return true; +} + +void RegionInfo::insertShortCut(BasicBlock *entry, BasicBlock *exit, + BBtoBBMap *ShortCut) const { + assert(entry && exit && "entry and exit must not be null!"); + + BBtoBBMap::iterator e = ShortCut->find(exit); + + if (e == ShortCut->end()) + // No further region at exit available. + (*ShortCut)[entry] = exit; + else { + // We found a region e that starts at exit. Therefore (entry, e->second) + // is also a region, that is larger than (entry, exit). Insert the + // larger one. + BasicBlock *BB = e->second; + (*ShortCut)[entry] = BB; + } +} + +DomTreeNode* RegionInfo::getNextPostDom(DomTreeNode* N, + BBtoBBMap *ShortCut) const { + BBtoBBMap::iterator e = ShortCut->find(N->getBlock()); + + if (e == ShortCut->end()) + return N->getIDom(); + + return PDT->getNode(e->second)->getIDom(); +} + +bool RegionInfo::isTrivialRegion(BasicBlock *entry, BasicBlock *exit) const { + assert(entry && exit && "entry and exit must not be null!"); + + unsigned num_successors = succ_end(entry) - succ_begin(entry); + + if (num_successors <= 1 && exit == *(succ_begin(entry))) + return true; + + return false; +} + +void RegionInfo::updateStatistics(Region *R) { + ++numRegions; + + // TODO: Slow. Should only be enabled if -stats is used. + if (R->isSimple()) ++numSimpleRegions; +} + +Region *RegionInfo::createRegion(BasicBlock *entry, BasicBlock *exit) { + assert(entry && exit && "entry and exit must not be null!"); + + if (isTrivialRegion(entry, exit)) + return 0; + + Region *region = new Region(entry, exit, this, DT); + BBtoRegion.insert(std::make_pair(entry, region)); + + #ifdef XDEBUG + region->verifyRegion(); + #else + DEBUG(region->verifyRegion()); + #endif + + updateStatistics(region); + return region; +} + +void RegionInfo::findRegionsWithEntry(BasicBlock *entry, BBtoBBMap *ShortCut) { + assert(entry); + + DomTreeNode *N = PDT->getNode(entry); + + if (!N) + return; + + Region *lastRegion= 0; + BasicBlock *lastExit = entry; + + // As only a BasicBlock that postdominates entry can finish a region, walk the + // post dominance tree upwards. + while ((N = getNextPostDom(N, ShortCut))) { + BasicBlock *exit = N->getBlock(); + + if (!exit) + break; + + if (isRegion(entry, exit)) { + Region *newRegion = createRegion(entry, exit); + + if (lastRegion) + newRegion->addSubRegion(lastRegion); + + lastRegion = newRegion; + lastExit = exit; + } + + // This can never be a region, so stop the search. + if (!DT->dominates(entry, exit)) + break; + } + + // Tried to create regions from entry to lastExit. Next time take a + // shortcut from entry to lastExit. + if (lastExit != entry) + insertShortCut(entry, lastExit, ShortCut); +} + +void RegionInfo::scanForRegions(Function &F, BBtoBBMap *ShortCut) { + BasicBlock *entry = &(F.getEntryBlock()); + DomTreeNode *N = DT->getNode(entry); + + // Iterate over the dominance tree in post order to start with the small + // regions from the bottom of the dominance tree. If the small regions are + // detected first, detection of bigger regions is faster, as we can jump + // over the small regions. + for (po_iterator FI = po_begin(N), FE = po_end(N); FI != FE; + ++FI) { + findRegionsWithEntry(FI->getBlock(), ShortCut); + } +} + +Region *RegionInfo::getTopMostParent(Region *region) { + while (region->parent) + region = region->getParent(); + + return region; +} + +void RegionInfo::buildRegionsTree(DomTreeNode *N, Region *region) { + BasicBlock *BB = N->getBlock(); + + // Passed region exit + while (BB == region->getExit()) + region = region->getParent(); + + BBtoRegionMap::iterator it = BBtoRegion.find(BB); + + // This basic block is a start block of a region. It is already in the + // BBtoRegion relation. Only the child basic blocks have to be updated. + if (it != BBtoRegion.end()) { + Region *newRegion = it->second;; + region->addSubRegion(getTopMostParent(newRegion)); + region = newRegion; + } else { + BBtoRegion[BB] = region; + } + + for (DomTreeNode::iterator CI = N->begin(), CE = N->end(); CI != CE; ++CI) + buildRegionsTree(*CI, region); +} + +void RegionInfo::releaseMemory() { + BBtoRegion.clear(); + if (TopLevelRegion) + delete TopLevelRegion; + TopLevelRegion = 0; +} + +RegionInfo::RegionInfo() : FunctionPass(ID) { + TopLevelRegion = 0; +} + +RegionInfo::~RegionInfo() { + releaseMemory(); +} + +void RegionInfo::Calculate(Function &F) { + // ShortCut a function where for every BB the exit of the largest region + // starting with BB is stored. These regions can be threated as single BBS. + // This improves performance on linear CFGs. + BBtoBBMap ShortCut; + + scanForRegions(F, &ShortCut); + BasicBlock *BB = &F.getEntryBlock(); + buildRegionsTree(DT->getNode(BB), TopLevelRegion); +} + +bool RegionInfo::runOnFunction(Function &F) { + releaseMemory(); + + DT = &getAnalysis(); + PDT = &getAnalysis(); + DF = &getAnalysis(); + + TopLevelRegion = new Region(&F.getEntryBlock(), 0, this, DT, 0); + updateStatistics(TopLevelRegion); + + Calculate(F); + + return false; +} + +void RegionInfo::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequiredTransitive(); + AU.addRequired(); + AU.addRequired(); +} + +void RegionInfo::print(raw_ostream &OS, const Module *) const { + OS << "Region tree:\n"; + TopLevelRegion->print(OS, true, 0); + OS << "End region tree\n"; +} + +void RegionInfo::verifyAnalysis() const { + // Only do verification when user wants to, otherwise this expensive check + // will be invoked by PMDataManager::verifyPreservedAnalysis when + // a regionpass (marked PreservedAll) finish. + if (!VerifyRegionInfo) return; + + TopLevelRegion->verifyRegionNest(); +} + +// Region pass manager support. +Region *RegionInfo::getRegionFor(BasicBlock *BB) const { + BBtoRegionMap::const_iterator I= + BBtoRegion.find(BB); + return I != BBtoRegion.end() ? I->second : 0; +} + +Region *RegionInfo::operator[](BasicBlock *BB) const { + return getRegionFor(BB); +} + + +BasicBlock *RegionInfo::getMaxRegionExit(BasicBlock *BB) const { + BasicBlock *Exit = NULL; + + while (true) { + // Get largest region that starts at BB. + Region *R = getRegionFor(BB); + while (R && R->getParent() && R->getParent()->getEntry() == BB) + R = R->getParent(); + + // Get the single exit of BB. + if (R && R->getEntry() == BB) + Exit = R->getExit(); + else if (++succ_begin(BB) == succ_end(BB)) + Exit = *succ_begin(BB); + else // No single exit exists. + return Exit; + + // Get largest region that starts at Exit. + Region *ExitR = getRegionFor(Exit); + while (ExitR && ExitR->getParent() + && ExitR->getParent()->getEntry() == Exit) + ExitR = ExitR->getParent(); + + for (pred_iterator PI = pred_begin(Exit), PE = pred_end(Exit); PI != PE; + ++PI) + if (!R->contains(*PI) && !ExitR->contains(*PI)) + break; + + // This stops infinite cycles. + if (DT->dominates(Exit, BB)) + break; + + BB = Exit; + } + + return Exit; +} + +Region* +RegionInfo::getCommonRegion(Region *A, Region *B) const { + assert (A && B && "One of the Regions is NULL"); + + if (A->contains(B)) return A; + + while (!B->contains(A)) + B = B->getParent(); + + return B; +} + +Region* +RegionInfo::getCommonRegion(SmallVectorImpl &Regions) const { + Region* ret = Regions.back(); + Regions.pop_back(); + + for (SmallVectorImpl::const_iterator I = Regions.begin(), + E = Regions.end(); I != E; ++I) + ret = getCommonRegion(ret, *I); + + return ret; +} + +Region* +RegionInfo::getCommonRegion(SmallVectorImpl &BBs) const { + Region* ret = getRegionFor(BBs.back()); + BBs.pop_back(); + + for (SmallVectorImpl::const_iterator I = BBs.begin(), + E = BBs.end(); I != E; ++I) + ret = getCommonRegion(ret, getRegionFor(*I)); + + return ret; +} + +char RegionInfo::ID = 0; +INITIALIZE_PASS(RegionInfo, "regions", + "Detect single entry single exit regions", true, true); + +// Create methods available outside of this file, to use them +// "include/llvm/LinkAllPasses.h". Otherwise the pass would be deleted by +// the link time optimization. + +namespace llvm { + FunctionPass *createRegionInfoPass() { + return new RegionInfo(); + } +} + diff --git a/lib/Analysis/RegionPrinter.cpp b/lib/Analysis/RegionPrinter.cpp new file mode 100644 index 0000000..fee5c1b --- /dev/null +++ b/lib/Analysis/RegionPrinter.cpp @@ -0,0 +1,186 @@ +//===- RegionPrinter.cpp - Print regions tree pass ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Print out the region tree of a function using dotty/graphviz. +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/RegionInfo.h" +#include "llvm/Analysis/RegionIterator.h" +#include "llvm/Analysis/RegionPrinter.h" +#include "llvm/Analysis/Passes.h" +#include "llvm/Analysis/DOTGraphTraitsPass.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +//===----------------------------------------------------------------------===// +/// onlySimpleRegion - Show only the simple regions in the RegionViewer. +static cl::opt +onlySimpleRegions("only-simple-regions", + cl::desc("Show only simple regions in the graphviz viewer"), + cl::Hidden, + cl::init(false)); + +namespace llvm { +template<> +struct DOTGraphTraits : public DefaultDOTGraphTraits { + + DOTGraphTraits (bool isSimple=false) + : DefaultDOTGraphTraits(isSimple) {} + + std::string getNodeLabel(RegionNode *Node, RegionNode *Graph) { + + if (!Node->isSubRegion()) { + BasicBlock *BB = Node->getNodeAs(); + + if (isSimple()) + return DOTGraphTraits + ::getSimpleNodeLabel(BB, BB->getParent()); + else + return DOTGraphTraits + ::getCompleteNodeLabel(BB, BB->getParent()); + } + + return "Not implemented"; + } +}; + +template<> +struct DOTGraphTraits : public DOTGraphTraits { + + DOTGraphTraits (bool isSimple=false) + : DOTGraphTraits(isSimple) {} + + static std::string getGraphName(RegionInfo *DT) { + return "Region Graph"; + } + + std::string getNodeLabel(RegionNode *Node, RegionInfo *G) { + return DOTGraphTraits::getNodeLabel(Node, + G->getTopLevelRegion()); + } + + // Print the cluster of the subregions. This groups the single basic blocks + // and adds a different background color for each group. + static void printRegionCluster(const Region *R, GraphWriter &GW, + unsigned depth = 0) { + raw_ostream &O = GW.getOStream(); + O.indent(2 * depth) << "subgraph cluster_" << static_cast(R) + << " {\n"; + O.indent(2 * (depth + 1)) << "label = \"\";\n"; + + if (!onlySimpleRegions || R->isSimple()) { + O.indent(2 * (depth + 1)) << "style = filled;\n"; + O.indent(2 * (depth + 1)) << "color = " + << ((R->getDepth() * 2 % 12) + 1) << "\n"; + + } else { + O.indent(2 * (depth + 1)) << "style = solid;\n"; + O.indent(2 * (depth + 1)) << "color = " + << ((R->getDepth() * 2 % 12) + 2) << "\n"; + } + + for (Region::const_iterator RI = R->begin(), RE = R->end(); RI != RE; ++RI) + printRegionCluster(*RI, GW, depth + 1); + + RegionInfo *RI = R->getRegionInfo(); + + for (Region::const_block_iterator BI = R->block_begin(), + BE = R->block_end(); BI != BE; ++BI) { + BasicBlock *BB = (*BI)->getNodeAs(); + if (RI->getRegionFor(BB) == R) + O.indent(2 * (depth + 1)) << "Node" + << static_cast(RI->getTopLevelRegion()->getBBNode(BB)) + << ";\n"; + } + + O.indent(2 * depth) << "}\n"; + } + + static void addCustomGraphFeatures(const RegionInfo* RI, + GraphWriter &GW) { + raw_ostream &O = GW.getOStream(); + O << "\tcolorscheme = \"paired12\"\n"; + printRegionCluster(RI->getTopLevelRegion(), GW, 4); + } +}; +} //end namespace llvm + +namespace { + +struct RegionViewer + : public DOTGraphTraitsViewer { + static char ID; + RegionViewer() : DOTGraphTraitsViewer("reg", ID){} +}; + +char RegionViewer::ID = 0; +INITIALIZE_PASS(RegionViewer, "view-regions", "View regions of function", + true, true); + +struct RegionOnlyViewer + : public DOTGraphTraitsViewer { + static char ID; + RegionOnlyViewer() : DOTGraphTraitsViewer("regonly", ID){} +}; + +char RegionOnlyViewer::ID = 0; +INITIALIZE_PASS(RegionOnlyViewer, "view-regions-only", + "View regions of function (with no function bodies)", + true, true); + +struct RegionPrinter + : public DOTGraphTraitsPrinter { + static char ID; + RegionPrinter() : + DOTGraphTraitsPrinter("reg", ID) {} +}; +} //end anonymous namespace + +char RegionPrinter::ID = 0; +INITIALIZE_PASS(RegionPrinter, "dot-regions", + "Print regions of function to 'dot' file", true, true); + +namespace { + +struct RegionOnlyPrinter + : public DOTGraphTraitsPrinter { + static char ID; + RegionOnlyPrinter() : + DOTGraphTraitsPrinter("reg", ID) {} +}; + +} + +char RegionOnlyPrinter::ID = 0; +INITIALIZE_PASS(RegionOnlyPrinter, "dot-regions-only", + "Print regions of function to 'dot' file " + "(with no function bodies)", + true, true); + +FunctionPass* llvm::createRegionViewerPass() { + return new RegionViewer(); +} + +FunctionPass* llvm::createRegionOnlyViewerPass() { + return new RegionOnlyViewer(); +} + +FunctionPass* llvm::createRegionPrinterPass() { + return new RegionPrinter(); +} + +FunctionPass* llvm::createRegionOnlyPrinterPass() { + return new RegionOnlyPrinter(); +} + diff --git a/lib/Analysis/ScalarEvolution.cpp b/lib/Analysis/ScalarEvolution.cpp index 413b3b4..b892d85 100644 --- a/lib/Analysis/ScalarEvolution.cpp +++ b/lib/Analysis/ScalarEvolution.cpp @@ -103,8 +103,8 @@ MaxBruteForceIterations("scalar-evolution-max-iterations", cl::ReallyHidden, "derived loop"), cl::init(100)); -static RegisterPass -R("scalar-evolution", "Scalar Evolution Analysis", false, true); +INITIALIZE_PASS(ScalarEvolution, "scalar-evolution", + "Scalar Evolution Analysis", false, true); char ScalarEvolution::ID = 0; //===----------------------------------------------------------------------===// @@ -251,28 +251,59 @@ void SCEVCommutativeExpr::print(raw_ostream &OS) const { OS << "("; for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) { OS << **I; - if (next(I) != E) + if (llvm::next(I) != E) OS << OpStr; } OS << ")"; } bool SCEVNAryExpr::dominates(BasicBlock *BB, DominatorTree *DT) const { - for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { - if (!getOperand(i)->dominates(BB, DT)) + for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) + if (!(*I)->dominates(BB, DT)) return false; - } return true; } bool SCEVNAryExpr::properlyDominates(BasicBlock *BB, DominatorTree *DT) const { - for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { - if (!getOperand(i)->properlyDominates(BB, DT)) + for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) + if (!(*I)->properlyDominates(BB, DT)) return false; - } return true; } +bool SCEVNAryExpr::isLoopInvariant(const Loop *L) const { + for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) + if (!(*I)->isLoopInvariant(L)) + return false; + return true; +} + +// hasComputableLoopEvolution - N-ary expressions have computable loop +// evolutions iff they have at least one operand that varies with the loop, +// but that all varying operands are computable. +bool SCEVNAryExpr::hasComputableLoopEvolution(const Loop *L) const { + bool HasVarying = false; + for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) { + const SCEV *S = *I; + if (!S->isLoopInvariant(L)) { + if (S->hasComputableLoopEvolution(L)) + HasVarying = true; + else + return false; + } + } + return HasVarying; +} + +bool SCEVNAryExpr::hasOperand(const SCEV *O) const { + for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) { + const SCEV *S = *I; + if (O == S || S->hasOperand(O)) + return true; + } + return false; +} + bool SCEVUDivExpr::dominates(BasicBlock *BB, DominatorTree *DT) const { return LHS->dominates(BB, DT) && RHS->dominates(BB, DT); } @@ -303,10 +334,14 @@ bool SCEVAddRecExpr::isLoopInvariant(const Loop *QueryLoop) const { if (QueryLoop->contains(L)) return false; + // This recurrence is invariant w.r.t. QueryLoop if L contains QueryLoop. + if (L->contains(QueryLoop)) + return true; + // This recurrence is variant w.r.t. QueryLoop if any of its operands // are variant. - for (unsigned i = 0, e = getNumOperands(); i != e; ++i) - if (!getOperand(i)->isLoopInvariant(QueryLoop)) + for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) + if (!(*I)->isLoopInvariant(QueryLoop)) return false; // Otherwise it's loop-invariant. @@ -337,12 +372,36 @@ void SCEVAddRecExpr::print(raw_ostream &OS) const { OS << ">"; } +void SCEVUnknown::deleted() { + // Clear this SCEVUnknown from ValuesAtScopes. + SE->ValuesAtScopes.erase(this); + + // Remove this SCEVUnknown from the uniquing map. + SE->UniqueSCEVs.RemoveNode(this); + + // Release the value. + setValPtr(0); +} + +void SCEVUnknown::allUsesReplacedWith(Value *New) { + // Clear this SCEVUnknown from ValuesAtScopes. + SE->ValuesAtScopes.erase(this); + + // Remove this SCEVUnknown from the uniquing map. + SE->UniqueSCEVs.RemoveNode(this); + + // Update this SCEVUnknown to point to the new value. This is needed + // because there may still be outstanding SCEVs which still point to + // this SCEVUnknown. + setValPtr(New); +} + bool SCEVUnknown::isLoopInvariant(const Loop *L) const { // All non-instruction values are loop invariant. All instructions are loop // invariant if they are not contained in the specified loop. // Instructions are never considered invariant in the function body // (null loop) because they are defined within the "loop". - if (Instruction *I = dyn_cast(V)) + if (Instruction *I = dyn_cast(getValue())) return L && !L->contains(I); return true; } @@ -360,11 +419,11 @@ bool SCEVUnknown::properlyDominates(BasicBlock *BB, DominatorTree *DT) const { } const Type *SCEVUnknown::getType() const { - return V->getType(); + return getValue()->getType(); } bool SCEVUnknown::isSizeOf(const Type *&AllocTy) const { - if (ConstantExpr *VCE = dyn_cast(V)) + if (ConstantExpr *VCE = dyn_cast(getValue())) if (VCE->getOpcode() == Instruction::PtrToInt) if (ConstantExpr *CE = dyn_cast(VCE->getOperand(0))) if (CE->getOpcode() == Instruction::GetElementPtr && @@ -381,7 +440,7 @@ bool SCEVUnknown::isSizeOf(const Type *&AllocTy) const { } bool SCEVUnknown::isAlignOf(const Type *&AllocTy) const { - if (ConstantExpr *VCE = dyn_cast(V)) + if (ConstantExpr *VCE = dyn_cast(getValue())) if (VCE->getOpcode() == Instruction::PtrToInt) if (ConstantExpr *CE = dyn_cast(VCE->getOperand(0))) if (CE->getOpcode() == Instruction::GetElementPtr && @@ -406,7 +465,7 @@ bool SCEVUnknown::isAlignOf(const Type *&AllocTy) const { } bool SCEVUnknown::isOffsetOf(const Type *&CTy, Constant *&FieldNo) const { - if (ConstantExpr *VCE = dyn_cast(V)) + if (ConstantExpr *VCE = dyn_cast(getValue())) if (VCE->getOpcode() == Instruction::PtrToInt) if (ConstantExpr *CE = dyn_cast(VCE->getOperand(0))) if (CE->getOpcode() == Instruction::GetElementPtr && @@ -448,166 +507,183 @@ void SCEVUnknown::print(raw_ostream &OS) const { } // Otherwise just print it normally. - WriteAsOperand(OS, V, false); + WriteAsOperand(OS, getValue(), false); } //===----------------------------------------------------------------------===// // SCEV Utilities //===----------------------------------------------------------------------===// -static bool CompareTypes(const Type *A, const Type *B) { - if (A->getTypeID() != B->getTypeID()) - return A->getTypeID() < B->getTypeID(); - if (const IntegerType *AI = dyn_cast(A)) { - const IntegerType *BI = cast(B); - return AI->getBitWidth() < BI->getBitWidth(); - } - if (const PointerType *AI = dyn_cast(A)) { - const PointerType *BI = cast(B); - return CompareTypes(AI->getElementType(), BI->getElementType()); - } - if (const ArrayType *AI = dyn_cast(A)) { - const ArrayType *BI = cast(B); - if (AI->getNumElements() != BI->getNumElements()) - return AI->getNumElements() < BI->getNumElements(); - return CompareTypes(AI->getElementType(), BI->getElementType()); - } - if (const VectorType *AI = dyn_cast(A)) { - const VectorType *BI = cast(B); - if (AI->getNumElements() != BI->getNumElements()) - return AI->getNumElements() < BI->getNumElements(); - return CompareTypes(AI->getElementType(), BI->getElementType()); - } - if (const StructType *AI = dyn_cast(A)) { - const StructType *BI = cast(B); - if (AI->getNumElements() != BI->getNumElements()) - return AI->getNumElements() < BI->getNumElements(); - for (unsigned i = 0, e = AI->getNumElements(); i != e; ++i) - if (CompareTypes(AI->getElementType(i), BI->getElementType(i)) || - CompareTypes(BI->getElementType(i), AI->getElementType(i))) - return CompareTypes(AI->getElementType(i), BI->getElementType(i)); - } - return false; -} - namespace { /// SCEVComplexityCompare - Return true if the complexity of the LHS is less /// than the complexity of the RHS. This comparator is used to canonicalize /// expressions. class SCEVComplexityCompare { - LoopInfo *LI; + const LoopInfo *const LI; public: - explicit SCEVComplexityCompare(LoopInfo *li) : LI(li) {} + explicit SCEVComplexityCompare(const LoopInfo *li) : LI(li) {} + // Return true or false if LHS is less than, or at least RHS, respectively. bool operator()(const SCEV *LHS, const SCEV *RHS) const { + return compare(LHS, RHS) < 0; + } + + // Return negative, zero, or positive, if LHS is less than, equal to, or + // greater than RHS, respectively. A three-way result allows recursive + // comparisons to be more efficient. + int compare(const SCEV *LHS, const SCEV *RHS) const { // Fast-path: SCEVs are uniqued so we can do a quick equality check. if (LHS == RHS) - return false; + return 0; // Primarily, sort the SCEVs by their getSCEVType(). - if (LHS->getSCEVType() != RHS->getSCEVType()) - return LHS->getSCEVType() < RHS->getSCEVType(); + unsigned LType = LHS->getSCEVType(), RType = RHS->getSCEVType(); + if (LType != RType) + return (int)LType - (int)RType; // Aside from the getSCEVType() ordering, the particular ordering // isn't very important except that it's beneficial to be consistent, // so that (a + b) and (b + a) don't end up as different expressions. - - // Sort SCEVUnknown values with some loose heuristics. TODO: This is - // not as complete as it could be. - if (const SCEVUnknown *LU = dyn_cast(LHS)) { + switch (LType) { + case scUnknown: { + const SCEVUnknown *LU = cast(LHS); const SCEVUnknown *RU = cast(RHS); + // Sort SCEVUnknown values with some loose heuristics. TODO: This is + // not as complete as it could be. + const Value *LV = LU->getValue(), *RV = RU->getValue(); + // Order pointer values after integer values. This helps SCEVExpander // form GEPs. - if (LU->getType()->isPointerTy() && !RU->getType()->isPointerTy()) - return false; - if (RU->getType()->isPointerTy() && !LU->getType()->isPointerTy()) - return true; + bool LIsPointer = LV->getType()->isPointerTy(), + RIsPointer = RV->getType()->isPointerTy(); + if (LIsPointer != RIsPointer) + return (int)LIsPointer - (int)RIsPointer; // Compare getValueID values. - if (LU->getValue()->getValueID() != RU->getValue()->getValueID()) - return LU->getValue()->getValueID() < RU->getValue()->getValueID(); + unsigned LID = LV->getValueID(), + RID = RV->getValueID(); + if (LID != RID) + return (int)LID - (int)RID; // Sort arguments by their position. - if (const Argument *LA = dyn_cast(LU->getValue())) { - const Argument *RA = cast(RU->getValue()); - return LA->getArgNo() < RA->getArgNo(); + if (const Argument *LA = dyn_cast(LV)) { + const Argument *RA = cast(RV); + unsigned LArgNo = LA->getArgNo(), RArgNo = RA->getArgNo(); + return (int)LArgNo - (int)RArgNo; } - // For instructions, compare their loop depth, and their opcode. - // This is pretty loose. - if (Instruction *LV = dyn_cast(LU->getValue())) { - Instruction *RV = cast(RU->getValue()); + // For instructions, compare their loop depth, and their operand + // count. This is pretty loose. + if (const Instruction *LInst = dyn_cast(LV)) { + const Instruction *RInst = cast(RV); // Compare loop depths. - if (LI->getLoopDepth(LV->getParent()) != - LI->getLoopDepth(RV->getParent())) - return LI->getLoopDepth(LV->getParent()) < - LI->getLoopDepth(RV->getParent()); - - // Compare opcodes. - if (LV->getOpcode() != RV->getOpcode()) - return LV->getOpcode() < RV->getOpcode(); + const BasicBlock *LParent = LInst->getParent(), + *RParent = RInst->getParent(); + if (LParent != RParent) { + unsigned LDepth = LI->getLoopDepth(LParent), + RDepth = LI->getLoopDepth(RParent); + if (LDepth != RDepth) + return (int)LDepth - (int)RDepth; + } // Compare the number of operands. - if (LV->getNumOperands() != RV->getNumOperands()) - return LV->getNumOperands() < RV->getNumOperands(); + unsigned LNumOps = LInst->getNumOperands(), + RNumOps = RInst->getNumOperands(); + return (int)LNumOps - (int)RNumOps; } - return false; + return 0; } - // Compare constant values. - if (const SCEVConstant *LC = dyn_cast(LHS)) { + case scConstant: { + const SCEVConstant *LC = cast(LHS); const SCEVConstant *RC = cast(RHS); - if (LC->getValue()->getBitWidth() != RC->getValue()->getBitWidth()) - return LC->getValue()->getBitWidth() < RC->getValue()->getBitWidth(); - return LC->getValue()->getValue().ult(RC->getValue()->getValue()); + + // Compare constant values. + const APInt &LA = LC->getValue()->getValue(); + const APInt &RA = RC->getValue()->getValue(); + unsigned LBitWidth = LA.getBitWidth(), RBitWidth = RA.getBitWidth(); + if (LBitWidth != RBitWidth) + return (int)LBitWidth - (int)RBitWidth; + return LA.ult(RA) ? -1 : 1; } - // Compare addrec loop depths. - if (const SCEVAddRecExpr *LA = dyn_cast(LHS)) { + case scAddRecExpr: { + const SCEVAddRecExpr *LA = cast(LHS); const SCEVAddRecExpr *RA = cast(RHS); - if (LA->getLoop()->getLoopDepth() != RA->getLoop()->getLoopDepth()) - return LA->getLoop()->getLoopDepth() < RA->getLoop()->getLoopDepth(); + + // Compare addrec loop depths. + const Loop *LLoop = LA->getLoop(), *RLoop = RA->getLoop(); + if (LLoop != RLoop) { + unsigned LDepth = LLoop->getLoopDepth(), + RDepth = RLoop->getLoopDepth(); + if (LDepth != RDepth) + return (int)LDepth - (int)RDepth; + } + + // Addrec complexity grows with operand count. + unsigned LNumOps = LA->getNumOperands(), RNumOps = RA->getNumOperands(); + if (LNumOps != RNumOps) + return (int)LNumOps - (int)RNumOps; + + // Lexicographically compare. + for (unsigned i = 0; i != LNumOps; ++i) { + long X = compare(LA->getOperand(i), RA->getOperand(i)); + if (X != 0) + return X; + } + + return 0; } - // Lexicographically compare n-ary expressions. - if (const SCEVNAryExpr *LC = dyn_cast(LHS)) { + case scAddExpr: + case scMulExpr: + case scSMaxExpr: + case scUMaxExpr: { + const SCEVNAryExpr *LC = cast(LHS); const SCEVNAryExpr *RC = cast(RHS); - for (unsigned i = 0, e = LC->getNumOperands(); i != e; ++i) { - if (i >= RC->getNumOperands()) - return false; - if (operator()(LC->getOperand(i), RC->getOperand(i))) - return true; - if (operator()(RC->getOperand(i), LC->getOperand(i))) - return false; + + // Lexicographically compare n-ary expressions. + unsigned LNumOps = LC->getNumOperands(), RNumOps = RC->getNumOperands(); + for (unsigned i = 0; i != LNumOps; ++i) { + if (i >= RNumOps) + return 1; + long X = compare(LC->getOperand(i), RC->getOperand(i)); + if (X != 0) + return X; } - return LC->getNumOperands() < RC->getNumOperands(); + return (int)LNumOps - (int)RNumOps; } - // Lexicographically compare udiv expressions. - if (const SCEVUDivExpr *LC = dyn_cast(LHS)) { + case scUDivExpr: { + const SCEVUDivExpr *LC = cast(LHS); const SCEVUDivExpr *RC = cast(RHS); - if (operator()(LC->getLHS(), RC->getLHS())) - return true; - if (operator()(RC->getLHS(), LC->getLHS())) - return false; - if (operator()(LC->getRHS(), RC->getRHS())) - return true; - if (operator()(RC->getRHS(), LC->getRHS())) - return false; - return false; + + // Lexicographically compare udiv expressions. + long X = compare(LC->getLHS(), RC->getLHS()); + if (X != 0) + return X; + return compare(LC->getRHS(), RC->getRHS()); } - // Compare cast expressions by operand. - if (const SCEVCastExpr *LC = dyn_cast(LHS)) { + case scTruncate: + case scZeroExtend: + case scSignExtend: { + const SCEVCastExpr *LC = cast(LHS); const SCEVCastExpr *RC = cast(RHS); - return operator()(LC->getOperand(), RC->getOperand()); + + // Compare cast expressions by operand. + return compare(LC->getOperand(), RC->getOperand()); + } + + default: + break; } llvm_unreachable("Unknown SCEV kind!"); - return false; + return 0; } }; } @@ -628,8 +704,9 @@ static void GroupByComplexity(SmallVectorImpl &Ops, if (Ops.size() == 2) { // This is the common case, which also happens to be trivially simple. // Special case it. - if (SCEVComplexityCompare(LI)(Ops[1], Ops[0])) - std::swap(Ops[0], Ops[1]); + const SCEV *&LHS = Ops[0], *&RHS = Ops[1]; + if (SCEVComplexityCompare(LI)(RHS, LHS)) + std::swap(LHS, RHS); return; } @@ -845,6 +922,13 @@ const SCEV *ScalarEvolution::getTruncateExpr(const SCEV *Op, return getAddRecExpr(Operands, AddRec->getLoop()); } + // As a special case, fold trunc(undef) to undef. We don't want to + // know too much about SCEVUnknowns, but this special case is handy + // and harmless. + if (const SCEVUnknown *U = dyn_cast(Op)) + if (isa(U->getValue())) + return getSCEV(UndefValue::get(Ty)); + // The cast wasn't folded; create an explicit cast node. We can reuse // the existing insert position since if we get here, we won't have // made any changes which would invalidate it. @@ -1163,6 +1247,13 @@ const SCEV *ScalarEvolution::getAnyExtendExpr(const SCEV *Op, return getAddRecExpr(Ops, AR->getLoop()); } + // As a special case, fold anyext(undef) to undef. We don't want to + // know too much about SCEVUnknowns, but this special case is handy + // and harmless. + if (const SCEVUnknown *U = dyn_cast(Op)) + if (isa(U->getValue())) + return getSCEV(UndefValue::get(Ty)); + // If the expression is obviously signed, use the sext cast value. if (isa(Op)) return SExt; @@ -1287,8 +1378,9 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, // If HasNSW is true and all the operands are non-negative, infer HasNUW. if (!HasNUW && HasNSW) { bool All = true; - for (unsigned i = 0, e = Ops.size(); i != e; ++i) - if (!isKnownNonNegative(Ops[i])) { + for (SmallVectorImpl::const_iterator I = Ops.begin(), + E = Ops.end(); I != E; ++I) + if (!isKnownNonNegative(*I)) { All = false; break; } @@ -1321,22 +1413,29 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, if (Ops.size() == 1) return Ops[0]; } - // Okay, check to see if the same value occurs in the operand list twice. If - // so, merge them together into an multiply expression. Since we sorted the - // list, these values are required to be adjacent. + // Okay, check to see if the same value occurs in the operand list more than + // once. If so, merge them together into an multiply expression. Since we + // sorted the list, these values are required to be adjacent. const Type *Ty = Ops[0]->getType(); - for (unsigned i = 0, e = Ops.size()-1; i != e; ++i) + bool FoundMatch = false; + for (unsigned i = 0, e = Ops.size(); i != e-1; ++i) if (Ops[i] == Ops[i+1]) { // X + Y + Y --> X + Y*2 - // Found a match, merge the two values into a multiply, and add any - // remaining values to the result. - const SCEV *Two = getConstant(Ty, 2); - const SCEV *Mul = getMulExpr(Ops[i], Two); - if (Ops.size() == 2) + // Scan ahead to count how many equal operands there are. + unsigned Count = 2; + while (i+Count != e && Ops[i+Count] == Ops[i]) + ++Count; + // Merge the values into a multiply. + const SCEV *Scale = getConstant(Ty, Count); + const SCEV *Mul = getMulExpr(Scale, Ops[i]); + if (Ops.size() == Count) return Mul; - Ops.erase(Ops.begin()+i, Ops.begin()+i+2); - Ops.push_back(Mul); - return getAddExpr(Ops, HasNUW, HasNSW); + Ops[i] = Mul; + Ops.erase(Ops.begin()+i+1, Ops.begin()+i+Count); + --i; e -= Count - 1; + FoundMatch = true; } + if (FoundMatch) + return getAddExpr(Ops, HasNUW, HasNSW); // Check for truncates. If all the operands are truncated from the same // type, see if factoring out the truncate would permit the result to be @@ -1433,7 +1532,7 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, // re-generate the operands list. Group the operands by constant scale, // to avoid multiplying by the same constant scale multiple times. std::map, APIntCompare> MulOpLists; - for (SmallVector::iterator I = NewOps.begin(), + for (SmallVector::const_iterator I = NewOps.begin(), E = NewOps.end(); I != E; ++I) MulOpLists[M.find(*I)->second].push_back(*I); // Re-generate the operands list. @@ -1460,20 +1559,23 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, const SCEVMulExpr *Mul = cast(Ops[Idx]); for (unsigned MulOp = 0, e = Mul->getNumOperands(); MulOp != e; ++MulOp) { const SCEV *MulOpSCEV = Mul->getOperand(MulOp); + if (isa(MulOpSCEV)) + continue; for (unsigned AddOp = 0, e = Ops.size(); AddOp != e; ++AddOp) - if (MulOpSCEV == Ops[AddOp] && !isa(Ops[AddOp])) { + if (MulOpSCEV == Ops[AddOp]) { // Fold W + X + (X * Y * Z) --> W + (X * ((Y*Z)+1)) const SCEV *InnerMul = Mul->getOperand(MulOp == 0); if (Mul->getNumOperands() != 2) { // If the multiply has more than two operands, we must get the // Y*Z term. - SmallVector MulOps(Mul->op_begin(), Mul->op_end()); - MulOps.erase(MulOps.begin()+MulOp); + SmallVector MulOps(Mul->op_begin(), + Mul->op_begin()+MulOp); + MulOps.append(Mul->op_begin()+MulOp+1, Mul->op_end()); InnerMul = getMulExpr(MulOps); } const SCEV *One = getConstant(Ty, 1); - const SCEV *AddOne = getAddExpr(InnerMul, One); - const SCEV *OuterMul = getMulExpr(AddOne, Ops[AddOp]); + const SCEV *AddOne = getAddExpr(One, InnerMul); + const SCEV *OuterMul = getMulExpr(AddOne, MulOpSCEV); if (Ops.size() == 2) return OuterMul; if (AddOp < Idx) { Ops.erase(Ops.begin()+AddOp); @@ -1500,15 +1602,15 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, const SCEV *InnerMul1 = Mul->getOperand(MulOp == 0); if (Mul->getNumOperands() != 2) { SmallVector MulOps(Mul->op_begin(), - Mul->op_end()); - MulOps.erase(MulOps.begin()+MulOp); + Mul->op_begin()+MulOp); + MulOps.append(Mul->op_begin()+MulOp+1, Mul->op_end()); InnerMul1 = getMulExpr(MulOps); } const SCEV *InnerMul2 = OtherMul->getOperand(OMulOp == 0); if (OtherMul->getNumOperands() != 2) { SmallVector MulOps(OtherMul->op_begin(), - OtherMul->op_end()); - MulOps.erase(MulOps.begin()+OMulOp); + OtherMul->op_begin()+OMulOp); + MulOps.append(OtherMul->op_begin()+OMulOp+1, OtherMul->op_end()); InnerMul2 = getMulExpr(MulOps); } const SCEV *InnerMulSum = getAddExpr(InnerMul1,InnerMul2); @@ -1574,30 +1676,31 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, // there are multiple AddRec's with the same loop induction variable being // added together. If so, we can fold them. for (unsigned OtherIdx = Idx+1; - OtherIdx < Ops.size() && isa(Ops[OtherIdx]);++OtherIdx) - if (OtherIdx != Idx) { - const SCEVAddRecExpr *OtherAddRec = cast(Ops[OtherIdx]); - if (AddRecLoop == OtherAddRec->getLoop()) { - // Other + {A,+,B} + {C,+,D} --> Other + {A+C,+,B+D} - SmallVector NewOps(AddRec->op_begin(), - AddRec->op_end()); - for (unsigned i = 0, e = OtherAddRec->getNumOperands(); i != e; ++i) { - if (i >= NewOps.size()) { - NewOps.append(OtherAddRec->op_begin()+i, - OtherAddRec->op_end()); - break; + OtherIdx < Ops.size() && isa(Ops[OtherIdx]); + ++OtherIdx) + if (AddRecLoop == cast(Ops[OtherIdx])->getLoop()) { + // Other + {A,+,B} + {C,+,D} --> Other + {A+C,+,B+D} + SmallVector AddRecOps(AddRec->op_begin(), + AddRec->op_end()); + for (; OtherIdx != Ops.size() && isa(Ops[OtherIdx]); + ++OtherIdx) + if (const SCEVAddRecExpr *OtherAddRec = + dyn_cast(Ops[OtherIdx])) + if (OtherAddRec->getLoop() == AddRecLoop) { + for (unsigned i = 0, e = OtherAddRec->getNumOperands(); + i != e; ++i) { + if (i >= AddRecOps.size()) { + AddRecOps.append(OtherAddRec->op_begin()+i, + OtherAddRec->op_end()); + break; + } + AddRecOps[i] = getAddExpr(AddRecOps[i], + OtherAddRec->getOperand(i)); + } + Ops.erase(Ops.begin() + OtherIdx); --OtherIdx; } - NewOps[i] = getAddExpr(NewOps[i], OtherAddRec->getOperand(i)); - } - const SCEV *NewAddRec = getAddRecExpr(NewOps, AddRecLoop); - - if (Ops.size() == 2) return NewAddRec; - - Ops.erase(Ops.begin()+Idx); - Ops.erase(Ops.begin()+OtherIdx-1); - Ops.push_back(NewAddRec); - return getAddExpr(Ops); - } + Ops[Idx] = getAddRecExpr(AddRecOps, AddRecLoop); + return getAddExpr(Ops); } // Otherwise couldn't fold anything into this recurrence. Move onto the @@ -1633,17 +1736,18 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, assert(!Ops.empty() && "Cannot get empty mul!"); if (Ops.size() == 1) return Ops[0]; #ifndef NDEBUG + const Type *ETy = getEffectiveSCEVType(Ops[0]->getType()); for (unsigned i = 1, e = Ops.size(); i != e; ++i) - assert(getEffectiveSCEVType(Ops[i]->getType()) == - getEffectiveSCEVType(Ops[0]->getType()) && + assert(getEffectiveSCEVType(Ops[i]->getType()) == ETy && "SCEVMulExpr operand types don't match!"); #endif // If HasNSW is true and all the operands are non-negative, infer HasNUW. if (!HasNUW && HasNSW) { bool All = true; - for (unsigned i = 0, e = Ops.size(); i != e; ++i) - if (!isKnownNonNegative(Ops[i])) { + for (SmallVectorImpl::const_iterator I = Ops.begin(), + E = Ops.end(); I != E; ++I) + if (!isKnownNonNegative(*I)) { All = false; break; } @@ -1740,8 +1844,9 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, // they are loop invariant w.r.t. the recurrence. SmallVector LIOps; const SCEVAddRecExpr *AddRec = cast(Ops[Idx]); + const Loop *AddRecLoop = AddRec->getLoop(); for (unsigned i = 0, e = Ops.size(); i != e; ++i) - if (Ops[i]->isLoopInvariant(AddRec->getLoop())) { + if (Ops[i]->isLoopInvariant(AddRecLoop)) { LIOps.push_back(Ops[i]); Ops.erase(Ops.begin()+i); --i; --e; @@ -1758,7 +1863,7 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, // Build the new addrec. Propagate the NUW and NSW flags if both the // outer mul and the inner addrec are guaranteed to have no overflow. - const SCEV *NewRec = getAddRecExpr(NewOps, AddRec->getLoop(), + const SCEV *NewRec = getAddRecExpr(NewOps, AddRecLoop, HasNUW && AddRec->hasNoUnsignedWrap(), HasNSW && AddRec->hasNoSignedWrap()); @@ -1778,28 +1883,30 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, // there are multiple AddRec's with the same loop induction variable being // multiplied together. If so, we can fold them. for (unsigned OtherIdx = Idx+1; - OtherIdx < Ops.size() && isa(Ops[OtherIdx]);++OtherIdx) - if (OtherIdx != Idx) { - const SCEVAddRecExpr *OtherAddRec = cast(Ops[OtherIdx]); - if (AddRec->getLoop() == OtherAddRec->getLoop()) { - // F * G --> {A,+,B} * {C,+,D} --> {A*C,+,F*D + G*B + B*D} - const SCEVAddRecExpr *F = AddRec, *G = OtherAddRec; - const SCEV *NewStart = getMulExpr(F->getStart(), - G->getStart()); - const SCEV *B = F->getStepRecurrence(*this); - const SCEV *D = G->getStepRecurrence(*this); - const SCEV *NewStep = getAddExpr(getMulExpr(F, D), - getMulExpr(G, B), - getMulExpr(B, D)); - const SCEV *NewAddRec = getAddRecExpr(NewStart, NewStep, - F->getLoop()); - if (Ops.size() == 2) return NewAddRec; - - Ops.erase(Ops.begin()+Idx); - Ops.erase(Ops.begin()+OtherIdx-1); - Ops.push_back(NewAddRec); - return getMulExpr(Ops); - } + OtherIdx < Ops.size() && isa(Ops[OtherIdx]); + ++OtherIdx) + if (AddRecLoop == cast(Ops[OtherIdx])->getLoop()) { + // F * G, where F = {A,+,B} and G = {C,+,D} --> + // {A*C,+,F*D + G*B + B*D} + for (; OtherIdx != Ops.size() && isa(Ops[OtherIdx]); + ++OtherIdx) + if (const SCEVAddRecExpr *OtherAddRec = + dyn_cast(Ops[OtherIdx])) + if (OtherAddRec->getLoop() == AddRecLoop) { + const SCEVAddRecExpr *F = AddRec, *G = OtherAddRec; + const SCEV *NewStart = getMulExpr(F->getStart(), G->getStart()); + const SCEV *B = F->getStepRecurrence(*this); + const SCEV *D = G->getStepRecurrence(*this); + const SCEV *NewStep = getAddExpr(getMulExpr(F, D), + getMulExpr(G, B), + getMulExpr(B, D)); + const SCEV *NewAddRec = getAddRecExpr(NewStart, NewStep, + F->getLoop()); + if (Ops.size() == 2) return NewAddRec; + Ops[Idx] = AddRec = cast(NewAddRec); + Ops.erase(Ops.begin() + OtherIdx); --OtherIdx; + } + return getMulExpr(Ops); } // Otherwise couldn't fold anything into this recurrence. Move onto the @@ -1848,7 +1955,7 @@ const SCEV *ScalarEvolution::getUDivExpr(const SCEV *LHS, // TODO: Generalize this to non-constants by using known-bits information. const Type *Ty = LHS->getType(); unsigned LZ = RHSC->getValue()->getValue().countLeadingZeros(); - unsigned MaxShiftAmt = getTypeSizeInBits(Ty) - LZ; + unsigned MaxShiftAmt = getTypeSizeInBits(Ty) - LZ - 1; // For non-power-of-two values, effectively round the value up to the // nearest power of two. if (!RHSC->getValue()->getValue().isPowerOf2()) @@ -1955,9 +2062,9 @@ ScalarEvolution::getAddRecExpr(SmallVectorImpl &Operands, bool HasNUW, bool HasNSW) { if (Operands.size() == 1) return Operands[0]; #ifndef NDEBUG + const Type *ETy = getEffectiveSCEVType(Operands[0]->getType()); for (unsigned i = 1, e = Operands.size(); i != e; ++i) - assert(getEffectiveSCEVType(Operands[i]->getType()) == - getEffectiveSCEVType(Operands[0]->getType()) && + assert(getEffectiveSCEVType(Operands[i]->getType()) == ETy && "SCEVAddRecExpr operand types don't match!"); #endif @@ -1975,8 +2082,9 @@ ScalarEvolution::getAddRecExpr(SmallVectorImpl &Operands, // If HasNSW is true and all the operands are non-negative, infer HasNUW. if (!HasNUW && HasNSW) { bool All = true; - for (unsigned i = 0, e = Operands.size(); i != e; ++i) - if (!isKnownNonNegative(Operands[i])) { + for (SmallVectorImpl::const_iterator I = Operands.begin(), + E = Operands.end(); I != E; ++I) + if (!isKnownNonNegative(*I)) { All = false; break; } @@ -1986,9 +2094,9 @@ ScalarEvolution::getAddRecExpr(SmallVectorImpl &Operands, // Canonicalize nested AddRecs in by nesting them in order of loop depth. if (const SCEVAddRecExpr *NestedAR = dyn_cast(Operands[0])) { const Loop *NestedLoop = NestedAR->getLoop(); - if (L->contains(NestedLoop->getHeader()) ? + if (L->contains(NestedLoop) ? (L->getLoopDepth() < NestedLoop->getLoopDepth()) : - (!NestedLoop->contains(L->getHeader()) && + (!NestedLoop->contains(L) && DT->dominates(L->getHeader(), NestedLoop->getHeader()))) { SmallVector NestedOperands(NestedAR->op_begin(), NestedAR->op_end()); @@ -2055,9 +2163,9 @@ ScalarEvolution::getSMaxExpr(SmallVectorImpl &Ops) { assert(!Ops.empty() && "Cannot get empty smax!"); if (Ops.size() == 1) return Ops[0]; #ifndef NDEBUG + const Type *ETy = getEffectiveSCEVType(Ops[0]->getType()); for (unsigned i = 1, e = Ops.size(); i != e; ++i) - assert(getEffectiveSCEVType(Ops[i]->getType()) == - getEffectiveSCEVType(Ops[0]->getType()) && + assert(getEffectiveSCEVType(Ops[i]->getType()) == ETy && "SCEVSMaxExpr operand types don't match!"); #endif @@ -2160,9 +2268,9 @@ ScalarEvolution::getUMaxExpr(SmallVectorImpl &Ops) { assert(!Ops.empty() && "Cannot get empty umax!"); if (Ops.size() == 1) return Ops[0]; #ifndef NDEBUG + const Type *ETy = getEffectiveSCEVType(Ops[0]->getType()); for (unsigned i = 1, e = Ops.size(); i != e; ++i) - assert(getEffectiveSCEVType(Ops[i]->getType()) == - getEffectiveSCEVType(Ops[0]->getType()) && + assert(getEffectiveSCEVType(Ops[i]->getType()) == ETy && "SCEVUMaxExpr operand types don't match!"); #endif @@ -2326,8 +2434,14 @@ const SCEV *ScalarEvolution::getUnknown(Value *V) { ID.AddInteger(scUnknown); ID.AddPointer(V); void *IP = 0; - if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; - SCEV *S = new (SCEVAllocator) SCEVUnknown(ID.Intern(SCEVAllocator), V); + if (SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) { + assert(cast(S)->getValue() == V && + "Stale SCEVUnknown in uniquing map!"); + return S; + } + SCEV *S = new (SCEVAllocator) SCEVUnknown(ID.Intern(SCEVAllocator), V, this, + FirstUnknown); + FirstUnknown = cast(S); UniqueSCEVs.InsertNode(S, IP); return S; } @@ -2391,10 +2505,15 @@ const SCEV *ScalarEvolution::getCouldNotCompute() { const SCEV *ScalarEvolution::getSCEV(Value *V) { assert(isSCEVable(V->getType()) && "Value is not SCEVable!"); - std::map::iterator I = Scalars.find(V); - if (I != Scalars.end()) return I->second; + ValueExprMapType::const_iterator I = ValueExprMap.find(V); + if (I != ValueExprMap.end()) return I->second; const SCEV *S = createSCEV(V); - Scalars.insert(std::make_pair(SCEVCallbackVH(V, this), S)); + + // The process of creating a SCEV for V may have caused other SCEVs + // to have been created, so it's necessary to insert the new entry + // from scratch, rather than trying to remember the insert position + // above. + ValueExprMap.insert(std::make_pair(SCEVCallbackVH(V, this), S)); return S; } @@ -2428,6 +2547,10 @@ const SCEV *ScalarEvolution::getNotSCEV(const SCEV *V) { /// const SCEV *ScalarEvolution::getMinusSCEV(const SCEV *LHS, const SCEV *RHS) { + // Fast path: X - X --> 0. + if (LHS == RHS) + return getConstant(LHS->getType(), 0); + // X - Y --> X + -Y return getAddExpr(LHS, getNegativeSCEV(RHS)); } @@ -2570,12 +2693,12 @@ PushDefUseChildren(Instruction *I, // Push the def-use children onto the Worklist stack. for (Value::use_iterator UI = I->use_begin(), UE = I->use_end(); UI != UE; ++UI) - Worklist.push_back(cast(UI)); + Worklist.push_back(cast(*UI)); } /// ForgetSymbolicValue - This looks up computed SCEV values for all /// instructions that depend on the given instruction and removes them from -/// the Scalars map if they reference SymName. This is used during PHI +/// the ValueExprMapType map if they reference SymName. This is used during PHI /// resolution. void ScalarEvolution::ForgetSymbolicName(Instruction *PN, const SCEV *SymName) { @@ -2588,9 +2711,9 @@ ScalarEvolution::ForgetSymbolicName(Instruction *PN, const SCEV *SymName) { Instruction *I = Worklist.pop_back_val(); if (!Visited.insert(I)) continue; - std::map::iterator It = - Scalars.find(static_cast(I)); - if (It != Scalars.end()) { + ValueExprMapType::iterator It = + ValueExprMap.find(static_cast(I)); + if (It != ValueExprMap.end()) { // Short-circuit the def-use traversal if the symbolic name // ceases to appear in expressions. if (It->second != SymName && !It->second->hasOperand(SymName)) @@ -2607,7 +2730,7 @@ ScalarEvolution::ForgetSymbolicName(Instruction *PN, const SCEV *SymName) { !isa(It->second) || (I != PN && It->second == SymName)) { ValuesAtScopes.erase(It->second); - Scalars.erase(It); + ValueExprMap.erase(It); } } @@ -2644,9 +2767,9 @@ const SCEV *ScalarEvolution::createNodeForPHI(PHINode *PN) { if (BEValueV && StartValueV) { // While we are analyzing this PHI node, handle its value symbolically. const SCEV *SymbolicName = getUnknown(PN); - assert(Scalars.find(PN) == Scalars.end() && + assert(ValueExprMap.find(PN) == ValueExprMap.end() && "PHI node already processed?"); - Scalars.insert(std::make_pair(SCEVCallbackVH(PN, this), SymbolicName)); + ValueExprMap.insert(std::make_pair(SCEVCallbackVH(PN, this), SymbolicName)); // Using this symbolic name for the PHI, analyze the value coming around // the back-edge. @@ -2707,7 +2830,7 @@ const SCEV *ScalarEvolution::createNodeForPHI(PHINode *PN) { // to be symbolic. We now need to go back and purge all of the // entries for the scalars that use the symbolic expression. ForgetSymbolicName(PN, SymbolicName); - Scalars[SCEVCallbackVH(PN, this)] = PHISCEV; + ValueExprMap[SCEVCallbackVH(PN, this)] = PHISCEV; return PHISCEV; } } @@ -2732,7 +2855,7 @@ const SCEV *ScalarEvolution::createNodeForPHI(PHINode *PN) { // to be symbolic. We now need to go back and purge all of the // entries for the scalars that use the symbolic expression. ForgetSymbolicName(PN, SymbolicName); - Scalars[SCEVCallbackVH(PN, this)] = PHISCEV; + ValueExprMap[SCEVCallbackVH(PN, this)] = PHISCEV; return PHISCEV; } } @@ -2777,7 +2900,7 @@ const SCEV *ScalarEvolution::createNodeForGEP(GEPOperator *GEP) { return getUnknown(GEP); const SCEV *TotalOffset = getConstant(IntPtrTy, 0); gep_type_iterator GTI = gep_type_begin(GEP); - for (GetElementPtrInst::op_iterator I = next(GEP->op_begin()), + for (GetElementPtrInst::op_iterator I = llvm::next(GEP->op_begin()), E = GEP->op_end(); I != E; ++I) { Value *Index = *I; @@ -3200,12 +3323,42 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) { Operator *U = cast(V); switch (Opcode) { - case Instruction::Add: - return getAddExpr(getSCEV(U->getOperand(0)), - getSCEV(U->getOperand(1))); - case Instruction::Mul: - return getMulExpr(getSCEV(U->getOperand(0)), - getSCEV(U->getOperand(1))); + case Instruction::Add: { + // The simple thing to do would be to just call getSCEV on both operands + // and call getAddExpr with the result. However if we're looking at a + // bunch of things all added together, this can be quite inefficient, + // because it leads to N-1 getAddExpr calls for N ultimate operands. + // Instead, gather up all the operands and make a single getAddExpr call. + // LLVM IR canonical form means we need only traverse the left operands. + SmallVector AddOps; + AddOps.push_back(getSCEV(U->getOperand(1))); + for (Value *Op = U->getOperand(0); ; Op = U->getOperand(0)) { + unsigned Opcode = Op->getValueID() - Value::InstructionVal; + if (Opcode != Instruction::Add && Opcode != Instruction::Sub) + break; + U = cast(Op); + const SCEV *Op1 = getSCEV(U->getOperand(1)); + if (Opcode == Instruction::Sub) + AddOps.push_back(getNegativeSCEV(Op1)); + else + AddOps.push_back(Op1); + } + AddOps.push_back(getSCEV(U->getOperand(0))); + return getAddExpr(AddOps); + } + case Instruction::Mul: { + // See the Add code above. + SmallVector MulOps; + MulOps.push_back(getSCEV(U->getOperand(1))); + for (Value *Op = U->getOperand(0); + Op->getValueID() == Instruction::Mul + Value::InstructionVal; + Op = U->getOperand(0)) { + U = cast(Op); + MulOps.push_back(getSCEV(U->getOperand(1))); + } + MulOps.push_back(getSCEV(U->getOperand(0))); + return getMulExpr(MulOps); + } case Instruction::UDiv: return getUDivExpr(getSCEV(U->getOperand(0)), getSCEV(U->getOperand(1))); @@ -3467,7 +3620,7 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) { const SCEV *LDiff = getMinusSCEV(LA, LS); const SCEV *RDiff = getMinusSCEV(RA, One); if (LDiff == RDiff) - return getAddExpr(getUMaxExpr(LS, One), LDiff); + return getAddExpr(getUMaxExpr(One, LS), LDiff); } break; case ICmpInst::ICMP_EQ: @@ -3482,7 +3635,7 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) { const SCEV *LDiff = getMinusSCEV(LA, One); const SCEV *RDiff = getMinusSCEV(RA, LS); if (LDiff == RDiff) - return getAddExpr(getUMaxExpr(LS, One), LDiff); + return getAddExpr(getUMaxExpr(One, LS), LDiff); } break; default: @@ -3579,9 +3732,9 @@ ScalarEvolution::getBackedgeTakenInfo(const Loop *L) { Instruction *I = Worklist.pop_back_val(); if (!Visited.insert(I)) continue; - std::map::iterator It = - Scalars.find(static_cast(I)); - if (It != Scalars.end()) { + ValueExprMapType::iterator It = + ValueExprMap.find(static_cast(I)); + if (It != ValueExprMap.end()) { // SCEVUnknown for a PHI either means that it has an unrecognized // structure, or it's a PHI that's in the progress of being computed // by createNodeForPHI. In the former case, additional loop trip @@ -3590,7 +3743,7 @@ ScalarEvolution::getBackedgeTakenInfo(const Loop *L) { // own when it gets to that point. if (!isa(I) || !isa(It->second)) { ValuesAtScopes.erase(It->second); - Scalars.erase(It); + ValueExprMap.erase(It); } if (PHINode *PN = dyn_cast(I)) ConstantEvolutionLoopExitValue.erase(PN); @@ -3619,11 +3772,10 @@ void ScalarEvolution::forgetLoop(const Loop *L) { Instruction *I = Worklist.pop_back_val(); if (!Visited.insert(I)) continue; - std::map::iterator It = - Scalars.find(static_cast(I)); - if (It != Scalars.end()) { + ValueExprMapType::iterator It = ValueExprMap.find(static_cast(I)); + if (It != ValueExprMap.end()) { ValuesAtScopes.erase(It->second); - Scalars.erase(It); + ValueExprMap.erase(It); if (PHINode *PN = dyn_cast(I)) ConstantEvolutionLoopExitValue.erase(PN); } @@ -3648,35 +3800,14 @@ void ScalarEvolution::forgetValue(Value *V) { I = Worklist.pop_back_val(); if (!Visited.insert(I)) continue; - std::map::iterator It = - Scalars.find(static_cast(I)); - if (It != Scalars.end()) { + ValueExprMapType::iterator It = ValueExprMap.find(static_cast(I)); + if (It != ValueExprMap.end()) { ValuesAtScopes.erase(It->second); - Scalars.erase(It); + ValueExprMap.erase(It); if (PHINode *PN = dyn_cast(I)) ConstantEvolutionLoopExitValue.erase(PN); } - // If there's a SCEVUnknown tying this value into the SCEV - // space, remove it from the folding set map. The SCEVUnknown - // object and any other SCEV objects which reference it - // (transitively) remain allocated, effectively leaked until - // the underlying BumpPtrAllocator is freed. - // - // This permits SCEV pointers to be used as keys in maps - // such as the ValuesAtScopes map. - FoldingSetNodeID ID; - ID.AddInteger(scUnknown); - ID.AddPointer(I); - void *IP; - if (SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) { - UniqueSCEVs.RemoveNode(S); - - // This isn't necessary, but we might as well remove the - // value from the ValuesAtScopes map too. - ValuesAtScopes.erase(S); - } - PushDefUseChildren(I, Worklist); } } @@ -3816,14 +3947,13 @@ ScalarEvolution::ComputeBackedgeTakenCountFromExitCond(const Loop *L, else MaxBECount = getUMinFromMismatchedTypes(BTI0.Max, BTI1.Max); } else { - // Both conditions must be true for the loop to exit. + // Both conditions must be true at the same time for the loop to exit. + // For now, be conservative. assert(L->contains(FBB) && "Loop block has no successor in loop!"); - if (BTI0.Exact != getCouldNotCompute() && - BTI1.Exact != getCouldNotCompute()) - BECount = getUMaxFromMismatchedTypes(BTI0.Exact, BTI1.Exact); - if (BTI0.Max != getCouldNotCompute() && - BTI1.Max != getCouldNotCompute()) - MaxBECount = getUMaxFromMismatchedTypes(BTI0.Max, BTI1.Max); + if (BTI0.Max == BTI1.Max) + MaxBECount = BTI0.Max; + if (BTI0.Exact == BTI1.Exact) + BECount = BTI0.Exact; } return BackedgeTakenInfo(BECount, MaxBECount); @@ -3851,14 +3981,13 @@ ScalarEvolution::ComputeBackedgeTakenCountFromExitCond(const Loop *L, else MaxBECount = getUMinFromMismatchedTypes(BTI0.Max, BTI1.Max); } else { - // Both conditions must be false for the loop to exit. + // Both conditions must be false at the same time for the loop to exit. + // For now, be conservative. assert(L->contains(TBB) && "Loop block has no successor in loop!"); - if (BTI0.Exact != getCouldNotCompute() && - BTI1.Exact != getCouldNotCompute()) - BECount = getUMaxFromMismatchedTypes(BTI0.Exact, BTI1.Exact); - if (BTI0.Max != getCouldNotCompute() && - BTI1.Max != getCouldNotCompute()) - MaxBECount = getUMaxFromMismatchedTypes(BTI0.Max, BTI1.Max); + if (BTI0.Max == BTI1.Max) + MaxBECount = BTI0.Max; + if (BTI0.Exact == BTI1.Exact) + BECount = BTI0.Exact; } return BackedgeTakenInfo(BECount, MaxBECount); @@ -4203,7 +4332,7 @@ Constant * ScalarEvolution::getConstantEvolutionLoopExitValue(PHINode *PN, const APInt &BEs, const Loop *L) { - std::map::iterator I = + std::map::const_iterator I = ConstantEvolutionLoopExitValue.find(PN); if (I != ConstantEvolutionLoopExitValue.end()) return I->second; @@ -5185,7 +5314,8 @@ ScalarEvolution::isLoopBackedgeGuardedByCond(const Loop *L, LoopContinuePredicate->isUnconditional()) return false; - return isImpliedCond(LoopContinuePredicate->getCondition(), Pred, LHS, RHS, + return isImpliedCond(Pred, LHS, RHS, + LoopContinuePredicate->getCondition(), LoopContinuePredicate->getSuccessor(0) != L->getHeader()); } @@ -5214,7 +5344,8 @@ ScalarEvolution::isLoopEntryGuardedByCond(const Loop *L, LoopEntryPredicate->isUnconditional()) continue; - if (isImpliedCond(LoopEntryPredicate->getCondition(), Pred, LHS, RHS, + if (isImpliedCond(Pred, LHS, RHS, + LoopEntryPredicate->getCondition(), LoopEntryPredicate->getSuccessor(0) != Pair.second)) return true; } @@ -5224,24 +5355,24 @@ ScalarEvolution::isLoopEntryGuardedByCond(const Loop *L, /// isImpliedCond - Test whether the condition described by Pred, LHS, /// and RHS is true whenever the given Cond value evaluates to true. -bool ScalarEvolution::isImpliedCond(Value *CondValue, - ICmpInst::Predicate Pred, +bool ScalarEvolution::isImpliedCond(ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS, + Value *FoundCondValue, bool Inverse) { // Recursively handle And and Or conditions. - if (BinaryOperator *BO = dyn_cast(CondValue)) { + if (BinaryOperator *BO = dyn_cast(FoundCondValue)) { if (BO->getOpcode() == Instruction::And) { if (!Inverse) - return isImpliedCond(BO->getOperand(0), Pred, LHS, RHS, Inverse) || - isImpliedCond(BO->getOperand(1), Pred, LHS, RHS, Inverse); + return isImpliedCond(Pred, LHS, RHS, BO->getOperand(0), Inverse) || + isImpliedCond(Pred, LHS, RHS, BO->getOperand(1), Inverse); } else if (BO->getOpcode() == Instruction::Or) { if (Inverse) - return isImpliedCond(BO->getOperand(0), Pred, LHS, RHS, Inverse) || - isImpliedCond(BO->getOperand(1), Pred, LHS, RHS, Inverse); + return isImpliedCond(Pred, LHS, RHS, BO->getOperand(0), Inverse) || + isImpliedCond(Pred, LHS, RHS, BO->getOperand(1), Inverse); } } - ICmpInst *ICI = dyn_cast(CondValue); + ICmpInst *ICI = dyn_cast(FoundCondValue); if (!ICI) return false; // Bail if the ICmp's operands' types are wider than the needed type @@ -5658,20 +5789,19 @@ void ScalarEvolution::SCEVCallbackVH::deleted() { assert(SE && "SCEVCallbackVH called with a null ScalarEvolution!"); if (PHINode *PN = dyn_cast(getValPtr())) SE->ConstantEvolutionLoopExitValue.erase(PN); - SE->Scalars.erase(getValPtr()); + SE->ValueExprMap.erase(getValPtr()); // this now dangles! } -void ScalarEvolution::SCEVCallbackVH::allUsesReplacedWith(Value *) { +void ScalarEvolution::SCEVCallbackVH::allUsesReplacedWith(Value *V) { assert(SE && "SCEVCallbackVH called with a null ScalarEvolution!"); // Forget all the expressions associated with users of the old value, // so that future queries will recompute the expressions using the new // value. + Value *Old = getValPtr(); SmallVector Worklist; SmallPtrSet Visited; - Value *Old = getValPtr(); - bool DeleteOld = false; for (Value::use_iterator UI = Old->use_begin(), UE = Old->use_end(); UI != UE; ++UI) Worklist.push_back(*UI); @@ -5679,27 +5809,22 @@ void ScalarEvolution::SCEVCallbackVH::allUsesReplacedWith(Value *) { User *U = Worklist.pop_back_val(); // Deleting the Old value will cause this to dangle. Postpone // that until everything else is done. - if (U == Old) { - DeleteOld = true; + if (U == Old) continue; - } if (!Visited.insert(U)) continue; if (PHINode *PN = dyn_cast(U)) SE->ConstantEvolutionLoopExitValue.erase(PN); - SE->Scalars.erase(U); + SE->ValueExprMap.erase(U); for (Value::use_iterator UI = U->use_begin(), UE = U->use_end(); UI != UE; ++UI) Worklist.push_back(*UI); } - // Delete the Old value if it (indirectly) references itself. - if (DeleteOld) { - if (PHINode *PN = dyn_cast(Old)) - SE->ConstantEvolutionLoopExitValue.erase(PN); - SE->Scalars.erase(Old); - // this now dangles! - } - // this may dangle! + // Delete the Old value. + if (PHINode *PN = dyn_cast(Old)) + SE->ConstantEvolutionLoopExitValue.erase(PN); + SE->ValueExprMap.erase(Old); + // this now dangles! } ScalarEvolution::SCEVCallbackVH::SCEVCallbackVH(Value *V, ScalarEvolution *se) @@ -5710,7 +5835,7 @@ ScalarEvolution::SCEVCallbackVH::SCEVCallbackVH(Value *V, ScalarEvolution *se) //===----------------------------------------------------------------------===// ScalarEvolution::ScalarEvolution() - : FunctionPass(&ID) { + : FunctionPass(ID), FirstUnknown(0) { } bool ScalarEvolution::runOnFunction(Function &F) { @@ -5722,7 +5847,13 @@ bool ScalarEvolution::runOnFunction(Function &F) { } void ScalarEvolution::releaseMemory() { - Scalars.clear(); + // Iterate through all the SCEVUnknown instances and call their + // destructors, so that they release their references to their values. + for (SCEVUnknown *U = FirstUnknown; U; U = U->Next) + U->~SCEVUnknown(); + FirstUnknown = 0; + + ValueExprMap.clear(); BackedgeTakenCounts.clear(); ConstantEvolutionLoopExitValue.clear(); ValuesAtScopes.clear(); diff --git a/lib/Analysis/ScalarEvolutionAliasAnalysis.cpp b/lib/Analysis/ScalarEvolutionAliasAnalysis.cpp index 58711b8..93b2a8b 100644 --- a/lib/Analysis/ScalarEvolutionAliasAnalysis.cpp +++ b/lib/Analysis/ScalarEvolutionAliasAnalysis.cpp @@ -34,14 +34,14 @@ namespace { public: static char ID; // Class identification, replacement for typeinfo - ScalarEvolutionAliasAnalysis() : FunctionPass(&ID), SE(0) {} + ScalarEvolutionAliasAnalysis() : FunctionPass(ID), SE(0) {} /// getAdjustedAnalysisPointer - This method is used when a pass implements /// an analysis interface through multiple inheritance. If needed, it /// should override this to adjust the this pointer as needed for the /// specified pass info. - virtual void *getAdjustedAnalysisPointer(const PassInfo *PI) { - if (PI->isPassID(&AliasAnalysis::ID)) + virtual void *getAdjustedAnalysisPointer(AnalysisID PI) { + if (PI == &AliasAnalysis::ID) return (AliasAnalysis*)this; return this; } @@ -58,11 +58,8 @@ namespace { // Register this pass... char ScalarEvolutionAliasAnalysis::ID = 0; -static RegisterPass -X("scev-aa", "ScalarEvolution-based Alias Analysis", false, true); - -// Declare that we implement the AliasAnalysis interface -static RegisterAnalysisGroup Y(X); +INITIALIZE_AG_PASS(ScalarEvolutionAliasAnalysis, AliasAnalysis, "scev-aa", + "ScalarEvolution-based Alias Analysis", false, true, false); FunctionPass *llvm::createScalarEvolutionAliasAnalysisPass() { return new ScalarEvolutionAliasAnalysis(); @@ -158,8 +155,8 @@ ScalarEvolutionAliasAnalysis::alias(const Value *A, unsigned ASize, Value *AO = GetBaseValue(AS); Value *BO = GetBaseValue(BS); if ((AO && AO != A) || (BO && BO != B)) - if (alias(AO ? AO : A, AO ? ~0u : ASize, - BO ? BO : B, BO ? ~0u : BSize) == NoAlias) + if (alias(AO ? AO : A, AO ? UnknownSize : ASize, + BO ? BO : B, BO ? UnknownSize : BSize) == NoAlias) return NoAlias; // Forward the query to the next analysis. diff --git a/lib/Analysis/ScalarEvolutionExpander.cpp b/lib/Analysis/ScalarEvolutionExpander.cpp index d4a4b26..66a06ae 100644 --- a/lib/Analysis/ScalarEvolutionExpander.cpp +++ b/lib/Analysis/ScalarEvolutionExpander.cpp @@ -647,6 +647,11 @@ public: bool operator()(std::pair LHS, std::pair RHS) const { + // Keep pointer operands sorted at the end. + if (LHS.second->getType()->isPointerTy() != + RHS.second->getType()->isPointerTy()) + return LHS.second->getType()->isPointerTy(); + // Compare loops with PickMostRelevantLoop. if (LHS.first != RHS.first) return PickMostRelevantLoop(LHS.first, RHS.first, DT) != LHS.first; @@ -699,8 +704,15 @@ Value *SCEVExpander::visitAddExpr(const SCEVAddExpr *S) { // The running sum expression is a pointer. Try to form a getelementptr // at this level with that as the base. SmallVector NewOps; - for (; I != E && I->first == CurLoop; ++I) - NewOps.push_back(I->second); + for (; I != E && I->first == CurLoop; ++I) { + // If the operand is SCEVUnknown and not instructions, peek through + // it, to enable more of it to be folded into the GEP. + const SCEV *X = I->second; + if (const SCEVUnknown *U = dyn_cast(X)) + if (!isa(U->getValue())) + X = SE.getSCEV(U->getValue()); + NewOps.push_back(X); + } Sum = expandAddToGEP(NewOps.begin(), NewOps.end(), PTy, Ty, Sum); } else if (const PointerType *PTy = dyn_cast(Op->getType())) { // The running sum is an integer, and there's a pointer at this level. @@ -1047,9 +1059,7 @@ Value *SCEVExpander::visitAddRecExpr(const SCEVAddRecExpr *S) { // First check for an existing canonical IV in a suitable type. PHINode *CanonicalIV = 0; if (PHINode *PN = L->getCanonicalInductionVariable()) - if (SE.isSCEVable(PN->getType()) && - SE.getEffectiveSCEVType(PN->getType())->isIntegerTy() && - SE.getTypeSizeInBits(PN->getType()) >= SE.getTypeSizeInBits(Ty)) + if (SE.getTypeSizeInBits(PN->getType()) >= SE.getTypeSizeInBits(Ty)) CanonicalIV = PN; // Rewrite an AddRec in terms of the canonical induction variable, if @@ -1102,21 +1112,13 @@ Value *SCEVExpander::visitAddRecExpr(const SCEVAddRecExpr *S) { SE.getUnknown(expand(Rest)))); } - // {0,+,1} --> Insert a canonical induction variable into the loop! - if (S->isAffine() && S->getOperand(1)->isOne()) { - // If there's a canonical IV, just use it. - if (CanonicalIV) { - assert(Ty == SE.getEffectiveSCEVType(CanonicalIV->getType()) && - "IVs with types different from the canonical IV should " - "already have been handled!"); - return CanonicalIV; - } - + // If we don't yet have a canonical IV, create one. + if (!CanonicalIV) { // Create and insert the PHI node for the induction variable in the // specified loop. BasicBlock *Header = L->getHeader(); - PHINode *PN = PHINode::Create(Ty, "indvar", Header->begin()); - rememberInstruction(PN); + CanonicalIV = PHINode::Create(Ty, "indvar", Header->begin()); + rememberInstruction(CanonicalIV); Constant *One = ConstantInt::get(Ty, 1); for (pred_iterator HPI = pred_begin(Header), HPE = pred_end(Header); @@ -1125,40 +1127,45 @@ Value *SCEVExpander::visitAddRecExpr(const SCEVAddRecExpr *S) { if (L->contains(HP)) { // Insert a unit add instruction right before the terminator // corresponding to the back-edge. - Instruction *Add = BinaryOperator::CreateAdd(PN, One, "indvar.next", - HP->getTerminator()); + Instruction *Add = BinaryOperator::CreateAdd(CanonicalIV, One, + "indvar.next", + HP->getTerminator()); rememberInstruction(Add); - PN->addIncoming(Add, HP); + CanonicalIV->addIncoming(Add, HP); } else { - PN->addIncoming(Constant::getNullValue(Ty), HP); + CanonicalIV->addIncoming(Constant::getNullValue(Ty), HP); } } } + // {0,+,1} --> Insert a canonical induction variable into the loop! + if (S->isAffine() && S->getOperand(1)->isOne()) { + assert(Ty == SE.getEffectiveSCEVType(CanonicalIV->getType()) && + "IVs with types different from the canonical IV should " + "already have been handled!"); + return CanonicalIV; + } + // {0,+,F} --> {0,+,1} * F - // Get the canonical induction variable I for this loop. - Value *I = CanonicalIV ? - CanonicalIV : - getOrInsertCanonicalInductionVariable(L, Ty); // If this is a simple linear addrec, emit it now as a special case. if (S->isAffine()) // {0,+,F} --> i*F return expand(SE.getTruncateOrNoop( - SE.getMulExpr(SE.getUnknown(I), + SE.getMulExpr(SE.getUnknown(CanonicalIV), SE.getNoopOrAnyExtend(S->getOperand(1), - I->getType())), + CanonicalIV->getType())), Ty)); // If this is a chain of recurrences, turn it into a closed form, using the // folders, then expandCodeFor the closed form. This allows the folders to // simplify the expression without having to build a bunch of special code // into this folder. - const SCEV *IH = SE.getUnknown(I); // Get I as a "symbolic" SCEV. + const SCEV *IH = SE.getUnknown(CanonicalIV); // Get I as a "symbolic" SCEV. // Promote S up to the canonical IV type, if the cast is foldable. const SCEV *NewS = S; - const SCEV *Ext = SE.getNoopOrAnyExtend(S, I->getType()); + const SCEV *Ext = SE.getNoopOrAnyExtend(S, CanonicalIV->getType()); if (isa(Ext)) NewS = Ext; @@ -1337,16 +1344,21 @@ void SCEVExpander::restoreInsertPoint(BasicBlock *BB, BasicBlock::iterator I) { /// canonical induction variable of the specified type for the specified /// loop (inserting one if there is none). A canonical induction variable /// starts at zero and steps by one on each iteration. -Value * +PHINode * SCEVExpander::getOrInsertCanonicalInductionVariable(const Loop *L, const Type *Ty) { assert(Ty->isIntegerTy() && "Can only insert integer induction variables!"); + + // Build a SCEV for {0,+,1}. const SCEV *H = SE.getAddRecExpr(SE.getConstant(Ty, 0), SE.getConstant(Ty, 1), L); + + // Emit code for it. BasicBlock *SaveInsertBB = Builder.GetInsertBlock(); BasicBlock::iterator SaveInsertPt = Builder.GetInsertPoint(); - Value *V = expandCodeFor(H, 0, L->getHeader()->begin()); + PHINode *V = cast(expandCodeFor(H, 0, L->getHeader()->begin())); if (SaveInsertBB) restoreInsertPoint(SaveInsertBB, SaveInsertPt); + return V; } diff --git a/lib/Analysis/ScalarEvolutionNormalization.cpp b/lib/Analysis/ScalarEvolutionNormalization.cpp index 563fd2f..ac36cef 100644 --- a/lib/Analysis/ScalarEvolutionNormalization.cpp +++ b/lib/Analysis/ScalarEvolutionNormalization.cpp @@ -26,7 +26,7 @@ using namespace llvm; /// post-inc value when we cannot) or it can end up adding extra live-ranges to /// the loop, resulting in reg-reg copies (if we use the pre-inc value when we /// should use the post-inc value). -static bool IVUseShouldUsePostIncValue(Instruction *User, Instruction *IV, +static bool IVUseShouldUsePostIncValue(Instruction *User, Value *Operand, const Loop *L, DominatorTree *DT) { // If the user is in the loop, use the preinc value. if (L->contains(User)) return false; @@ -45,20 +45,17 @@ static bool IVUseShouldUsePostIncValue(Instruction *User, Instruction *IV, // their uses occur in the predecessor block, not the block the PHI lives in) // should still use the post-inc value. Check for this case now. PHINode *PN = dyn_cast(User); - if (!PN) return false; // not a phi, not dominated by latch block. + if (!PN || !Operand) return false; // not a phi, not dominated by latch block. - // Look at all of the uses of IV by the PHI node. If any use corresponds to - // a block that is not dominated by the latch block, give up and use the + // Look at all of the uses of Operand by the PHI node. If any use corresponds + // to a block that is not dominated by the latch block, give up and use the // preincremented value. - unsigned NumUses = 0; for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) - if (PN->getIncomingValue(i) == IV) { - ++NumUses; - if (!DT->dominates(LatchBlock, PN->getIncomingBlock(i))) - return false; - } + if (PN->getIncomingValue(i) == Operand && + !DT->dominates(LatchBlock, PN->getIncomingBlock(i))) + return false; - // Okay, all uses of IV by PN are in predecessor blocks that really are + // Okay, all uses of Operand by PN are in predecessor blocks that really are // dominated by the latch block. Use the post-incremented value. return true; } @@ -72,6 +69,7 @@ const SCEV *llvm::TransformForPostIncUse(TransformKind Kind, DominatorTree &DT) { if (isa(S) || isa(S)) return S; + if (const SCEVCastExpr *X = dyn_cast(S)) { const SCEV *O = X->getOperand(); const SCEV *N = TransformForPostIncUse(Kind, O, User, OperandValToReplace, @@ -85,9 +83,69 @@ const SCEV *llvm::TransformForPostIncUse(TransformKind Kind, } return S; } + + if (const SCEVAddRecExpr *AR = dyn_cast(S)) { + // An addrec. This is the interesting part. + SmallVector Operands; + const Loop *L = AR->getLoop(); + // The addrec conceptually uses its operands at loop entry. + Instruction *LUser = L->getHeader()->begin(); + // Transform each operand. + for (SCEVNAryExpr::op_iterator I = AR->op_begin(), E = AR->op_end(); + I != E; ++I) { + const SCEV *O = *I; + const SCEV *N = TransformForPostIncUse(Kind, O, LUser, 0, Loops, SE, DT); + Operands.push_back(N); + } + const SCEV *Result = SE.getAddRecExpr(Operands, L); + switch (Kind) { + default: llvm_unreachable("Unexpected transform name!"); + case NormalizeAutodetect: + if (IVUseShouldUsePostIncValue(User, OperandValToReplace, L, &DT)) { + const SCEV *TransformedStep = + TransformForPostIncUse(Kind, AR->getStepRecurrence(SE), + User, OperandValToReplace, Loops, SE, DT); + Result = SE.getMinusSCEV(Result, TransformedStep); + Loops.insert(L); + } +#if 0 + // This assert is conceptually correct, but ScalarEvolution currently + // sometimes fails to canonicalize two equal SCEVs to exactly the same + // form. It's possibly a pessimization when this happens, but it isn't a + // correctness problem, so disable this assert for now. + assert(S == TransformForPostIncUse(Denormalize, Result, + User, OperandValToReplace, + Loops, SE, DT) && + "SCEV normalization is not invertible!"); +#endif + break; + case Normalize: + if (Loops.count(L)) { + const SCEV *TransformedStep = + TransformForPostIncUse(Kind, AR->getStepRecurrence(SE), + User, OperandValToReplace, Loops, SE, DT); + Result = SE.getMinusSCEV(Result, TransformedStep); + } +#if 0 + // See the comment on the assert above. + assert(S == TransformForPostIncUse(Denormalize, Result, + User, OperandValToReplace, + Loops, SE, DT) && + "SCEV normalization is not invertible!"); +#endif + break; + case Denormalize: + if (Loops.count(L)) + Result = cast(Result)->getPostIncExpr(SE); + break; + } + return Result; + } + if (const SCEVNAryExpr *X = dyn_cast(S)) { SmallVector Operands; bool Changed = false; + // Transform each operand. for (SCEVNAryExpr::op_iterator I = X->op_begin(), E = X->op_end(); I != E; ++I) { const SCEV *O = *I; @@ -96,37 +154,7 @@ const SCEV *llvm::TransformForPostIncUse(TransformKind Kind, Changed |= N != O; Operands.push_back(N); } - if (const SCEVAddRecExpr *AR = dyn_cast(S)) { - // An addrec. This is the interesting part. - const Loop *L = AR->getLoop(); - const SCEV *Result = SE.getAddRecExpr(Operands, L); - switch (Kind) { - default: llvm_unreachable("Unexpected transform name!"); - case NormalizeAutodetect: - if (Instruction *OI = dyn_cast(OperandValToReplace)) - if (IVUseShouldUsePostIncValue(User, OI, L, &DT)) { - const SCEV *TransformedStep = - TransformForPostIncUse(Kind, AR->getStepRecurrence(SE), - User, OperandValToReplace, Loops, SE, DT); - Result = SE.getMinusSCEV(Result, TransformedStep); - Loops.insert(L); - } - break; - case Normalize: - if (Loops.count(L)) { - const SCEV *TransformedStep = - TransformForPostIncUse(Kind, AR->getStepRecurrence(SE), - User, OperandValToReplace, Loops, SE, DT); - Result = SE.getMinusSCEV(Result, TransformedStep); - } - break; - case Denormalize: - if (Loops.count(L)) - Result = SE.getAddExpr(Result, AR->getStepRecurrence(SE)); - break; - } - return Result; - } + // If any operand actually changed, return a transformed result. if (Changed) switch (S->getSCEVType()) { case scAddExpr: return SE.getAddExpr(Operands); @@ -137,6 +165,7 @@ const SCEV *llvm::TransformForPostIncUse(TransformKind Kind, } return S; } + if (const SCEVUDivExpr *X = dyn_cast(S)) { const SCEV *LO = X->getLHS(); const SCEV *RO = X->getRHS(); @@ -148,6 +177,7 @@ const SCEV *llvm::TransformForPostIncUse(TransformKind Kind, return SE.getUDivExpr(LN, RN); return S; } + llvm_unreachable("Unexpected SCEV kind!"); return 0; } diff --git a/lib/Analysis/TypeBasedAliasAnalysis.cpp b/lib/Analysis/TypeBasedAliasAnalysis.cpp new file mode 100644 index 0000000..bbfdcec --- /dev/null +++ b/lib/Analysis/TypeBasedAliasAnalysis.cpp @@ -0,0 +1,191 @@ +//===- TypeBasedAliasAnalysis.cpp - Type-Based Alias Analysis -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TypeBasedAliasAnalysis pass, which implements +// metadata-based TBAA. +// +// In LLVM IR, memory does not have types, so LLVM's own type system is not +// suitable for doing TBAA. Instead, metadata is added to the IR to describe +// a type system of a higher level language. +// +// This pass is language-independent. The type system is encoded in +// metadata. This allows this pass to support typical C and C++ TBAA, but +// it can also support custom aliasing behavior for other languages. +// +// This is a work-in-progress. It doesn't work yet, and the metadata +// format isn't stable. +// +// TODO: getModRefBehavior. The AliasAnalysis infrastructure will need to +// be extended. +// TODO: AA chaining +// TODO: struct fields +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/Passes.h" +#include "llvm/Module.h" +#include "llvm/Metadata.h" +#include "llvm/Pass.h" +using namespace llvm; + +namespace { + /// TBAANode - This is a simple wrapper around an MDNode which provides a + /// higher-level interface by hiding the details of how alias analysis + /// information is encoded in its operands. + class TBAANode { + const MDNode *Node; + + public: + TBAANode() : Node(0) {} + explicit TBAANode(MDNode *N) : Node(N) {} + + /// getNode - Get the MDNode for this TBAANode. + const MDNode *getNode() const { return Node; } + + /// getParent - Get this TBAANode's Alias DAG parent. + TBAANode getParent() const { + if (Node->getNumOperands() < 2) + return TBAANode(); + MDNode *P = dyn_cast(Node->getOperand(1)); + if (!P) + return TBAANode(); + // Ok, this node has a valid parent. Return it. + return TBAANode(P); + } + + /// TypeIsImmutable - Test if this TBAANode represents a type for objects + /// which are not modified (by any means) in the context where this + /// AliasAnalysis is relevant. + bool TypeIsImmutable() const { + if (Node->getNumOperands() < 3) + return false; + ConstantInt *CI = dyn_cast(Node->getOperand(2)); + if (!CI) + return false; + // TODO: Think about the encoding. + return CI->isOne(); + } + }; +} + +namespace { + /// TypeBasedAliasAnalysis - This is a simple alias analysis + /// implementation that uses TypeBased to answer queries. + class TypeBasedAliasAnalysis : public ImmutablePass, + public AliasAnalysis { + public: + static char ID; // Class identification, replacement for typeinfo + TypeBasedAliasAnalysis() : ImmutablePass(ID) {} + + /// getAdjustedAnalysisPointer - This method is used when a pass implements + /// an analysis interface through multiple inheritance. If needed, it + /// should override this to adjust the this pointer as needed for the + /// specified pass info. + virtual void *getAdjustedAnalysisPointer(const void *PI) { + if (PI == &AliasAnalysis::ID) + return (AliasAnalysis*)this; + return this; + } + + private: + virtual void getAnalysisUsage(AnalysisUsage &AU) const; + virtual AliasResult alias(const Value *V1, unsigned V1Size, + const Value *V2, unsigned V2Size); + virtual bool pointsToConstantMemory(const Value *P); + }; +} // End of anonymous namespace + +// Register this pass... +char TypeBasedAliasAnalysis::ID = 0; +INITIALIZE_AG_PASS(TypeBasedAliasAnalysis, AliasAnalysis, "tbaa", + "Type-Based Alias Analysis", false, true, false); + +ImmutablePass *llvm::createTypeBasedAliasAnalysisPass() { + return new TypeBasedAliasAnalysis(); +} + +void +TypeBasedAliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AliasAnalysis::getAnalysisUsage(AU); +} + +AliasAnalysis::AliasResult +TypeBasedAliasAnalysis::alias(const Value *A, unsigned ASize, + const Value *B, unsigned BSize) { + // Currently, metadata can only be attached to Instructions. + const Instruction *AI = dyn_cast(A); + if (!AI) return MayAlias; + const Instruction *BI = dyn_cast(B); + if (!BI) return MayAlias; + + // Get the attached MDNodes. If either value lacks a tbaa MDNode, we must + // be conservative. + MDNode *AM = + AI->getMetadata(AI->getParent()->getParent()->getParent() + ->getMDKindID("tbaa")); + if (!AM) return MayAlias; + MDNode *BM = + BI->getMetadata(BI->getParent()->getParent()->getParent() + ->getMDKindID("tbaa")); + if (!BM) return MayAlias; + + // Keep track of the root node for A and B. + TBAANode RootA, RootB; + + // Climb the DAG from A to see if we reach B. + for (TBAANode T(AM); ; ) { + if (T.getNode() == BM) + // B is an ancestor of A. + return MayAlias; + + RootA = T; + T = T.getParent(); + if (!T.getNode()) + break; + } + + // Climb the DAG from B to see if we reach A. + for (TBAANode T(BM); ; ) { + if (T.getNode() == AM) + // A is an ancestor of B. + return MayAlias; + + RootB = T; + T = T.getParent(); + if (!T.getNode()) + break; + } + + // Neither node is an ancestor of the other. + + // If they have the same root, then we've proved there's no alias. + if (RootA.getNode() == RootB.getNode()) + return NoAlias; + + // If they have different roots, they're part of different potentially + // unrelated type systems, so we must be conservative. + return MayAlias; +} + +bool TypeBasedAliasAnalysis::pointsToConstantMemory(const Value *P) { + // Currently, metadata can only be attached to Instructions. + const Instruction *I = dyn_cast(P); + if (!I) return false; + + MDNode *M = + I->getMetadata(I->getParent()->getParent()->getParent() + ->getMDKindID("tbaa")); + if (!M) return false; + + // If this is an "immutable" type, we can assume the pointer is pointing + // to constant memory. + return TBAANode(M).TypeIsImmutable(); +} diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index b4c9884..181c9b0 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -880,19 +880,20 @@ bool llvm::ComputeMultiple(Value *V, unsigned Base, Value *&Multiple, } Value *Mul0 = NULL; - Value *Mul1 = NULL; - bool M0 = ComputeMultiple(Op0, Base, Mul0, - LookThroughSExt, Depth+1); - bool M1 = ComputeMultiple(Op1, Base, Mul1, - LookThroughSExt, Depth+1); - - if (M0) { - if (isa(Op1) && isa(Mul0)) { - // V == Base * (Mul0 * Op1), so return (Mul0 * Op1) - Multiple = ConstantExpr::getMul(cast(Mul0), - cast(Op1)); - return true; - } + if (ComputeMultiple(Op0, Base, Mul0, LookThroughSExt, Depth+1)) { + if (Constant *Op1C = dyn_cast(Op1)) + if (Constant *MulC = dyn_cast(Mul0)) { + if (Op1C->getType()->getPrimitiveSizeInBits() < + MulC->getType()->getPrimitiveSizeInBits()) + Op1C = ConstantExpr::getZExt(Op1C, MulC->getType()); + if (Op1C->getType()->getPrimitiveSizeInBits() > + MulC->getType()->getPrimitiveSizeInBits()) + MulC = ConstantExpr::getZExt(MulC, Op1C->getType()); + + // V == Base * (Mul0 * Op1), so return (Mul0 * Op1) + Multiple = ConstantExpr::getMul(MulC, Op1C); + return true; + } if (ConstantInt *Mul0CI = dyn_cast(Mul0)) if (Mul0CI->getValue() == 1) { @@ -902,13 +903,21 @@ bool llvm::ComputeMultiple(Value *V, unsigned Base, Value *&Multiple, } } - if (M1) { - if (isa(Op0) && isa(Mul1)) { - // V == Base * (Mul1 * Op0), so return (Mul1 * Op0) - Multiple = ConstantExpr::getMul(cast(Mul1), - cast(Op0)); - return true; - } + Value *Mul1 = NULL; + if (ComputeMultiple(Op1, Base, Mul1, LookThroughSExt, Depth+1)) { + if (Constant *Op0C = dyn_cast(Op0)) + if (Constant *MulC = dyn_cast(Mul1)) { + if (Op0C->getType()->getPrimitiveSizeInBits() < + MulC->getType()->getPrimitiveSizeInBits()) + Op0C = ConstantExpr::getZExt(Op0C, MulC->getType()); + if (Op0C->getType()->getPrimitiveSizeInBits() > + MulC->getType()->getPrimitiveSizeInBits()) + MulC = ConstantExpr::getZExt(MulC, Op0C->getType()); + + // V == Base * (Mul1 * Op0), so return (Mul1 * Op0) + Multiple = ConstantExpr::getMul(MulC, Op0C); + return true; + } if (ConstantInt *Mul1CI = dyn_cast(Mul1)) if (Mul1CI->getValue() == 1) { @@ -973,195 +982,6 @@ bool llvm::CannotBeNegativeZero(const Value *V, unsigned Depth) { return false; } - -/// GetLinearExpression - Analyze the specified value as a linear expression: -/// "A*V + B", where A and B are constant integers. Return the scale and offset -/// values as APInts and return V as a Value*. The incoming Value is known to -/// have IntegerType. Note that this looks through extends, so the high bits -/// may not be represented in the result. -static Value *GetLinearExpression(Value *V, APInt &Scale, APInt &Offset, - const TargetData *TD, unsigned Depth) { - assert(V->getType()->isIntegerTy() && "Not an integer value"); - - // Limit our recursion depth. - if (Depth == 6) { - Scale = 1; - Offset = 0; - return V; - } - - if (BinaryOperator *BOp = dyn_cast(V)) { - if (ConstantInt *RHSC = dyn_cast(BOp->getOperand(1))) { - switch (BOp->getOpcode()) { - default: break; - case Instruction::Or: - // X|C == X+C if all the bits in C are unset in X. Otherwise we can't - // analyze it. - if (!MaskedValueIsZero(BOp->getOperand(0), RHSC->getValue(), TD)) - break; - // FALL THROUGH. - case Instruction::Add: - V = GetLinearExpression(BOp->getOperand(0), Scale, Offset, TD, Depth+1); - Offset += RHSC->getValue(); - return V; - case Instruction::Mul: - V = GetLinearExpression(BOp->getOperand(0), Scale, Offset, TD, Depth+1); - Offset *= RHSC->getValue(); - Scale *= RHSC->getValue(); - return V; - case Instruction::Shl: - V = GetLinearExpression(BOp->getOperand(0), Scale, Offset, TD, Depth+1); - Offset <<= RHSC->getValue().getLimitedValue(); - Scale <<= RHSC->getValue().getLimitedValue(); - return V; - } - } - } - - // Since clients don't care about the high bits of the value, just scales and - // offsets, we can look through extensions. - if (isa(V) || isa(V)) { - Value *CastOp = cast(V)->getOperand(0); - unsigned OldWidth = Scale.getBitWidth(); - unsigned SmallWidth = CastOp->getType()->getPrimitiveSizeInBits(); - Scale.trunc(SmallWidth); - Offset.trunc(SmallWidth); - Value *Result = GetLinearExpression(CastOp, Scale, Offset, TD, Depth+1); - Scale.zext(OldWidth); - Offset.zext(OldWidth); - return Result; - } - - Scale = 1; - Offset = 0; - return V; -} - -/// DecomposeGEPExpression - If V is a symbolic pointer expression, decompose it -/// into a base pointer with a constant offset and a number of scaled symbolic -/// offsets. -/// -/// The scaled symbolic offsets (represented by pairs of a Value* and a scale in -/// the VarIndices vector) are Value*'s that are known to be scaled by the -/// specified amount, but which may have other unrepresented high bits. As such, -/// the gep cannot necessarily be reconstructed from its decomposed form. -/// -/// When TargetData is around, this function is capable of analyzing everything -/// that Value::getUnderlyingObject() can look through. When not, it just looks -/// through pointer casts. -/// -const Value *llvm::DecomposeGEPExpression(const Value *V, int64_t &BaseOffs, - SmallVectorImpl > &VarIndices, - const TargetData *TD) { - // Limit recursion depth to limit compile time in crazy cases. - unsigned MaxLookup = 6; - - BaseOffs = 0; - do { - // See if this is a bitcast or GEP. - const Operator *Op = dyn_cast(V); - if (Op == 0) { - // The only non-operator case we can handle are GlobalAliases. - if (const GlobalAlias *GA = dyn_cast(V)) { - if (!GA->mayBeOverridden()) { - V = GA->getAliasee(); - continue; - } - } - return V; - } - - if (Op->getOpcode() == Instruction::BitCast) { - V = Op->getOperand(0); - continue; - } - - const GEPOperator *GEPOp = dyn_cast(Op); - if (GEPOp == 0) - return V; - - // Don't attempt to analyze GEPs over unsized objects. - if (!cast(GEPOp->getOperand(0)->getType()) - ->getElementType()->isSized()) - return V; - - // If we are lacking TargetData information, we can't compute the offets of - // elements computed by GEPs. However, we can handle bitcast equivalent - // GEPs. - if (!TD) { - if (!GEPOp->hasAllZeroIndices()) - return V; - V = GEPOp->getOperand(0); - continue; - } - - // Walk the indices of the GEP, accumulating them into BaseOff/VarIndices. - gep_type_iterator GTI = gep_type_begin(GEPOp); - for (User::const_op_iterator I = GEPOp->op_begin()+1, - E = GEPOp->op_end(); I != E; ++I) { - Value *Index = *I; - // Compute the (potentially symbolic) offset in bytes for this index. - if (const StructType *STy = dyn_cast(*GTI++)) { - // For a struct, add the member offset. - unsigned FieldNo = cast(Index)->getZExtValue(); - if (FieldNo == 0) continue; - - BaseOffs += TD->getStructLayout(STy)->getElementOffset(FieldNo); - continue; - } - - // For an array/pointer, add the element offset, explicitly scaled. - if (ConstantInt *CIdx = dyn_cast(Index)) { - if (CIdx->isZero()) continue; - BaseOffs += TD->getTypeAllocSize(*GTI)*CIdx->getSExtValue(); - continue; - } - - uint64_t Scale = TD->getTypeAllocSize(*GTI); - - // Use GetLinearExpression to decompose the index into a C1*V+C2 form. - unsigned Width = cast(Index->getType())->getBitWidth(); - APInt IndexScale(Width, 0), IndexOffset(Width, 0); - Index = GetLinearExpression(Index, IndexScale, IndexOffset, TD, 0); - - // The GEP index scale ("Scale") scales C1*V+C2, yielding (C1*V+C2)*Scale. - // This gives us an aggregate computation of (C1*Scale)*V + C2*Scale. - BaseOffs += IndexOffset.getZExtValue()*Scale; - Scale *= IndexScale.getZExtValue(); - - - // If we already had an occurrance of this index variable, merge this - // scale into it. For example, we want to handle: - // A[x][x] -> x*16 + x*4 -> x*20 - // This also ensures that 'x' only appears in the index list once. - for (unsigned i = 0, e = VarIndices.size(); i != e; ++i) { - if (VarIndices[i].first == Index) { - Scale += VarIndices[i].second; - VarIndices.erase(VarIndices.begin()+i); - break; - } - } - - // Make sure that we have a scale that makes sense for this target's - // pointer size. - if (unsigned ShiftBits = 64-TD->getPointerSizeInBits()) { - Scale <<= ShiftBits; - Scale >>= ShiftBits; - } - - if (Scale) - VarIndices.push_back(std::make_pair(Index, Scale)); - } - - // Analyze the base pointer next. - V = GEPOp->getOperand(0); - } while (--MaxLookup); - - // If the chain of expressions is too deep, just return early. - return V; -} - - // This is the recursive version of BuildSubAggregate. It takes a few different // arguments. Idxs is the index within the nested struct From that we are // looking at now (which is of type IndexedType). IdxSkip is the number of diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index f4c0e50..032753a 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -493,6 +493,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(private); KEYWORD(linker_private); KEYWORD(linker_private_weak); + KEYWORD(linker_private_weak_def_auto); KEYWORD(internal); KEYWORD(available_externally); KEYWORD(linkonce); @@ -572,7 +573,6 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(type); KEYWORD(opaque); - KEYWORD(union); KEYWORD(eq); KEYWORD(ne); KEYWORD(slt); KEYWORD(sgt); KEYWORD(sle); KEYWORD(sge); KEYWORD(ult); KEYWORD(ugt); KEYWORD(ule); KEYWORD(uge); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 221b994..f21a065 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -199,6 +199,7 @@ bool LLParser::ParseTopLevelEntities() { case lltok::kw_private: // OptionalLinkage case lltok::kw_linker_private: // OptionalLinkage case lltok::kw_linker_private_weak: // OptionalLinkage + case lltok::kw_linker_private_weak_def_auto: // OptionalLinkage case lltok::kw_internal: // OptionalLinkage case lltok::kw_weak: // OptionalLinkage case lltok::kw_weak_odr: // OptionalLinkage @@ -517,11 +518,7 @@ bool LLParser::ParseMDNodeID(MDNode *&Result) { if (Result) return false; // Otherwise, create MDNode forward reference. - - // FIXME: This is not unique enough! - std::string FwdRefName = "llvm.mdnode.fwdref." + utostr(MID); - Value *V = MDString::get(Context, FwdRefName); - MDNode *FwdNode = MDNode::get(Context, &V, 1); + MDNode *FwdNode = MDNode::getTemporary(Context, 0, 0); ForwardRefMDNodes[MID] = std::make_pair(FwdNode, Lex.getLoc()); if (NumberedMetadata.size() <= MID) @@ -543,27 +540,20 @@ bool LLParser::ParseNamedMetadata() { ParseToken(lltok::lbrace, "Expected '{' here")) return true; - SmallVector Elts; + NamedMDNode *NMD = M->getOrInsertNamedMetadata(Name); if (Lex.getKind() != lltok::rbrace) do { - // Null is a special case since it is typeless. - if (EatIfPresent(lltok::kw_null)) { - Elts.push_back(0); - continue; - } - if (ParseToken(lltok::exclaim, "Expected '!' here")) return true; MDNode *N = 0; if (ParseMDNodeID(N)) return true; - Elts.push_back(N); + NMD->addOperand(N); } while (EatIfPresent(lltok::comma)); if (ParseToken(lltok::rbrace, "expected end of metadata node")) return true; - NamedMDNode::Create(Context, Name, Elts.data(), Elts.size(), M); return false; } @@ -592,7 +582,9 @@ bool LLParser::ParseStandaloneMetadata() { std::map, LocTy> >::iterator FI = ForwardRefMDNodes.find(MetadataID); if (FI != ForwardRefMDNodes.end()) { - FI->second.first->replaceAllUsesWith(Init); + MDNode *Temp = FI->second.first; + Temp->replaceAllUsesWith(Init); + MDNode::deleteTemporary(Temp); ForwardRefMDNodes.erase(FI); assert(NumberedMetadata[MetadataID] == Init && "Tracking VH didn't work"); @@ -632,7 +624,8 @@ bool LLParser::ParseAlias(const std::string &Name, LocTy NameLoc, Linkage != GlobalValue::InternalLinkage && Linkage != GlobalValue::PrivateLinkage && Linkage != GlobalValue::LinkerPrivateLinkage && - Linkage != GlobalValue::LinkerPrivateWeakLinkage) + Linkage != GlobalValue::LinkerPrivateWeakLinkage && + Linkage != GlobalValue::LinkerPrivateWeakDefAutoLinkage) return Error(LinkageLoc, "invalid linkage type for alias"); Constant *Aliasee; @@ -1017,6 +1010,7 @@ bool LLParser::ParseOptionalAttrs(unsigned &Attrs, unsigned AttrKind) { /// ::= 'private' /// ::= 'linker_private' /// ::= 'linker_private_weak' +/// ::= 'linker_private_weak_def_auto' /// ::= 'internal' /// ::= 'weak' /// ::= 'weak_odr' @@ -1038,6 +1032,9 @@ bool LLParser::ParseOptionalLinkage(unsigned &Res, bool &HasLinkage) { case lltok::kw_linker_private_weak: Res = GlobalValue::LinkerPrivateWeakLinkage; break; + case lltok::kw_linker_private_weak_def_auto: + Res = GlobalValue::LinkerPrivateWeakDefAutoLinkage; + break; case lltok::kw_internal: Res = GlobalValue::InternalLinkage; break; case lltok::kw_weak: Res = GlobalValue::WeakAnyLinkage; break; case lltok::kw_weak_odr: Res = GlobalValue::WeakODRLinkage; break; @@ -1120,29 +1117,44 @@ bool LLParser::ParseOptionalCallingConv(CallingConv::ID &CC) { /// ParseInstructionMetadata /// ::= !dbg !42 (',' !dbg !57)* -bool LLParser::ParseInstructionMetadata(Instruction *Inst) { +bool LLParser::ParseInstructionMetadata(Instruction *Inst, + PerFunctionState *PFS) { do { if (Lex.getKind() != lltok::MetadataVar) return TokError("expected metadata after comma"); std::string Name = Lex.getStrVal(); + unsigned MDK = M->getMDKindID(Name.c_str()); Lex.Lex(); MDNode *Node; unsigned NodeID; SMLoc Loc = Lex.getLoc(); - if (ParseToken(lltok::exclaim, "expected '!' here") || - ParseMDNodeID(Node, NodeID)) + + if (ParseToken(lltok::exclaim, "expected '!' here")) return true; - unsigned MDK = M->getMDKindID(Name.c_str()); - if (Node) { - // If we got the node, add it to the instruction. - Inst->setMetadata(MDK, Node); + // This code is similar to that of ParseMetadataValue, however it needs to + // have special-case code for a forward reference; see the comments on + // ForwardRefInstMetadata for details. Also, MDStrings are not supported + // at the top level here. + if (Lex.getKind() == lltok::lbrace) { + ValID ID; + if (ParseMetadataListValue(ID, PFS)) + return true; + assert(ID.Kind == ValID::t_MDNode); + Inst->setMetadata(MDK, ID.MDNodeVal); } else { - MDRef R = { Loc, MDK, NodeID }; - // Otherwise, remember that this should be resolved later. - ForwardRefInstMetadata[Inst].push_back(R); + if (ParseMDNodeID(Node, NodeID)) + return true; + if (Node) { + // If we got the node, add it to the instruction. + Inst->setMetadata(MDK, Node); + } else { + MDRef R = { Loc, MDK, NodeID }; + // Otherwise, remember that this should be resolved later. + ForwardRefInstMetadata[Inst].push_back(R); + } } // If this is the end of the list, we're done. @@ -1161,6 +1173,8 @@ bool LLParser::ParseOptionalAlignment(unsigned &Alignment) { if (ParseUInt32(Alignment)) return true; if (!isPowerOf2_32(Alignment)) return Error(AlignLoc, "alignment is not a power of two"); + if (Alignment > Value::MaximumAlignment) + return Error(AlignLoc, "huge alignments are not supported yet"); return false; } @@ -1183,6 +1197,7 @@ bool LLParser::ParseOptionalCommaAlign(unsigned &Alignment, if (Lex.getKind() != lltok::kw_align) return Error(Lex.getLoc(), "expected metadata or 'align'"); + LocTy AlignLoc = Lex.getLoc(); if (ParseOptionalAlignment(Alignment)) return true; } @@ -1344,11 +1359,6 @@ bool LLParser::ParseTypeRec(PATypeHolder &Result) { if (ParseStructType(Result, false)) return true; break; - case lltok::kw_union: - // TypeRec ::= 'union' '{' ... '}' - if (ParseUnionType(Result)) - return true; - break; case lltok::lsquare: // TypeRec ::= '[' ... ']' Lex.Lex(); // eat the lsquare. @@ -1658,38 +1668,6 @@ bool LLParser::ParseStructType(PATypeHolder &Result, bool Packed) { return false; } -/// ParseUnionType -/// TypeRec -/// ::= 'union' '{' TypeRec (',' TypeRec)* '}' -bool LLParser::ParseUnionType(PATypeHolder &Result) { - assert(Lex.getKind() == lltok::kw_union); - Lex.Lex(); // Consume the 'union' - - if (ParseToken(lltok::lbrace, "'{' expected after 'union'")) return true; - - SmallVector ParamsList; - do { - LocTy EltTyLoc = Lex.getLoc(); - if (ParseTypeRec(Result)) return true; - ParamsList.push_back(Result); - - if (Result->isVoidTy()) - return Error(EltTyLoc, "union element can not have void type"); - if (!UnionType::isValidElementType(Result)) - return Error(EltTyLoc, "invalid element type for union"); - - } while (EatIfPresent(lltok::comma)) ; - - if (ParseToken(lltok::rbrace, "expected '}' at end of union")) - return true; - - SmallVector ParamsListTy; - for (unsigned i = 0, e = ParamsList.size(); i != e; ++i) - ParamsListTy.push_back(ParamsList[i].get()); - Result = HandleUpRefs(UnionType::get(&ParamsListTy[0], ParamsListTy.size())); - return false; -} - /// ParseArrayVectorType - Parse an array or vector type, assuming the first /// token has already been consumed. /// TypeRec @@ -2504,6 +2482,20 @@ bool LLParser::ParseGlobalValueVector(SmallVectorImpl &Elts) { return false; } +bool LLParser::ParseMetadataListValue(ValID &ID, PerFunctionState *PFS) { + assert(Lex.getKind() == lltok::lbrace); + Lex.Lex(); + + SmallVector Elts; + if (ParseMDNodeVector(Elts, PFS) || + ParseToken(lltok::rbrace, "expected end of metadata node")) + return true; + + ID.MDNodeVal = MDNode::get(Context, Elts.data(), Elts.size()); + ID.Kind = ValID::t_MDNode; + return false; +} + /// ParseMetadataValue /// ::= !42 /// ::= !{...} @@ -2514,16 +2506,8 @@ bool LLParser::ParseMetadataValue(ValID &ID, PerFunctionState *PFS) { // MDNode: // !{ ... } - if (EatIfPresent(lltok::lbrace)) { - SmallVector Elts; - if (ParseMDNodeVector(Elts, PFS) || - ParseToken(lltok::rbrace, "expected end of metadata node")) - return true; - - ID.MDNodeVal = MDNode::get(Context, Elts.data(), Elts.size()); - ID.Kind = ValID::t_MDNode; - return false; - } + if (Lex.getKind() == lltok::lbrace) + return ParseMetadataListValue(ID, PFS); // Standalone metadata reference // !42 @@ -2635,16 +2619,8 @@ bool LLParser::ConvertValIDToValue(const Type *Ty, ValID &ID, Value *&V, V = Constant::getNullValue(Ty); return false; case ValID::t_Constant: - if (ID.ConstantVal->getType() != Ty) { - // Allow a constant struct with a single member to be converted - // to a union, if the union has a member which is the same type - // as the struct member. - if (const UnionType* utype = dyn_cast(Ty)) { - return ParseUnionValue(utype, ID, V); - } - + if (ID.ConstantVal->getType() != Ty) return Error(ID.Loc, "constant expression type mismatch"); - } V = ID.ConstantVal; return false; @@ -2675,22 +2651,6 @@ bool LLParser::ParseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc, return false; } -bool LLParser::ParseUnionValue(const UnionType* utype, ValID &ID, Value *&V) { - if (const StructType* stype = dyn_cast(ID.ConstantVal->getType())) { - if (stype->getNumContainedTypes() != 1) - return Error(ID.Loc, "constant expression type mismatch"); - int index = utype->getElementTypeIndex(stype->getContainedType(0)); - if (index < 0) - return Error(ID.Loc, "initializer type is not a member of the union"); - - V = ConstantUnion::get( - utype, cast(ID.ConstantVal->getOperand(0))); - return false; - } - - return Error(ID.Loc, "constant expression type mismatch"); -} - /// FunctionHeader /// ::= OptionalLinkage OptionalVisibility OptionalCallingConv OptRetAttrs @@ -2724,6 +2684,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { case GlobalValue::PrivateLinkage: case GlobalValue::LinkerPrivateLinkage: case GlobalValue::LinkerPrivateWeakLinkage: + case GlobalValue::LinkerPrivateWeakDefAutoLinkage: case GlobalValue::InternalLinkage: case GlobalValue::AvailableExternallyLinkage: case GlobalValue::LinkOnceAnyLinkage: @@ -2980,7 +2941,7 @@ bool LLParser::ParseBasicBlock(PerFunctionState &PFS) { // With a normal result, we check to see if the instruction is followed by // a comma and metadata. if (EatIfPresent(lltok::comma)) - if (ParseInstructionMetadata(Inst)) + if (ParseInstructionMetadata(Inst, &PFS)) return true; break; case InstExtraComma: @@ -2988,7 +2949,7 @@ bool LLParser::ParseBasicBlock(PerFunctionState &PFS) { // If the instruction parser ate an extra comma at the end of it, it // *must* be followed by metadata. - if (ParseInstructionMetadata(Inst)) + if (ParseInstructionMetadata(Inst, &PFS)) return true; break; } diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index f765a2a..404cec3 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -32,7 +32,6 @@ namespace llvm { class GlobalValue; class MDString; class MDNode; - class UnionType; /// ValID - Represents a reference of a definition of some sort with no type. /// There are several cases where we have to parse the value but where the @@ -80,6 +79,14 @@ namespace llvm { // Instruction metadata resolution. Each instruction can have a list of // MDRef info associated with them. + // + // The simpler approach of just creating temporary MDNodes and then calling + // RAUW on them when the definition is processed doesn't work because some + // instruction metadata kinds, such as dbg, get stored in the IR in an + // "optimized" format which doesn't participate in the normal value use + // lists. This means that RAUW doesn't work, even on temporary MDNodes + // which otherwise support RAUW. Instead, we defer resolving MDNode + // references until the definitions have been processed. struct MDRef { SMLoc Loc; unsigned MDKind, MDSlot; @@ -180,7 +187,6 @@ namespace llvm { bool ParseOptionalCallingConv(CallingConv::ID &CC); bool ParseOptionalAlignment(unsigned &Alignment); bool ParseOptionalStackAlignment(unsigned &Alignment); - bool ParseInstructionMetadata(Instruction *Inst); bool ParseOptionalCommaAlign(unsigned &Alignment, bool &AteExtraComma); bool ParseIndexList(SmallVectorImpl &Indices,bool &AteExtraComma); bool ParseIndexList(SmallVectorImpl &Indices) { @@ -222,7 +228,6 @@ namespace llvm { } bool ParseTypeRec(PATypeHolder &H); bool ParseStructType(PATypeHolder &H, bool Packed); - bool ParseUnionType(PATypeHolder &H); bool ParseArrayVectorType(PATypeHolder &H, bool isVector); bool ParseFunctionType(PATypeHolder &Result); PATypeHolder HandleUpRefs(const Type *Ty); @@ -291,7 +296,6 @@ namespace llvm { return ParseTypeAndBasicBlock(BB, Loc, PFS); } - bool ParseUnionValue(const UnionType* utype, ValID &ID, Value *&V); struct ParamInfo { LocTy Loc; @@ -308,8 +312,10 @@ namespace llvm { bool ParseGlobalValue(const Type *Ty, Constant *&V); bool ParseGlobalTypeAndValue(Constant *&V); bool ParseGlobalValueVector(SmallVectorImpl &Elts); + bool ParseMetadataListValue(ValID &ID, PerFunctionState *PFS); bool ParseMetadataValue(ValID &ID, PerFunctionState *PFS); bool ParseMDNodeVector(SmallVectorImpl &, PerFunctionState *PFS); + bool ParseInstructionMetadata(Instruction *Inst, PerFunctionState *PFS); // Function Parsing. struct ArgInfo { diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index 2703134..61f93a4 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -37,7 +37,8 @@ namespace lltok { kw_declare, kw_define, kw_global, kw_constant, - kw_private, kw_linker_private, kw_linker_private_weak, kw_internal, + kw_private, kw_linker_private, kw_linker_private_weak, + kw_linker_private_weak_def_auto, kw_internal, kw_linkonce, kw_linkonce_odr, kw_weak, kw_weak_odr, kw_appending, kw_dllimport, kw_dllexport, kw_common, kw_available_externally, kw_default, kw_hidden, kw_protected, @@ -97,7 +98,6 @@ namespace lltok { kw_type, kw_opaque, - kw_union, kw_eq, kw_ne, kw_slt, kw_sgt, kw_sle, kw_sge, kw_ult, kw_ugt, kw_ule, kw_uge, kw_oeq, kw_one, kw_olt, kw_ogt, kw_ole, kw_oge, kw_ord, kw_uno, diff --git a/lib/AsmParser/Parser.cpp b/lib/AsmParser/Parser.cpp index e511cbe..e7cef9b 100644 --- a/lib/AsmParser/Parser.cpp +++ b/lib/AsmParser/Parser.cpp @@ -45,8 +45,7 @@ Module *llvm::ParseAssemblyFile(const std::string &Filename, SMDiagnostic &Err, MemoryBuffer *F = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), &ErrorStr); if (F == 0) { Err = SMDiagnostic(Filename, - "Could not open input file '" + Filename + "': " + - ErrorStr); + "Could not open input file: " + ErrorStr); return 0; } diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index b3f0776..830c79a 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -39,6 +39,7 @@ void BitcodeReader::FreeState() { std::vector().swap(FunctionBBs); std::vector().swap(FunctionsWithBodies); DeferredFunctionInfo.clear(); + MDKindMap.clear(); } //===----------------------------------------------------------------------===// @@ -76,6 +77,7 @@ static GlobalValue::LinkageTypes GetDecodedLinkage(unsigned Val) { case 12: return GlobalValue::AvailableExternallyLinkage; case 13: return GlobalValue::LinkerPrivateLinkage; case 14: return GlobalValue::LinkerPrivateWeakLinkage; + case 15: return GlobalValue::LinkerPrivateWeakDefAutoLinkage; } } @@ -295,8 +297,6 @@ void BitcodeReaderValueList::ResolveConstantForwardRefs() { } else if (ConstantStruct *UserCS = dyn_cast(UserC)) { NewC = ConstantStruct::get(Context, &NewOps[0], NewOps.size(), UserCS->getType()->isPacked()); - } else if (ConstantUnion *UserCU = dyn_cast(UserC)) { - NewC = ConstantUnion::get(UserCU->getType(), NewOps[0]); } else if (isa(UserC)) { NewC = ConstantVector::get(&NewOps[0], NewOps.size()); } else { @@ -332,9 +332,9 @@ void BitcodeReaderMDValueList::AssignValue(Value *V, unsigned Idx) { } // If there was a forward reference to this value, replace it. - Value *PrevVal = OldV; + MDNode *PrevVal = cast(OldV); OldV->replaceAllUsesWith(V); - delete PrevVal; + MDNode::deleteTemporary(PrevVal); // Deleting PrevVal sets Idx value in MDValuePtrs to null. Set new // value for Idx. MDValuePtrs[Idx] = V; @@ -350,7 +350,7 @@ Value *BitcodeReaderMDValueList::getValueFwdRef(unsigned Idx) { } // Create and return a placeholder, which will later be RAUW'd. - Value *V = new Argument(Type::getMetadataTy(Context)); + Value *V = MDNode::getTemporary(Context, 0, 0); MDValuePtrs[Idx] = V; return V; } @@ -589,13 +589,6 @@ bool BitcodeReader::ParseTypeTable() { ResultTy = StructType::get(Context, EltTys, Record[0]); break; } - case bitc::TYPE_CODE_UNION: { // UNION: [eltty x N] - SmallVector EltTys; - for (unsigned i = 0, e = Record.size(); i != e; ++i) - EltTys.push_back(getTypeByID(Record[i], true)); - ResultTy = UnionType::get(&EltTys[0], EltTys.size()); - break; - } case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty] if (Record.size() < 2) return Error("Invalid ARRAY type record"); @@ -781,7 +774,8 @@ bool BitcodeReader::ParseMetadata() { bool IsFunctionLocal = false; // Read a record. Record.clear(); - switch (Stream.ReadRecord(Code, Record)) { + Code = Stream.ReadRecord(Code, Record); + switch (Code) { default: // Default behavior: ignore. break; case bitc::METADATA_NAME: { @@ -794,34 +788,46 @@ bool BitcodeReader::ParseMetadata() { Record.clear(); Code = Stream.ReadCode(); - // METADATA_NAME is always followed by METADATA_NAMED_NODE. - if (Stream.ReadRecord(Code, Record) != bitc::METADATA_NAMED_NODE) + // METADATA_NAME is always followed by METADATA_NAMED_NODE2. + // Or METADATA_NAMED_NODE in LLVM 2.7. FIXME: Remove this in LLVM 3.0. + unsigned NextBitCode = Stream.ReadRecord(Code, Record); + if (NextBitCode == bitc::METADATA_NAMED_NODE) { + LLVM2_7MetadataDetected = true; + } else if (NextBitCode != bitc::METADATA_NAMED_NODE2) assert ( 0 && "Inavlid Named Metadata record"); // Read named metadata elements. unsigned Size = Record.size(); - SmallVector Elts; + NamedMDNode *NMD = TheModule->getOrInsertNamedMetadata(Name); for (unsigned i = 0; i != Size; ++i) { - if (Record[i] == ~0U) { - Elts.push_back(NULL); - continue; - } MDNode *MD = dyn_cast(MDValueList.getValueFwdRef(Record[i])); if (MD == 0) return Error("Malformed metadata record"); - Elts.push_back(MD); + NMD->addOperand(MD); } - Value *V = NamedMDNode::Create(Context, Name.str(), Elts.data(), - Elts.size(), TheModule); - MDValueList.AssignValue(V, NextMDValueNo++); + // Backwards compatibility hack: NamedMDValues used to be Values, + // and they got their own slots in the value numbering. They are no + // longer Values, however we still need to account for them in the + // numbering in order to be able to read old bitcode files. + // FIXME: Remove this in LLVM 3.0. + if (LLVM2_7MetadataDetected) + MDValueList.AssignValue(0, NextMDValueNo++); break; } - case bitc::METADATA_FN_NODE: + case bitc::METADATA_FN_NODE: // FIXME: Remove in LLVM 3.0. + case bitc::METADATA_FN_NODE2: IsFunctionLocal = true; // fall-through - case bitc::METADATA_NODE: { + case bitc::METADATA_NODE: // FIXME: Remove in LLVM 3.0. + case bitc::METADATA_NODE2: { + + // Detect 2.7-era metadata. + // FIXME: Remove in LLVM 3.0. + if (Code == bitc::METADATA_FN_NODE || Code == bitc::METADATA_NODE) + LLVM2_7MetadataDetected = true; + if (Record.size() % 2 == 1) - return Error("Invalid METADATA_NODE record"); + return Error("Invalid METADATA_NODE2 record"); unsigned Size = Record.size(); SmallVector Elts; @@ -859,13 +865,12 @@ bool BitcodeReader::ParseMetadata() { SmallString<8> Name; Name.resize(RecordLength-1); unsigned Kind = Record[0]; - (void) Kind; for (unsigned i = 1; i != RecordLength; ++i) Name[i-1] = Record[i]; unsigned NewKind = TheModule->getMDKindID(Name.str()); - assert(Kind == NewKind && - "FIXME: Unable to handle custom metadata mismatch!");(void)NewKind; + if (!MDKindMap.insert(std::make_pair(Kind, NewKind)).second) + return Error("Conflicting METADATA_KIND records"); break; } } @@ -1020,11 +1025,6 @@ bool BitcodeReader::ParseConstants() { Elts.push_back(ValueList.getConstantFwdRef(Record[i], STy->getElementType(i))); V = ConstantStruct::get(STy, Elts); - } else if (const UnionType *UnTy = dyn_cast(CurTy)) { - uint64_t Index = Record[0]; - Constant *Val = ValueList.getConstantFwdRef(Record[1], - UnTy->getElementType(Index)); - V = ConstantUnion::get(UnTy, Val); } else if (const ArrayType *ATy = dyn_cast(CurTy)) { const Type *EltTy = ATy->getElementType(); for (unsigned i = 0; i != Size; ++i) @@ -1297,6 +1297,12 @@ bool BitcodeReader::ParseModule() { UpgradedIntrinsics.push_back(std::make_pair(FI, NewFn)); } + // Look for global variables which need to be renamed. + for (Module::global_iterator + GI = TheModule->global_begin(), GE = TheModule->global_end(); + GI != GE; ++GI) + UpgradeGlobalVariable(GI); + // Force deallocation of memory for these vectors to favor the client that // want lazy deserialization. std::vector >().swap(GlobalInits); @@ -1614,15 +1620,22 @@ bool BitcodeReader::ParseMetadataAttachment() { switch (Stream.ReadRecord(Code, Record)) { default: // Default behavior: ignore. break; - case bitc::METADATA_ATTACHMENT: { + // FIXME: Remove in LLVM 3.0. + case bitc::METADATA_ATTACHMENT: + LLVM2_7MetadataDetected = true; + case bitc::METADATA_ATTACHMENT2: { unsigned RecordLength = Record.size(); if (Record.empty() || (RecordLength - 1) % 2 == 1) return Error ("Invalid METADATA_ATTACHMENT reader!"); Instruction *Inst = InstructionList[Record[0]]; for (unsigned i = 1; i != RecordLength; i = i+2) { unsigned Kind = Record[i]; + DenseMap::iterator I = + MDKindMap.find(Kind); + if (I == MDKindMap.end()) + return Error("Invalid metadata kind ID"); Value *Node = MDValueList.getValueFwdRef(Record[i+1]); - Inst->setMetadata(Kind, cast(Node)); + Inst->setMetadata(I->second, cast(Node)); } break; } @@ -1638,6 +1651,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { InstructionList.clear(); unsigned ModuleValueListSize = ValueList.size(); + unsigned ModuleMDValueListSize = MDValueList.size(); // Add all the function arguments to the value table. for(Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I) @@ -1722,7 +1736,10 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { I = 0; continue; - case bitc::FUNC_CODE_DEBUG_LOC: { // DEBUG_LOC: [line, col, scope, ia] + // FIXME: Remove this in LLVM 3.0. + case bitc::FUNC_CODE_DEBUG_LOC: + LLVM2_7MetadataDetected = true; + case bitc::FUNC_CODE_DEBUG_LOC2: { // DEBUG_LOC: [line, col, scope, ia] I = 0; // Get the last instruction emitted. if (CurBB && !CurBB->empty()) I = &CurBB->back(); @@ -1988,6 +2005,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { } while(OpNum != Record.size()); const Type *ReturnType = F->getReturnType(); + // Handle multiple return values. FIXME: Remove in LLVM 3.0. if (Vs.size() > 1 || (ReturnType->isStructTy() && (Vs.empty() || Vs[0]->getType() != ReturnType))) { @@ -2183,7 +2201,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { } case bitc::FUNC_CODE_INST_ALLOCA: { // ALLOCA: [instty, opty, op, align] // For backward compatibility, tolerate a lack of an opty, and use i32. - // LLVM 3.0: Remove this. + // Remove this in LLVM 3.0. if (Record.size() < 3 || Record.size() > 4) return Error("Invalid ALLOCA record"); unsigned OpNum = 0; @@ -2236,7 +2254,10 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { InstructionList.push_back(I); break; } - case bitc::FUNC_CODE_INST_CALL: { + // FIXME: Remove this in LLVM 3.0. + case bitc::FUNC_CODE_INST_CALL: + LLVM2_7MetadataDetected = true; + case bitc::FUNC_CODE_INST_CALL2: { // CALL: [paramattrs, cc, fnty, fnid, arg0, arg1...] if (Record.size() < 3) return Error("Invalid CALL record"); @@ -2324,7 +2345,7 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { if (A->getParent() == 0) { // We found at least one unresolved value. Nuke them all to avoid leaks. for (unsigned i = ModuleValueListSize, e = ValueList.size(); i != e; ++i){ - if ((A = dyn_cast(ValueList.back())) && A->getParent() == 0) { + if ((A = dyn_cast(ValueList[i])) && A->getParent() == 0) { A->replaceAllUsesWith(UndefValue::get(A->getType())); delete A; } @@ -2333,6 +2354,9 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { } } + // FIXME: Check for unresolved forward-declared metadata references + // and clean up leaks. + // See if anything took the address of blocks in this function. If so, // resolve them now. DenseMap >::iterator BAFRI = @@ -2352,8 +2376,21 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { BlockAddrFwdRefs.erase(BAFRI); } + // FIXME: Remove this in LLVM 3.0. + unsigned NewMDValueListSize = MDValueList.size(); + // Trim the value list down to the size it was before we parsed this function. ValueList.shrinkTo(ModuleValueListSize); + MDValueList.shrinkTo(ModuleMDValueListSize); + + // Backwards compatibility hack: Function-local metadata numbers + // were previously not reset between functions. This is now fixed, + // however we still need to understand the old numbering in order + // to be able to read old bitcode files. + // FIXME: Remove this in LLVM 3.0. + if (LLVM2_7MetadataDetected) + MDValueList.resize(NewMDValueListSize); + std::vector().swap(FunctionBBs); return false; diff --git a/lib/Bitcode/Reader/BitcodeReader.h b/lib/Bitcode/Reader/BitcodeReader.h index 55c71f7..053121b 100644 --- a/lib/Bitcode/Reader/BitcodeReader.h +++ b/lib/Bitcode/Reader/BitcodeReader.h @@ -156,6 +156,9 @@ class BitcodeReader : public GVMaterializer { // stored here with their replacement function. typedef std::vector > UpgradedIntrinsicMap; UpgradedIntrinsicMap UpgradedIntrinsics; + + // Map the bitcode's custom MDKind ID to the Module's MDKind ID. + DenseMap MDKindMap; // After the module header has been read, the FunctionsWithBodies list is // reversed. This keeps track of whether we've done this yet. @@ -170,11 +173,18 @@ class BitcodeReader : public GVMaterializer { /// are resolved lazily when functions are loaded. typedef std::pair BlockAddrRefTy; DenseMap > BlockAddrFwdRefs; + + /// LLVM2_7MetadataDetected - True if metadata produced by LLVM 2.7 or + /// earlier was detected, in which case we behave slightly differently, + /// for compatibility. + /// FIXME: Remove in LLVM 3.0. + bool LLVM2_7MetadataDetected; public: explicit BitcodeReader(MemoryBuffer *buffer, LLVMContext &C) : Context(C), TheModule(0), Buffer(buffer), BufferOwned(false), - ErrorString(0), ValueList(C), MDValueList(C) { + ErrorString(0), ValueList(C), MDValueList(C), + LLVM2_7MetadataDetected(false) { HasReversedFunctionsWithBodies = false; } ~BitcodeReader() { diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index fa1b2c4..7b6fc6c 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -181,14 +181,6 @@ static void WriteTypeTable(const ValueEnumerator &VE, BitstreamWriter &Stream) { Log2_32_Ceil(VE.getTypes().size()+1))); unsigned StructAbbrev = Stream.EmitAbbrev(Abbv); - // Abbrev for TYPE_CODE_UNION. - Abbv = new BitCodeAbbrev(); - Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_UNION)); - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); - Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, - Log2_32_Ceil(VE.getTypes().size()+1))); - unsigned UnionAbbrev = Stream.EmitAbbrev(Abbv); - // Abbrev for TYPE_CODE_ARRAY. Abbv = new BitCodeAbbrev(); Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_ARRAY)); @@ -258,17 +250,6 @@ static void WriteTypeTable(const ValueEnumerator &VE, BitstreamWriter &Stream) { AbbrevToUse = StructAbbrev; break; } - case Type::UnionTyID: { - const UnionType *UT = cast(T); - // UNION: [eltty x N] - Code = bitc::TYPE_CODE_UNION; - // Output all of the element types. - for (UnionType::element_iterator I = UT->element_begin(), - E = UT->element_end(); I != E; ++I) - TypeVals.push_back(VE.getTypeID(*I)); - AbbrevToUse = UnionAbbrev; - break; - } case Type::ArrayTyID: { const ArrayType *AT = cast(T); // ARRAY: [numelts, eltty] @@ -299,21 +280,22 @@ static void WriteTypeTable(const ValueEnumerator &VE, BitstreamWriter &Stream) { static unsigned getEncodedLinkage(const GlobalValue *GV) { switch (GV->getLinkage()) { default: llvm_unreachable("Invalid linkage!"); - case GlobalValue::ExternalLinkage: return 0; - case GlobalValue::WeakAnyLinkage: return 1; - case GlobalValue::AppendingLinkage: return 2; - case GlobalValue::InternalLinkage: return 3; - case GlobalValue::LinkOnceAnyLinkage: return 4; - case GlobalValue::DLLImportLinkage: return 5; - case GlobalValue::DLLExportLinkage: return 6; - case GlobalValue::ExternalWeakLinkage: return 7; - case GlobalValue::CommonLinkage: return 8; - case GlobalValue::PrivateLinkage: return 9; - case GlobalValue::WeakODRLinkage: return 10; - case GlobalValue::LinkOnceODRLinkage: return 11; - case GlobalValue::AvailableExternallyLinkage: return 12; - case GlobalValue::LinkerPrivateLinkage: return 13; - case GlobalValue::LinkerPrivateWeakLinkage: return 14; + case GlobalValue::ExternalLinkage: return 0; + case GlobalValue::WeakAnyLinkage: return 1; + case GlobalValue::AppendingLinkage: return 2; + case GlobalValue::InternalLinkage: return 3; + case GlobalValue::LinkOnceAnyLinkage: return 4; + case GlobalValue::DLLImportLinkage: return 5; + case GlobalValue::DLLExportLinkage: return 6; + case GlobalValue::ExternalWeakLinkage: return 7; + case GlobalValue::CommonLinkage: return 8; + case GlobalValue::PrivateLinkage: return 9; + case GlobalValue::WeakODRLinkage: return 10; + case GlobalValue::LinkOnceODRLinkage: return 11; + case GlobalValue::AvailableExternallyLinkage: return 12; + case GlobalValue::LinkerPrivateLinkage: return 13; + case GlobalValue::LinkerPrivateWeakLinkage: return 14; + case GlobalValue::LinkerPrivateWeakDefAutoLinkage: return 15; } } @@ -503,13 +485,14 @@ static void WriteMDNode(const MDNode *N, Record.push_back(0); } } - unsigned MDCode = N->isFunctionLocal() ? bitc::METADATA_FN_NODE : - bitc::METADATA_NODE; + unsigned MDCode = N->isFunctionLocal() ? bitc::METADATA_FN_NODE2 : + bitc::METADATA_NODE2; Stream.EmitRecord(MDCode, Record, 0); Record.clear(); } -static void WriteModuleMetadata(const ValueEnumerator &VE, +static void WriteModuleMetadata(const Module *M, + const ValueEnumerator &VE, BitstreamWriter &Stream) { const ValueEnumerator::ValueList &Vals = VE.getMDValues(); bool StartedMetadataBlock = false; @@ -544,29 +527,30 @@ static void WriteModuleMetadata(const ValueEnumerator &VE, // Emit the finished record. Stream.EmitRecord(bitc::METADATA_STRING, Record, MDSAbbrev); Record.clear(); - } else if (const NamedMDNode *NMD = dyn_cast(Vals[i].first)) { - if (!StartedMetadataBlock) { - Stream.EnterSubblock(bitc::METADATA_BLOCK_ID, 3); - StartedMetadataBlock = true; - } - - // Write name. - StringRef Str = NMD->getName(); - for (unsigned i = 0, e = Str.size(); i != e; ++i) - Record.push_back(Str[i]); - Stream.EmitRecord(bitc::METADATA_NAME, Record, 0/*TODO*/); - Record.clear(); + } + } - // Write named metadata operands. - for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { - if (NMD->getOperand(i)) - Record.push_back(VE.getValueID(NMD->getOperand(i))); - else - Record.push_back(~0U); - } - Stream.EmitRecord(bitc::METADATA_NAMED_NODE, Record, 0); - Record.clear(); + // Write named metadata. + for (Module::const_named_metadata_iterator I = M->named_metadata_begin(), + E = M->named_metadata_end(); I != E; ++I) { + const NamedMDNode *NMD = I; + if (!StartedMetadataBlock) { + Stream.EnterSubblock(bitc::METADATA_BLOCK_ID, 3); + StartedMetadataBlock = true; } + + // Write name. + StringRef Str = NMD->getName(); + for (unsigned i = 0, e = Str.size(); i != e; ++i) + Record.push_back(Str[i]); + Stream.EmitRecord(bitc::METADATA_NAME, Record, 0/*TODO*/); + Record.clear(); + + // Write named metadata operands. + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) + Record.push_back(VE.getValueID(NMD->getOperand(i))); + Stream.EmitRecord(bitc::METADATA_NAMED_NODE2, Record, 0); + Record.clear(); } if (StartedMetadataBlock) @@ -601,7 +585,7 @@ static void WriteMetadataAttachment(const Function &F, SmallVector Record; // Write metadata attachments - // METADATA_ATTACHMENT - [m x [value, [n x [id, mdnode]]] + // METADATA_ATTACHMENT2 - [m x [value, [n x [id, mdnode]]] SmallVector, 4> MDs; for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB) @@ -619,7 +603,7 @@ static void WriteMetadataAttachment(const Function &F, Record.push_back(MDs[i].first); Record.push_back(VE.getValueID(MDs[i].second)); } - Stream.EmitRecord(bitc::METADATA_ATTACHMENT, Record, 0); + Stream.EmitRecord(bitc::METADATA_ATTACHMENT2, Record, 0); Record.clear(); } @@ -634,12 +618,11 @@ static void WriteModuleMetadataStore(const Module *M, BitstreamWriter &Stream) { SmallVector Names; M->getMDKindNames(Names); - assert(Names[0] == "" && "MDKind #0 is invalid"); - if (Names.size() == 1) return; + if (Names.empty()) return; Stream.EnterSubblock(bitc::METADATA_BLOCK_ID, 3); - for (unsigned MDKindID = 1, e = Names.size(); MDKindID != e; ++MDKindID) { + for (unsigned MDKindID = 0, e = Names.size(); MDKindID != e; ++MDKindID) { Record.push_back(MDKindID); StringRef KName = Names[MDKindID]; Record.append(KName.begin(), KName.end()); @@ -734,8 +717,8 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal, Code = bitc::CST_CODE_UNDEF; } else if (const ConstantInt *IV = dyn_cast(C)) { if (IV->getBitWidth() <= 64) { - int64_t V = IV->getSExtValue(); - if (V >= 0) + uint64_t V = IV->getSExtValue(); + if ((int64_t)V >= 0) Record.push_back(V << 1); else Record.push_back((-V << 1) | 1); @@ -809,20 +792,6 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal, for (unsigned i = 0, e = C->getNumOperands(); i != e; ++i) Record.push_back(VE.getValueID(C->getOperand(i))); AbbrevToUse = AggregateAbbrev; - } else if (isa(C)) { - Code = bitc::CST_CODE_AGGREGATE; - - // Unions only have one entry but we must send type along with it. - const Type *EntryKind = C->getOperand(0)->getType(); - - const UnionType *UnTy = cast(C->getType()); - int UnionIndex = UnTy->getElementTypeIndex(EntryKind); - assert(UnionIndex != -1 && "Constant union contains invalid entry"); - - Record.push_back(UnionIndex); - Record.push_back(VE.getValueID(C->getOperand(0))); - - AbbrevToUse = AggregateAbbrev; } else if (const ConstantExpr *CE = dyn_cast(C)) { switch (CE->getOpcode()) { default: @@ -902,6 +871,9 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal, Record.push_back(VE.getValueID(BA->getFunction())); Record.push_back(VE.getGlobalBasicBlockID(BA->getBasicBlock())); } else { +#ifndef NDEBUG + C->dump(); +#endif llvm_unreachable("Unknown constant!"); } Stream.EmitRecord(Code, Record, AbbrevToUse); @@ -1139,7 +1111,7 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, const PointerType *PTy = cast(CI.getCalledValue()->getType()); const FunctionType *FTy = cast(PTy->getElementType()); - Code = bitc::FUNC_CODE_INST_CALL; + Code = bitc::FUNC_CODE_INST_CALL2; Vals.push_back(VE.getAttributeID(CI.getAttributes())); Vals.push_back((CI.getCallingConv() << 1) | unsigned(CI.isTailCall())); @@ -1283,7 +1255,7 @@ static void WriteFunction(const Function &F, ValueEnumerator &VE, Vals.push_back(DL.getCol()); Vals.push_back(Scope ? VE.getValueID(Scope)+1 : 0); Vals.push_back(IA ? VE.getValueID(IA)+1 : 0); - Stream.EmitRecord(bitc::FUNC_CODE_DEBUG_LOC, Vals); + Stream.EmitRecord(bitc::FUNC_CODE_DEBUG_LOC2, Vals); Vals.clear(); LastDL = DL; @@ -1532,7 +1504,7 @@ static void WriteModule(const Module *M, BitstreamWriter &Stream) { WriteModuleConstants(VE, Stream); // Emit metadata. - WriteModuleMetadata(VE, Stream); + WriteModuleMetadata(M, VE, Stream); // Emit function bodies. for (Module::const_iterator I = M->begin(), E = M->end(); I != E; ++I) diff --git a/lib/Bitcode/Writer/BitcodeWriterPass.cpp b/lib/Bitcode/Writer/BitcodeWriterPass.cpp index 3a0d3ce..91e115c 100644 --- a/lib/Bitcode/Writer/BitcodeWriterPass.cpp +++ b/lib/Bitcode/Writer/BitcodeWriterPass.cpp @@ -21,7 +21,7 @@ namespace { public: static char ID; // Pass identification, replacement for typeid explicit WriteBitcodePass(raw_ostream &o) - : ModulePass(&ID), OS(o) {} + : ModulePass(ID), OS(o) {} const char *getPassName() const { return "Bitcode Writer"; } diff --git a/lib/Bitcode/Writer/ValueEnumerator.cpp b/lib/Bitcode/Writer/ValueEnumerator.cpp index 7fa425a..2f02262 100644 --- a/lib/Bitcode/Writer/ValueEnumerator.cpp +++ b/lib/Bitcode/Writer/ValueEnumerator.cpp @@ -75,7 +75,7 @@ ValueEnumerator::ValueEnumerator(const Module *M) { // Insert constants and metadata that are named at module level into the slot // pool so that the module symbol table can refer to them... EnumerateValueSymbolTable(M->getValueSymbolTable()); - EnumerateMDSymbolTable(M->getMDSymbolTable()); + EnumerateNamedMetadata(M); SmallVector, 8> MDs; @@ -137,7 +137,7 @@ ValueEnumerator::ValueEnumerator(const Module *M) { unsigned ValueEnumerator::getInstructionID(const Instruction *Inst) const { InstructionMapType::const_iterator I = InstructionMap.find(Inst); assert (I != InstructionMap.end() && "Instruction is not mapped!"); - return I->second; + return I->second; } void ValueEnumerator::setInstructionID(const Instruction *I) { @@ -207,35 +207,48 @@ void ValueEnumerator::EnumerateValueSymbolTable(const ValueSymbolTable &VST) { EnumerateValue(VI->getValue()); } -/// EnumerateMDSymbolTable - Insert all of the values in the specified metadata -/// table. -void ValueEnumerator::EnumerateMDSymbolTable(const MDSymbolTable &MST) { - for (MDSymbolTable::const_iterator MI = MST.begin(), ME = MST.end(); - MI != ME; ++MI) - EnumerateValue(MI->getValue()); +/// EnumerateNamedMetadata - Insert all of the values referenced by +/// named metadata in the specified module. +void ValueEnumerator::EnumerateNamedMetadata(const Module *M) { + for (Module::const_named_metadata_iterator I = M->named_metadata_begin(), + E = M->named_metadata_end(); I != E; ++I) + EnumerateNamedMDNode(I); } void ValueEnumerator::EnumerateNamedMDNode(const NamedMDNode *MD) { - // Check to see if it's already in! - unsigned &MDValueID = MDValueMap[MD]; - if (MDValueID) { - // Increment use count. - MDValues[MDValueID-1].second++; - return; + for (unsigned i = 0, e = MD->getNumOperands(); i != e; ++i) + EnumerateMetadata(MD->getOperand(i)); +} + +/// EnumerateMDNodeOperands - Enumerate all non-function-local values +/// and types referenced by the given MDNode. +void ValueEnumerator::EnumerateMDNodeOperands(const MDNode *N) { + for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { + if (Value *V = N->getOperand(i)) { + if (isa(V) || isa(V)) + EnumerateMetadata(V); + else if (!isa(V) && !isa(V)) + EnumerateValue(V); + } else + EnumerateType(Type::getVoidTy(N->getContext())); } +} + +void ValueEnumerator::EnumerateMetadata(const Value *MD) { + assert((isa(MD) || isa(MD)) && "Invalid metadata kind"); // Enumerate the type of this value. EnumerateType(MD->getType()); - for (unsigned i = 0, e = MD->getNumOperands(); i != e; ++i) - if (MDNode *E = MD->getOperand(i)) - EnumerateValue(E); - MDValues.push_back(std::make_pair(MD, 1U)); - MDValueMap[MD] = Values.size(); -} + const MDNode *N = dyn_cast(MD); + + // In the module-level pass, skip function-local nodes themselves, but + // do walk their operands. + if (N && N->isFunctionLocal() && N->getFunction()) { + EnumerateMDNodeOperands(N); + return; + } -void ValueEnumerator::EnumerateMetadata(const Value *MD) { - assert((isa(MD) || isa(MD)) && "Invalid metadata kind"); // Check to see if it's already in! unsigned &MDValueID = MDValueMap[MD]; if (MDValueID) { @@ -243,37 +256,52 @@ void ValueEnumerator::EnumerateMetadata(const Value *MD) { MDValues[MDValueID-1].second++; return; } + MDValues.push_back(std::make_pair(MD, 1U)); + MDValueID = MDValues.size(); + + // Enumerate all non-function-local operands. + if (N) + EnumerateMDNodeOperands(N); +} + +/// EnumerateFunctionLocalMetadataa - Incorporate function-local metadata +/// information reachable from the given MDNode. +void ValueEnumerator::EnumerateFunctionLocalMetadata(const MDNode *N) { + assert(N->isFunctionLocal() && N->getFunction() && + "EnumerateFunctionLocalMetadata called on non-function-local mdnode!"); // Enumerate the type of this value. - EnumerateType(MD->getType()); + EnumerateType(N->getType()); - if (const MDNode *N = dyn_cast(MD)) { - MDValues.push_back(std::make_pair(MD, 1U)); - MDValueMap[MD] = MDValues.size(); - MDValueID = MDValues.size(); - for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { - if (Value *V = N->getOperand(i)) - EnumerateValue(V); - else - EnumerateType(Type::getVoidTy(MD->getContext())); - } - if (N->isFunctionLocal() && N->getFunction()) - FunctionLocalMDs.push_back(N); + // Check to see if it's already in! + unsigned &MDValueID = MDValueMap[N]; + if (MDValueID) { + // Increment use count. + MDValues[MDValueID-1].second++; return; } - - // Add the value. - assert(isa(MD) && "Unknown metadata kind"); - MDValues.push_back(std::make_pair(MD, 1U)); + MDValues.push_back(std::make_pair(N, 1U)); MDValueID = MDValues.size(); + + // To incoroporate function-local information visit all function-local + // MDNodes and all function-local values they reference. + for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) + if (Value *V = N->getOperand(i)) { + if (MDNode *O = dyn_cast(V)) { + if (O->isFunctionLocal() && O->getFunction()) + EnumerateFunctionLocalMetadata(O); + } else if (isa(V) || isa(V)) + EnumerateValue(V); + } + + // Also, collect all function-local MDNodes for easy access. + FunctionLocalMDs.push_back(N); } void ValueEnumerator::EnumerateValue(const Value *V) { assert(!V->getType()->isVoidTy() && "Can't insert void values!"); - if (isa(V) || isa(V)) - return EnumerateMetadata(V); - else if (const NamedMDNode *NMD = dyn_cast(V)) - return EnumerateNamedMDNode(NMD); + assert(!isa(V) && !isa(V) && + "EnumerateValue doesn't handle Metadata!"); // Check to see if it's already in! unsigned &ValueID = ValueMap[V]; @@ -359,7 +387,7 @@ void ValueEnumerator::EnumerateOperandType(const Value *V) { // blockaddress. if (isa(Op)) continue; - EnumerateOperandType(cast(Op)); + EnumerateOperandType(Op); } if (const MDNode *N = dyn_cast(V)) { @@ -368,7 +396,7 @@ void ValueEnumerator::EnumerateOperandType(const Value *V) { EnumerateOperandType(Elem); } } else if (isa(V) || isa(V)) - EnumerateValue(V); + EnumerateMetadata(V); } void ValueEnumerator::EnumerateAttributes(const AttrListPtr &PAL) { @@ -386,10 +414,11 @@ void ValueEnumerator::EnumerateAttributes(const AttrListPtr &PAL) { void ValueEnumerator::incorporateFunction(const Function &F) { InstructionCount = 0; NumModuleValues = Values.size(); + NumModuleMDValues = MDValues.size(); // Adding function arguments to the value table. - for(Function::const_arg_iterator I = F.arg_begin(), E = F.arg_end(); - I != E; ++I) + for (Function::const_arg_iterator I = F.arg_begin(), E = F.arg_end(); + I != E; ++I) EnumerateValue(I); FirstFuncConstantID = Values.size(); @@ -416,7 +445,6 @@ void ValueEnumerator::incorporateFunction(const Function &F) { FirstInstID = Values.size(); - FunctionLocalMDs.clear(); SmallVector FnLocalMDVector; // Add all of the instructions. for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB) { @@ -428,6 +456,15 @@ void ValueEnumerator::incorporateFunction(const Function &F) { // Enumerate metadata after the instructions they might refer to. FnLocalMDVector.push_back(MD); } + + SmallVector, 8> MDs; + I->getAllMetadataOtherThanDebugLoc(MDs); + for (unsigned i = 0, e = MDs.size(); i != e; ++i) { + MDNode *N = MDs[i].second; + if (N->isFunctionLocal() && N->getFunction()) + FnLocalMDVector.push_back(N); + } + if (!I->getType()->isVoidTy()) EnumerateValue(I); } @@ -435,18 +472,22 @@ void ValueEnumerator::incorporateFunction(const Function &F) { // Add all of the function-local metadata. for (unsigned i = 0, e = FnLocalMDVector.size(); i != e; ++i) - EnumerateOperandType(FnLocalMDVector[i]); + EnumerateFunctionLocalMetadata(FnLocalMDVector[i]); } void ValueEnumerator::purgeFunction() { /// Remove purged values from the ValueMap. for (unsigned i = NumModuleValues, e = Values.size(); i != e; ++i) ValueMap.erase(Values[i].first); + for (unsigned i = NumModuleMDValues, e = MDValues.size(); i != e; ++i) + MDValueMap.erase(MDValues[i].first); for (unsigned i = 0, e = BasicBlocks.size(); i != e; ++i) ValueMap.erase(BasicBlocks[i]); Values.resize(NumModuleValues); + MDValues.resize(NumModuleMDValues); BasicBlocks.clear(); + FunctionLocalMDs.clear(); } static void IncorporateFunctionInfoGlobalBBIDs(const Function *F, diff --git a/lib/Bitcode/Writer/ValueEnumerator.h b/lib/Bitcode/Writer/ValueEnumerator.h index 2b9b15f..cd1d237 100644 --- a/lib/Bitcode/Writer/ValueEnumerator.h +++ b/lib/Bitcode/Writer/ValueEnumerator.h @@ -72,6 +72,11 @@ private: /// When a function is incorporated, this is the size of the Values list /// before incorporation. unsigned NumModuleValues; + + /// When a function is incorporated, this is the size of the MDValues list + /// before incorporation. + unsigned NumModuleMDValues; + unsigned FirstFuncConstantID; unsigned FirstInstID; @@ -132,7 +137,9 @@ public: private: void OptimizeConstants(unsigned CstStart, unsigned CstEnd); + void EnumerateMDNodeOperands(const MDNode *N); void EnumerateMetadata(const Value *MD); + void EnumerateFunctionLocalMetadata(const MDNode *N); void EnumerateNamedMDNode(const NamedMDNode *NMD); void EnumerateValue(const Value *V); void EnumerateType(const Type *T); @@ -141,7 +148,7 @@ private: void EnumerateTypeSymbolTable(const TypeSymbolTable &ST); void EnumerateValueSymbolTable(const ValueSymbolTable &ST); - void EnumerateMDSymbolTable(const MDSymbolTable &ST); + void EnumerateNamedMetadata(const Module *M); }; } // End llvm namespace diff --git a/lib/CodeGen/AggressiveAntiDepBreaker.cpp b/lib/CodeGen/AggressiveAntiDepBreaker.cpp index a7189ac..5a634d6 100644 --- a/lib/CodeGen/AggressiveAntiDepBreaker.cpp +++ b/lib/CodeGen/AggressiveAntiDepBreaker.cpp @@ -41,8 +41,11 @@ DebugMod("agg-antidep-debugmod", AggressiveAntiDepState::AggressiveAntiDepState(const unsigned TargetRegs, MachineBasicBlock *BB) : - NumTargetRegs(TargetRegs), GroupNodes(TargetRegs, 0) { - + NumTargetRegs(TargetRegs), GroupNodes(TargetRegs, 0), + GroupNodeIndices(TargetRegs, 0), + KillIndices(TargetRegs, 0), + DefIndices(TargetRegs, 0) +{ const unsigned BBSize = BB->size(); for (unsigned i = 0; i < NumTargetRegs; ++i) { // Initialize all registers to be in their own group. Initially we @@ -54,8 +57,7 @@ AggressiveAntiDepState::AggressiveAntiDepState(const unsigned TargetRegs, } } -unsigned AggressiveAntiDepState::GetGroup(unsigned Reg) -{ +unsigned AggressiveAntiDepState::GetGroup(unsigned Reg) { unsigned Node = GroupNodeIndices[Reg]; while (GroupNodes[Node] != Node) Node = GroupNodes[Node]; @@ -145,8 +147,8 @@ void AggressiveAntiDepBreaker::StartBlock(MachineBasicBlock *BB) { State = new AggressiveAntiDepState(TRI->getNumRegs(), BB); bool IsReturnBlock = (!BB->empty() && BB->back().getDesc().isReturn()); - unsigned *KillIndices = State->GetKillIndices(); - unsigned *DefIndices = State->GetDefIndices(); + std::vector &KillIndices = State->GetKillIndices(); + std::vector &DefIndices = State->GetDefIndices(); // Determine the live-out physregs for this block. if (IsReturnBlock) { @@ -226,7 +228,7 @@ void AggressiveAntiDepBreaker::Observe(MachineInstr *MI, unsigned Count, DEBUG(MI->dump()); DEBUG(dbgs() << "\tRegs:"); - unsigned *DefIndices = State->GetDefIndices(); + std::vector &DefIndices = State->GetDefIndices(); for (unsigned Reg = 0; Reg != TRI->getNumRegs(); ++Reg) { // If Reg is current live, then mark that it can't be renamed as // we don't know the extent of its live-range anymore (now that it @@ -328,8 +330,8 @@ void AggressiveAntiDepBreaker::HandleLastUse(unsigned Reg, unsigned KillIdx, const char *tag, const char *header, const char *footer) { - unsigned *KillIndices = State->GetKillIndices(); - unsigned *DefIndices = State->GetDefIndices(); + std::vector &KillIndices = State->GetKillIndices(); + std::vector &DefIndices = State->GetDefIndices(); std::multimap& RegRefs = State->GetRegRefs(); @@ -364,7 +366,7 @@ void AggressiveAntiDepBreaker::HandleLastUse(unsigned Reg, unsigned KillIdx, void AggressiveAntiDepBreaker::PrescanInstruction(MachineInstr *MI, unsigned Count, std::set& PassthruRegs) { - unsigned *DefIndices = State->GetDefIndices(); + std::vector &DefIndices = State->GetDefIndices(); std::multimap& RegRefs = State->GetRegRefs(); @@ -560,8 +562,8 @@ bool AggressiveAntiDepBreaker::FindSuitableFreeRegisters( unsigned AntiDepGroupIndex, RenameOrderType& RenameOrder, std::map &RenameMap) { - unsigned *KillIndices = State->GetKillIndices(); - unsigned *DefIndices = State->GetDefIndices(); + std::vector &KillIndices = State->GetKillIndices(); + std::vector &DefIndices = State->GetDefIndices(); std::multimap& RegRefs = State->GetRegRefs(); @@ -652,6 +654,8 @@ bool AggressiveAntiDepBreaker::FindSuitableFreeRegisters( if (R == RB) R = RE; --R; const unsigned NewSuperReg = *R; + // Don't consider non-allocatable registers + if (!AllocatableSet.test(NewSuperReg)) continue; // Don't replace a register with itself. if (NewSuperReg == SuperReg) continue; @@ -733,8 +737,8 @@ unsigned AggressiveAntiDepBreaker::BreakAntiDependencies( MachineBasicBlock::iterator Begin, MachineBasicBlock::iterator End, unsigned InsertPosIndex) { - unsigned *KillIndices = State->GetKillIndices(); - unsigned *DefIndices = State->GetDefIndices(); + std::vector &KillIndices = State->GetKillIndices(); + std::vector &DefIndices = State->GetDefIndices(); std::multimap& RegRefs = State->GetRegRefs(); diff --git a/lib/CodeGen/AggressiveAntiDepBreaker.h b/lib/CodeGen/AggressiveAntiDepBreaker.h index 91ebb85..9d715cc 100644 --- a/lib/CodeGen/AggressiveAntiDepBreaker.h +++ b/lib/CodeGen/AggressiveAntiDepBreaker.h @@ -59,27 +59,27 @@ namespace llvm { /// currently representing the group that the register belongs to. /// Register 0 is always represented by the 0 group, a group /// composed of registers that are not eligible for anti-aliasing. - unsigned GroupNodeIndices[TargetRegisterInfo::FirstVirtualRegister]; + std::vector GroupNodeIndices; /// RegRefs - Map registers to all their references within a live range. std::multimap RegRefs; /// KillIndices - The index of the most recent kill (proceding bottom-up), /// or ~0u if the register is not live. - unsigned KillIndices[TargetRegisterInfo::FirstVirtualRegister]; + std::vector KillIndices; /// DefIndices - The index of the most recent complete def (proceding bottom /// up), or ~0u if the register is live. - unsigned DefIndices[TargetRegisterInfo::FirstVirtualRegister]; + std::vector DefIndices; public: AggressiveAntiDepState(const unsigned TargetRegs, MachineBasicBlock *BB); /// GetKillIndices - Return the kill indices. - unsigned *GetKillIndices() { return KillIndices; } + std::vector &GetKillIndices() { return KillIndices; } /// GetDefIndices - Return the define indices. - unsigned *GetDefIndices() { return DefIndices; } + std::vector &GetDefIndices() { return DefIndices; } /// GetRegRefs - Return the RegRefs map. std::multimap& GetRegRefs() { return RegRefs; } diff --git a/lib/CodeGen/Analysis.cpp b/lib/CodeGen/Analysis.cpp index f71eee5..e3dd646 100644 --- a/lib/CodeGen/Analysis.cpp +++ b/lib/CodeGen/Analysis.cpp @@ -109,7 +109,7 @@ GlobalVariable *llvm::ExtractTypeInfo(Value *V) { V = V->stripPointerCasts(); GlobalVariable *GV = dyn_cast(V); - if (GV && GV->getName() == ".llvm.eh.catch.all.value") { + if (GV && GV->getName() == "llvm.eh.catch.all.value") { assert(GV->hasInitializer() && "The EH catch-all value must have an initializer"); Value *Init = GV->getInitializer(); @@ -171,7 +171,7 @@ ISD::CondCode llvm::getFCmpCondCode(FCmpInst::Predicate Pred) { FOC = FPC = ISD::SETFALSE; break; } - if (FiniteOnlyFPMath()) + if (NoNaNsFPMath) return FOC; else return FPC; diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index db1b37a..d358ab2 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -91,7 +91,7 @@ static unsigned getGVAlignmentLog2(const GlobalValue *GV, const TargetData &TD, AsmPrinter::AsmPrinter(TargetMachine &tm, MCStreamer &Streamer) - : MachineFunctionPass(&ID), + : MachineFunctionPass(ID), TM(tm), MAI(tm.getMCAsmInfo()), OutContext(Streamer.getContext()), OutStreamer(Streamer), @@ -200,11 +200,17 @@ void AsmPrinter::EmitLinkage(unsigned Linkage, MCSymbol *GVSym) const { case GlobalValue::WeakAnyLinkage: case GlobalValue::WeakODRLinkage: case GlobalValue::LinkerPrivateWeakLinkage: + case GlobalValue::LinkerPrivateWeakDefAutoLinkage: if (MAI->getWeakDefDirective() != 0) { // .globl _foo OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global); - // .weak_definition _foo - OutStreamer.EmitSymbolAttribute(GVSym, MCSA_WeakDefinition); + + if ((GlobalValue::LinkageTypes)Linkage != + GlobalValue::LinkerPrivateWeakDefAutoLinkage) + // .weak_definition _foo + OutStreamer.EmitSymbolAttribute(GVSym, MCSA_WeakDefinition); + else + OutStreamer.EmitSymbolAttribute(GVSym, MCSA_WeakDefAutoPrivate); } else if (MAI->getLinkOnceDirective() != 0) { // .globl _foo OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global); @@ -510,12 +516,8 @@ static void EmitComments(const MachineInstr &MI, raw_ostream &CommentOS) { } // Check for spill-induced copies - unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx; - if (TM.getInstrInfo()->isMoveInstr(MI, SrcReg, DstReg, - SrcSubIdx, DstSubIdx)) { - if (MI.getAsmPrinterFlag(MachineInstr::ReloadReuse)) - CommentOS << " Reload Reuse\n"; - } + if (MI.getAsmPrinterFlag(MachineInstr::ReloadReuse)) + CommentOS << " Reload Reuse\n"; } /// EmitImplicitDef - This method emits the specified machine instruction @@ -603,12 +605,15 @@ void AsmPrinter::EmitFunctionBody() { // Print out code for the function. bool HasAnyRealCode = false; + const MachineInstr *LastMI = 0; for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); I != E; ++I) { // Print a label for the basic block. EmitBasicBlockStart(I); for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end(); II != IE; ++II) { + LastMI = II; + // Print the assembly for the instruction. if (!II->isLabel() && !II->isImplicitDef() && !II->isKill() && !II->isDebugValue()) { @@ -625,7 +630,7 @@ void AsmPrinter::EmitFunctionBody() { EmitComments(*II, OutStreamer.GetCommentOS()); switch (II->getOpcode()) { - case TargetOpcode::DBG_LABEL: + case TargetOpcode::PROLOG_LABEL: case TargetOpcode::EH_LABEL: case TargetOpcode::GC_LABEL: OutStreamer.EmitLabel(II->getOperand(0).getMCSymbol()); @@ -656,11 +661,18 @@ void AsmPrinter::EmitFunctionBody() { } } } - + + // If the last instruction was a prolog label, then we have a situation where + // we emitted a prolog but no function body. This results in the ending prolog + // label equaling the end of function label and an invalid "row" in the + // FDE. We need to emit a noop in this situation so that the FDE's rows are + // valid. + bool RequiresNoop = LastMI && LastMI->isPrologLabel(); + // If the function is empty and the object file uses .subsections_via_symbols, // then we need to emit *something* to the function body to prevent the // labels from collapsing together. Just emit a noop. - if (MAI->hasSubsectionsViaSymbols() && !HasAnyRealCode) { + if ((MAI->hasSubsectionsViaSymbols() && !HasAnyRealCode) || RequiresNoop) { MCInst Noop; TM.getInstrInfo()->getNoopForMachoTarget(Noop); if (Noop.getOpcode()) { @@ -1206,6 +1218,22 @@ void AsmPrinter::EmitLabelOffsetDifference(const MCSymbol *Hi, uint64_t Offset, OutStreamer.EmitSymbolValue(SetLabel, 4, 0/*AddrSpace*/); } } + +/// EmitLabelPlusOffset - Emit something like ".long Label+Offset" +/// where the size in bytes of the directive is specified by Size and Label +/// specifies the label. This implicitly uses .set if it is available. +void AsmPrinter::EmitLabelPlusOffset(const MCSymbol *Label, uint64_t Offset, + unsigned Size) + const { + + // Emit Label+Offset + const MCExpr *Plus = + MCBinaryExpr::CreateAdd(MCSymbolRefExpr::Create(Label, OutContext), + MCConstantExpr::Create(Offset, OutContext), + OutContext); + + OutStreamer.EmitValue(Plus, 4, 0/*AddrSpace*/); +} //===----------------------------------------------------------------------===// @@ -1244,6 +1272,7 @@ static const MCExpr *LowerConstant(const Constant *CV, AsmPrinter &AP) { if (const GlobalValue *GV = dyn_cast(CV)) return MCSymbolRefExpr::Create(AP.Mang->getSymbol(GV), Ctx); + if (const BlockAddress *BA = dyn_cast(CV)) return MCSymbolRefExpr::Create(AP.GetBlockAddressSymbol(BA), Ctx); @@ -1262,10 +1291,17 @@ static const MCExpr *LowerConstant(const Constant *CV, AsmPrinter &AP) { ConstantFoldConstantExpression(CE, AP.TM.getTargetData())) if (C != CE) return LowerConstant(C, AP); -#ifndef NDEBUG - CE->dump(); -#endif - llvm_unreachable("FIXME: Don't support this constant expr"); + + // Otherwise report the problem to the user. + { + std::string S; + raw_string_ostream OS(S); + OS << "Unsupported expression in static initializer: "; + WriteAsOperand(OS, CE, /*PrintType=*/false, + !AP.MF ? 0 : AP.MF->getFunction()->getParent()); + report_fatal_error(OS.str()); + } + return MCConstantExpr::Create(0, Ctx); case Instruction::GetElementPtr: { const TargetData &TD = *AP.TM.getTargetData(); // Generate a symbolic expression for the byte address @@ -1413,21 +1449,6 @@ static void EmitGlobalConstantStruct(const ConstantStruct *CS, "Layout of constant struct may be incorrect!"); } -static void EmitGlobalConstantUnion(const ConstantUnion *CU, - unsigned AddrSpace, AsmPrinter &AP) { - const TargetData *TD = AP.TM.getTargetData(); - unsigned Size = TD->getTypeAllocSize(CU->getType()); - - const Constant *Contents = CU->getOperand(0); - unsigned FilledSize = TD->getTypeAllocSize(Contents->getType()); - - // Print the actually filled part - EmitGlobalConstantImpl(Contents, AddrSpace, AP); - - // And pad with enough zeroes - AP.OutStreamer.EmitZeros(Size-FilledSize, AddrSpace); -} - static void EmitGlobalConstantFP(const ConstantFP *CFP, unsigned AddrSpace, AsmPrinter &AP) { // FP Constants are printed as integer constants to avoid losing @@ -1530,7 +1551,7 @@ static void EmitGlobalConstantImpl(const Constant *CV, unsigned AddrSpace, case 8: if (AP.isVerbose()) AP.OutStreamer.GetCommentOS() << format("0x%llx\n", CI->getZExtValue()); - AP.OutStreamer.EmitIntValue(CI->getZExtValue(), Size, AddrSpace); + AP.OutStreamer.EmitIntValue(CI->getZExtValue(), Size, AddrSpace); return; default: EmitGlobalConstantLargeInt(CI, AddrSpace, AP); @@ -1553,9 +1574,6 @@ static void EmitGlobalConstantImpl(const Constant *CV, unsigned AddrSpace, return; } - if (const ConstantUnion *CVU = dyn_cast(CV)) - return EmitGlobalConstantUnion(CVU, AddrSpace, AP); - if (const ConstantVector *V = dyn_cast(CV)) return EmitGlobalConstantVector(V, AddrSpace, AP); diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp index b310578..ce4519c 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -36,7 +36,7 @@ void AsmPrinter::EmitSLEB128(int Value, const char *Desc) const { if (isVerbose() && Desc) OutStreamer.AddComment(Desc); - if (MAI->hasLEB128()) { + if (MAI->hasLEB128() && OutStreamer.hasRawTextSupport()) { // FIXME: MCize. OutStreamer.EmitRawText("\t.sleb128\t" + Twine(Value)); return; @@ -61,7 +61,7 @@ void AsmPrinter::EmitULEB128(unsigned Value, const char *Desc, if (isVerbose() && Desc) OutStreamer.AddComment(Desc); - if (MAI->hasLEB128() && PadTo == 0) { + if (MAI->hasLEB128() && PadTo == 0 && OutStreamer.hasRawTextSupport()) { // FIXME: MCize. OutStreamer.EmitRawText("\t.uleb128\t" + Twine(Value)); return; diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp index 202d9b6..df03168 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -22,7 +22,6 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCParser/AsmParser.h" #include "llvm/Target/TargetAsmParser.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegistry.h" @@ -72,16 +71,18 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, unsigned LocCookie) const { // Tell SrcMgr about this buffer, it takes ownership of the buffer. SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); - AsmParser Parser(TM.getTarget(), SrcMgr, OutContext, OutStreamer, *MAI); - OwningPtr TAP(TM.getTarget().createAsmParser(Parser)); + OwningPtr Parser(createMCAsmParser(TM.getTarget(), SrcMgr, + OutContext, OutStreamer, + *MAI)); + OwningPtr TAP(TM.getTarget().createAsmParser(*Parser, TM)); if (!TAP) report_fatal_error("Inline asm not supported by this streamer because" " we don't have an asm parser for this target\n"); - Parser.setTargetParser(*TAP.get()); + Parser->setTargetParser(*TAP.get()); // Don't implicitly switch to the text section before the asm. - int Res = Parser.Run(/*NoInitialTextSection*/ true, - /*NoFinalize*/ true); + int Res = Parser->Run(/*NoInitialTextSection*/ true, + /*NoFinalize*/ true); if (Res && !HasDiagHandler) report_fatal_error("Error parsing inline asm\n"); } diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 65c1d19..c886a5e 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -44,7 +44,7 @@ using namespace llvm; static cl::opt PrintDbgScope("print-dbgscope", cl::Hidden, cl::desc("Print DbgScope information for each machine instruction")); -static cl::opt DisableDebugInfoPrinting("disable-debug-info-print", +static cl::opt DisableDebugInfoPrinting("disable-debug-info-print", cl::Hidden, cl::desc("Disable debug info printing")); @@ -116,8 +116,8 @@ public: /// addGlobalType - Add a new global type to the compile unit. /// - void addGlobalType(StringRef Name, DIE *Die) { - GlobalTypes[Name] = Die; + void addGlobalType(StringRef Name, DIE *Die) { + GlobalTypes[Name] = Die; } /// getDIE - Returns the debug information entry map slot for the @@ -131,8 +131,9 @@ public: /// getDIEEntry - Returns the debug information entry for the speciefied /// debug variable. - DIEEntry *getDIEEntry(const MDNode *N) { - DenseMap::iterator I = MDNodeToDIEEntryMap.find(N); + DIEEntry *getDIEEntry(const MDNode *N) { + DenseMap::iterator I = + MDNodeToDIEEntryMap.find(N); if (I == MDNodeToDIEEntryMap.end()) return NULL; return I->second; @@ -179,6 +180,73 @@ public: DIE *getDIE() const { return TheDIE; } void setDotDebugLocOffset(unsigned O) { DotDebugLocOffset = O; } unsigned getDotDebugLocOffset() const { return DotDebugLocOffset; } + StringRef getName() const { return Var.getName(); } + unsigned getTag() const { return Var.getTag(); } + bool variableHasComplexAddress() const { + assert(Var.Verify() && "Invalid complex DbgVariable!"); + return Var.hasComplexAddress(); + } + bool isBlockByrefVariable() const { + assert(Var.Verify() && "Invalid complex DbgVariable!"); + return Var.isBlockByrefVariable(); + } + unsigned getNumAddrElements() const { + assert(Var.Verify() && "Invalid complex DbgVariable!"); + return Var.getNumAddrElements(); + } + uint64_t getAddrElement(unsigned i) const { + return Var.getAddrElement(i); + } + DIType getType() const { + DIType Ty = Var.getType(); + // FIXME: isBlockByrefVariable should be reformulated in terms of complex + // addresses instead. + if (Var.isBlockByrefVariable()) { + /* Byref variables, in Blocks, are declared by the programmer as + "SomeType VarName;", but the compiler creates a + __Block_byref_x_VarName struct, and gives the variable VarName + either the struct, or a pointer to the struct, as its type. This + is necessary for various behind-the-scenes things the compiler + needs to do with by-reference variables in blocks. + + However, as far as the original *programmer* is concerned, the + variable should still have type 'SomeType', as originally declared. + + The following function dives into the __Block_byref_x_VarName + struct to find the original type of the variable. This will be + passed back to the code generating the type for the Debug + Information Entry for the variable 'VarName'. 'VarName' will then + have the original type 'SomeType' in its debug information. + + The original type 'SomeType' will be the type of the field named + 'VarName' inside the __Block_byref_x_VarName struct. + + NOTE: In order for this to not completely fail on the debugger + side, the Debug Information Entry for the variable VarName needs to + have a DW_AT_location that tells the debugger how to unwind through + the pointers and __Block_byref_x_VarName struct to find the actual + value of the variable. The function addBlockByrefType does this. */ + DIType subType = Ty; + unsigned tag = Ty.getTag(); + + if (tag == dwarf::DW_TAG_pointer_type) { + DIDerivedType DTy = DIDerivedType(Ty); + subType = DTy.getTypeDerivedFrom(); + } + + DICompositeType blockStruct = DICompositeType(subType); + DIArray Elements = blockStruct.getTypeArray(); + + for (unsigned i = 0, N = Elements.getNumElements(); i < N; ++i) { + DIDescriptor Element = Elements.getElement(i); + DIDerivedType DT = DIDerivedType(Element); + if (getName() == DT.getName()) + return (DT.getTypeDerivedFrom()); + } + return Ty; + } + return Ty; + } }; //===----------------------------------------------------------------------===// @@ -194,7 +262,7 @@ class DbgScope { DbgScope *Parent; // Parent to this scope. DIDescriptor Desc; // Debug info descriptor for scope. // Location at which this scope is inlined. - AssertingVH InlinedAtLocation; + AssertingVH InlinedAtLocation; bool AbstractScope; // Abstract Scope const MachineInstr *LastInsn; // Last instruction of this scope. const MachineInstr *FirstInsn; // First instruction of this scope. @@ -220,19 +288,19 @@ public: const MDNode *getInlinedAt() const { return InlinedAtLocation; } const MDNode *getScopeNode() const { return Desc; } const SmallVector &getScopes() { return Scopes; } - const SmallVector &getVariables() { return Variables; } + const SmallVector &getDbgVariables() { return Variables; } const SmallVector &getRanges() { return Ranges; } /// openInsnRange - This scope covers instruction range starting from MI. void openInsnRange(const MachineInstr *MI) { - if (!FirstInsn) + if (!FirstInsn) FirstInsn = MI; - + if (Parent) Parent->openInsnRange(MI); } - /// extendInsnRange - Extend the current instruction range covered by + /// extendInsnRange - Extend the current instruction range covered by /// this scope. void extendInsnRange(const MachineInstr *MI) { assert (FirstInsn && "MI Range is not open!"); @@ -247,9 +315,9 @@ public: void closeInsnRange(DbgScope *NewScope = NULL) { assert (LastInsn && "Last insn missing!"); Ranges.push_back(DbgRange(FirstInsn, LastInsn)); - FirstInsn = NULL; + FirstInsn = NULL; LastInsn = NULL; - // If Parent dominates NewScope then do not close Parent's instruction + // If Parent dominates NewScope then do not close Parent's instruction // range. if (Parent && (!NewScope || !Parent->dominates(NewScope))) Parent->closeInsnRange(NewScope); @@ -264,7 +332,7 @@ public: unsigned getDFSIn() const { return DFSIn; } void setDFSIn(unsigned I) { DFSIn = I; } bool dominates(const DbgScope *S) { - if (S == this) + if (S == this) return true; if (DFSIn < S->getDFSIn() && DFSOut > S->getDFSOut()) return true; @@ -313,14 +381,13 @@ DbgScope::~DbgScope() { DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) : Asm(A), MMI(Asm->MMI), FirstCU(0), - AbbreviationsSet(InitAbbreviationsSetSize), + AbbreviationsSet(InitAbbreviationsSetSize), CurrentFnDbgScope(0), PrevLabel(NULL) { NextStringPoolNumber = 0; - + DwarfFrameSectionSym = DwarfInfoSectionSym = DwarfAbbrevSectionSym = 0; DwarfStrSectionSym = TextSectionSym = 0; - DwarfDebugRangeSectionSym = DwarfDebugLocSectionSym = 0; - DwarfDebugLineSectionSym = CurrentLineSectionSym = 0; + DwarfDebugRangeSectionSym = DwarfDebugLocSectionSym = 0; FunctionBeginSym = FunctionEndSym = 0; DIEIntegerOne = new (DIEValueAllocator) DIEInteger(1); { @@ -377,7 +444,7 @@ DIEEntry *DwarfDebug::createDIEEntry(DIE *Entry) { void DwarfDebug::addUInt(DIE *Die, unsigned Attribute, unsigned Form, uint64_t Integer) { if (!Form) Form = DIEInteger::BestForm(false, Integer); - DIEValue *Value = Integer == 1 ? + DIEValue *Value = Integer == 1 ? DIEIntegerOne : new (DIEValueAllocator) DIEInteger(Integer); Die->addValue(Attribute, Form, Value); } @@ -392,7 +459,7 @@ void DwarfDebug::addSInt(DIE *Die, unsigned Attribute, } /// addString - Add a string attribute data and value. DIEString only -/// keeps string reference. +/// keeps string reference. void DwarfDebug::addString(DIE *Die, unsigned Attribute, unsigned Form, StringRef String) { DIEValue *Value = new (DIEValueAllocator) DIEString(String); @@ -434,14 +501,14 @@ void DwarfDebug::addBlock(DIE *Die, unsigned Attribute, unsigned Form, /// addSourceLine - Add location information to specified debug information /// entry. -void DwarfDebug::addSourceLine(DIE *Die, const DIVariable *V) { +void DwarfDebug::addSourceLine(DIE *Die, DIVariable V) { // Verify variable. - if (!V->Verify()) + if (!V.Verify()) return; - unsigned Line = V->getLineNumber(); - unsigned FileID = GetOrCreateSourceID(V->getContext().getDirectory(), - V->getContext().getFilename()); + unsigned Line = V.getLineNumber(); + unsigned FileID = GetOrCreateSourceID(V.getContext().getDirectory(), + V.getContext().getFilename()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); @@ -449,14 +516,14 @@ void DwarfDebug::addSourceLine(DIE *Die, const DIVariable *V) { /// addSourceLine - Add location information to specified debug information /// entry. -void DwarfDebug::addSourceLine(DIE *Die, const DIGlobalVariable *G) { +void DwarfDebug::addSourceLine(DIE *Die, DIGlobalVariable G) { // Verify global variable. - if (!G->Verify()) + if (!G.Verify()) return; - unsigned Line = G->getLineNumber(); - unsigned FileID = GetOrCreateSourceID(G->getContext().getDirectory(), - G->getContext().getFilename()); + unsigned Line = G.getLineNumber(); + unsigned FileID = GetOrCreateSourceID(G.getContext().getDirectory(), + G.getContext().getFilename()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); @@ -464,19 +531,19 @@ void DwarfDebug::addSourceLine(DIE *Die, const DIGlobalVariable *G) { /// addSourceLine - Add location information to specified debug information /// entry. -void DwarfDebug::addSourceLine(DIE *Die, const DISubprogram *SP) { +void DwarfDebug::addSourceLine(DIE *Die, DISubprogram SP) { // Verify subprogram. - if (!SP->Verify()) + if (!SP.Verify()) return; // If the line number is 0, don't add it. - if (SP->getLineNumber() == 0) + if (SP.getLineNumber() == 0) return; - unsigned Line = SP->getLineNumber(); - if (!SP->getContext().Verify()) + unsigned Line = SP.getLineNumber(); + if (!SP.getContext().Verify()) return; - unsigned FileID = GetOrCreateSourceID(SP->getDirectory(), - SP->getFilename()); + unsigned FileID = GetOrCreateSourceID(SP.getDirectory(), + SP.getFilename()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); @@ -484,16 +551,16 @@ void DwarfDebug::addSourceLine(DIE *Die, const DISubprogram *SP) { /// addSourceLine - Add location information to specified debug information /// entry. -void DwarfDebug::addSourceLine(DIE *Die, const DIType *Ty) { +void DwarfDebug::addSourceLine(DIE *Die, DIType Ty) { // Verify type. - if (!Ty->Verify()) + if (!Ty.Verify()) return; - unsigned Line = Ty->getLineNumber(); - if (!Ty->getContext().Verify()) + unsigned Line = Ty.getLineNumber(); + if (!Ty.getContext().Verify()) return; - unsigned FileID = GetOrCreateSourceID(Ty->getContext().getDirectory(), - Ty->getContext().getFilename()); + unsigned FileID = GetOrCreateSourceID(Ty.getContext().getDirectory(), + Ty.getContext().getFilename()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); @@ -501,14 +568,14 @@ void DwarfDebug::addSourceLine(DIE *Die, const DIType *Ty) { /// addSourceLine - Add location information to specified debug information /// entry. -void DwarfDebug::addSourceLine(DIE *Die, const DINameSpace *NS) { +void DwarfDebug::addSourceLine(DIE *Die, DINameSpace NS) { // Verify namespace. - if (!NS->Verify()) + if (!NS.Verify()) return; - unsigned Line = NS->getLineNumber(); - StringRef FN = NS->getFilename(); - StringRef Dir = NS->getDirectory(); + unsigned Line = NS.getLineNumber(); + StringRef FN = NS.getFilename(); + StringRef Dir = NS.getDirectory(); unsigned FileID = GetOrCreateSourceID(Dir, FN); assert(FileID && "Invalid file id"); @@ -516,55 +583,21 @@ void DwarfDebug::addSourceLine(DIE *Die, const DINameSpace *NS) { addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); } -/* Byref variables, in Blocks, are declared by the programmer as - "SomeType VarName;", but the compiler creates a - __Block_byref_x_VarName struct, and gives the variable VarName - either the struct, or a pointer to the struct, as its type. This - is necessary for various behind-the-scenes things the compiler - needs to do with by-reference variables in blocks. - - However, as far as the original *programmer* is concerned, the - variable should still have type 'SomeType', as originally declared. - - The following function dives into the __Block_byref_x_VarName - struct to find the original type of the variable. This will be - passed back to the code generating the type for the Debug - Information Entry for the variable 'VarName'. 'VarName' will then - have the original type 'SomeType' in its debug information. - - The original type 'SomeType' will be the type of the field named - 'VarName' inside the __Block_byref_x_VarName struct. - - NOTE: In order for this to not completely fail on the debugger - side, the Debug Information Entry for the variable VarName needs to - have a DW_AT_location that tells the debugger how to unwind through - the pointers and __Block_byref_x_VarName struct to find the actual - value of the variable. The function addBlockByrefType does this. */ - -/// Find the type the programmer originally declared the variable to be -/// and return that type. -/// -DIType DwarfDebug::getBlockByrefType(DIType Ty, std::string Name) { - - DIType subType = Ty; - unsigned tag = Ty.getTag(); - - if (tag == dwarf::DW_TAG_pointer_type) { - DIDerivedType DTy = DIDerivedType(Ty); - subType = DTy.getTypeDerivedFrom(); - } - - DICompositeType blockStruct = DICompositeType(subType); - DIArray Elements = blockStruct.getTypeArray(); - - for (unsigned i = 0, N = Elements.getNumElements(); i < N; ++i) { - DIDescriptor Element = Elements.getElement(i); - DIDerivedType DT = DIDerivedType(Element); - if (Name == DT.getName()) - return (DT.getTypeDerivedFrom()); - } +/// addVariableAddress - Add DW_AT_location attribute for a DbgVariable based +/// on provided frame index. +void DwarfDebug::addVariableAddress(DbgVariable *&DV, DIE *Die, int64_t FI) { + MachineLocation Location; + unsigned FrameReg; + const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo(); + int Offset = RI->getFrameIndexReference(*Asm->MF, FI, FrameReg); + Location.set(FrameReg, Offset); - return Ty; + if (DV->variableHasComplexAddress()) + addComplexAddress(DV, Die, dwarf::DW_AT_location, Location); + else if (DV->isBlockByrefVariable()) + addBlockByrefAddress(DV, Die, dwarf::DW_AT_location, Location); + else + addAddress(Die, dwarf::DW_AT_location, Location); } /// addComplexAddress - Start with the address based on the location provided, @@ -575,8 +608,7 @@ DIType DwarfDebug::getBlockByrefType(DIType Ty, std::string Name) { void DwarfDebug::addComplexAddress(DbgVariable *&DV, DIE *Die, unsigned Attribute, const MachineLocation &Location) { - const DIVariable &VD = DV->getVariable(); - DIType Ty = VD.getType(); + DIType Ty = DV->getType(); // Decode the original location, and use that as the start of the byref // variable's location. @@ -603,12 +635,12 @@ void DwarfDebug::addComplexAddress(DbgVariable *&DV, DIE *Die, addUInt(Block, 0, dwarf::DW_FORM_sdata, Location.getOffset()); } - for (unsigned i = 0, N = VD.getNumAddrElements(); i < N; ++i) { - uint64_t Element = VD.getAddrElement(i); + for (unsigned i = 0, N = DV->getNumAddrElements(); i < N; ++i) { + uint64_t Element = DV->getAddrElement(i); if (Element == DIFactory::OpPlus) { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); - addUInt(Block, 0, dwarf::DW_FORM_udata, VD.getAddrElement(++i)); + addUInt(Block, 0, dwarf::DW_FORM_udata, DV->getAddrElement(++i)); } else if (Element == DIFactory::OpDeref) { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); } else llvm_unreachable("unknown DIFactory Opcode"); @@ -681,13 +713,12 @@ void DwarfDebug::addComplexAddress(DbgVariable *&DV, DIE *Die, void DwarfDebug::addBlockByrefAddress(DbgVariable *&DV, DIE *Die, unsigned Attribute, const MachineLocation &Location) { - const DIVariable &VD = DV->getVariable(); - DIType Ty = VD.getType(); + DIType Ty = DV->getType(); DIType TmpTy = Ty; unsigned Tag = Ty.getTag(); bool isPointer = false; - StringRef varName = VD.getName(); + StringRef varName = DV->getName(); if (Tag == dwarf::DW_TAG_pointer_type) { DIDerivedType DTy = DIDerivedType(Ty); @@ -835,26 +866,26 @@ bool DwarfDebug::addConstantFPValue(DIE *Die, const MCSymbol *VS, assert (MO.isFPImm() && "Invalid machine operand!"); DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); APFloat FPImm = MO.getFPImm()->getValueAPF(); - + // Get the raw data form of the floating point. const APInt FltVal = FPImm.bitcastToAPInt(); const char *FltPtr = (const char*)FltVal.getRawData(); - + int NumBytes = FltVal.getBitWidth() / 8; // 8 bits per byte. bool LittleEndian = Asm->getTargetData().isLittleEndian(); int Incr = (LittleEndian ? 1 : -1); int Start = (LittleEndian ? 0 : NumBytes - 1); int Stop = (LittleEndian ? NumBytes : -1); - + // Output the constant to DWARF one byte at a time. for (; Start != Stop; Start += Incr) addUInt(Block, 0, dwarf::DW_FORM_data1, (unsigned char)0xFF & FltPtr[Start]); - + addBlock(Die, dwarf::DW_AT_const_value, 0, Block); if (VS) addLabel(Die, dwarf::DW_AT_start_scope, dwarf::DW_FORM_addr, VS); - return true; + return true; } @@ -872,7 +903,7 @@ void DwarfDebug::addToContextOwner(DIE *Die, DIDescriptor Context) { ContextDIE->addChild(Die); } else if (DIE *ContextDIE = getCompileUnit(Context)->getDIE(Context)) ContextDIE->addChild(Die); - else + else getCompileUnit(Context)->addDie(Die); } @@ -965,7 +996,7 @@ void DwarfDebug::constructTypeDIE(DIE &Buffer, DIDerivedType DTy) { // Add source line info if available and TyDesc is not a forward declaration. if (!DTy.isForwardDecl()) - addSourceLine(&Buffer, &DTy); + addSourceLine(&Buffer, DTy); } /// constructTypeDIE - Construct type DIE from DICompositeType. @@ -1039,7 +1070,7 @@ void DwarfDebug::constructTypeDIE(DIE &Buffer, DICompositeType CTy) { addType(ElemDie, DV.getType()); addUInt(ElemDie, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag, 1); addUInt(ElemDie, dwarf::DW_AT_external, dwarf::DW_FORM_flag, 1); - addSourceLine(ElemDie, &DV); + addSourceLine(ElemDie, DV); } else if (Element.isDerivedType()) ElemDie = createMemberDIE(DIDerivedType(Element)); else @@ -1057,7 +1088,7 @@ void DwarfDebug::constructTypeDIE(DIE &Buffer, DICompositeType CTy) { DICompositeType ContainingType = CTy.getContainingType(); if (DIDescriptor(ContainingType).isCompositeType()) - addDIEEntry(&Buffer, dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4, + addDIEEntry(&Buffer, dwarf::DW_AT_containing_type, dwarf::DW_FORM_ref4, getOrCreateTypeDIE(DIType(ContainingType))); else { DIDescriptor Context = CTy.getContext(); @@ -1073,7 +1104,7 @@ void DwarfDebug::constructTypeDIE(DIE &Buffer, DICompositeType CTy) { if (!Name.empty()) addString(&Buffer, dwarf::DW_AT_name, dwarf::DW_FORM_string, Name); - if (Tag == dwarf::DW_TAG_enumeration_type || Tag == dwarf::DW_TAG_class_type + if (Tag == dwarf::DW_TAG_enumeration_type || Tag == dwarf::DW_TAG_class_type || Tag == dwarf::DW_TAG_structure_type || Tag == dwarf::DW_TAG_union_type) { // Add size if non-zero (derived types might be zero-sized.) @@ -1089,7 +1120,7 @@ void DwarfDebug::constructTypeDIE(DIE &Buffer, DICompositeType CTy) { // Add source line info if available. if (!CTy.isForwardDecl()) - addSourceLine(&Buffer, &CTy); + addSourceLine(&Buffer, CTy); } } @@ -1149,7 +1180,7 @@ DIE *DwarfDebug::constructEnumTypeDIE(DIEnumerator ETy) { return Enumerator; } -/// getRealLinkageName - If special LLVM prefix that is used to inform the asm +/// getRealLinkageName - If special LLVM prefix that is used to inform the asm /// printer to not emit usual symbol prefix before the symbol name is used then /// return linkage name after skipping this special LLVM prefix. static StringRef getRealLinkageName(StringRef LinkageName) { @@ -1159,40 +1190,16 @@ static StringRef getRealLinkageName(StringRef LinkageName) { return LinkageName; } -/// createGlobalVariableDIE - Create new DIE using GV. -DIE *DwarfDebug::createGlobalVariableDIE(const DIGlobalVariable &GV) { - // If the global variable was optmized out then no need to create debug info - // entry. - if (!GV.getGlobal()) return NULL; - if (GV.getDisplayName().empty()) return NULL; - - DIE *GVDie = new DIE(dwarf::DW_TAG_variable); - addString(GVDie, dwarf::DW_AT_name, dwarf::DW_FORM_string, - GV.getDisplayName()); - - StringRef LinkageName = GV.getLinkageName(); - if (!LinkageName.empty()) - addString(GVDie, dwarf::DW_AT_MIPS_linkage_name, dwarf::DW_FORM_string, - getRealLinkageName(LinkageName)); - - addType(GVDie, GV.getType()); - if (!GV.isLocalToUnit()) - addUInt(GVDie, dwarf::DW_AT_external, dwarf::DW_FORM_flag, 1); - addSourceLine(GVDie, &GV); - - return GVDie; -} - /// createMemberDIE - Create new member DIE. -DIE *DwarfDebug::createMemberDIE(const DIDerivedType &DT) { +DIE *DwarfDebug::createMemberDIE(DIDerivedType DT) { DIE *MemberDie = new DIE(DT.getTag()); StringRef Name = DT.getName(); if (!Name.empty()) addString(MemberDie, dwarf::DW_AT_name, dwarf::DW_FORM_string, Name); - + addType(MemberDie, DT.getTypeDerivedFrom()); - addSourceLine(MemberDie, &DT); + addSourceLine(MemberDie, DT); DIEBlock *MemLocationDie = new (DIEValueAllocator) DIEBlock(); addUInt(MemLocationDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); @@ -1240,7 +1247,7 @@ DIE *DwarfDebug::createMemberDIE(const DIDerivedType &DT) { addUInt(VBaseLocationDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); addUInt(VBaseLocationDie, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus); - addBlock(MemberDie, dwarf::DW_AT_data_member_location, 0, + addBlock(MemberDie, dwarf::DW_AT_data_member_location, 0, VBaseLocationDie); } else addBlock(MemberDie, dwarf::DW_AT_data_member_location, 0, MemLocationDie); @@ -1261,7 +1268,7 @@ DIE *DwarfDebug::createMemberDIE(const DIDerivedType &DT) { } /// createSubprogramDIE - Create new DIE using SP. -DIE *DwarfDebug::createSubprogramDIE(const DISubprogram &SP, bool MakeDecl) { +DIE *DwarfDebug::createSubprogramDIE(DISubprogram SP, bool MakeDecl) { CompileUnit *SPCU = getCompileUnit(SP); DIE *SPDie = SPCU->getDIE(SP); if (SPDie) @@ -1277,7 +1284,7 @@ DIE *DwarfDebug::createSubprogramDIE(const DISubprogram &SP, bool MakeDecl) { addString(SPDie, dwarf::DW_AT_MIPS_linkage_name, dwarf::DW_FORM_string, getRealLinkageName(LinkageName)); - addSourceLine(SPDie, &SP); + addSourceLine(SPDie, SP); // Add prototyped tag, if C or ObjC. unsigned Lang = SP.getCompileUnit().getLanguage(); @@ -1302,7 +1309,7 @@ DIE *DwarfDebug::createSubprogramDIE(const DISubprogram &SP, bool MakeDecl) { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_constu); addUInt(Block, 0, dwarf::DW_FORM_data1, SP.getVirtualIndex()); addBlock(SPDie, dwarf::DW_AT_vtable_elem_location, 0, Block); - ContainingTypeMap.insert(std::make_pair(SPDie, + ContainingTypeMap.insert(std::make_pair(SPDie, SP.getContainingType())); } @@ -1331,10 +1338,14 @@ DIE *DwarfDebug::createSubprogramDIE(const DISubprogram &SP, bool MakeDecl) { if (!SP.isLocalToUnit()) addUInt(SPDie, dwarf::DW_AT_external, dwarf::DW_FORM_flag, 1); - + if (SP.isOptimized()) addUInt(SPDie, dwarf::DW_AT_APPLE_optimized, dwarf::DW_FORM_flag, 1); + if (unsigned isa = Asm->getISAEncoding()) { + addUInt(SPDie, dwarf::DW_AT_APPLE_isa, dwarf::DW_FORM_flag, isa); + } + // DW_TAG_inlined_subroutine may refer to this DIE. SPCU->insertDIE(SP, SPDie); @@ -1394,18 +1405,18 @@ DIE *DwarfDebug::updateSubprogramScopeDIE(const MDNode *SPNode) { assert(SPDie && "Unable to find subprogram DIE!"); DISubprogram SP(SPNode); - + // There is not any need to generate specification DIE for a function // defined at compile unit level. If a function is defined inside another // function then gdb prefers the definition at top level and but does not - // expect specification DIE in parent function. So avoid creating + // expect specification DIE in parent function. So avoid creating // specification DIE for a function defined inside a function. if (SP.isDefinition() && !SP.getContext().isCompileUnit() && - !SP.getContext().isFile() && + !SP.getContext().isFile() && !isSubprogramContext(SP.getContext())) { addUInt(SPDie, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag, 1); - - // Add arguments. + + // Add arguments. DICompositeType SPTy = SP.getType(); DIArray Args = SPTy.getTypeArray(); unsigned SPTag = SPTy.getTag(); @@ -1420,11 +1431,11 @@ DIE *DwarfDebug::updateSubprogramScopeDIE(const MDNode *SPNode) { } DIE *SPDeclDie = SPDie; SPDie = new DIE(dwarf::DW_TAG_subprogram); - addDIEEntry(SPDie, dwarf::DW_AT_specification, dwarf::DW_FORM_ref4, + addDIEEntry(SPDie, dwarf::DW_AT_specification, dwarf::DW_FORM_ref4, SPDeclDie); SPCU->addDie(SPDie); } - + // Pick up abstract subprogram DIE. if (DIE *AbsSPDIE = AbstractSPDies.lookup(SPNode)) { SPDie = new DIE(dwarf::DW_TAG_subprogram); @@ -1459,7 +1470,7 @@ DIE *DwarfDebug::constructLexicalScopeDIE(DbgScope *Scope) { SmallVector::const_iterator RI = Ranges.begin(); if (Ranges.size() > 1) { // .debug_range section has not been laid out yet. Emit offset in - // .debug_range as a uint, size 4, for now. emitDIE will handle + // .debug_range as a uint, size 4, for now. emitDIE will handle // DW_AT_ranges appropriately. addUInt(ScopeDIE, dwarf::DW_AT_ranges, dwarf::DW_FORM_data4, DebugRangeSymbols.size() * Asm->getTargetData().getPointerSize()); @@ -1480,7 +1491,7 @@ DIE *DwarfDebug::constructLexicalScopeDIE(DbgScope *Scope) { assert(Start->isDefined() && "Invalid starting label for an inlined scope!"); assert(End->isDefined() && "Invalid end label for an inlined scope!"); - + addLabel(ScopeDIE, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr, Start); addLabel(ScopeDIE, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr, End); @@ -1493,7 +1504,7 @@ DIE *DwarfDebug::constructLexicalScopeDIE(DbgScope *Scope) { DIE *DwarfDebug::constructInlinedScopeDIE(DbgScope *Scope) { const SmallVector &Ranges = Scope->getRanges(); - assert (Ranges.empty() == false + assert (Ranges.empty() == false && "DbgScope does not have instruction markers!"); // FIXME : .debug_inlined section specification does not clearly state how @@ -1551,16 +1562,14 @@ DIE *DwarfDebug::constructInlinedScopeDIE(DbgScope *Scope) { /// constructVariableDIE - Construct a DIE for the given DbgVariable. DIE *DwarfDebug::constructVariableDIE(DbgVariable *DV, DbgScope *Scope) { - // Get the descriptor. - const DIVariable &VD = DV->getVariable(); - StringRef Name = VD.getName(); + StringRef Name = DV->getName(); if (Name.empty()) return NULL; // Translate tag to proper Dwarf tag. The result variable is dropped for // now. unsigned Tag; - switch (VD.getTag()) { + switch (DV->getTag()) { case dwarf::DW_TAG_return_variable: return NULL; case dwarf::DW_TAG_arg_variable: @@ -1586,18 +1595,13 @@ DIE *DwarfDebug::constructVariableDIE(DbgVariable *DV, DbgScope *Scope) { dwarf::DW_FORM_ref4, AbsDIE); else { addString(VariableDie, dwarf::DW_AT_name, dwarf::DW_FORM_string, Name); - addSourceLine(VariableDie, &VD); + addSourceLine(VariableDie, DV->getVariable()); // Add variable type. - // FIXME: isBlockByrefVariable should be reformulated in terms of complex - // addresses instead. - if (VD.isBlockByrefVariable()) - addType(VariableDie, getBlockByrefType(VD.getType(), Name)); - else - addType(VariableDie, VD.getType()); + addType(VariableDie, DV->getType()); } - if (Tag == dwarf::DW_TAG_formal_parameter && VD.getType().isArtificial()) + if (Tag == dwarf::DW_TAG_formal_parameter && DV->getType().isArtificial()) addUInt(VariableDie, dwarf::DW_AT_artificial, dwarf::DW_FORM_flag, 1); if (Scope->isAbstractScope()) { @@ -1623,15 +1627,22 @@ DIE *DwarfDebug::constructVariableDIE(DbgVariable *DV, DbgScope *Scope) { const MachineInstr *DVInsn = DVI->second; const MCSymbol *DVLabel = findVariableLabel(DV); bool updated = false; - // FIXME : Handle getNumOperands != 3 + // FIXME : Handle getNumOperands != 3 if (DVInsn->getNumOperands() == 3) { - if (DVInsn->getOperand(0).isReg()) - updated = - addRegisterAddress(VariableDie, DVLabel, DVInsn->getOperand(0)); + if (DVInsn->getOperand(0).isReg()) { + const MachineOperand RegOp = DVInsn->getOperand(0); + const TargetRegisterInfo *TRI = Asm->TM.getRegisterInfo(); + if (DVInsn->getOperand(1).isImm() && + TRI->getFrameRegister(*Asm->MF) == RegOp.getReg()) { + addVariableAddress(DV, VariableDie, DVInsn->getOperand(1).getImm()); + updated = true; + } else + updated = addRegisterAddress(VariableDie, DVLabel, RegOp); + } else if (DVInsn->getOperand(0).isImm()) updated = addConstantValue(VariableDie, DVLabel, DVInsn->getOperand(0)); - else if (DVInsn->getOperand(0).isFPImm()) - updated = + else if (DVInsn->getOperand(0).isFPImm()) + updated = addConstantFPValue(VariableDie, DVLabel, DVInsn->getOperand(0)); } else { MachineLocation Location = Asm->getDebugValueLocation(DVInsn); @@ -1651,24 +1662,13 @@ DIE *DwarfDebug::constructVariableDIE(DbgVariable *DV, DbgScope *Scope) { } DV->setDIE(VariableDie); return VariableDie; - } + } // .. else use frame index, if available. - MachineLocation Location; - unsigned FrameReg; - const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo(); int FI = 0; - if (findVariableFrameIndex(DV, &FI)) { - int Offset = RI->getFrameIndexReference(*Asm->MF, FI, FrameReg); - Location.set(FrameReg, Offset); - - if (VD.hasComplexAddress()) - addComplexAddress(DV, VariableDie, dwarf::DW_AT_location, Location); - else if (VD.isBlockByrefVariable()) - addBlockByrefAddress(DV, VariableDie, dwarf::DW_AT_location, Location); - else - addAddress(VariableDie, dwarf::DW_AT_location, Location); - } + if (findVariableFrameIndex(DV, &FI)) + addVariableAddress(DV, VariableDie, FI); + DV->setDIE(VariableDie); return VariableDie; @@ -1677,7 +1677,7 @@ DIE *DwarfDebug::constructVariableDIE(DbgVariable *DV, DbgScope *Scope) { void DwarfDebug::addPubTypes(DISubprogram SP) { DICompositeType SPTy = SP.getType(); unsigned SPTag = SPTy.getTag(); - if (SPTag != dwarf::DW_TAG_subroutine_type) + if (SPTag != dwarf::DW_TAG_subroutine_type) return; DIArray Args = SPTy.getTypeArray(); @@ -1699,7 +1699,7 @@ void DwarfDebug::addPubTypes(DISubprogram SP) { DIE *DwarfDebug::constructScopeDIE(DbgScope *Scope) { if (!Scope || !Scope->getScopeNode()) return NULL; - + DIScope DS(Scope->getScopeNode()); DIE *ScopeDIE = NULL; if (Scope->getInlinedAt()) @@ -1718,9 +1718,9 @@ DIE *DwarfDebug::constructScopeDIE(DbgScope *Scope) { else ScopeDIE = constructLexicalScopeDIE(Scope); if (!ScopeDIE) return NULL; - + // Add variables to scope. - const SmallVector &Variables = Scope->getVariables(); + const SmallVector &Variables = Scope->getDbgVariables(); for (unsigned i = 0, N = Variables.size(); i < N; ++i) { DIE *VariableDIE = constructVariableDIE(Variables[i], Scope); if (VariableDIE) @@ -1736,9 +1736,9 @@ DIE *DwarfDebug::constructScopeDIE(DbgScope *Scope) { ScopeDIE->addChild(NestedDIE); } - if (DS.isSubprogram()) + if (DS.isSubprogram()) addPubTypes(DISubprogram(DS)); - + return ScopeDIE; } @@ -1748,6 +1748,8 @@ DIE *DwarfDebug::constructScopeDIE(DbgScope *Scope) { /// maps as well. unsigned DwarfDebug::GetOrCreateSourceID(StringRef DirName, StringRef FileName){ unsigned DId; + assert (DirName.empty() == false && "Invalid directory name!"); + StringMap::iterator DI = DirectoryIdMap.find(DirName); if (DI != DirectoryIdMap.end()) { DId = DI->getValue(); @@ -1789,12 +1791,12 @@ DIE *DwarfDebug::getOrCreateNameSpace(DINameSpace NS) { TheCU->insertDIE(NS, NDie); if (!NS.getName().empty()) addString(NDie, dwarf::DW_AT_name, dwarf::DW_FORM_string, NS.getName()); - addSourceLine(NDie, &NS); + addSourceLine(NDie, NS); addToContextOwner(NDie, NS.getContext()); return NDie; } -/// constructCompileUnit - Create new CompileUnit for the given +/// constructCompileUnit - Create new CompileUnit for the given /// metadata node with tag DW_TAG_compile_unit. void DwarfDebug::constructCompileUnit(const MDNode *N) { DICompileUnit DIUnit(N); @@ -1812,9 +1814,12 @@ void DwarfDebug::constructCompileUnit(const MDNode *N) { // simplifies debug range entries. addUInt(Die, dwarf::DW_AT_entry_pc, dwarf::DW_FORM_addr, 0); // DW_AT_stmt_list is a offset of line number information for this - // compile unit in debug_line section. This offset is calculated - // during endMoudle(). - addLabel(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_data4, 0); + // compile unit in debug_line section. + if (Asm->MAI->doesDwarfUsesAbsoluteLabelForStmtList()) + addLabel(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_addr, + Asm->GetTempSymbol("section_line")); + else + addUInt(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_data4, 0); if (!Dir.empty()) addString(Die, dwarf::DW_AT_comp_dir, dwarf::DW_FORM_string, Dir); @@ -1865,64 +1870,98 @@ CompileUnit *DwarfDebug::getCompileUnit(const MDNode *N) const { return I->second; } +/// isUnsignedDIType - Return true if type encoding is unsigned. +static bool isUnsignedDIType(DIType Ty) { + DIDerivedType DTy(Ty); + if (DTy.Verify()) + return isUnsignedDIType(DTy.getTypeDerivedFrom()); + + DIBasicType BTy(Ty); + if (BTy.Verify()) { + unsigned Encoding = BTy.getEncoding(); + if (Encoding == dwarf::DW_ATE_unsigned || + Encoding == dwarf::DW_ATE_unsigned_char) + return true; + } + return false; +} /// constructGlobalVariableDIE - Construct global variable DIE. void DwarfDebug::constructGlobalVariableDIE(const MDNode *N) { - DIGlobalVariable DI_GV(N); + DIGlobalVariable GV(N); // If debug information is malformed then ignore it. - if (DI_GV.Verify() == false) + if (GV.Verify() == false) return; // Check for pre-existence. CompileUnit *TheCU = getCompileUnit(N); - if (TheCU->getDIE(DI_GV)) + if (TheCU->getDIE(GV)) return; - DIE *VariableDie = createGlobalVariableDIE(DI_GV); - if (!VariableDie) - return; - - // Add to map. - TheCU->insertDIE(N, VariableDie); + DIType GTy = GV.getType(); + DIE *VariableDIE = new DIE(GV.getTag()); - // Add to context owner. - DIDescriptor GVContext = DI_GV.getContext(); - // Do not create specification DIE if context is either compile unit - // or a subprogram. - if (DI_GV.isDefinition() && !GVContext.isCompileUnit() && - !GVContext.isFile() && - !isSubprogramContext(GVContext)) { - // Create specification DIE. - DIE *VariableSpecDIE = new DIE(dwarf::DW_TAG_variable); - addDIEEntry(VariableSpecDIE, dwarf::DW_AT_specification, - dwarf::DW_FORM_ref4, VariableDie); - DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); - addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_addr); - addLabel(Block, 0, dwarf::DW_FORM_udata, - Asm->Mang->getSymbol(DI_GV.getGlobal())); - addBlock(VariableSpecDIE, dwarf::DW_AT_location, 0, Block); - addUInt(VariableDie, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag, 1); - TheCU->addDie(VariableSpecDIE); - } else { - DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); - addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_addr); - addLabel(Block, 0, dwarf::DW_FORM_udata, - Asm->Mang->getSymbol(DI_GV.getGlobal())); - addBlock(VariableDie, dwarf::DW_AT_location, 0, Block); - } - addToContextOwner(VariableDie, GVContext); - - // Expose as global. FIXME - need to check external flag. - TheCU->addGlobal(DI_GV.getName(), VariableDie); + bool isGlobalVariable = GV.getGlobal() != NULL; - DIType GTy = DI_GV.getType(); + // Add name. + addString(VariableDIE, dwarf::DW_AT_name, dwarf::DW_FORM_string, + GV.getDisplayName()); + StringRef LinkageName = GV.getLinkageName(); + if (!LinkageName.empty() && isGlobalVariable) + addString(VariableDIE, dwarf::DW_AT_MIPS_linkage_name, dwarf::DW_FORM_string, + getRealLinkageName(LinkageName)); + // Add type. + addType(VariableDIE, GTy); if (GTy.isCompositeType() && !GTy.getName().empty() && !GTy.isForwardDecl()) { DIEEntry *Entry = TheCU->getDIEEntry(GTy); assert(Entry && "Missing global type!"); TheCU->addGlobalType(GTy.getName(), Entry->getEntry()); } + // Add scoping info. + if (!GV.isLocalToUnit()) { + addUInt(VariableDIE, dwarf::DW_AT_external, dwarf::DW_FORM_flag, 1); + // Expose as global. + TheCU->addGlobal(GV.getName(), VariableDIE); + } + // Add line number info. + addSourceLine(VariableDIE, GV); + // Add to map. + TheCU->insertDIE(N, VariableDIE); + // Add to context owner. + DIDescriptor GVContext = GV.getContext(); + addToContextOwner(VariableDIE, GVContext); + // Add location. + if (isGlobalVariable) { + DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); + addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_addr); + addLabel(Block, 0, dwarf::DW_FORM_udata, + Asm->Mang->getSymbol(GV.getGlobal())); + // Do not create specification DIE if context is either compile unit + // or a subprogram. + if (GV.isDefinition() && !GVContext.isCompileUnit() && + !GVContext.isFile() && !isSubprogramContext(GVContext)) { + // Create specification DIE. + DIE *VariableSpecDIE = new DIE(dwarf::DW_TAG_variable); + addDIEEntry(VariableSpecDIE, dwarf::DW_AT_specification, + dwarf::DW_FORM_ref4, VariableDIE); + addBlock(VariableSpecDIE, dwarf::DW_AT_location, 0, Block); + addUInt(VariableDIE, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag, 1); + TheCU->addDie(VariableSpecDIE); + } else { + addBlock(VariableDIE, dwarf::DW_AT_location, 0, Block); + } + } else if (Constant *C = GV.getConstant()) { + if (ConstantInt *CI = dyn_cast(C)) { + if (isUnsignedDIType(GTy)) + addUInt(VariableDIE, dwarf::DW_AT_const_value, dwarf::DW_FORM_udata, + CI->getZExtValue()); + else + addSInt(VariableDIE, dwarf::DW_AT_const_value, dwarf::DW_FORM_sdata, + CI->getSExtValue()); + } + } return; } @@ -1965,7 +2004,7 @@ void DwarfDebug::beginModule(Module *M) { DbgFinder.processModule(*M); bool HasDebugInfo = false; - + // Scan all the compile-units to see if there are any marked as the main unit. // if not, we do not generate debug info. for (DebugInfoFinder::iterator I = DbgFinder.compile_unit_begin(), @@ -1975,15 +2014,15 @@ void DwarfDebug::beginModule(Module *M) { break; } } - + if (!HasDebugInfo) return; // Tell MMI that we have debug info. MMI->setDebugInfoAvailability(true); - + // Emit initial sections. EmitSectionLabels(); - + // Create all the compile unit DIEs. for (DebugInfoFinder::iterator I = DbgFinder.compile_unit_begin(), E = DbgFinder.compile_unit_end(); I != E; ++I) @@ -1999,6 +2038,11 @@ void DwarfDebug::beginModule(Module *M) { E = DbgFinder.global_variable_end(); I != E; ++I) constructGlobalVariableDIE(*I); + //getOrCreateTypeDIE + if (NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.enum")) + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) + getOrCreateTypeDIE(DIType(NMD->getOperand(i))); + // Prime section data. SectionMap.insert(Asm->getObjFileLowering().getTextSection()); @@ -2025,6 +2069,7 @@ void DwarfDebug::beginModule(Module *M) { void DwarfDebug::endModule() { if (!FirstCU) return; const Module *M = MMI->getModule(); + DenseMap DeadFnScopeMap; if (NamedMDNode *AllSPs = M->getNamedMetadata("llvm.dbg.sp")) { for (unsigned SI = 0, SE = AllSPs->getNumOperands(); SI != SE; ++SI) { if (ProcessedSPNodes.count(AllSPs->getOperand(SI)) != 0) continue; @@ -2032,25 +2077,27 @@ void DwarfDebug::endModule() { if (!SP.Verify()) continue; // Collect info for variables that were optimized out. + if (!SP.isDefinition()) continue; StringRef FName = SP.getLinkageName(); if (FName.empty()) FName = SP.getName(); - NamedMDNode *NMD = + NamedMDNode *NMD = M->getNamedMetadata(Twine("llvm.dbg.lv.", getRealLinkageName(FName))); if (!NMD) continue; unsigned E = NMD->getNumOperands(); if (!E) continue; DbgScope *Scope = new DbgScope(NULL, DIDescriptor(SP), NULL); + DeadFnScopeMap[SP] = Scope; for (unsigned I = 0; I != E; ++I) { DIVariable DV(NMD->getOperand(I)); if (!DV.Verify()) continue; Scope->addVariable(new DbgVariable(DV)); } - + // Construct subprogram DIE and add variables DIEs. constructSubprogramDIE(SP); DIE *ScopeDIE = getCompileUnit(SP)->getDIE(SP); - const SmallVector &Variables = Scope->getVariables(); + const SmallVector &Variables = Scope->getDbgVariables(); for (unsigned i = 0, N = Variables.size(); i < N; ++i) { DIE *VariableDIE = constructVariableDIE(Variables[i], Scope); if (VariableDIE) @@ -2099,15 +2146,15 @@ void DwarfDebug::endModule() { // Compute DIE offsets and sizes. computeSizeAndOffsets(); - // Emit source line correspondence into a debug line section. - emitDebugLines(); - // Emit all the DIEs into a debug info section emitDebugInfo(); // Corresponding abbreviations into a abbrev section. emitAbbreviations(); + // Emit source line correspondence into a debug line section. + emitDebugLines(); + // Emit info into a debug pubnames section. emitDebugPubNames(); @@ -2131,7 +2178,9 @@ void DwarfDebug::endModule() { // Emit info into a debug str section. emitDebugStr(); - + + // clean up. + DeleteContainerSeconds(DeadFnScopeMap); for (DenseMap::iterator I = CUMap.begin(), E = CUMap.end(); I != E; ++I) delete I->second; @@ -2139,7 +2188,7 @@ void DwarfDebug::endModule() { } /// findAbstractVariable - Find abstract variable, if any, associated with Var. -DbgVariable *DwarfDebug::findAbstractVariable(DIVariable &Var, +DbgVariable *DwarfDebug::findAbstractVariable(DIVariable &Var, DebugLoc ScopeLoc) { DbgVariable *AbsDbgVariable = AbstractVariables.lookup(Var); @@ -2159,7 +2208,7 @@ DbgVariable *DwarfDebug::findAbstractVariable(DIVariable &Var, /// collectVariableInfoFromMMITable - Collect variable information from /// side table maintained by MMI. -void +void DwarfDebug::collectVariableInfoFromMMITable(const MachineFunction * MF, SmallPtrSet &Processed) { const LLVMContext &Ctx = Asm->MF->getFunction()->getContext(); @@ -2177,7 +2226,7 @@ DwarfDebug::collectVariableInfoFromMMITable(const MachineFunction * MF, Scope = ConcreteScopes.lookup(IA); if (Scope == 0) Scope = DbgScopeMap.lookup(VP.second.getScope(Ctx)); - + // If variable scope is not found then skip this variable. if (Scope == 0) continue; @@ -2193,7 +2242,7 @@ DwarfDebug::collectVariableInfoFromMMITable(const MachineFunction * MF, } } -/// isDbgValueInUndefinedReg - Return true if debug value, encoded by +/// isDbgValueInUndefinedReg - Return true if debug value, encoded by /// DBG_VALUE instruction, is in undefined reg. static bool isDbgValueInUndefinedReg(const MachineInstr *MI) { assert (MI->isDebugValue() && "Invalid DBG_VALUE machine instruction!"); @@ -2202,7 +2251,7 @@ static bool isDbgValueInUndefinedReg(const MachineInstr *MI) { return false; } -/// isDbgValueInDefinedReg - Return true if debug value, encoded by +/// isDbgValueInDefinedReg - Return true if debug value, encoded by /// DBG_VALUE instruction, is in a defined reg. static bool isDbgValueInDefinedReg(const MachineInstr *MI) { assert (MI->isDebugValue() && "Invalid DBG_VALUE machine instruction!"); @@ -2212,10 +2261,10 @@ static bool isDbgValueInDefinedReg(const MachineInstr *MI) { } /// collectVariableInfo - Populate DbgScope entries with variables' info. -void +void DwarfDebug::collectVariableInfo(const MachineFunction *MF, SmallPtrSet &Processed) { - + /// collection info from MMI table. collectVariableInfoFromMMITable(MF, Processed); @@ -2244,11 +2293,11 @@ DwarfDebug::collectVariableInfo(const MachineFunction *MF, continue; const MachineInstr *PrevMI = MInsn; - for (SmallVector::iterator MI = I+1, + for (SmallVector::iterator MI = I+1, ME = DbgValues.end(); MI != ME; ++MI) { - const MDNode *Var = + const MDNode *Var = (*MI)->getOperand((*MI)->getNumOperands()-1).getMetadata(); - if (Var == DV && isDbgValueInDefinedReg(*MI) && + if (Var == DV && isDbgValueInDefinedReg(*MI) && !PrevMI->isIdenticalTo(*MI)) MultipleValues.push_back(*MI); PrevMI = *MI; @@ -2269,7 +2318,7 @@ DwarfDebug::collectVariableInfo(const MachineFunction *MF, DbgVariable *RegVar = new DbgVariable(DV); Scope->addVariable(RegVar); if (!CurFnArg) - DbgVariableLabelsMap[RegVar] = getLabelBeforeInsn(MInsn); + DbgVariableLabelsMap[RegVar] = getLabelBeforeInsn(MInsn); if (DbgVariable *AbsVar = findAbstractVariable(DV, MInsn->getDebugLoc())) { DbgVariableToDbgInstMap[AbsVar] = MInsn; VarToAbstractVarMap[RegVar] = AbsVar; @@ -2286,26 +2335,39 @@ DwarfDebug::collectVariableInfo(const MachineFunction *MF, RegVar->setDotDebugLocOffset(DotDebugLocEntries.size()); const MachineInstr *Begin = NULL; const MachineInstr *End = NULL; - for (SmallVector::iterator - MVI = MultipleValues.begin(), MVE = MultipleValues.end(); + for (SmallVector::iterator + MVI = MultipleValues.begin(), MVE = MultipleValues.end(); MVI != MVE; ++MVI) { if (!Begin) { Begin = *MVI; continue; - } + } End = *MVI; MachineLocation MLoc; - MLoc.set(Begin->getOperand(0).getReg(), 0); + if (Begin->getNumOperands() == 3) { + if (Begin->getOperand(0).isReg() && Begin->getOperand(1).isImm()) + MLoc.set(Begin->getOperand(0).getReg(), Begin->getOperand(1).getImm()); + } else + MLoc = Asm->getDebugValueLocation(Begin); + const MCSymbol *FLabel = getLabelBeforeInsn(Begin); const MCSymbol *SLabel = getLabelBeforeInsn(End); - DotDebugLocEntries.push_back(DotDebugLocEntry(FLabel, SLabel, MLoc)); + if (MLoc.getReg()) + DotDebugLocEntries.push_back(DotDebugLocEntry(FLabel, SLabel, MLoc)); + Begin = End; if (MVI + 1 == MVE) { // If End is the last instruction then its value is valid // until the end of the funtion. - MLoc.set(End->getOperand(0).getReg(), 0); - DotDebugLocEntries. - push_back(DotDebugLocEntry(SLabel, FunctionEndSym, MLoc)); + MachineLocation EMLoc; + if (End->getNumOperands() == 3) { + if (End->getOperand(0).isReg() && Begin->getOperand(1).isImm()) + EMLoc.set(Begin->getOperand(0).getReg(), Begin->getOperand(1).getImm()); + } else + EMLoc = Asm->getDebugValueLocation(End); + if (EMLoc.getReg()) + DotDebugLocEntries. + push_back(DotDebugLocEntry(SLabel, FunctionEndSym, EMLoc)); } } DotDebugLocEntries.push_back(DotDebugLocEntry()); @@ -2314,11 +2376,11 @@ DwarfDebug::collectVariableInfo(const MachineFunction *MF, // Collect info for variables that were optimized out. const Function *F = MF->getFunction(); const Module *M = F->getParent(); - if (NamedMDNode *NMD = - M->getNamedMetadata(Twine("llvm.dbg.lv.", + if (NamedMDNode *NMD = + M->getNamedMetadata(Twine("llvm.dbg.lv.", getRealLinkageName(F->getName())))) { for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { - DIVariable DV(cast_or_null(NMD->getOperand(i))); + DIVariable DV(cast(NMD->getOperand(i))); if (!DV || !Processed.insert(DV)) continue; DbgScope *Scope = DbgScopeMap.lookup(DV.getContext()); @@ -2364,7 +2426,7 @@ void DwarfDebug::beginScope(const MachineInstr *MI) { return; } - // If location is unknown then use temp label for this DBG_VALUE + // If location is unknown then use temp label for this DBG_VALUE // instruction. if (MI->isDebugValue()) { PrevLabel = MMI->getContext().CreateTempSymbol(); @@ -2393,7 +2455,7 @@ void DwarfDebug::endScope(const MachineInstr *MI) { } /// getOrCreateDbgScope - Create DbgScope for the scope. -DbgScope *DwarfDebug::getOrCreateDbgScope(const MDNode *Scope, +DbgScope *DwarfDebug::getOrCreateDbgScope(const MDNode *Scope, const MDNode *InlinedAt) { if (!InlinedAt) { DbgScope *WScope = DbgScopeMap.lookup(Scope); @@ -2402,7 +2464,7 @@ DbgScope *DwarfDebug::getOrCreateDbgScope(const MDNode *Scope, WScope = new DbgScope(NULL, DIDescriptor(Scope), NULL); DbgScopeMap.insert(std::make_pair(Scope, WScope)); if (DIDescriptor(Scope).isLexicalBlock()) { - DbgScope *Parent = + DbgScope *Parent = getOrCreateDbgScope(DILexicalBlock(Scope).getContext(), NULL); WScope->setParent(Parent); Parent->addScope(WScope); @@ -2419,7 +2481,7 @@ DbgScope *DwarfDebug::getOrCreateDbgScope(const MDNode *Scope, DISubprogram(Scope).getFunction() == Asm->MF->getFunction()) CurrentFnDbgScope = WScope; } - + return WScope; } @@ -2448,14 +2510,14 @@ static bool hasValidLocation(LLVMContext &Ctx, const MDNode *&Scope, const MDNode *&InlinedAt) { DebugLoc DL = MInsn->getDebugLoc(); if (DL.isUnknown()) return false; - + const MDNode *S = DL.getScope(Ctx); - + // There is no need to create another DIE for compile unit. For all // other scopes, create one DbgScope now. This will be translated // into a scope DIE at the end. if (DIScope(S).isCompileUnit()) return false; - + Scope = S; InlinedAt = DL.getInlinedAt(Ctx); return true; @@ -2490,7 +2552,7 @@ static void calculateDominanceGraph(DbgScope *Scope) { } /// printDbgScopeInfo - Print DbgScope info for each machine instruction. -static +static void printDbgScopeInfo(LLVMContext &Ctx, const MachineFunction *MF, DenseMap &MI2ScopeMap) { @@ -2507,9 +2569,9 @@ void printDbgScopeInfo(LLVMContext &Ctx, const MachineFunction *MF, // Check if instruction has valid location information. if (hasValidLocation(Ctx, MInsn, Scope, InlinedAt)) { dbgs() << " [ "; - if (InlinedAt) + if (InlinedAt) dbgs() << "*"; - DenseMap::iterator DI = + DenseMap::iterator DI = MI2ScopeMap.find(MInsn); if (DI != MI2ScopeMap.end()) { DbgScope *S = DI->second; @@ -2517,7 +2579,7 @@ void printDbgScopeInfo(LLVMContext &Ctx, const MachineFunction *MF, PrevDFSIn = S->getDFSIn(); } else dbgs() << PrevDFSIn; - } else + } else dbgs() << " [ x" << PrevDFSIn; dbgs() << " ]"; MInsn->dump(); @@ -2555,26 +2617,26 @@ bool DwarfDebug::extractScopeInformation() { PrevMI = MInsn; continue; } - + // If scope has not changed then skip this instruction. if (Scope == PrevScope && PrevInlinedAt == InlinedAt) { PrevMI = MInsn; continue; } - if (RangeBeginMI) { - // If we have alread seen a beginning of a instruction range and + if (RangeBeginMI) { + // If we have alread seen a beginning of a instruction range and // current instruction scope does not match scope of first instruction // in this range then create a new instruction range. DbgRange R(RangeBeginMI, PrevMI); - MI2ScopeMap[RangeBeginMI] = getOrCreateDbgScope(PrevScope, + MI2ScopeMap[RangeBeginMI] = getOrCreateDbgScope(PrevScope, PrevInlinedAt); MIRanges.push_back(R); - } + } // This is a beginning of a new instruction range. RangeBeginMI = MInsn; - + // Reset previous markers. PrevMI = MInsn; PrevScope = Scope; @@ -2588,7 +2650,7 @@ bool DwarfDebug::extractScopeInformation() { MIRanges.push_back(R); MI2ScopeMap[RangeBeginMI] = getOrCreateDbgScope(PrevScope, PrevInlinedAt); } - + if (!CurrentFnDbgScope) return false; @@ -2618,7 +2680,7 @@ bool DwarfDebug::extractScopeInformation() { return !DbgScopeMap.empty(); } -/// identifyScopeMarkers() - +/// identifyScopeMarkers() - /// Each DbgScope has first instruction and last instruction to mark beginning /// and end of a scope respectively. Create an inverse map that list scopes /// starts (and ends) with an instruction. One instruction may start (or end) @@ -2628,23 +2690,23 @@ void DwarfDebug::identifyScopeMarkers() { WorkList.push_back(CurrentFnDbgScope); while (!WorkList.empty()) { DbgScope *S = WorkList.pop_back_val(); - + const SmallVector &Children = S->getScopes(); - if (!Children.empty()) + if (!Children.empty()) for (SmallVector::const_iterator SI = Children.begin(), SE = Children.end(); SI != SE; ++SI) WorkList.push_back(*SI); if (S->isAbstractScope()) continue; - + const SmallVector &Ranges = S->getRanges(); if (Ranges.empty()) continue; for (SmallVector::const_iterator RI = Ranges.begin(), RE = Ranges.end(); RI != RE; ++RI) { - assert(RI->first && "DbgRange does not have first instruction!"); - assert(RI->second && "DbgRange does not have second instruction!"); + assert(RI->first && "DbgRange does not have first instruction!"); + assert(RI->second && "DbgRange does not have second instruction!"); InsnsEndScopeSet.insert(RI->second); } } @@ -2680,20 +2742,23 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) { // function. DebugLoc FDL = FindFirstDebugLoc(MF); if (FDL.isUnknown()) return; - + const MDNode *Scope = FDL.getScope(MF->getFunction()->getContext()); - + const MDNode *TheScope = 0; + DISubprogram SP = getDISubprogram(Scope); unsigned Line, Col; if (SP.Verify()) { Line = SP.getLineNumber(); Col = 0; + TheScope = SP; } else { Line = FDL.getLine(); Col = FDL.getCol(); + TheScope = Scope; } - - recordSourceLine(Line, Col, Scope); + + recordSourceLine(Line, Col, TheScope); /// ProcessedArgs - Collection of arguments already processed. SmallPtrSet ProcessedArgs; @@ -2710,7 +2775,7 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) { DIVariable DV(MI->getOperand(MI->getNumOperands() - 1).getMetadata()); if (!DV.Verify()) continue; // If DBG_VALUE is for a local variable then it needs a label. - if (DV.getTag() != dwarf::DW_TAG_arg_variable + if (DV.getTag() != dwarf::DW_TAG_arg_variable && isDbgValueInUndefinedReg(MI) == false) InsnNeedsLabel.insert(MI); // DBG_VALUE for inlined functions argument needs a label. @@ -2718,10 +2783,11 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) { describes(MF->getFunction())) InsnNeedsLabel.insert(MI); // DBG_VALUE indicating argument location change needs a label. - else if (isDbgValueInUndefinedReg(MI) == false && !ProcessedArgs.insert(DV)) + else if (isDbgValueInUndefinedReg(MI) == false + && !ProcessedArgs.insert(DV)) InsnNeedsLabel.insert(MI); } else { - // If location is unknown then instruction needs a location only if + // If location is unknown then instruction needs a location only if // UnknownLocations flag is set. if (DL.isUnknown()) { if (UnknownLocations && !PrevLoc.isUnknown()) @@ -2730,7 +2796,7 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) { // Otherwise, instruction needs a location only if it is new location. InsnNeedsLabel.insert(MI); } - + if (!DL.isUnknown() || UnknownLocations) PrevLoc = DL; } @@ -2750,7 +2816,7 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { Asm->getFunctionNumber()); // Assumes in correct section after the entry point. Asm->OutStreamer.EmitLabel(FunctionEndSym); - + SmallPtrSet ProcessedVars; collectVariableInfo(MF, ProcessedVars); @@ -2764,7 +2830,7 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { SectionLineInfos.insert(SectionLineInfos.end(), Lines.begin(), Lines.end()); } - + // Construct abstract scopes. for (SmallVector::iterator AI = AbstractScopesList.begin(), AE = AbstractScopesList.end(); AI != AE; ++AI) { @@ -2775,11 +2841,11 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { if (FName.empty()) FName = SP.getName(); const Module *M = MF->getFunction()->getParent(); - if (NamedMDNode *NMD = - M->getNamedMetadata(Twine("llvm.dbg.lv.", + if (NamedMDNode *NMD = + M->getNamedMetadata(Twine("llvm.dbg.lv.", getRealLinkageName(FName)))) { for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { - DIVariable DV(cast_or_null(NMD->getOperand(i))); + DIVariable DV(cast(NMD->getOperand(i))); if (!DV || !ProcessedVars.insert(DV)) continue; DbgScope *Scope = AbstractScopes.lookup(DV.getContext()); @@ -2793,9 +2859,9 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { } DIE *CurFnDIE = constructScopeDIE(CurrentFnDbgScope); - + if (!DisableFramePointerElim(*MF)) - addUInt(CurFnDIE, dwarf::DW_AT_APPLE_omit_frame_ptr, + addUInt(CurFnDIE, dwarf::DW_AT_APPLE_omit_frame_ptr, dwarf::DW_FORM_flag, 1); @@ -2849,22 +2915,22 @@ const MCSymbol *DwarfDebug::findVariableLabel(const DbgVariable *V) { else return I->second; } -/// findDbgScope - Find DbgScope for the debug loc attached with an +/// findDbgScope - Find DbgScope for the debug loc attached with an /// instruction. DbgScope *DwarfDebug::findDbgScope(const MachineInstr *MInsn) { DbgScope *Scope = NULL; - LLVMContext &Ctx = + LLVMContext &Ctx = MInsn->getParent()->getParent()->getFunction()->getContext(); DebugLoc DL = MInsn->getDebugLoc(); - if (DL.isUnknown()) + if (DL.isUnknown()) return Scope; if (const MDNode *IA = DL.getInlinedAt(Ctx)) Scope = ConcreteScopes.lookup(IA); if (Scope == 0) Scope = DbgScopeMap.lookup(DL.getScope(Ctx)); - + return Scope; } @@ -2872,7 +2938,7 @@ DbgScope *DwarfDebug::findDbgScope(const MachineInstr *MInsn) { /// recordSourceLine - Register a source line with debug info. Returns the /// unique label that was emitted and which provides correspondence to /// the source line list. -MCSymbol *DwarfDebug::recordSourceLine(unsigned Line, unsigned Col, +MCSymbol *DwarfDebug::recordSourceLine(unsigned Line, unsigned Col, const MDNode *S) { StringRef Dir; StringRef Fn; @@ -2899,16 +2965,6 @@ MCSymbol *DwarfDebug::recordSourceLine(unsigned Line, unsigned Col, Src = GetOrCreateSourceID(Dir, Fn); } -#if 0 - if (!Lines.empty()) { - SrcLineInfo lastSrcLineInfo = Lines.back(); - // Emitting sequential line records with the same line number (but - // different addresses) seems to confuse GDB. Avoid this. - if (lastSrcLineInfo.getLine() == Line) - return NULL; - } -#endif - MCSymbol *Label = MMI->getContext().CreateTempSymbol(); Lines.push_back(SrcLineInfo(Line, Col, Src, Label)); @@ -2991,7 +3047,7 @@ static MCSymbol *EmitSectionSym(AsmPrinter *Asm, const MCSection *Section, const char *SymbolStem = 0) { Asm->OutStreamer.SwitchSection(Section); if (!SymbolStem) return 0; - + MCSymbol *TmpSym = Asm->GetTempSymbol(SymbolStem); Asm->OutStreamer.EmitLabel(TmpSym); return TmpSym; @@ -3008,21 +3064,20 @@ void DwarfDebug::EmitSectionLabels() { EmitSectionSym(Asm, TLOF.getDwarfFrameSection(), "section_debug_frame"); } - DwarfInfoSectionSym = + DwarfInfoSectionSym = EmitSectionSym(Asm, TLOF.getDwarfInfoSection(), "section_info"); - DwarfAbbrevSectionSym = + DwarfAbbrevSectionSym = EmitSectionSym(Asm, TLOF.getDwarfAbbrevSection(), "section_abbrev"); EmitSectionSym(Asm, TLOF.getDwarfARangesSection()); - + if (const MCSection *MacroInfo = TLOF.getDwarfMacroInfoSection()) EmitSectionSym(Asm, MacroInfo); - DwarfDebugLineSectionSym = - EmitSectionSym(Asm, TLOF.getDwarfLineSection(), "section_line"); + EmitSectionSym(Asm, TLOF.getDwarfLineSection(), "section_line"); EmitSectionSym(Asm, TLOF.getDwarfLocSection()); EmitSectionSym(Asm, TLOF.getDwarfPubNamesSection()); EmitSectionSym(Asm, TLOF.getDwarfPubTypesSection()); - DwarfStrSectionSym = + DwarfStrSectionSym = EmitSectionSym(Asm, TLOF.getDwarfStrSection(), "section_str"); DwarfDebugRangeSectionSym = EmitSectionSym(Asm, TLOF.getDwarfRangesSection(), "debug_range"); @@ -3060,7 +3115,7 @@ void DwarfDebug::emitDIE(DIE *Die) { if (Asm->isVerbose()) Asm->OutStreamer.AddComment(dwarf::AttributeString(Attr)); - + switch (Attr) { case dwarf::DW_AT_sibling: Asm->EmitInt32(Die->getSiblingOffset()); @@ -3075,15 +3130,17 @@ void DwarfDebug::emitDIE(DIE *Die) { case dwarf::DW_AT_ranges: { // DW_AT_range Value encodes offset in debug_range section. DIEInteger *V = cast(Values[i]); - Asm->EmitLabelOffsetDifference(DwarfDebugRangeSectionSym, - V->getValue(), - DwarfDebugRangeSectionSym, - 4); - break; - } - case dwarf::DW_AT_stmt_list: { - Asm->EmitLabelDifference(CurrentLineSectionSym, - DwarfDebugLineSectionSym, 4); + + if (Asm->MAI->doesDwarfUsesLabelOffsetForRanges()) { + Asm->EmitLabelPlusOffset(DwarfDebugRangeSectionSym, + V->getValue(), + 4); + } else { + Asm->EmitLabelOffsetDifference(DwarfDebugRangeSectionSym, + V->getValue(), + DwarfDebugRangeSectionSym, + 4); + } break; } case dwarf::DW_AT_location: { @@ -3124,18 +3181,18 @@ void DwarfDebug::emitDebugInfo() { E = CUMap.end(); I != E; ++I) { CompileUnit *TheCU = I->second; DIE *Die = TheCU->getCUDie(); - + // Emit the compile units header. Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("info_begin", TheCU->getID())); - + // Emit size of content not including length itself unsigned ContentSize = Die->getSize() + sizeof(int16_t) + // DWARF version number sizeof(int32_t) + // Offset Into Abbrev. Section sizeof(int8_t) + // Pointer Size (in bytes) sizeof(int32_t); // FIXME - extra pad for gdb bug. - + Asm->OutStreamer.AddComment("Length of Compilation Unit Info"); Asm->EmitInt32(ContentSize); Asm->OutStreamer.AddComment("DWARF version number"); @@ -3145,7 +3202,7 @@ void DwarfDebug::emitDebugInfo() { DwarfAbbrevSectionSym); Asm->OutStreamer.AddComment("Address Size (in bytes)"); Asm->EmitInt8(Asm->getTargetData().getPointerSize()); - + emitDIE(Die); // FIXME - extra padding for gdb bug. Asm->OutStreamer.AddComment("4 extra padding bytes for GDB"); @@ -3194,7 +3251,7 @@ void DwarfDebug::emitEndOfLineMatrix(unsigned SectionEnd) { // Define last address of section. Asm->OutStreamer.AddComment("Extended Op"); Asm->EmitInt8(0); - + Asm->OutStreamer.AddComment("Op size"); Asm->EmitInt8(Asm->getTargetData().getPointerSize() + 1); Asm->OutStreamer.AddComment("DW_LNE_set_address"); @@ -3231,15 +3288,13 @@ void DwarfDebug::emitDebugLines() { Asm->getObjFileLowering().getDwarfLineSection()); // Construct the section header. - CurrentLineSectionSym = Asm->GetTempSymbol("section_line_begin"); - Asm->OutStreamer.EmitLabel(CurrentLineSectionSym); Asm->OutStreamer.AddComment("Length of Source Line Info"); Asm->EmitLabelDifference(Asm->GetTempSymbol("line_end"), Asm->GetTempSymbol("line_begin"), 4); Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("line_begin")); Asm->OutStreamer.AddComment("DWARF version number"); - Asm->EmitInt16(dwarf::DWARF_VERSION); + Asm->EmitInt16(dwarf::DWARF_VERSION); Asm->OutStreamer.AddComment("Prolog Length"); Asm->EmitLabelDifference(Asm->GetTempSymbol("line_prolog_end"), @@ -3294,7 +3349,7 @@ void DwarfDebug::emitDebugLines() { const std::string &FN = getSourceFileName(Id.second); if (Asm->isVerbose()) Asm->OutStreamer.AddComment("Source"); Asm->OutStreamer.EmitBytes(StringRef(FN.c_str(), FN.size()+1), 0); - + Asm->EmitULEB128(Id.first, "Directory #"); Asm->EmitULEB128(0, "Mod date"); Asm->EmitULEB128(0, "File size"); @@ -3338,18 +3393,18 @@ void DwarfDebug::emitDebugLines() { Asm->EmitInt8(Asm->getTargetData().getPointerSize() + 1); Asm->OutStreamer.AddComment("DW_LNE_set_address"); - Asm->EmitInt8(dwarf::DW_LNE_set_address); + Asm->EmitInt8(dwarf::DW_LNE_set_address); Asm->OutStreamer.AddComment("Location label"); Asm->OutStreamer.EmitSymbolValue(Label, Asm->getTargetData().getPointerSize(), 0/*AddrSpace*/); - + // If change of source, then switch to the new source. if (Source != LineInfo.getSourceID()) { Source = LineInfo.getSourceID(); Asm->OutStreamer.AddComment("DW_LNS_set_file"); - Asm->EmitInt8(dwarf::DW_LNS_set_file); + Asm->EmitInt8(dwarf::DW_LNS_set_file); Asm->EmitULEB128(Source, "New Source"); } @@ -3457,7 +3512,7 @@ emitFunctionDebugFrame(const FunctionDebugFrameInfo &DebugFrameInfo) { Asm->OutStreamer.EmitLabel(DebugFrameBegin); Asm->OutStreamer.AddComment("FDE CIE offset"); - Asm->EmitSectionOffset(Asm->GetTempSymbol("debug_frame_common"), + Asm->EmitSectionOffset(Asm->GetTempSymbol("debug_frame_common"), DwarfFrameSectionSym); Asm->OutStreamer.AddComment("FDE initial location"); @@ -3466,8 +3521,8 @@ emitFunctionDebugFrame(const FunctionDebugFrameInfo &DebugFrameInfo) { Asm->OutStreamer.EmitSymbolValue(FuncBeginSym, Asm->getTargetData().getPointerSize(), 0/*AddrSpace*/); - - + + Asm->OutStreamer.AddComment("FDE address range"); Asm->EmitLabelDifference(Asm->GetTempSymbol("func_end",DebugFrameInfo.Number), FuncBeginSym, Asm->getTargetData().getPointerSize()); @@ -3487,41 +3542,41 @@ void DwarfDebug::emitDebugPubNames() { // Start the dwarf pubnames section. Asm->OutStreamer.SwitchSection( Asm->getObjFileLowering().getDwarfPubNamesSection()); - + Asm->OutStreamer.AddComment("Length of Public Names Info"); Asm->EmitLabelDifference( Asm->GetTempSymbol("pubnames_end", TheCU->getID()), Asm->GetTempSymbol("pubnames_begin", TheCU->getID()), 4); - + Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("pubnames_begin", TheCU->getID())); - + Asm->OutStreamer.AddComment("DWARF Version"); - Asm->EmitInt16(dwarf::DWARF_VERSION); - + Asm->EmitInt16(dwarf::DWARF_VERSION); + Asm->OutStreamer.AddComment("Offset of Compilation Unit Info"); - Asm->EmitSectionOffset(Asm->GetTempSymbol("info_begin", TheCU->getID()), + Asm->EmitSectionOffset(Asm->GetTempSymbol("info_begin", TheCU->getID()), DwarfInfoSectionSym); - + Asm->OutStreamer.AddComment("Compilation Unit Length"); Asm->EmitLabelDifference(Asm->GetTempSymbol("info_end", TheCU->getID()), Asm->GetTempSymbol("info_begin", TheCU->getID()), 4); - + const StringMap &Globals = TheCU->getGlobals(); for (StringMap::const_iterator GI = Globals.begin(), GE = Globals.end(); GI != GE; ++GI) { const char *Name = GI->getKeyData(); DIE *Entity = GI->second; - + Asm->OutStreamer.AddComment("DIE offset"); Asm->EmitInt32(Entity->getOffset()); - + if (Asm->isVerbose()) Asm->OutStreamer.AddComment("External Name"); Asm->OutStreamer.EmitBytes(StringRef(Name, strlen(Name)+1), 0); } - + Asm->OutStreamer.AddComment("End Mark"); Asm->EmitInt32(0); Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("pubnames_end", @@ -3540,37 +3595,37 @@ void DwarfDebug::emitDebugPubTypes() { Asm->EmitLabelDifference( Asm->GetTempSymbol("pubtypes_end", TheCU->getID()), Asm->GetTempSymbol("pubtypes_begin", TheCU->getID()), 4); - + Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("pubtypes_begin", TheCU->getID())); - + if (Asm->isVerbose()) Asm->OutStreamer.AddComment("DWARF Version"); Asm->EmitInt16(dwarf::DWARF_VERSION); - + Asm->OutStreamer.AddComment("Offset of Compilation Unit Info"); Asm->EmitSectionOffset(Asm->GetTempSymbol("info_begin", TheCU->getID()), DwarfInfoSectionSym); - + Asm->OutStreamer.AddComment("Compilation Unit Length"); Asm->EmitLabelDifference(Asm->GetTempSymbol("info_end", TheCU->getID()), Asm->GetTempSymbol("info_begin", TheCU->getID()), 4); - + const StringMap &Globals = TheCU->getGlobalTypes(); for (StringMap::const_iterator GI = Globals.begin(), GE = Globals.end(); GI != GE; ++GI) { const char *Name = GI->getKeyData(); DIE * Entity = GI->second; - + if (Asm->isVerbose()) Asm->OutStreamer.AddComment("DIE offset"); Asm->EmitInt32(Entity->getOffset()); - + if (Asm->isVerbose()) Asm->OutStreamer.AddComment("External Name"); Asm->OutStreamer.EmitBytes(StringRef(Name, GI->getKeyLength()+1), 0); } - + Asm->OutStreamer.AddComment("End Mark"); - Asm->EmitInt32(0); + Asm->EmitInt32(0); Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("pubtypes_end", TheCU->getID())); } @@ -3581,26 +3636,26 @@ void DwarfDebug::emitDebugPubTypes() { void DwarfDebug::emitDebugStr() { // Check to see if it is worth the effort. if (StringPool.empty()) return; - + // Start the dwarf str section. Asm->OutStreamer.SwitchSection( Asm->getObjFileLowering().getDwarfStrSection()); // Get all of the string pool entries and put them in an array by their ID so // we can sort them. - SmallVector >*>, 64> Entries; - + for (StringMap >::iterator I = StringPool.begin(), E = StringPool.end(); I != E; ++I) Entries.push_back(std::make_pair(I->second.second, &*I)); - + array_pod_sort(Entries.begin(), Entries.end()); - + for (unsigned i = 0, e = Entries.size(); i != e; ++i) { // Emit a label for reference from debug information entries. Asm->OutStreamer.EmitLabel(Entries[i].second->getValue().first); - + // Emit the string itself. Asm->OutStreamer.EmitBytes(Entries[i].second->getKey(), 0/*addrspace*/); } @@ -3618,8 +3673,8 @@ void DwarfDebug::emitDebugLoc() { unsigned char Size = Asm->getTargetData().getPointerSize(); Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("debug_loc", 0)); unsigned index = 1; - for (SmallVector::iterator - I = DotDebugLocEntries.begin(), E = DotDebugLocEntries.end(); + for (SmallVector::iterator + I = DotDebugLocEntries.begin(), E = DotDebugLocEntries.end(); I != E; ++I, ++index) { DotDebugLocEntry Entry = *I; if (Entry.isEmpty()) { @@ -3631,15 +3686,30 @@ void DwarfDebug::emitDebugLoc() { Asm->OutStreamer.EmitSymbolValue(Entry.End, Size, 0); const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo(); unsigned Reg = RI->getDwarfRegNum(Entry.Loc.getReg(), false); - if (Reg < 32) { + if (int Offset = Entry.Loc.getOffset()) { + // If the value is at a certain offset from frame register then + // use DW_OP_fbreg. + unsigned OffsetSize = Offset ? MCAsmInfo::getSLEB128Size(Offset) : 1; Asm->OutStreamer.AddComment("Loc expr size"); - Asm->EmitInt16(1); - Asm->EmitInt8(dwarf::DW_OP_reg0 + Reg); + Asm->EmitInt16(1 + OffsetSize); + Asm->OutStreamer.AddComment( + dwarf::OperationEncodingString(dwarf::DW_OP_fbreg)); + Asm->EmitInt8(dwarf::DW_OP_fbreg); + Asm->OutStreamer.AddComment("Offset"); + Asm->EmitSLEB128(Offset); } else { - Asm->OutStreamer.AddComment("Loc expr size"); - Asm->EmitInt16(1+MCAsmInfo::getULEB128Size(Reg)); - Asm->EmitInt8(dwarf::DW_OP_regx); - Asm->EmitULEB128(Reg); + if (Reg < 32) { + Asm->OutStreamer.AddComment("Loc expr size"); + Asm->EmitInt16(1); + Asm->OutStreamer.AddComment( + dwarf::OperationEncodingString(dwarf::DW_OP_reg0 + Reg)); + Asm->EmitInt8(dwarf::DW_OP_reg0 + Reg); + } else { + Asm->OutStreamer.AddComment("Loc expr size"); + Asm->EmitInt16(1 + MCAsmInfo::getULEB128Size(Reg)); + Asm->EmitInt8(dwarf::DW_OP_regx); + Asm->EmitULEB128(Reg); + } } } } @@ -3661,7 +3731,7 @@ void DwarfDebug::emitDebugRanges() { Asm->getObjFileLowering().getDwarfRangesSection()); unsigned char Size = Asm->getTargetData().getPointerSize(); for (SmallVector::iterator - I = DebugRangeSymbols.begin(), E = DebugRangeSymbols.end(); + I = DebugRangeSymbols.begin(), E = DebugRangeSymbols.end(); I != E; ++I) { if (*I) Asm->OutStreamer.EmitSymbolValue(const_cast(*I), Size, 0); @@ -3734,7 +3804,7 @@ void DwarfDebug::emitDebugInlineInfo() { if (LName.empty()) { Asm->OutStreamer.EmitBytes(Name, 0); Asm->OutStreamer.EmitIntValue(0, 1, 0); // nul terminator. - } else + } else Asm->EmitSectionOffset(getStringPoolEntry(getRealLinkageName(LName)), DwarfStrSectionSym); diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index 5a281c8..f0ff3bc 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -261,7 +261,6 @@ class DwarfDebug { MCSymbol *DwarfFrameSectionSym, *DwarfInfoSectionSym, *DwarfAbbrevSectionSym; MCSymbol *DwarfStrSectionSym, *TextSectionSym, *DwarfDebugRangeSectionSym; MCSymbol *DwarfDebugLocSectionSym; - MCSymbol *DwarfDebugLineSectionSym, *CurrentLineSectionSym; MCSymbol *FunctionBeginSym, *FunctionEndSym; DIEInteger *DIEIntegerOne; @@ -338,11 +337,11 @@ private: /// addSourceLine - Add location information to specified debug information /// entry. - void addSourceLine(DIE *Die, const DIVariable *V); - void addSourceLine(DIE *Die, const DIGlobalVariable *G); - void addSourceLine(DIE *Die, const DISubprogram *SP); - void addSourceLine(DIE *Die, const DIType *Ty); - void addSourceLine(DIE *Die, const DINameSpace *NS); + void addSourceLine(DIE *Die, DIVariable V); + void addSourceLine(DIE *Die, DIGlobalVariable G); + void addSourceLine(DIE *Die, DISubprogram SP); + void addSourceLine(DIE *Die, DIType Ty); + void addSourceLine(DIE *Die, DINameSpace NS); /// addAddress - Add an address attribute to a die based on the location /// provided. @@ -376,6 +375,10 @@ private: void addBlockByrefAddress(DbgVariable *&DV, DIE *Die, unsigned Attribute, const MachineLocation &Location); + /// addVariableAddress - Add DW_AT_location attribute for a DbgVariable based + /// on provided frame index. + void addVariableAddress(DbgVariable *&DV, DIE *Die, int64_t FI); + /// addToContextOwner - Add Die into the list of its context owner's children. void addToContextOwner(DIE *Die, DIDescriptor Context); @@ -414,14 +417,11 @@ private: /// constructEnumTypeDIE - Construct enum type DIE from DIEnumerator. DIE *constructEnumTypeDIE(DIEnumerator ETy); - /// createGlobalVariableDIE - Create new DIE using GV. - DIE *createGlobalVariableDIE(const DIGlobalVariable &GV); - /// createMemberDIE - Create new member DIE. - DIE *createMemberDIE(const DIDerivedType &DT); + DIE *createMemberDIE(DIDerivedType DT); /// createSubprogramDIE - Create new DIE using SP. - DIE *createSubprogramDIE(const DISubprogram &SP, bool MakeDecl = false); + DIE *createSubprogramDIE(DISubprogram SP, bool MakeDecl = false); /// getOrCreateDbgScope - Create DbgScope for the scope. DbgScope *getOrCreateDbgScope(const MDNode *Scope, const MDNode *InlinedAt); @@ -560,12 +560,6 @@ private: /// construct SubprogramDIE - Construct subprogram DIE. void constructSubprogramDIE(const MDNode *N); - // FIXME: This should go away in favor of complex addresses. - /// Find the type the programmer originally declared the variable to be - /// and return that type. Obsolete, use GetComplexAddrType instead. - /// - DIType getBlockByrefType(DIType Ty, std::string Name); - /// recordSourceLine - Register a source line with debug info. Returns the /// unique label that was emitted and which provides correspondence to /// the source line list. diff --git a/lib/CodeGen/AsmPrinter/DwarfException.cpp b/lib/CodeGen/AsmPrinter/DwarfException.cpp index c872840..86a3688 100644 --- a/lib/CodeGen/AsmPrinter/DwarfException.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfException.cpp @@ -894,7 +894,7 @@ void DwarfException::EndModule() { if (!shouldEmitMovesModule && !shouldEmitTableModule) return; - const std::vector Personalities = MMI->getPersonalities(); + const std::vector &Personalities = MMI->getPersonalities(); for (unsigned I = 0, E = Personalities.size(); I < E; ++I) EmitCIE(Personalities[I], I); diff --git a/lib/CodeGen/BranchFolding.cpp b/lib/CodeGen/BranchFolding.cpp index 7f98df0..cb81aa3 100644 --- a/lib/CodeGen/BranchFolding.cpp +++ b/lib/CodeGen/BranchFolding.cpp @@ -65,7 +65,7 @@ namespace { public: static char ID; explicit BranchFolderPass(bool defaultEnableTailMerge) - : MachineFunctionPass(&ID), BranchFolder(defaultEnableTailMerge) {} + : MachineFunctionPass(ID), BranchFolder(defaultEnableTailMerge) {} virtual bool runOnMachineFunction(MachineFunction &MF); virtual const char *getPassName() const { return "Control Flow Optimizer"; } diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index ffeff1e..2ef115d 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -22,6 +22,7 @@ add_llvm_library(LLVMCodeGen LiveIntervalAnalysis.cpp LiveStackAnalysis.cpp LiveVariables.cpp + LocalStackSlotAllocation.cpp LowerSubregs.cpp MachineBasicBlock.cpp MachineCSE.cpp @@ -42,10 +43,10 @@ add_llvm_library(LLVMCodeGen MachineVerifier.cpp ObjectCodeEmitter.cpp OcamlGC.cpp - OptimizeExts.cpp OptimizePHIs.cpp PHIElimination.cpp Passes.cpp + PeepholeOptimizer.cpp PostRAHazardRecognizer.cpp PostRASchedulerList.cpp PreAllocSplitting.cpp @@ -57,6 +58,7 @@ add_llvm_library(LLVMCodeGen RegAllocPBQP.cpp RegisterCoalescer.cpp RegisterScavenging.cpp + RenderMachineFunction.cpp ScheduleDAG.cpp ScheduleDAGEmit.cpp ScheduleDAGInstrs.cpp @@ -67,6 +69,8 @@ add_llvm_library(LLVMCodeGen SjLjEHPrepare.cpp SlotIndexes.cpp Spiller.cpp + SplitKit.cpp + Splitter.cpp StackProtector.cpp StackSlotColoring.cpp StrongPHIElimination.cpp diff --git a/lib/CodeGen/CalcSpillWeights.cpp b/lib/CodeGen/CalcSpillWeights.cpp index 240a7b9..1b7e08a 100644 --- a/lib/CodeGen/CalcSpillWeights.cpp +++ b/lib/CodeGen/CalcSpillWeights.cpp @@ -25,8 +25,8 @@ using namespace llvm; char CalculateSpillWeights::ID = 0; -static RegisterPass X("calcspillweights", - "Calculate spill weights"); +INITIALIZE_PASS(CalculateSpillWeights, "calcspillweights", + "Calculate spill weights", false, false); void CalculateSpillWeights::getAnalysisUsage(AnalysisUsage &au) const { au.addRequired(); @@ -41,108 +41,184 @@ bool CalculateSpillWeights::runOnMachineFunction(MachineFunction &fn) { << "********** Function: " << fn.getFunction()->getName() << '\n'); - LiveIntervals *lis = &getAnalysis(); - MachineLoopInfo *loopInfo = &getAnalysis(); - const TargetInstrInfo *tii = fn.getTarget().getInstrInfo(); - MachineRegisterInfo *mri = &fn.getRegInfo(); - - SmallSet processed; - for (MachineFunction::iterator mbbi = fn.begin(), mbbe = fn.end(); - mbbi != mbbe; ++mbbi) { - MachineBasicBlock* mbb = mbbi; - SlotIndex mbbEnd = lis->getMBBEndIdx(mbb); - MachineLoop* loop = loopInfo->getLoopFor(mbb); - unsigned loopDepth = loop ? loop->getLoopDepth() : 0; - bool isExiting = loop ? loop->isLoopExiting(mbb) : false; - - for (MachineBasicBlock::const_iterator mii = mbb->begin(), mie = mbb->end(); - mii != mie; ++mii) { - const MachineInstr *mi = mii; - if (tii->isIdentityCopy(*mi) || mi->isImplicitDef() || mi->isDebugValue()) - continue; - - for (unsigned i = 0, e = mi->getNumOperands(); i != e; ++i) { - const MachineOperand &mopi = mi->getOperand(i); - if (!mopi.isReg() || mopi.getReg() == 0) - continue; - unsigned reg = mopi.getReg(); - if (!TargetRegisterInfo::isVirtualRegister(mopi.getReg())) - continue; - // Multiple uses of reg by the same instruction. It should not - // contribute to spill weight again. - if (!processed.insert(reg)) - continue; - - bool hasDef = mopi.isDef(); - bool hasUse = !hasDef; - for (unsigned j = i+1; j != e; ++j) { - const MachineOperand &mopj = mi->getOperand(j); - if (!mopj.isReg() || mopj.getReg() != reg) - continue; - hasDef |= mopj.isDef(); - hasUse |= mopj.isUse(); - if (hasDef && hasUse) - break; - } - - LiveInterval ®Int = lis->getInterval(reg); - float weight = lis->getSpillWeight(hasDef, hasUse, loopDepth); - if (hasDef && isExiting) { - // Looks like this is a loop count variable update. - SlotIndex defIdx = lis->getInstructionIndex(mi).getDefIndex(); - const LiveRange *dlr = - lis->getInterval(reg).getLiveRangeContaining(defIdx); - if (dlr->end >= mbbEnd) - weight *= 3.0F; - } - regInt.weight += weight; - } - processed.clear(); - } + LiveIntervals &lis = getAnalysis(); + VirtRegAuxInfo vrai(fn, lis, getAnalysis()); + for (LiveIntervals::iterator I = lis.begin(), E = lis.end(); I != E; ++I) { + LiveInterval &li = *I->second; + if (TargetRegisterInfo::isVirtualRegister(li.reg)) + vrai.CalculateWeightAndHint(li); + } + return false; +} + +// Return the preferred allocation register for reg, given a COPY instruction. +static unsigned copyHint(const MachineInstr *mi, unsigned reg, + const TargetRegisterInfo &tri, + const MachineRegisterInfo &mri) { + unsigned sub, hreg, hsub; + if (mi->getOperand(0).getReg() == reg) { + sub = mi->getOperand(0).getSubReg(); + hreg = mi->getOperand(1).getReg(); + hsub = mi->getOperand(1).getSubReg(); + } else { + sub = mi->getOperand(1).getSubReg(); + hreg = mi->getOperand(0).getReg(); + hsub = mi->getOperand(0).getSubReg(); } - for (LiveIntervals::iterator I = lis->begin(), E = lis->end(); I != E; ++I) { - LiveInterval &li = *I->second; - if (TargetRegisterInfo::isVirtualRegister(li.reg)) { - // If the live interval length is essentially zero, i.e. in every live - // range the use follows def immediately, it doesn't make sense to spill - // it and hope it will be easier to allocate for this li. - if (isZeroLengthInterval(&li)) { - li.weight = HUGE_VALF; - continue; - } - - bool isLoad = false; - SmallVector spillIs; - if (lis->isReMaterializable(li, spillIs, isLoad)) { - // If all of the definitions of the interval are re-materializable, - // it is a preferred candidate for spilling. If none of the defs are - // loads, then it's potentially very cheap to re-materialize. - // FIXME: this gets much more complicated once we support non-trivial - // re-materialization. - if (isLoad) - li.weight *= 0.9F; - else - li.weight *= 0.5F; - } - - // Slightly prefer live interval that has been assigned a preferred reg. - std::pair Hint = mri->getRegAllocationHint(li.reg); - if (Hint.first || Hint.second) - li.weight *= 1.01F; - - lis->normalizeSpillWeight(li); + if (!hreg) + return 0; + + if (TargetRegisterInfo::isVirtualRegister(hreg)) + return sub == hsub ? hreg : 0; + + const TargetRegisterClass *rc = mri.getRegClass(reg); + + // Only allow physreg hints in rc. + if (sub == 0) + return rc->contains(hreg) ? hreg : 0; + + // reg:sub should match the physreg hreg. + return tri.getMatchingSuperReg(hreg, sub, rc); +} + +void VirtRegAuxInfo::CalculateWeightAndHint(LiveInterval &li) { + MachineRegisterInfo &mri = mf_.getRegInfo(); + const TargetRegisterInfo &tri = *mf_.getTarget().getRegisterInfo(); + MachineBasicBlock *mbb = 0; + MachineLoop *loop = 0; + unsigned loopDepth = 0; + bool isExiting = false; + float totalWeight = 0; + SmallPtrSet visited; + + // Find the best physreg hist and the best virtreg hint. + float bestPhys = 0, bestVirt = 0; + unsigned hintPhys = 0, hintVirt = 0; + + // Don't recompute a target specific hint. + bool noHint = mri.getRegAllocationHint(li.reg).first != 0; + + for (MachineRegisterInfo::reg_iterator I = mri.reg_begin(li.reg); + MachineInstr *mi = I.skipInstruction();) { + if (mi->isIdentityCopy() || mi->isImplicitDef() || mi->isDebugValue()) + continue; + if (!visited.insert(mi)) + continue; + + // Get loop info for mi. + if (mi->getParent() != mbb) { + mbb = mi->getParent(); + loop = loops_.getLoopFor(mbb); + loopDepth = loop ? loop->getLoopDepth() : 0; + isExiting = loop ? loop->isLoopExiting(mbb) : false; + } + + // Calculate instr weight. + bool reads, writes; + tie(reads, writes) = mi->readsWritesVirtualRegister(li.reg); + float weight = LiveIntervals::getSpillWeight(writes, reads, loopDepth); + + // Give extra weight to what looks like a loop induction variable update. + if (writes && isExiting && lis_.isLiveOutOfMBB(li, mbb)) + weight *= 3; + + totalWeight += weight; + + // Get allocation hints from copies. + if (noHint || !mi->isCopy()) + continue; + unsigned hint = copyHint(mi, li.reg, tri, mri); + if (!hint) + continue; + float hweight = hint_[hint] += weight; + if (TargetRegisterInfo::isPhysicalRegister(hint)) { + if (hweight > bestPhys && lis_.isAllocatable(hint)) + bestPhys = hweight, hintPhys = hint; + } else { + if (hweight > bestVirt) + bestVirt = hweight, hintVirt = hint; } } - - return false; + + hint_.clear(); + + // Always prefer the physreg hint. + if (unsigned hint = hintPhys ? hintPhys : hintVirt) { + mri.setRegAllocationHint(li.reg, 0, hint); + // Weakly boost the spill weifght of hinted registers. + totalWeight *= 1.01F; + } + + // Mark li as unspillable if all live ranges are tiny. + if (li.isZeroLength()) { + li.markNotSpillable(); + return; + } + + // If all of the definitions of the interval are re-materializable, + // it is a preferred candidate for spilling. If none of the defs are + // loads, then it's potentially very cheap to re-materialize. + // FIXME: this gets much more complicated once we support non-trivial + // re-materialization. + bool isLoad = false; + SmallVector spillIs; + if (lis_.isReMaterializable(li, spillIs, isLoad)) { + if (isLoad) + totalWeight *= 0.9F; + else + totalWeight *= 0.5F; + } + + li.weight = totalWeight; + lis_.normalizeSpillWeight(li); } -/// Returns true if the given live interval is zero length. -bool CalculateSpillWeights::isZeroLengthInterval(LiveInterval *li) const { - for (LiveInterval::Ranges::const_iterator - i = li->ranges.begin(), e = li->ranges.end(); i != e; ++i) - if (i->end.getPrevIndex() > i->start) - return false; - return true; +void VirtRegAuxInfo::CalculateRegClass(unsigned reg) { + MachineRegisterInfo &mri = mf_.getRegInfo(); + const TargetRegisterInfo *tri = mf_.getTarget().getRegisterInfo(); + const TargetRegisterClass *orc = mri.getRegClass(reg); + SmallPtrSet rcs; + + for (MachineRegisterInfo::reg_nodbg_iterator I = mri.reg_nodbg_begin(reg), + E = mri.reg_nodbg_end(); I != E; ++I) { + // The targets don't have accurate enough regclass descriptions that we can + // handle subregs. We need something similar to + // TRI::getMatchingSuperRegClass, but returning a super class instead of a + // sub class. + if (I.getOperand().getSubReg()) { + DEBUG(dbgs() << "Cannot handle subregs: " << I.getOperand() << '\n'); + return; + } + if (const TargetRegisterClass *rc = + I->getDesc().getRegClass(I.getOperandNo(), tri)) + rcs.insert(rc); + } + + // If we found no regclass constraints, just leave reg as is. + // In theory, we could inflate to the largest superclass of reg's existing + // class, but that might not be legal for the current cpu setting. + // This could happen if reg is only used by COPY instructions, so we may need + // to improve on this. + if (rcs.empty()) { + return; + } + + // Compute the intersection of all classes in rcs. + // This ought to be independent of iteration order, but if the target register + // classes don't form a proper algebra, it is possible to get different + // results. The solution is to make sure the intersection of any two register + // classes is also a register class or the null set. + const TargetRegisterClass *rc = 0; + for (SmallPtrSet::iterator I = rcs.begin(), + E = rcs.end(); I != E; ++I) { + rc = rc ? getCommonSubClass(rc, *I) : *I; + assert(rc && "Incompatible regclass constraints found"); + } + + if (rc == orc) + return; + DEBUG(dbgs() << "Inflating " << orc->getName() << ":%reg" << reg << " to " + << rc->getName() <<".\n"); + mri.setRegClass(reg, rc); } diff --git a/lib/CodeGen/CodePlacementOpt.cpp b/lib/CodeGen/CodePlacementOpt.cpp index e0e315c..91a9536 100644 --- a/lib/CodeGen/CodePlacementOpt.cpp +++ b/lib/CodeGen/CodePlacementOpt.cpp @@ -36,7 +36,7 @@ namespace { public: static char ID; - CodePlacementOpt() : MachineFunctionPass(&ID) {} + CodePlacementOpt() : MachineFunctionPass(ID) {} virtual bool runOnMachineFunction(MachineFunction &MF); virtual const char *getPassName() const { diff --git a/lib/CodeGen/CriticalAntiDepBreaker.cpp b/lib/CodeGen/CriticalAntiDepBreaker.cpp index e3746a9..335d2d8 100644 --- a/lib/CodeGen/CriticalAntiDepBreaker.cpp +++ b/lib/CodeGen/CriticalAntiDepBreaker.cpp @@ -32,21 +32,21 @@ CriticalAntiDepBreaker(MachineFunction& MFi) : MRI(MF.getRegInfo()), TII(MF.getTarget().getInstrInfo()), TRI(MF.getTarget().getRegisterInfo()), - AllocatableSet(TRI->getAllocatableSet(MF)) -{ -} + AllocatableSet(TRI->getAllocatableSet(MF)), + Classes(TRI->getNumRegs(), static_cast(0)), + KillIndices(TRI->getNumRegs(), 0), + DefIndices(TRI->getNumRegs(), 0) {} CriticalAntiDepBreaker::~CriticalAntiDepBreaker() { } void CriticalAntiDepBreaker::StartBlock(MachineBasicBlock *BB) { - // Clear out the register class data. - std::fill(Classes, array_endof(Classes), - static_cast(0)); - - // Initialize the indices to indicate that no registers are live. const unsigned BBSize = BB->size(); - for (unsigned i = 0; i < TRI->getNumRegs(); ++i) { + for (unsigned i = 0, e = TRI->getNumRegs(); i != e; ++i) { + // Clear out the register class data. + Classes[i] = static_cast(0); + + // Initialize the indices to indicate that no registers are live. KillIndices[i] = ~0u; DefIndices[i] = BBSize; } @@ -65,6 +65,7 @@ void CriticalAntiDepBreaker::StartBlock(MachineBasicBlock *BB) { Classes[Reg] = reinterpret_cast(-1); KillIndices[Reg] = BB->size(); DefIndices[Reg] = ~0u; + // Repeat, for all aliases. for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) { unsigned AliasReg = *Alias; @@ -86,6 +87,7 @@ void CriticalAntiDepBreaker::StartBlock(MachineBasicBlock *BB) { Classes[Reg] = reinterpret_cast(-1); KillIndices[Reg] = BB->size(); DefIndices[Reg] = ~0u; + // Repeat, for all aliases. for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) { unsigned AliasReg = *Alias; @@ -106,6 +108,7 @@ void CriticalAntiDepBreaker::StartBlock(MachineBasicBlock *BB) { Classes[Reg] = reinterpret_cast(-1); KillIndices[Reg] = BB->size(); DefIndices[Reg] = ~0u; + // Repeat, for all aliases. for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) { unsigned AliasReg = *Alias; @@ -134,8 +137,10 @@ void CriticalAntiDepBreaker::Observe(MachineInstr *MI, unsigned Count, for (unsigned Reg = 0; Reg != TRI->getNumRegs(); ++Reg) if (DefIndices[Reg] < InsertPosIndex && DefIndices[Reg] >= Count) { assert(KillIndices[Reg] == ~0u && "Clobbered register is live!"); + // Mark this register to be non-renamable. Classes[Reg] = reinterpret_cast(-1); + // Move the def index to the end of the previous region, to reflect // that the def could theoretically have been scheduled at the end. DefIndices[Reg] = InsertPosIndex; @@ -325,6 +330,8 @@ CriticalAntiDepBreaker::findSuitableFreeRegister(MachineInstr *MI, for (TargetRegisterClass::iterator R = RC->allocation_order_begin(MF), RE = RC->allocation_order_end(MF); R != RE; ++R) { unsigned NewReg = *R; + // Don't consider non-allocatable registers + if (!AllocatableSet.test(NewReg)) continue; // Don't replace a register with itself. if (NewReg == AntiDepReg) continue; // Don't replace a register with one that was recently used to repair @@ -433,7 +440,7 @@ BreakAntiDependencies(const std::vector& SUnits, // fix that remaining critical edge too. This is a little more involved, // because unlike the most recent register, less recent registers should // still be considered, though only if no other registers are available. - unsigned LastNewReg[TargetRegisterInfo::FirstVirtualRegister] = {}; + std::vector LastNewReg(TRI->getNumRegs(), 0); // Attempt to break anti-dependence edges on the critical path. Walk the // instructions from the bottom up, tracking information about liveness diff --git a/lib/CodeGen/CriticalAntiDepBreaker.h b/lib/CodeGen/CriticalAntiDepBreaker.h index 5406300..0ed7c35 100644 --- a/lib/CodeGen/CriticalAntiDepBreaker.h +++ b/lib/CodeGen/CriticalAntiDepBreaker.h @@ -46,19 +46,18 @@ class TargetRegisterInfo; /// corresponding value is null. If the register is live but used in /// multiple register classes, the corresponding value is -1 casted to a /// pointer. - const TargetRegisterClass * - Classes[TargetRegisterInfo::FirstVirtualRegister]; + std::vector Classes; /// RegRegs - Map registers to all their references within a live range. std::multimap RegRefs; /// KillIndices - The index of the most recent kill (proceding bottom-up), /// or ~0u if the register is not live. - unsigned KillIndices[TargetRegisterInfo::FirstVirtualRegister]; + std::vector KillIndices; /// DefIndices - The index of the most recent complete def (proceding bottom /// up), or ~0u if the register is live. - unsigned DefIndices[TargetRegisterInfo::FirstVirtualRegister]; + std::vector DefIndices; /// KeepRegs - A set of registers which are live and cannot be changed to /// break anti-dependencies. diff --git a/lib/CodeGen/DeadMachineInstructionElim.cpp b/lib/CodeGen/DeadMachineInstructionElim.cpp index d69c995..318d922 100644 --- a/lib/CodeGen/DeadMachineInstructionElim.cpp +++ b/lib/CodeGen/DeadMachineInstructionElim.cpp @@ -36,7 +36,7 @@ namespace { public: static char ID; // Pass identification, replacement for typeid - DeadMachineInstructionElim() : MachineFunctionPass(&ID) {} + DeadMachineInstructionElim() : MachineFunctionPass(ID) {} private: bool isDead(const MachineInstr *MI) const; @@ -44,9 +44,8 @@ namespace { } char DeadMachineInstructionElim::ID = 0; -static RegisterPass -Y("dead-mi-elimination", - "Remove dead machine instructions"); +INITIALIZE_PASS(DeadMachineInstructionElim, "dead-mi-elimination", + "Remove dead machine instructions", false, false); FunctionPass *llvm::createDeadMachineInstructionElimPass() { return new DeadMachineInstructionElim(); @@ -81,9 +80,8 @@ bool DeadMachineInstructionElim::runOnMachineFunction(MachineFunction &MF) { TRI = MF.getTarget().getRegisterInfo(); TII = MF.getTarget().getInstrInfo(); - // Compute a bitvector to represent all non-allocatable physregs. - BitVector NonAllocatableRegs = TRI->getAllocatableSet(MF); - NonAllocatableRegs.flip(); + // Treat reserved registers as always live. + BitVector ReservedRegs = TRI->getReservedRegs(MF); // Loop over all instructions in all blocks, from bottom to top, so that it's // more likely that chains of dependent but ultimately dead instructions will @@ -92,9 +90,8 @@ bool DeadMachineInstructionElim::runOnMachineFunction(MachineFunction &MF) { I != E; ++I) { MachineBasicBlock *MBB = &*I; - // Start out assuming that all non-allocatable registers are live - // out of this block. - LivePhysRegs = NonAllocatableRegs; + // Start out assuming that reserved registers are live out of this block. + LivePhysRegs = ReservedRegs; // Also add any explicit live-out physregs for this block. if (!MBB->empty() && MBB->back().getDesc().isReturn()) @@ -105,6 +102,10 @@ bool DeadMachineInstructionElim::runOnMachineFunction(MachineFunction &MF) { LivePhysRegs.set(Reg); } + // FIXME: Add live-ins from sucessors to LivePhysRegs. Normally, physregs + // are not live across blocks, but some targets (x86) can have flags live + // out of a block. + // Now scan the instructions and delete dead ones, tracking physreg // liveness as we go. for (MachineBasicBlock::reverse_iterator MII = MBB->rbegin(), diff --git a/lib/CodeGen/DwarfEHPrepare.cpp b/lib/CodeGen/DwarfEHPrepare.cpp index 01b31b4..550fd3e 100644 --- a/lib/CodeGen/DwarfEHPrepare.cpp +++ b/lib/CodeGen/DwarfEHPrepare.cpp @@ -25,19 +25,17 @@ #include "llvm/Support/CallSite.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/PromoteMemToReg.h" +#include "llvm/Transforms/Utils/SSAUpdater.h" using namespace llvm; STATISTIC(NumLandingPadsSplit, "Number of landing pads split"); STATISTIC(NumUnwindsLowered, "Number of unwind instructions lowered"); STATISTIC(NumExceptionValuesMoved, "Number of eh.exception calls moved"); -STATISTIC(NumStackTempsIntroduced, "Number of stack temporaries introduced"); namespace { class DwarfEHPrepare : public FunctionPass { const TargetMachine *TM; const TargetLowering *TLI; - bool CompileFast; // The eh.exception intrinsic. Function *ExceptionValueIntrinsic; @@ -54,9 +52,8 @@ namespace { // _Unwind_Resume or the target equivalent. Constant *RewindFunction; - // Dominator info is used when turning stack temporaries into registers. + // We both use and preserve dominator info. DominatorTree *DT; - DominanceFrontier *DF; // The function we are running on. Function *F; @@ -65,28 +62,14 @@ namespace { typedef SmallPtrSet BBSet; BBSet LandingPads; - // Stack temporary used to hold eh.exception values. - AllocaInst *ExceptionValueVar; - bool NormalizeLandingPads(); bool LowerUnwinds(); bool MoveExceptionValueCalls(); - bool FinishStackTemporaries(); - bool PromoteStackTemporaries(); Instruction *CreateExceptionValueCall(BasicBlock *BB); - Instruction *CreateValueLoad(BasicBlock *BB); - - /// CreateReadOfExceptionValue - Return the result of the eh.exception - /// intrinsic by calling the intrinsic if in a landing pad, or loading it - /// from the exception value variable otherwise. - Instruction *CreateReadOfExceptionValue(BasicBlock *BB) { - return LandingPads.count(BB) ? - CreateExceptionValueCall(BB) : CreateValueLoad(BB); - } /// CleanupSelectors - Any remaining eh.selector intrinsic calls which still - /// use the ".llvm.eh.catch.all.value" call need to convert to using its + /// use the "llvm.eh.catch.all.value" call need to convert to using its /// initializer instead. bool CleanupSelectors(SmallPtrSet &Sels); @@ -112,69 +95,19 @@ namespace { bool FindSelectorAndURoR(Instruction *Inst, bool &URoRInvoke, SmallPtrSet &SelCalls); - /// DoMem2RegPromotion - Take an alloca call and promote it from memory to a - /// register. - bool DoMem2RegPromotion(Value *V) { - AllocaInst *AI = dyn_cast(V); - if (!AI || !isAllocaPromotable(AI)) return false; - - // Turn the alloca into a register. - std::vector Allocas(1, AI); - PromoteMemToReg(Allocas, *DT, *DF); - return true; - } - - /// PromoteStoreInst - Perform Mem2Reg on a StoreInst. - bool PromoteStoreInst(StoreInst *SI) { - if (!SI || !DT || !DF) return false; - if (DoMem2RegPromotion(SI->getOperand(1))) - return true; - return false; - } - - /// PromoteEHPtrStore - Promote the storing of an EH pointer into a - /// register. This should get rid of the store and subsequent loads. - bool PromoteEHPtrStore(IntrinsicInst *II) { - if (!DT || !DF) return false; - - bool Changed = false; - StoreInst *SI; - - while (1) { - SI = 0; - for (Value::use_iterator - I = II->use_begin(), E = II->use_end(); I != E; ++I) { - SI = dyn_cast(I); - if (SI) break; - } - - if (!PromoteStoreInst(SI)) - break; - - Changed = true; - } - - return Changed; - } - public: static char ID; // Pass identification, replacement for typeid. - DwarfEHPrepare(const TargetMachine *tm, bool fast) : - FunctionPass(&ID), TM(tm), TLI(TM->getTargetLowering()), - CompileFast(fast), + DwarfEHPrepare(const TargetMachine *tm) : + FunctionPass(ID), TM(tm), TLI(TM->getTargetLowering()), ExceptionValueIntrinsic(0), SelectorIntrinsic(0), URoR(0), EHCatchAllValue(0), RewindFunction(0) {} virtual bool runOnFunction(Function &Fn); - // getAnalysisUsage - We need dominance frontiers for memory promotion. + // getAnalysisUsage - We need the dominator tree for handling URoR. virtual void getAnalysisUsage(AnalysisUsage &AU) const { - if (!CompileFast) - AU.addRequired(); + AU.addRequired(); AU.addPreserved(); - if (!CompileFast) - AU.addRequired(); - AU.addPreserved(); } const char *getPassName() const { @@ -186,8 +119,8 @@ namespace { char DwarfEHPrepare::ID = 0; -FunctionPass *llvm::createDwarfEHPass(const TargetMachine *tm, bool fast) { - return new DwarfEHPrepare(tm, fast); +FunctionPass *llvm::createDwarfEHPass(const TargetMachine *tm) { + return new DwarfEHPrepare(tm); } /// HasCatchAllInSelector - Return true if the intrinsic instruction has a @@ -207,7 +140,7 @@ FindAllCleanupSelectors(SmallPtrSet &Sels, for (Value::use_iterator I = SelectorIntrinsic->use_begin(), E = SelectorIntrinsic->use_end(); I != E; ++I) { - IntrinsicInst *II = cast(I); + IntrinsicInst *II = cast(*I); if (II->getParent()->getParent() != F) continue; @@ -225,13 +158,13 @@ FindAllURoRInvokes(SmallPtrSet &URoRInvokes) { for (Value::use_iterator I = URoR->use_begin(), E = URoR->use_end(); I != E; ++I) { - if (InvokeInst *II = dyn_cast(I)) + if (InvokeInst *II = dyn_cast(*I)) URoRInvokes.insert(II); } } /// CleanupSelectors - Any remaining eh.selector intrinsic calls which still use -/// the ".llvm.eh.catch.all.value" call need to convert to using its +/// the "llvm.eh.catch.all.value" call need to convert to using its /// initializer instead. bool DwarfEHPrepare::CleanupSelectors(SmallPtrSet &Sels) { if (!EHCatchAllValue) return false; @@ -247,7 +180,7 @@ bool DwarfEHPrepare::CleanupSelectors(SmallPtrSet &Sels) { I = Sels.begin(), E = Sels.end(); I != E; ++I) { IntrinsicInst *Sel = *I; - // Index of the ".llvm.eh.catch.all.value" variable. + // Index of the "llvm.eh.catch.all.value" variable. unsigned OpIdx = Sel->getNumArgOperands() - 1; GlobalVariable *GV = dyn_cast(Sel->getArgOperand(OpIdx)); if (GV != EHCatchAllValue) continue; @@ -268,10 +201,9 @@ DwarfEHPrepare::FindSelectorAndURoR(Instruction *Inst, bool &URoRInvoke, SmallPtrSet SeenPHIs; bool Changed = false; - restart: for (Value::use_iterator I = Inst->use_begin(), E = Inst->use_end(); I != E; ++I) { - Instruction *II = dyn_cast(I); + Instruction *II = dyn_cast(*I); if (!II || II->getParent()->getParent() != F) continue; if (IntrinsicInst *Sel = dyn_cast(II)) { @@ -282,11 +214,6 @@ DwarfEHPrepare::FindSelectorAndURoR(Instruction *Inst, bool &URoRInvoke, URoRInvoke = true; } else if (CastInst *CI = dyn_cast(II)) { Changed |= FindSelectorAndURoR(CI, URoRInvoke, SelCalls); - } else if (StoreInst *SI = dyn_cast(II)) { - if (!PromoteStoreInst(SI)) continue; - Changed = true; - SeenPHIs.clear(); - goto restart; // Uses may have changed, restart loop. } else if (PHINode *PN = dyn_cast(II)) { if (SeenPHIs.insert(PN)) // Don't process a PHI node more than once. @@ -304,7 +231,7 @@ DwarfEHPrepare::FindSelectorAndURoR(Instruction *Inst, bool &URoRInvoke, bool DwarfEHPrepare::HandleURoRInvokes() { if (!EHCatchAllValue) { EHCatchAllValue = - F->getParent()->getNamedGlobal(".llvm.eh.catch.all.value"); + F->getParent()->getNamedGlobal("llvm.eh.catch.all.value"); if (!EHCatchAllValue) return false; } @@ -318,10 +245,6 @@ bool DwarfEHPrepare::HandleURoRInvokes() { SmallPtrSet CatchAllSels; FindAllCleanupSelectors(Sels, CatchAllSels); - if (!DT) - // We require DominatorTree information. - return CleanupSelectors(CatchAllSels); - if (!URoR) { URoR = F->getParent()->getFunction("_Unwind_Resume_or_Rethrow"); if (!URoR) return CleanupSelectors(CatchAllSels); @@ -338,7 +261,7 @@ bool DwarfEHPrepare::HandleURoRInvokes() { for (SmallPtrSet::iterator UI = URoRInvokes.begin(), UE = URoRInvokes.end(); UI != UE; ++UI) { const BasicBlock *URoRBB = (*UI)->getParent(); - if (SelBB == URoRBB || DT->dominates(SelBB, URoRBB)) { + if (DT->dominates(SelBB, URoRBB)) { SelsToConvert.insert(*SI); break; } @@ -360,11 +283,9 @@ bool DwarfEHPrepare::HandleURoRInvokes() { for (Value::use_iterator I = ExceptionValueIntrinsic->use_begin(), E = ExceptionValueIntrinsic->use_end(); I != E; ++I) { - IntrinsicInst *EHPtr = dyn_cast(I); + IntrinsicInst *EHPtr = dyn_cast(*I); if (!EHPtr || EHPtr->getParent()->getParent() != F) continue; - Changed |= PromoteEHPtrStore(EHPtr); - bool URoRInvoke = false; SmallPtrSet SelCalls; Changed |= FindSelectorAndURoR(EHPtr, URoRInvoke, SelCalls); @@ -532,11 +453,8 @@ bool DwarfEHPrepare::NormalizeLandingPads() { // Add a fallthrough from NewBB to the original landing pad. BranchInst::Create(LPad, NewBB); - // Now update DominatorTree and DominanceFrontier analysis information. - if (DT) - DT->splitBlock(NewBB); - if (DF) - DF->splitBlock(NewBB); + // Now update DominatorTree analysis information. + DT->splitBlock(NewBB); // Remember the newly constructed landing pad. The original landing pad // LPad is no longer a landing pad now that all unwind edges have been @@ -586,7 +504,7 @@ bool DwarfEHPrepare::LowerUnwinds() { // Create the call... CallInst *CI = CallInst::Create(RewindFunction, - CreateReadOfExceptionValue(TI->getParent()), + CreateExceptionValueCall(TI->getParent()), "", TI); CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME)); // ...followed by an UnreachableInst. @@ -602,9 +520,11 @@ bool DwarfEHPrepare::LowerUnwinds() { } /// MoveExceptionValueCalls - Ensure that eh.exception is only ever called from -/// landing pads by replacing calls outside of landing pads with loads from a -/// stack temporary. Move eh.exception calls inside landing pads to the start -/// of the landing pad (optional, but may make things simpler for later passes). +/// landing pads by replacing calls outside of landing pads with direct use of +/// a register holding the appropriate value; this requires adding calls inside +/// all landing pads to initialize the register. Also, move eh.exception calls +/// inside landing pads to the start of the landing pad (optional, but may make +/// things simpler for later passes). bool DwarfEHPrepare::MoveExceptionValueCalls() { // If the eh.exception intrinsic is not declared in the module then there is // nothing to do. Speed up compilation by checking for this common case. @@ -614,61 +534,87 @@ bool DwarfEHPrepare::MoveExceptionValueCalls() { bool Changed = false; - for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { - for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E;) - if (IntrinsicInst *CI = dyn_cast(II++)) - if (CI->getIntrinsicID() == Intrinsic::eh_exception) { - if (!CI->use_empty()) { - Value *ExceptionValue = CreateReadOfExceptionValue(BB); - if (CI == ExceptionValue) { - // The call was at the start of a landing pad - leave it alone. - assert(LandingPads.count(BB) && - "Created eh.exception call outside landing pad!"); - continue; - } - CI->replaceAllUsesWith(ExceptionValue); - } - CI->eraseFromParent(); - ++NumExceptionValuesMoved; - Changed = true; + // Move calls to eh.exception that are inside a landing pad to the start of + // the landing pad. + for (BBSet::const_iterator LI = LandingPads.begin(), LE = LandingPads.end(); + LI != LE; ++LI) { + BasicBlock *LP = *LI; + for (BasicBlock::iterator II = LP->getFirstNonPHIOrDbg(), IE = LP->end(); + II != IE;) + if (EHExceptionInst *EI = dyn_cast(II++)) { + // Found a call to eh.exception. + if (!EI->use_empty()) { + // If there is already a call to eh.exception at the start of the + // landing pad, then get hold of it; otherwise create such a call. + Value *CallAtStart = CreateExceptionValueCall(LP); + + // If the call was at the start of a landing pad then leave it alone. + if (EI == CallAtStart) + continue; + EI->replaceAllUsesWith(CallAtStart); } + EI->eraseFromParent(); + ++NumExceptionValuesMoved; + Changed = true; + } } - return Changed; -} - -/// FinishStackTemporaries - If we introduced a stack variable to hold the -/// exception value then initialize it in each landing pad. -bool DwarfEHPrepare::FinishStackTemporaries() { - if (!ExceptionValueVar) - // Nothing to do. - return false; + // Look for calls to eh.exception that are not in a landing pad. If one is + // found, then a register that holds the exception value will be created in + // each landing pad, and the SSAUpdater will be used to compute the values + // returned by eh.exception calls outside of landing pads. + SSAUpdater SSA; + + // Remember where we found the eh.exception call, to avoid rescanning earlier + // basic blocks which we already know contain no eh.exception calls. + bool FoundCallOutsideLandingPad = false; + Function::iterator BB = F->begin(); + for (Function::iterator BE = F->end(); BB != BE; ++BB) { + // Skip over landing pads. + if (LandingPads.count(BB)) + continue; - bool Changed = false; + for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg(), IE = BB->end(); + II != IE; ++II) + if (isa(II)) { + SSA.Initialize(II->getType(), II->getName()); + FoundCallOutsideLandingPad = true; + break; + } - // Make sure that there is a store of the exception value at the start of - // each landing pad. - for (BBSet::iterator LI = LandingPads.begin(), LE = LandingPads.end(); - LI != LE; ++LI) { - Instruction *ExceptionValue = CreateReadOfExceptionValue(*LI); - Instruction *Store = new StoreInst(ExceptionValue, ExceptionValueVar); - Store->insertAfter(ExceptionValue); - Changed = true; + if (FoundCallOutsideLandingPad) + break; } - return Changed; -} + // If all calls to eh.exception are in landing pads then we are done. + if (!FoundCallOutsideLandingPad) + return Changed; -/// PromoteStackTemporaries - Turn any stack temporaries we introduced into -/// registers if possible. -bool DwarfEHPrepare::PromoteStackTemporaries() { - if (ExceptionValueVar && DT && DF && isAllocaPromotable(ExceptionValueVar)) { - // Turn the exception temporary into registers and phi nodes if possible. - std::vector Allocas(1, ExceptionValueVar); - PromoteMemToReg(Allocas, *DT, *DF); - return true; + // Add a call to eh.exception at the start of each landing pad, and tell the + // SSAUpdater that this is the value produced by the landing pad. + for (BBSet::iterator LI = LandingPads.begin(), LE = LandingPads.end(); + LI != LE; ++LI) + SSA.AddAvailableValue(*LI, CreateExceptionValueCall(*LI)); + + // Now turn all calls to eh.exception that are not in a landing pad into a use + // of the appropriate register. + for (Function::iterator BE = F->end(); BB != BE; ++BB) { + // Skip over landing pads. + if (LandingPads.count(BB)) + continue; + + for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg(), IE = BB->end(); + II != IE;) + if (EHExceptionInst *EI = dyn_cast(II++)) { + // Found a call to eh.exception, replace it with the value from any + // upstream landing pad(s). + EI->replaceAllUsesWith(SSA.GetValueAtEndOfBlock(BB)); + EI->eraseFromParent(); + ++NumExceptionValuesMoved; + } } - return false; + + return true; } /// CreateExceptionValueCall - Insert a call to the eh.exception intrinsic at @@ -691,36 +637,11 @@ Instruction *DwarfEHPrepare::CreateExceptionValueCall(BasicBlock *BB) { return CallInst::Create(ExceptionValueIntrinsic, "eh.value.call", Start); } -/// CreateValueLoad - Insert a load of the exception value stack variable -/// (creating it if necessary) at the start of the basic block (unless -/// there already is a load, in which case the existing load is returned). -Instruction *DwarfEHPrepare::CreateValueLoad(BasicBlock *BB) { - Instruction *Start = BB->getFirstNonPHIOrDbg(); - // Is this a load of the exception temporary? - if (ExceptionValueVar) - if (LoadInst* LI = dyn_cast(Start)) - if (LI->getPointerOperand() == ExceptionValueVar) - // Reuse the existing load. - return Start; - - // Create the temporary if we didn't already. - if (!ExceptionValueVar) { - ExceptionValueVar = new AllocaInst(PointerType::getUnqual( - Type::getInt8Ty(BB->getContext())), "eh.value", F->begin()->begin()); - ++NumStackTempsIntroduced; - } - - // Load the value. - return new LoadInst(ExceptionValueVar, "eh.value.load", Start); -} - bool DwarfEHPrepare::runOnFunction(Function &Fn) { bool Changed = false; // Initialize internal state. - DT = getAnalysisIfAvailable(); - DF = getAnalysisIfAvailable(); - ExceptionValueVar = 0; + DT = &getAnalysis(); F = &Fn; // Ensure that only unwind edges end at landing pads (a landing pad is a @@ -735,13 +656,6 @@ bool DwarfEHPrepare::runOnFunction(Function &Fn) { // Move eh.exception calls to landing pads. Changed |= MoveExceptionValueCalls(); - // Initialize any stack temporaries we introduced. - Changed |= FinishStackTemporaries(); - - // Turn any stack temporaries into registers if possible. - if (!CompileFast) - Changed |= PromoteStackTemporaries(); - Changed |= HandleURoRInvokes(); LandingPads.clear(); diff --git a/lib/CodeGen/ELF.h b/lib/CodeGen/ELF.h index cb5a8c0..fb884c9 100644 --- a/lib/CodeGen/ELF.h +++ b/lib/CodeGen/ELF.h @@ -22,36 +22,12 @@ #include "llvm/CodeGen/BinaryObject.h" #include "llvm/CodeGen/MachineRelocation.h" +#include "llvm/Support/ELF.h" #include "llvm/System/DataTypes.h" namespace llvm { class GlobalValue; - // Identification Indexes - enum { - EI_MAG0 = 0, - EI_MAG1 = 1, - EI_MAG2 = 2, - EI_MAG3 = 3 - }; - - // File types - enum { - ET_NONE = 0, // No file type - ET_REL = 1, // Relocatable file - ET_EXEC = 2, // Executable file - ET_DYN = 3, // Shared object file - ET_CORE = 4, // Core file - ET_LOPROC = 0xff00, // Beginning of processor-specific codes - ET_HIPROC = 0xffff // Processor-specific - }; - - // Versioning - enum { - EV_NONE = 0, - EV_CURRENT = 1 - }; - /// ELFSym - This struct contains information about each symbol that is /// added to logical symbol table for the module. This is eventually /// turned into a real symbol table in the file. @@ -108,9 +84,9 @@ namespace llvm { static ELFSym *getExtSym(const char *Ext) { ELFSym *Sym = new ELFSym(); Sym->Source.Ext = Ext; - Sym->setBind(STB_GLOBAL); - Sym->setType(STT_NOTYPE); - Sym->setVisibility(STV_DEFAULT); + Sym->setBind(ELF::STB_GLOBAL); + Sym->setType(ELF::STT_NOTYPE); + Sym->setVisibility(ELF::STV_DEFAULT); Sym->SourceType = isExtSym; return Sym; } @@ -118,9 +94,9 @@ namespace llvm { // getSectionSym - Returns a elf symbol to represent an elf section static ELFSym *getSectionSym() { ELFSym *Sym = new ELFSym(); - Sym->setBind(STB_LOCAL); - Sym->setType(STT_SECTION); - Sym->setVisibility(STV_DEFAULT); + Sym->setBind(ELF::STB_LOCAL); + Sym->setType(ELF::STT_SECTION); + Sym->setVisibility(ELF::STV_DEFAULT); Sym->SourceType = isOther; return Sym; } @@ -128,9 +104,9 @@ namespace llvm { // getFileSym - Returns a elf symbol to represent the module identifier static ELFSym *getFileSym() { ELFSym *Sym = new ELFSym(); - Sym->setBind(STB_LOCAL); - Sym->setType(STT_FILE); - Sym->setVisibility(STV_DEFAULT); + Sym->setBind(ELF::STB_LOCAL); + Sym->setType(ELF::STT_FILE); + Sym->setVisibility(ELF::STV_DEFAULT); Sym->SectionIdx = 0xfff1; // ELFSection::SHN_ABS; Sym->SourceType = isOther; return Sym; @@ -141,8 +117,8 @@ namespace llvm { ELFSym *Sym = new ELFSym(); Sym->Source.GV = GV; Sym->setBind(Bind); - Sym->setType(STT_NOTYPE); - Sym->setVisibility(STV_DEFAULT); + Sym->setType(ELF::STT_NOTYPE); + Sym->setVisibility(ELF::STV_DEFAULT); Sym->SectionIdx = 0; //ELFSection::SHN_UNDEF; Sym->SourceType = isGV; return Sym; @@ -159,35 +135,14 @@ namespace llvm { // Symbol index into the Symbol table unsigned SymTabIdx; - enum { - STB_LOCAL = 0, // Local sym, not visible outside obj file containing def - STB_GLOBAL = 1, // Global sym, visible to all object files being combined - STB_WEAK = 2 // Weak symbol, like global but lower-precedence - }; - - enum { - STT_NOTYPE = 0, // Symbol's type is not specified - STT_OBJECT = 1, // Symbol is a data object (variable, array, etc.) - STT_FUNC = 2, // Symbol is executable code (function, etc.) - STT_SECTION = 3, // Symbol refers to a section - STT_FILE = 4 // Local, absolute symbol that refers to a file - }; - - enum { - STV_DEFAULT = 0, // Visibility is specified by binding type - STV_INTERNAL = 1, // Defined by processor supplements - STV_HIDDEN = 2, // Not visible to other components - STV_PROTECTED = 3 // Visible in other components but not preemptable - }; - ELFSym() : SourceType(isOther), NameIdx(0), Value(0), - Size(0), Info(0), Other(STV_DEFAULT), SectionIdx(0), + Size(0), Info(0), Other(ELF::STV_DEFAULT), SectionIdx(0), SymTabIdx(0) {} unsigned getBind() const { return (Info >> 4) & 0xf; } unsigned getType() const { return Info & 0xf; } - bool isLocalBind() const { return getBind() == STB_LOCAL; } - bool isFileType() const { return getType() == STT_FILE; } + bool isLocalBind() const { return getBind() == ELF::STB_LOCAL; } + bool isFileType() const { return getType() == ELF::STT_FILE; } void setBind(unsigned X) { assert(X == (X & 0xF) && "Bind value out of range!"); @@ -222,51 +177,6 @@ namespace llvm { unsigned Align; // sh_addralign - Alignment of section. unsigned EntSize; // sh_entsize - Size of entries in the section e - // Section Header Flags - enum { - SHF_WRITE = 1 << 0, // Writable - SHF_ALLOC = 1 << 1, // Mapped into the process addr space - SHF_EXECINSTR = 1 << 2, // Executable - SHF_MERGE = 1 << 4, // Might be merged if equal - SHF_STRINGS = 1 << 5, // Contains null-terminated strings - SHF_INFO_LINK = 1 << 6, // 'sh_info' contains SHT index - SHF_LINK_ORDER = 1 << 7, // Preserve order after combining - SHF_OS_NONCONFORMING = 1 << 8, // nonstandard OS support required - SHF_GROUP = 1 << 9, // Section is a member of a group - SHF_TLS = 1 << 10 // Section holds thread-local data - }; - - // Section Types - enum { - SHT_NULL = 0, // No associated section (inactive entry). - SHT_PROGBITS = 1, // Program-defined contents. - SHT_SYMTAB = 2, // Symbol table. - SHT_STRTAB = 3, // String table. - SHT_RELA = 4, // Relocation entries; explicit addends. - SHT_HASH = 5, // Symbol hash table. - SHT_DYNAMIC = 6, // Information for dynamic linking. - SHT_NOTE = 7, // Information about the file. - SHT_NOBITS = 8, // Data occupies no space in the file. - SHT_REL = 9, // Relocation entries; no explicit addends. - SHT_SHLIB = 10, // Reserved. - SHT_DYNSYM = 11, // Symbol table. - SHT_LOPROC = 0x70000000, // Lowest processor arch-specific type. - SHT_HIPROC = 0x7fffffff, // Highest processor arch-specific type. - SHT_LOUSER = 0x80000000, // Lowest type reserved for applications. - SHT_HIUSER = 0xffffffff // Highest type reserved for applications. - }; - - // Special section indices. - enum { - SHN_UNDEF = 0, // Undefined, missing, irrelevant - SHN_LORESERVE = 0xff00, // Lowest reserved index - SHN_LOPROC = 0xff00, // Lowest processor-specific index - SHN_HIPROC = 0xff1f, // Highest processor-specific index - SHN_ABS = 0xfff1, // Symbol has absolute value; no relocation - SHN_COMMON = 0xfff2, // FORTRAN COMMON or C external global variables - SHN_HIRESERVE = 0xffff // Highest reserved index - }; - /// SectionIdx - The number of the section in the Section Table. unsigned short SectionIdx; diff --git a/lib/CodeGen/ELFCodeEmitter.cpp b/lib/CodeGen/ELFCodeEmitter.cpp index 36b0e65..3fb087c 100644 --- a/lib/CodeGen/ELFCodeEmitter.cpp +++ b/lib/CodeGen/ELFCodeEmitter.cpp @@ -71,7 +71,7 @@ void ELFCodeEmitter::startFunction(MachineFunction &MF) { bool ELFCodeEmitter::finishFunction(MachineFunction &MF) { // Add a symbol to represent the function. const Function *F = MF.getFunction(); - ELFSym *FnSym = ELFSym::getGV(F, EW.getGlobalELFBinding(F), ELFSym::STT_FUNC, + ELFSym *FnSym = ELFSym::getGV(F, EW.getGlobalELFBinding(F), ELF::STT_FUNC, EW.getGlobalELFVisibility(F)); FnSym->SectionIdx = ES->SectionIdx; FnSym->Size = ES->getCurrentPCOffset()-FnStartOff; diff --git a/lib/CodeGen/ELFWriter.cpp b/lib/CodeGen/ELFWriter.cpp index b644ebe..d14728d 100644 --- a/lib/CodeGen/ELFWriter.cpp +++ b/lib/CodeGen/ELFWriter.cpp @@ -63,7 +63,7 @@ char ELFWriter::ID = 0; //===----------------------------------------------------------------------===// ELFWriter::ELFWriter(raw_ostream &o, TargetMachine &tm) - : MachineFunctionPass(&ID), O(o), TM(tm), + : MachineFunctionPass(ID), O(o), TM(tm), OutContext(*new MCContext(*TM.getMCAsmInfo())), TLOF(TM.getTargetLowering()->getObjFileLowering()), is64Bit(TM.getTargetData()->getPointerSizeInBits() == 64), @@ -129,12 +129,12 @@ bool ELFWriter::doInitialization(Module &M) { ElfHdr.emitByte(TEW->getEIClass()); // e_ident[EI_CLASS] ElfHdr.emitByte(TEW->getEIData()); // e_ident[EI_DATA] - ElfHdr.emitByte(EV_CURRENT); // e_ident[EI_VERSION] + ElfHdr.emitByte(ELF::EV_CURRENT); // e_ident[EI_VERSION] ElfHdr.emitAlignment(16); // e_ident[EI_NIDENT-EI_PAD] - ElfHdr.emitWord16(ET_REL); // e_type + ElfHdr.emitWord16(ELF::ET_REL); // e_type ElfHdr.emitWord16(TEW->getEMachine()); // e_machine = target - ElfHdr.emitWord32(EV_CURRENT); // e_version + ElfHdr.emitWord32(ELF::EV_CURRENT); // e_version ElfHdr.emitWord(0); // e_entry, no entry point in .o file ElfHdr.emitWord(0); // e_phoff, no program header for .o ELFHdr_e_shoff_Offset = ElfHdr.size(); @@ -252,7 +252,7 @@ ELFSection &ELFWriter::getConstantPoolSection(MachineConstantPoolEntry &CPE) { // is true if the relocation section contains entries with addends. ELFSection &ELFWriter::getRelocSection(ELFSection &S) { unsigned SectionType = TEW->hasRelocationAddend() ? - ELFSection::SHT_RELA : ELFSection::SHT_REL; + ELF::SHT_RELA : ELF::SHT_REL; std::string SectionName(".rel"); if (TEW->hasRelocationAddend()) @@ -268,11 +268,11 @@ unsigned ELFWriter::getGlobalELFVisibility(const GlobalValue *GV) { default: llvm_unreachable("unknown visibility type"); case GlobalValue::DefaultVisibility: - return ELFSym::STV_DEFAULT; + return ELF::STV_DEFAULT; case GlobalValue::HiddenVisibility: - return ELFSym::STV_HIDDEN; + return ELF::STV_HIDDEN; case GlobalValue::ProtectedVisibility: - return ELFSym::STV_PROTECTED; + return ELF::STV_PROTECTED; } return 0; } @@ -280,23 +280,23 @@ unsigned ELFWriter::getGlobalELFVisibility(const GlobalValue *GV) { // getGlobalELFBinding - Returns the ELF specific binding type unsigned ELFWriter::getGlobalELFBinding(const GlobalValue *GV) { if (GV->hasInternalLinkage()) - return ELFSym::STB_LOCAL; + return ELF::STB_LOCAL; if (GV->isWeakForLinker() && !GV->hasCommonLinkage()) - return ELFSym::STB_WEAK; + return ELF::STB_WEAK; - return ELFSym::STB_GLOBAL; + return ELF::STB_GLOBAL; } // getGlobalELFType - Returns the ELF specific type for a global unsigned ELFWriter::getGlobalELFType(const GlobalValue *GV) { if (GV->isDeclaration()) - return ELFSym::STT_NOTYPE; + return ELF::STT_NOTYPE; if (isa(GV)) - return ELFSym::STT_FUNC; + return ELF::STT_FUNC; - return ELFSym::STT_OBJECT; + return ELF::STT_OBJECT; } // IsELFUndefSym - True if the global value must be marked as a symbol @@ -364,7 +364,7 @@ void ELFWriter::EmitGlobal(const GlobalValue *GV) { GblSym->Size = Size; if (S->HasCommonSymbols()) { // Symbol must go to a common section - GblSym->SectionIdx = ELFSection::SHN_COMMON; + GblSym->SectionIdx = ELF::SHN_COMMON; // A new linkonce section is created for each global in the // common section, the default alignment is 1 and the symbol diff --git a/lib/CodeGen/ELFWriter.h b/lib/CodeGen/ELFWriter.h index db66ecc..b8bac55 100644 --- a/lib/CodeGen/ELFWriter.h +++ b/lib/CodeGen/ELFWriter.h @@ -39,6 +39,7 @@ namespace llvm { class raw_ostream; class SectionKind; class MCContext; + class TargetMachine; typedef std::vector::iterator ELFSymIter; typedef std::vector::iterator ELFSectionIter; @@ -160,29 +161,29 @@ namespace llvm { SN->SectionIdx = NumSections++; SN->Type = Type; SN->Flags = Flags; - SN->Link = ELFSection::SHN_UNDEF; + SN->Link = ELF::SHN_UNDEF; SN->Align = Align; return *SN; } ELFSection &getNonExecStackSection() { - return getSection(".note.GNU-stack", ELFSection::SHT_PROGBITS, 0, 1); + return getSection(".note.GNU-stack", ELF::SHT_PROGBITS, 0, 1); } ELFSection &getSymbolTableSection() { - return getSection(".symtab", ELFSection::SHT_SYMTAB, 0); + return getSection(".symtab", ELF::SHT_SYMTAB, 0); } ELFSection &getStringTableSection() { - return getSection(".strtab", ELFSection::SHT_STRTAB, 0, 1); + return getSection(".strtab", ELF::SHT_STRTAB, 0, 1); } ELFSection &getSectionHeaderStringTableSection() { - return getSection(".shstrtab", ELFSection::SHT_STRTAB, 0, 1); + return getSection(".shstrtab", ELF::SHT_STRTAB, 0, 1); } ELFSection &getNullSection() { - return getSection("", ELFSection::SHT_NULL, 0); + return getSection("", ELF::SHT_NULL, 0); } ELFSection &getDataSection(); diff --git a/lib/CodeGen/GCMetadata.cpp b/lib/CodeGen/GCMetadata.cpp index ab0a800..0f6e882 100644 --- a/lib/CodeGen/GCMetadata.cpp +++ b/lib/CodeGen/GCMetadata.cpp @@ -30,8 +30,8 @@ namespace { raw_ostream &OS; public: - Printer() : FunctionPass(&ID), OS(errs()) {} - explicit Printer(raw_ostream &OS) : FunctionPass(&ID), OS(OS) {} + Printer() : FunctionPass(ID), OS(errs()) {} + explicit Printer(raw_ostream &OS) : FunctionPass(ID), OS(OS) {} const char *getPassName() const; @@ -55,8 +55,8 @@ namespace { } -static RegisterPass -X("collector-metadata", "Create Garbage Collector Module Metadata"); +INITIALIZE_PASS(GCModuleInfo, "collector-metadata", + "Create Garbage Collector Module Metadata", false, false); // ----------------------------------------------------------------------------- @@ -70,7 +70,7 @@ GCFunctionInfo::~GCFunctionInfo() {} char GCModuleInfo::ID = 0; GCModuleInfo::GCModuleInfo() - : ImmutablePass(&ID) {} + : ImmutablePass(ID) {} GCModuleInfo::~GCModuleInfo() { clear(); @@ -189,7 +189,7 @@ FunctionPass *llvm::createGCInfoDeleter() { return new Deleter(); } -Deleter::Deleter() : FunctionPass(&ID) {} +Deleter::Deleter() : FunctionPass(ID) {} const char *Deleter::getPassName() const { return "Delete Garbage Collector Information"; diff --git a/lib/CodeGen/GCStrategy.cpp b/lib/CodeGen/GCStrategy.cpp index 71506cc..719fa19 100644 --- a/lib/CodeGen/GCStrategy.cpp +++ b/lib/CodeGen/GCStrategy.cpp @@ -130,7 +130,7 @@ FunctionPass *llvm::createGCLoweringPass() { char LowerIntrinsics::ID = 0; LowerIntrinsics::LowerIntrinsics() - : FunctionPass(&ID) {} + : FunctionPass(ID) {} const char *LowerIntrinsics::getPassName() const { return "Lower Garbage Collection Instructions"; @@ -260,7 +260,7 @@ bool LowerIntrinsics::PerformDefaultLowering(Function &F, GCStrategy &S) { bool LowerRd = !S.customReadBarrier(); bool InitRoots = S.initializeRoots(); - SmallVector Roots; + SmallVector Roots; bool MadeChange = false; for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) { @@ -271,7 +271,8 @@ bool LowerIntrinsics::PerformDefaultLowering(Function &F, GCStrategy &S) { case Intrinsic::gcwrite: if (LowerWr) { // Replace a write barrier with a simple store. - Value *St = new StoreInst(CI->getArgOperand(0), CI->getArgOperand(2), CI); + Value *St = new StoreInst(CI->getArgOperand(0), + CI->getArgOperand(2), CI); CI->replaceAllUsesWith(St); CI->eraseFromParent(); } @@ -317,7 +318,7 @@ FunctionPass *llvm::createGCMachineCodeAnalysisPass() { char MachineCodeAnalysis::ID = 0; MachineCodeAnalysis::MachineCodeAnalysis() - : MachineFunctionPass(&ID) {} + : MachineFunctionPass(ID) {} const char *MachineCodeAnalysis::getPassName() const { return "Analyze Machine Code For Garbage Collection"; diff --git a/lib/CodeGen/IfConversion.cpp b/lib/CodeGen/IfConversion.cpp index 6b445e0..0ea30d7 100644 --- a/lib/CodeGen/IfConversion.cpp +++ b/lib/CodeGen/IfConversion.cpp @@ -154,7 +154,7 @@ namespace { int FnNum; public: static char ID; - IfConverter() : MachineFunctionPass(&ID), FnNum(-1) {} + IfConverter() : MachineFunctionPass(ID), FnNum(-1) {} virtual bool runOnMachineFunction(MachineFunction &MF); virtual const char *getPassName() const { return "If Converter"; } @@ -230,8 +230,7 @@ namespace { char IfConverter::ID = 0; } -static RegisterPass -X("if-converter", "If Converter"); +INITIALIZE_PASS(IfConverter, "if-converter", "If Converter", false, false); FunctionPass *llvm::createIfConverterPass() { return new IfConverter(); } diff --git a/lib/CodeGen/InlineSpiller.cpp b/lib/CodeGen/InlineSpiller.cpp index 12adcaa..b965bfd 100644 --- a/lib/CodeGen/InlineSpiller.cpp +++ b/lib/CodeGen/InlineSpiller.cpp @@ -14,10 +14,12 @@ #define DEBUG_TYPE "spiller" #include "Spiller.h" +#include "SplitKit.h" #include "VirtRegMap.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" @@ -28,8 +30,10 @@ using namespace llvm; namespace { class InlineSpiller : public Spiller { + MachineFunctionPass &pass_; MachineFunction &mf_; LiveIntervals &lis_; + MachineLoopInfo &loops_; VirtRegMap &vrm_; MachineFrameInfo &mfi_; MachineRegisterInfo &mri_; @@ -37,9 +41,11 @@ class InlineSpiller : public Spiller { const TargetRegisterInfo &tri_; const BitVector reserved_; + SplitAnalysis splitAnalysis_; + // Variables that are valid during spill(), but used by multiple methods. LiveInterval *li_; - std::vector *newIntervals_; + SmallVectorImpl *newIntervals_; const TargetRegisterClass *rc_; int stackSlot_; const SmallVectorImpl *spillIs_; @@ -53,25 +59,34 @@ class InlineSpiller : public Spiller { ~InlineSpiller() {} public: - InlineSpiller(MachineFunction *mf, LiveIntervals *lis, VirtRegMap *vrm) - : mf_(*mf), lis_(*lis), vrm_(*vrm), - mfi_(*mf->getFrameInfo()), - mri_(mf->getRegInfo()), - tii_(*mf->getTarget().getInstrInfo()), - tri_(*mf->getTarget().getRegisterInfo()), - reserved_(tri_.getReservedRegs(mf_)) {} + InlineSpiller(MachineFunctionPass &pass, + MachineFunction &mf, + VirtRegMap &vrm) + : pass_(pass), + mf_(mf), + lis_(pass.getAnalysis()), + loops_(pass.getAnalysis()), + vrm_(vrm), + mfi_(*mf.getFrameInfo()), + mri_(mf.getRegInfo()), + tii_(*mf.getTarget().getInstrInfo()), + tri_(*mf.getTarget().getRegisterInfo()), + reserved_(tri_.getReservedRegs(mf_)), + splitAnalysis_(mf, lis_, loops_) {} void spill(LiveInterval *li, - std::vector &newIntervals, - SmallVectorImpl &spillIs, - SlotIndex *earliestIndex); + SmallVectorImpl &newIntervals, + SmallVectorImpl &spillIs); private: + bool split(); + bool allUsesAvailableAt(const MachineInstr *OrigMI, SlotIndex OrigIdx, SlotIndex UseIdx); bool reMaterializeFor(MachineBasicBlock::iterator MI); void reMaterializeAll(); + bool coalesceStackAccess(MachineInstr *MI); bool foldMemoryOperand(MachineBasicBlock::iterator MI, const SmallVectorImpl &Ops); void insertReload(LiveInterval &NewLI, MachineBasicBlock::iterator MI); @@ -80,12 +95,43 @@ private: } namespace llvm { -Spiller *createInlineSpiller(MachineFunction *mf, - LiveIntervals *lis, - const MachineLoopInfo *mli, - VirtRegMap *vrm) { - return new InlineSpiller(mf, lis, vrm); +Spiller *createInlineSpiller(MachineFunctionPass &pass, + MachineFunction &mf, + VirtRegMap &vrm) { + return new InlineSpiller(pass, mf, vrm); +} } + +/// split - try splitting the current interval into pieces that may allocate +/// separately. Return true if successful. +bool InlineSpiller::split() { + splitAnalysis_.analyze(li_); + + if (const MachineLoop *loop = splitAnalysis_.getBestSplitLoop()) { + // We can split, but li_ may be left intact with fewer uses. + if (SplitEditor(splitAnalysis_, lis_, vrm_, *newIntervals_) + .splitAroundLoop(loop)) + return true; + } + + // Try splitting into single block intervals. + SplitAnalysis::BlockPtrSet blocks; + if (splitAnalysis_.getMultiUseBlocks(blocks)) { + if (SplitEditor(splitAnalysis_, lis_, vrm_, *newIntervals_) + .splitSingleBlocks(blocks)) + return true; + } + + // Try splitting inside a basic block. + if (const MachineBasicBlock *MBB = splitAnalysis_.getBlockForInsideSplit()) { + if (SplitEditor(splitAnalysis_, lis_, vrm_, *newIntervals_) + .splitInsideBlock(MBB)) + return true; + } + + // We may have been able to split out some uses, but the original interval is + // intact, and it should still be spilled. + return false; } /// allUsesAvailableAt - Return true if all registers used by OrigMI at @@ -237,7 +283,7 @@ void InlineSpiller::reMaterializeAll() { lis_.RemoveMachineInstrFromMaps(DefMI); vrm_.RemoveMachineInstrFromMaps(DefMI); DefMI->eraseFromParent(); - li_->removeValNo(VNI); + VNI->setIsDefAccurate(false); anyRemoved = true; } @@ -253,8 +299,8 @@ void InlineSpiller::reMaterializeAll() { MachineBasicBlock::iterator NextMI = MI; ++NextMI; if (NextMI != MI->getParent()->end() && !lis_.isNotInMIMap(NextMI)) { - SlotIndex NearIdx = lis_.getInstructionIndex(NextMI); - if (li_->liveAt(NearIdx)) + VNInfo *VNI = li_->getVNInfoAt(lis_.getInstructionIndex(NextMI)); + if (VNI && (VNI->hasPHIKill() || usedValues_.count(VNI))) continue; } DEBUG(dbgs() << "Removing debug info due to remat:" << "\t" << *MI); @@ -262,6 +308,24 @@ void InlineSpiller::reMaterializeAll() { } } +/// If MI is a load or store of stackSlot_, it can be removed. +bool InlineSpiller::coalesceStackAccess(MachineInstr *MI) { + int FI = 0; + unsigned reg; + if (!(reg = tii_.isLoadFromStackSlot(MI, FI)) && + !(reg = tii_.isStoreToStackSlot(MI, FI))) + return false; + + // We have a stack access. Is it the right register and slot? + if (reg != li_->reg || FI != stackSlot_) + return false; + + DEBUG(dbgs() << "Coalescing stack access: " << *MI); + lis_.RemoveMachineInstrFromMaps(MI); + MI->eraseFromParent(); + return true; +} + /// foldMemoryOperand - Try folding stack slot references in Ops into MI. /// Return true on success, and MI will be erased. bool InlineSpiller::foldMemoryOperand(MachineBasicBlock::iterator MI, @@ -323,9 +387,8 @@ void InlineSpiller::insertSpill(LiveInterval &NewLI, } void InlineSpiller::spill(LiveInterval *li, - std::vector &newIntervals, - SmallVectorImpl &spillIs, - SlotIndex *earliestIndex) { + SmallVectorImpl &newIntervals, + SmallVectorImpl &spillIs) { DEBUG(dbgs() << "Inline spilling " << *li << "\n"); assert(li->isSpillable() && "Attempting to spill already spilled value."); assert(!li->isStackSlot() && "Trying to spill a stack slot."); @@ -335,13 +398,18 @@ void InlineSpiller::spill(LiveInterval *li, rc_ = mri_.getRegClass(li->reg); spillIs_ = &spillIs; + if (split()) + return; + reMaterializeAll(); // Remat may handle everything. if (li_->empty()) return; - stackSlot_ = vrm_.assignVirt2StackSlot(li->reg); + stackSlot_ = vrm_.getStackSlot(li->reg); + if (stackSlot_ == VirtRegMap::NO_STACK_SLOT) + stackSlot_ = vrm_.assignVirt2StackSlot(li->reg); // Iterate over instructions using register. for (MachineRegisterInfo::reg_iterator RI = mri_.reg_begin(li->reg); @@ -365,6 +433,10 @@ void InlineSpiller::spill(LiveInterval *li, continue; } + // Stack slot accesses may coalesce away. + if (coalesceStackAccess(MI)) + continue; + // Analyze instruction. bool Reads, Writes; SmallVector Ops; diff --git a/lib/CodeGen/IntrinsicLowering.cpp b/lib/CodeGen/IntrinsicLowering.cpp index 03ae214..3852eba 100644 --- a/lib/CodeGen/IntrinsicLowering.cpp +++ b/lib/CodeGen/IntrinsicLowering.cpp @@ -481,7 +481,8 @@ void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) { Value *Ops[3]; Ops[0] = CI->getArgOperand(0); // Extend the amount to i32. - Ops[1] = Builder.CreateIntCast(CI->getArgOperand(1), Type::getInt32Ty(Context), + Ops[1] = Builder.CreateIntCast(CI->getArgOperand(1), + Type::getInt32Ty(Context), /* isSigned */ false); Ops[2] = Size; ReplaceCallWith("memset", CI, Ops, Ops+3, CI->getArgOperand(0)->getType()); diff --git a/lib/CodeGen/LLVMTargetMachine.cpp b/lib/CodeGen/LLVMTargetMachine.cpp index bf3137e..3603802 100644 --- a/lib/CodeGen/LLVMTargetMachine.cpp +++ b/lib/CodeGen/LLVMTargetMachine.cpp @@ -85,7 +85,7 @@ static bool getVerboseAsm() { case cl::BOU_UNSET: return TargetMachine::getAsmVerbosityDefault(); case cl::BOU_TRUE: return true; case cl::BOU_FALSE: return false; - } + } } // Enable or disable FastISel. Both options are needed, because @@ -139,8 +139,6 @@ bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM, getTarget().createMCInstPrinter(MAI.getAssemblerDialect(), MAI); // Create a code emitter if asked to show the encoding. - // - // FIXME: These are currently leaked. MCCodeEmitter *MCE = 0; if (ShowMCEncoding) MCE = getTarget().createCodeEmitter(*this, *Context); @@ -154,8 +152,6 @@ bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM, case CGFT_ObjectFile: { // Create the code emitter for the target if it exists. If not, .o file // emission fails. - // - // FIXME: These are currently leaked. MCCodeEmitter *MCE = getTarget().createCodeEmitter(*this, *Context); TargetAsmBackend *TAB = getTarget().createAsmBackend(TargetTriple); if (MCE == 0 || TAB == 0) @@ -180,12 +176,12 @@ bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM, FunctionPass *Printer = getTarget().createAsmPrinter(*this, *AsmStreamer); if (Printer == 0) return true; - + // If successful, createAsmPrinter took ownership of AsmStreamer. AsmStreamer.take(); - + PM.add(Printer); - + // Make sure the code model is set. setCodeModelForStatic(); PM.add(createGCInfoDeleter()); @@ -204,7 +200,7 @@ bool LLVMTargetMachine::addPassesToEmitMachineCode(PassManagerBase &PM, bool DisableVerify) { // Make sure the code model is set. setCodeModelForJIT(); - + // Add common CodeGen passes. MCContext *Ctx = 0; if (addCommonCodeGenPasses(PM, OptLevel, DisableVerify, Ctx)) @@ -216,19 +212,36 @@ bool LLVMTargetMachine::addPassesToEmitMachineCode(PassManagerBase &PM, return false; // success! } +/// addPassesToEmitMC - Add passes to the specified pass manager to get +/// machine code emitted with the MCJIT. This method returns true if machine +/// code is not supported. It fills the MCContext Ctx pointer which can be +/// used to build custom MCStreamer. +/// +bool LLVMTargetMachine::addPassesToEmitMC(PassManagerBase &PM, + MCContext *&Ctx, + CodeGenOpt::Level OptLevel, + bool DisableVerify) { + // Add common CodeGen passes. + if (addCommonCodeGenPasses(PM, OptLevel, DisableVerify, Ctx)) + return true; + // Make sure the code model is set. + setCodeModelForJIT(); + + return false; // success! +} + static void printNoVerify(PassManagerBase &PM, const char *Banner) { if (PrintMachineCode) PM.add(createMachineFunctionPrinterPass(dbgs(), Banner)); } static void printAndVerify(PassManagerBase &PM, - const char *Banner, - bool allowDoubleDefs = false) { + const char *Banner) { if (PrintMachineCode) PM.add(createMachineFunctionPrinterPass(dbgs(), Banner)); if (VerifyMachineCode) - PM.add(createMachineVerifierPass(allowDoubleDefs)); + PM.add(createMachineVerifierPass()); } /// addCommonCodeGenPasses - Add standard LLVM codegen passes used for both @@ -258,6 +271,11 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, PM.add(createPrintFunctionPass("\n\n*** Code after LSR ***\n", &dbgs())); } + PM.add(createGCLoweringPass()); + + // Make sure that no unreachable blocks are instruction selected. + PM.add(createUnreachableBlockEliminationPass()); + // Turn exception handling constructs into something the code generators can // handle. switch (getMCAsmInfo()->getExceptionHandlingType()) { @@ -269,26 +287,25 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, // pad is shared by multiple invokes and is also a target of a normal // edge from elsewhere. PM.add(createSjLjEHPass(getTargetLowering())); - PM.add(createDwarfEHPass(this, OptLevel==CodeGenOpt::None)); - break; + // FALLTHROUGH case ExceptionHandling::Dwarf: - PM.add(createDwarfEHPass(this, OptLevel==CodeGenOpt::None)); + PM.add(createDwarfEHPass(this)); break; case ExceptionHandling::None: PM.add(createLowerInvokePass(getTargetLowering())); + + // The lower invoke pass may create unreachable code. Remove it. + PM.add(createUnreachableBlockEliminationPass()); break; } - PM.add(createGCLoweringPass()); - - // Make sure that no unreachable blocks are instruction selected. - PM.add(createUnreachableBlockEliminationPass()); - if (OptLevel != CodeGenOpt::None && !DisableCGP) PM.add(createCodeGenPreparePass(getTargetLowering())); PM.add(createStackProtectorPass(getTargetLowering())); + addPreISel(PM, OptLevel); + if (PrintISelInput) PM.add(createPrintFunctionPass("\n\n" "*** Final LLVM Code input to ISel ***\n", @@ -300,13 +317,12 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, PM.add(createVerifierPass()); // Standard Lower-Level Passes. - + // Install a MachineModuleInfo class, which is an immutable pass that holds // all the per-module stuff we're generating, including MCContext. MachineModuleInfo *MMI = new MachineModuleInfo(*getMCAsmInfo()); PM.add(MMI); OutContext = &MMI->getContext(); // Return the MCContext specifically by-ref. - // Set up a MachineFunction for the rest of CodeGen to work on. PM.add(new MachineFunctionAnalysis(*this, OptLevel)); @@ -321,44 +337,43 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, return true; // Print the instruction selected machine code... - printAndVerify(PM, "After Instruction Selection", - /* allowDoubleDefs= */ true); + printAndVerify(PM, "After Instruction Selection"); // Optimize PHIs before DCE: removing dead PHI cycles may make more // instructions dead. if (OptLevel != CodeGenOpt::None) PM.add(createOptimizePHIsPass()); + // If the target requests it, assign local variables to stack slots relative + // to one another and simplify frame index references where possible. + PM.add(createLocalStackSlotAllocationPass()); + if (OptLevel != CodeGenOpt::None) { // With optimization, dead code should already be eliminated. However // there is one known exception: lowered code for arguments that are only // used by tail calls, where the tail calls reuse the incoming stack // arguments directly (see t11 in test/CodeGen/X86/sibcall.ll). PM.add(createDeadMachineInstructionElimPass()); - printAndVerify(PM, "After codegen DCE pass", - /* allowDoubleDefs= */ true); + printAndVerify(PM, "After codegen DCE pass"); - PM.add(createOptimizeExtsPass()); + PM.add(createPeepholeOptimizerPass()); if (!DisableMachineLICM) PM.add(createMachineLICMPass()); PM.add(createMachineCSEPass()); if (!DisableMachineSink) PM.add(createMachineSinkingPass()); - printAndVerify(PM, "After Machine LICM, CSE and Sinking passes", - /* allowDoubleDefs= */ true); + printAndVerify(PM, "After Machine LICM, CSE and Sinking passes"); } // Pre-ra tail duplication. if (OptLevel != CodeGenOpt::None && !DisableEarlyTailDup) { PM.add(createTailDuplicatePass(true)); - printAndVerify(PM, "After Pre-RegAlloc TailDuplicate", - /* allowDoubleDefs= */ true); + printAndVerify(PM, "After Pre-RegAlloc TailDuplicate"); } // Run pre-ra passes. if (addPreRegAlloc(PM, OptLevel)) - printAndVerify(PM, "After PreRegAlloc passes", - /* allowDoubleDefs= */ true); + printAndVerify(PM, "After PreRegAlloc passes"); // Perform register allocation. PM.add(createRegisterAllocator(OptLevel)); diff --git a/lib/CodeGen/LiveInterval.cpp b/lib/CodeGen/LiveInterval.cpp index ad57284..59f380a 100644 --- a/lib/CodeGen/LiveInterval.cpp +++ b/lib/CodeGen/LiveInterval.cpp @@ -166,6 +166,56 @@ bool LiveInterval::overlaps(SlotIndex Start, SlotIndex End) const { return I != begin() && (--I)->end > Start; } + +/// ValNo is dead, remove it. If it is the largest value number, just nuke it +/// (and any other deleted values neighboring it), otherwise mark it as ~1U so +/// it can be nuked later. +void LiveInterval::markValNoForDeletion(VNInfo *ValNo) { + if (ValNo->id == getNumValNums()-1) { + do { + valnos.pop_back(); + } while (!valnos.empty() && valnos.back()->isUnused()); + } else { + ValNo->setIsUnused(true); + } +} + +/// RenumberValues - Renumber all values in order of appearance and delete the +/// remaining unused values. +void LiveInterval::RenumberValues(LiveIntervals &lis) { + SmallPtrSet Seen; + bool seenPHIDef = false; + valnos.clear(); + for (const_iterator I = begin(), E = end(); I != E; ++I) { + VNInfo *VNI = I->valno; + if (!Seen.insert(VNI)) + continue; + assert(!VNI->isUnused() && "Unused valno used by live range"); + VNI->id = (unsigned)valnos.size(); + valnos.push_back(VNI); + VNI->setHasPHIKill(false); + if (VNI->isPHIDef()) + seenPHIDef = true; + } + + // Recompute phi kill flags. + if (!seenPHIDef) + return; + for (const_vni_iterator I = vni_begin(), E = vni_end(); I != E; ++I) { + VNInfo *VNI = *I; + if (!VNI->isPHIDef()) + continue; + const MachineBasicBlock *PHIBB = lis.getMBBFromIndex(VNI->def); + assert(PHIBB && "No basic block for phi-def"); + for (MachineBasicBlock::const_pred_iterator PI = PHIBB->pred_begin(), + PE = PHIBB->pred_end(); PI != PE; ++PI) { + VNInfo *KVNI = getVNInfoAt(lis.getMBBEndIdx(*PI).getPrevSlot()); + if (KVNI) + KVNI->setHasPHIKill(true); + } + } +} + /// extendIntervalEndTo - This method is used when we want to extend the range /// specified by I to end at the specified endpoint. To do this, we should /// merge and eliminate all ranges that this will overlap with. The iterator is @@ -175,7 +225,7 @@ void LiveInterval::extendIntervalEndTo(Ranges::iterator I, SlotIndex NewEnd) { VNInfo *ValNo = I->valno; // Search for the first interval that we can't merge with. - Ranges::iterator MergeTo = next(I); + Ranges::iterator MergeTo = llvm::next(I); for (; MergeTo != ranges.end() && NewEnd >= MergeTo->end; ++MergeTo) { assert(MergeTo->valno == ValNo && "Cannot merge with differing values!"); } @@ -184,11 +234,11 @@ void LiveInterval::extendIntervalEndTo(Ranges::iterator I, SlotIndex NewEnd) { I->end = std::max(NewEnd, prior(MergeTo)->end); // Erase any dead ranges. - ranges.erase(next(I), MergeTo); + ranges.erase(llvm::next(I), MergeTo); // If the newly formed range now touches the range after it and if they have // the same value number, merge the two ranges into one range. - Ranges::iterator Next = next(I); + Ranges::iterator Next = llvm::next(I); if (Next != ranges.end() && Next->start <= I->end && Next->valno == ValNo) { I->end = Next->end; ranges.erase(Next); @@ -227,7 +277,7 @@ LiveInterval::extendIntervalStartTo(Ranges::iterator I, SlotIndex NewStart) { MergeTo->end = I->end; } - ranges.erase(next(MergeTo), next(I)); + ranges.erase(llvm::next(MergeTo), llvm::next(I)); return MergeTo; } @@ -280,7 +330,7 @@ LiveInterval::addRangeFrom(LiveRange LR, iterator From) { return ranges.insert(it, LR); } -/// isInOneLiveRange - Return true if the range specified is entirely in +/// isInOneLiveRange - Return true if the range specified is entirely in /// a single LiveRange of the live interval. bool LiveInterval::isInOneLiveRange(SlotIndex Start, SlotIndex End) { Ranges::iterator I = std::upper_bound(ranges.begin(), ranges.end(), Start); @@ -314,16 +364,8 @@ void LiveInterval::removeRange(SlotIndex Start, SlotIndex End, break; } if (isDead) { - // Now that ValNo is dead, remove it. If it is the largest value - // number, just nuke it (and any other deleted values neighboring it), - // otherwise mark it as ~1U so it can be nuked later. - if (ValNo->id == getNumValNums()-1) { - do { - valnos.pop_back(); - } while (!valnos.empty() && valnos.back()->isUnused()); - } else { - ValNo->setIsUnused(true); - } + // Now that ValNo is dead, remove it. + markValNoForDeletion(ValNo); } } @@ -345,7 +387,7 @@ void LiveInterval::removeRange(SlotIndex Start, SlotIndex End, I->end = Start; // Trim the old interval. // Insert the new one. - ranges.insert(next(I), LiveRange(End, OldEnd, ValNo)); + ranges.insert(llvm::next(I), LiveRange(End, OldEnd, ValNo)); } /// removeValNo - Remove all the ranges defined by the specified value#. @@ -359,21 +401,13 @@ void LiveInterval::removeValNo(VNInfo *ValNo) { if (I->valno == ValNo) ranges.erase(I); } while (I != E); - // Now that ValNo is dead, remove it. If it is the largest value - // number, just nuke it (and any other deleted values neighboring it), - // otherwise mark it as ~1U so it can be nuked later. - if (ValNo->id == getNumValNums()-1) { - do { - valnos.pop_back(); - } while (!valnos.empty() && valnos.back()->isUnused()); - } else { - ValNo->setIsUnused(true); - } + // Now that ValNo is dead, remove it. + markValNoForDeletion(ValNo); } /// getLiveRangeContaining - Return the live range that contains the /// specified index, or null if there is none. -LiveInterval::const_iterator +LiveInterval::const_iterator LiveInterval::FindLiveRangeContaining(SlotIndex Idx) const { const_iterator It = std::upper_bound(begin(), end(), Idx); if (It != ranges.begin()) { @@ -385,7 +419,7 @@ LiveInterval::FindLiveRangeContaining(SlotIndex Idx) const { return end(); } -LiveInterval::iterator +LiveInterval::iterator LiveInterval::FindLiveRangeContaining(SlotIndex Idx) { iterator It = std::upper_bound(begin(), end(), Idx); if (It != begin()) { @@ -393,7 +427,7 @@ LiveInterval::FindLiveRangeContaining(SlotIndex Idx) { if (It->contains(Idx)) return It; } - + return end(); } @@ -425,11 +459,11 @@ VNInfo *LiveInterval::findDefinedVNInfoForStackInt(unsigned reg) const { /// the intervals are not joinable, this aborts. void LiveInterval::join(LiveInterval &Other, const int *LHSValNoAssignments, - const int *RHSValNoAssignments, + const int *RHSValNoAssignments, SmallVector &NewVNInfo, MachineRegisterInfo *MRI) { // Determine if any of our live range values are mapped. This is uncommon, so - // we want to avoid the interval scan if not. + // we want to avoid the interval scan if not. bool MustMapCurValNos = false; unsigned NumVals = getNumValNums(); unsigned NumNewVals = NewVNInfo.size(); @@ -449,7 +483,7 @@ void LiveInterval::join(LiveInterval &Other, ++OutIt; for (iterator I = OutIt, E = end(); I != E; ++I) { OutIt->valno = NewVNInfo[LHSValNoAssignments[I->valno->id]]; - + // If this live range has the same value # as its immediate predecessor, // and if they are neighbors, remove one LiveRange. This happens when we // have [0,3:0)[4,7:1) and map 0/1 onto the same value #. @@ -460,12 +494,12 @@ void LiveInterval::join(LiveInterval &Other, OutIt->start = I->start; OutIt->end = I->end; } - + // Didn't merge, on to the next one. ++OutIt; } } - + // If we merge some live ranges, chop off the end. ranges.erase(OutIt, end()); } @@ -483,7 +517,7 @@ void LiveInterval::join(LiveInterval &Other, if (VNI) { if (NumValNos >= NumVals) valnos.push_back(VNI); - else + else valnos[NumValNos] = VNI; VNI->id = NumValNos++; // Renumber val#. } @@ -502,25 +536,13 @@ void LiveInterval::join(LiveInterval &Other, } ComputeJoinedWeight(Other); - - // Update regalloc hint if currently there isn't one. - if (TargetRegisterInfo::isVirtualRegister(reg) && - TargetRegisterInfo::isVirtualRegister(Other.reg)) { - std::pair Hint = MRI->getRegAllocationHint(reg); - if (Hint.first == 0 && Hint.second == 0) { - std::pair OtherHint = - MRI->getRegAllocationHint(Other.reg); - if (OtherHint.first || OtherHint.second) - MRI->setRegAllocationHint(reg, OtherHint.first, OtherHint.second); - } - } } /// MergeRangesInAsValue - Merge all of the intervals in RHS into this live /// interval as the specified value number. The LiveRanges in RHS are /// allowed to overlap with LiveRanges in the current interval, but only if /// the overlapping LiveRanges have the specified value number. -void LiveInterval::MergeRangesInAsValue(const LiveInterval &RHS, +void LiveInterval::MergeRangesInAsValue(const LiveInterval &RHS, VNInfo *LHSValNo) { // TODO: Make this more efficient. iterator InsertPos = begin(); @@ -569,7 +591,7 @@ void LiveInterval::MergeValueInAsValue( // If this trimmed away the whole range, ignore it. if (Start == End) continue; } - + // Map the valno in the other live range to the current live range. IP = addRangeFrom(LiveRange(Start, End, LHSValNo), IP); } @@ -584,18 +606,10 @@ void LiveInterval::MergeValueInAsValue( if (I->valno == V1) { isDead = false; break; - } - if (isDead) { - // Now that V1 is dead, remove it. If it is the largest value number, - // just nuke it (and any other deleted values neighboring it), otherwise - // mark it as ~1U so it can be nuked later. - if (V1->id == getNumValNums()-1) { - do { - valnos.pop_back(); - } while (!valnos.empty() && valnos.back()->isUnused()); - } else { - V1->setIsUnused(true); } + if (isDead) { + // Now that V1 is dead, remove it. + markValNoForDeletion(V1); } } } @@ -609,7 +623,7 @@ void LiveInterval::MergeInClobberRanges(LiveIntervals &li_, const LiveInterval &Clobbers, VNInfo::Allocator &VNInfoAllocator) { if (Clobbers.empty()) return; - + DenseMap ValNoMaps; VNInfo *UnusedValNo = 0; iterator IP = begin(); @@ -679,10 +693,10 @@ void LiveInterval::MergeInClobberRange(LiveIntervals &li_, // for unknown values, use it. VNInfo *ClobberValNo = getNextValue(li_.getInvalidIndex(), 0, false, VNInfoAllocator); - + iterator IP = begin(); IP = std::upper_bound(IP, end(), Start); - + // If the start of this range overlaps with an existing liverange, trim it. if (IP != begin() && IP[-1].end > Start) { Start = IP[-1].end; @@ -695,7 +709,7 @@ void LiveInterval::MergeInClobberRange(LiveIntervals &li_, // If this trimmed away the whole range, ignore it. if (Start == End) return; } - + // Insert the clobber interval. addRangeFrom(LiveRange(Start, End, ClobberValNo), IP); } @@ -722,7 +736,7 @@ VNInfo* LiveInterval::MergeValueNumberInto(VNInfo *V1, VNInfo *V2) { for (iterator I = begin(); I != end(); ) { iterator LR = I++; if (LR->valno != V1) continue; // Not a V1 LiveRange. - + // Okay, we found a V1 live range. If it had a previous, touching, V2 live // range, extend it. if (LR != begin()) { @@ -736,11 +750,11 @@ VNInfo* LiveInterval::MergeValueNumberInto(VNInfo *V1, VNInfo *V2) { LR = Prev; } } - + // Okay, now we have a V1 or V2 live range that is maximally merged forward. // Ensure that it is a V2 live-range. LR->valno = V2; - + // If we can merge it into later V2 live ranges, do so now. We ignore any // following V1 live ranges, as they will be merged in subsequent iterations // of the loop. @@ -752,18 +766,10 @@ VNInfo* LiveInterval::MergeValueNumberInto(VNInfo *V1, VNInfo *V2) { } } } - - // Now that V1 is dead, remove it. If it is the largest value number, just - // nuke it (and any other deleted values neighboring it), otherwise mark it as - // ~1U so it can be nuked later. - if (V1->id == getNumValNums()-1) { - do { - valnos.pop_back(); - } while (valnos.back()->isUnused()); - } else { - V1->setIsUnused(true); - } - + + // Now that V1 is dead, remove it. + markValNoForDeletion(V1); + return V2; } diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp index 194d03d..2726fc3 100644 --- a/lib/CodeGen/LiveIntervalAnalysis.cpp +++ b/lib/CodeGen/LiveIntervalAnalysis.cpp @@ -47,7 +47,7 @@ using namespace llvm; // Hidden options for help debugging. -static cl::opt DisableReMat("disable-rematerialization", +static cl::opt DisableReMat("disable-rematerialization", cl::init(false), cl::Hidden); STATISTIC(numIntervals , "Number of original intervals"); @@ -55,22 +55,24 @@ STATISTIC(numFolds , "Number of loads/stores folded into instructions"); STATISTIC(numSplits , "Number of intervals split"); char LiveIntervals::ID = 0; -static RegisterPass X("liveintervals", "Live Interval Analysis"); +INITIALIZE_PASS(LiveIntervals, "liveintervals", + "Live Interval Analysis", false, false); void LiveIntervals::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); AU.addRequired(); AU.addPreserved(); - AU.addPreserved(); AU.addRequired(); - AU.addPreservedID(MachineLoopInfoID); + AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); AU.addPreservedID(MachineDominatorsID); - + if (!StrongPHIElim) { AU.addPreservedID(PHIEliminationID); AU.addRequiredID(PHIEliminationID); } - + AU.addRequiredID(TwoAddressInstructionPassID); AU.addPreserved(); AU.addRequired(); @@ -84,7 +86,7 @@ void LiveIntervals::releaseMemory() { for (DenseMap::iterator I = r2iMap_.begin(), E = r2iMap_.end(); I != E; ++I) delete I->second; - + r2iMap_.clear(); // Release VNInfo memory regions, VNInfo objects don't need to be dtor'd. @@ -188,10 +190,6 @@ bool LiveIntervals::conflictsWithPhysReg(const LiveInterval &li, const MachineInstr &MI = *I; // Allow copies to and from li.reg - unsigned SrcReg, DstReg, SrcSubReg, DstSubReg; - if (tii_->isMoveInstr(MI, SrcReg, DstReg, SrcSubReg, DstSubReg)) - if (SrcReg == li.reg || DstReg == li.reg) - continue; if (MI.isCopy()) if (MI.getOperand(0).getReg() == li.reg || MI.getOperand(1).getReg() == li.reg) @@ -278,7 +276,7 @@ bool MultipleDefsBySameMI(const MachineInstr &MI, unsigned MOIdx) { /// isPartialRedef - Return true if the specified def at the specific index is /// partially re-defining the specified live interval. A common case of this is -/// a definition of the sub-register. +/// a definition of the sub-register. bool LiveIntervals::isPartialRedef(SlotIndex MIIdx, MachineOperand &MO, LiveInterval &interval) { if (!MO.getSubReg() || MO.isEarlyClobber()) @@ -324,9 +322,7 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, mi->addRegisterDefined(interval.reg); MachineInstr *CopyMI = NULL; - unsigned SrcReg, DstReg, SrcSubReg, DstSubReg; - if (mi->isCopyLike() || - tii_->isMoveInstr(*mi, SrcReg, DstReg, SrcSubReg, DstSubReg)) { + if (mi->isCopyLike()) { CopyMI = mi; } @@ -420,8 +416,8 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, // def-and-use register operand. // It may also be partial redef like this: - // 80 %reg1041:6 = VSHRNv4i16 %reg1034, 12, pred:14, pred:%reg0 - // 120 %reg1041:5 = VSHRNv4i16 %reg1039, 12, pred:14, pred:%reg0 + // 80 %reg1041:6 = VSHRNv4i16 %reg1034, 12, pred:14, pred:%reg0 + // 120 %reg1041:5 = VSHRNv4i16 %reg1039, 12, pred:14, pred:%reg0 bool PartReDef = isPartialRedef(MIIdx, MO, interval); if (PartReDef || mi->isRegTiedToUseOperand(MOIdx)) { // If this is a two-address definition, then we have already processed @@ -454,11 +450,9 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, OldValNo->setCopy(0); // A re-def may be a copy. e.g. %reg1030:6 = VMOVD %reg1026, ... - unsigned SrcReg, DstReg, SrcSubReg, DstSubReg; - if (PartReDef && (mi->isCopyLike() || - tii_->isMoveInstr(*mi, SrcReg, DstReg, SrcSubReg, DstSubReg))) + if (PartReDef && mi->isCopyLike()) OldValNo->setCopy(&*mi); - + // Add the new live interval which replaces the range for the input copy. LiveRange LR(DefIndex, RedefIndex, ValNo); DEBUG(dbgs() << " replace range with " << LR); @@ -485,12 +479,10 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, VNInfo *ValNo; MachineInstr *CopyMI = NULL; - unsigned SrcReg, DstReg, SrcSubReg, DstSubReg; - if (mi->isCopyLike() || - tii_->isMoveInstr(*mi, SrcReg, DstReg, SrcSubReg, DstSubReg)) + if (mi->isCopyLike()) CopyMI = mi; ValNo = interval.getNextValue(defIndex, CopyMI, true, VNInfoAllocator); - + SlotIndex killIndex = getMBBEndIdx(mbb); LiveRange LR(defIndex, killIndex, ValNo); interval.addRange(LR); @@ -567,10 +559,10 @@ void LiveIntervals::handlePhysicalRegisterDef(MachineBasicBlock *MBB, goto exit; } } - + baseIndex = baseIndex.getNextIndex(); } - + // The only case we should have a dead physreg here without a killing or // instruction where we know it's dead is if it is live-in to the function // and never used. Another possible case is the implicit use of the @@ -602,9 +594,7 @@ void LiveIntervals::handleRegisterDef(MachineBasicBlock *MBB, getOrCreateInterval(MO.getReg())); else if (allocatableRegs_[MO.getReg()]) { MachineInstr *CopyMI = NULL; - unsigned SrcReg, DstReg, SrcSubReg, DstSubReg; - if (MI->isCopyLike() || - tii_->isMoveInstr(*MI, SrcReg, DstReg, SrcSubReg, DstSubReg)) + if (MI->isCopyLike()) CopyMI = MI; handlePhysicalRegisterDef(MBB, MI, MIIdx, MO, getOrCreateInterval(MO.getReg()), CopyMI); @@ -696,7 +686,7 @@ void LiveIntervals::handleLiveInRegister(MachineBasicBlock *MBB, /// registers. for some ordering of the machine instructions [1,N] a /// live interval is an interval [i, j) where 1 <= i <= j < N for /// which a variable is live -void LiveIntervals::computeIntervals() { +void LiveIntervals::computeIntervals() { DEBUG(dbgs() << "********** COMPUTING LIVE INTERVALS **********\n" << "********** Function: " << ((Value*)mf_->getFunction())->getName() << '\n'); @@ -723,11 +713,11 @@ void LiveIntervals::computeIntervals() { handleLiveInRegister(MBB, MIIndex, getOrCreateInterval(*AS), true); } - + // Skip over empty initial indices. if (getInstructionFromIndex(MIIndex) == 0) MIIndex = indexes_->getNextNonNullIndex(MIIndex); - + for (MachineBasicBlock::iterator MI = MBB->begin(), miEnd = MBB->end(); MI != miEnd; ++MI) { DEBUG(dbgs() << MIIndex << "\t" << *MI); @@ -746,7 +736,7 @@ void LiveIntervals::computeIntervals() { else if (MO.isUndef()) UndefUses.push_back(MO.getReg()); } - + // Move to the next instr slot. MIIndex = indexes_->getNextNonNullIndex(MIIndex); } @@ -791,7 +781,7 @@ unsigned LiveIntervals::getReMatImplicitUse(const LiveInterval &li, unsigned Reg = MO.getReg(); if (Reg == 0 || Reg == li.reg) continue; - + if (TargetRegisterInfo::isPhysicalRegister(Reg) && !allocatableRegs_[Reg]) continue; @@ -810,7 +800,7 @@ unsigned LiveIntervals::getReMatImplicitUse(const LiveInterval &li, /// which reaches the given instruction also reaches the specified use index. bool LiveIntervals::isValNoAvailableAt(const LiveInterval &li, MachineInstr *MI, SlotIndex UseIdx) const { - SlotIndex Index = getInstructionIndex(MI); + SlotIndex Index = getInstructionIndex(MI); VNInfo *ValNo = li.FindLiveRangeContaining(Index)->valno; LiveInterval::const_iterator UI = li.FindLiveRangeContaining(UseIdx); return UI != li.end() && UI->valno == ValNo; @@ -915,7 +905,7 @@ static bool FilterFoldedOps(MachineInstr *MI, } return false; } - + /// tryFoldMemoryOperand - Attempts to fold either a spill / restore from /// slot / to reg or any rematerialized load into ith operand of specified @@ -1035,7 +1025,7 @@ void LiveIntervals::rewriteImplicitOps(const LiveInterval &li, /// for addIntervalsForSpills to rewrite uses / defs for the given live range. bool LiveIntervals:: rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI, - bool TrySplit, SlotIndex index, SlotIndex end, + bool TrySplit, SlotIndex index, SlotIndex end, MachineInstr *MI, MachineInstr *ReMatOrigDefMI, MachineInstr *ReMatDefMI, unsigned Slot, int LdSlot, @@ -1094,7 +1084,7 @@ rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI, // keep the src/dst regs pinned. // // Keep track of whether we replace a use and/or def so that we can - // create the spill interval with the appropriate range. + // create the spill interval with the appropriate range. SmallVector Ops; tie(HasUse, HasDef) = MI->readsWritesVirtualRegister(Reg, &Ops); @@ -1156,7 +1146,7 @@ rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI, if (mopj.isImplicit()) rewriteImplicitOps(li, MI, NewVReg, vrm); } - + if (CreatedNewVReg) { if (DefIsReMat) { vrm.setVirtIsReMaterialized(NewVReg, ReMatDefMI); @@ -1696,7 +1686,7 @@ addIntervalsForSpills(const LiveInterval &li, if (NeedStackSlot && vrm.getPreSplitReg(li.reg) == 0) { if (vrm.getStackSlot(li.reg) == VirtRegMap::NO_STACK_SLOT) Slot = vrm.assignVirt2StackSlot(li.reg); - + // This case only occurs when the prealloc splitter has already assigned // a stack slot to this vreg. else @@ -1753,7 +1743,7 @@ addIntervalsForSpills(const LiveInterval &li, Ops.push_back(j); if (MO.isDef()) continue; - if (isReMat || + if (isReMat || (!FoundUse && !alsoFoldARestore(Id, index, VReg, RestoreMBBs, RestoreIdxes))) { // MI has two-address uses of the same register. If the use @@ -1866,7 +1856,6 @@ addIntervalsForSpills(const LiveInterval &li, for (unsigned i = 0, e = NewLIs.size(); i != e; ++i) { LiveInterval *LI = NewLIs[i]; if (!LI->empty()) { - LI->weight /= SlotIndex::NUM * getApproximateInstructionCount(*LI); if (!AddedKill.count(LI)) { LiveRange *LR = &LI->ranges[LI->ranges.size()-1]; SlotIndex LastUseIdx = LR->end.getBaseIndex(); @@ -1899,7 +1888,7 @@ bool LiveIntervals::hasAllocatableSuperReg(unsigned Reg) const { /// getRepresentativeReg - Find the largest super register of the specified /// physical register. unsigned LiveIntervals::getRepresentativeReg(unsigned Reg) const { - // Find the largest super-register that is allocatable. + // Find the largest super-register that is allocatable. unsigned BestReg = Reg; for (const unsigned* AS = tri_->getSuperRegisters(Reg); *AS; ++AS) { unsigned SuperReg = *AS; @@ -2013,7 +2002,7 @@ LiveRange LiveIntervals::addLiveRangeToEndOfBlock(unsigned reg, SlotIndex(getInstructionIndex(startInst).getDefIndex()), getMBBEndIdx(startInst->getParent()), VN); Interval.addRange(LR); - + return LR; } diff --git a/lib/CodeGen/LiveStackAnalysis.cpp b/lib/CodeGen/LiveStackAnalysis.cpp index 709e2c6..b5c385f 100644 --- a/lib/CodeGen/LiveStackAnalysis.cpp +++ b/lib/CodeGen/LiveStackAnalysis.cpp @@ -25,7 +25,8 @@ using namespace llvm; char LiveStacks::ID = 0; -static RegisterPass X("livestacks", "Live Stack Slot Analysis"); +INITIALIZE_PASS(LiveStacks, "livestacks", + "Live Stack Slot Analysis", false, false); void LiveStacks::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); diff --git a/lib/CodeGen/LiveVariables.cpp b/lib/CodeGen/LiveVariables.cpp index 41b891d..375307b 100644 --- a/lib/CodeGen/LiveVariables.cpp +++ b/lib/CodeGen/LiveVariables.cpp @@ -42,7 +42,8 @@ using namespace llvm; char LiveVariables::ID = 0; -static RegisterPass X("livevars", "Live Variable Analysis"); +INITIALIZE_PASS(LiveVariables, "livevars", + "Live Variable Analysis", false, false); void LiveVariables::getAnalysisUsage(AnalysisUsage &AU) const { @@ -482,21 +483,6 @@ void LiveVariables::UpdatePhysRegDefs(MachineInstr *MI, } } -namespace { - struct RegSorter { - const TargetRegisterInfo *TRI; - - RegSorter(const TargetRegisterInfo *tri) : TRI(tri) { } - bool operator()(unsigned A, unsigned B) { - if (TRI->isSubRegister(A, B)) - return true; - else if (TRI->isSubRegister(B, A)) - return false; - return A < B; - } - }; -} - bool LiveVariables::runOnMachineFunction(MachineFunction &mf) { MF = &mf; MRI = &mf.getRegInfo(); diff --git a/lib/CodeGen/LocalStackSlotAllocation.cpp b/lib/CodeGen/LocalStackSlotAllocation.cpp new file mode 100644 index 0000000..7e366f0 --- /dev/null +++ b/lib/CodeGen/LocalStackSlotAllocation.cpp @@ -0,0 +1,354 @@ +//===- LocalStackSlotAllocation.cpp - Pre-allocate locals to stack slots --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass assigns local frame indices to stack slots relative to one another +// and allocates additional base registers to access them when the target +// estimates the are likely to be out of range of stack pointer and frame +// pointer relative addressing. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "localstackalloc" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Instructions.h" +#include "llvm/Intrinsics.h" +#include "llvm/LLVMContext.h" +#include "llvm/Module.h" +#include "llvm/Pass.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetFrameInfo.h" + +using namespace llvm; + +STATISTIC(NumAllocations, "Number of frame indices allocated into local block"); +STATISTIC(NumBaseRegisters, "Number of virtual frame base registers allocated"); +STATISTIC(NumReplacements, "Number of frame indices references replaced"); + +namespace { + class FrameRef { + MachineBasicBlock::iterator MI; // Instr referencing the frame + int64_t LocalOffset; // Local offset of the frame idx referenced + public: + FrameRef(MachineBasicBlock::iterator I, int64_t Offset) : + MI(I), LocalOffset(Offset) {} + bool operator<(const FrameRef &RHS) const { + return LocalOffset < RHS.LocalOffset; + } + MachineBasicBlock::iterator getMachineInstr() { return MI; } + }; + + class LocalStackSlotPass: public MachineFunctionPass { + SmallVector LocalOffsets; + + void AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx, int64_t &Offset, + bool StackGrowsDown, unsigned &MaxAlign); + void calculateFrameObjectOffsets(MachineFunction &Fn); + bool insertFrameReferenceRegisters(MachineFunction &Fn); + public: + static char ID; // Pass identification, replacement for typeid + explicit LocalStackSlotPass() : MachineFunctionPass(ID) { } + bool runOnMachineFunction(MachineFunction &MF); + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); + MachineFunctionPass::getAnalysisUsage(AU); + } + const char *getPassName() const { + return "Local Stack Slot Allocation"; + } + + private: + }; +} // end anonymous namespace + +char LocalStackSlotPass::ID = 0; + +FunctionPass *llvm::createLocalStackSlotAllocationPass() { + return new LocalStackSlotPass(); +} + +bool LocalStackSlotPass::runOnMachineFunction(MachineFunction &MF) { + MachineFrameInfo *MFI = MF.getFrameInfo(); + const TargetRegisterInfo *TRI = MF.getTarget().getRegisterInfo(); + unsigned LocalObjectCount = MFI->getObjectIndexEnd(); + + // If the target doesn't want/need this pass, or if there are no locals + // to consider, early exit. + if (!TRI->requiresVirtualBaseRegisters(MF) || LocalObjectCount == 0) + return true; + + // Make sure we have enough space to store the local offsets. + LocalOffsets.resize(MFI->getObjectIndexEnd()); + + // Lay out the local blob. + calculateFrameObjectOffsets(MF); + + // Insert virtual base registers to resolve frame index references. + bool UsedBaseRegs = insertFrameReferenceRegisters(MF); + + // Tell MFI whether any base registers were allocated. PEI will only + // want to use the local block allocations from this pass if there were any. + // Otherwise, PEI can do a bit better job of getting the alignment right + // without a hole at the start since it knows the alignment of the stack + // at the start of local allocation, and this pass doesn't. + MFI->setUseLocalStackAllocationBlock(UsedBaseRegs); + + return true; +} + +/// AdjustStackOffset - Helper function used to adjust the stack frame offset. +void LocalStackSlotPass::AdjustStackOffset(MachineFrameInfo *MFI, + int FrameIdx, int64_t &Offset, + bool StackGrowsDown, + unsigned &MaxAlign) { + // If the stack grows down, add the object size to find the lowest address. + if (StackGrowsDown) + Offset += MFI->getObjectSize(FrameIdx); + + unsigned Align = MFI->getObjectAlignment(FrameIdx); + + // If the alignment of this object is greater than that of the stack, then + // increase the stack alignment to match. + MaxAlign = std::max(MaxAlign, Align); + + // Adjust to alignment boundary. + Offset = (Offset + Align - 1) / Align * Align; + + int64_t LocalOffset = StackGrowsDown ? -Offset : Offset; + DEBUG(dbgs() << "Allocate FI(" << FrameIdx << ") to local offset " + << LocalOffset << "\n"); + // Keep the offset available for base register allocation + LocalOffsets[FrameIdx] = LocalOffset; + // And tell MFI about it for PEI to use later + MFI->mapLocalFrameObject(FrameIdx, LocalOffset); + + if (!StackGrowsDown) + Offset += MFI->getObjectSize(FrameIdx); + + ++NumAllocations; +} + +/// calculateFrameObjectOffsets - Calculate actual frame offsets for all of the +/// abstract stack objects. +/// +void LocalStackSlotPass::calculateFrameObjectOffsets(MachineFunction &Fn) { + // Loop over all of the stack objects, assigning sequential addresses... + MachineFrameInfo *MFI = Fn.getFrameInfo(); + const TargetFrameInfo &TFI = *Fn.getTarget().getFrameInfo(); + bool StackGrowsDown = + TFI.getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown; + int64_t Offset = 0; + unsigned MaxAlign = 0; + + // Make sure that the stack protector comes before the local variables on the + // stack. + SmallSet LargeStackObjs; + if (MFI->getStackProtectorIndex() >= 0) { + AdjustStackOffset(MFI, MFI->getStackProtectorIndex(), Offset, + StackGrowsDown, MaxAlign); + + // Assign large stack objects first. + for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) { + if (MFI->isDeadObjectIndex(i)) + continue; + if (MFI->getStackProtectorIndex() == (int)i) + continue; + if (!MFI->MayNeedStackProtector(i)) + continue; + + AdjustStackOffset(MFI, i, Offset, StackGrowsDown, MaxAlign); + LargeStackObjs.insert(i); + } + } + + // Then assign frame offsets to stack objects that are not used to spill + // callee saved registers. + for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) { + if (MFI->isDeadObjectIndex(i)) + continue; + if (MFI->getStackProtectorIndex() == (int)i) + continue; + if (LargeStackObjs.count(i)) + continue; + + AdjustStackOffset(MFI, i, Offset, StackGrowsDown, MaxAlign); + } + + // Remember how big this blob of stack space is + MFI->setLocalFrameSize(Offset); + MFI->setLocalFrameMaxAlign(MaxAlign); +} + +static inline bool +lookupCandidateBaseReg(const SmallVector, 8> &Regs, + std::pair &RegOffset, + int64_t FrameSizeAdjust, + int64_t LocalFrameOffset, + const MachineInstr *MI, + const TargetRegisterInfo *TRI) { + unsigned e = Regs.size(); + for (unsigned i = 0; i < e; ++i) { + RegOffset = Regs[i]; + // Check if the relative offset from the where the base register references + // to the target address is in range for the instruction. + int64_t Offset = FrameSizeAdjust + LocalFrameOffset - RegOffset.second; + if (TRI->isFrameOffsetLegal(MI, Offset)) + return true; + } + return false; +} + +bool LocalStackSlotPass::insertFrameReferenceRegisters(MachineFunction &Fn) { + // Scan the function's instructions looking for frame index references. + // For each, ask the target if it wants a virtual base register for it + // based on what we can tell it about where the local will end up in the + // stack frame. If it wants one, re-use a suitable one we've previously + // allocated, or if there isn't one that fits the bill, allocate a new one + // and ask the target to create a defining instruction for it. + bool UsedBaseReg = false; + + MachineFrameInfo *MFI = Fn.getFrameInfo(); + const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo(); + const TargetFrameInfo &TFI = *Fn.getTarget().getFrameInfo(); + bool StackGrowsDown = + TFI.getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown; + MachineBasicBlock::iterator InsertionPt = Fn.begin()->begin(); + + // Collect all of the instructions in the block that reference + // a frame index. Also store the frame index referenced to ease later + // lookup. (For any insn that has more than one FI reference, we arbitrarily + // choose the first one). + SmallVector FrameReferenceInsns; + // A base register definition is a register+offset pair. + SmallVector, 8> BaseRegisters; + + + for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB) { + for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) { + MachineInstr *MI = I; + // Debug value instructions can't be out of range, so they don't need + // any updates. + if (MI->isDebugValue()) + continue; + // For now, allocate the base register(s) within the basic block + // where they're used, and don't try to keep them around outside + // of that. It may be beneficial to try sharing them more broadly + // than that, but the increased register pressure makes that a + // tricky thing to balance. Investigate if re-materializing these + // becomes an issue. + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + // Consider replacing all frame index operands that reference + // an object allocated in the local block. + if (MI->getOperand(i).isFI()) { + // Don't try this with values not in the local block. + if (!MFI->isObjectPreAllocated(MI->getOperand(i).getIndex())) + break; + FrameReferenceInsns. + push_back(FrameRef(MI, LocalOffsets[MI->getOperand(i).getIndex()])); + break; + } + } + } + } + // Sort the frame references by local offset + array_pod_sort(FrameReferenceInsns.begin(), FrameReferenceInsns.end()); + + + // Loop throught the frame references and allocate for them as necessary + for (int ref = 0, e = FrameReferenceInsns.size(); ref < e ; ++ref) { + MachineBasicBlock::iterator I = + FrameReferenceInsns[ref].getMachineInstr(); + MachineInstr *MI = I; + for (unsigned idx = 0, e = MI->getNumOperands(); idx != e; ++idx) { + // Consider replacing all frame index operands that reference + // an object allocated in the local block. + if (MI->getOperand(idx).isFI()) { + int FrameIdx = MI->getOperand(idx).getIndex(); + + assert(MFI->isObjectPreAllocated(FrameIdx) && + "Only pre-allocated locals expected!"); + + DEBUG(dbgs() << "Considering: " << *MI); + if (TRI->needsFrameBaseReg(MI, LocalOffsets[FrameIdx])) { + unsigned BaseReg = 0; + int64_t Offset = 0; + int64_t FrameSizeAdjust = + StackGrowsDown ? MFI->getLocalFrameSize() : 0; + + DEBUG(dbgs() << " Replacing FI in: " << *MI); + + // If we have a suitable base register available, use it; otherwise + // create a new one. Note that any offset encoded in the + // instruction itself will be taken into account by the target, + // so we don't have to adjust for it here when reusing a base + // register. + std::pair RegOffset; + if (lookupCandidateBaseReg(BaseRegisters, RegOffset, + FrameSizeAdjust, + LocalOffsets[FrameIdx], + MI, TRI)) { + DEBUG(dbgs() << " Reusing base register " << + RegOffset.first << "\n"); + // We found a register to reuse. + BaseReg = RegOffset.first; + Offset = FrameSizeAdjust + LocalOffsets[FrameIdx] - + RegOffset.second; + } else { + // No previously defined register was in range, so create a + // new one. + int64_t InstrOffset = TRI->getFrameIndexInstrOffset(MI, idx); + const TargetRegisterClass *RC = TRI->getPointerRegClass(); + BaseReg = Fn.getRegInfo().createVirtualRegister(RC); + + DEBUG(dbgs() << " Materializing base register " << BaseReg << + " at frame local offset " << + LocalOffsets[FrameIdx] + InstrOffset << "\n"); + // Tell the target to insert the instruction to initialize + // the base register. + TRI->materializeFrameBaseRegister(InsertionPt, BaseReg, + FrameIdx, InstrOffset); + + // The base register already includes any offset specified + // by the instruction, so account for that so it doesn't get + // applied twice. + Offset = -InstrOffset; + + int64_t BaseOffset = FrameSizeAdjust + LocalOffsets[FrameIdx] + + InstrOffset; + BaseRegisters.push_back( + std::pair(BaseReg, BaseOffset)); + ++NumBaseRegisters; + UsedBaseReg = true; + } + assert(BaseReg != 0 && "Unable to allocate virtual base register!"); + + // Modify the instruction to use the new base register rather + // than the frame index operand. + TRI->resolveFrameIndex(I, BaseReg, Offset); + DEBUG(dbgs() << "Resolved: " << *MI); + + ++NumReplacements; + } + } + } + } + return UsedBaseReg; +} diff --git a/lib/CodeGen/LowerSubregs.cpp b/lib/CodeGen/LowerSubregs.cpp index dfd4eae..ad1c537 100644 --- a/lib/CodeGen/LowerSubregs.cpp +++ b/lib/CodeGen/LowerSubregs.cpp @@ -36,7 +36,7 @@ namespace { public: static char ID; // Pass identification, replacement for typeid - LowerSubregsInstructionPass() : MachineFunctionPass(&ID) {} + LowerSubregsInstructionPass() : MachineFunctionPass(ID) {} const char *getPassName() const { return "Subregister lowering instruction pass"; @@ -58,9 +58,6 @@ namespace { void TransferDeadFlag(MachineInstr *MI, unsigned DstReg, const TargetRegisterInfo *TRI); - void TransferKillFlag(MachineInstr *MI, unsigned SrcReg, - const TargetRegisterInfo *TRI, - bool AddIfNotFound = false); void TransferImplicitDefs(MachineInstr *MI); }; @@ -87,23 +84,6 @@ LowerSubregsInstructionPass::TransferDeadFlag(MachineInstr *MI, } } -/// TransferKillFlag - MI is a pseudo-instruction with SrcReg killed, -/// and the lowered replacement instructions immediately precede it. -/// Mark the replacement instructions with the kill flag. -void -LowerSubregsInstructionPass::TransferKillFlag(MachineInstr *MI, - unsigned SrcReg, - const TargetRegisterInfo *TRI, - bool AddIfNotFound) { - for (MachineBasicBlock::iterator MII = - prior(MachineBasicBlock::iterator(MI)); ; --MII) { - if (MII->addRegisterKilled(SrcReg, TRI, AddIfNotFound)) - break; - assert(MII != MI->getParent()->begin() && - "copyPhysReg output doesn't reference source register!"); - } -} - /// TransferImplicitDefs - MI is a pseudo-instruction, and the lowered /// replacement instructions immediately precede it. Copy any implicit-def /// operands from MI to the replacement instruction. diff --git a/lib/CodeGen/MachineBasicBlock.cpp b/lib/CodeGen/MachineBasicBlock.cpp index a27ee47..50f3f67 100644 --- a/lib/CodeGen/MachineBasicBlock.cpp +++ b/lib/CodeGen/MachineBasicBlock.cpp @@ -441,7 +441,7 @@ MachineBasicBlock::SplitCriticalEdge(MachineBasicBlock *Succ, Pass *P) { MachineBasicBlock *NMBB = MF->CreateMachineBasicBlock(); MF->insert(llvm::next(MachineFunction::iterator(this)), NMBB); - DEBUG(dbgs() << "PHIElimination splitting critical edge:" + DEBUG(dbgs() << "Splitting critical edge:" " BB#" << getNumber() << " -- BB#" << NMBB->getNumber() << " -- BB#" << Succ->getNumber() << '\n'); @@ -468,11 +468,33 @@ MachineBasicBlock::SplitCriticalEdge(MachineBasicBlock *Succ, Pass *P) { LV->addNewBlock(NMBB, this, Succ); if (MachineDominatorTree *MDT = - P->getAnalysisIfAvailable()) - MDT->addNewBlock(NMBB, this); + P->getAnalysisIfAvailable()) { + // Update dominator information. + MachineDomTreeNode *SucccDTNode = MDT->getNode(Succ); + + bool IsNewIDom = true; + for (const_pred_iterator PI = Succ->pred_begin(), E = Succ->pred_end(); + PI != E; ++PI) { + MachineBasicBlock *PredBB = *PI; + if (PredBB == NMBB) + continue; + if (!MDT->dominates(SucccDTNode, MDT->getNode(PredBB))) { + IsNewIDom = false; + break; + } + } + + // We know "this" dominates the newly created basic block. + MachineDomTreeNode *NewDTNode = MDT->addNewBlock(NMBB, this); + + // If all the other predecessors of "Succ" are dominated by "Succ" itself + // then the new block is the new immediate dominator of "Succ". Otherwise, + // the new block doesn't dominate anything. + if (IsNewIDom) + MDT->changeImmediateDominator(SucccDTNode, NewDTNode); + } - if (MachineLoopInfo *MLI = - P->getAnalysisIfAvailable()) + if (MachineLoopInfo *MLI = P->getAnalysisIfAvailable()) if (MachineLoop *TIL = MLI->getLoopFor(this)) { // If one or the other blocks were not in a loop, the new block is not // either, and thus LI doesn't need to be updated. diff --git a/lib/CodeGen/MachineCSE.cpp b/lib/CodeGen/MachineCSE.cpp index 833cc00..92e2299 100644 --- a/lib/CodeGen/MachineCSE.cpp +++ b/lib/CodeGen/MachineCSE.cpp @@ -41,7 +41,7 @@ namespace { MachineRegisterInfo *MRI; public: static char ID; // Pass identification - MachineCSE() : MachineFunctionPass(&ID), LookAheadLimit(5), CurrVN(0) {} + MachineCSE() : MachineFunctionPass(ID), LookAheadLimit(5), CurrVN(0) {} virtual bool runOnMachineFunction(MachineFunction &MF); @@ -49,6 +49,7 @@ namespace { AU.setPreservesCFG(); MachineFunctionPass::getAnalysisUsage(AU); AU.addRequired(); + AU.addPreservedID(MachineLoopInfoID); AU.addRequired(); AU.addPreserved(); } @@ -85,8 +86,8 @@ namespace { } // end anonymous namespace char MachineCSE::ID = 0; -static RegisterPass -X("machine-cse", "Machine Common Subexpression Elimination"); +INITIALIZE_PASS(MachineCSE, "machine-cse", + "Machine Common Subexpression Elimination", false, false); FunctionPass *llvm::createMachineCSEPass() { return new MachineCSE(); } @@ -107,29 +108,9 @@ bool MachineCSE::PerformTrivialCoalescing(MachineInstr *MI, MachineInstr *DefMI = MRI->getVRegDef(Reg); if (DefMI->getParent() != MBB) continue; - unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx; - if (TII->isMoveInstr(*DefMI, SrcReg, DstReg, SrcSubIdx, DstSubIdx) && - TargetRegisterInfo::isVirtualRegister(SrcReg) && - !SrcSubIdx && !DstSubIdx) { - const TargetRegisterClass *SRC = MRI->getRegClass(SrcReg); - const TargetRegisterClass *RC = MRI->getRegClass(Reg); - const TargetRegisterClass *NewRC = getCommonSubClass(RC, SRC); - if (!NewRC) - continue; - DEBUG(dbgs() << "Coalescing: " << *DefMI); - DEBUG(dbgs() << "*** to: " << *MI); - MO.setReg(SrcReg); - MRI->clearKillFlags(SrcReg); - if (NewRC != SRC) - MRI->setRegClass(SrcReg, NewRC); - DefMI->eraseFromParent(); - ++NumCoalesces; - Changed = true; - } - if (!DefMI->isCopy()) continue; - SrcReg = DefMI->getOperand(1).getReg(); + unsigned SrcReg = DefMI->getOperand(1).getReg(); if (!TargetRegisterInfo::isVirtualRegister(SrcReg)) continue; if (DefMI->getOperand(0).getSubReg() || DefMI->getOperand(1).getSubReg()) @@ -261,19 +242,13 @@ bool MachineCSE::PhysRegDefReaches(MachineInstr *CSMI, MachineInstr *MI, return false; } -static bool isCopy(const MachineInstr *MI, const TargetInstrInfo *TII) { - unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx; - return MI->isCopyLike() || - TII->isMoveInstr(*MI, SrcReg, DstReg, SrcSubIdx, DstSubIdx); -} - bool MachineCSE::isCSECandidate(MachineInstr *MI) { if (MI->isLabel() || MI->isPHI() || MI->isImplicitDef() || MI->isKill() || MI->isInlineAsm() || MI->isDebugValue()) return false; // Ignore copies. - if (isCopy(MI, TII)) + if (MI->isCopyLike()) return false; // Ignore stuff that we obviously can't move. @@ -329,7 +304,7 @@ bool MachineCSE::isProfitableToCSE(unsigned CSReg, unsigned Reg, E = MRI->use_nodbg_end(); I != E; ++I) { MachineInstr *Use = &*I; // Ignore copies. - if (!isCopy(Use, TII)) { + if (!Use->isCopyLike()) { HasNonCopyUse = true; break; } @@ -385,7 +360,7 @@ bool MachineCSE::ProcessBlock(MachineBasicBlock *MBB) { // Look for trivial copy coalescing opportunities. if (PerformTrivialCoalescing(MI, MBB)) { // After coalescing MI itself may become a copy. - if (isCopy(MI, TII)) + if (MI->isCopyLike()) continue; FoundCSE = VNT.count(MI); } diff --git a/lib/CodeGen/MachineDominators.cpp b/lib/CodeGen/MachineDominators.cpp index b5f8fbb..3c67478 100644 --- a/lib/CodeGen/MachineDominators.cpp +++ b/lib/CodeGen/MachineDominators.cpp @@ -24,10 +24,10 @@ TEMPLATE_INSTANTIATION(class DominatorTreeBase); char MachineDominatorTree::ID = 0; -static RegisterPass -E("machinedomtree", "MachineDominator Tree Construction", true); +INITIALIZE_PASS(MachineDominatorTree, "machinedomtree", + "MachineDominator Tree Construction", true, true); -const PassInfo *const llvm::MachineDominatorsID = &E; +char &llvm::MachineDominatorsID = MachineDominatorTree::ID; void MachineDominatorTree::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); @@ -41,7 +41,7 @@ bool MachineDominatorTree::runOnMachineFunction(MachineFunction &F) { } MachineDominatorTree::MachineDominatorTree() - : MachineFunctionPass(&ID) { + : MachineFunctionPass(ID) { DT = new DominatorTreeBase(false); } diff --git a/lib/CodeGen/MachineFunction.cpp b/lib/CodeGen/MachineFunction.cpp index 666120f..0171700 100644 --- a/lib/CodeGen/MachineFunction.cpp +++ b/lib/CodeGen/MachineFunction.cpp @@ -397,7 +397,6 @@ void MachineFunction::viewCFGOnly() const /// create a corresponding virtual register for it. unsigned MachineFunction::addLiveIn(unsigned PReg, const TargetRegisterClass *RC) { - assert(RC->contains(PReg) && "Not the correct regclass!"); MachineRegisterInfo &MRI = getRegInfo(); unsigned VReg = MRI.getLiveInVirtReg(PReg); if (VReg) { @@ -447,7 +446,7 @@ int MachineFrameInfo::CreateFixedObject(uint64_t Size, int64_t SPOffset, unsigned StackAlign = TFI.getStackAlignment(); unsigned Align = MinAlign(SPOffset, StackAlign); Objects.insert(Objects.begin(), StackObject(Size, Align, SPOffset, Immutable, - /*isSS*/false)); + /*isSS*/false, false)); return -++NumFixedObjects; } diff --git a/lib/CodeGen/MachineFunctionAnalysis.cpp b/lib/CodeGen/MachineFunctionAnalysis.cpp index 07a0f45..4f84b95 100644 --- a/lib/CodeGen/MachineFunctionAnalysis.cpp +++ b/lib/CodeGen/MachineFunctionAnalysis.cpp @@ -20,14 +20,14 @@ using namespace llvm; // a default constructor. static PassInfo X("Machine Function Analysis", "machine-function-analysis", - intptr_t(&MachineFunctionAnalysis::ID), 0, + &MachineFunctionAnalysis::ID, 0, /*CFGOnly=*/false, /*is_analysis=*/true); char MachineFunctionAnalysis::ID = 0; MachineFunctionAnalysis::MachineFunctionAnalysis(const TargetMachine &tm, CodeGenOpt::Level OL) : - FunctionPass(&ID), TM(tm), OptLevel(OL), MF(0) { + FunctionPass(ID), TM(tm), OptLevel(OL), MF(0) { } MachineFunctionAnalysis::~MachineFunctionAnalysis() { diff --git a/lib/CodeGen/MachineFunctionPrinterPass.cpp b/lib/CodeGen/MachineFunctionPrinterPass.cpp index 547c4fe..2aaa798 100644 --- a/lib/CodeGen/MachineFunctionPrinterPass.cpp +++ b/lib/CodeGen/MachineFunctionPrinterPass.cpp @@ -29,7 +29,7 @@ struct MachineFunctionPrinterPass : public MachineFunctionPass { const std::string Banner; MachineFunctionPrinterPass(raw_ostream &os, const std::string &banner) - : MachineFunctionPass(&ID), OS(os), Banner(banner) {} + : MachineFunctionPass(ID), OS(os), Banner(banner) {} const char *getPassName() const { return "MachineFunction Printer"; } diff --git a/lib/CodeGen/MachineInstr.cpp b/lib/CodeGen/MachineInstr.cpp index 6b2e985..446e461 100644 --- a/lib/CodeGen/MachineInstr.cpp +++ b/lib/CodeGen/MachineInstr.cpp @@ -1236,12 +1236,18 @@ static void printDebugLoc(DebugLoc DL, const MachineFunction *MF, void MachineInstr::print(raw_ostream &OS, const TargetMachine *TM) const { // We can be a bit tidier if we know the TargetMachine and/or MachineFunction. const MachineFunction *MF = 0; + const MachineRegisterInfo *MRI = 0; if (const MachineBasicBlock *MBB = getParent()) { MF = MBB->getParent(); if (!TM && MF) TM = &MF->getTarget(); + if (MF) + MRI = &MF->getRegInfo(); } + // Save a list of virtual registers. + SmallVector VirtRegs; + // Print explicitly defined operands on the left of an assignment syntax. unsigned StartOp = 0, e = getNumOperands(); for (; StartOp < e && getOperand(StartOp).isReg() && @@ -1250,6 +1256,9 @@ void MachineInstr::print(raw_ostream &OS, const TargetMachine *TM) const { ++StartOp) { if (StartOp != 0) OS << ", "; getOperand(StartOp).print(OS, TM); + unsigned Reg = getOperand(StartOp).getReg(); + if (Reg && TargetRegisterInfo::isVirtualRegister(Reg)) + VirtRegs.push_back(Reg); } if (StartOp != 0) @@ -1264,6 +1273,10 @@ void MachineInstr::print(raw_ostream &OS, const TargetMachine *TM) const { for (unsigned i = StartOp, e = getNumOperands(); i != e; ++i) { const MachineOperand &MO = getOperand(i); + if (MO.isReg() && MO.getReg() && + TargetRegisterInfo::isVirtualRegister(MO.getReg())) + VirtRegs.push_back(MO.getReg()); + // Omit call-clobbered registers which aren't used anywhere. This makes // call instructions much less noisy on targets where calls clobber lots // of registers. Don't rely on MO.isDead() because we may be called before @@ -1325,11 +1338,29 @@ void MachineInstr::print(raw_ostream &OS, const TargetMachine *TM) const { for (mmo_iterator i = memoperands_begin(), e = memoperands_end(); i != e; ++i) { OS << **i; - if (next(i) != e) + if (llvm::next(i) != e) OS << " "; } } + // Print the regclass of any virtual registers encountered. + if (MRI && !VirtRegs.empty()) { + if (!HaveSemi) OS << ";"; HaveSemi = true; + for (unsigned i = 0; i != VirtRegs.size(); ++i) { + const TargetRegisterClass *RC = MRI->getRegClass(VirtRegs[i]); + OS << " " << RC->getName() << ":%reg" << VirtRegs[i]; + for (unsigned j = i+1; j != VirtRegs.size();) { + if (MRI->getRegClass(VirtRegs[j]) != RC) { + ++j; + continue; + } + if (VirtRegs[i] != VirtRegs[j]) + OS << "," << VirtRegs[j]; + VirtRegs.erase(VirtRegs.begin()+j); + } + } + } + if (!debugLoc.isUnknown() && MF) { if (!HaveSemi) OS << ";"; OS << " dbg:"; diff --git a/lib/CodeGen/MachineLICM.cpp b/lib/CodeGen/MachineLICM.cpp index 4c054f5..1a74b74 100644 --- a/lib/CodeGen/MachineLICM.cpp +++ b/lib/CodeGen/MachineLICM.cpp @@ -68,16 +68,16 @@ namespace { BitVector AllocatableSet; - // For each opcode, keep a list of potentail CSE instructions. + // For each opcode, keep a list of potential CSE instructions. DenseMap > CSEMap; public: static char ID; // Pass identification, replacement for typeid MachineLICM() : - MachineFunctionPass(&ID), PreRegAlloc(true) {} + MachineFunctionPass(ID), PreRegAlloc(true) {} explicit MachineLICM(bool PreRA) : - MachineFunctionPass(&ID), PreRegAlloc(PreRA) {} + MachineFunctionPass(ID), PreRegAlloc(PreRA) {} virtual bool runOnMachineFunction(MachineFunction &MF); @@ -189,8 +189,8 @@ namespace { } // end anonymous namespace char MachineLICM::ID = 0; -static RegisterPass -X("machinelicm", "Machine Loop Invariant Code Motion"); +INITIALIZE_PASS(MachineLICM, "machinelicm", + "Machine Loop Invariant Code Motion", false, false); FunctionPass *llvm::createMachineLICMPass(bool PreRegAlloc) { return new MachineLICM(PreRegAlloc); @@ -488,9 +488,14 @@ void MachineLICM::HoistRegion(MachineDomTreeNode *N) { MII = NextMII; } - const std::vector &Children = N->getChildren(); - for (unsigned I = 0, E = Children.size(); I != E; ++I) - HoistRegion(Children[I]); + // Don't hoist things out of a large switch statement. This often causes + // code to be hoisted that wasn't going to be executed, and increases + // register pressure in a situation where it's likely to matter. + if (BB->succ_size() < 25) { + const std::vector &Children = N->getChildren(); + for (unsigned I = 0, E = Children.size(); I != E; ++I) + HoistRegion(Children[I]); + } } /// IsLICMCandidate - Returns true if the instruction may be a suitable diff --git a/lib/CodeGen/MachineLoopInfo.cpp b/lib/CodeGen/MachineLoopInfo.cpp index 269538b..bca4b0c 100644 --- a/lib/CodeGen/MachineLoopInfo.cpp +++ b/lib/CodeGen/MachineLoopInfo.cpp @@ -30,10 +30,10 @@ TEMPLATE_INSTANTIATION(MLIB); } char MachineLoopInfo::ID = 0; -static RegisterPass -X("machine-loops", "Machine Natural Loop Construction", true); +INITIALIZE_PASS(MachineLoopInfo, "machine-loops", + "Machine Natural Loop Construction", true, true); -const PassInfo *const llvm::MachineLoopInfoID = &X; +char &llvm::MachineLoopInfoID = MachineLoopInfo::ID; bool MachineLoopInfo::runOnMachineFunction(MachineFunction &) { releaseMemory(); diff --git a/lib/CodeGen/MachineModuleInfo.cpp b/lib/CodeGen/MachineModuleInfo.cpp index 15778b4..b647a4d 100644 --- a/lib/CodeGen/MachineModuleInfo.cpp +++ b/lib/CodeGen/MachineModuleInfo.cpp @@ -28,8 +28,8 @@ using namespace llvm; using namespace llvm::dwarf; // Handle the Pass registration stuff necessary to use TargetData's. -static RegisterPass -X("machinemoduleinfo", "Machine Module Information"); +INITIALIZE_PASS(MachineModuleInfo, "machinemoduleinfo", + "Machine Module Information", false, false); char MachineModuleInfo::ID = 0; // Out of line virtual method. @@ -254,7 +254,7 @@ void MMIAddrLabelMapCallbackPtr::allUsesReplacedWith(Value *V2) { //===----------------------------------------------------------------------===// MachineModuleInfo::MachineModuleInfo(const MCAsmInfo &MAI) -: ImmutablePass(&ID), Context(MAI), +: ImmutablePass(ID), Context(MAI), ObjFileMMI(0), CurCallSite(0), CallsEHReturn(0), CallsUnwindInit(0), DbgInfoAvailable(false){ // Always emit some info, by default "no personality" info. @@ -264,7 +264,7 @@ MachineModuleInfo::MachineModuleInfo(const MCAsmInfo &MAI) } MachineModuleInfo::MachineModuleInfo() -: ImmutablePass(&ID), Context(*(MCAsmInfo*)0) { +: ImmutablePass(ID), Context(*(MCAsmInfo*)0) { assert(0 && "This MachineModuleInfo constructor should never be called, MMI " "should always be explicitly constructed by LLVMTargetMachine"); abort(); @@ -579,10 +579,3 @@ namespace { } }; } - -MachineModuleInfo::VariableDbgInfoMapTy & -MachineModuleInfo::getVariableDbgInfo() { - std::stable_sort(VariableDbgInfo.begin(), VariableDbgInfo.end(), - VariableDebugSorter()); - return VariableDbgInfo; -} diff --git a/lib/CodeGen/MachineSink.cpp b/lib/CodeGen/MachineSink.cpp index 61334fc..c8f8faf 100644 --- a/lib/CodeGen/MachineSink.cpp +++ b/lib/CodeGen/MachineSink.cpp @@ -26,11 +26,21 @@ #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; -STATISTIC(NumSunk, "Number of machine instructions sunk"); +static cl::opt +SplitEdges("machine-sink-split", + cl::desc("Split critical edges during machine sinking"), + cl::init(false), cl::Hidden); +static cl::opt +SplitLimit("split-limit", + cl::init(~0u), cl::Hidden); + +STATISTIC(NumSunk, "Number of machine instructions sunk"); +STATISTIC(NumSplit, "Number of critical edges split"); namespace { class MachineSinking : public MachineFunctionPass { @@ -44,7 +54,7 @@ namespace { public: static char ID; // Pass identification - MachineSinking() : MachineFunctionPass(&ID) {} + MachineSinking() : MachineFunctionPass(ID) {} virtual bool runOnMachineFunction(MachineFunction &MF); @@ -59,21 +69,28 @@ namespace { } private: bool ProcessBlock(MachineBasicBlock &MBB); + MachineBasicBlock *SplitCriticalEdge(MachineBasicBlock *From, + MachineBasicBlock *To); bool SinkInstruction(MachineInstr *MI, bool &SawStore); - bool AllUsesDominatedByBlock(unsigned Reg, MachineBasicBlock *MBB) const; + bool AllUsesDominatedByBlock(unsigned Reg, MachineBasicBlock *MBB, + MachineBasicBlock *DefMBB, bool &LocalUse) const; }; } // end anonymous namespace char MachineSinking::ID = 0; -static RegisterPass -X("machine-sink", "Machine code sinking"); +INITIALIZE_PASS(MachineSinking, "machine-sink", + "Machine code sinking", false, false); FunctionPass *llvm::createMachineSinkingPass() { return new MachineSinking(); } /// AllUsesDominatedByBlock - Return true if all uses of the specified register -/// occur in blocks dominated by the specified block. +/// occur in blocks dominated by the specified block. If any use is in the +/// definition block, then return false since it is never legal to move def +/// after uses. bool MachineSinking::AllUsesDominatedByBlock(unsigned Reg, - MachineBasicBlock *MBB) const { + MachineBasicBlock *MBB, + MachineBasicBlock *DefMBB, + bool &LocalUse) const { assert(TargetRegisterInfo::isVirtualRegister(Reg) && "Only makes sense for vregs"); // Ignoring debug uses is necessary so debug info doesn't affect the code. @@ -91,6 +108,9 @@ bool MachineSinking::AllUsesDominatedByBlock(unsigned Reg, // PHI nodes use the operand in the predecessor block, not the block with // the PHI. UseBlock = UseInst->getOperand(I.getOperandNo()+1).getMBB(); + } else if (UseBlock == DefMBB) { + LocalUse = true; + return false; } // Check that it dominates. @@ -166,6 +186,66 @@ bool MachineSinking::ProcessBlock(MachineBasicBlock &MBB) { return MadeChange; } +MachineBasicBlock *MachineSinking::SplitCriticalEdge(MachineBasicBlock *FromBB, + MachineBasicBlock *ToBB) { + // Avoid breaking back edge. From == To means backedge for single BB loop. + if (!SplitEdges || NumSplit == SplitLimit || FromBB == ToBB) + return 0; + + // Check for more "complex" loops. + if (LI->getLoopFor(FromBB) != LI->getLoopFor(ToBB) || + !LI->isLoopHeader(ToBB)) { + // It's not always legal to break critical edges and sink the computation + // to the edge. + // + // BB#1: + // v1024 + // Beq BB#3 + // + // BB#2: + // ... no uses of v1024 + // + // BB#3: + // ... + // = v1024 + // + // If BB#1 -> BB#3 edge is broken and computation of v1024 is inserted: + // + // BB#1: + // ... + // Bne BB#2 + // BB#4: + // v1024 = + // B BB#3 + // BB#2: + // ... no uses of v1024 + // + // BB#3: + // ... + // = v1024 + // + // This is incorrect since v1024 is not computed along the BB#1->BB#2->BB#3 + // flow. We need to ensure the new basic block where the computation is + // sunk to dominates all the uses. + // It's only legal to break critical edge and sink the computation to the + // new block if all the predecessors of "To", except for "From", are + // not dominated by "From". Given SSA property, this means these + // predecessors are dominated by "To". + for (MachineBasicBlock::pred_iterator PI = ToBB->pred_begin(), + E = ToBB->pred_end(); PI != E; ++PI) { + if (*PI == FromBB) + continue; + if (!DT->dominates(ToBB, *PI)) + return 0; + } + + // FIXME: Determine if it's cost effective to break this edge. + return FromBB->SplitCriticalEdge(ToBB, this); + } + + return 0; +} + /// SinkInstruction - Determine whether it is safe to sink the specified machine /// instruction out of its current block into a successor. bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { @@ -246,7 +326,8 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { if (SuccToSinkTo) { // If a previous operand picked a block to sink to, then this operand // must be sinkable to the same block. - if (!AllUsesDominatedByBlock(Reg, SuccToSinkTo)) + bool LocalUse = false; + if (!AllUsesDominatedByBlock(Reg, SuccToSinkTo, ParentBlock, LocalUse)) return false; continue; @@ -256,10 +337,14 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { // we should sink to. for (MachineBasicBlock::succ_iterator SI = ParentBlock->succ_begin(), E = ParentBlock->succ_end(); SI != E; ++SI) { - if (AllUsesDominatedByBlock(Reg, *SI)) { + bool LocalUse = false; + if (AllUsesDominatedByBlock(Reg, *SI, ParentBlock, LocalUse)) { SuccToSinkTo = *SI; break; } + if (LocalUse) + // Def is used locally, it's never safe to move this def. + return false; } // If we couldn't find a block to sink to, ignore this instruction. @@ -303,27 +388,44 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { if (SuccToSinkTo->pred_size() > 1) { // We cannot sink a load across a critical edge - there may be stores in // other code paths. + bool TryBreak = false; bool store = true; if (!MI->isSafeToMove(TII, AA, store)) { - DEBUG(dbgs() << " *** PUNTING: Wont sink load along critical edge.\n"); - return false; + DEBUG(dbgs() << " *** NOTE: Won't sink load along critical edge.\n"); + TryBreak = true; } // We don't want to sink across a critical edge if we don't dominate the // successor. We could be introducing calculations to new code paths. - if (!DT->dominates(ParentBlock, SuccToSinkTo)) { - DEBUG(dbgs() << " *** PUNTING: Critical edge found\n"); - return false; + if (!TryBreak && !DT->dominates(ParentBlock, SuccToSinkTo)) { + DEBUG(dbgs() << " *** NOTE: Critical edge found\n"); + TryBreak = true; } // Don't sink instructions into a loop. - if (LI->isLoopHeader(SuccToSinkTo)) { - DEBUG(dbgs() << " *** PUNTING: Loop header found\n"); - return false; + if (!TryBreak && LI->isLoopHeader(SuccToSinkTo)) { + DEBUG(dbgs() << " *** NOTE: Loop header found\n"); + TryBreak = true; } // Otherwise we are OK with sinking along a critical edge. - DEBUG(dbgs() << "Sinking along critical edge.\n"); + if (!TryBreak) + DEBUG(dbgs() << "Sinking along critical edge.\n"); + else { + MachineBasicBlock *NewSucc = SplitCriticalEdge(ParentBlock, SuccToSinkTo); + if (!NewSucc) { + DEBUG(dbgs() << + " *** PUNTING: Not legal or profitable to break critical edge\n"); + return false; + } else { + DEBUG(dbgs() << " *** Splitting critical edge:" + " BB#" << ParentBlock->getNumber() + << " -- BB#" << NewSucc->getNumber() + << " -- BB#" << SuccToSinkTo->getNumber() << '\n'); + SuccToSinkTo = NewSucc; + ++NumSplit; + } + } } // Determine where to insert into. Skip phi nodes. diff --git a/lib/CodeGen/MachineVerifier.cpp b/lib/CodeGen/MachineVerifier.cpp index 2297c90..1e88562 100644 --- a/lib/CodeGen/MachineVerifier.cpp +++ b/lib/CodeGen/MachineVerifier.cpp @@ -1,4 +1,4 @@ -//===-- MachineVerifier.cpp - Machine Code Verifier -------------*- C++ -*-===// +//===-- MachineVerifier.cpp - Machine Code Verifier -----------------------===// // // The LLVM Compiler Infrastructure // @@ -24,6 +24,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Function.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/LiveVariables.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -44,19 +45,14 @@ using namespace llvm; namespace { struct MachineVerifier { - MachineVerifier(Pass *pass, bool allowDoubleDefs) : + MachineVerifier(Pass *pass) : PASS(pass), - allowVirtDoubleDefs(allowDoubleDefs), - allowPhysDoubleDefs(true), OutFileName(getenv("LLVM_VERIFY_MACHINEINSTRS")) {} bool runOnMachineFunction(MachineFunction &MF); Pass *const PASS; - const bool allowVirtDoubleDefs; - const bool allowPhysDoubleDefs; - const char *const OutFileName; raw_ostream *OS; const MachineFunction *MF; @@ -91,10 +87,6 @@ namespace { // defined. Map value is the user. RegMap vregsLiveIn; - // Vregs that must be dead in because they are defined without being - // killed first. Map value is the defining instruction. - RegMap vregsDeadIn; - // Regs killed in MBB. They may be defined again, and will then be in both // regsKilled and regsLiveOut. RegSet regsKilled; @@ -175,6 +167,7 @@ namespace { // Analysis information if available LiveVariables *LiveVars; + const LiveIntervals *LiveInts; void visitMachineFunctionBefore(); void visitMachineBasicBlockBefore(const MachineBasicBlock *MBB); @@ -195,15 +188,14 @@ namespace { void calcRegsRequired(); void verifyLiveVariables(); + void verifyLiveIntervals(); }; struct MachineVerifierPass : public MachineFunctionPass { static char ID; // Pass ID, replacement for typeid - bool AllowDoubleDefs; - explicit MachineVerifierPass(bool allowDoubleDefs = false) - : MachineFunctionPass(&ID), - AllowDoubleDefs(allowDoubleDefs) {} + MachineVerifierPass() + : MachineFunctionPass(ID) {} void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); @@ -211,7 +203,7 @@ namespace { } bool runOnMachineFunction(MachineFunction &MF) { - MF.verify(this, AllowDoubleDefs); + MF.verify(this); return false; } }; @@ -219,17 +211,15 @@ namespace { } char MachineVerifierPass::ID = 0; -static RegisterPass -MachineVer("machineverifier", "Verify generated machine code"); -static const PassInfo *const MachineVerifyID = &MachineVer; +INITIALIZE_PASS(MachineVerifierPass, "machineverifier", + "Verify generated machine code", false, false); -FunctionPass *llvm::createMachineVerifierPass(bool allowPhysDoubleDefs) { - return new MachineVerifierPass(allowPhysDoubleDefs); +FunctionPass *llvm::createMachineVerifierPass() { + return new MachineVerifierPass(); } -void MachineFunction::verify(Pass *p, bool allowDoubleDefs) const { - MachineVerifier(p, allowDoubleDefs) - .runOnMachineFunction(const_cast(*this)); +void MachineFunction::verify(Pass *p) const { + MachineVerifier(p).runOnMachineFunction(const_cast(*this)); } bool MachineVerifier::runOnMachineFunction(MachineFunction &MF) { @@ -255,10 +245,13 @@ bool MachineVerifier::runOnMachineFunction(MachineFunction &MF) { TRI = TM->getRegisterInfo(); MRI = &MF.getRegInfo(); + LiveVars = NULL; + LiveInts = NULL; if (PASS) { - LiveVars = PASS->getAnalysisIfAvailable(); - } else { - LiveVars = NULL; + LiveInts = PASS->getAnalysisIfAvailable(); + // We don't want to verify LiveVariables if LiveIntervals is available. + if (!LiveInts) + LiveVars = PASS->getAnalysisIfAvailable(); } visitMachineFunctionBefore(); @@ -512,6 +505,20 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) { if ((*I)->isStore() && !TI.mayStore()) report("Missing mayStore flag", MI); } + + // Debug values must not have a slot index. + // Other instructions must have one. + if (LiveInts) { + bool mapped = !LiveInts->isNotInMIMap(MI); + if (MI->isDebugValue()) { + if (mapped) + report("Debug instruction has a slot index", MI); + } else { + if (!mapped) + report("Missing slot index", MI); + } + } + } void @@ -570,15 +577,30 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { } else isKill = MO->isKill(); - if (isKill) { + if (isKill) addRegWithSubRegs(regsKilled, Reg); - // Check that LiveVars knows this kill - if (LiveVars && TargetRegisterInfo::isVirtualRegister(Reg)) { - LiveVariables::VarInfo &VI = LiveVars->getVarInfo(Reg); - if (std::find(VI.Kills.begin(), - VI.Kills.end(), MI) == VI.Kills.end()) - report("Kill missing from LiveVariables", MO, MONum); + // Check that LiveVars knows this kill. + if (LiveVars && TargetRegisterInfo::isVirtualRegister(Reg) && + MO->isKill()) { + LiveVariables::VarInfo &VI = LiveVars->getVarInfo(Reg); + if (std::find(VI.Kills.begin(), + VI.Kills.end(), MI) == VI.Kills.end()) + report("Kill missing from LiveVariables", MO, MONum); + } + + // Check LiveInts liveness and kill. + if (LiveInts && !LiveInts->isNotInMIMap(MI)) { + SlotIndex UseIdx = LiveInts->getInstructionIndex(MI).getUseIndex(); + if (LiveInts->hasInterval(Reg)) { + const LiveInterval &LI = LiveInts->getInterval(Reg); + if (!LI.liveAt(UseIdx)) { + report("No live range at use", MO, MONum); + *OS << UseIdx << " is not live in " << LI << '\n'; + } + // TODO: Verify isKill == LI.killedAt. + } else if (TargetRegisterInfo::isVirtualRegister(Reg)) { + report("Virtual register has no Live interval", MO, MONum); } } @@ -607,6 +629,28 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { addRegWithSubRegs(regsDead, Reg); else addRegWithSubRegs(regsDefined, Reg); + + // Check LiveInts for a live range, but only for virtual registers. + if (LiveInts && TargetRegisterInfo::isVirtualRegister(Reg) && + !LiveInts->isNotInMIMap(MI)) { + SlotIndex DefIdx = LiveInts->getInstructionIndex(MI).getDefIndex(); + if (LiveInts->hasInterval(Reg)) { + const LiveInterval &LI = LiveInts->getInterval(Reg); + if (const LiveRange *LR = LI.getLiveRangeContaining(DefIdx)) { + assert(LR->valno && "NULL valno is not allowed"); + if (LR->valno->def != DefIdx) { + report("Inconsistent valno->def", MO, MONum); + *OS << "Valno " << LR->valno->id << " is not defined at " + << DefIdx << " in " << LI << '\n'; + } + } else { + report("No live range at def", MO, MONum); + *OS << DefIdx << " is not live in " << LI << '\n'; + } + } else { + report("Virtual register has no Live interval", MO, MONum); + } + } } // Check register classes. @@ -670,40 +714,9 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { void MachineVerifier::visitMachineInstrAfter(const MachineInstr *MI) { BBInfo &MInfo = MBBInfoMap[MI->getParent()]; set_union(MInfo.regsKilled, regsKilled); - set_subtract(regsLive, regsKilled); - regsKilled.clear(); - - // Verify that both and operands refer to dead registers. - RegVector defs(regsDefined); - defs.append(regsDead.begin(), regsDead.end()); - - for (RegVector::const_iterator I = defs.begin(), E = defs.end(); - I != E; ++I) { - if (regsLive.count(*I)) { - if (TargetRegisterInfo::isPhysicalRegister(*I)) { - if (!allowPhysDoubleDefs && !isReserved(*I) && - !regsLiveInButUnused.count(*I)) { - report("Redefining a live physical register", MI); - *OS << "Register " << TRI->getName(*I) - << " was defined but already live.\n"; - } - } else { - if (!allowVirtDoubleDefs) { - report("Redefining a live virtual register", MI); - *OS << "Virtual register %reg" << *I - << " was defined but already live.\n"; - } - } - } else if (TargetRegisterInfo::isVirtualRegister(*I) && - !MInfo.regsKilled.count(*I)) { - // Virtual register defined without being killed first must be dead on - // entry. - MInfo.vregsDeadIn.insert(std::make_pair(*I, MI)); - } - } - - set_subtract(regsLive, regsDead); regsDead.clear(); - set_union(regsLive, regsDefined); regsDefined.clear(); + set_subtract(regsLive, regsKilled); regsKilled.clear(); + set_subtract(regsLive, regsDead); regsDead.clear(); + set_union(regsLive, regsDefined); regsDefined.clear(); } void @@ -828,35 +841,15 @@ void MachineVerifier::visitMachineFunctionAfter() { continue; checkPHIOps(MFI); - - // Verify dead-in virtual registers. - if (!allowVirtDoubleDefs) { - for (MachineBasicBlock::const_pred_iterator PrI = MFI->pred_begin(), - PrE = MFI->pred_end(); PrI != PrE; ++PrI) { - BBInfo &PrInfo = MBBInfoMap[*PrI]; - if (!PrInfo.reachable) - continue; - - for (RegMap::iterator I = MInfo.vregsDeadIn.begin(), - E = MInfo.vregsDeadIn.end(); I != E; ++I) { - // DeadIn register must be in neither regsLiveOut or vregsPassed of - // any predecessor. - if (PrInfo.isLiveOut(I->first)) { - report("Live-in virtual register redefined", I->second); - *OS << "Register %reg" << I->first - << " was live-out from predecessor MBB #" - << (*PrI)->getNumber() << ".\n"; - } - } - } - } } - // Now check LiveVariables info if available - if (LiveVars) { + // Now check liveness info if available + if (LiveVars || LiveInts) calcRegsRequired(); + if (LiveVars) verifyLiveVariables(); - } + if (LiveInts) + verifyLiveIntervals(); } void MachineVerifier::verifyLiveVariables() { @@ -886,4 +879,55 @@ void MachineVerifier::verifyLiveVariables() { } } +void MachineVerifier::verifyLiveIntervals() { + assert(LiveInts && "Don't call verifyLiveIntervals without LiveInts"); + for (LiveIntervals::const_iterator LVI = LiveInts->begin(), + LVE = LiveInts->end(); LVI != LVE; ++LVI) { + const LiveInterval &LI = *LVI->second; + assert(LVI->first == LI.reg && "Invalid reg to interval mapping"); + + for (LiveInterval::const_vni_iterator I = LI.vni_begin(), E = LI.vni_end(); + I!=E; ++I) { + VNInfo *VNI = *I; + const LiveRange *DefLR = LI.getLiveRangeContaining(VNI->def); + + if (!DefLR) { + if (!VNI->isUnused()) { + report("Valno not live at def and not marked unused", MF); + *OS << "Valno #" << VNI->id << " in " << LI << '\n'; + } + continue; + } + + if (VNI->isUnused()) + continue; + + if (DefLR->valno != VNI) { + report("Live range at def has different valno", MF); + DefLR->print(*OS); + *OS << " should use valno #" << VNI->id << " in " << LI << '\n'; + } + + } + + for (LiveInterval::const_iterator I = LI.begin(), E = LI.end(); I!=E; ++I) { + const LiveRange &LR = *I; + assert(LR.valno && "Live range has no valno"); + + if (LR.valno->id >= LI.getNumValNums() || + LR.valno != LI.getValNumInfo(LR.valno->id)) { + report("Foreign valno in live range", MF); + LR.print(*OS); + *OS << " has a valno not in " << LI << '\n'; + } + + if (LR.valno->isUnused()) { + report("Live range valno is marked unused", MF); + LR.print(*OS); + *OS << " in " << LI << '\n'; + } + + } + } +} diff --git a/lib/CodeGen/OptimizeExts.cpp b/lib/CodeGen/OptimizeExts.cpp deleted file mode 100644 index dcdc243..0000000 --- a/lib/CodeGen/OptimizeExts.cpp +++ /dev/null @@ -1,220 +0,0 @@ -//===-- OptimizeExts.cpp - Optimize sign / zero extension instrs -----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass performs optimization of sign / zero extension instructions. It -// may be extended to handle other instructions of similar property. -// -// On some targets, some instructions, e.g. X86 sign / zero extension, may -// leave the source value in the lower part of the result. This pass will -// replace (some) uses of the pre-extension value with uses of the sub-register -// of the results. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "ext-opt" -#include "llvm/CodeGen/Passes.h" -#include "llvm/CodeGen/MachineDominators.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetRegisterInfo.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/Statistic.h" -using namespace llvm; - -static cl::opt Aggressive("aggressive-ext-opt", cl::Hidden, - cl::desc("Aggressive extension optimization")); - -STATISTIC(NumReuse, "Number of extension results reused"); - -namespace { - class OptimizeExts : public MachineFunctionPass { - const TargetMachine *TM; - const TargetInstrInfo *TII; - MachineRegisterInfo *MRI; - MachineDominatorTree *DT; // Machine dominator tree - - public: - static char ID; // Pass identification - OptimizeExts() : MachineFunctionPass(&ID) {} - - virtual bool runOnMachineFunction(MachineFunction &MF); - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesCFG(); - MachineFunctionPass::getAnalysisUsage(AU); - if (Aggressive) { - AU.addRequired(); - AU.addPreserved(); - } - } - - private: - bool OptimizeInstr(MachineInstr *MI, MachineBasicBlock *MBB, - SmallPtrSet &LocalMIs); - }; -} - -char OptimizeExts::ID = 0; -static RegisterPass -X("opt-exts", "Optimize sign / zero extensions"); - -FunctionPass *llvm::createOptimizeExtsPass() { return new OptimizeExts(); } - -/// OptimizeInstr - If instruction is a copy-like instruction, i.e. it reads -/// a single register and writes a single register and it does not modify -/// the source, and if the source value is preserved as a sub-register of -/// the result, then replace all reachable uses of the source with the subreg -/// of the result. -/// Do not generate an EXTRACT that is used only in a debug use, as this -/// changes the code. Since this code does not currently share EXTRACTs, just -/// ignore all debug uses. -bool OptimizeExts::OptimizeInstr(MachineInstr *MI, MachineBasicBlock *MBB, - SmallPtrSet &LocalMIs) { - bool Changed = false; - LocalMIs.insert(MI); - - unsigned SrcReg, DstReg, SubIdx; - if (TII->isCoalescableExtInstr(*MI, SrcReg, DstReg, SubIdx)) { - if (TargetRegisterInfo::isPhysicalRegister(DstReg) || - TargetRegisterInfo::isPhysicalRegister(SrcReg)) - return false; - - MachineRegisterInfo::use_nodbg_iterator UI = MRI->use_nodbg_begin(SrcReg); - if (++UI == MRI->use_nodbg_end()) - // No other uses. - return false; - - // Ok, the source has other uses. See if we can replace the other uses - // with use of the result of the extension. - SmallPtrSet ReachedBBs; - UI = MRI->use_nodbg_begin(DstReg); - for (MachineRegisterInfo::use_nodbg_iterator UE = MRI->use_nodbg_end(); - UI != UE; ++UI) - ReachedBBs.insert(UI->getParent()); - - bool ExtendLife = true; - // Uses that are in the same BB of uses of the result of the instruction. - SmallVector Uses; - // Uses that the result of the instruction can reach. - SmallVector ExtendedUses; - - UI = MRI->use_nodbg_begin(SrcReg); - for (MachineRegisterInfo::use_nodbg_iterator UE = MRI->use_nodbg_end(); - UI != UE; ++UI) { - MachineOperand &UseMO = UI.getOperand(); - MachineInstr *UseMI = &*UI; - if (UseMI == MI) - continue; - if (UseMI->isPHI()) { - ExtendLife = false; - continue; - } - - // It's an error to translate this: - // - // %reg1025 = %reg1024 - // ... - // %reg1026 = SUBREG_TO_REG 0, %reg1024, 4 - // - // into this: - // - // %reg1025 = %reg1024 - // ... - // %reg1027 = COPY %reg1025:4 - // %reg1026 = SUBREG_TO_REG 0, %reg1027, 4 - // - // The problem here is that SUBREG_TO_REG is there to assert that an - // implicit zext occurs. It doesn't insert a zext instruction. If we allow - // the COPY here, it will give us the value after the , - // not the original value of %reg1024 before . - if (UseMI->getOpcode() == TargetOpcode::SUBREG_TO_REG) - continue; - - MachineBasicBlock *UseMBB = UseMI->getParent(); - if (UseMBB == MBB) { - // Local uses that come after the extension. - if (!LocalMIs.count(UseMI)) - Uses.push_back(&UseMO); - } else if (ReachedBBs.count(UseMBB)) - // Non-local uses where the result of extension is used. Always - // replace these unless it's a PHI. - Uses.push_back(&UseMO); - else if (Aggressive && DT->dominates(MBB, UseMBB)) - // We may want to extend live range of the extension result in order - // to replace these uses. - ExtendedUses.push_back(&UseMO); - else { - // Both will be live out of the def MBB anyway. Don't extend live - // range of the extension result. - ExtendLife = false; - break; - } - } - - if (ExtendLife && !ExtendedUses.empty()) - // Ok, we'll extend the liveness of the extension result. - std::copy(ExtendedUses.begin(), ExtendedUses.end(), - std::back_inserter(Uses)); - - // Now replace all uses. - if (!Uses.empty()) { - SmallPtrSet PHIBBs; - // Look for PHI uses of the extended result, we don't want to extend the - // liveness of a PHI input. It breaks all kinds of assumptions down - // stream. A PHI use is expected to be the kill of its source values. - UI = MRI->use_nodbg_begin(DstReg); - for (MachineRegisterInfo::use_nodbg_iterator UE = MRI->use_nodbg_end(); - UI != UE; ++UI) - if (UI->isPHI()) - PHIBBs.insert(UI->getParent()); - - const TargetRegisterClass *RC = MRI->getRegClass(SrcReg); - for (unsigned i = 0, e = Uses.size(); i != e; ++i) { - MachineOperand *UseMO = Uses[i]; - MachineInstr *UseMI = UseMO->getParent(); - MachineBasicBlock *UseMBB = UseMI->getParent(); - if (PHIBBs.count(UseMBB)) - continue; - unsigned NewVR = MRI->createVirtualRegister(RC); - BuildMI(*UseMBB, UseMI, UseMI->getDebugLoc(), - TII->get(TargetOpcode::COPY), NewVR) - .addReg(DstReg, 0, SubIdx); - UseMO->setReg(NewVR); - ++NumReuse; - Changed = true; - } - } - } - - return Changed; -} - -bool OptimizeExts::runOnMachineFunction(MachineFunction &MF) { - TM = &MF.getTarget(); - TII = TM->getInstrInfo(); - MRI = &MF.getRegInfo(); - DT = Aggressive ? &getAnalysis() : 0; - - bool Changed = false; - - SmallPtrSet LocalMIs; - for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) { - MachineBasicBlock *MBB = &*I; - LocalMIs.clear(); - for (MachineBasicBlock::iterator MII = I->begin(), ME = I->end(); MII != ME; - ++MII) { - MachineInstr *MI = &*MII; - Changed |= OptimizeInstr(MI, MBB, LocalMIs); - } - } - - return Changed; -} diff --git a/lib/CodeGen/OptimizePHIs.cpp b/lib/CodeGen/OptimizePHIs.cpp index 1613fe2..edb4eea 100644 --- a/lib/CodeGen/OptimizePHIs.cpp +++ b/lib/CodeGen/OptimizePHIs.cpp @@ -33,7 +33,7 @@ namespace { public: static char ID; // Pass identification - OptimizePHIs() : MachineFunctionPass(&ID) {} + OptimizePHIs() : MachineFunctionPass(ID) {} virtual bool runOnMachineFunction(MachineFunction &MF); @@ -54,8 +54,8 @@ namespace { } char OptimizePHIs::ID = 0; -static RegisterPass -X("opt-phis", "Optimize machine instruction PHIs"); +INITIALIZE_PASS(OptimizePHIs, "opt-phis", + "Optimize machine instruction PHIs", false, false); FunctionPass *llvm::createOptimizePHIsPass() { return new OptimizePHIs(); } @@ -101,16 +101,10 @@ bool OptimizePHIs::IsSingleValuePHICycle(MachineInstr *MI, MachineInstr *SrcMI = MRI->getVRegDef(SrcReg); // Skip over register-to-register moves. - unsigned MvSrcReg, MvDstReg, SrcSubIdx, DstSubIdx; - if (SrcMI && - TII->isMoveInstr(*SrcMI, MvSrcReg, MvDstReg, SrcSubIdx, DstSubIdx) && - SrcSubIdx == 0 && DstSubIdx == 0 && - TargetRegisterInfo::isVirtualRegister(MvSrcReg)) - SrcMI = MRI->getVRegDef(MvSrcReg); - else if (SrcMI && SrcMI->isCopy() && - !SrcMI->getOperand(0).getSubReg() && - !SrcMI->getOperand(1).getSubReg() && - TargetRegisterInfo::isVirtualRegister(SrcMI->getOperand(1).getReg())) + if (SrcMI && SrcMI->isCopy() && + !SrcMI->getOperand(0).getSubReg() && + !SrcMI->getOperand(1).getSubReg() && + TargetRegisterInfo::isVirtualRegister(SrcMI->getOperand(1).getReg())) SrcMI = MRI->getVRegDef(SrcMI->getOperand(1).getReg()); if (!SrcMI) return false; diff --git a/lib/CodeGen/PBQP/HeuristicBase.h b/lib/CodeGen/PBQP/HeuristicBase.h index 3bb24e1..791c227 100644 --- a/lib/CodeGen/PBQP/HeuristicBase.h +++ b/lib/CodeGen/PBQP/HeuristicBase.h @@ -173,9 +173,13 @@ namespace PBQP { bool finished = false; while (!finished) { - if (!optimalReduce()) - if (!impl().heuristicReduce()) + if (!optimalReduce()) { + if (impl().heuristicReduce()) { + getSolver().recordRN(); + } else { finished = true; + } + } } } diff --git a/lib/CodeGen/PBQP/HeuristicSolver.h b/lib/CodeGen/PBQP/HeuristicSolver.h index 02938df..35514f9 100644 --- a/lib/CodeGen/PBQP/HeuristicSolver.h +++ b/lib/CodeGen/PBQP/HeuristicSolver.h @@ -226,6 +226,8 @@ namespace PBQP { // Nothing to do. Just push the node onto the reduction stack. pushToStack(nItr); + + s.recordR0(); } /// \brief Apply rule R1. @@ -274,6 +276,7 @@ namespace PBQP { assert(nd.getSolverDegree() == 0 && "Degree 1 with edge removed should be 0."); pushToStack(xnItr); + s.recordR1(); } /// \brief Apply rule R2. @@ -378,8 +381,14 @@ namespace PBQP { removeSolverEdge(zxeItr); pushToStack(xnItr); + s.recordR2(); } + /// \brief Record an application of the RN rule. + /// + /// For use by the HeuristicBase. + void recordRN() { s.recordRN(); } + private: NodeData& getSolverNodeData(Graph::NodeItr nItr) { diff --git a/lib/CodeGen/PBQP/Heuristics/Briggs.h b/lib/CodeGen/PBQP/Heuristics/Briggs.h index 4c1ce11..18eaf7c 100644 --- a/lib/CodeGen/PBQP/Heuristics/Briggs.h +++ b/lib/CodeGen/PBQP/Heuristics/Briggs.h @@ -52,9 +52,7 @@ namespace PBQP { bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const { if (s->getSolverDegree(n1Itr) > s->getSolverDegree(n2Itr)) return true; - if (s->getSolverDegree(n1Itr) < s->getSolverDegree(n2Itr)) - return false; - return (&*n1Itr < &*n2Itr); + return false; } private: HeuristicSolverImpl *s; @@ -69,9 +67,7 @@ namespace PBQP { cost2 = g->getNodeCosts(n2Itr)[0] / s->getSolverDegree(n2Itr); if (cost1 < cost2) return true; - if (cost1 > cost2) - return false; - return (&*n1Itr < &*n2Itr); + return false; } private: diff --git a/lib/CodeGen/PBQP/Solution.h b/lib/CodeGen/PBQP/Solution.h index 294b537..047fd04 100644 --- a/lib/CodeGen/PBQP/Solution.h +++ b/lib/CodeGen/PBQP/Solution.h @@ -26,15 +26,46 @@ namespace PBQP { /// To get the selection for each node in the problem use the getSelection method. class Solution { private: + typedef std::map SelectionsMap; SelectionsMap selections; + unsigned r0Reductions, r1Reductions, r2Reductions, rNReductions; + public: /// \brief Number of nodes for which selections have been made. /// @return Number of nodes for which selections have been made. unsigned numNodes() const { return selections.size(); } + /// \brief Records a reduction via the R0 rule. Should be called from the + /// solver only. + void recordR0() { ++r0Reductions; } + + /// \brief Returns the number of R0 reductions applied to solve the problem. + unsigned numR0Reductions() const { return r0Reductions; } + + /// \brief Records a reduction via the R1 rule. Should be called from the + /// solver only. + void recordR1() { ++r1Reductions; } + + /// \brief Returns the number of R1 reductions applied to solve the problem. + unsigned numR1Reductions() const { return r1Reductions; } + + /// \brief Records a reduction via the R2 rule. Should be called from the + /// solver only. + void recordR2() { ++r2Reductions; } + + /// \brief Returns the number of R2 reductions applied to solve the problem. + unsigned numR2Reductions() const { return r2Reductions; } + + /// \brief Records a reduction via the RN rule. Should be called from the + /// solver only. + void recordRN() { ++ rNReductions; } + + /// \brief Returns the number of RN reductions applied to solve the problem. + unsigned numRNReductions() const { return rNReductions; } + /// \brief Set the selection for a given node. /// @param nItr Node iterator. /// @param selection Selection for nItr. diff --git a/lib/CodeGen/PHIElimination.cpp b/lib/CodeGen/PHIElimination.cpp index ea6b094..d4df4c5 100644 --- a/lib/CodeGen/PHIElimination.cpp +++ b/lib/CodeGen/PHIElimination.cpp @@ -20,6 +20,7 @@ #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Function.h" @@ -37,16 +38,15 @@ STATISTIC(NumAtomic, "Number of atomic phis lowered"); STATISTIC(NumReused, "Number of reused lowered phis"); char PHIElimination::ID = 0; -static RegisterPass -X("phi-node-elimination", "Eliminate PHI nodes for register allocation"); +INITIALIZE_PASS(PHIElimination, "phi-node-elimination", + "Eliminate PHI nodes for register allocation", false, false); -const PassInfo *const llvm::PHIEliminationID = &X; +char &llvm::PHIEliminationID = PHIElimination::ID; void llvm::PHIElimination::getAnalysisUsage(AnalysisUsage &AU) const { AU.addPreserved(); AU.addPreserved(); - // rdar://7401784 This would be nice: - // AU.addPreservedID(MachineLoopInfoID); + AU.addPreserved(); MachineFunctionPass::getAnalysisUsage(AU); } @@ -56,9 +56,11 @@ bool llvm::PHIElimination::runOnMachineFunction(MachineFunction &MF) { bool Changed = false; // Split critical edges to help the coalescer - if (LiveVariables *LV = getAnalysisIfAvailable()) + if (LiveVariables *LV = getAnalysisIfAvailable()) { + MachineLoopInfo *MLI = getAnalysisIfAvailable(); for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) - Changed |= SplitPHIEdges(MF, *I, *LV); + Changed |= SplitPHIEdges(MF, *I, *LV, MLI); + } // Populate VRegPHIUseCount analyzePHINodes(MF); @@ -179,6 +181,7 @@ void llvm::PHIElimination::LowerAtomicPHINode( unsigned NumSrcs = (MPhi->getNumOperands() - 1) / 2; unsigned DestReg = MPhi->getOperand(0).getReg(); + assert(MPhi->getOperand(0).getSubReg() == 0 && "Can't handle sub-reg PHIs"); bool isDead = MPhi->getOperand(0).isDead(); // Create a new register for the incoming PHI arguments. @@ -265,6 +268,8 @@ void llvm::PHIElimination::LowerAtomicPHINode( SmallPtrSet MBBsInsertedInto; for (int i = NumSrcs - 1; i >= 0; --i) { unsigned SrcReg = MPhi->getOperand(i*2+1).getReg(); + unsigned SrcSubReg = MPhi->getOperand(i*2+1).getSubReg(); + assert(TargetRegisterInfo::isVirtualRegister(SrcReg) && "Machine PHI Operands must all be virtual registers!"); @@ -294,7 +299,7 @@ void llvm::PHIElimination::LowerAtomicPHINode( // Insert the copy. if (!reusedIncoming && IncomingReg) BuildMI(opBlock, InsertPos, MPhi->getDebugLoc(), - TII->get(TargetOpcode::COPY), IncomingReg).addReg(SrcReg); + TII->get(TargetOpcode::COPY), IncomingReg).addReg(SrcReg, 0, SrcSubReg); // Now update live variable information if we have it. Otherwise we're done if (!LV) continue; @@ -378,10 +383,12 @@ void llvm::PHIElimination::analyzePHINodes(const MachineFunction& MF) { bool llvm::PHIElimination::SplitPHIEdges(MachineFunction &MF, MachineBasicBlock &MBB, - LiveVariables &LV) { + LiveVariables &LV, + MachineLoopInfo *MLI) { if (MBB.empty() || !MBB.front().isPHI() || MBB.isLandingPad()) return false; // Quick exit for basic blocks without PHIs. + bool Changed = false; for (MachineBasicBlock::const_iterator BBI = MBB.begin(), BBE = MBB.end(); BBI != BBE && BBI->isPHI(); ++BBI) { for (unsigned i = 1, e = BBI->getNumOperands(); i != e; i += 2) { @@ -390,8 +397,15 @@ bool llvm::PHIElimination::SplitPHIEdges(MachineFunction &MF, // We break edges when registers are live out from the predecessor block // (not considering PHI nodes). If the register is live in to this block // anyway, we would gain nothing from splitting. - if (!LV.isLiveIn(Reg, MBB) && LV.isLiveOut(Reg, *PreMBB)) - PreMBB->SplitCriticalEdge(&MBB, this); + // Avoid splitting backedges of loops. It would introduce small + // out-of-line blocks into the loop which is very bad for code placement. + if (PreMBB != &MBB && + !LV.isLiveIn(Reg, MBB) && LV.isLiveOut(Reg, *PreMBB)) { + if (!MLI || + !(MLI->getLoopFor(PreMBB) == MLI->getLoopFor(&MBB) && + MLI->isLoopHeader(&MBB))) + Changed |= PreMBB->SplitCriticalEdge(&MBB, this) != 0; + } } } return true; diff --git a/lib/CodeGen/PHIElimination.h b/lib/CodeGen/PHIElimination.h index 7dedf03..45a9718 100644 --- a/lib/CodeGen/PHIElimination.h +++ b/lib/CodeGen/PHIElimination.h @@ -13,19 +13,21 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineRegisterInfo.h" namespace llvm { class LiveVariables; + class MachineRegisterInfo; + class MachineLoopInfo; /// Lower PHI instructions to copies. class PHIElimination : public MachineFunctionPass { - MachineRegisterInfo *MRI; // Machine register information + MachineRegisterInfo *MRI; // Machine register information public: static char ID; // Pass identification, replacement for typeid - PHIElimination() : MachineFunctionPass(&ID) {} + PHIElimination() : MachineFunctionPass(ID) {} virtual bool runOnMachineFunction(MachineFunction &Fn); @@ -49,7 +51,7 @@ namespace llvm { /// Split critical edges where necessary for good coalescer performance. bool SplitPHIEdges(MachineFunction &MF, MachineBasicBlock &MBB, - LiveVariables &LV); + LiveVariables &LV, MachineLoopInfo *MLI); /// SplitCriticalEdge - Split a critical edge from A to B by /// inserting a new MBB. Update branches in A and PHI instructions diff --git a/lib/CodeGen/PeepholeOptimizer.cpp b/lib/CodeGen/PeepholeOptimizer.cpp new file mode 100644 index 0000000..17cee46 --- /dev/null +++ b/lib/CodeGen/PeepholeOptimizer.cpp @@ -0,0 +1,287 @@ +//===-- PeepholeOptimizer.cpp - Peephole Optimizations --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Perform peephole optimizations on the machine code: +// +// - Optimize Extensions +// +// Optimization of sign / zero extension instructions. It may be extended to +// handle other instructions with similar properties. +// +// On some targets, some instructions, e.g. X86 sign / zero extension, may +// leave the source value in the lower part of the result. This optimization +// will replace some uses of the pre-extension value with uses of the +// sub-register of the results. +// +// - Optimize Comparisons +// +// Optimization of comparison instructions. For instance, in this code: +// +// sub r1, 1 +// cmp r1, 0 +// bz L1 +// +// If the "sub" instruction all ready sets (or could be modified to set) the +// same flag that the "cmp" instruction sets and that "bz" uses, then we can +// eliminate the "cmp" instruction. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "peephole-opt" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/MachineDominators.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/Statistic.h" +using namespace llvm; + +// Optimize Extensions +static cl::opt +Aggressive("aggressive-ext-opt", cl::Hidden, + cl::desc("Aggressive extension optimization")); + +STATISTIC(NumReuse, "Number of extension results reused"); +STATISTIC(NumEliminated, "Number of compares eliminated"); + +namespace { + class PeepholeOptimizer : public MachineFunctionPass { + const TargetMachine *TM; + const TargetInstrInfo *TII; + MachineRegisterInfo *MRI; + MachineDominatorTree *DT; // Machine dominator tree + + public: + static char ID; // Pass identification + PeepholeOptimizer() : MachineFunctionPass(ID) {} + + virtual bool runOnMachineFunction(MachineFunction &MF); + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); + MachineFunctionPass::getAnalysisUsage(AU); + if (Aggressive) { + AU.addRequired(); + AU.addPreserved(); + } + } + + private: + bool OptimizeCmpInstr(MachineInstr *MI, MachineBasicBlock *MBB); + bool OptimizeExtInstr(MachineInstr *MI, MachineBasicBlock *MBB, + SmallPtrSet &LocalMIs); + }; +} + +char PeepholeOptimizer::ID = 0; +INITIALIZE_PASS(PeepholeOptimizer, "peephole-opts", + "Peephole Optimizations", false, false); + +FunctionPass *llvm::createPeepholeOptimizerPass() { + return new PeepholeOptimizer(); +} + +/// OptimizeExtInstr - If instruction is a copy-like instruction, i.e. it reads +/// a single register and writes a single register and it does not modify the +/// source, and if the source value is preserved as a sub-register of the +/// result, then replace all reachable uses of the source with the subreg of the +/// result. +/// +/// Do not generate an EXTRACT that is used only in a debug use, as this changes +/// the code. Since this code does not currently share EXTRACTs, just ignore all +/// debug uses. +bool PeepholeOptimizer:: +OptimizeExtInstr(MachineInstr *MI, MachineBasicBlock *MBB, + SmallPtrSet &LocalMIs) { + LocalMIs.insert(MI); + + unsigned SrcReg, DstReg, SubIdx; + if (!TII->isCoalescableExtInstr(*MI, SrcReg, DstReg, SubIdx)) + return false; + + if (TargetRegisterInfo::isPhysicalRegister(DstReg) || + TargetRegisterInfo::isPhysicalRegister(SrcReg)) + return false; + + MachineRegisterInfo::use_nodbg_iterator UI = MRI->use_nodbg_begin(SrcReg); + if (++UI == MRI->use_nodbg_end()) + // No other uses. + return false; + + // The source has other uses. See if we can replace the other uses with use of + // the result of the extension. + SmallPtrSet ReachedBBs; + UI = MRI->use_nodbg_begin(DstReg); + for (MachineRegisterInfo::use_nodbg_iterator UE = MRI->use_nodbg_end(); + UI != UE; ++UI) + ReachedBBs.insert(UI->getParent()); + + // Uses that are in the same BB of uses of the result of the instruction. + SmallVector Uses; + + // Uses that the result of the instruction can reach. + SmallVector ExtendedUses; + + bool ExtendLife = true; + UI = MRI->use_nodbg_begin(SrcReg); + for (MachineRegisterInfo::use_nodbg_iterator UE = MRI->use_nodbg_end(); + UI != UE; ++UI) { + MachineOperand &UseMO = UI.getOperand(); + MachineInstr *UseMI = &*UI; + if (UseMI == MI) + continue; + + if (UseMI->isPHI()) { + ExtendLife = false; + continue; + } + + // It's an error to translate this: + // + // %reg1025 = %reg1024 + // ... + // %reg1026 = SUBREG_TO_REG 0, %reg1024, 4 + // + // into this: + // + // %reg1025 = %reg1024 + // ... + // %reg1027 = COPY %reg1025:4 + // %reg1026 = SUBREG_TO_REG 0, %reg1027, 4 + // + // The problem here is that SUBREG_TO_REG is there to assert that an + // implicit zext occurs. It doesn't insert a zext instruction. If we allow + // the COPY here, it will give us the value after the , not the + // original value of %reg1024 before . + if (UseMI->getOpcode() == TargetOpcode::SUBREG_TO_REG) + continue; + + MachineBasicBlock *UseMBB = UseMI->getParent(); + if (UseMBB == MBB) { + // Local uses that come after the extension. + if (!LocalMIs.count(UseMI)) + Uses.push_back(&UseMO); + } else if (ReachedBBs.count(UseMBB)) { + // Non-local uses where the result of the extension is used. Always + // replace these unless it's a PHI. + Uses.push_back(&UseMO); + } else if (Aggressive && DT->dominates(MBB, UseMBB)) { + // We may want to extend the live range of the extension result in order + // to replace these uses. + ExtendedUses.push_back(&UseMO); + } else { + // Both will be live out of the def MBB anyway. Don't extend live range of + // the extension result. + ExtendLife = false; + break; + } + } + + if (ExtendLife && !ExtendedUses.empty()) + // Extend the liveness of the extension result. + std::copy(ExtendedUses.begin(), ExtendedUses.end(), + std::back_inserter(Uses)); + + // Now replace all uses. + bool Changed = false; + if (!Uses.empty()) { + SmallPtrSet PHIBBs; + + // Look for PHI uses of the extended result, we don't want to extend the + // liveness of a PHI input. It breaks all kinds of assumptions down + // stream. A PHI use is expected to be the kill of its source values. + UI = MRI->use_nodbg_begin(DstReg); + for (MachineRegisterInfo::use_nodbg_iterator + UE = MRI->use_nodbg_end(); UI != UE; ++UI) + if (UI->isPHI()) + PHIBBs.insert(UI->getParent()); + + const TargetRegisterClass *RC = MRI->getRegClass(SrcReg); + for (unsigned i = 0, e = Uses.size(); i != e; ++i) { + MachineOperand *UseMO = Uses[i]; + MachineInstr *UseMI = UseMO->getParent(); + MachineBasicBlock *UseMBB = UseMI->getParent(); + if (PHIBBs.count(UseMBB)) + continue; + + unsigned NewVR = MRI->createVirtualRegister(RC); + BuildMI(*UseMBB, UseMI, UseMI->getDebugLoc(), + TII->get(TargetOpcode::COPY), NewVR) + .addReg(DstReg, 0, SubIdx); + + UseMO->setReg(NewVR); + ++NumReuse; + Changed = true; + } + } + + return Changed; +} + +/// OptimizeCmpInstr - If the instruction is a compare and the previous +/// instruction it's comparing against all ready sets (or could be modified to +/// set) the same flag as the compare, then we can remove the comparison and use +/// the flag from the previous instruction. +bool PeepholeOptimizer::OptimizeCmpInstr(MachineInstr *MI, + MachineBasicBlock *MBB) { + // If this instruction is a comparison against zero and isn't comparing a + // physical register, we can try to optimize it. + unsigned SrcReg; + int CmpValue; + if (!TII->AnalyzeCompare(MI, SrcReg, CmpValue) || + TargetRegisterInfo::isPhysicalRegister(SrcReg) || CmpValue != 0) + return false; + + MachineRegisterInfo::def_iterator DI = MRI->def_begin(SrcReg); + if (llvm::next(DI) != MRI->def_end()) + // Only support one definition. + return false; + + // Attempt to convert the defining instruction to set the "zero" flag. + if (TII->ConvertToSetZeroFlag(&*DI, MI)) { + ++NumEliminated; + return true; + } + + return false; +} + +bool PeepholeOptimizer::runOnMachineFunction(MachineFunction &MF) { + TM = &MF.getTarget(); + TII = TM->getInstrInfo(); + MRI = &MF.getRegInfo(); + DT = Aggressive ? &getAnalysis() : 0; + + bool Changed = false; + + SmallPtrSet LocalMIs; + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) { + MachineBasicBlock *MBB = &*I; + LocalMIs.clear(); + + for (MachineBasicBlock::iterator + MII = I->begin(), ME = I->end(); MII != ME; ) { + MachineInstr *MI = &*MII; + + if (MI->getDesc().isCompare() && + !MI->getDesc().hasUnmodeledSideEffects()) { + ++MII; // The iterator may become invalid if the compare is deleted. + Changed |= OptimizeCmpInstr(MI, MBB); + } else { + Changed |= OptimizeExtInstr(MI, MBB, LocalMIs); + ++MII; + } + } + } + + return Changed; +} diff --git a/lib/CodeGen/PostRASchedulerList.cpp b/lib/CodeGen/PostRASchedulerList.cpp index 4af8e07..f0bd6d1 100644 --- a/lib/CodeGen/PostRASchedulerList.cpp +++ b/lib/CodeGen/PostRASchedulerList.cpp @@ -85,7 +85,7 @@ namespace { public: static char ID; PostRAScheduler(CodeGenOpt::Level ol) : - MachineFunctionPass(&ID), OptLevel(ol) {} + MachineFunctionPass(ID), OptLevel(ol) {} void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); @@ -130,7 +130,7 @@ namespace { /// KillIndices - The index of the most recent kill (proceding bottom-up), /// or ~0u if the register is not live. - unsigned KillIndices[TargetRegisterInfo::FirstVirtualRegister]; + std::vector KillIndices; public: SchedulePostRATDList(MachineFunction &MF, @@ -140,7 +140,8 @@ namespace { AntiDepBreaker *ADB, AliasAnalysis *aa) : ScheduleDAGInstrs(MF, MLI, MDT), Topo(SUnits), - HazardRec(HR), AntiDepBreak(ADB), AA(aa) {} + HazardRec(HR), AntiDepBreak(ADB), AA(aa), + KillIndices(TRI->getNumRegs()) {} ~SchedulePostRATDList() { } diff --git a/lib/CodeGen/PreAllocSplitting.cpp b/lib/CodeGen/PreAllocSplitting.cpp index fb2f909..cd9d83e 100644 --- a/lib/CodeGen/PreAllocSplitting.cpp +++ b/lib/CodeGen/PreAllocSplitting.cpp @@ -92,7 +92,7 @@ namespace { public: static char ID; PreAllocSplitting() - : MachineFunctionPass(&ID) {} + : MachineFunctionPass(ID) {} virtual bool runOnMachineFunction(MachineFunction &MF); @@ -203,10 +203,11 @@ namespace { char PreAllocSplitting::ID = 0; -static RegisterPass -X("pre-alloc-splitting", "Pre-Register Allocation Live Interval Splitting"); +INITIALIZE_PASS(PreAllocSplitting, "pre-alloc-splitting", + "Pre-Register Allocation Live Interval Splitting", + false, false); -const PassInfo *const llvm::PreAllocSplittingID = &X; +char &llvm::PreAllocSplittingID = PreAllocSplitting::ID; /// findSpillPoint - Find a gap as far away from the given MI that's suitable /// for spilling the current live interval. The index must be before any @@ -676,11 +677,7 @@ void PreAllocSplitting::ReconstructLiveInterval(LiveInterval* LI) { VNInfo* NewVN = LI->getNextValue(DefIdx, 0, true, Alloc); // If the def is a move, set the copy field. - unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx; - if (TII->isMoveInstr(*DI, SrcReg, DstReg, SrcSubIdx, DstSubIdx)) { - if (DstReg == LI->reg) - NewVN->setCopy(&*DI); - } else if (DI->isCopyLike() && DI->getOperand(0).getReg() == LI->reg) + if (DI->isCopyLike() && DI->getOperand(0).getReg() == LI->reg) NewVN->setCopy(&*DI); NewVNs[&*DI] = NewVN; diff --git a/lib/CodeGen/ProcessImplicitDefs.cpp b/lib/CodeGen/ProcessImplicitDefs.cpp index 2e31908..b8831db 100644 --- a/lib/CodeGen/ProcessImplicitDefs.cpp +++ b/lib/CodeGen/ProcessImplicitDefs.cpp @@ -26,8 +26,8 @@ using namespace llvm; char ProcessImplicitDefs::ID = 0; -static RegisterPass X("processimpdefs", - "Process Implicit Definitions."); +INITIALIZE_PASS(ProcessImplicitDefs, "processimpdefs", + "Process Implicit Definitions.", false, false); void ProcessImplicitDefs::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); @@ -46,12 +46,6 @@ ProcessImplicitDefs::CanTurnIntoImplicitDef(MachineInstr *MI, unsigned Reg, unsigned OpIdx, const TargetInstrInfo *tii_, SmallSet &ImpDefRegs) { - unsigned SrcReg, DstReg, SrcSubReg, DstSubReg; - if (tii_->isMoveInstr(*MI, SrcReg, DstReg, SrcSubReg, DstSubReg) && - Reg == SrcReg && - (DstSubReg == 0 || ImpDefRegs.count(DstReg))) - return true; - switch(OpIdx) { case 1: return MI->isCopy() && (MI->getOperand(0).getSubReg() == 0 || @@ -75,14 +69,6 @@ static bool isUndefCopy(MachineInstr *MI, unsigned Reg, return true; return false; } - - unsigned SrcReg, DstReg, SrcSubReg, DstSubReg; - if (tii_->isMoveInstr(*MI, SrcReg, DstReg, SrcSubReg, DstSubReg)) { - if (Reg != SrcReg) - return false; - if (DstSubReg == 0 || ImpDefRegs.count(DstReg)) - return true; - } return false; } diff --git a/lib/CodeGen/PrologEpilogInserter.cpp b/lib/CodeGen/PrologEpilogInserter.cpp index 3843b25..e2802c1 100644 --- a/lib/CodeGen/PrologEpilogInserter.cpp +++ b/lib/CodeGen/PrologEpilogInserter.cpp @@ -19,6 +19,7 @@ // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "pei" #include "PrologEpilogInserter.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineLoopInfo.h" @@ -32,7 +33,10 @@ #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" #include "llvm/ADT/IndexedMap.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/Statistic.h" #include "llvm/ADT/STLExtras.h" #include @@ -40,8 +44,11 @@ using namespace llvm; char PEI::ID = 0; -static RegisterPass -X("prologepilog", "Prologue/Epilogue Insertion"); +INITIALIZE_PASS(PEI, "prologepilog", + "Prologue/Epilogue Insertion", false, false); + +STATISTIC(NumVirtualFrameRegs, "Number of virtual frame regs encountered"); +STATISTIC(NumScavengedRegs, "Number of frame index regs scavenged"); /// createPrologEpilogCodeInserter - This function returns a pass that inserts /// prolog and epilog code, and eliminates abstract frame references. @@ -56,7 +63,6 @@ bool PEI::runOnMachineFunction(MachineFunction &Fn) { const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo(); RS = TRI->requiresRegisterScavenging(Fn) ? new RegScavenger() : NULL; FrameIndexVirtualScavenging = TRI->requiresFrameIndexScavenging(Fn); - FrameConstantRegMap.clear(); // Calculate the MaxCallFrameSize and AdjustsStack variables for the // function's frame information. Also eliminates call frame pseudo @@ -72,10 +78,10 @@ bool PEI::runOnMachineFunction(MachineFunction &Fn) { calculateCalleeSavedRegisters(Fn); // Determine placement of CSR spill/restore code: - // - with shrink wrapping, place spills and restores to tightly + // - With shrink wrapping, place spills and restores to tightly // enclose regions in the Machine CFG of the function where - // they are used. Without shrink wrapping - // - default (no shrink wrapping), place all spills in the + // they are used. + // - Without shink wrapping (default), place all spills in the // entry block, all restores in return blocks. placeCSRSpillsAndRestores(Fn); @@ -461,8 +467,10 @@ AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx, Offset = (Offset + Align - 1) / Align * Align; if (StackGrowsDown) { + DEBUG(dbgs() << "alloc FI(" << FrameIdx << ") at SP[" << -Offset << "]\n"); MFI->setObjectOffset(FrameIdx, -Offset); // Set the computed offset } else { + DEBUG(dbgs() << "alloc FI(" << FrameIdx << ") at SP[" << Offset << "]\n"); MFI->setObjectOffset(FrameIdx, Offset); Offset += MFI->getObjectSize(FrameIdx); } @@ -547,15 +555,66 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) { AdjustStackOffset(MFI, SFI, StackGrowsDown, Offset, MaxAlign); } + // FIXME: Once this is working, then enable flag will change to a target + // check for whether the frame is large enough to want to use virtual + // frame index registers. Functions which don't want/need this optimization + // will continue to use the existing code path. + if (MFI->getUseLocalStackAllocationBlock()) { + unsigned Align = MFI->getLocalFrameMaxAlign(); + + // Adjust to alignment boundary. + Offset = (Offset + Align - 1) / Align * Align; + + DEBUG(dbgs() << "Local frame base offset: " << Offset << "\n"); + + // Resolve offsets for objects in the local block. + for (unsigned i = 0, e = MFI->getLocalFrameObjectCount(); i != e; ++i) { + std::pair Entry = MFI->getLocalFrameObjectMap(i); + int64_t FIOffset = (StackGrowsDown ? -Offset : Offset) + Entry.second; + DEBUG(dbgs() << "alloc FI(" << Entry.first << ") at SP[" << + FIOffset << "]\n"); + MFI->setObjectOffset(Entry.first, FIOffset); + } + // Allocate the local block + Offset += MFI->getLocalFrameSize(); + + MaxAlign = std::max(Align, MaxAlign); + } + // Make sure that the stack protector comes before the local variables on the // stack. - if (MFI->getStackProtectorIndex() >= 0) + SmallSet LargeStackObjs; + if (MFI->getStackProtectorIndex() >= 0) { AdjustStackOffset(MFI, MFI->getStackProtectorIndex(), StackGrowsDown, Offset, MaxAlign); + // Assign large stack objects first. + for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) { + if (MFI->isObjectPreAllocated(i) && + MFI->getUseLocalStackAllocationBlock()) + continue; + if (i >= MinCSFrameIndex && i <= MaxCSFrameIndex) + continue; + if (RS && (int)i == RS->getScavengingFrameIndex()) + continue; + if (MFI->isDeadObjectIndex(i)) + continue; + if (MFI->getStackProtectorIndex() == (int)i) + continue; + if (!MFI->MayNeedStackProtector(i)) + continue; + + AdjustStackOffset(MFI, i, StackGrowsDown, Offset, MaxAlign); + LargeStackObjs.insert(i); + } + } + // Then assign frame offsets to stack objects that are not used to spill // callee saved registers. for (unsigned i = 0, e = MFI->getObjectIndexEnd(); i != e; ++i) { + if (MFI->isObjectPreAllocated(i) && + MFI->getUseLocalStackAllocationBlock()) + continue; if (i >= MinCSFrameIndex && i <= MaxCSFrameIndex) continue; if (RS && (int)i == RS->getScavengingFrameIndex()) @@ -564,6 +623,8 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) { continue; if (MFI->getStackProtectorIndex() == (int)i) continue; + if (LargeStackObjs.count(i)) + continue; AdjustStackOffset(MFI, i, StackGrowsDown, Offset, MaxAlign); } @@ -694,16 +755,8 @@ void PEI::replaceFrameIndices(MachineFunction &Fn) { // If this instruction has a FrameIndex operand, we need to // use that target machine register info object to eliminate // it. - TargetRegisterInfo::FrameIndexValue Value; - unsigned VReg = - TRI.eliminateFrameIndex(MI, SPAdj, &Value, + TRI.eliminateFrameIndex(MI, SPAdj, FrameIndexVirtualScavenging ? NULL : RS); - if (VReg) { - assert (FrameIndexVirtualScavenging && - "Not scavenging, but virtual returned from " - "eliminateFrameIndex()!"); - FrameConstantRegMap[VReg] = FrameConstantEntry(Value, SPAdj); - } // Reset the iterator if we were at the beginning of the BB. if (AtBeginning) { @@ -731,38 +784,6 @@ void PEI::replaceFrameIndices(MachineFunction &Fn) { } } -/// findLastUseReg - find the killing use of the specified register within -/// the instruciton range. Return the operand number of the kill in Operand. -static MachineBasicBlock::iterator -findLastUseReg(MachineBasicBlock::iterator I, MachineBasicBlock::iterator ME, - unsigned Reg) { - // Scan forward to find the last use of this virtual register - for (++I; I != ME; ++I) { - MachineInstr *MI = I; - bool isDefInsn = false; - bool isKillInsn = false; - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) - if (MI->getOperand(i).isReg()) { - unsigned OpReg = MI->getOperand(i).getReg(); - if (OpReg == 0 || !TargetRegisterInfo::isVirtualRegister(OpReg)) - continue; - assert (OpReg == Reg - && "overlapping use of scavenged index register!"); - // If this is the killing use, we have a candidate. - if (MI->getOperand(i).isKill()) - isKillInsn = true; - else if (MI->getOperand(i).isDef()) - isDefInsn = true; - } - if (isKillInsn && !isDefInsn) - return I; - } - // If we hit the end of the basic block, there was no kill of - // the virtual register, which is wrong. - assert (0 && "scavenged index register never killed!"); - return ME; -} - /// scavengeFrameVirtualRegs - Replace all frame index virtual registers /// with physical registers. Use the register scavenger to find an /// appropriate register to use. @@ -772,27 +793,14 @@ void PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) { E = Fn.end(); BB != E; ++BB) { RS->enterBasicBlock(BB); - // FIXME: The logic flow in this function is still too convoluted. - // It needs a cleanup refactoring. Do that in preparation for tracking - // more than one scratch register value and using ranges to find - // available scratch registers. - unsigned CurrentVirtReg = 0; - unsigned CurrentScratchReg = 0; - bool havePrevValue = false; - TargetRegisterInfo::FrameIndexValue PrevValue(0,0); - TargetRegisterInfo::FrameIndexValue Value(0,0); - MachineInstr *PrevLastUseMI = NULL; - unsigned PrevLastUseOp = 0; - bool trackingCurrentValue = false; + unsigned VirtReg = 0; + unsigned ScratchReg = 0; int SPAdj = 0; // The instruction stream may change in the loop, so check BB->end() // directly. for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ) { MachineInstr *MI = I; - bool isDefInsn = false; - bool isKillInsn = false; - bool clobbersScratchReg = false; bool DoIncr = true; for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { if (MI->getOperand(i).isReg()) { @@ -800,121 +808,30 @@ void PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) { unsigned Reg = MO.getReg(); if (Reg == 0) continue; - if (!TargetRegisterInfo::isVirtualRegister(Reg)) { - // If we have a previous scratch reg, check and see if anything - // here kills whatever value is in there. - if (Reg == CurrentScratchReg) { - if (MO.isUse()) { - // Two-address operands implicitly kill - if (MO.isKill() || MI->isRegTiedToDefOperand(i)) - clobbersScratchReg = true; - } else { - assert (MO.isDef()); - clobbersScratchReg = true; - } - } + if (!TargetRegisterInfo::isVirtualRegister(Reg)) continue; - } - // If this is a def, remember that this insn defines the value. - // This lets us properly consider insns which re-use the scratch - // register, such as r2 = sub r2, #imm, in the middle of the - // scratch range. - if (MO.isDef()) - isDefInsn = true; + + ++NumVirtualFrameRegs; // Have we already allocated a scratch register for this virtual? - if (Reg != CurrentVirtReg) { + if (Reg != VirtReg) { // When we first encounter a new virtual register, it // must be a definition. assert(MI->getOperand(i).isDef() && "frame index virtual missing def!"); - // We can't have nested virtual register live ranges because - // there's only a guarantee of one scavenged register at a time. - assert (CurrentVirtReg == 0 && - "overlapping frame index virtual registers!"); - - // If the target gave us information about what's in the register, - // we can use that to re-use scratch regs. - DenseMap::iterator Entry = - FrameConstantRegMap.find(Reg); - trackingCurrentValue = Entry != FrameConstantRegMap.end(); - if (trackingCurrentValue) { - SPAdj = (*Entry).second.second; - Value = (*Entry).second.first; - } else { - SPAdj = 0; - Value.first = 0; - Value.second = 0; - } - - // If the scratch register from the last allocation is still - // available, see if the value matches. If it does, just re-use it. - if (trackingCurrentValue && havePrevValue && PrevValue == Value) { - // FIXME: This assumes that the instructions in the live range - // for the virtual register are exclusively for the purpose - // of populating the value in the register. That's reasonable - // for these frame index registers, but it's still a very, very - // strong assumption. rdar://7322732. Better would be to - // explicitly check each instruction in the range for references - // to the virtual register. Only delete those insns that - // touch the virtual register. - - // Find the last use of the new virtual register. Remove all - // instruction between here and there, and update the current - // instruction to reference the last use insn instead. - MachineBasicBlock::iterator LastUseMI = - findLastUseReg(I, BB->end(), Reg); - - // Remove all instructions up 'til the last use, since they're - // just calculating the value we already have. - BB->erase(I, LastUseMI); - I = LastUseMI; - - // Extend the live range of the scratch register - PrevLastUseMI->getOperand(PrevLastUseOp).setIsKill(false); - RS->setUsed(CurrentScratchReg); - CurrentVirtReg = Reg; - - // We deleted the instruction we were scanning the operands of. - // Jump back to the instruction iterator loop. Don't increment - // past this instruction since we updated the iterator already. - DoIncr = false; - break; - } - // Scavenge a new scratch register - CurrentVirtReg = Reg; + VirtReg = Reg; const TargetRegisterClass *RC = Fn.getRegInfo().getRegClass(Reg); - CurrentScratchReg = RS->scavengeRegister(RC, I, SPAdj); - PrevValue = Value; + ScratchReg = RS->scavengeRegister(RC, I, SPAdj); + ++NumScavengedRegs; } // replace this reference to the virtual register with the // scratch register. - assert (CurrentScratchReg && "Missing scratch register!"); - MI->getOperand(i).setReg(CurrentScratchReg); + assert (ScratchReg && "Missing scratch register!"); + MI->getOperand(i).setReg(ScratchReg); - if (MI->getOperand(i).isKill()) { - isKillInsn = true; - PrevLastUseOp = i; - PrevLastUseMI = MI; - } } } - // If this is the last use of the scratch, stop tracking it. The - // last use will be a kill operand in an instruction that does - // not also define the scratch register. - if (isKillInsn && !isDefInsn) { - CurrentVirtReg = 0; - havePrevValue = trackingCurrentValue; - } - // Similarly, notice if instruction clobbered the value in the - // register we're tracking for possible later reuse. This is noted - // above, but enforced here since the value is still live while we - // process the rest of the operands of the instruction. - if (clobbersScratchReg) { - havePrevValue = false; - CurrentScratchReg = 0; - } if (DoIncr) { RS->forward(I); ++I; diff --git a/lib/CodeGen/PrologEpilogInserter.h b/lib/CodeGen/PrologEpilogInserter.h index aa95773..d575124 100644 --- a/lib/CodeGen/PrologEpilogInserter.h +++ b/lib/CodeGen/PrologEpilogInserter.h @@ -36,7 +36,7 @@ namespace llvm { class PEI : public MachineFunctionPass { public: static char ID; - PEI() : MachineFunctionPass(&ID) {} + PEI() : MachineFunctionPass(ID) {} const char *getPassName() const { return "Prolog/Epilog Insertion & Frame Finalization"; @@ -99,13 +99,6 @@ namespace llvm { // TRI->requiresFrameIndexScavenging() for the curren function. bool FrameIndexVirtualScavenging; - // When using the scavenger post-pass to resolve frame reference - // materialization registers, maintain a map of the registers to - // the constant value and SP adjustment associated with it. - typedef std::pair - FrameConstantEntry; - DenseMap FrameConstantRegMap; - #ifndef NDEBUG // Machine function handle. MachineFunction* MF; diff --git a/lib/CodeGen/RegAllocFast.cpp b/lib/CodeGen/RegAllocFast.cpp index f44478e..fc150d5 100644 --- a/lib/CodeGen/RegAllocFast.cpp +++ b/lib/CodeGen/RegAllocFast.cpp @@ -16,6 +16,7 @@ #include "llvm/BasicBlock.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" @@ -46,7 +47,7 @@ namespace { class RAFast : public MachineFunctionPass { public: static char ID; - RAFast() : MachineFunctionPass(&ID), StackSlotForVirtReg(-1), + RAFast() : MachineFunctionPass(ID), StackSlotForVirtReg(-1), isBulkSpilling(false) {} private: const TargetMachine *TM; @@ -80,6 +81,8 @@ namespace { // that is currently available in a physical register. LiveRegMap LiveVirtRegs; + DenseMap LiveDbgValueMap; + // RegState - Track the state of a physical register. enum RegState { // A disabled register is not available for allocation, but an alias may @@ -110,9 +113,9 @@ namespace { // Allocatable - vector of allocatable physical registers. BitVector Allocatable; - // SkippedInstrs - Descriptors of instructions whose clobber list was ignored - // because all registers were spilled. It is still necessary to mark all the - // clobbered registers as used by the function. + // SkippedInstrs - Descriptors of instructions whose clobber list was + // ignored because all registers were spilled. It is still necessary to + // mark all the clobbered registers as used by the function. SmallPtrSet SkippedInstrs; // isBulkSpilling - This flag is set when LiveRegMap will be cleared @@ -236,8 +239,7 @@ void RAFast::killVirtReg(unsigned VirtReg) { } /// spillVirtReg - This method spills the value specified by VirtReg into the -/// corresponding stack slot if needed. If isKill is set, the register is also -/// killed. +/// corresponding stack slot if needed. void RAFast::spillVirtReg(MachineBasicBlock::iterator MI, unsigned VirtReg) { assert(TargetRegisterInfo::isVirtualRegister(VirtReg) && "Spilling a physical register is illegal!"); @@ -265,6 +267,31 @@ void RAFast::spillVirtReg(MachineBasicBlock::iterator MI, TII->storeRegToStackSlot(*MBB, MI, LR.PhysReg, SpillKill, FI, RC, TRI); ++NumStores; // Update statistics + // If this register is used by DBG_VALUE then insert new DBG_VALUE to + // identify spilled location as the place to find corresponding variable's + // value. + if (MachineInstr *DBG = LiveDbgValueMap.lookup(LRI->first)) { + const MDNode *MDPtr = + DBG->getOperand(DBG->getNumOperands()-1).getMetadata(); + int64_t Offset = 0; + if (DBG->getOperand(1).isImm()) + Offset = DBG->getOperand(1).getImm(); + DebugLoc DL; + if (MI == MBB->end()) { + // If MI is at basic block end then use last instruction's location. + MachineBasicBlock::iterator EI = MI; + DL = (--EI)->getDebugLoc(); + } + else + DL = MI->getDebugLoc(); + if (MachineInstr *NewDV = + TII->emitFrameIndexDebugValue(*MF, FI, Offset, MDPtr, DL)) { + MachineBasicBlock *MBB = DBG->getParent(); + MBB->insert(MI, NewDV); + DEBUG(dbgs() << "Inserting debug info due to spill:" << "\n" << *NewDV); + LiveDbgValueMap[LRI->first] = NewDV; + } + } if (SpillKill) LR.LastUse = 0; // Don't kill register again } @@ -471,7 +498,8 @@ void RAFast::allocVirtReg(MachineInstr *MI, LiveRegEntry &LRE, unsigned Hint) { // First try to find a completely free register. for (TargetRegisterClass::iterator I = AOB; I != AOE; ++I) { unsigned PhysReg = *I; - if (PhysRegState[PhysReg] == regFree && !UsedInInstr.test(PhysReg)) + if (PhysRegState[PhysReg] == regFree && !UsedInInstr.test(PhysReg) && + Allocatable.test(PhysReg)) return assignVirtToPhysReg(LRE, PhysReg); } @@ -480,6 +508,8 @@ void RAFast::allocVirtReg(MachineInstr *MI, LiveRegEntry &LRE, unsigned Hint) { unsigned BestReg = 0, BestCost = spillImpossible; for (TargetRegisterClass::iterator I = AOB; I != AOE; ++I) { + if (!Allocatable.test(*I)) + continue; unsigned Cost = calcSpillCost(*I); // Cost is 0 when all aliases are already disabled. if (Cost == 0) @@ -520,12 +550,9 @@ RAFast::defineVirtReg(MachineInstr *MI, unsigned OpNum, if ((!Hint || !TargetRegisterInfo::isPhysicalRegister(Hint)) && MRI->hasOneNonDBGUse(VirtReg)) { const MachineInstr &UseMI = *MRI->use_nodbg_begin(VirtReg); - unsigned SrcReg, DstReg, SrcSubReg, DstSubReg; // It's a copy, use the destination register as a hint. if (UseMI.isCopyLike()) Hint = UseMI.getOperand(0).getReg(); - else if (TII->isMoveInstr(UseMI, SrcReg, DstReg, SrcSubReg, DstSubReg)) - Hint = DstReg; } allocVirtReg(MI, *LRI, Hint); } else if (LR.LastUse) { @@ -712,7 +739,8 @@ void RAFast::AllocateBasicBlock() { // Add live-in registers as live. for (MachineBasicBlock::livein_iterator I = MBB->livein_begin(), E = MBB->livein_end(); I != E; ++I) - definePhysReg(MII, *I, regReserved); + if (Allocatable.test(*I)) + definePhysReg(MII, *I, regReserved); SmallVector VirtDead; SmallVector Coalesced; @@ -756,31 +784,43 @@ void RAFast::AllocateBasicBlock() { // Debug values are not allowed to change codegen in any way. if (MI->isDebugValue()) { - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { - MachineOperand &MO = MI->getOperand(i); - if (!MO.isReg()) continue; - unsigned Reg = MO.getReg(); - if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) continue; - LiveRegMap::iterator LRI = LiveVirtRegs.find(Reg); - if (LRI != LiveVirtRegs.end()) - setPhysReg(MI, i, LRI->second.PhysReg); - else { - int SS = StackSlotForVirtReg[Reg]; - if (SS == -1) - MO.setReg(0); // We can't allocate a physreg for a DebugValue, sorry! + bool ScanDbgValue = true; + while (ScanDbgValue) { + ScanDbgValue = false; + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + MachineOperand &MO = MI->getOperand(i); + if (!MO.isReg()) continue; + unsigned Reg = MO.getReg(); + if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) continue; + LiveDbgValueMap[Reg] = MI; + LiveRegMap::iterator LRI = LiveVirtRegs.find(Reg); + if (LRI != LiveVirtRegs.end()) + setPhysReg(MI, i, LRI->second.PhysReg); else { - // Modify DBG_VALUE now that the value is in a spill slot. - uint64_t Offset = MI->getOperand(1).getImm(); - const MDNode *MDPtr = - MI->getOperand(MI->getNumOperands()-1).getMetadata(); - DebugLoc DL = MI->getDebugLoc(); - if (MachineInstr *NewDV = - TII->emitFrameIndexDebugValue(*MF, SS, Offset, MDPtr, DL)) { - DEBUG(dbgs() << "Modifying debug info due to spill:" << "\t" << *MI); - MachineBasicBlock *MBB = MI->getParent(); - MBB->insert(MBB->erase(MI), NewDV); - } else - MO.setReg(0); // We can't allocate a physreg for a DebugValue, sorry! + int SS = StackSlotForVirtReg[Reg]; + if (SS == -1) + // We can't allocate a physreg for a DebugValue, sorry! + MO.setReg(0); + else { + // Modify DBG_VALUE now that the value is in a spill slot. + int64_t Offset = MI->getOperand(1).getImm(); + const MDNode *MDPtr = + MI->getOperand(MI->getNumOperands()-1).getMetadata(); + DebugLoc DL = MI->getDebugLoc(); + if (MachineInstr *NewDV = + TII->emitFrameIndexDebugValue(*MF, SS, Offset, MDPtr, DL)) { + DEBUG(dbgs() << "Modifying debug info due to spill:" << + "\t" << *MI); + MachineBasicBlock *MBB = MI->getParent(); + MBB->insert(MBB->erase(MI), NewDV); + // Scan NewDV operands from the beginning. + MI = NewDV; + ScanDbgValue = true; + break; + } else + // We can't allocate a physreg for a DebugValue; sorry! + MO.setReg(0); + } } } } @@ -789,14 +829,13 @@ void RAFast::AllocateBasicBlock() { } // If this is a copy, we may be able to coalesce. - unsigned CopySrc, CopyDst, CopySrcSub, CopyDstSub; + unsigned CopySrc = 0, CopyDst = 0, CopySrcSub = 0, CopyDstSub = 0; if (MI->isCopy()) { CopyDst = MI->getOperand(0).getReg(); CopySrc = MI->getOperand(1).getReg(); CopyDstSub = MI->getOperand(0).getSubReg(); CopySrcSub = MI->getOperand(1).getSubReg(); - } else if (!TII->isMoveInstr(*MI, CopySrc, CopyDst, CopySrcSub, CopyDstSub)) - CopySrc = CopyDst = 0; + } // Track registers used by instruction. UsedInInstr.reset(); @@ -843,13 +882,18 @@ void RAFast::AllocateBasicBlock() { // operands. If there are also physical defs, these registers must avoid // both physical defs and uses, making them more constrained than normal // operands. + // Similarly, if there are multiple defs and tied operands, we must make + // sure the same register is allocated to uses and defs. // We didn't detect inline asm tied operands above, so just make this extra // pass for all inline asm. if (MI->isInlineAsm() || hasEarlyClobbers || hasPartialRedefs || - (hasTiedOps && hasPhysDefs)) { + (hasTiedOps && (hasPhysDefs || TID.getNumDefs() > 1))) { handleThroughOperands(MI, VirtDead); // Don't attempt coalescing when we have funny stuff going on. CopyDst = 0; + // Pretend we have early clobbers so the use operands get marked below. + // This is not necessary for the common case of a single tied use. + hasEarlyClobbers = true; } // Second scan. @@ -870,14 +914,17 @@ void RAFast::AllocateBasicBlock() { MRI->addPhysRegsUsed(UsedInInstr); - // Track registers defined by instruction - early clobbers at this point. + // Track registers defined by instruction - early clobbers and tied uses at + // this point. UsedInInstr.reset(); if (hasEarlyClobbers) { for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { MachineOperand &MO = MI->getOperand(i); - if (!MO.isReg() || !MO.isDef()) continue; + if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); if (!Reg || !TargetRegisterInfo::isPhysicalRegister(Reg)) continue; + // Look for physreg defs and tied uses. + if (!MO.isDef() && !MI->isRegTiedToDefOperand(i)) continue; UsedInInstr.set(Reg); for (const unsigned *AS = TRI->getAliasSet(Reg); *AS; ++AS) UsedInInstr.set(*AS); @@ -887,9 +934,9 @@ void RAFast::AllocateBasicBlock() { unsigned DefOpEnd = MI->getNumOperands(); if (TID.isCall()) { // Spill all virtregs before a call. This serves two purposes: 1. If an - // exception is thrown, the landing pad is going to expect to find registers - // in their spill slots, and 2. we don't have to wade through all the - // operands on the call instruction. + // exception is thrown, the landing pad is going to expect to find + // registers in their spill slots, and 2. we don't have to wade through + // all the operands on the call instruction. DefOpEnd = VirtOpEnd; DEBUG(dbgs() << " Spilling remaining registers before call.\n"); spillAll(MI); @@ -992,6 +1039,7 @@ bool RAFast::runOnMachineFunction(MachineFunction &Fn) { SkippedInstrs.clear(); StackSlotForVirtReg.clear(); + LiveDbgValueMap.clear(); return true; } diff --git a/lib/CodeGen/RegAllocLinearScan.cpp b/lib/CodeGen/RegAllocLinearScan.cpp index 044672d..5c62354 100644 --- a/lib/CodeGen/RegAllocLinearScan.cpp +++ b/lib/CodeGen/RegAllocLinearScan.cpp @@ -87,10 +87,10 @@ namespace { "to skip."), cl::init(0), cl::Hidden); - + struct RALinScan : public MachineFunctionPass { static char ID; - RALinScan() : MachineFunctionPass(&ID) { + RALinScan() : MachineFunctionPass(ID) { // Initialize the queue to record recently-used registers. if (NumRecentlyUsedRegs > 0) RecentRegs.resize(NumRecentlyUsedRegs, 0); @@ -125,9 +125,10 @@ namespace { const TargetRegisterInfo* tri_; const TargetInstrInfo* tii_; BitVector allocatableRegs_; + BitVector reservedRegs_; LiveIntervals* li_; LiveStacks* ls_; - const MachineLoopInfo *loopInfo; + MachineLoopInfo *loopInfo; /// handled_ - Intervals are added to the handled_ set in the order of their /// start value. This is uses for backtracking. @@ -255,9 +256,9 @@ namespace { SmallVector &SpillIntervals); /// attemptTrivialCoalescing - If a simple interval is defined by a copy, - /// try allocate the definition the same register as the source register - /// if the register is not defined during live time of the interval. This - /// eliminate a copy. This is used to coalesce copies which were not + /// try to allocate the definition to the same register as the source, + /// if the register is not defined during the life time of the interval. + /// This eliminates a copy, and is used to coalesce copies which were not /// coalesced away before allocation either due to dest and src being in /// different register classes or because the coalescer was overly /// conservative. @@ -335,6 +336,17 @@ namespace { SmallVector &inactiveCounts, bool SkipDGRegs); + /// getFirstNonReservedPhysReg - return the first non-reserved physical + /// register in the register class. + unsigned getFirstNonReservedPhysReg(const TargetRegisterClass *RC) { + TargetRegisterClass::iterator aoe = RC->allocation_order_end(*mf_); + TargetRegisterClass::iterator i = RC->allocation_order_begin(*mf_); + while (i != aoe && reservedRegs_.test(*i)) + ++i; + assert(i != aoe && "All registers reserved?!"); + return *i; + } + void ComputeRelatedRegClasses(); template @@ -358,8 +370,8 @@ namespace { char RALinScan::ID = 0; } -static RegisterPass -X("linearscan-regalloc", "Linear Scan Register Allocator"); +INITIALIZE_PASS(RALinScan, "linearscan-regalloc", + "Linear Scan Register Allocator", false, false); void RALinScan::ComputeRelatedRegClasses() { // First pass, add all reg classes to the union, and determine at least one @@ -371,7 +383,7 @@ void RALinScan::ComputeRelatedRegClasses() { for (TargetRegisterClass::iterator I = (*RCI)->begin(), E = (*RCI)->end(); I != E; ++I) { HasAliases = HasAliases || *tri_->getAliasSet(*I) != 0; - + const TargetRegisterClass *&PRC = OneClassForEachPhysReg[*I]; if (PRC) { // Already processed this register. Just make sure we know that @@ -382,7 +394,7 @@ void RALinScan::ComputeRelatedRegClasses() { } } } - + // Second pass, now that we know conservatively what register classes each reg // belongs to, add info about aliases. We don't need to do this for targets // without register aliases. @@ -419,20 +431,15 @@ unsigned RALinScan::attemptTrivialCoalescing(LiveInterval &cur, unsigned Reg) { unsigned CandReg; { MachineInstr *CopyMI; - unsigned SrcReg, DstReg, SrcSubReg, DstSubReg; if (vni->def != SlotIndex() && vni->isDefAccurate() && - (CopyMI = li_->getInstructionFromIndex(vni->def)) && - (CopyMI->isCopy() || - tii_->isMoveInstr(*CopyMI, SrcReg, DstReg, SrcSubReg, DstSubReg))) + (CopyMI = li_->getInstructionFromIndex(vni->def)) && CopyMI->isCopy()) // Defined by a copy, try to extend SrcReg forward - CandReg = CopyMI->isCopy() ? CopyMI->getOperand(1).getReg() : SrcReg; + CandReg = CopyMI->getOperand(1).getReg(); else if (TrivCoalesceEnds && - (CopyMI = - li_->getInstructionFromIndex(range.end.getBaseIndex())) && - tii_->isMoveInstr(*CopyMI, SrcReg, DstReg, SrcSubReg, DstSubReg) && - cur.reg == SrcReg) + (CopyMI = li_->getInstructionFromIndex(range.end.getBaseIndex())) && + CopyMI->isCopy() && cur.reg == CopyMI->getOperand(1).getReg()) // Only used by a copy, try to extend DstReg backwards - CandReg = DstReg; + CandReg = CopyMI->getOperand(0).getReg(); else return Reg; } @@ -469,6 +476,7 @@ bool RALinScan::runOnMachineFunction(MachineFunction &fn) { tri_ = tm_->getRegisterInfo(); tii_ = tm_->getInstrInfo(); allocatableRegs_ = tri_->getAllocatableSet(fn); + reservedRegs_ = tri_->getReservedRegs(fn); li_ = &getAnalysis(); ls_ = &getAnalysis(); loopInfo = &getAnalysis(); @@ -487,9 +495,9 @@ bool RALinScan::runOnMachineFunction(MachineFunction &fn) { vrm_ = &getAnalysis(); if (!rewriter_.get()) rewriter_.reset(createVirtRegRewriter()); - - spiller_.reset(createSpiller(mf_, li_, loopInfo, vrm_)); - + + spiller_.reset(createSpiller(*this, *mf_, *vrm_)); + initIntervalSets(); linearScan(); @@ -543,7 +551,7 @@ void RALinScan::linearScan() { // linear scan algorithm DEBUG({ dbgs() << "********** LINEAR SCAN **********\n" - << "********** Function: " + << "********** Function: " << mf_->getFunction()->getName() << '\n'; printIntervals("fixed", fixed_.begin(), fixed_.end()); }); @@ -765,7 +773,8 @@ FindIntervalInVector(RALinScan::IntervalPtrs &IP, LiveInterval *LI) { return IP.end(); } -static void RevertVectorIteratorsTo(RALinScan::IntervalPtrs &V, SlotIndex Point){ +static void RevertVectorIteratorsTo(RALinScan::IntervalPtrs &V, + SlotIndex Point){ for (unsigned i = 0, e = V.size(); i != e; ++i) { RALinScan::IntervalPtr &IP = V[i]; LiveInterval::iterator I = std::upper_bound(IP.first->begin(), @@ -804,7 +813,7 @@ static void addStackInterval(LiveInterval *cur, LiveStacks *ls_, static float getConflictWeight(LiveInterval *cur, unsigned Reg, LiveIntervals *li_, MachineRegisterInfo *mri_, - const MachineLoopInfo *loopInfo) { + MachineLoopInfo *loopInfo) { float Conflicts = 0; for (MachineRegisterInfo::reg_iterator I = mri_->reg_begin(Reg), E = mri_->reg_end(); I != E; ++I) { @@ -837,7 +846,7 @@ void RALinScan::findIntervalsToSpill(LiveInterval *cur, dbgs() << tri_->getName(Candidates[i].first) << " "; dbgs() << "\n"; }); - + // Calculate the number of conflicts of each candidate. for (IntervalPtrs::iterator i = active_.begin(); i != active_.end(); ++i) { unsigned Reg = i->first->reg; @@ -955,7 +964,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { if (cur->empty()) { unsigned physReg = vrm_->getRegAllocPref(cur->reg); if (!physReg) - physReg = *RC->allocation_order_begin(*mf_); + physReg = getFirstNonReservedPhysReg(RC); DEBUG(dbgs() << tri_->getName(physReg) << '\n'); // Note the register is not really in use. vrm_->assignVirt2Phys(cur->reg, physReg); @@ -978,27 +987,10 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { if ((vni->def != SlotIndex()) && !vni->isUnused() && vni->isDefAccurate()) { MachineInstr *CopyMI = li_->getInstructionFromIndex(vni->def); - unsigned SrcReg, DstReg, SrcSubReg, DstSubReg; - if (CopyMI && - tii_->isMoveInstr(*CopyMI, SrcReg, DstReg, SrcSubReg, DstSubReg)) { - unsigned Reg = 0; - if (TargetRegisterInfo::isPhysicalRegister(SrcReg)) - Reg = SrcReg; - else if (vrm_->isAssignedReg(SrcReg)) - Reg = vrm_->getPhys(SrcReg); - if (Reg) { - if (SrcSubReg) - Reg = tri_->getSubReg(Reg, SrcSubReg); - if (DstSubReg) - Reg = tri_->getMatchingSuperReg(Reg, DstSubReg, RC); - if (Reg && allocatableRegs_[Reg] && RC->contains(Reg)) - mri_->setRegAllocationHint(cur->reg, 0, Reg); - } - } else if (CopyMI && CopyMI->isCopy()) { - DstReg = CopyMI->getOperand(0).getReg(); - DstSubReg = CopyMI->getOperand(0).getSubReg(); - SrcReg = CopyMI->getOperand(1).getReg(); - SrcSubReg = CopyMI->getOperand(1).getSubReg(); + if (CopyMI && CopyMI->isCopy()) { + unsigned DstSubReg = CopyMI->getOperand(0).getSubReg(); + unsigned SrcReg = CopyMI->getOperand(1).getReg(); + unsigned SrcSubReg = CopyMI->getOperand(1).getSubReg(); unsigned Reg = 0; if (TargetRegisterInfo::isPhysicalRegister(SrcReg)) Reg = SrcReg; @@ -1024,7 +1016,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { assert(TargetRegisterInfo::isVirtualRegister(Reg) && "Can only allocate virtual registers!"); const TargetRegisterClass *RegRC = mri_->getRegClass(Reg); - // If this is not in a related reg class to the register we're allocating, + // If this is not in a related reg class to the register we're allocating, // don't check it. if (RelatedRegClasses.getLeaderValue(RegRC) == RCLeader && cur->overlapsFrom(*i->first, i->second-1)) { @@ -1033,7 +1025,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { SpillWeightsToAdd.push_back(std::make_pair(Reg, i->first->weight)); } } - + // Speculatively check to see if we can get a register right now. If not, // we know we won't be able to by adding more constraints. If so, we can // check to see if it is valid. Doing an exhaustive search of the fixed_ list @@ -1048,7 +1040,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { SmallSet RegAliases; for (const unsigned *AS = tri_->getAliasSet(physReg); *AS; ++AS) RegAliases.insert(*AS); - + bool ConflictsWithFixed = false; for (unsigned i = 0, e = fixed_.size(); i != e; ++i) { IntervalPtr &IP = fixed_[i]; @@ -1068,7 +1060,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { } } } - + // Okay, the register picked by our speculative getFreePhysReg call turned // out to be in use. Actually add all of the conflicting fixed registers to // regUse_ so we can do an accurate query. @@ -1080,7 +1072,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { LiveInterval *I = IP.first; const TargetRegisterClass *RegRC = OneClassForEachPhysReg[I->reg]; - if (RelatedRegClasses.getLeaderValue(RegRC) == RCLeader && + if (RelatedRegClasses.getLeaderValue(RegRC) == RCLeader && I->endIndex() > StartPosition) { LiveInterval::iterator II = I->advanceTo(IP.second, StartPosition); IP.second = II; @@ -1099,11 +1091,11 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { physReg = getFreePhysReg(cur); } } - + // Restore the physical register tracker, removing information about the // future. restoreRegUses(); - + // If we find a free register, we are done: assign this virtual to // the free physical register and add this interval to the active // list. @@ -1118,7 +1110,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { UpgradeRegister(physReg); if (LiveInterval *NextReloadLI = hasNextReloadInterval(cur)) { // "Downgrade" physReg to try to keep physReg from being allocated until - // the next reload from the same SS is allocated. + // the next reload from the same SS is allocated. mri_->setRegAllocationHint(NextReloadLI->reg, 0, physReg); DowngradeRegister(cur, physReg); } @@ -1131,7 +1123,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { for (std::vector >::iterator I = SpillWeightsToAdd.begin(), E = SpillWeightsToAdd.end(); I != E; ++I) updateSpillWeights(SpillWeights, I->first, I->second, RC); - + // for each interval in active, update spill weights. for (IntervalPtrs::const_iterator i = active_.begin(), e = active_.end(); i != e; ++i) { @@ -1141,7 +1133,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { reg = vrm_->getPhys(reg); updateSpillWeights(SpillWeights, reg, i->first->weight, RC); } - + DEBUG(dbgs() << "\tassigning stack slot at interval "<< *cur << ":\n"); // Find a register to spill. @@ -1155,17 +1147,22 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { e = RC->allocation_order_end(*mf_); i != e; ++i) { unsigned reg = *i; float regWeight = SpillWeights[reg]; - // Skip recently allocated registers. + // Don't even consider reserved regs. + if (reservedRegs_.test(reg)) + continue; + // Skip recently allocated registers and reserved registers. if (minWeight > regWeight && !isRecentlyUsed(reg)) Found = true; RegsWeights.push_back(std::make_pair(reg, regWeight)); } - + // If we didn't find a register that is spillable, try aliases? if (!Found) { for (TargetRegisterClass::iterator i = RC->allocation_order_begin(*mf_), e = RC->allocation_order_end(*mf_); i != e; ++i) { unsigned reg = *i; + if (reservedRegs_.test(reg)) + continue; // No need to worry about if the alias register size < regsize of RC. // We are going to spill all registers that alias it anyway. for (const unsigned* as = tri_->getAliasSet(reg); *as; ++as) @@ -1179,7 +1176,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { minWeight = RegsWeights[0].second; if (minWeight == HUGE_VALF) { // All registers must have inf weight. Just grab one! - minReg = BestPhysReg ? BestPhysReg : *RC->allocation_order_begin(*mf_); + minReg = BestPhysReg ? BestPhysReg : getFirstNonReservedPhysReg(RC); if (cur->weight == HUGE_VALF || li_->getApproximateInstructionCount(*cur) == 0) { // Spill a physical register around defs and uses. @@ -1224,8 +1221,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { // linearscan. if (cur->weight != HUGE_VALF && cur->weight <= minWeight) { DEBUG(dbgs() << "\t\t\tspilling(c): " << *cur << '\n'); - SmallVector spillIs; - std::vector added; + SmallVector spillIs, added; spiller_->spill(cur, added, spillIs); std::sort(added.begin(), added.end(), LISorter()); @@ -1288,27 +1284,33 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { // The earliest start of a Spilled interval indicates up to where // in handled we need to roll back - assert(!spillIs.empty() && "No spill intervals?"); + assert(!spillIs.empty() && "No spill intervals?"); SlotIndex earliestStart = spillIs[0]->beginIndex(); - + // Spill live intervals of virtual regs mapped to the physical register we // want to clear (and its aliases). We only spill those that overlap with the // current interval as the rest do not affect its allocation. we also keep // track of the earliest start of all spilled live intervals since this will // mark our rollback point. - std::vector added; + SmallVector added; while (!spillIs.empty()) { LiveInterval *sli = spillIs.back(); spillIs.pop_back(); DEBUG(dbgs() << "\t\t\tspilling(a): " << *sli << '\n'); if (sli->beginIndex() < earliestStart) earliestStart = sli->beginIndex(); - - spiller_->spill(sli, added, spillIs, &earliestStart); + spiller_->spill(sli, added, spillIs); addStackInterval(sli, ls_, li_, mri_, *vrm_); spilled.insert(sli->reg); } + // Include any added intervals in earliestStart. + for (unsigned i = 0, e = added.size(); i != e; ++i) { + SlotIndex SI = added[i]->beginIndex(); + if (SI < earliestStart) + earliestStart = SI; + } + DEBUG(dbgs() << "\t\trolling back to: " << earliestStart << '\n'); // Scan handled in reverse order up to the earliest start of a @@ -1431,6 +1433,9 @@ unsigned RALinScan::getFreePhysReg(LiveInterval* cur, // Ignore "downgraded" registers. if (SkipDGRegs && DowngradedRegs.count(Reg)) continue; + // Skip reserved registers. + if (reservedRegs_.test(Reg)) + continue; // Skip recently allocated registers. if (isRegAvail(Reg) && !isRecentlyUsed(Reg)) { FreeReg = Reg; @@ -1459,6 +1464,9 @@ unsigned RALinScan::getFreePhysReg(LiveInterval* cur, // Ignore "downgraded" registers. if (SkipDGRegs && DowngradedRegs.count(Reg)) continue; + // Skip reserved registers. + if (reservedRegs_.test(Reg)) + continue; if (isRegAvail(Reg) && Reg < inactiveCounts.size() && FreeRegInactiveCount < inactiveCounts[Reg] && !isRecentlyUsed(Reg)) { FreeReg = Reg; @@ -1479,17 +1487,17 @@ unsigned RALinScan::getFreePhysReg(LiveInterval* cur, unsigned RALinScan::getFreePhysReg(LiveInterval *cur) { SmallVector inactiveCounts; unsigned MaxInactiveCount = 0; - + const TargetRegisterClass *RC = mri_->getRegClass(cur->reg); const TargetRegisterClass *RCLeader = RelatedRegClasses.getLeaderValue(RC); - + for (IntervalPtrs::iterator i = inactive_.begin(), e = inactive_.end(); i != e; ++i) { unsigned reg = i->first->reg; assert(TargetRegisterInfo::isVirtualRegister(reg) && "Can only allocate virtual registers!"); - // If this is not in a related reg class to the register we're allocating, + // If this is not in a related reg class to the register we're allocating, // don't check it. const TargetRegisterClass *RegRC = mri_->getRegClass(reg); if (RelatedRegClasses.getLeaderValue(RegRC) == RCLeader) { @@ -1506,7 +1514,7 @@ unsigned RALinScan::getFreePhysReg(LiveInterval *cur) { unsigned Preference = vrm_->getRegAllocPref(cur->reg); if (Preference) { DEBUG(dbgs() << "(preferred: " << tri_->getName(Preference) << ") "); - if (isRegAvail(Preference) && + if (isRegAvail(Preference) && RC->contains(Preference)) return Preference; } diff --git a/lib/CodeGen/RegAllocPBQP.cpp b/lib/CodeGen/RegAllocPBQP.cpp index 7e61a12..61f337b 100644 --- a/lib/CodeGen/RegAllocPBQP.cpp +++ b/lib/CodeGen/RegAllocPBQP.cpp @@ -34,6 +34,8 @@ #include "PBQP/HeuristicSolver.h" #include "PBQP/Graph.h" #include "PBQP/Heuristics/Briggs.h" +#include "RenderMachineFunction.h" +#include "Splitter.h" #include "VirtRegMap.h" #include "VirtRegRewriter.h" #include "llvm/CodeGen/CalcSpillWeights.h" @@ -65,6 +67,11 @@ pbqpCoalescing("pbqp-coalescing", cl::desc("Attempt coalescing during PBQP register allocation."), cl::init(false), cl::Hidden); +static cl::opt +pbqpPreSplitting("pbqp-pre-splitting", + cl::desc("Pre-splite before PBQP register allocation."), + cl::init(false), cl::Hidden); + namespace { /// @@ -77,7 +84,7 @@ namespace { static char ID; /// Construct a PBQP register allocator. - PBQPRegAlloc() : MachineFunctionPass(&ID) {} + PBQPRegAlloc() : MachineFunctionPass(ID) {} /// Return the pass name. virtual const char* getPassName() const { @@ -96,7 +103,10 @@ namespace { au.addPreserved(); au.addRequired(); au.addPreserved(); + if (pbqpPreSplitting) + au.addRequired(); au.addRequired(); + au.addRequired(); MachineFunctionPass::getAnalysisUsage(au); } @@ -104,7 +114,15 @@ namespace { virtual bool runOnMachineFunction(MachineFunction &MF); private: - typedef std::map LI2NodeMap; + + class LIOrdering { + public: + bool operator()(const LiveInterval *li1, const LiveInterval *li2) const { + return li1->reg < li2->reg; + } + }; + + typedef std::map LI2NodeMap; typedef std::vector Node2LIMap; typedef std::vector AllowedSet; typedef std::vector AllowedSetMap; @@ -112,7 +130,7 @@ namespace { typedef std::pair RegPair; typedef std::map CoalesceMap; - typedef std::set LiveIntervalSet; + typedef std::set LiveIntervalSet; typedef std::vector NodeVector; @@ -122,6 +140,7 @@ namespace { const TargetInstrInfo *tii; const MachineLoopInfo *loopInfo; MachineRegisterInfo *mri; + RenderMachineFunction *rmf; LiveIntervals *lis; LiveStacks *lss; @@ -379,12 +398,14 @@ PBQPRegAlloc::CoalesceMap PBQPRegAlloc::findCoalesces() { iItr != iEnd; ++iItr) { const MachineInstr *instr = &*iItr; - unsigned srcReg, dstReg, srcSubReg, dstSubReg; // If this isn't a copy then continue to the next instruction. - if (!tii->isMoveInstr(*instr, srcReg, dstReg, srcSubReg, dstSubReg)) + if (!instr->isCopy()) continue; + unsigned srcReg = instr->getOperand(1).getReg(); + unsigned dstReg = instr->getOperand(0).getReg(); + // If the registers are already the same our job is nice and easy. if (dstReg == srcReg) continue; @@ -567,6 +588,8 @@ PBQP::Graph PBQPRegAlloc::constructPBQPProblem() { // Resize allowedSets container appropriately. allowedSets.resize(vregIntervalsToAlloc.size()); + BitVector ReservedRegs = tri->getReservedRegs(*mf); + // Iterate over virtual register intervals to compute allowed sets... for (unsigned node = 0; node < node2LI.size(); ++node) { @@ -575,8 +598,12 @@ PBQP::Graph PBQPRegAlloc::constructPBQPProblem() { const TargetRegisterClass *liRC = mri->getRegClass(li->reg); // Start by assuming all allocable registers in the class are allowed... - RegVector liAllowed(liRC->allocation_order_begin(*mf), - liRC->allocation_order_end(*mf)); + RegVector liAllowed; + TargetRegisterClass::iterator aob = liRC->allocation_order_begin(*mf); + TargetRegisterClass::iterator aoe = liRC->allocation_order_end(*mf); + for (TargetRegisterClass::iterator it = aob; it != aoe; ++it) + if (!ReservedRegs.test(*it)) + liAllowed.push_back(*it); // Eliminate the physical registers which overlap with this range, along // with all their aliases. @@ -735,9 +762,11 @@ bool PBQPRegAlloc::mapPBQPToRegAlloc(const PBQP::Solution &solution) { const LiveInterval *spillInterval = node2LI[node]; double oldSpillWeight = spillInterval->weight; SmallVector spillIs; + rmf->rememberUseDefs(spillInterval); std::vector newSpills = lis->addIntervalsForSpills(*spillInterval, spillIs, loopInfo, *vrm); addStackInterval(spillInterval, mri); + rmf->rememberSpills(spillInterval, newSpills); (void) oldSpillWeight; DEBUG(dbgs() << "VREG " << virtReg << " -> SPILLED (Cost: " @@ -845,9 +874,11 @@ bool PBQPRegAlloc::runOnMachineFunction(MachineFunction &MF) { lis = &getAnalysis(); lss = &getAnalysis(); loopInfo = &getAnalysis(); + rmf = &getAnalysis(); vrm = &getAnalysis(); + DEBUG(dbgs() << "PBQP Register Allocating for " << mf->getFunction()->getName() << "\n"); // Allocator main loop: @@ -884,6 +915,8 @@ bool PBQPRegAlloc::runOnMachineFunction(MachineFunction &MF) { // Finalise allocation, allocate empty ranges. finalizeAlloc(); + rmf->renderMachineFunction("After PBQP register allocation.", vrm); + vregIntervalsToAlloc.clear(); emptyVRegIntervals.clear(); li2Node.clear(); diff --git a/lib/CodeGen/RegisterCoalescer.cpp b/lib/CodeGen/RegisterCoalescer.cpp index ab0bc2d..02b5539 100644 --- a/lib/CodeGen/RegisterCoalescer.cpp +++ b/lib/CodeGen/RegisterCoalescer.cpp @@ -54,9 +54,8 @@ bool CoalescerPair::isMoveInstr(const MachineInstr *MI, DstSub = compose(MI->getOperand(0).getSubReg(), MI->getOperand(3).getImm()); Src = MI->getOperand(2).getReg(); SrcSub = MI->getOperand(2).getSubReg(); - } else if (!tii_.isMoveInstr(*MI, Src, Dst, SrcSub, DstSub)) { + } else return false; - } return true; } diff --git a/lib/CodeGen/RegisterScavenging.cpp b/lib/CodeGen/RegisterScavenging.cpp index 43b3fb6..a2580b8 100644 --- a/lib/CodeGen/RegisterScavenging.cpp +++ b/lib/CodeGen/RegisterScavenging.cpp @@ -21,7 +21,9 @@ #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" @@ -226,19 +228,14 @@ void RegScavenger::getRegsUsed(BitVector &used, bool includeReserved) { used = ~RegsAvailable & ~ReservedRegs; } -/// CreateRegClassMask - Set the bits that represent the registers in the -/// TargetRegisterClass. -static void CreateRegClassMask(const TargetRegisterClass *RC, BitVector &Mask) { - for (TargetRegisterClass::iterator I = RC->begin(), E = RC->end(); I != E; - ++I) - Mask.set(*I); -} - unsigned RegScavenger::FindUnusedReg(const TargetRegisterClass *RC) const { for (TargetRegisterClass::iterator I = RC->begin(), E = RC->end(); I != E; ++I) - if (!isAliasUsed(*I)) + if (!isAliasUsed(*I)) { + DEBUG(dbgs() << "Scavenger found unused reg: " << TRI->getName(*I) << + "\n"); return *I; + } return 0; } @@ -325,11 +322,9 @@ unsigned RegScavenger::findSurvivorReg(MachineBasicBlock::iterator StartMI, unsigned RegScavenger::scavengeRegister(const TargetRegisterClass *RC, MachineBasicBlock::iterator I, int SPAdj) { - // Mask off the registers which are not in the TargetRegisterClass. - BitVector Candidates(NumPhysRegs, false); - CreateRegClassMask(RC, Candidates); - // Do not include reserved registers. - Candidates ^= ReservedRegs & Candidates; + // Consider all allocatable registers in the register class initially + BitVector Candidates = + TRI->getAllocatableSet(*I->getParent()->getParent(), RC); // Exclude all the registers being used by the instruction. for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { @@ -349,8 +344,10 @@ unsigned RegScavenger::scavengeRegister(const TargetRegisterClass *RC, unsigned SReg = findSurvivorReg(I, Candidates, 25, UseMI); // If we found an unused register there is no reason to spill it. - if (!isAliasUsed(SReg)) + if (!isAliasUsed(SReg)) { + DEBUG(dbgs() << "Scavenged register: " << TRI->getName(SReg) << "\n"); return SReg; + } assert(ScavengedReg == 0 && "Scavenger slot is live, unable to scavenge another register!"); @@ -366,12 +363,12 @@ unsigned RegScavenger::scavengeRegister(const TargetRegisterClass *RC, "Cannot scavenge register without an emergency spill slot!"); TII->storeRegToStackSlot(*MBB, I, SReg, true, ScavengingFrameIndex, RC,TRI); MachineBasicBlock::iterator II = prior(I); - TRI->eliminateFrameIndex(II, SPAdj, NULL, this); + TRI->eliminateFrameIndex(II, SPAdj, this); // Restore the scavenged register before its use (or first terminator). TII->loadRegFromStackSlot(*MBB, UseMI, SReg, ScavengingFrameIndex, RC, TRI); II = prior(UseMI); - TRI->eliminateFrameIndex(II, SPAdj, NULL, this); + TRI->eliminateFrameIndex(II, SPAdj, this); } ScavengeRestore = prior(UseMI); @@ -380,5 +377,8 @@ unsigned RegScavenger::scavengeRegister(const TargetRegisterClass *RC, // ScavengedReg = SReg; ScavengedRC = RC; + DEBUG(dbgs() << "Scavenged register (with spill): " << TRI->getName(SReg) << + "\n"); + return SReg; } diff --git a/lib/CodeGen/RenderMachineFunction.cpp b/lib/CodeGen/RenderMachineFunction.cpp new file mode 100644 index 0000000..93426ee --- /dev/null +++ b/lib/CodeGen/RenderMachineFunction.cpp @@ -0,0 +1,1014 @@ +//===-- llvm/CodeGen/RenderMachineFunction.cpp - MF->HTML -----s-----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "rendermf" + +#include "RenderMachineFunction.h" + +#include "VirtRegMap.h" + +#include "llvm/Function.h" +#include "llvm/Module.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" + +#include + +using namespace llvm; + +char RenderMachineFunction::ID = 0; +INITIALIZE_PASS(RenderMachineFunction, "rendermf", + "Render machine functions (and related info) to HTML pages", + false, false); + +static cl::opt +outputFileSuffix("rmf-file-suffix", + cl::desc("Appended to function name to get output file name " + "(default: \".html\")"), + cl::init(".html"), cl::Hidden); + +static cl::opt +machineFuncsToRender("rmf-funcs", + cl::desc("Coma seperated list of functions to render" + ", or \"*\"."), + cl::init(""), cl::Hidden); + +static cl::opt +pressureClasses("rmf-classes", + cl::desc("Register classes to render pressure for."), + cl::init(""), cl::Hidden); + +static cl::opt +showIntervals("rmf-intervals", + cl::desc("Live intervals to show alongside code."), + cl::init(""), cl::Hidden); + +static cl::opt +filterEmpty("rmf-filter-empty-intervals", + cl::desc("Don't display empty intervals."), + cl::init(true), cl::Hidden); + +static cl::opt +showEmptyIndexes("rmf-empty-indexes", + cl::desc("Render indexes not associated with instructions or " + "MBB starts."), + cl::init(false), cl::Hidden); + +static cl::opt +useFancyVerticals("rmf-fancy-verts", + cl::desc("Use SVG for vertical text."), + cl::init(true), cl::Hidden); + +static cl::opt +prettyHTML("rmf-pretty-html", + cl::desc("Pretty print HTML. For debugging the renderer only.."), + cl::init(false), cl::Hidden); + + +namespace llvm { + + bool MFRenderingOptions::renderingOptionsProcessed; + std::set MFRenderingOptions::mfNamesToRender; + bool MFRenderingOptions::renderAllMFs = false; + + std::set MFRenderingOptions::classNamesToRender; + bool MFRenderingOptions::renderAllClasses = false; + + std::set > + MFRenderingOptions::intervalNumsToRender; + unsigned MFRenderingOptions::intervalTypesToRender = ExplicitOnly; + + template + void MFRenderingOptions::splitComaSeperatedList(const std::string &s, + OutputItr outItr) { + std::string::const_iterator curPos = s.begin(); + std::string::const_iterator nextComa = std::find(curPos, s.end(), ','); + while (nextComa != s.end()) { + std::string elem; + std::copy(curPos, nextComa, std::back_inserter(elem)); + *outItr = elem; + ++outItr; + curPos = llvm::next(nextComa); + nextComa = std::find(curPos, s.end(), ','); + } + + if (curPos != s.end()) { + std::string elem; + std::copy(curPos, s.end(), std::back_inserter(elem)); + *outItr = elem; + ++outItr; + } + } + + void MFRenderingOptions::processOptions() { + if (!renderingOptionsProcessed) { + processFuncNames(); + processRegClassNames(); + processIntervalNumbers(); + renderingOptionsProcessed = true; + } + } + + void MFRenderingOptions::processFuncNames() { + if (machineFuncsToRender == "*") { + renderAllMFs = true; + } else { + splitComaSeperatedList(machineFuncsToRender, + std::inserter(mfNamesToRender, + mfNamesToRender.begin())); + } + } + + void MFRenderingOptions::processRegClassNames() { + if (pressureClasses == "*") { + renderAllClasses = true; + } else { + splitComaSeperatedList(pressureClasses, + std::inserter(classNamesToRender, + classNamesToRender.begin())); + } + } + + void MFRenderingOptions::processIntervalNumbers() { + std::set intervalRanges; + splitComaSeperatedList(showIntervals, + std::inserter(intervalRanges, + intervalRanges.begin())); + std::for_each(intervalRanges.begin(), intervalRanges.end(), + processIntervalRange); + } + + void MFRenderingOptions::processIntervalRange( + const std::string &intervalRangeStr) { + if (intervalRangeStr == "*") { + intervalTypesToRender |= All; + } else if (intervalRangeStr == "virt-nospills*") { + intervalTypesToRender |= VirtNoSpills; + } else if (intervalRangeStr == "spills*") { + intervalTypesToRender |= VirtSpills; + } else if (intervalRangeStr == "virt*") { + intervalTypesToRender |= AllVirt; + } else if (intervalRangeStr == "phys*") { + intervalTypesToRender |= AllPhys; + } else { + std::istringstream iss(intervalRangeStr); + unsigned reg1, reg2; + if ((iss >> reg1 >> std::ws)) { + if (iss.eof()) { + intervalNumsToRender.insert(std::make_pair(reg1, reg1 + 1)); + } else { + char c; + iss >> c; + if (c == '-' && (iss >> reg2)) { + intervalNumsToRender.insert(std::make_pair(reg1, reg2 + 1)); + } else { + dbgs() << "Warning: Invalid interval range \"" + << intervalRangeStr << "\" in -rmf-intervals. Skipping.\n"; + } + } + } else { + dbgs() << "Warning: Invalid interval number \"" + << intervalRangeStr << "\" in -rmf-intervals. Skipping.\n"; + } + } + } + + void MFRenderingOptions::setup(MachineFunction *mf, + const TargetRegisterInfo *tri, + LiveIntervals *lis, + const RenderMachineFunction *rmf) { + this->mf = mf; + this->tri = tri; + this->lis = lis; + this->rmf = rmf; + + clear(); + } + + void MFRenderingOptions::clear() { + regClassesTranslatedToCurrentFunction = false; + regClassSet.clear(); + + intervalsTranslatedToCurrentFunction = false; + intervalSet.clear(); + } + + void MFRenderingOptions::resetRenderSpecificOptions() { + intervalSet.clear(); + intervalsTranslatedToCurrentFunction = false; + } + + bool MFRenderingOptions::shouldRenderCurrentMachineFunction() const { + processOptions(); + + return (renderAllMFs || + mfNamesToRender.find(mf->getFunction()->getName()) != + mfNamesToRender.end()); + } + + const MFRenderingOptions::RegClassSet& MFRenderingOptions::regClasses() const{ + translateRegClassNamesToCurrentFunction(); + return regClassSet; + } + + const MFRenderingOptions::IntervalSet& MFRenderingOptions::intervals() const { + translateIntervalNumbersToCurrentFunction(); + return intervalSet; + } + + bool MFRenderingOptions::renderEmptyIndexes() const { + return showEmptyIndexes; + } + + bool MFRenderingOptions::fancyVerticals() const { + return useFancyVerticals; + } + + void MFRenderingOptions::translateRegClassNamesToCurrentFunction() const { + if (!regClassesTranslatedToCurrentFunction) { + processOptions(); + for (TargetRegisterInfo::regclass_iterator rcItr = tri->regclass_begin(), + rcEnd = tri->regclass_end(); + rcItr != rcEnd; ++rcItr) { + const TargetRegisterClass *trc = *rcItr; + if (renderAllClasses || + classNamesToRender.find(trc->getName()) != + classNamesToRender.end()) { + regClassSet.insert(trc); + } + } + regClassesTranslatedToCurrentFunction = true; + } + } + + void MFRenderingOptions::translateIntervalNumbersToCurrentFunction() const { + if (!intervalsTranslatedToCurrentFunction) { + processOptions(); + + // If we're not just doing explicit then do a copy over all matching + // types. + if (intervalTypesToRender != ExplicitOnly) { + for (LiveIntervals::iterator liItr = lis->begin(), liEnd = lis->end(); + liItr != liEnd; ++liItr) { + LiveInterval *li = liItr->second; + + if (filterEmpty && li->empty()) + continue; + + if ((TargetRegisterInfo::isPhysicalRegister(li->reg) && + (intervalTypesToRender & AllPhys))) { + intervalSet.insert(li); + } else if (TargetRegisterInfo::isVirtualRegister(li->reg)) { + if (((intervalTypesToRender & VirtNoSpills) && !rmf->isSpill(li)) || + ((intervalTypesToRender & VirtSpills) && rmf->isSpill(li))) { + intervalSet.insert(li); + } + } + } + } + + // If we need to process the explicit list... + if (intervalTypesToRender != All) { + for (std::set >::const_iterator + regRangeItr = intervalNumsToRender.begin(), + regRangeEnd = intervalNumsToRender.end(); + regRangeItr != regRangeEnd; ++regRangeItr) { + const std::pair &range = *regRangeItr; + for (unsigned reg = range.first; reg != range.second; ++reg) { + if (lis->hasInterval(reg)) { + intervalSet.insert(&lis->getInterval(reg)); + } + } + } + } + + intervalsTranslatedToCurrentFunction = true; + } + } + + // ---------- TargetRegisterExtraInformation implementation ---------- + + TargetRegisterExtraInfo::TargetRegisterExtraInfo() + : mapsPopulated(false) { + } + + void TargetRegisterExtraInfo::setup(MachineFunction *mf, + MachineRegisterInfo *mri, + const TargetRegisterInfo *tri, + LiveIntervals *lis) { + this->mf = mf; + this->mri = mri; + this->tri = tri; + this->lis = lis; + } + + void TargetRegisterExtraInfo::reset() { + if (!mapsPopulated) { + initWorst(); + //initBounds(); + initCapacity(); + mapsPopulated = true; + } + + resetPressureAndLiveStates(); + } + + void TargetRegisterExtraInfo::clear() { + prWorst.clear(); + vrWorst.clear(); + capacityMap.clear(); + pressureMap.clear(); + //liveStatesMap.clear(); + mapsPopulated = false; + } + + void TargetRegisterExtraInfo::initWorst() { + assert(!mapsPopulated && prWorst.empty() && vrWorst.empty() && + "Worst map already initialised?"); + + // Start with the physical registers. + for (unsigned preg = 1; preg < tri->getNumRegs(); ++preg) { + WorstMapLine &pregLine = prWorst[preg]; + + for (TargetRegisterInfo::regclass_iterator rcItr = tri->regclass_begin(), + rcEnd = tri->regclass_end(); + rcItr != rcEnd; ++rcItr) { + const TargetRegisterClass *trc = *rcItr; + + unsigned numOverlaps = 0; + for (TargetRegisterClass::iterator rItr = trc->begin(), + rEnd = trc->end(); + rItr != rEnd; ++rItr) { + unsigned trcPReg = *rItr; + if (tri->regsOverlap(preg, trcPReg)) + ++numOverlaps; + } + + pregLine[trc] = numOverlaps; + } + } + + // Now the register classes. + for (TargetRegisterInfo::regclass_iterator rc1Itr = tri->regclass_begin(), + rcEnd = tri->regclass_end(); + rc1Itr != rcEnd; ++rc1Itr) { + const TargetRegisterClass *trc1 = *rc1Itr; + WorstMapLine &classLine = vrWorst[trc1]; + + for (TargetRegisterInfo::regclass_iterator rc2Itr = tri->regclass_begin(); + rc2Itr != rcEnd; ++rc2Itr) { + const TargetRegisterClass *trc2 = *rc2Itr; + + unsigned worst = 0; + + for (TargetRegisterClass::iterator trc1Itr = trc1->begin(), + trc1End = trc1->end(); + trc1Itr != trc1End; ++trc1Itr) { + unsigned trc1Reg = *trc1Itr; + unsigned trc1RegWorst = 0; + + for (TargetRegisterClass::iterator trc2Itr = trc2->begin(), + trc2End = trc2->end(); + trc2Itr != trc2End; ++trc2Itr) { + unsigned trc2Reg = *trc2Itr; + if (tri->regsOverlap(trc1Reg, trc2Reg)) + ++trc1RegWorst; + } + if (trc1RegWorst > worst) { + worst = trc1RegWorst; + } + } + + if (worst != 0) { + classLine[trc2] = worst; + } + } + } + } + + unsigned TargetRegisterExtraInfo::getWorst( + unsigned reg, + const TargetRegisterClass *trc) const { + const WorstMapLine *wml = 0; + if (TargetRegisterInfo::isPhysicalRegister(reg)) { + PRWorstMap::const_iterator prwItr = prWorst.find(reg); + assert(prwItr != prWorst.end() && "Missing prWorst entry."); + wml = &prwItr->second; + } else { + const TargetRegisterClass *regTRC = mri->getRegClass(reg); + VRWorstMap::const_iterator vrwItr = vrWorst.find(regTRC); + assert(vrwItr != vrWorst.end() && "Missing vrWorst entry."); + wml = &vrwItr->second; + } + + WorstMapLine::const_iterator wmlItr = wml->find(trc); + if (wmlItr == wml->end()) + return 0; + + return wmlItr->second; + } + + void TargetRegisterExtraInfo::initCapacity() { + assert(!mapsPopulated && capacityMap.empty() && + "Capacity map already initialised?"); + + for (TargetRegisterInfo::regclass_iterator rcItr = tri->regclass_begin(), + rcEnd = tri->regclass_end(); + rcItr != rcEnd; ++rcItr) { + const TargetRegisterClass *trc = *rcItr; + unsigned capacity = std::distance(trc->allocation_order_begin(*mf), + trc->allocation_order_end(*mf)); + + if (capacity != 0) + capacityMap[trc] = capacity; + } + } + + unsigned TargetRegisterExtraInfo::getCapacity( + const TargetRegisterClass *trc) const { + CapacityMap::const_iterator cmItr = capacityMap.find(trc); + assert(cmItr != capacityMap.end() && + "vreg with unallocable register class"); + return cmItr->second; + } + + void TargetRegisterExtraInfo::resetPressureAndLiveStates() { + pressureMap.clear(); + //liveStatesMap.clear(); + + // Iterate over all slots. + + + // Iterate over all live intervals. + for (LiveIntervals::iterator liItr = lis->begin(), + liEnd = lis->end(); + liItr != liEnd; ++liItr) { + LiveInterval *li = liItr->second; + + const TargetRegisterClass *liTRC; + + if (TargetRegisterInfo::isPhysicalRegister(li->reg)) + continue; + + liTRC = mri->getRegClass(li->reg); + + + // For all ranges in the current interal. + for (LiveInterval::iterator lrItr = li->begin(), + lrEnd = li->end(); + lrItr != lrEnd; ++lrItr) { + LiveRange *lr = &*lrItr; + + // For all slots in the current range. + for (SlotIndex i = lr->start; i != lr->end; i = i.getNextSlot()) { + + // Record increased pressure at index for all overlapping classes. + for (TargetRegisterInfo::regclass_iterator + rcItr = tri->regclass_begin(), + rcEnd = tri->regclass_end(); + rcItr != rcEnd; ++rcItr) { + const TargetRegisterClass *trc = *rcItr; + + if (trc->allocation_order_begin(*mf) == + trc->allocation_order_end(*mf)) + continue; + + unsigned worstAtI = getWorst(li->reg, trc); + + if (worstAtI != 0) { + pressureMap[i][trc] += worstAtI; + } + } + } + } + } + } + + unsigned TargetRegisterExtraInfo::getPressureAtSlot( + const TargetRegisterClass *trc, + SlotIndex i) const { + PressureMap::const_iterator pmItr = pressureMap.find(i); + if (pmItr == pressureMap.end()) + return 0; + const PressureMapLine &pmLine = pmItr->second; + PressureMapLine::const_iterator pmlItr = pmLine.find(trc); + if (pmlItr == pmLine.end()) + return 0; + return pmlItr->second; + } + + bool TargetRegisterExtraInfo::classOverCapacityAtSlot( + const TargetRegisterClass *trc, + SlotIndex i) const { + return (getPressureAtSlot(trc, i) > getCapacity(trc)); + } + + // ---------- MachineFunctionRenderer implementation ---------- + + void RenderMachineFunction::Spacer::print(raw_ostream &os) const { + if (!prettyHTML) + return; + for (unsigned i = 0; i < ns; ++i) { + os << " "; + } + } + + RenderMachineFunction::Spacer RenderMachineFunction::s(unsigned ns) const { + return Spacer(ns); + } + + raw_ostream& operator<<(raw_ostream &os, const RenderMachineFunction::Spacer &s) { + s.print(os); + return os; + } + + template + std::string RenderMachineFunction::escapeChars(Iterator sBegin, Iterator sEnd) const { + std::string r; + + for (Iterator sItr = sBegin; sItr != sEnd; ++sItr) { + char c = *sItr; + + switch (c) { + case '<': r.append("<"); break; + case '>': r.append(">"); break; + case '&': r.append("&"); break; + case ' ': r.append(" "); break; + case '\"': r.append("""); break; + default: r.push_back(c); break; + } + } + + return r; + } + + RenderMachineFunction::LiveState + RenderMachineFunction::getLiveStateAt(const LiveInterval *li, + SlotIndex i) const { + const MachineInstr *mi = sis->getInstructionFromIndex(i); + + // For uses/defs recorded use/def indexes override current liveness and + // instruction operands (Only for the interval which records the indexes). + if (i.isUse() || i.isDef()) { + UseDefs::const_iterator udItr = useDefs.find(li); + if (udItr != useDefs.end()) { + const SlotSet &slotSet = udItr->second; + if (slotSet.count(i)) { + if (i.isUse()) { + return Used; + } + // else + return Defined; + } + } + } + + // If the slot is a load/store, or there's no info in the use/def set then + // use liveness and instruction operand info. + if (li->liveAt(i)) { + + if (mi == 0) { + if (vrm == 0 || + (vrm->getStackSlot(li->reg) == VirtRegMap::NO_STACK_SLOT)) { + return AliveReg; + } else { + return AliveStack; + } + } else { + if (i.isDef() && mi->definesRegister(li->reg, tri)) { + return Defined; + } else if (i.isUse() && mi->readsRegister(li->reg)) { + return Used; + } else { + if (vrm == 0 || + (vrm->getStackSlot(li->reg) == VirtRegMap::NO_STACK_SLOT)) { + return AliveReg; + } else { + return AliveStack; + } + } + } + } + return Dead; + } + + RenderMachineFunction::PressureState + RenderMachineFunction::getPressureStateAt(const TargetRegisterClass *trc, + SlotIndex i) const { + if (trei.getPressureAtSlot(trc, i) == 0) { + return Zero; + } else if (trei.classOverCapacityAtSlot(trc, i)){ + return High; + } + return Low; + } + + /// \brief Render a machine instruction. + void RenderMachineFunction::renderMachineInstr(raw_ostream &os, + const MachineInstr *mi) const { + std::string s; + raw_string_ostream oss(s); + oss << *mi; + + os << escapeChars(oss.str()); + } + + template + void RenderMachineFunction::renderVertical(const Spacer &indent, + raw_ostream &os, + const T &t) const { + if (ro.fancyVerticals()) { + os << indent << "\n" + << indent + s(6) << "" << t << "\n" + << indent + s(4) << "\">\n" + << indent << "\n"; + } else { + std::ostringstream oss; + oss << t; + std::string tStr(oss.str()); + + os << indent; + for (std::string::iterator tStrItr = tStr.begin(), tStrEnd = tStr.end(); + tStrItr != tStrEnd; ++tStrItr) { + os << *tStrItr << "
"; + } + os << "\n"; + } + } + + void RenderMachineFunction::insertCSS(const Spacer &indent, + raw_ostream &os) const { + os << indent << "\n"; + } + + void RenderMachineFunction::renderFunctionSummary( + const Spacer &indent, raw_ostream &os, + const char * const renderContextStr) const { + os << indent << "

Function: " << mf->getFunction()->getName() + << "

\n" + << indent << "

Rendering context: " << renderContextStr << "

\n"; + } + + + void RenderMachineFunction::renderPressureTableLegend( + const Spacer &indent, + raw_ostream &os) const { + os << indent << "

Rendering Pressure Legend:

\n" + << indent << "\n" + << indent + s(2) << "\n" + << indent + s(4) << "" + "\n" + << indent + s(2) << "\n" + << indent + s(2) << "\n" + << indent + s(4) << "" + "" + "\n" + << indent + s(2) << "\n" + << indent + s(2) << "\n" + << indent + s(4) << "" + "" + "\n" + << indent + s(2) << "\n" + << indent + s(2) << "\n" + << indent + s(4) << "" + "" + "\n" + << indent + s(2) << "\n" + << indent << "
PressureDescriptionAppearance
No PressureNo physical registers of this class requested.  
Low PressureSufficient physical registers to meet demand.  
High PressurePotentially insufficient physical registers to meet demand.  
\n"; + } + + template + void RenderMachineFunction::renderCellsWithRLE( + const Spacer &indent, raw_ostream &os, + const std::pair &rleAccumulator, + const std::map &cellTypeStrs) const { + + if (rleAccumulator.second == 0) + return; + + typename std::map::const_iterator ctsItr = + cellTypeStrs.find(rleAccumulator.first); + + assert(ctsItr != cellTypeStrs.end() && "No string for given cell type."); + + os << indent + s(4) << "second << "\""; + if (rleAccumulator.second > 1) + os << " colspan=" << rleAccumulator.second; + os << ">\n"; + } + + + void RenderMachineFunction::renderCodeTablePlusPI(const Spacer &indent, + raw_ostream &os) const { + + std::map lsStrs; + lsStrs[Dead] = "l-n"; + lsStrs[Defined] = "l-d"; + lsStrs[Used] = "l-u"; + lsStrs[AliveReg] = "l-r"; + lsStrs[AliveStack] = "l-s"; + + std::map psStrs; + psStrs[Zero] = "p-z"; + psStrs[Low] = "p-l"; + psStrs[High] = "p-h"; + + // Open the table... + + os << indent << "\n" + << indent + s(2) << "\n"; + + // Render the header row... + + os << indent + s(4) << "\n" + << indent + s(4) << "\n"; + + // Render class names if necessary... + if (!ro.regClasses().empty()) { + for (MFRenderingOptions::RegClassSet::const_iterator + rcItr = ro.regClasses().begin(), + rcEnd = ro.regClasses().end(); + rcItr != rcEnd; ++rcItr) { + const TargetRegisterClass *trc = *rcItr; + os << indent + s(4) << "\n"; + } + } + + // FIXME: Is there a nicer way to insert space between columns in HTML? + if (!ro.regClasses().empty() && !ro.intervals().empty()) + os << indent + s(4) << "\n"; + + // Render interval numbers if necessary... + if (!ro.intervals().empty()) { + for (MFRenderingOptions::IntervalSet::const_iterator + liItr = ro.intervals().begin(), + liEnd = ro.intervals().end(); + liItr != liEnd; ++liItr) { + + const LiveInterval *li = *liItr; + os << indent + s(4) << "\n"; + } + } + + os << indent + s(2) << "\n"; + + // End header row, start with the data rows... + + MachineInstr *mi = 0; + + // Data rows: + for (SlotIndex i = sis->getZeroIndex(); i != sis->getLastIndex(); + i = i.getNextSlot()) { + + // Render the slot column. + os << indent + s(2) << "\n"; + + // Render the code column. + if (i.isLoad()) { + MachineBasicBlock *mbb = sis->getMBBFromIndex(i); + mi = sis->getInstructionFromIndex(i); + + if (i == sis->getMBBStartIdx(mbb) || mi != 0 || + ro.renderEmptyIndexes()) { + os << indent + s(4) << "\n" + << indent + s(4) << "\n"; + } else { + i = i.getStoreIndex(); // <- Will be incremented to the next index. + continue; + } + } + + // Render the class columns. + if (!ro.regClasses().empty()) { + std::pair psRLEAccumulator(Zero, 0); + for (MFRenderingOptions::RegClassSet::const_iterator + rcItr = ro.regClasses().begin(), + rcEnd = ro.regClasses().end(); + rcItr != rcEnd; ++rcItr) { + const TargetRegisterClass *trc = *rcItr; + PressureState newPressure = getPressureStateAt(trc, i); + + if (newPressure == psRLEAccumulator.first) { + ++psRLEAccumulator.second; + } else { + renderCellsWithRLE(indent + s(4), os, psRLEAccumulator, psStrs); + psRLEAccumulator.first = newPressure; + psRLEAccumulator.second = 1; + } + } + renderCellsWithRLE(indent + s(4), os, psRLEAccumulator, psStrs); + } + + // FIXME: Is there a nicer way to insert space between columns in HTML? + if (!ro.regClasses().empty() && !ro.intervals().empty()) + os << indent + s(4) << "\n"; + + if (!ro.intervals().empty()) { + std::pair lsRLEAccumulator(Dead, 0); + for (MFRenderingOptions::IntervalSet::const_iterator + liItr = ro.intervals().begin(), + liEnd = ro.intervals().end(); + liItr != liEnd; ++liItr) { + const LiveInterval *li = *liItr; + LiveState newLiveness = getLiveStateAt(li, i); + + if (newLiveness == lsRLEAccumulator.first) { + ++lsRLEAccumulator.second; + } else { + renderCellsWithRLE(indent + s(4), os, lsRLEAccumulator, lsStrs); + lsRLEAccumulator.first = newLiveness; + lsRLEAccumulator.second = 1; + } + } + renderCellsWithRLE(indent + s(4), os, lsRLEAccumulator, lsStrs); + } + os << indent + s(2) << "\n"; + } + + os << indent << "
indexinstr\n"; + renderVertical(indent + s(6), os, trc->getName()); + os << indent + s(4) << "  \n"; + renderVertical(indent + s(6), os, li->reg); + os << indent + s(4) << "
" << i << " \n"; + + if (i == sis->getMBBStartIdx(mbb)) { + os << indent + s(6) << "BB#" << mbb->getNumber() << ": \n"; + } else if (mi != 0) { + os << indent + s(6) << "  "; + renderMachineInstr(os, mi); + } else { + // Empty interval - leave blank. + } + os << indent + s(4) << "
\n"; + + if (!ro.regClasses().empty()) + renderPressureTableLegend(indent, os); + } + + void RenderMachineFunction::renderFunctionPage( + raw_ostream &os, + const char * const renderContextStr) const { + os << "\n" + << s(2) << "\n" + << s(4) << "" << fqn << "\n"; + + insertCSS(s(4), os); + + os << s(2) << "\n" + << s(2) << "\n"; + + renderFunctionSummary(s(4), os, renderContextStr); + + os << s(4) << "


\n"; + + //renderLiveIntervalInfoTable(" ", os); + + os << s(4) << "


\n"; + + renderCodeTablePlusPI(s(4), os); + + os << s(2) << "\n" + << "\n"; + } + + void RenderMachineFunction::getAnalysisUsage(AnalysisUsage &au) const { + au.addRequired(); + au.addRequired(); + au.setPreservesAll(); + MachineFunctionPass::getAnalysisUsage(au); + } + + bool RenderMachineFunction::runOnMachineFunction(MachineFunction &fn) { + + mf = &fn; + mri = &mf->getRegInfo(); + tri = mf->getTarget().getRegisterInfo(); + lis = &getAnalysis(); + sis = &getAnalysis(); + + trei.setup(mf, mri, tri, lis); + ro.setup(mf, tri, lis, this); + spillIntervals.clear(); + spillFor.clear(); + useDefs.clear(); + + fqn = mf->getFunction()->getParent()->getModuleIdentifier() + "." + + mf->getFunction()->getName().str(); + + return false; + } + + void RenderMachineFunction::releaseMemory() { + trei.clear(); + ro.clear(); + spillIntervals.clear(); + spillFor.clear(); + useDefs.clear(); + } + + void RenderMachineFunction::rememberUseDefs(const LiveInterval *li) { + + if (!ro.shouldRenderCurrentMachineFunction()) + return; + + for (MachineRegisterInfo::reg_iterator rItr = mri->reg_begin(li->reg), + rEnd = mri->reg_end(); + rItr != rEnd; ++rItr) { + const MachineInstr *mi = &*rItr; + if (mi->readsRegister(li->reg)) { + useDefs[li].insert(lis->getInstructionIndex(mi).getUseIndex()); + } + if (mi->definesRegister(li->reg)) { + useDefs[li].insert(lis->getInstructionIndex(mi).getDefIndex()); + } + } + } + + void RenderMachineFunction::rememberSpills( + const LiveInterval *li, + const std::vector &spills) { + + if (!ro.shouldRenderCurrentMachineFunction()) + return; + + for (std::vector::const_iterator siItr = spills.begin(), + siEnd = spills.end(); + siItr != siEnd; ++siItr) { + const LiveInterval *spill = *siItr; + spillIntervals[li].insert(spill); + spillFor[spill] = li; + } + } + + bool RenderMachineFunction::isSpill(const LiveInterval *li) const { + SpillForMap::const_iterator sfItr = spillFor.find(li); + if (sfItr == spillFor.end()) + return false; + return true; + } + + void RenderMachineFunction::renderMachineFunction( + const char *renderContextStr, + const VirtRegMap *vrm, + const char *renderSuffix) { + if (!ro.shouldRenderCurrentMachineFunction()) + return; + + this->vrm = vrm; + trei.reset(); + + std::string rpFileName(mf->getFunction()->getName().str() + + (renderSuffix ? renderSuffix : "") + + outputFileSuffix); + + std::string errMsg; + raw_fd_ostream outFile(rpFileName.c_str(), errMsg, raw_fd_ostream::F_Binary); + + renderFunctionPage(outFile, renderContextStr); + + ro.resetRenderSpecificOptions(); + } + + std::string RenderMachineFunction::escapeChars(const std::string &s) const { + return escapeChars(s.begin(), s.end()); + } + +} diff --git a/lib/CodeGen/RenderMachineFunction.h b/lib/CodeGen/RenderMachineFunction.h new file mode 100644 index 0000000..8d56a82 --- /dev/null +++ b/lib/CodeGen/RenderMachineFunction.h @@ -0,0 +1,336 @@ +//===-- llvm/CodeGen/RenderMachineFunction.h - MF->HTML -*- C++ -*---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_RENDERMACHINEFUNCTION_H +#define LLVM_CODEGEN_RENDERMACHINEFUNCTION_H + +#include "llvm/CodeGen/LiveInterval.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/SlotIndexes.h" +#include "llvm/Target/TargetRegisterInfo.h" + +#include +#include +#include +#include + +namespace llvm { + + class LiveInterval; + class LiveIntervals; + class MachineInstr; + class MachineRegisterInfo; + class RenderMachineFunction; + class TargetRegisterClass; + class TargetRegisterInfo; + class VirtRegMap; + class raw_ostream; + + /// \brief Helper class to process rendering options. Tries to be as lazy as + /// possible. + class MFRenderingOptions { + public: + + struct RegClassComp { + bool operator()(const TargetRegisterClass *trc1, + const TargetRegisterClass *trc2) const { + std::string trc1Name(trc1->getName()), trc2Name(trc2->getName()); + return std::lexicographical_compare(trc1Name.begin(), trc1Name.end(), + trc2Name.begin(), trc2Name.end()); + } + }; + + typedef std::set RegClassSet; + + struct IntervalComp { + bool operator()(const LiveInterval *li1, const LiveInterval *li2) const { + return li1->reg < li2->reg; + } + }; + + typedef std::set IntervalSet; + + /// Initialise the rendering options. + void setup(MachineFunction *mf, const TargetRegisterInfo *tri, + LiveIntervals *lis, const RenderMachineFunction *rmf); + + /// Clear translations of options to the current function. + void clear(); + + /// Reset any options computed for this specific rendering. + void resetRenderSpecificOptions(); + + /// Should we render the current function. + bool shouldRenderCurrentMachineFunction() const; + + /// Return the set of register classes to render pressure for. + const RegClassSet& regClasses() const; + + /// Return the set of live intervals to render liveness for. + const IntervalSet& intervals() const; + + /// Render indexes which are not associated with instructions / MBB starts. + bool renderEmptyIndexes() const; + + /// Return whether or not to render using SVG for fancy vertical text. + bool fancyVerticals() const; + + private: + + static bool renderingOptionsProcessed; + static std::set mfNamesToRender; + static bool renderAllMFs; + + static std::set classNamesToRender; + static bool renderAllClasses; + + + static std::set > intervalNumsToRender; + typedef enum { ExplicitOnly = 0, + AllPhys = 1, + VirtNoSpills = 2, + VirtSpills = 4, + AllVirt = 6, + All = 7 } + IntervalTypesToRender; + static unsigned intervalTypesToRender; + + template + static void splitComaSeperatedList(const std::string &s, OutputItr outItr); + + static void processOptions(); + + static void processFuncNames(); + static void processRegClassNames(); + static void processIntervalNumbers(); + + static void processIntervalRange(const std::string &intervalRangeStr); + + MachineFunction *mf; + const TargetRegisterInfo *tri; + LiveIntervals *lis; + const RenderMachineFunction *rmf; + + mutable bool regClassesTranslatedToCurrentFunction; + mutable RegClassSet regClassSet; + + mutable bool intervalsTranslatedToCurrentFunction; + mutable IntervalSet intervalSet; + + void translateRegClassNamesToCurrentFunction() const; + + void translateIntervalNumbersToCurrentFunction() const; + }; + + /// \brief Provide extra information about the physical and virtual registers + /// in the function being compiled. + class TargetRegisterExtraInfo { + public: + TargetRegisterExtraInfo(); + + /// \brief Set up TargetRegisterExtraInfo with pointers to necessary + /// sources of information. + void setup(MachineFunction *mf, MachineRegisterInfo *mri, + const TargetRegisterInfo *tri, LiveIntervals *lis); + + /// \brief Recompute tables for changed function. + void reset(); + + /// \brief Free all tables in TargetRegisterExtraInfo. + void clear(); + + /// \brief Maximum number of registers from trc which alias reg. + unsigned getWorst(unsigned reg, const TargetRegisterClass *trc) const; + + /// \brief Returns the number of allocable registers in trc. + unsigned getCapacity(const TargetRegisterClass *trc) const; + + /// \brief Return the number of registers of class trc that may be + /// needed at slot i. + unsigned getPressureAtSlot(const TargetRegisterClass *trc, + SlotIndex i) const; + + /// \brief Return true if the number of registers of type trc that may be + /// needed at slot i is greater than the capacity of trc. + bool classOverCapacityAtSlot(const TargetRegisterClass *trc, + SlotIndex i) const; + + private: + + MachineFunction *mf; + MachineRegisterInfo *mri; + const TargetRegisterInfo *tri; + LiveIntervals *lis; + + typedef std::map WorstMapLine; + typedef std::map VRWorstMap; + VRWorstMap vrWorst; + + typedef std::map PRWorstMap; + PRWorstMap prWorst; + + typedef std::map CapacityMap; + CapacityMap capacityMap; + + typedef std::map PressureMapLine; + typedef std::map PressureMap; + PressureMap pressureMap; + + bool mapsPopulated; + + /// \brief Initialise the 'worst' table. + void initWorst(); + + /// \brief Initialise the 'capacity' table. + void initCapacity(); + + /// \brief Initialise/Reset the 'pressure' and live states tables. + void resetPressureAndLiveStates(); + }; + + /// \brief Render MachineFunction objects and related information to a HTML + /// page. + class RenderMachineFunction : public MachineFunctionPass { + public: + static char ID; + + RenderMachineFunction() : MachineFunctionPass(ID) {} + + virtual void getAnalysisUsage(AnalysisUsage &au) const; + + virtual bool runOnMachineFunction(MachineFunction &fn); + + virtual void releaseMemory(); + + void rememberUseDefs(const LiveInterval *li); + + void rememberSpills(const LiveInterval *li, + const std::vector &spills); + + bool isSpill(const LiveInterval *li) const; + + /// \brief Render this machine function to HTML. + /// + /// @param renderContextStr This parameter will be included in the top of + /// the html file to explain where (in the + /// codegen pipeline) this function was rendered + /// from. Set it to something like + /// "Pre-register-allocation". + /// @param vrm If non-null the VRM will be queried to determine + /// whether a virtual register was allocated to a + /// physical register or spilled. + /// @param renderFilePrefix This string will be appended to the function + /// name (before the output file suffix) to enable + /// multiple renderings from the same function. + void renderMachineFunction(const char *renderContextStr, + const VirtRegMap *vrm = 0, + const char *renderSuffix = 0); + + private: + class Spacer; + friend raw_ostream& operator<<(raw_ostream &os, const Spacer &s); + + std::string fqn; + + MachineFunction *mf; + MachineRegisterInfo *mri; + const TargetRegisterInfo *tri; + LiveIntervals *lis; + SlotIndexes *sis; + const VirtRegMap *vrm; + + TargetRegisterExtraInfo trei; + MFRenderingOptions ro; + + + + // Utilities. + typedef enum { Dead, Defined, Used, AliveReg, AliveStack } LiveState; + LiveState getLiveStateAt(const LiveInterval *li, SlotIndex i) const; + + typedef enum { Zero, Low, High } PressureState; + PressureState getPressureStateAt(const TargetRegisterClass *trc, + SlotIndex i) const; + + typedef std::map > + SpillIntervals; + SpillIntervals spillIntervals; + + typedef std::map SpillForMap; + SpillForMap spillFor; + + typedef std::set SlotSet; + typedef std::map UseDefs; + UseDefs useDefs; + + // ---------- Rendering methods ---------- + + /// For inserting spaces when pretty printing. + class Spacer { + public: + explicit Spacer(unsigned numSpaces) : ns(numSpaces) {} + Spacer operator+(const Spacer &o) const { return Spacer(ns + o.ns); } + void print(raw_ostream &os) const; + private: + unsigned ns; + }; + + Spacer s(unsigned ns) const; + + template + std::string escapeChars(Iterator sBegin, Iterator sEnd) const; + + /// \brief Render a machine instruction. + void renderMachineInstr(raw_ostream &os, + const MachineInstr *mi) const; + + /// \brief Render vertical text. + template + void renderVertical(const Spacer &indent, + raw_ostream &os, + const T &t) const; + + /// \brief Insert CSS layout info. + void insertCSS(const Spacer &indent, + raw_ostream &os) const; + + /// \brief Render a brief summary of the function (including rendering + /// context). + void renderFunctionSummary(const Spacer &indent, + raw_ostream &os, + const char * const renderContextStr) const; + + /// \brief Render a legend for the pressure table. + void renderPressureTableLegend(const Spacer &indent, + raw_ostream &os) const; + + /// \brief Render a consecutive set of HTML cells of the same class using + /// the colspan attribute for run-length encoding. + template + void renderCellsWithRLE( + const Spacer &indent, raw_ostream &os, + const std::pair &rleAccumulator, + const std::map &cellTypeStrs) const; + + /// \brief Render code listing, potentially with register pressure + /// and live intervals shown alongside. + void renderCodeTablePlusPI(const Spacer &indent, + raw_ostream &os) const; + + /// \brief Render the HTML page representing the MachineFunction. + void renderFunctionPage(raw_ostream &os, + const char * const renderContextStr) const; + + std::string escapeChars(const std::string &s) const; + }; +} + +#endif /* LLVM_CODEGEN_RENDERMACHINEFUNCTION_H */ diff --git a/lib/CodeGen/ScheduleDAGInstrs.cpp b/lib/CodeGen/ScheduleDAGInstrs.cpp index 09202f8..ea93dd5 100644 --- a/lib/CodeGen/ScheduleDAGInstrs.cpp +++ b/lib/CodeGen/ScheduleDAGInstrs.cpp @@ -32,7 +32,8 @@ using namespace llvm; ScheduleDAGInstrs::ScheduleDAGInstrs(MachineFunction &mf, const MachineLoopInfo &mli, const MachineDominatorTree &mdt) - : ScheduleDAG(mf), MLI(mli), MDT(mdt), LoopRegs(MLI, MDT) { + : ScheduleDAG(mf), MLI(mli), MDT(mdt), Defs(TRI->getNumRegs()), + Uses(TRI->getNumRegs()), LoopRegs(MLI, MDT) { MFI = mf.getFrameInfo(); DbgValueVec.clear(); } @@ -159,8 +160,9 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { std::map > AliasMemUses, NonAliasMemUses; // Keep track of dangling debug references to registers. - std::pair - DanglingDebugValue[TargetRegisterInfo::FirstVirtualRegister]; + std::vector > + DanglingDebugValue(TRI->getNumRegs(), + std::make_pair(static_cast(0), 0)); // Check to see if the scheduler cares about latencies. bool UnitLatencies = ForceUnitLatencies(); @@ -172,7 +174,6 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { // Remove any stale debug info; sometimes BuildSchedGraph is called again // without emitting the info from the previous call. DbgValueVec.clear(); - std::memset(DanglingDebugValue, 0, sizeof(DanglingDebugValue)); // Walk the list of instructions, from bottom moving up. for (MachineBasicBlock::iterator MII = InsertPos, MIE = Begin; diff --git a/lib/CodeGen/ScheduleDAGInstrs.h b/lib/CodeGen/ScheduleDAGInstrs.h index d90659b..c8f543f 100644 --- a/lib/CodeGen/ScheduleDAGInstrs.h +++ b/lib/CodeGen/ScheduleDAGInstrs.h @@ -106,8 +106,8 @@ namespace llvm { /// are as we iterate upward through the instructions. This is allocated /// here instead of inside BuildSchedGraph to avoid the need for it to be /// initialized and destructed for each block. - std::vector Defs[TargetRegisterInfo::FirstVirtualRegister]; - std::vector Uses[TargetRegisterInfo::FirstVirtualRegister]; + std::vector > Defs; + std::vector > Uses; /// DbgValueVec - Remember DBG_VALUEs that refer to a particular /// register. diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index e671752..c9c4d91 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -4489,6 +4489,16 @@ ConstantFoldBIT_CONVERTofBUILD_VECTOR(SDNode *BV, EVT DstEltVT) { // If this is a conversion of N elements of one type to N elements of another // type, convert each element. This handles FP<->INT cases. if (SrcBitSize == DstBitSize) { + EVT VT = EVT::getVectorVT(*DAG.getContext(), DstEltVT, + BV->getValueType(0).getVectorNumElements()); + + // Due to the FP element handling below calling this routine recursively, + // we can end up with a scalar-to-vector node here. + if (BV->getOpcode() == ISD::SCALAR_TO_VECTOR) + return DAG.getNode(ISD::SCALAR_TO_VECTOR, BV->getDebugLoc(), VT, + DAG.getNode(ISD::BIT_CONVERT, BV->getDebugLoc(), + DstEltVT, BV->getOperand(0))); + SmallVector Ops; for (unsigned i = 0, e = BV->getNumOperands(); i != e; ++i) { SDValue Op = BV->getOperand(i); @@ -4500,8 +4510,6 @@ ConstantFoldBIT_CONVERTofBUILD_VECTOR(SDNode *BV, EVT DstEltVT) { DstEltVT, Op)); AddToWorkList(Ops.back().getNode()); } - EVT VT = EVT::getVectorVT(*DAG.getContext(), DstEltVT, - BV->getValueType(0).getVectorNumElements()); return DAG.getNode(ISD::BUILD_VECTOR, BV->getDebugLoc(), VT, &Ops[0], Ops.size()); } @@ -5790,7 +5798,8 @@ SDValue DAGCombiner::ReduceLoadOpStoreWidth(SDNode *N) { return SDValue(); SDValue N0 = Value.getOperand(0); - if (ISD::isNormalLoad(N0.getNode()) && N0.hasOneUse()) { + if (ISD::isNormalLoad(N0.getNode()) && N0.hasOneUse() && + Chain == SDValue(N0.getNode(), 1)) { LoadSDNode *LD = cast(N0); if (LD->getBasePtr() != Ptr) return SDValue(); diff --git a/lib/CodeGen/SelectionDAG/FastISel.cpp b/lib/CodeGen/SelectionDAG/FastISel.cpp index decaa76..a4eed71 100644 --- a/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -94,7 +94,7 @@ bool FastISel::hasTrivialKill(const Value *V) const { !(I->getOpcode() == Instruction::BitCast || I->getOpcode() == Instruction::PtrToInt || I->getOpcode() == Instruction::IntToPtr) && - cast(I->use_begin())->getParent() == I->getParent(); + cast(*I->use_begin())->getParent() == I->getParent(); } unsigned FastISel::getRegForValue(const Value *V) { @@ -146,7 +146,7 @@ unsigned FastISel::getRegForValue(const Value *V) { return Reg; } -/// materializeRegForValue - Helper for getRegForVale. This function is +/// materializeRegForValue - Helper for getRegForValue. This function is /// called when the value isn't already available in a register and must /// be materialized with new instructions. unsigned FastISel::materializeRegForValue(const Value *V, MVT VT) { @@ -276,6 +276,7 @@ std::pair FastISel::getRegForGEPIndex(const Value *Idx) { void FastISel::recomputeInsertPt() { if (getLastLocalValue()) { FuncInfo.InsertPt = getLastLocalValue(); + FuncInfo.MBB = FuncInfo.InsertPt->getParent(); ++FuncInfo.InsertPt; } else FuncInfo.InsertPt = FuncInfo.MBB->getFirstNonPHI(); @@ -472,17 +473,7 @@ bool FastISel::SelectCall(const User *I) { return true; const AllocaInst *AI = dyn_cast(Address); // Don't handle byval struct arguments or VLAs, for example. - // Note that if we have a byval struct argument, fast ISel is turned off; - // those are handled in SelectionDAGBuilder. - if (AI) { - DenseMap::iterator SI = - FuncInfo.StaticAllocaMap.find(AI); - if (SI == FuncInfo.StaticAllocaMap.end()) break; // VLAs. - int FI = SI->second; - if (!DI->getDebugLoc().isUnknown()) - FuncInfo.MF->getMMI().setVariableDbgInfo(DI->getVariable(), - FI, DI->getDebugLoc()); - } else + if (!AI) // Building the map above is target independent. Generating DBG_VALUE // inline is target dependent; do this now. (void)TargetSelectInstruction(cast(I)); diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index 928e1ec..5ef6404 100644 --- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -20,6 +20,7 @@ #include "llvm/IntrinsicInst.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" +#include "llvm/Analysis/DebugInfo.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -111,17 +112,56 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf) { TySize *= CUI->getZExtValue(); // Get total allocated size. if (TySize == 0) TySize = 1; // Don't create zero-sized stack objects. + + // The object may need to be placed onto the stack near the stack + // protector if one exists. Determine here if this object is a suitable + // candidate. I.e., it would trigger the creation of a stack protector. + bool MayNeedSP = + (AI->isArrayAllocation() || + (TySize > 8 && isa(Ty) && + cast(Ty)->getElementType()->isIntegerTy(8))); StaticAllocaMap[AI] = - MF->getFrameInfo()->CreateStackObject(TySize, Align, false); + MF->getFrameInfo()->CreateStackObject(TySize, Align, false, MayNeedSP); } for (; BB != EB; ++BB) - for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E; ++I) + for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E; ++I) { + // Mark values used outside their block as exported, by allocating + // a virtual register for them. if (isUsedOutsideOfDefiningBlock(I)) if (!isa(I) || !StaticAllocaMap.count(cast(I))) InitializeRegForValue(I); + // Collect llvm.dbg.declare information. This is done now instead of + // during the initial isel pass through the IR so that it is done + // in a predictable order. + if (const DbgDeclareInst *DI = dyn_cast(I)) { + MachineModuleInfo &MMI = MF->getMMI(); + if (MMI.hasDebugInfo() && + DIVariable(DI->getVariable()).Verify() && + !DI->getDebugLoc().isUnknown()) { + // Don't handle byval struct arguments or VLAs, for example. + // Non-byval arguments are handled here (they refer to the stack + // temporary alloca at this point). + const Value *Address = DI->getAddress(); + if (Address) { + if (const BitCastInst *BCI = dyn_cast(Address)) + Address = BCI->getOperand(0); + if (const AllocaInst *AI = dyn_cast(Address)) { + DenseMap::iterator SI = + StaticAllocaMap.find(AI); + if (SI != StaticAllocaMap.end()) { // Check for VLAs. + int FI = SI->second; + MMI.setVariableDbgInfo(DI->getVariable(), + FI, DI->getDebugLoc()); + } + } + } + } + } + } + // Create an initial MachineBasicBlock for each LLVM BasicBlock in F. This // also creates the initial PHI MachineInstrs, though none of the input // operands are populated. @@ -181,6 +221,7 @@ void FunctionLoweringInfo::clear() { #endif LiveOutRegInfo.clear(); ArgDbgValues.clear(); + ByValArgFrameIndexMap.clear(); RegFixups.clear(); } @@ -214,6 +255,28 @@ unsigned FunctionLoweringInfo::CreateRegs(const Type *Ty) { return FirstReg; } +/// setByValArgumentFrameIndex - Record frame index for the byval +/// argument. This overrides previous frame index entry for this argument, +/// if any. +void FunctionLoweringInfo::setByValArgumentFrameIndex(const Argument *A, + int FI) { + assert (A->hasByValAttr() && "Argument does not have byval attribute!"); + ByValArgFrameIndexMap[A] = FI; +} + +/// getByValArgumentFrameIndex - Get frame index for the byval argument. +/// If the argument does not have any assigned frame index then 0 is +/// returned. +int FunctionLoweringInfo::getByValArgumentFrameIndex(const Argument *A) { + assert (A->hasByValAttr() && "Argument does not have byval attribute!"); + DenseMap::iterator I = + ByValArgFrameIndexMap.find(A); + if (I != ByValArgFrameIndexMap.end()) + return I->second; + DEBUG(dbgs() << "Argument does not have assigned frame index!"); + return 0; +} + /// AddCatchInfo - Extract the personality and type infos from an eh.selector /// call, and add them to the specified machine basic block. void llvm::AddCatchInfo(const CallInst &I, MachineModuleInfo *MMI, diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 7a47da4..2981cd3 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -100,8 +100,7 @@ public: /// it is already legal or we need to expand it into multiple registers of /// smaller integer type, or we need to promote it to a larger type. LegalizeAction getTypeAction(EVT VT) const { - return - (LegalizeAction)ValueTypeActions.getTypeAction(*DAG.getContext(), VT); + return (LegalizeAction)ValueTypeActions.getTypeAction(VT); } /// isTypeLegal - Return true if this type is legal on this target. @@ -1314,21 +1313,30 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { } break; case TargetLowering::Expand: - // f64 = EXTLOAD f32 should expand to LOAD, FP_EXTEND - // f128 = EXTLOAD {f32,f64} too - if ((SrcVT == MVT::f32 && (Node->getValueType(0) == MVT::f64 || - Node->getValueType(0) == MVT::f128)) || - (SrcVT == MVT::f64 && Node->getValueType(0) == MVT::f128)) { + if (!TLI.isLoadExtLegal(ISD::EXTLOAD, SrcVT) && isTypeLegal(SrcVT)) { SDValue Load = DAG.getLoad(SrcVT, dl, Tmp1, Tmp2, LD->getSrcValue(), LD->getSrcValueOffset(), LD->isVolatile(), LD->isNonTemporal(), LD->getAlignment()); - Result = DAG.getNode(ISD::FP_EXTEND, dl, - Node->getValueType(0), Load); + unsigned ExtendOp; + switch (ExtType) { + case ISD::EXTLOAD: + ExtendOp = (SrcVT.isFloatingPoint() ? + ISD::FP_EXTEND : ISD::ANY_EXTEND); + break; + case ISD::SEXTLOAD: ExtendOp = ISD::SIGN_EXTEND; break; + case ISD::ZEXTLOAD: ExtendOp = ISD::ZERO_EXTEND; break; + default: llvm_unreachable("Unexpected extend load type!"); + } + Result = DAG.getNode(ExtendOp, dl, Node->getValueType(0), Load); Tmp1 = LegalizeOp(Result); // Relegalize new nodes. Tmp2 = LegalizeOp(Load.getValue(1)); break; } + // FIXME: This does not work for vectors on most targets. Sign- and + // zero-extend operations are currently folded into extending loads, + // whether they are legal or not, and then we end up here without any + // support for legalizing them. assert(ExtType != ISD::EXTLOAD && "EXTLOAD should always be supported!"); // Turn the unsupported load into an EXTLOAD followed by an explicit diff --git a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp index b94ea9a..f8c5890 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -234,8 +234,9 @@ SDValue DAGTypeLegalizer::PromoteIntRes_BUILD_PAIR(SDNode *N) { // The pair element type may be legal, or may not promote to the same type as // the result, for example i14 = BUILD_PAIR (i7, i7). Handle all cases. return DAG.getNode(ISD::ANY_EXTEND, N->getDebugLoc(), - TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)), - JoinIntegers(N->getOperand(0), N->getOperand(1))); + TLI.getTypeToTransformTo(*DAG.getContext(), + N->getValueType(0)), JoinIntegers(N->getOperand(0), + N->getOperand(1))); } SDValue DAGTypeLegalizer::PromoteIntRes_Constant(SDNode *N) { @@ -245,7 +246,8 @@ SDValue DAGTypeLegalizer::PromoteIntRes_Constant(SDNode *N) { // Zero extend things like i1, sign extend everything else. It shouldn't // matter in theory which one we pick, but this tends to give better code? unsigned Opc = VT.isByteSized() ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND; - SDValue Result = DAG.getNode(Opc, dl, TLI.getTypeToTransformTo(*DAG.getContext(), VT), + SDValue Result = DAG.getNode(Opc, dl, + TLI.getTypeToTransformTo(*DAG.getContext(), VT), SDValue(N, 0)); assert(isa(Result) && "Didn't constant fold ext?"); return Result; @@ -310,8 +312,8 @@ SDValue DAGTypeLegalizer::PromoteIntRes_FP_TO_XINT(SDNode *N) { // If we're promoting a UINT to a larger size and the larger FP_TO_UINT is // not Legal, check to see if we can use FP_TO_SINT instead. (If both UINT - // and SINT conversions are Custom, there is no way to tell which is preferable. - // We choose SINT because that's the right thing on PPC.) + // and SINT conversions are Custom, there is no way to tell which is + // preferable. We choose SINT because that's the right thing on PPC.) if (N->getOpcode() == ISD::FP_TO_UINT && !TLI.isOperationLegal(ISD::FP_TO_UINT, NVT) && TLI.isOperationLegalOrCustom(ISD::FP_TO_SINT, NVT)) @@ -1030,7 +1032,7 @@ void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt, Hi = InL; } else if (Amt == 1 && TLI.isOperationLegalOrCustom(ISD::ADDC, - TLI.getTypeToExpandTo(*DAG.getContext(), NVT))) { + TLI.getTypeToExpandTo(*DAG.getContext(), NVT))) { // Emit this X << 1 as X+X. SDVTList VTList = DAG.getVTList(NVT, MVT::Flag); SDValue LoOps[2] = { InL, InL }; @@ -1926,7 +1928,8 @@ ExpandIntRes_SIGN_EXTEND_INREG(SDNode *N, SDValue &Lo, SDValue &Hi) { unsigned ExcessBits = EVT.getSizeInBits() - Lo.getValueType().getSizeInBits(); Hi = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, Hi.getValueType(), Hi, - DAG.getValueType(EVT::getIntegerVT(*DAG.getContext(), ExcessBits))); + DAG.getValueType(EVT::getIntegerVT(*DAG.getContext(), + ExcessBits))); } } @@ -2046,7 +2049,8 @@ void DAGTypeLegalizer::ExpandIntRes_ZERO_EXTEND(SDNode *N, unsigned ExcessBits = Op.getValueType().getSizeInBits() - NVT.getSizeInBits(); Hi = DAG.getZeroExtendInReg(Hi, dl, - EVT::getIntegerVT(*DAG.getContext(), ExcessBits)); + EVT::getIntegerVT(*DAG.getContext(), + ExcessBits)); } } diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h index bd86694..d560292 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -75,7 +75,7 @@ private: /// getTypeAction - Return how we should legalize values of this type. LegalizeAction getTypeAction(EVT VT) const { - switch (ValueTypeActions.getTypeAction(*DAG.getContext(), VT)) { + switch (ValueTypeActions.getTypeAction(VT)) { default: assert(false && "Unknown legalize action!"); case TargetLowering::Legal: @@ -86,8 +86,7 @@ private: // 2) For vectors, use a wider vector type (e.g. v3i32 -> v4i32). if (!VT.isVector()) return PromoteInteger; - else - return WidenVector; + return WidenVector; case TargetLowering::Expand: // Expand can mean // 1) split scalar in half, 2) convert a float to an integer, @@ -95,23 +94,21 @@ private: if (!VT.isVector()) { if (VT.isInteger()) return ExpandInteger; - else if (VT.getSizeInBits() == - TLI.getTypeToTransformTo(*DAG.getContext(), VT).getSizeInBits()) + if (VT.getSizeInBits() == + TLI.getTypeToTransformTo(*DAG.getContext(), VT).getSizeInBits()) return SoftenFloat; - else - return ExpandFloat; - } else if (VT.getVectorNumElements() == 1) { - return ScalarizeVector; - } else { - return SplitVector; + return ExpandFloat; } + + if (VT.getVectorNumElements() == 1) + return ScalarizeVector; + return SplitVector; } } /// isTypeLegal - Return true if this type is legal on this target. bool isTypeLegal(EVT VT) const { - return (ValueTypeActions.getTypeAction(*DAG.getContext(), VT) == - TargetLowering::Legal); + return ValueTypeActions.getTypeAction(VT) == TargetLowering::Legal; } /// IgnoreNodeResults - Pretend all of this node's results are legal. @@ -584,6 +581,7 @@ private: SDValue SplitVecOp_EXTRACT_SUBVECTOR(SDNode *N); SDValue SplitVecOp_EXTRACT_VECTOR_ELT(SDNode *N); SDValue SplitVecOp_STORE(StoreSDNode *N, unsigned OpNo); + SDValue SplitVecOp_CONCAT_VECTORS(SDNode *N); //===--------------------------------------------------------------------===// // Vector Widening Support: LegalizeVectorTypes.cpp diff --git a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp index 93aeff5..93bc2d0 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -983,6 +983,7 @@ bool DAGTypeLegalizer::SplitVectorOperand(SDNode *N, unsigned OpNo) { case ISD::BIT_CONVERT: Res = SplitVecOp_BIT_CONVERT(N); break; case ISD::EXTRACT_SUBVECTOR: Res = SplitVecOp_EXTRACT_SUBVECTOR(N); break; case ISD::EXTRACT_VECTOR_ELT:Res = SplitVecOp_EXTRACT_VECTOR_ELT(N); break; + case ISD::CONCAT_VECTORS: Res = SplitVecOp_CONCAT_VECTORS(N); break; case ISD::STORE: Res = SplitVecOp_STORE(cast(N), OpNo); break; @@ -1091,8 +1092,7 @@ SDValue DAGTypeLegalizer::SplitVecOp_EXTRACT_VECTOR_ELT(SDNode *N) { return SDValue(DAG.UpdateNodeOperands(N, Lo, Idx), 0); return SDValue(DAG.UpdateNodeOperands(N, Hi, DAG.getConstant(IdxVal - LoElts, - Idx.getValueType())), - 0); + Idx.getValueType())), 0); } // Store the vector to the stack. @@ -1113,7 +1113,7 @@ SDValue DAGTypeLegalizer::SplitVecOp_EXTRACT_VECTOR_ELT(SDNode *N) { SDValue DAGTypeLegalizer::SplitVecOp_STORE(StoreSDNode *N, unsigned OpNo) { assert(N->isUnindexed() && "Indexed store of vector?"); assert(OpNo == 1 && "Can only split the stored value"); - DebugLoc dl = N->getDebugLoc(); + DebugLoc DL = N->getDebugLoc(); bool isTruncating = N->isTruncatingStore(); SDValue Ch = N->getChain(); @@ -1132,25 +1132,49 @@ SDValue DAGTypeLegalizer::SplitVecOp_STORE(StoreSDNode *N, unsigned OpNo) { unsigned IncrementSize = LoMemVT.getSizeInBits()/8; if (isTruncating) - Lo = DAG.getTruncStore(Ch, dl, Lo, Ptr, N->getSrcValue(), SVOffset, + Lo = DAG.getTruncStore(Ch, DL, Lo, Ptr, N->getSrcValue(), SVOffset, LoMemVT, isVol, isNT, Alignment); else - Lo = DAG.getStore(Ch, dl, Lo, Ptr, N->getSrcValue(), SVOffset, + Lo = DAG.getStore(Ch, DL, Lo, Ptr, N->getSrcValue(), SVOffset, isVol, isNT, Alignment); // Increment the pointer to the other half. - Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, + Ptr = DAG.getNode(ISD::ADD, DL, Ptr.getValueType(), Ptr, DAG.getIntPtrConstant(IncrementSize)); SVOffset += IncrementSize; if (isTruncating) - Hi = DAG.getTruncStore(Ch, dl, Hi, Ptr, N->getSrcValue(), SVOffset, + Hi = DAG.getTruncStore(Ch, DL, Hi, Ptr, N->getSrcValue(), SVOffset, HiMemVT, isVol, isNT, Alignment); else - Hi = DAG.getStore(Ch, dl, Hi, Ptr, N->getSrcValue(), SVOffset, + Hi = DAG.getStore(Ch, DL, Hi, Ptr, N->getSrcValue(), SVOffset, isVol, isNT, Alignment); - return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo, Hi); + return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Lo, Hi); +} + +SDValue DAGTypeLegalizer::SplitVecOp_CONCAT_VECTORS(SDNode *N) { + DebugLoc DL = N->getDebugLoc(); + + // The input operands all must have the same type, and we know the result the + // result type is valid. Convert this to a buildvector which extracts all the + // input elements. + // TODO: If the input elements are power-two vectors, we could convert this to + // a new CONCAT_VECTORS node with elements that are half-wide. + SmallVector Elts; + EVT EltVT = N->getValueType(0).getVectorElementType(); + for (unsigned op = 0, e = N->getNumOperands(); op != e; ++op) { + SDValue Op = N->getOperand(op); + for (unsigned i = 0, e = Op.getValueType().getVectorNumElements(); + i != e; ++i) { + Elts.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, EltVT, + Op, DAG.getIntPtrConstant(i))); + + } + } + + return DAG.getNode(ISD::BUILD_VECTOR, DL, N->getValueType(0), + &Elts[0], Elts.size()); } @@ -1274,8 +1298,8 @@ SDValue DAGTypeLegalizer::WidenVecRes_Binary(SDNode *N) { EVT VT = WidenVT; unsigned NumElts = VT.getVectorNumElements(); while (!TLI.isTypeSynthesizable(VT) && NumElts != 1) { - NumElts = NumElts / 2; - VT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NumElts); + NumElts = NumElts / 2; + VT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NumElts); } if (NumElts != 1 && !TLI.canOpTrap(N->getOpcode(), VT)) { @@ -1283,124 +1307,123 @@ SDValue DAGTypeLegalizer::WidenVecRes_Binary(SDNode *N) { SDValue InOp1 = GetWidenedVector(N->getOperand(0)); SDValue InOp2 = GetWidenedVector(N->getOperand(1)); return DAG.getNode(N->getOpcode(), dl, WidenVT, InOp1, InOp2); - } else if (NumElts == 1) { - // No legal vector version so unroll the vector operation and then widen. + } + + // No legal vector version so unroll the vector operation and then widen. + if (NumElts == 1) return DAG.UnrollVectorOp(N, WidenVT.getVectorNumElements()); - } else { - // Since the operation can trap, apply operation on the original vector. - EVT MaxVT = VT; - SDValue InOp1 = GetWidenedVector(N->getOperand(0)); - SDValue InOp2 = GetWidenedVector(N->getOperand(1)); - unsigned CurNumElts = N->getValueType(0).getVectorNumElements(); - - SmallVector ConcatOps(CurNumElts); - unsigned ConcatEnd = 0; // Current ConcatOps index. - int Idx = 0; // Current Idx into input vectors. - - // NumElts := greatest synthesizable vector size (at most WidenVT) - // while (orig. vector has unhandled elements) { - // take munches of size NumElts from the beginning and add to ConcatOps - // NumElts := next smaller supported vector size or 1 - // } - while (CurNumElts != 0) { - while (CurNumElts >= NumElts) { - SDValue EOp1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, InOp1, - DAG.getIntPtrConstant(Idx)); - SDValue EOp2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, InOp2, - DAG.getIntPtrConstant(Idx)); - ConcatOps[ConcatEnd++] = DAG.getNode(Opcode, dl, VT, EOp1, EOp2); - Idx += NumElts; - CurNumElts -= NumElts; - } - do { - NumElts = NumElts / 2; - VT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NumElts); - } while (!TLI.isTypeSynthesizable(VT) && NumElts != 1); - - if (NumElts == 1) { - for (unsigned i = 0; i != CurNumElts; ++i, ++Idx) { - SDValue EOp1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, WidenEltVT, - InOp1, DAG.getIntPtrConstant(Idx)); - SDValue EOp2 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, WidenEltVT, - InOp2, DAG.getIntPtrConstant(Idx)); - ConcatOps[ConcatEnd++] = DAG.getNode(Opcode, dl, WidenEltVT, - EOp1, EOp2); - } - CurNumElts = 0; + + // Since the operation can trap, apply operation on the original vector. + EVT MaxVT = VT; + SDValue InOp1 = GetWidenedVector(N->getOperand(0)); + SDValue InOp2 = GetWidenedVector(N->getOperand(1)); + unsigned CurNumElts = N->getValueType(0).getVectorNumElements(); + + SmallVector ConcatOps(CurNumElts); + unsigned ConcatEnd = 0; // Current ConcatOps index. + int Idx = 0; // Current Idx into input vectors. + + // NumElts := greatest synthesizable vector size (at most WidenVT) + // while (orig. vector has unhandled elements) { + // take munches of size NumElts from the beginning and add to ConcatOps + // NumElts := next smaller supported vector size or 1 + // } + while (CurNumElts != 0) { + while (CurNumElts >= NumElts) { + SDValue EOp1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, InOp1, + DAG.getIntPtrConstant(Idx)); + SDValue EOp2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, InOp2, + DAG.getIntPtrConstant(Idx)); + ConcatOps[ConcatEnd++] = DAG.getNode(Opcode, dl, VT, EOp1, EOp2); + Idx += NumElts; + CurNumElts -= NumElts; + } + do { + NumElts = NumElts / 2; + VT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NumElts); + } while (!TLI.isTypeSynthesizable(VT) && NumElts != 1); + + if (NumElts == 1) { + for (unsigned i = 0; i != CurNumElts; ++i, ++Idx) { + SDValue EOp1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, WidenEltVT, + InOp1, DAG.getIntPtrConstant(Idx)); + SDValue EOp2 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, WidenEltVT, + InOp2, DAG.getIntPtrConstant(Idx)); + ConcatOps[ConcatEnd++] = DAG.getNode(Opcode, dl, WidenEltVT, + EOp1, EOp2); } + CurNumElts = 0; } + } - // Check to see if we have a single operation with the widen type. - if (ConcatEnd == 1) { - VT = ConcatOps[0].getValueType(); - if (VT == WidenVT) - return ConcatOps[0]; - } + // Check to see if we have a single operation with the widen type. + if (ConcatEnd == 1) { + VT = ConcatOps[0].getValueType(); + if (VT == WidenVT) + return ConcatOps[0]; + } - // while (Some element of ConcatOps is not of type MaxVT) { - // From the end of ConcatOps, collect elements of the same type and put - // them into an op of the next larger supported type - // } - while (ConcatOps[ConcatEnd-1].getValueType() != MaxVT) { - Idx = ConcatEnd - 1; - VT = ConcatOps[Idx--].getValueType(); - while (Idx >= 0 && ConcatOps[Idx].getValueType() == VT) - Idx--; - - int NextSize = VT.isVector() ? VT.getVectorNumElements() : 1; - EVT NextVT; - do { - NextSize *= 2; - NextVT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NextSize); - } while (!TLI.isTypeSynthesizable(NextVT)); - - if (!VT.isVector()) { - // Scalar type, create an INSERT_VECTOR_ELEMENT of type NextVT - SDValue VecOp = DAG.getUNDEF(NextVT); - unsigned NumToInsert = ConcatEnd - Idx - 1; - for (unsigned i = 0, OpIdx = Idx+1; i < NumToInsert; i++, OpIdx++) { - VecOp = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, NextVT, VecOp, - ConcatOps[OpIdx], DAG.getIntPtrConstant(i)); - } - ConcatOps[Idx+1] = VecOp; - ConcatEnd = Idx + 2; - } - else { - // Vector type, create a CONCAT_VECTORS of type NextVT - SDValue undefVec = DAG.getUNDEF(VT); - unsigned OpsToConcat = NextSize/VT.getVectorNumElements(); - SmallVector SubConcatOps(OpsToConcat); - unsigned RealVals = ConcatEnd - Idx - 1; - unsigned SubConcatEnd = 0; - unsigned SubConcatIdx = Idx + 1; - while (SubConcatEnd < RealVals) - SubConcatOps[SubConcatEnd++] = ConcatOps[++Idx]; - while (SubConcatEnd < OpsToConcat) - SubConcatOps[SubConcatEnd++] = undefVec; - ConcatOps[SubConcatIdx] = DAG.getNode(ISD::CONCAT_VECTORS, dl, - NextVT, &SubConcatOps[0], - OpsToConcat); - ConcatEnd = SubConcatIdx + 1; + // while (Some element of ConcatOps is not of type MaxVT) { + // From the end of ConcatOps, collect elements of the same type and put + // them into an op of the next larger supported type + // } + while (ConcatOps[ConcatEnd-1].getValueType() != MaxVT) { + Idx = ConcatEnd - 1; + VT = ConcatOps[Idx--].getValueType(); + while (Idx >= 0 && ConcatOps[Idx].getValueType() == VT) + Idx--; + + int NextSize = VT.isVector() ? VT.getVectorNumElements() : 1; + EVT NextVT; + do { + NextSize *= 2; + NextVT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NextSize); + } while (!TLI.isTypeSynthesizable(NextVT)); + + if (!VT.isVector()) { + // Scalar type, create an INSERT_VECTOR_ELEMENT of type NextVT + SDValue VecOp = DAG.getUNDEF(NextVT); + unsigned NumToInsert = ConcatEnd - Idx - 1; + for (unsigned i = 0, OpIdx = Idx+1; i < NumToInsert; i++, OpIdx++) { + VecOp = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, NextVT, VecOp, + ConcatOps[OpIdx], DAG.getIntPtrConstant(i)); } + ConcatOps[Idx+1] = VecOp; + ConcatEnd = Idx + 2; + } else { + // Vector type, create a CONCAT_VECTORS of type NextVT + SDValue undefVec = DAG.getUNDEF(VT); + unsigned OpsToConcat = NextSize/VT.getVectorNumElements(); + SmallVector SubConcatOps(OpsToConcat); + unsigned RealVals = ConcatEnd - Idx - 1; + unsigned SubConcatEnd = 0; + unsigned SubConcatIdx = Idx + 1; + while (SubConcatEnd < RealVals) + SubConcatOps[SubConcatEnd++] = ConcatOps[++Idx]; + while (SubConcatEnd < OpsToConcat) + SubConcatOps[SubConcatEnd++] = undefVec; + ConcatOps[SubConcatIdx] = DAG.getNode(ISD::CONCAT_VECTORS, dl, + NextVT, &SubConcatOps[0], + OpsToConcat); + ConcatEnd = SubConcatIdx + 1; } + } - // Check to see if we have a single operation with the widen type. - if (ConcatEnd == 1) { - VT = ConcatOps[0].getValueType(); - if (VT == WidenVT) - return ConcatOps[0]; - } - - // add undefs of size MaxVT until ConcatOps grows to length of WidenVT - unsigned NumOps = - WidenVT.getVectorNumElements()/MaxVT.getVectorNumElements(); - if (NumOps != ConcatEnd ) { - SDValue UndefVal = DAG.getUNDEF(MaxVT); - for (unsigned j = ConcatEnd; j < NumOps; ++j) - ConcatOps[j] = UndefVal; - } - return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT, &ConcatOps[0], NumOps); + // Check to see if we have a single operation with the widen type. + if (ConcatEnd == 1) { + VT = ConcatOps[0].getValueType(); + if (VT == WidenVT) + return ConcatOps[0]; } + + // add undefs of size MaxVT until ConcatOps grows to length of WidenVT + unsigned NumOps = WidenVT.getVectorNumElements()/MaxVT.getVectorNumElements(); + if (NumOps != ConcatEnd ) { + SDValue UndefVal = DAG.getUNDEF(MaxVT); + for (unsigned j = ConcatEnd; j < NumOps; ++j) + ConcatOps[j] = UndefVal; + } + return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT, &ConcatOps[0], NumOps); } SDValue DAGTypeLegalizer::WidenVecRes_Convert(SDNode *N) { @@ -1561,8 +1584,8 @@ SDValue DAGTypeLegalizer::WidenVecRes_BIT_CONVERT(SDNode *N) { unsigned NewNumElts = WidenSize / InSize; if (InVT.isVector()) { EVT InEltVT = InVT.getVectorElementType(); - NewInVT= EVT::getVectorVT(*DAG.getContext(), InEltVT, - WidenSize / InEltVT.getSizeInBits()); + NewInVT = EVT::getVectorVT(*DAG.getContext(), InEltVT, + WidenSize / InEltVT.getSizeInBits()); } else { NewInVT = EVT::getVectorVT(*DAG.getContext(), InVT, NewNumElts); } @@ -1686,8 +1709,7 @@ SDValue DAGTypeLegalizer::WidenVecRes_CONVERT_RNDSAT(SDNode *N) { SDValue RndOp = N->getOperand(3); SDValue SatOp = N->getOperand(4); - EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), - N->getValueType(0)); + EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); unsigned WidenNumElts = WidenVT.getVectorNumElements(); EVT InVT = InOp.getValueType(); @@ -1720,9 +1742,9 @@ SDValue DAGTypeLegalizer::WidenVecRes_CONVERT_RNDSAT(SDNode *N) { SmallVector Ops(NumConcat); Ops[0] = InOp; SDValue UndefVal = DAG.getUNDEF(InVT); - for (unsigned i = 1; i != NumConcat; ++i) { + for (unsigned i = 1; i != NumConcat; ++i) Ops[i] = UndefVal; - } + InOp = DAG.getNode(ISD::CONCAT_VECTORS, dl, InWidenVT, &Ops[0],NumConcat); return DAG.getConvertRndSat(WidenVT, dl, InOp, DTyOp, STyOp, RndOp, SatOp, CvtCode); @@ -2225,25 +2247,24 @@ SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVector& LdChain, // Check if we can load the element with one instruction if (LdWidth <= NewVTWidth) { - if (NewVT.isVector()) { - if (NewVT != WidenVT) { - assert(WidenWidth % NewVTWidth == 0); - unsigned NumConcat = WidenWidth / NewVTWidth; - SmallVector ConcatOps(NumConcat); - SDValue UndefVal = DAG.getUNDEF(NewVT); - ConcatOps[0] = LdOp; - for (unsigned i = 1; i != NumConcat; ++i) - ConcatOps[i] = UndefVal; - return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT, &ConcatOps[0], - NumConcat); - } else - return LdOp; - } else { + if (!NewVT.isVector()) { unsigned NumElts = WidenWidth / NewVTWidth; EVT NewVecVT = EVT::getVectorVT(*DAG.getContext(), NewVT, NumElts); SDValue VecOp = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, NewVecVT, LdOp); return DAG.getNode(ISD::BIT_CONVERT, dl, WidenVT, VecOp); } + if (NewVT == WidenVT) + return LdOp; + + assert(WidenWidth % NewVTWidth == 0); + unsigned NumConcat = WidenWidth / NewVTWidth; + SmallVector ConcatOps(NumConcat); + SDValue UndefVal = DAG.getUNDEF(NewVT); + ConcatOps[0] = LdOp; + for (unsigned i = 1; i != NumConcat; ++i) + ConcatOps[i] = UndefVal; + return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT, &ConcatOps[0], + NumConcat); } // Load vector by using multiple loads from largest vector to scalar @@ -2276,52 +2297,55 @@ SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVector& LdChain, // Build the vector from the loads operations unsigned End = LdOps.size(); - if (LdOps[0].getValueType().isVector()) { - // If the load contains vectors, build the vector using concat vector. - // All of the vectors used to loads are power of 2 and the scalars load - // can be combined to make a power of 2 vector. - SmallVector ConcatOps(End); - int i = End - 1; - int Idx = End; - EVT LdTy = LdOps[i].getValueType(); - // First combine the scalar loads to a vector - if (!LdTy.isVector()) { - for (--i; i >= 0; --i) { - LdTy = LdOps[i].getValueType(); - if (LdTy.isVector()) - break; - } - ConcatOps[--Idx] = BuildVectorFromScalar(DAG, LdTy, LdOps, i+1, End); - } - ConcatOps[--Idx] = LdOps[i]; + if (!LdOps[0].getValueType().isVector()) + // All the loads are scalar loads. + return BuildVectorFromScalar(DAG, WidenVT, LdOps, 0, End); + + // If the load contains vectors, build the vector using concat vector. + // All of the vectors used to loads are power of 2 and the scalars load + // can be combined to make a power of 2 vector. + SmallVector ConcatOps(End); + int i = End - 1; + int Idx = End; + EVT LdTy = LdOps[i].getValueType(); + // First combine the scalar loads to a vector + if (!LdTy.isVector()) { for (--i; i >= 0; --i) { - EVT NewLdTy = LdOps[i].getValueType(); - if (NewLdTy != LdTy) { - // Create a larger vector - ConcatOps[End-1] = DAG.getNode(ISD::CONCAT_VECTORS, dl, NewLdTy, - &ConcatOps[Idx], End - Idx); - Idx = End - 1; - LdTy = NewLdTy; - } - ConcatOps[--Idx] = LdOps[i]; + LdTy = LdOps[i].getValueType(); + if (LdTy.isVector()) + break; } + ConcatOps[--Idx] = BuildVectorFromScalar(DAG, LdTy, LdOps, i+1, End); + } + ConcatOps[--Idx] = LdOps[i]; + for (--i; i >= 0; --i) { + EVT NewLdTy = LdOps[i].getValueType(); + if (NewLdTy != LdTy) { + // Create a larger vector + ConcatOps[End-1] = DAG.getNode(ISD::CONCAT_VECTORS, dl, NewLdTy, + &ConcatOps[Idx], End - Idx); + Idx = End - 1; + LdTy = NewLdTy; + } + ConcatOps[--Idx] = LdOps[i]; + } - if (WidenWidth != LdTy.getSizeInBits()*(End - Idx)) { - // We need to fill the rest with undefs to build the vector - unsigned NumOps = WidenWidth / LdTy.getSizeInBits(); - SmallVector WidenOps(NumOps); - SDValue UndefVal = DAG.getUNDEF(LdTy); - unsigned i = 0; - for (; i != End-Idx; ++i) - WidenOps[i] = ConcatOps[Idx+i]; - for (; i != NumOps; ++i) - WidenOps[i] = UndefVal; - return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT, &WidenOps[0],NumOps); - } else - return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT, - &ConcatOps[Idx], End - Idx); - } else // All the loads are scalar loads. - return BuildVectorFromScalar(DAG, WidenVT, LdOps, 0, End); + if (WidenWidth == LdTy.getSizeInBits()*(End - Idx)) + return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT, + &ConcatOps[Idx], End - Idx); + + // We need to fill the rest with undefs to build the vector + unsigned NumOps = WidenWidth / LdTy.getSizeInBits(); + SmallVector WidenOps(NumOps); + SDValue UndefVal = DAG.getUNDEF(LdTy); + { + unsigned i = 0; + for (; i != End-Idx; ++i) + WidenOps[i] = ConcatOps[Idx+i]; + for (; i != NumOps; ++i) + WidenOps[i] = UndefVal; + } + return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT, &WidenOps[0],NumOps); } SDValue diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp index 3b86c32..fae2729 100644 --- a/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp +++ b/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp @@ -13,6 +13,7 @@ #define DEBUG_TYPE "pre-RA-sched" #include "ScheduleDAGSDNodes.h" +#include "llvm/InlineAsm.h" #include "llvm/CodeGen/SchedulerRegistry.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/Target/TargetRegisterInfo.h" @@ -432,6 +433,30 @@ static EVT getPhysicalRegisterVT(SDNode *N, unsigned Reg, return N->getValueType(NumRes); } +/// CheckForLiveRegDef - Return true and update live register vector if the +/// specified register def of the specified SUnit clobbers any "live" registers. +static bool CheckForLiveRegDef(SUnit *SU, unsigned Reg, + std::vector &LiveRegDefs, + SmallSet &RegAdded, + SmallVector &LRegs, + const TargetRegisterInfo *TRI) { + bool Added = false; + if (LiveRegDefs[Reg] && LiveRegDefs[Reg] != SU) { + if (RegAdded.insert(Reg)) { + LRegs.push_back(Reg); + Added = true; + } + } + for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) + if (LiveRegDefs[*Alias] && LiveRegDefs[*Alias] != SU) { + if (RegAdded.insert(*Alias)) { + LRegs.push_back(*Alias); + Added = true; + } + } + return Added; +} + /// DelayForLiveRegsBottomUp - Returns true if it is necessary to delay /// scheduling of the given node to satisfy live physical register dependencies. /// If the specific node is the last one that's available to schedule, do @@ -446,37 +471,44 @@ bool ScheduleDAGFast::DelayForLiveRegsBottomUp(SUnit *SU, for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); I != E; ++I) { if (I->isAssignedRegDep()) { - unsigned Reg = I->getReg(); - if (LiveRegDefs[Reg] && LiveRegDefs[Reg] != I->getSUnit()) { - if (RegAdded.insert(Reg)) - LRegs.push_back(Reg); - } - for (const unsigned *Alias = TRI->getAliasSet(Reg); - *Alias; ++Alias) - if (LiveRegDefs[*Alias] && LiveRegDefs[*Alias] != I->getSUnit()) { - if (RegAdded.insert(*Alias)) - LRegs.push_back(*Alias); - } + CheckForLiveRegDef(I->getSUnit(), I->getReg(), LiveRegDefs, + RegAdded, LRegs, TRI); } } for (SDNode *Node = SU->getNode(); Node; Node = Node->getFlaggedNode()) { + if (Node->getOpcode() == ISD::INLINEASM) { + // Inline asm can clobber physical defs. + unsigned NumOps = Node->getNumOperands(); + if (Node->getOperand(NumOps-1).getValueType() == MVT::Flag) + --NumOps; // Ignore the flag operand. + + for (unsigned i = InlineAsm::Op_FirstOperand; i != NumOps;) { + unsigned Flags = + cast(Node->getOperand(i))->getZExtValue(); + unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags); + + ++i; // Skip the ID value. + if (InlineAsm::isRegDefKind(Flags) || + InlineAsm::isRegDefEarlyClobberKind(Flags)) { + // Check for def of register or earlyclobber register. + for (; NumVals; --NumVals, ++i) { + unsigned Reg = cast(Node->getOperand(i))->getReg(); + if (TargetRegisterInfo::isPhysicalRegister(Reg)) + CheckForLiveRegDef(SU, Reg, LiveRegDefs, RegAdded, LRegs, TRI); + } + } else + i += NumVals; + } + continue; + } if (!Node->isMachineOpcode()) continue; const TargetInstrDesc &TID = TII->get(Node->getMachineOpcode()); if (!TID.ImplicitDefs) continue; for (const unsigned *Reg = TID.ImplicitDefs; *Reg; ++Reg) { - if (LiveRegDefs[*Reg] && LiveRegDefs[*Reg] != SU) { - if (RegAdded.insert(*Reg)) - LRegs.push_back(*Reg); - } - for (const unsigned *Alias = TRI->getAliasSet(*Reg); - *Alias; ++Alias) - if (LiveRegDefs[*Alias] && LiveRegDefs[*Alias] != SU) { - if (RegAdded.insert(*Alias)) - LRegs.push_back(*Alias); - } + CheckForLiveRegDef(SU, *Reg, LiveRegDefs, RegAdded, LRegs, TRI); } } return !LRegs.empty(); diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp index 3ef521c..4c3e4e3 100644 --- a/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp +++ b/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp @@ -24,6 +24,7 @@ #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetLowering.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/STLExtras.h" @@ -54,10 +55,16 @@ static RegisterScheduler static RegisterScheduler hybridListDAGScheduler("list-hybrid", - "Bottom-up rr list scheduling which avoid stalls for " - "long latency instructions", + "Bottom-up register pressure aware list scheduling " + "which tries to balance latency and register pressure", createHybridListDAGScheduler); +static RegisterScheduler + ILPListDAGScheduler("list-ilp", + "Bottom-up register pressure aware list scheduling " + "which tries to balance ILP and register pressure", + createILPListDAGScheduler); + namespace { //===----------------------------------------------------------------------===// /// ScheduleDAGRRList - The actual register reduction list scheduler @@ -181,7 +188,9 @@ private: /// Schedule - Schedule the DAG using list scheduling. void ScheduleDAGRRList::Schedule() { - DEBUG(dbgs() << "********** List Scheduling **********\n"); + DEBUG(dbgs() + << "********** List Scheduling BB#" << BB->getNumber() + << " **********\n"); NumLiveRegs = 0; LiveRegDefs.resize(TRI->getNumRegs(), NULL); @@ -273,6 +282,8 @@ void ScheduleDAGRRList::ScheduleNodeBottomUp(SUnit *SU, unsigned CurCycle) { SU->setHeightToAtLeast(CurCycle); Sequence.push_back(SU); + AvailableQueue->ScheduledNode(SU); + ReleasePredecessors(SU, CurCycle); // Release all the implicit physical register defs that are live. @@ -291,7 +302,6 @@ void ScheduleDAGRRList::ScheduleNodeBottomUp(SUnit *SU, unsigned CurCycle) { } SU->isScheduled = true; - AvailableQueue->ScheduledNode(SU); } /// CapturePred - This does the opposite of ReleasePred. Since SU is being @@ -315,8 +325,6 @@ void ScheduleDAGRRList::UnscheduleNodeBottomUp(SUnit *SU) { DEBUG(dbgs() << "*** Unscheduling [" << SU->getHeight() << "]: "); DEBUG(SU->dump(this)); - AvailableQueue->UnscheduledNode(SU); - for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); I != E; ++I) { CapturePred(&*I); @@ -346,6 +354,7 @@ void ScheduleDAGRRList::UnscheduleNodeBottomUp(SUnit *SU) { SU->isScheduled = false; SU->isAvailable = true; AvailableQueue->push(SU); + AvailableQueue->UnscheduledNode(SU); } /// BacktrackBottomUp - Backtrack scheduling to a previous cycle specified in @@ -956,7 +965,8 @@ namespace { template class RegReductionPriorityQueue; - /// Sorting functions for the Available queue. + /// bu_ls_rr_sort - Priority function for bottom up register pressure + // reduction scheduler. struct bu_ls_rr_sort : public std::binary_function { RegReductionPriorityQueue *SPQ; bu_ls_rr_sort(RegReductionPriorityQueue *spq) : SPQ(spq) {} @@ -965,6 +975,8 @@ namespace { bool operator()(const SUnit* left, const SUnit* right) const; }; + // td_ls_rr_sort - Priority function for top down register pressure reduction + // scheduler. struct td_ls_rr_sort : public std::binary_function { RegReductionPriorityQueue *SPQ; td_ls_rr_sort(RegReductionPriorityQueue *spq) : SPQ(spq) {} @@ -973,6 +985,7 @@ namespace { bool operator()(const SUnit* left, const SUnit* right) const; }; + // src_ls_rr_sort - Priority function for source order scheduler. struct src_ls_rr_sort : public std::binary_function { RegReductionPriorityQueue *SPQ; src_ls_rr_sort(RegReductionPriorityQueue *spq) @@ -983,13 +996,26 @@ namespace { bool operator()(const SUnit* left, const SUnit* right) const; }; + // hybrid_ls_rr_sort - Priority function for hybrid scheduler. struct hybrid_ls_rr_sort : public std::binary_function { RegReductionPriorityQueue *SPQ; hybrid_ls_rr_sort(RegReductionPriorityQueue *spq) : SPQ(spq) {} hybrid_ls_rr_sort(const hybrid_ls_rr_sort &RHS) : SPQ(RHS.SPQ) {} - + + bool operator()(const SUnit* left, const SUnit* right) const; + }; + + // ilp_ls_rr_sort - Priority function for ILP (instruction level parallelism) + // scheduler. + struct ilp_ls_rr_sort : public std::binary_function { + RegReductionPriorityQueue *SPQ; + ilp_ls_rr_sort(RegReductionPriorityQueue *spq) + : SPQ(spq) {} + ilp_ls_rr_sort(const ilp_ls_rr_sort &RHS) + : SPQ(RHS.SPQ) {} + bool operator()(const SUnit* left, const SUnit* right) const; }; } // end anonymous namespace @@ -1029,23 +1055,48 @@ namespace { std::vector Queue; SF Picker; unsigned CurQueueId; + bool TracksRegPressure; protected: // SUnits - The SUnits for the current graph. std::vector *SUnits; - + + MachineFunction &MF; const TargetInstrInfo *TII; const TargetRegisterInfo *TRI; + const TargetLowering *TLI; ScheduleDAGRRList *scheduleDAG; // SethiUllmanNumbers - The SethiUllman number for each node. std::vector SethiUllmanNumbers; + /// RegPressure - Tracking current reg pressure per register class. + /// + std::vector RegPressure; + + /// RegLimit - Tracking the number of allocatable registers per register + /// class. + std::vector RegLimit; + public: - RegReductionPriorityQueue(const TargetInstrInfo *tii, - const TargetRegisterInfo *tri) - : Picker(this), CurQueueId(0), - TII(tii), TRI(tri), scheduleDAG(NULL) {} + RegReductionPriorityQueue(MachineFunction &mf, + bool tracksrp, + const TargetInstrInfo *tii, + const TargetRegisterInfo *tri, + const TargetLowering *tli) + : Picker(this), CurQueueId(0), TracksRegPressure(tracksrp), + MF(mf), TII(tii), TRI(tri), TLI(tli), scheduleDAG(NULL) { + if (TracksRegPressure) { + unsigned NumRC = TRI->getNumRegClasses(); + RegLimit.resize(NumRC); + RegPressure.resize(NumRC); + std::fill(RegLimit.begin(), RegLimit.end(), 0); + std::fill(RegPressure.begin(), RegPressure.end(), 0); + for (TargetRegisterInfo::regclass_iterator I = TRI->regclass_begin(), + E = TRI->regclass_end(); I != E; ++I) + RegLimit[(*I)->getID()] = tli->getRegPressureLimit(*I, MF); + } + } void initNodes(std::vector &sunits) { SUnits = &sunits; @@ -1072,6 +1123,7 @@ namespace { void releaseState() { SUnits = 0; SethiUllmanNumbers.clear(); + std::fill(RegPressure.begin(), RegPressure.end(), 0); } unsigned getNodePriority(const SUnit *SU) const { @@ -1139,10 +1191,244 @@ namespace { SU->NodeQueueId = 0; } + bool HighRegPressure(const SUnit *SU) const { + if (!TLI) + return false; + + for (SUnit::const_pred_iterator I = SU->Preds.begin(),E = SU->Preds.end(); + I != E; ++I) { + if (I->isCtrl()) + continue; + SUnit *PredSU = I->getSUnit(); + const SDNode *PN = PredSU->getNode(); + if (!PN->isMachineOpcode()) { + if (PN->getOpcode() == ISD::CopyFromReg) { + EVT VT = PN->getValueType(0); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + unsigned Cost = TLI->getRepRegClassCostFor(VT); + if ((RegPressure[RCId] + Cost) >= RegLimit[RCId]) + return true; + } + continue; + } + unsigned POpc = PN->getMachineOpcode(); + if (POpc == TargetOpcode::IMPLICIT_DEF) + continue; + if (POpc == TargetOpcode::EXTRACT_SUBREG) { + EVT VT = PN->getOperand(0).getValueType(); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + unsigned Cost = TLI->getRepRegClassCostFor(VT); + // Check if this increases register pressure of the specific register + // class to the point where it would cause spills. + if ((RegPressure[RCId] + Cost) >= RegLimit[RCId]) + return true; + continue; + } else if (POpc == TargetOpcode::INSERT_SUBREG || + POpc == TargetOpcode::SUBREG_TO_REG) { + EVT VT = PN->getValueType(0); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + unsigned Cost = TLI->getRepRegClassCostFor(VT); + // Check if this increases register pressure of the specific register + // class to the point where it would cause spills. + if ((RegPressure[RCId] + Cost) >= RegLimit[RCId]) + return true; + continue; + } + unsigned NumDefs = TII->get(PN->getMachineOpcode()).getNumDefs(); + for (unsigned i = 0; i != NumDefs; ++i) { + EVT VT = PN->getValueType(i); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + if (RegPressure[RCId] >= RegLimit[RCId]) + return true; // Reg pressure already high. + unsigned Cost = TLI->getRepRegClassCostFor(VT); + if (!PN->hasAnyUseOfValue(i)) + continue; + // Check if this increases register pressure of the specific register + // class to the point where it would cause spills. + if ((RegPressure[RCId] + Cost) >= RegLimit[RCId]) + return true; + } + } + + return false; + } + + void ScheduledNode(SUnit *SU) { + if (!TracksRegPressure) + return; + + const SDNode *N = SU->getNode(); + if (!N->isMachineOpcode()) { + if (N->getOpcode() != ISD::CopyToReg) + return; + } else { + unsigned Opc = N->getMachineOpcode(); + if (Opc == TargetOpcode::EXTRACT_SUBREG || + Opc == TargetOpcode::INSERT_SUBREG || + Opc == TargetOpcode::SUBREG_TO_REG || + Opc == TargetOpcode::REG_SEQUENCE || + Opc == TargetOpcode::IMPLICIT_DEF) + return; + } + + for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); + I != E; ++I) { + if (I->isCtrl()) + continue; + SUnit *PredSU = I->getSUnit(); + if (PredSU->NumSuccsLeft != PredSU->NumSuccs) + continue; + const SDNode *PN = PredSU->getNode(); + if (!PN->isMachineOpcode()) { + if (PN->getOpcode() == ISD::CopyFromReg) { + EVT VT = PN->getValueType(0); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + } + continue; + } + unsigned POpc = PN->getMachineOpcode(); + if (POpc == TargetOpcode::IMPLICIT_DEF) + continue; + if (POpc == TargetOpcode::EXTRACT_SUBREG) { + EVT VT = PN->getOperand(0).getValueType(); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + continue; + } else if (POpc == TargetOpcode::INSERT_SUBREG || + POpc == TargetOpcode::SUBREG_TO_REG) { + EVT VT = PN->getValueType(0); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + continue; + } + unsigned NumDefs = TII->get(PN->getMachineOpcode()).getNumDefs(); + for (unsigned i = 0; i != NumDefs; ++i) { + EVT VT = PN->getValueType(i); + if (!PN->hasAnyUseOfValue(i)) + continue; + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + } + } + + // Check for isMachineOpcode() as PrescheduleNodesWithMultipleUses() + // may transfer data dependencies to CopyToReg. + if (SU->NumSuccs && N->isMachineOpcode()) { + unsigned NumDefs = TII->get(N->getMachineOpcode()).getNumDefs(); + for (unsigned i = 0; i != NumDefs; ++i) { + EVT VT = N->getValueType(i); + if (!N->hasAnyUseOfValue(i)) + continue; + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + if (RegPressure[RCId] < TLI->getRepRegClassCostFor(VT)) + // Register pressure tracking is imprecise. This can happen. + RegPressure[RCId] = 0; + else + RegPressure[RCId] -= TLI->getRepRegClassCostFor(VT); + } + } + + dumpRegPressure(); + } + + void UnscheduledNode(SUnit *SU) { + if (!TracksRegPressure) + return; + + const SDNode *N = SU->getNode(); + if (!N->isMachineOpcode()) { + if (N->getOpcode() != ISD::CopyToReg) + return; + } else { + unsigned Opc = N->getMachineOpcode(); + if (Opc == TargetOpcode::EXTRACT_SUBREG || + Opc == TargetOpcode::INSERT_SUBREG || + Opc == TargetOpcode::SUBREG_TO_REG || + Opc == TargetOpcode::REG_SEQUENCE || + Opc == TargetOpcode::IMPLICIT_DEF) + return; + } + + for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); + I != E; ++I) { + if (I->isCtrl()) + continue; + SUnit *PredSU = I->getSUnit(); + if (PredSU->NumSuccsLeft != PredSU->NumSuccs) + continue; + const SDNode *PN = PredSU->getNode(); + if (!PN->isMachineOpcode()) { + if (PN->getOpcode() == ISD::CopyFromReg) { + EVT VT = PN->getValueType(0); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + } + continue; + } + unsigned POpc = PN->getMachineOpcode(); + if (POpc == TargetOpcode::IMPLICIT_DEF) + continue; + if (POpc == TargetOpcode::EXTRACT_SUBREG) { + EVT VT = PN->getOperand(0).getValueType(); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + continue; + } else if (POpc == TargetOpcode::INSERT_SUBREG || + POpc == TargetOpcode::SUBREG_TO_REG) { + EVT VT = PN->getValueType(0); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + continue; + } + unsigned NumDefs = TII->get(PN->getMachineOpcode()).getNumDefs(); + for (unsigned i = 0; i != NumDefs; ++i) { + EVT VT = PN->getValueType(i); + if (!PN->hasAnyUseOfValue(i)) + continue; + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + if (RegPressure[RCId] < TLI->getRepRegClassCostFor(VT)) + // Register pressure tracking is imprecise. This can happen. + RegPressure[RCId] = 0; + else + RegPressure[RCId] -= TLI->getRepRegClassCostFor(VT); + } + } + + // Check for isMachineOpcode() as PrescheduleNodesWithMultipleUses() + // may transfer data dependencies to CopyToReg. + if (SU->NumSuccs && N->isMachineOpcode()) { + unsigned NumDefs = TII->get(N->getMachineOpcode()).getNumDefs(); + for (unsigned i = NumDefs, e = N->getNumValues(); i != e; ++i) { + EVT VT = N->getValueType(i); + if (VT == MVT::Flag || VT == MVT::Other) + continue; + if (!N->hasAnyUseOfValue(i)) + continue; + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + } + } + + dumpRegPressure(); + } + void setScheduleDAG(ScheduleDAGRRList *scheduleDag) { scheduleDAG = scheduleDag; } + void dumpRegPressure() const { + for (TargetRegisterInfo::regclass_iterator I = TRI->regclass_begin(), + E = TRI->regclass_end(); I != E; ++I) { + const TargetRegisterClass *RC = *I; + unsigned Id = RC->getID(); + unsigned RP = RegPressure[Id]; + if (!RP) continue; + DEBUG(dbgs() << RC->getName() << ": " << RP << " / " << RegLimit[Id] + << '\n'); + } + } + protected: bool canClobber(const SUnit *SU, const SUnit *Op); void AddPseudoTwoAddrDeps(); @@ -1161,6 +1447,9 @@ namespace { typedef RegReductionPriorityQueue HybridBURRPriorityQueue; + + typedef RegReductionPriorityQueue + ILPBURRPriorityQueue; } /// closestSucc - Returns the scheduled cycle of the successor which is @@ -1260,30 +1549,63 @@ bool src_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const { } bool hybrid_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const{ - bool LStall = left->SchedulingPref == Sched::Latency && - SPQ->getCurCycle() < left->getHeight(); - bool RStall = right->SchedulingPref == Sched::Latency && - SPQ->getCurCycle() < right->getHeight(); - // If scheduling one of the node will cause a pipeline stall, delay it. - // If scheduling either one of the node will cause a pipeline stall, sort them - // according to their height. - // If neither will cause a pipeline stall, try to reduce register pressure. - if (LStall) { - if (!RStall) - return true; - if (left->getHeight() != right->getHeight()) - return left->getHeight() > right->getHeight(); - } else if (RStall) + bool LHigh = SPQ->HighRegPressure(left); + bool RHigh = SPQ->HighRegPressure(right); + // Avoid causing spills. If register pressure is high, schedule for + // register pressure reduction. + if (LHigh && !RHigh) + return true; + else if (!LHigh && RHigh) + return false; + else if (!LHigh && !RHigh) { + // Low register pressure situation, schedule for latency if possible. + bool LStall = left->SchedulingPref == Sched::Latency && + SPQ->getCurCycle() < left->getHeight(); + bool RStall = right->SchedulingPref == Sched::Latency && + SPQ->getCurCycle() < right->getHeight(); + // If scheduling one of the node will cause a pipeline stall, delay it. + // If scheduling either one of the node will cause a pipeline stall, sort + // them according to their height. + // If neither will cause a pipeline stall, try to reduce register pressure. + if (LStall) { + if (!RStall) + return true; + if (left->getHeight() != right->getHeight()) + return left->getHeight() > right->getHeight(); + } else if (RStall) return false; - // If either node is scheduling for latency, sort them by height and latency - // first. - if (left->SchedulingPref == Sched::Latency || - right->SchedulingPref == Sched::Latency) { - if (left->getHeight() != right->getHeight()) - return left->getHeight() > right->getHeight(); - if (left->Latency != right->Latency) - return left->Latency > right->Latency; + // If either node is scheduling for latency, sort them by height and latency + // first. + if (left->SchedulingPref == Sched::Latency || + right->SchedulingPref == Sched::Latency) { + if (left->getHeight() != right->getHeight()) + return left->getHeight() > right->getHeight(); + if (left->Latency != right->Latency) + return left->Latency > right->Latency; + } + } + + return BURRSort(left, right, SPQ); +} + +bool ilp_ls_rr_sort::operator()(const SUnit *left, + const SUnit *right) const { + bool LHigh = SPQ->HighRegPressure(left); + bool RHigh = SPQ->HighRegPressure(right); + // Avoid causing spills. If register pressure is high, schedule for + // register pressure reduction. + if (LHigh && !RHigh) + return true; + else if (!LHigh && RHigh) + return false; + else if (!LHigh && !RHigh) { + // Low register pressure situation, schedule to maximize instruction level + // parallelism. + if (left->NumPreds > right->NumPreds) + return false; + else if (left->NumPreds < right->NumPreds) + return false; } return BURRSort(left, right, SPQ); @@ -1635,8 +1957,8 @@ llvm::createBURRListDAGScheduler(SelectionDAGISel *IS, CodeGenOpt::Level) { const TargetInstrInfo *TII = TM.getInstrInfo(); const TargetRegisterInfo *TRI = TM.getRegisterInfo(); - BURegReductionPriorityQueue *PQ = new BURegReductionPriorityQueue(TII, TRI); - + BURegReductionPriorityQueue *PQ = + new BURegReductionPriorityQueue(*IS->MF, false, TII, TRI, 0); ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, true, false, PQ); PQ->setScheduleDAG(SD); return SD; @@ -1648,8 +1970,8 @@ llvm::createTDRRListDAGScheduler(SelectionDAGISel *IS, CodeGenOpt::Level) { const TargetInstrInfo *TII = TM.getInstrInfo(); const TargetRegisterInfo *TRI = TM.getRegisterInfo(); - TDRegReductionPriorityQueue *PQ = new TDRegReductionPriorityQueue(TII, TRI); - + TDRegReductionPriorityQueue *PQ = + new TDRegReductionPriorityQueue(*IS->MF, false, TII, TRI, 0); ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, false, false, PQ); PQ->setScheduleDAG(SD); return SD; @@ -1661,8 +1983,8 @@ llvm::createSourceListDAGScheduler(SelectionDAGISel *IS, CodeGenOpt::Level) { const TargetInstrInfo *TII = TM.getInstrInfo(); const TargetRegisterInfo *TRI = TM.getRegisterInfo(); - SrcRegReductionPriorityQueue *PQ = new SrcRegReductionPriorityQueue(TII, TRI); - + SrcRegReductionPriorityQueue *PQ = + new SrcRegReductionPriorityQueue(*IS->MF, false, TII, TRI, 0); ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, true, false, PQ); PQ->setScheduleDAG(SD); return SD; @@ -1673,9 +1995,24 @@ llvm::createHybridListDAGScheduler(SelectionDAGISel *IS, CodeGenOpt::Level) { const TargetMachine &TM = IS->TM; const TargetInstrInfo *TII = TM.getInstrInfo(); const TargetRegisterInfo *TRI = TM.getRegisterInfo(); + const TargetLowering *TLI = &IS->getTargetLowering(); - HybridBURRPriorityQueue *PQ = new HybridBURRPriorityQueue(TII, TRI); + HybridBURRPriorityQueue *PQ = + new HybridBURRPriorityQueue(*IS->MF, true, TII, TRI, TLI); + ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, true, true, PQ); + PQ->setScheduleDAG(SD); + return SD; +} +llvm::ScheduleDAGSDNodes * +llvm::createILPListDAGScheduler(SelectionDAGISel *IS, CodeGenOpt::Level) { + const TargetMachine &TM = IS->TM; + const TargetInstrInfo *TII = TM.getInstrInfo(); + const TargetRegisterInfo *TRI = TM.getRegisterInfo(); + const TargetLowering *TLI = &IS->getTargetLowering(); + + ILPBURRPriorityQueue *PQ = + new ILPBURRPriorityQueue(*IS->MF, true, TII, TRI, TLI); ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, true, true, PQ); PQ->setScheduleDAG(SD); return SD; diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp index 06cf053..f1bf82a 100644 --- a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp +++ b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp @@ -59,8 +59,9 @@ SUnit *ScheduleDAGSDNodes::NewSUnit(SDNode *N) { SUnits.back().OrigNode = &SUnits.back(); SUnit *SU = &SUnits.back(); const TargetLowering &TLI = DAG->getTargetLoweringInfo(); - if (N->isMachineOpcode() && - N->getMachineOpcode() == TargetOpcode::IMPLICIT_DEF) + if (!N || + (N->isMachineOpcode() && + N->getMachineOpcode() == TargetOpcode::IMPLICIT_DEF)) SU->SchedulingPref = Sched::None; else SU->SchedulingPref = TLI.getSchedulingPreference(N); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index e83a034..ad06ebd 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -2236,7 +2236,7 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, unsigned Depth) const{ bool SelectionDAG::isKnownNeverNaN(SDValue Op) const { // If we're told that NaNs won't happen, assume they won't. - if (FiniteOnlyFPMath()) + if (NoNaNsFPMath) return true; // If the value is a constant, we can obviously see if it is a NaN or not. @@ -2281,35 +2281,6 @@ bool SelectionDAG::isVerifiedDebugInfoDesc(SDValue Op) const { } -/// getShuffleScalarElt - Returns the scalar element that will make up the ith -/// element of the result of the vector shuffle. -SDValue SelectionDAG::getShuffleScalarElt(const ShuffleVectorSDNode *N, - unsigned i) { - EVT VT = N->getValueType(0); - if (N->getMaskElt(i) < 0) - return getUNDEF(VT.getVectorElementType()); - unsigned Index = N->getMaskElt(i); - unsigned NumElems = VT.getVectorNumElements(); - SDValue V = (Index < NumElems) ? N->getOperand(0) : N->getOperand(1); - Index %= NumElems; - - if (V.getOpcode() == ISD::BIT_CONVERT) { - V = V.getOperand(0); - EVT VVT = V.getValueType(); - if (!VVT.isVector() || VVT.getVectorNumElements() != (unsigned)NumElems) - return SDValue(); - } - if (V.getOpcode() == ISD::SCALAR_TO_VECTOR) - return (Index == 0) ? V.getOperand(0) - : getUNDEF(VT.getVectorElementType()); - if (V.getOpcode() == ISD::BUILD_VECTOR) - return V.getOperand(Index); - if (const ShuffleVectorSDNode *SVN = dyn_cast(V)) - return getShuffleScalarElt(SVN, Index); - return SDValue(); -} - - /// getNode - Gets or creates the specified node. /// SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT) { @@ -2624,7 +2595,8 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT, // one big BUILD_VECTOR. if (N1.getOpcode() == ISD::BUILD_VECTOR && N2.getOpcode() == ISD::BUILD_VECTOR) { - SmallVector Elts(N1.getNode()->op_begin(), N1.getNode()->op_end()); + SmallVector Elts(N1.getNode()->op_begin(), + N1.getNode()->op_end()); Elts.append(N2.getNode()->op_begin(), N2.getNode()->op_end()); return getNode(ISD::BUILD_VECTOR, DL, VT, &Elts[0], Elts.size()); } @@ -3021,7 +2993,8 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT, if (N1.getOpcode() == ISD::BUILD_VECTOR && N2.getOpcode() == ISD::BUILD_VECTOR && N3.getOpcode() == ISD::BUILD_VECTOR) { - SmallVector Elts(N1.getNode()->op_begin(), N1.getNode()->op_end()); + SmallVector Elts(N1.getNode()->op_begin(), + N1.getNode()->op_end()); Elts.append(N2.getNode()->op_begin(), N2.getNode()->op_end()); Elts.append(N3.getNode()->op_begin(), N3.getNode()->op_end()); return getNode(ISD::BUILD_VECTOR, DL, VT, &Elts[0], Elts.size()); @@ -5872,6 +5845,7 @@ std::string ISD::ArgFlagsTy::getArgFlagsString() { void SDNode::dump() const { dump(0); } void SDNode::dump(const SelectionDAG *G) const { print(dbgs(), G); + dbgs() << '\n'; } void SDNode::print_types(raw_ostream &OS, const SelectionDAG *G) const { @@ -5895,7 +5869,7 @@ void SDNode::print_details(raw_ostream &OS, const SelectionDAG *G) const { for (MachineSDNode::mmo_iterator i = MN->memoperands_begin(), e = MN->memoperands_end(); i != e; ++i) { OS << **i; - if (next(i) != e) + if (llvm::next(i) != e) OS << " "; } OS << ">"; diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 458e865..e657445 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -70,22 +70,29 @@ LimitFPPrecision("limit-float-precision", cl::location(LimitFloatPrecision), cl::init(0)); +static SDValue getCopyFromPartsVector(SelectionDAG &DAG, DebugLoc DL, + const SDValue *Parts, unsigned NumParts, + EVT PartVT, EVT ValueVT); + /// getCopyFromParts - Create a value that contains the specified legal parts /// combined into the value they represent. If the parts combine to a type /// larger then ValueVT then AssertOp can be used to specify whether the extra /// bits are known to be zero (ISD::AssertZext) or sign extended from ValueVT /// (ISD::AssertSext). -static SDValue getCopyFromParts(SelectionDAG &DAG, DebugLoc dl, +static SDValue getCopyFromParts(SelectionDAG &DAG, DebugLoc DL, const SDValue *Parts, unsigned NumParts, EVT PartVT, EVT ValueVT, ISD::NodeType AssertOp = ISD::DELETED_NODE) { + if (ValueVT.isVector()) + return getCopyFromPartsVector(DAG, DL, Parts, NumParts, PartVT, ValueVT); + assert(NumParts > 0 && "No parts to assemble!"); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); SDValue Val = Parts[0]; if (NumParts > 1) { // Assemble the value from multiple parts. - if (!ValueVT.isVector() && ValueVT.isInteger()) { + if (ValueVT.isInteger()) { unsigned PartBits = PartVT.getSizeInBits(); unsigned ValueBits = ValueVT.getSizeInBits(); @@ -100,25 +107,25 @@ static SDValue getCopyFromParts(SelectionDAG &DAG, DebugLoc dl, EVT HalfVT = EVT::getIntegerVT(*DAG.getContext(), RoundBits/2); if (RoundParts > 2) { - Lo = getCopyFromParts(DAG, dl, Parts, RoundParts / 2, + Lo = getCopyFromParts(DAG, DL, Parts, RoundParts / 2, PartVT, HalfVT); - Hi = getCopyFromParts(DAG, dl, Parts + RoundParts / 2, + Hi = getCopyFromParts(DAG, DL, Parts + RoundParts / 2, RoundParts / 2, PartVT, HalfVT); } else { - Lo = DAG.getNode(ISD::BIT_CONVERT, dl, HalfVT, Parts[0]); - Hi = DAG.getNode(ISD::BIT_CONVERT, dl, HalfVT, Parts[1]); + Lo = DAG.getNode(ISD::BIT_CONVERT, DL, HalfVT, Parts[0]); + Hi = DAG.getNode(ISD::BIT_CONVERT, DL, HalfVT, Parts[1]); } if (TLI.isBigEndian()) std::swap(Lo, Hi); - Val = DAG.getNode(ISD::BUILD_PAIR, dl, RoundVT, Lo, Hi); + Val = DAG.getNode(ISD::BUILD_PAIR, DL, RoundVT, Lo, Hi); if (RoundParts < NumParts) { // Assemble the trailing non-power-of-2 part. unsigned OddParts = NumParts - RoundParts; EVT OddVT = EVT::getIntegerVT(*DAG.getContext(), OddParts * PartBits); - Hi = getCopyFromParts(DAG, dl, + Hi = getCopyFromParts(DAG, DL, Parts + RoundParts, OddParts, PartVT, OddVT); // Combine the round and odd parts. @@ -126,68 +133,29 @@ static SDValue getCopyFromParts(SelectionDAG &DAG, DebugLoc dl, if (TLI.isBigEndian()) std::swap(Lo, Hi); EVT TotalVT = EVT::getIntegerVT(*DAG.getContext(), NumParts * PartBits); - Hi = DAG.getNode(ISD::ANY_EXTEND, dl, TotalVT, Hi); - Hi = DAG.getNode(ISD::SHL, dl, TotalVT, Hi, + Hi = DAG.getNode(ISD::ANY_EXTEND, DL, TotalVT, Hi); + Hi = DAG.getNode(ISD::SHL, DL, TotalVT, Hi, DAG.getConstant(Lo.getValueType().getSizeInBits(), TLI.getPointerTy())); - Lo = DAG.getNode(ISD::ZERO_EXTEND, dl, TotalVT, Lo); - Val = DAG.getNode(ISD::OR, dl, TotalVT, Lo, Hi); - } - } else if (ValueVT.isVector()) { - // Handle a multi-element vector. - EVT IntermediateVT, RegisterVT; - unsigned NumIntermediates; - unsigned NumRegs = - TLI.getVectorTypeBreakdown(*DAG.getContext(), ValueVT, IntermediateVT, - NumIntermediates, RegisterVT); - assert(NumRegs == NumParts - && "Part count doesn't match vector breakdown!"); - NumParts = NumRegs; // Silence a compiler warning. - assert(RegisterVT == PartVT - && "Part type doesn't match vector breakdown!"); - assert(RegisterVT == Parts[0].getValueType() && - "Part type doesn't match part!"); - - // Assemble the parts into intermediate operands. - SmallVector Ops(NumIntermediates); - if (NumIntermediates == NumParts) { - // If the register was not expanded, truncate or copy the value, - // as appropriate. - for (unsigned i = 0; i != NumParts; ++i) - Ops[i] = getCopyFromParts(DAG, dl, &Parts[i], 1, - PartVT, IntermediateVT); - } else if (NumParts > 0) { - // If the intermediate type was expanded, build the intermediate - // operands from the parts. - assert(NumParts % NumIntermediates == 0 && - "Must expand into a divisible number of parts!"); - unsigned Factor = NumParts / NumIntermediates; - for (unsigned i = 0; i != NumIntermediates; ++i) - Ops[i] = getCopyFromParts(DAG, dl, &Parts[i * Factor], Factor, - PartVT, IntermediateVT); + Lo = DAG.getNode(ISD::ZERO_EXTEND, DL, TotalVT, Lo); + Val = DAG.getNode(ISD::OR, DL, TotalVT, Lo, Hi); } - - // Build a vector with BUILD_VECTOR or CONCAT_VECTORS from the - // intermediate operands. - Val = DAG.getNode(IntermediateVT.isVector() ? - ISD::CONCAT_VECTORS : ISD::BUILD_VECTOR, dl, - ValueVT, &Ops[0], NumIntermediates); } else if (PartVT.isFloatingPoint()) { // FP split into multiple FP parts (for ppcf128) assert(ValueVT == EVT(MVT::ppcf128) && PartVT == EVT(MVT::f64) && "Unexpected split"); SDValue Lo, Hi; - Lo = DAG.getNode(ISD::BIT_CONVERT, dl, EVT(MVT::f64), Parts[0]); - Hi = DAG.getNode(ISD::BIT_CONVERT, dl, EVT(MVT::f64), Parts[1]); + Lo = DAG.getNode(ISD::BIT_CONVERT, DL, EVT(MVT::f64), Parts[0]); + Hi = DAG.getNode(ISD::BIT_CONVERT, DL, EVT(MVT::f64), Parts[1]); if (TLI.isBigEndian()) std::swap(Lo, Hi); - Val = DAG.getNode(ISD::BUILD_PAIR, dl, ValueVT, Lo, Hi); + Val = DAG.getNode(ISD::BUILD_PAIR, DL, ValueVT, Lo, Hi); } else { // FP split into integer parts (soft fp) assert(ValueVT.isFloatingPoint() && PartVT.isInteger() && !PartVT.isVector() && "Unexpected split"); EVT IntVT = EVT::getIntegerVT(*DAG.getContext(), ValueVT.getSizeInBits()); - Val = getCopyFromParts(DAG, dl, Parts, NumParts, PartVT, IntVT); + Val = getCopyFromParts(DAG, DL, Parts, NumParts, PartVT, IntVT); } } @@ -197,219 +165,315 @@ static SDValue getCopyFromParts(SelectionDAG &DAG, DebugLoc dl, if (PartVT == ValueVT) return Val; - if (PartVT.isVector()) { - assert(ValueVT.isVector() && "Unknown vector conversion!"); - return DAG.getNode(ISD::BIT_CONVERT, dl, ValueVT, Val); - } - - if (ValueVT.isVector()) { - assert(ValueVT.getVectorElementType() == PartVT && - ValueVT.getVectorNumElements() == 1 && - "Only trivial scalar-to-vector conversions should get here!"); - return DAG.getNode(ISD::BUILD_VECTOR, dl, ValueVT, Val); - } - - if (PartVT.isInteger() && - ValueVT.isInteger()) { + if (PartVT.isInteger() && ValueVT.isInteger()) { if (ValueVT.bitsLT(PartVT)) { // For a truncate, see if we have any information to // indicate whether the truncated bits will always be // zero or sign-extension. if (AssertOp != ISD::DELETED_NODE) - Val = DAG.getNode(AssertOp, dl, PartVT, Val, + Val = DAG.getNode(AssertOp, DL, PartVT, Val, DAG.getValueType(ValueVT)); - return DAG.getNode(ISD::TRUNCATE, dl, ValueVT, Val); - } else { - return DAG.getNode(ISD::ANY_EXTEND, dl, ValueVT, Val); + return DAG.getNode(ISD::TRUNCATE, DL, ValueVT, Val); } + return DAG.getNode(ISD::ANY_EXTEND, DL, ValueVT, Val); } if (PartVT.isFloatingPoint() && ValueVT.isFloatingPoint()) { - if (ValueVT.bitsLT(Val.getValueType())) { - // FP_ROUND's are always exact here. - return DAG.getNode(ISD::FP_ROUND, dl, ValueVT, Val, + // FP_ROUND's are always exact here. + if (ValueVT.bitsLT(Val.getValueType())) + return DAG.getNode(ISD::FP_ROUND, DL, ValueVT, Val, DAG.getIntPtrConstant(1)); - } - return DAG.getNode(ISD::FP_EXTEND, dl, ValueVT, Val); + return DAG.getNode(ISD::FP_EXTEND, DL, ValueVT, Val); } if (PartVT.getSizeInBits() == ValueVT.getSizeInBits()) - return DAG.getNode(ISD::BIT_CONVERT, dl, ValueVT, Val); + return DAG.getNode(ISD::BIT_CONVERT, DL, ValueVT, Val); llvm_unreachable("Unknown mismatch!"); return SDValue(); } +/// getCopyFromParts - Create a value that contains the specified legal parts +/// combined into the value they represent. If the parts combine to a type +/// larger then ValueVT then AssertOp can be used to specify whether the extra +/// bits are known to be zero (ISD::AssertZext) or sign extended from ValueVT +/// (ISD::AssertSext). +static SDValue getCopyFromPartsVector(SelectionDAG &DAG, DebugLoc DL, + const SDValue *Parts, unsigned NumParts, + EVT PartVT, EVT ValueVT) { + assert(ValueVT.isVector() && "Not a vector value"); + assert(NumParts > 0 && "No parts to assemble!"); + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + SDValue Val = Parts[0]; + + // Handle a multi-element vector. + if (NumParts > 1) { + EVT IntermediateVT, RegisterVT; + unsigned NumIntermediates; + unsigned NumRegs = + TLI.getVectorTypeBreakdown(*DAG.getContext(), ValueVT, IntermediateVT, + NumIntermediates, RegisterVT); + assert(NumRegs == NumParts && "Part count doesn't match vector breakdown!"); + NumParts = NumRegs; // Silence a compiler warning. + assert(RegisterVT == PartVT && "Part type doesn't match vector breakdown!"); + assert(RegisterVT == Parts[0].getValueType() && + "Part type doesn't match part!"); + + // Assemble the parts into intermediate operands. + SmallVector Ops(NumIntermediates); + if (NumIntermediates == NumParts) { + // If the register was not expanded, truncate or copy the value, + // as appropriate. + for (unsigned i = 0; i != NumParts; ++i) + Ops[i] = getCopyFromParts(DAG, DL, &Parts[i], 1, + PartVT, IntermediateVT); + } else if (NumParts > 0) { + // If the intermediate type was expanded, build the intermediate + // operands from the parts. + assert(NumParts % NumIntermediates == 0 && + "Must expand into a divisible number of parts!"); + unsigned Factor = NumParts / NumIntermediates; + for (unsigned i = 0; i != NumIntermediates; ++i) + Ops[i] = getCopyFromParts(DAG, DL, &Parts[i * Factor], Factor, + PartVT, IntermediateVT); + } + + // Build a vector with BUILD_VECTOR or CONCAT_VECTORS from the + // intermediate operands. + Val = DAG.getNode(IntermediateVT.isVector() ? + ISD::CONCAT_VECTORS : ISD::BUILD_VECTOR, DL, + ValueVT, &Ops[0], NumIntermediates); + } + + // There is now one part, held in Val. Correct it to match ValueVT. + PartVT = Val.getValueType(); + + if (PartVT == ValueVT) + return Val; + + if (PartVT.isVector()) { + // If the element type of the source/dest vectors are the same, but the + // parts vector has more elements than the value vector, then we have a + // vector widening case (e.g. <2 x float> -> <4 x float>). Extract the + // elements we want. + if (PartVT.getVectorElementType() == ValueVT.getVectorElementType()) { + assert(PartVT.getVectorNumElements() > ValueVT.getVectorNumElements() && + "Cannot narrow, it would be a lossy transformation"); + return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ValueVT, Val, + DAG.getIntPtrConstant(0)); + } + + // Vector/Vector bitcast. + return DAG.getNode(ISD::BIT_CONVERT, DL, ValueVT, Val); + } + + assert(ValueVT.getVectorElementType() == PartVT && + ValueVT.getVectorNumElements() == 1 && + "Only trivial scalar-to-vector conversions should get here!"); + return DAG.getNode(ISD::BUILD_VECTOR, DL, ValueVT, Val); +} + + + + +static void getCopyToPartsVector(SelectionDAG &DAG, DebugLoc dl, + SDValue Val, SDValue *Parts, unsigned NumParts, + EVT PartVT); + /// getCopyToParts - Create a series of nodes that contain the specified value /// split into legal parts. If the parts contain more bits than Val, then, for /// integers, ExtendKind can be used to specify how to generate the extra bits. -static void getCopyToParts(SelectionDAG &DAG, DebugLoc dl, +static void getCopyToParts(SelectionDAG &DAG, DebugLoc DL, SDValue Val, SDValue *Parts, unsigned NumParts, EVT PartVT, ISD::NodeType ExtendKind = ISD::ANY_EXTEND) { - const TargetLowering &TLI = DAG.getTargetLoweringInfo(); - EVT PtrVT = TLI.getPointerTy(); EVT ValueVT = Val.getValueType(); + + // Handle the vector case separately. + if (ValueVT.isVector()) + return getCopyToPartsVector(DAG, DL, Val, Parts, NumParts, PartVT); + + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); unsigned PartBits = PartVT.getSizeInBits(); unsigned OrigNumParts = NumParts; assert(TLI.isTypeLegal(PartVT) && "Copying to an illegal type!"); - if (!NumParts) + if (NumParts == 0) return; - if (!ValueVT.isVector()) { - if (PartVT == ValueVT) { - assert(NumParts == 1 && "No-op copy with multiple parts!"); - Parts[0] = Val; - return; - } - - if (NumParts * PartBits > ValueVT.getSizeInBits()) { - // If the parts cover more bits than the value has, promote the value. - if (PartVT.isFloatingPoint() && ValueVT.isFloatingPoint()) { - assert(NumParts == 1 && "Do not know what to promote to!"); - Val = DAG.getNode(ISD::FP_EXTEND, dl, PartVT, Val); - } else if (PartVT.isInteger() && ValueVT.isInteger()) { - ValueVT = EVT::getIntegerVT(*DAG.getContext(), NumParts * PartBits); - Val = DAG.getNode(ExtendKind, dl, ValueVT, Val); - } else { - llvm_unreachable("Unknown mismatch!"); - } - } else if (PartBits == ValueVT.getSizeInBits()) { - // Different types of the same size. - assert(NumParts == 1 && PartVT != ValueVT); - Val = DAG.getNode(ISD::BIT_CONVERT, dl, PartVT, Val); - } else if (NumParts * PartBits < ValueVT.getSizeInBits()) { - // If the parts cover less bits than value has, truncate the value. - if (PartVT.isInteger() && ValueVT.isInteger()) { - ValueVT = EVT::getIntegerVT(*DAG.getContext(), NumParts * PartBits); - Val = DAG.getNode(ISD::TRUNCATE, dl, ValueVT, Val); - } else { - llvm_unreachable("Unknown mismatch!"); - } - } - - // The value may have changed - recompute ValueVT. - ValueVT = Val.getValueType(); - assert(NumParts * PartBits == ValueVT.getSizeInBits() && - "Failed to tile the value with PartVT!"); - - if (NumParts == 1) { - assert(PartVT == ValueVT && "Type conversion failed!"); - Parts[0] = Val; - return; - } + assert(!ValueVT.isVector() && "Vector case handled elsewhere"); + if (PartVT == ValueVT) { + assert(NumParts == 1 && "No-op copy with multiple parts!"); + Parts[0] = Val; + return; + } - // Expand the value into multiple parts. - if (NumParts & (NumParts - 1)) { - // The number of parts is not a power of 2. Split off and copy the tail. + if (NumParts * PartBits > ValueVT.getSizeInBits()) { + // If the parts cover more bits than the value has, promote the value. + if (PartVT.isFloatingPoint() && ValueVT.isFloatingPoint()) { + assert(NumParts == 1 && "Do not know what to promote to!"); + Val = DAG.getNode(ISD::FP_EXTEND, DL, PartVT, Val); + } else { assert(PartVT.isInteger() && ValueVT.isInteger() && - "Do not know what to expand to!"); - unsigned RoundParts = 1 << Log2_32(NumParts); - unsigned RoundBits = RoundParts * PartBits; - unsigned OddParts = NumParts - RoundParts; - SDValue OddVal = DAG.getNode(ISD::SRL, dl, ValueVT, Val, - DAG.getConstant(RoundBits, - TLI.getPointerTy())); - getCopyToParts(DAG, dl, OddVal, Parts + RoundParts, - OddParts, PartVT); - - if (TLI.isBigEndian()) - // The odd parts were reversed by getCopyToParts - unreverse them. - std::reverse(Parts + RoundParts, Parts + NumParts); - - NumParts = RoundParts; + "Unknown mismatch!"); ValueVT = EVT::getIntegerVT(*DAG.getContext(), NumParts * PartBits); - Val = DAG.getNode(ISD::TRUNCATE, dl, ValueVT, Val); + Val = DAG.getNode(ExtendKind, DL, ValueVT, Val); } + } else if (PartBits == ValueVT.getSizeInBits()) { + // Different types of the same size. + assert(NumParts == 1 && PartVT != ValueVT); + Val = DAG.getNode(ISD::BIT_CONVERT, DL, PartVT, Val); + } else if (NumParts * PartBits < ValueVT.getSizeInBits()) { + // If the parts cover less bits than value has, truncate the value. + assert(PartVT.isInteger() && ValueVT.isInteger() && + "Unknown mismatch!"); + ValueVT = EVT::getIntegerVT(*DAG.getContext(), NumParts * PartBits); + Val = DAG.getNode(ISD::TRUNCATE, DL, ValueVT, Val); + } + + // The value may have changed - recompute ValueVT. + ValueVT = Val.getValueType(); + assert(NumParts * PartBits == ValueVT.getSizeInBits() && + "Failed to tile the value with PartVT!"); - // The number of parts is a power of 2. Repeatedly bisect the value using - // EXTRACT_ELEMENT. - Parts[0] = DAG.getNode(ISD::BIT_CONVERT, dl, - EVT::getIntegerVT(*DAG.getContext(), - ValueVT.getSizeInBits()), - Val); - - for (unsigned StepSize = NumParts; StepSize > 1; StepSize /= 2) { - for (unsigned i = 0; i < NumParts; i += StepSize) { - unsigned ThisBits = StepSize * PartBits / 2; - EVT ThisVT = EVT::getIntegerVT(*DAG.getContext(), ThisBits); - SDValue &Part0 = Parts[i]; - SDValue &Part1 = Parts[i+StepSize/2]; - - Part1 = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, - ThisVT, Part0, - DAG.getConstant(1, PtrVT)); - Part0 = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, - ThisVT, Part0, - DAG.getConstant(0, PtrVT)); - - if (ThisBits == PartBits && ThisVT != PartVT) { - Part0 = DAG.getNode(ISD::BIT_CONVERT, dl, - PartVT, Part0); - Part1 = DAG.getNode(ISD::BIT_CONVERT, dl, - PartVT, Part1); - } + if (NumParts == 1) { + assert(PartVT == ValueVT && "Type conversion failed!"); + Parts[0] = Val; + return; + } + + // Expand the value into multiple parts. + if (NumParts & (NumParts - 1)) { + // The number of parts is not a power of 2. Split off and copy the tail. + assert(PartVT.isInteger() && ValueVT.isInteger() && + "Do not know what to expand to!"); + unsigned RoundParts = 1 << Log2_32(NumParts); + unsigned RoundBits = RoundParts * PartBits; + unsigned OddParts = NumParts - RoundParts; + SDValue OddVal = DAG.getNode(ISD::SRL, DL, ValueVT, Val, + DAG.getIntPtrConstant(RoundBits)); + getCopyToParts(DAG, DL, OddVal, Parts + RoundParts, OddParts, PartVT); + + if (TLI.isBigEndian()) + // The odd parts were reversed by getCopyToParts - unreverse them. + std::reverse(Parts + RoundParts, Parts + NumParts); + + NumParts = RoundParts; + ValueVT = EVT::getIntegerVT(*DAG.getContext(), NumParts * PartBits); + Val = DAG.getNode(ISD::TRUNCATE, DL, ValueVT, Val); + } + + // The number of parts is a power of 2. Repeatedly bisect the value using + // EXTRACT_ELEMENT. + Parts[0] = DAG.getNode(ISD::BIT_CONVERT, DL, + EVT::getIntegerVT(*DAG.getContext(), + ValueVT.getSizeInBits()), + Val); + + for (unsigned StepSize = NumParts; StepSize > 1; StepSize /= 2) { + for (unsigned i = 0; i < NumParts; i += StepSize) { + unsigned ThisBits = StepSize * PartBits / 2; + EVT ThisVT = EVT::getIntegerVT(*DAG.getContext(), ThisBits); + SDValue &Part0 = Parts[i]; + SDValue &Part1 = Parts[i+StepSize/2]; + + Part1 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, + ThisVT, Part0, DAG.getIntPtrConstant(1)); + Part0 = DAG.getNode(ISD::EXTRACT_ELEMENT, DL, + ThisVT, Part0, DAG.getIntPtrConstant(0)); + + if (ThisBits == PartBits && ThisVT != PartVT) { + Part0 = DAG.getNode(ISD::BIT_CONVERT, DL, PartVT, Part0); + Part1 = DAG.getNode(ISD::BIT_CONVERT, DL, PartVT, Part1); } } + } - if (TLI.isBigEndian()) - std::reverse(Parts, Parts + OrigNumParts); + if (TLI.isBigEndian()) + std::reverse(Parts, Parts + OrigNumParts); +} - return; - } - // Vector ValueVT. +/// getCopyToPartsVector - Create a series of nodes that contain the specified +/// value split into legal parts. +static void getCopyToPartsVector(SelectionDAG &DAG, DebugLoc DL, + SDValue Val, SDValue *Parts, unsigned NumParts, + EVT PartVT) { + EVT ValueVT = Val.getValueType(); + assert(ValueVT.isVector() && "Not a vector"); + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + if (NumParts == 1) { - if (PartVT != ValueVT) { - if (PartVT.getSizeInBits() == ValueVT.getSizeInBits()) { - Val = DAG.getNode(ISD::BIT_CONVERT, dl, PartVT, Val); - } else { - assert(ValueVT.getVectorElementType() == PartVT && - ValueVT.getVectorNumElements() == 1 && - "Only trivial vector-to-scalar conversions should get here!"); - Val = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, - PartVT, Val, - DAG.getConstant(0, PtrVT)); - } - } + if (PartVT == ValueVT) { + // Nothing to do. + } else if (PartVT.getSizeInBits() == ValueVT.getSizeInBits()) { + // Bitconvert vector->vector case. + Val = DAG.getNode(ISD::BIT_CONVERT, DL, PartVT, Val); + } else if (PartVT.isVector() && + PartVT.getVectorElementType() == ValueVT.getVectorElementType()&& + PartVT.getVectorNumElements() > ValueVT.getVectorNumElements()) { + EVT ElementVT = PartVT.getVectorElementType(); + // Vector widening case, e.g. <2 x float> -> <4 x float>. Shuffle in + // undef elements. + SmallVector Ops; + for (unsigned i = 0, e = ValueVT.getVectorNumElements(); i != e; ++i) + Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, + ElementVT, Val, DAG.getIntPtrConstant(i))); + + for (unsigned i = ValueVT.getVectorNumElements(), + e = PartVT.getVectorNumElements(); i != e; ++i) + Ops.push_back(DAG.getUNDEF(ElementVT)); + + Val = DAG.getNode(ISD::BUILD_VECTOR, DL, PartVT, &Ops[0], Ops.size()); + // FIXME: Use CONCAT for 2x -> 4x. + + //SDValue UndefElts = DAG.getUNDEF(VectorTy); + //Val = DAG.getNode(ISD::CONCAT_VECTORS, DL, PartVT, Val, UndefElts); + } else { + // Vector -> scalar conversion. + assert(ValueVT.getVectorElementType() == PartVT && + ValueVT.getVectorNumElements() == 1 && + "Only trivial vector-to-scalar conversions should get here!"); + Val = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, + PartVT, Val, DAG.getIntPtrConstant(0)); + } + Parts[0] = Val; return; } - + // Handle a multi-element vector. EVT IntermediateVT, RegisterVT; unsigned NumIntermediates; unsigned NumRegs = TLI.getVectorTypeBreakdown(*DAG.getContext(), ValueVT, - IntermediateVT, NumIntermediates, RegisterVT); + IntermediateVT, + NumIntermediates, RegisterVT); unsigned NumElements = ValueVT.getVectorNumElements(); - + assert(NumRegs == NumParts && "Part count doesn't match vector breakdown!"); NumParts = NumRegs; // Silence a compiler warning. assert(RegisterVT == PartVT && "Part type doesn't match vector breakdown!"); - + // Split the vector into intermediate operands. SmallVector Ops(NumIntermediates); for (unsigned i = 0; i != NumIntermediates; ++i) { if (IntermediateVT.isVector()) - Ops[i] = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, + Ops[i] = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, IntermediateVT, Val, - DAG.getConstant(i * (NumElements / NumIntermediates), - PtrVT)); + DAG.getIntPtrConstant(i * (NumElements / NumIntermediates))); else - Ops[i] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, - IntermediateVT, Val, - DAG.getConstant(i, PtrVT)); + Ops[i] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, + IntermediateVT, Val, DAG.getIntPtrConstant(i)); } - + // Split the intermediate operands into legal parts. if (NumParts == NumIntermediates) { // If the register was not expanded, promote or copy the value, // as appropriate. for (unsigned i = 0; i != NumParts; ++i) - getCopyToParts(DAG, dl, Ops[i], &Parts[i], 1, PartVT); + getCopyToParts(DAG, DL, Ops[i], &Parts[i], 1, PartVT); } else if (NumParts > 0) { // If the intermediate type was expanded, split each the value into // legal parts. @@ -417,10 +481,13 @@ static void getCopyToParts(SelectionDAG &DAG, DebugLoc dl, "Must expand into a divisible number of parts!"); unsigned Factor = NumParts / NumIntermediates; for (unsigned i = 0; i != NumIntermediates; ++i) - getCopyToParts(DAG, dl, Ops[i], &Parts[i*Factor], Factor, PartVT); + getCopyToParts(DAG, DL, Ops[i], &Parts[i*Factor], Factor, PartVT); } } + + + namespace { /// RegsForValue - This struct represents the registers (physical or virtual) /// that a particular set of values is assigned, and the type information @@ -460,11 +527,6 @@ namespace { EVT regvt, EVT valuevt) : ValueVTs(1, valuevt), RegVTs(1, regvt), Regs(regs) {} - RegsForValue(const SmallVector ®s, - const SmallVector ®vts, - const SmallVector &valuevts) - : ValueVTs(valuevts), RegVTs(regvts), Regs(regs) {} - RegsForValue(LLVMContext &Context, const TargetLowering &tli, unsigned Reg, const Type *Ty) { ComputeValueVTs(tli, Ty, ValueVTs); @@ -530,6 +592,10 @@ SDValue RegsForValue::getCopyFromRegs(SelectionDAG &DAG, FunctionLoweringInfo &FuncInfo, DebugLoc dl, SDValue &Chain, SDValue *Flag) const { + // A Value with type {} or [0 x %t] needs no registers. + if (ValueVTs.empty()) + return SDValue(); + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); // Assemble the legal parts into the final values. @@ -623,8 +689,7 @@ void RegsForValue::getCopyToRegs(SDValue Val, SelectionDAG &DAG, DebugLoc dl, unsigned NumParts = TLI.getNumRegisters(*DAG.getContext(), ValueVT); EVT RegisterVT = RegVTs[Value]; - getCopyToParts(DAG, dl, - Val.getValue(Val.getResNo() + Value), + getCopyToParts(DAG, dl, Val.getValue(Val.getResNo() + Value), &Parts[Part], NumParts, RegisterVT); Part += NumParts; } @@ -701,6 +766,7 @@ void SelectionDAGBuilder::clear() { UnusedArgNodeMap.clear(); PendingLoads.clear(); PendingExports.clear(); + DanglingDebugInfoMap.clear(); CurDebugLoc = DebugLoc(); HasTailCall = false; } @@ -805,6 +871,33 @@ void SelectionDAGBuilder::visit(unsigned Opcode, const User &I) { } } +// resolveDanglingDebugInfo - if we saw an earlier dbg_value referring to V, +// generate the debug data structures now that we've seen its definition. +void SelectionDAGBuilder::resolveDanglingDebugInfo(const Value *V, + SDValue Val) { + DanglingDebugInfo &DDI = DanglingDebugInfoMap[V]; + if (DDI.getDI()) { + const DbgValueInst *DI = DDI.getDI(); + DebugLoc dl = DDI.getdl(); + unsigned DbgSDNodeOrder = DDI.getSDNodeOrder(); + MDNode *Variable = DI->getVariable(); + uint64_t Offset = DI->getOffset(); + SDDbgValue *SDV; + if (Val.getNode()) { + if (!EmitFuncArgumentDbgValue(V, Variable, Offset, Val)) { + SDV = DAG.getDbgValue(Variable, Val.getNode(), + Val.getResNo(), Offset, dl, DbgSDNodeOrder); + DAG.AddDbgValue(SDV, Val.getNode(), false); + } + } else { + SDV = DAG.getDbgValue(Variable, UndefValue::get(V->getType()), + Offset, dl, SDNodeOrder); + DAG.AddDbgValue(SDV, 0, false); + } + DanglingDebugInfoMap[V] = DanglingDebugInfo(); + } +} + // getValue - Return an SDValue for the given Value. SDValue SelectionDAGBuilder::getValue(const Value *V) { // If we already have an SDValue for this value, use it. It's important @@ -826,6 +919,7 @@ SDValue SelectionDAGBuilder::getValue(const Value *V) { // Otherwise create a new SDValue and remember it. SDValue Val = getValueImpl(V); NodeMap[V] = Val; + resolveDanglingDebugInfo(V, Val); return Val; } @@ -839,10 +933,11 @@ SDValue SelectionDAGBuilder::getNonRegisterValue(const Value *V) { // Otherwise create a new SDValue and remember it. SDValue Val = getValueImpl(V); NodeMap[V] = Val; + resolveDanglingDebugInfo(V, Val); return Val; } -/// getValueImpl - Helper function for getValue and getMaterializedValue. +/// getValueImpl - Helper function for getValue and getNonRegisterValue. /// Create an SDValue for the given value. SDValue SelectionDAGBuilder::getValueImpl(const Value *V) { if (const Constant *C = dyn_cast(V)) { @@ -986,10 +1081,10 @@ void SelectionDAGBuilder::visitRet(const ReturnInst &I) { unsigned NumValues = ValueVTs.size(); SmallVector Chains(NumValues); - EVT PtrVT = PtrValueVTs[0]; for (unsigned i = 0; i != NumValues; ++i) { - SDValue Add = DAG.getNode(ISD::ADD, getCurDebugLoc(), PtrVT, RetPtr, - DAG.getConstant(Offsets[i], PtrVT)); + SDValue Add = DAG.getNode(ISD::ADD, getCurDebugLoc(), + RetPtr.getValueType(), RetPtr, + DAG.getIntPtrConstant(Offsets[i])); Chains[i] = DAG.getStore(Chain, getCurDebugLoc(), SDValue(RetOp.getNode(), RetOp.getResNo() + i), @@ -2709,11 +2804,6 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) { } Ty = StTy->getElementType(Field); - } else if (const UnionType *UnTy = dyn_cast(Ty)) { - unsigned Field = cast(Idx)->getZExtValue(); - - // Offset canonically 0 for unions, but type changes - Ty = UnTy->getElementType(Field); } else { Ty = cast(Ty)->getElementType(); @@ -2818,7 +2908,7 @@ void SelectionDAGBuilder::visitAlloca(const AllocaInst &I) { // Inform the Frame Information that we have just allocated a variable-sized // object. - FuncInfo.MF->getFrameInfo()->CreateVariableSizedObject(); + FuncInfo.MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1); } void SelectionDAGBuilder::visitLoad(const LoadInst &I) { @@ -3824,11 +3914,11 @@ static SDValue ExpandPowI(DebugLoc DL, SDValue LHS, SDValue RHS, /// argument, create the corresponding DBG_VALUE machine instruction for it now. /// At the end of instruction selection, they will be inserted to the entry BB. bool -SelectionDAGBuilder::EmitFuncArgumentDbgValue(const DbgValueInst &DI, - const Value *V, MDNode *Variable, - uint64_t Offset, +SelectionDAGBuilder::EmitFuncArgumentDbgValue(const Value *V, MDNode *Variable, + int64_t Offset, const SDValue &N) { - if (!isa(V)) + const Argument *Arg = dyn_cast(V); + if (!Arg) return false; MachineFunction &MF = DAG.getMachineFunction(); @@ -3842,7 +3932,15 @@ SelectionDAGBuilder::EmitFuncArgumentDbgValue(const DbgValueInst &DI, return false; unsigned Reg = 0; - if (N.getOpcode() == ISD::CopyFromReg) { + if (Arg->hasByValAttr()) { + // Byval arguments' frame index is recorded during argument lowering. + // Use this info directly. + const TargetRegisterInfo *TRI = DAG.getTarget().getRegisterInfo(); + Reg = TRI->getFrameRegister(MF); + Offset = FuncInfo.getByValArgumentFrameIndex(Arg); + } + + if (N.getNode() && N.getOpcode() == ISD::CopyFromReg) { Reg = cast(N.getOperand(1))->getReg(); if (Reg && TargetRegisterInfo::isVirtualRegister(Reg)) { MachineRegisterInfo &RegInfo = MF.getRegInfo(); @@ -3966,42 +4064,40 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { } case Intrinsic::dbg_declare: { const DbgDeclareInst &DI = cast(I); - if (!DIVariable(DI.getVariable()).Verify()) - return 0; - MDNode *Variable = DI.getVariable(); - // Parameters are handled specially. - bool isParameter = - DIVariable(Variable).getTag() == dwarf::DW_TAG_arg_variable; const Value *Address = DI.getAddress(); - if (!Address) + if (!Address || !DIVariable(DI.getVariable()).Verify()) return 0; - if (const BitCastInst *BCI = dyn_cast(Address)) - Address = BCI->getOperand(0); - const AllocaInst *AI = dyn_cast(Address); - if (AI) { - // Don't handle byval arguments or VLAs, for example. - // Non-byval arguments are handled here (they refer to the stack temporary - // alloca at this point). - DenseMap::iterator SI = - FuncInfo.StaticAllocaMap.find(AI); - if (SI == FuncInfo.StaticAllocaMap.end()) - return 0; // VLAs. - int FI = SI->second; - - MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI(); - if (!DI.getDebugLoc().isUnknown() && MMI.hasDebugInfo()) - MMI.setVariableDbgInfo(Variable, FI, DI.getDebugLoc()); - } // Build an entry in DbgOrdering. Debug info input nodes get an SDNodeOrder // but do not always have a corresponding SDNode built. The SDNodeOrder // absolute, but not relative, values are different depending on whether // debug info exists. ++SDNodeOrder; + + // Check if address has undef value. + if (isa(Address) || + (Address->use_empty() && !isa(Address))) { + SDDbgValue*SDV = + DAG.getDbgValue(Variable, UndefValue::get(Address->getType()), + 0, dl, SDNodeOrder); + DAG.AddDbgValue(SDV, 0, false); + return 0; + } + SDValue &N = NodeMap[Address]; + if (!N.getNode() && isa(Address)) + // Check unused arguments map. + N = UnusedArgNodeMap[Address]; SDDbgValue *SDV; if (N.getNode()) { + // Parameters are handled specially. + bool isParameter = + DIVariable(Variable).getTag() == dwarf::DW_TAG_arg_variable; + if (const BitCastInst *BCI = dyn_cast(Address)) + Address = BCI->getOperand(0); + const AllocaInst *AI = dyn_cast(Address); + if (isParameter && !AI) { FrameIndexSDNode *FINode = dyn_cast(N.getNode()); if (FINode) @@ -4020,10 +4116,14 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { return 0; DAG.AddDbgValue(SDV, N.getNode(), isParameter); } else { - // This isn't useful, but it shows what we're missing. - SDV = DAG.getDbgValue(Variable, UndefValue::get(Address->getType()), - 0, dl, SDNodeOrder); - DAG.AddDbgValue(SDV, 0, isParameter); + // If Address is an arugment then try to emits its dbg value using + // virtual register info from the FuncInfo.ValueMap. Otherwise add undef + // to help track missing debug info. + if (!EmitFuncArgumentDbgValue(Address, Variable, 0, N)) { + SDV = DAG.getDbgValue(Variable, UndefValue::get(Address->getType()), + 0, dl, SDNodeOrder); + DAG.AddDbgValue(SDV, 0, false); + } } return 0; } @@ -4048,31 +4148,24 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { SDV = DAG.getDbgValue(Variable, V, Offset, dl, SDNodeOrder); DAG.AddDbgValue(SDV, 0, false); } else { - bool createUndef = false; - // FIXME : Why not use getValue() directly ? + // Do not use getValue() in here; we don't want to generate code at + // this point if it hasn't been done yet. SDValue N = NodeMap[V]; if (!N.getNode() && isa(V)) // Check unused arguments map. N = UnusedArgNodeMap[V]; if (N.getNode()) { - if (!EmitFuncArgumentDbgValue(DI, V, Variable, Offset, N)) { + if (!EmitFuncArgumentDbgValue(V, Variable, Offset, N)) { SDV = DAG.getDbgValue(Variable, N.getNode(), N.getResNo(), Offset, dl, SDNodeOrder); DAG.AddDbgValue(SDV, N.getNode(), false); } - } else if (isa(V) && !V->use_empty()) { - SDValue N = getValue(V); - if (N.getNode()) { - if (!EmitFuncArgumentDbgValue(DI, V, Variable, Offset, N)) { - SDV = DAG.getDbgValue(Variable, N.getNode(), - N.getResNo(), Offset, dl, SDNodeOrder); - DAG.AddDbgValue(SDV, N.getNode(), false); - } - } else - createUndef = true; - } else - createUndef = true; - if (createUndef) { + } else if (isa(V) && !V->use_empty() ) { + // Do not call getValue(V) yet, as we don't want to generate code. + // Remember it for later. + DanglingDebugInfo DDI(&DI, dl, SDNodeOrder); + DanglingDebugInfoMap[V] = DDI; + } else { // We may expand this to cover more cases. One case where we have no // data available is an unreferenced parameter; we need this fallback. SDV = DAG.getDbgValue(Variable, UndefValue::get(V->getType()), @@ -4572,6 +4665,11 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee, !isInTailCallPosition(CS, CS.getAttributes().getRetAttributes(), TLI)) isTailCall = false; + // If there's a possibility that fast-isel has already selected some amount + // of the current basic block, don't emit a tail call. + if (isTailCall && EnableFastISel) + isTailCall = false; + std::pair Result = TLI.LowerCallTo(getRoot(), RetTy, CS.paramHasAttr(0, Attribute::SExt), @@ -6054,6 +6152,12 @@ void SelectionDAGISel::LowerArguments(const BasicBlock *LLVMBB) { i += NumParts; } + // Note down frame index for byval arguments. + if (I->hasByValAttr() && !ArgValues.empty()) + if (FrameIndexSDNode *FI = + dyn_cast(ArgValues[0].getNode())) + FuncInfo->setByValArgumentFrameIndex(I, FI->getIndex()); + if (!I->use_empty()) { SDValue Res; if (!ArgValues.empty()) diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h index 46733d6..5f400e9 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -18,9 +18,6 @@ #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" -#ifndef NDEBUG -#include "llvm/ADT/SmallSet.h" -#endif #include "llvm/CodeGen/SelectionDAGNodes.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/Support/CallSite.h" @@ -64,6 +61,7 @@ class PHINode; class PtrToIntInst; class ReturnInst; class SDISelAsmOperandInfo; +class SDDbgValue; class SExtInst; class SelectInst; class ShuffleVectorInst; @@ -93,6 +91,24 @@ class SelectionDAGBuilder { /// to preserve debug information for incoming arguments. DenseMap UnusedArgNodeMap; + /// DanglingDebugInfo - Helper type for DanglingDebugInfoMap. + class DanglingDebugInfo { + const DbgValueInst* DI; + DebugLoc dl; + unsigned SDNodeOrder; + public: + DanglingDebugInfo() : DI(0), dl(DebugLoc()), SDNodeOrder(0) { } + DanglingDebugInfo(const DbgValueInst *di, DebugLoc DL, unsigned SDNO) : + DI(di), dl(DL), SDNodeOrder(SDNO) { } + const DbgValueInst* getDI() { return DI; } + DebugLoc getdl() { return dl; } + unsigned getSDNodeOrder() { return SDNodeOrder; } + }; + + /// DanglingDebugInfoMap - Keeps track of dbg_values for which we have not + /// yet seen the referent. We defer handling these until we do see it. + DenseMap DanglingDebugInfoMap; + public: /// PendingLoads - Loads are not emitted to the program immediately. We bunch /// them up and then emit token factor nodes when possible. This allows us to @@ -345,6 +361,9 @@ public: void visit(unsigned Opcode, const User &I); + // resolveDanglingDebugInfo - if we saw an earlier dbg_value referring to V, + // generate the debug data structures now that we've seen its definition. + void resolveDanglingDebugInfo(const Value *V, SDValue Val); SDValue getValue(const Value *V); SDValue getNonRegisterValue(const Value *V); SDValue getValueImpl(const Value *V); @@ -506,13 +525,11 @@ private: void HandlePHINodesInSuccessorBlocks(const BasicBlock *LLVMBB); - /// EmitFuncArgumentDbgValue - If the DbgValueInst is a dbg_value of a - /// function argument, create the corresponding DBG_VALUE machine instruction - /// for it now. At the end of instruction selection, they will be inserted to - /// the entry BB. - bool EmitFuncArgumentDbgValue(const DbgValueInst &DI, - const Value *V, MDNode *Variable, - uint64_t Offset, const SDValue &N); + /// EmitFuncArgumentDbgValue - If V is an function argument then create + /// corresponding DBG_VALUE machine instruction for it now. At the end of + /// instruction selection, they will be inserted to the entry BB. + bool EmitFuncArgumentDbgValue(const Value *V, MDNode *Variable, + int64_t Offset, const SDValue &N); }; } // end namespace llvm diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 08ba548..66cb5ce 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -132,14 +132,16 @@ namespace llvm { const TargetLowering &TLI = IS->getTargetLowering(); if (OptLevel == CodeGenOpt::None) - return createFastDAGScheduler(IS, OptLevel); + return createSourceListDAGScheduler(IS, OptLevel); if (TLI.getSchedulingPreference() == Sched::Latency) return createTDListDAGScheduler(IS, OptLevel); if (TLI.getSchedulingPreference() == Sched::RegPressure) return createBURRListDAGScheduler(IS, OptLevel); - assert(TLI.getSchedulingPreference() == Sched::Hybrid && + if (TLI.getSchedulingPreference() == Sched::Hybrid) + return createHybridListDAGScheduler(IS, OptLevel); + assert(TLI.getSchedulingPreference() == Sched::ILP && "Unknown sched type!"); - return createHybridListDAGScheduler(IS, OptLevel); + return createILPListDAGScheduler(IS, OptLevel); } } @@ -169,7 +171,7 @@ TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, //===----------------------------------------------------------------------===// SelectionDAGISel::SelectionDAGISel(const TargetMachine &tm, CodeGenOpt::Level OL) : - MachineFunctionPass(&ID), TM(tm), TLI(*tm.getTargetLowering()), + MachineFunctionPass(ID), TM(tm), TLI(*tm.getTargetLowering()), FuncInfo(new FunctionLoweringInfo(TLI)), CurDAG(new SelectionDAG(tm)), SDB(new SelectionDAGBuilder(*CurDAG, *FuncInfo, OL)), @@ -216,7 +218,7 @@ static bool FunctionCallsSetJmp(const Function *F) { for (Value::const_use_iterator I = Callee->use_begin(), E = Callee->use_end(); I != E; ++I) - if (const CallInst *CI = dyn_cast(I)) + if (const CallInst *CI = dyn_cast(*I)) if (CI->getParent()->getParent() == F) return true; } @@ -362,38 +364,6 @@ SelectionDAGISel::SelectBasicBlock(BasicBlock::const_iterator Begin, CodeGenAndEmitDAG(); } -namespace { -/// WorkListRemover - This class is a DAGUpdateListener that removes any deleted -/// nodes from the worklist. -class SDOPsWorkListRemover : public SelectionDAG::DAGUpdateListener { - SmallVector &Worklist; - SmallPtrSet &InWorklist; -public: - SDOPsWorkListRemover(SmallVector &wl, - SmallPtrSet &inwl) - : Worklist(wl), InWorklist(inwl) {} - - void RemoveFromWorklist(SDNode *N) { - if (!InWorklist.erase(N)) return; - - SmallVector::iterator I = - std::find(Worklist.begin(), Worklist.end(), N); - assert(I != Worklist.end() && "Not in worklist"); - - *I = Worklist.back(); - Worklist.pop_back(); - } - - virtual void NodeDeleted(SDNode *N, SDNode *E) { - RemoveFromWorklist(N); - } - - virtual void NodeUpdated(SDNode *N) { - // Ignore updates. - } -}; -} - void SelectionDAGISel::ComputeLiveOutVRegInfo() { SmallPtrSet VisitedNodes; SmallVector Worklist; diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp index 6cae804..8313de5 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp @@ -199,7 +199,7 @@ const std::string SelectionDAG::getGraphAttrs(const SDNode *N) const { #else errs() << "SelectionDAG::getGraphAttrs is only available in debug builds" << " on systems with Graphviz or gv!\n"; - return std::string(""); + return std::string(); #endif } diff --git a/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 4f38669..b74f600 100644 --- a/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -651,6 +651,53 @@ static unsigned getVectorTypeBreakdownMVT(MVT VT, MVT &IntermediateVT, return NumVectorRegs; } +/// isLegalRC - Return true if the value types that can be represented by the +/// specified register class are all legal. +bool TargetLowering::isLegalRC(const TargetRegisterClass *RC) const { + for (TargetRegisterClass::vt_iterator I = RC->vt_begin(), E = RC->vt_end(); + I != E; ++I) { + if (isTypeLegal(*I)) + return true; + } + return false; +} + +/// hasLegalSuperRegRegClasses - Return true if the specified register class +/// has one or more super-reg register classes that are legal. +bool +TargetLowering::hasLegalSuperRegRegClasses(const TargetRegisterClass *RC) const{ + if (*RC->superregclasses_begin() == 0) + return false; + for (TargetRegisterInfo::regclass_iterator I = RC->superregclasses_begin(), + E = RC->superregclasses_end(); I != E; ++I) { + const TargetRegisterClass *RRC = *I; + if (isLegalRC(RRC)) + return true; + } + return false; +} + +/// findRepresentativeClass - Return the largest legal super-reg register class +/// of the register class for the specified type and its associated "cost". +std::pair +TargetLowering::findRepresentativeClass(EVT VT) const { + const TargetRegisterClass *RC = RegClassForVT[VT.getSimpleVT().SimpleTy]; + if (!RC) + return std::make_pair(RC, 0); + const TargetRegisterClass *BestRC = RC; + for (TargetRegisterInfo::regclass_iterator I = RC->superregclasses_begin(), + E = RC->superregclasses_end(); I != E; ++I) { + const TargetRegisterClass *RRC = *I; + if (RRC->isASubClass() || !isLegalRC(RRC)) + continue; + if (!hasLegalSuperRegRegClasses(RRC)) + return std::make_pair(RRC, 1); + BestRC = RRC; + } + return std::make_pair(BestRC, 1); +} + + /// computeRegisterProperties - Once all of the register classes are added, /// this allows us to compute derived properties we expose. void TargetLowering::computeRegisterProperties() { @@ -736,6 +783,28 @@ void TargetLowering::computeRegisterProperties() { MVT VT = (MVT::SimpleValueType)i; if (isTypeLegal(VT)) continue; + // Determine if there is a legal wider type. If so, we should promote to + // that wider vector type. + EVT EltVT = VT.getVectorElementType(); + unsigned NElts = VT.getVectorNumElements(); + if (NElts != 1) { + bool IsLegalWiderType = false; + for (unsigned nVT = i+1; nVT <= MVT::LAST_VECTOR_VALUETYPE; ++nVT) { + EVT SVT = (MVT::SimpleValueType)nVT; + if (SVT.getVectorElementType() == EltVT && + SVT.getVectorNumElements() > NElts && + isTypeSynthesizable(SVT)) { + TransformToType[i] = SVT; + RegisterTypeForVT[i] = SVT; + NumRegistersForVT[i] = 1; + ValueTypeActions.setTypeAction(VT, Promote); + IsLegalWiderType = true; + break; + } + } + if (IsLegalWiderType) continue; + } + MVT IntermediateVT; EVT RegisterVT; unsigned NumIntermediates; @@ -744,32 +813,29 @@ void TargetLowering::computeRegisterProperties() { RegisterVT, this); RegisterTypeForVT[i] = RegisterVT; - // Determine if there is a legal wider type. - bool IsLegalWiderType = false; - EVT EltVT = VT.getVectorElementType(); - unsigned NElts = VT.getVectorNumElements(); - for (unsigned nVT = i+1; nVT <= MVT::LAST_VECTOR_VALUETYPE; ++nVT) { - EVT SVT = (MVT::SimpleValueType)nVT; - if (isTypeSynthesizable(SVT) && SVT.getVectorElementType() == EltVT && - SVT.getVectorNumElements() > NElts && NElts != 1) { - TransformToType[i] = SVT; - ValueTypeActions.setTypeAction(VT, Promote); - IsLegalWiderType = true; - break; - } - } - if (!IsLegalWiderType) { - EVT NVT = VT.getPow2VectorType(); - if (NVT == VT) { - // Type is already a power of 2. The default action is to split. - TransformToType[i] = MVT::Other; - ValueTypeActions.setTypeAction(VT, Expand); - } else { - TransformToType[i] = NVT; - ValueTypeActions.setTypeAction(VT, Promote); - } + EVT NVT = VT.getPow2VectorType(); + if (NVT == VT) { + // Type is already a power of 2. The default action is to split. + TransformToType[i] = MVT::Other; + ValueTypeActions.setTypeAction(VT, Expand); + } else { + TransformToType[i] = NVT; + ValueTypeActions.setTypeAction(VT, Promote); } } + + // Determine the 'representative' register class for each value type. + // An representative register class is the largest (meaning one which is + // not a sub-register class / subreg register class) legal register class for + // a group of value types. For example, on i386, i8, i16, and i32 + // representative would be GR32; while on x86_64 it's GR64. + for (unsigned i = 0; i != MVT::LAST_VALUETYPE; ++i) { + const TargetRegisterClass* RRC; + uint8_t Cost; + tie(RRC, Cost) = findRepresentativeClass((MVT::SimpleValueType)i); + RepRegClassForVT[i] = RRC; + RepRegClassCostForVT[i] = Cost; + } } const char *TargetLowering::getTargetNodeName(unsigned Opcode) const { @@ -798,8 +864,21 @@ unsigned TargetLowering::getVectorTypeBreakdown(LLVMContext &Context, EVT VT, EVT &IntermediateVT, unsigned &NumIntermediates, EVT &RegisterVT) const { - // Figure out the right, legal destination reg to copy into. unsigned NumElts = VT.getVectorNumElements(); + + // If there is a wider vector type with the same element type as this one, + // we should widen to that legal vector type. This handles things like + // <2 x float> -> <4 x float>. + if (NumElts != 1 && getTypeAction(VT) == Promote) { + RegisterVT = getTypeToTransformTo(Context, VT); + if (isTypeLegal(RegisterVT)) { + IntermediateVT = RegisterVT; + NumIntermediates = 1; + return 1; + } + } + + // Figure out the right, legal destination reg to copy into. EVT EltTy = VT.getVectorElementType(); unsigned NumVectorRegs = 1; @@ -828,16 +907,12 @@ unsigned TargetLowering::getVectorTypeBreakdown(LLVMContext &Context, EVT VT, EVT DestVT = getRegisterType(Context, NewVT); RegisterVT = DestVT; - if (DestVT.bitsLT(NewVT)) { - // Value is expanded, e.g. i64 -> i16. + if (DestVT.bitsLT(NewVT)) // Value is expanded, e.g. i64 -> i16. return NumVectorRegs*(NewVT.getSizeInBits()/DestVT.getSizeInBits()); - } else { - // Otherwise, promotion or legal types use the same number of registers as - // the vector decimated to the appropriate level. - return NumVectorRegs; - } - return 1; + // Otherwise, promotion or legal types use the same number of registers as + // the vector decimated to the appropriate level. + return NumVectorRegs; } /// Get the EVTs and ArgFlags collections that represent the legalized return @@ -1308,9 +1383,32 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, } } - if (SimplifyDemandedBits(Op.getOperand(0), NewMask.lshr(ShAmt), + if (SimplifyDemandedBits(InOp, NewMask.lshr(ShAmt), KnownZero, KnownOne, TLO, Depth+1)) return true; + + // Convert (shl (anyext x, c)) to (anyext (shl x, c)) if the high bits + // are not demanded. This will likely allow the anyext to be folded away. + if (InOp.getNode()->getOpcode() == ISD::ANY_EXTEND) { + SDValue InnerOp = InOp.getNode()->getOperand(0); + EVT InnerVT = InnerOp.getValueType(); + if ((APInt::getHighBitsSet(BitWidth, + BitWidth - InnerVT.getSizeInBits()) & + DemandedMask) == 0 && + isTypeDesirableForOp(ISD::SHL, InnerVT)) { + EVT ShTy = getShiftAmountTy(); + if (!APInt(BitWidth, ShAmt).isIntN(ShTy.getSizeInBits())) + ShTy = InnerVT; + SDValue NarrowShl = + TLO.DAG.getNode(ISD::SHL, dl, InnerVT, InnerOp, + TLO.DAG.getConstant(ShAmt, ShTy)); + return + TLO.CombineTo(Op, + TLO.DAG.getNode(ISD::ANY_EXTEND, dl, Op.getValueType(), + NarrowShl)); + } + } + KnownZero <<= SA->getZExtValue(); KnownOne <<= SA->getZExtValue(); // low bits known zero. @@ -1415,11 +1513,10 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, // present in the input. APInt NewBits = APInt::getHighBitsSet(BitWidth, - BitWidth - EVT.getScalarType().getSizeInBits()) & - NewMask; + BitWidth - EVT.getScalarType().getSizeInBits()); // If none of the extended bits are demanded, eliminate the sextinreg. - if (NewBits == 0) + if ((NewBits & NewMask) == 0) return TLO.CombineTo(Op, Op.getOperand(0)); APInt InSignBit = APInt::getSignBit(EVT.getScalarType().getSizeInBits()); @@ -1886,12 +1983,9 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, EVT ExtDstTy = N0.getValueType(); unsigned ExtDstTyBits = ExtDstTy.getSizeInBits(); - // If the extended part has any inconsistent bits, it cannot ever - // compare equal. In other words, they have to be all ones or all - // zeros. - APInt ExtBits = - APInt::getHighBitsSet(ExtDstTyBits, ExtDstTyBits - ExtSrcTyBits); - if ((C1 & ExtBits) != 0 && (C1 & ExtBits) != ExtBits) + // If the constant doesn't fit into the number of bits for the source of + // the sign extension, it is impossible for both sides to be equal. + if (C1.getMinSignedBits() > ExtSrcTyBits) return DAG.getConstant(Cond == ISD::SETNE, VT); SDValue ZextOp; @@ -2476,7 +2570,7 @@ void TargetLowering::LowerAsmOperandForConstraint(SDValue Op, int64_t Offs = GA->getOffset(); if (C) Offs += C->getZExtValue(); Ops.push_back(DAG.getTargetGlobalAddress(GA->getGlobal(), - C->getDebugLoc(), + C ? C->getDebugLoc() : DebugLoc(), Op.getValueType(), Offs)); return; } diff --git a/lib/CodeGen/SimpleRegisterCoalescing.cpp b/lib/CodeGen/SimpleRegisterCoalescing.cpp index e69d3e4..b29ea19 100644 --- a/lib/CodeGen/SimpleRegisterCoalescing.cpp +++ b/lib/CodeGen/SimpleRegisterCoalescing.cpp @@ -59,13 +59,16 @@ DisableCrossClassJoin("disable-cross-class-join", cl::desc("Avoid coalescing cross register class copies"), cl::init(false), cl::Hidden); -static RegisterPass -X("simple-register-coalescing", "Simple Register Coalescing"); +static cl::opt +DisablePhysicalJoin("disable-physical-join", + cl::desc("Avoid coalescing physical register copies"), + cl::init(false), cl::Hidden); -// Declare that we implement the RegisterCoalescer interface -static RegisterAnalysisGroup V(X); +INITIALIZE_AG_PASS(SimpleRegisterCoalescing, RegisterCoalescer, + "simple-register-coalescing", "Simple Register Coalescing", + false, false, true); -const PassInfo *const llvm::SimpleRegisterCoalescingID = &X; +char &llvm::SimpleRegisterCoalescingID = SimpleRegisterCoalescing::ID; void SimpleRegisterCoalescing::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); @@ -386,16 +389,12 @@ bool SimpleRegisterCoalescing::RemoveCopyByCommutingDef(const CoalescerPair &CP, if (HasOtherReachingDefs(IntA, IntB, AValNo, BValNo)) return false; - bool BHasSubRegs = false; - if (TargetRegisterInfo::isPhysicalRegister(IntB.reg)) - BHasSubRegs = *tri_->getSubRegisters(IntB.reg); - - // Abort if the subregisters of IntB.reg have values that are not simply the + // Abort if the aliases of IntB.reg have values that are not simply the // clobbers from the superreg. - if (BHasSubRegs) - for (const unsigned *SR = tri_->getSubRegisters(IntB.reg); *SR; ++SR) - if (li_->hasInterval(*SR) && - HasOtherReachingDefs(IntA, li_->getInterval(*SR), AValNo, 0)) + if (TargetRegisterInfo::isPhysicalRegister(IntB.reg)) + for (const unsigned *AS = tri_->getAliasSet(IntB.reg); *AS; ++AS) + if (li_->hasInterval(*AS) && + HasOtherReachingDefs(IntA, li_->getInterval(*AS), AValNo, 0)) return false; // If some of the uses of IntA.reg is already coalesced away, return false. @@ -412,6 +411,8 @@ bool SimpleRegisterCoalescing::RemoveCopyByCommutingDef(const CoalescerPair &CP, return false; } + DEBUG(dbgs() << "\tRemoveCopyByCommutingDef: " << *DefMI); + // At this point we have decided that it is legal to do this // transformation. Start by commuting the instruction. MachineBasicBlock *MBB = DefMI->getParent(); @@ -470,16 +471,12 @@ bool SimpleRegisterCoalescing::RemoveCopyByCommutingDef(const CoalescerPair &CP, if (Extended) UseMO.setIsKill(false); } - unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx; - if (UseMI->isCopy()) { - if (UseMI->getOperand(0).getReg() != IntB.reg || - UseMI->getOperand(0).getSubReg()) - continue; - } else if (tii_->isMoveInstr(*UseMI, SrcReg, DstReg, SrcSubIdx, DstSubIdx)){ - if (DstReg != IntB.reg || DstSubIdx) - continue; - } else + if (!UseMI->isCopy()) continue; + if (UseMI->getOperand(0).getReg() != IntB.reg || + UseMI->getOperand(0).getSubReg()) + continue; + // This copy will become a noop. If it's defining a new val#, // remove that val# as well. However this live range is being // extended to the end of the existing live range defined by the copy. @@ -504,13 +501,13 @@ bool SimpleRegisterCoalescing::RemoveCopyByCommutingDef(const CoalescerPair &CP, // Remove val#'s defined by copies that will be coalesced away. for (unsigned i = 0, e = BDeadValNos.size(); i != e; ++i) { VNInfo *DeadVNI = BDeadValNos[i]; - if (BHasSubRegs) { - for (const unsigned *SR = tri_->getSubRegisters(IntB.reg); *SR; ++SR) { - if (!li_->hasInterval(*SR)) + if (TargetRegisterInfo::isPhysicalRegister(IntB.reg)) { + for (const unsigned *AS = tri_->getAliasSet(IntB.reg); *AS; ++AS) { + if (!li_->hasInterval(*AS)) continue; - LiveInterval &SRLI = li_->getInterval(*SR); - if (const LiveRange *SRLR = SRLI.getLiveRangeContaining(DeadVNI->def)) - SRLI.removeValNo(SRLR->valno); + LiveInterval &ASLI = li_->getInterval(*AS); + if (const LiveRange *ASLR = ASLI.getLiveRangeContaining(DeadVNI->def)) + ASLI.removeValNo(ASLR->valno); } } IntB.removeValNo(BDeadValNos[i]); @@ -628,14 +625,6 @@ SimpleRegisterCoalescing::TrimLiveIntervalToLastUse(SlotIndex CopyIdx, if (DefMO.getReg() == li.reg && !DefMO.getSubReg()) DefMO.setIsDead(); } - unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx; - if (tii_->isMoveInstr(*LastUseMI, SrcReg, DstReg, SrcSubIdx, DstSubIdx) && - DstReg == li.reg && DstSubIdx == 0) { - // Last use is itself an identity code. - int DeadIdx = LastUseMI->findRegisterDefOperandIdx(li.reg, - false, false, tri_); - LastUseMI->getOperand(DeadIdx).setIsDead(); - } return true; } @@ -772,16 +761,6 @@ SimpleRegisterCoalescing::UpdateRegDefsUses(const CoalescerPair &CP) { // A PhysReg copy that won't be coalesced can perhaps be rematerialized // instead. if (DstIsPhys) { - unsigned CopySrcReg, CopyDstReg, CopySrcSubIdx, CopyDstSubIdx; - if (tii_->isMoveInstr(*UseMI, CopySrcReg, CopyDstReg, - CopySrcSubIdx, CopyDstSubIdx) && - CopySrcSubIdx == 0 && CopyDstSubIdx == 0 && - CopySrcReg != CopyDstReg && CopySrcReg == SrcReg && - CopyDstReg != DstReg && !JoinedCopies.count(UseMI) && - ReMaterializeTrivialDef(li_->getInterval(SrcReg), CopyDstReg, 0, - UseMI)) - continue; - if (UseMI->isCopy() && !UseMI->getOperand(1).getSubReg() && !UseMI->getOperand(0).getSubReg() && @@ -834,28 +813,6 @@ SimpleRegisterCoalescing::UpdateRegDefsUses(const CoalescerPair &CP) { dbgs() << li_->getInstructionIndex(UseMI) << "\t"; dbgs() << *UseMI; }); - - - // After updating the operand, check if the machine instruction has - // become a copy. If so, update its val# information. - const TargetInstrDesc &TID = UseMI->getDesc(); - if (DstIsPhys || TID.getNumDefs() != 1 || TID.getNumOperands() <= 2) - continue; - - unsigned CopySrcReg, CopyDstReg, CopySrcSubIdx, CopyDstSubIdx; - if (tii_->isMoveInstr(*UseMI, CopySrcReg, CopyDstReg, - CopySrcSubIdx, CopyDstSubIdx) && - CopySrcReg != CopyDstReg && - (TargetRegisterInfo::isVirtualRegister(CopyDstReg) || - allocatableRegs_[CopyDstReg])) { - LiveInterval &LI = li_->getInterval(CopyDstReg); - SlotIndex DefIdx = - li_->getInstructionIndex(UseMI).getDefIndex(); - if (const LiveRange *DLR = LI.getLiveRangeContaining(DefIdx)) { - if (DLR->valno->def == DefIdx) - DLR->valno->setCopy(UseMI); - } - } } } @@ -1082,13 +1039,18 @@ bool SimpleRegisterCoalescing::JoinCopy(CopyRec &TheCopy, bool &Again) { return false; // Not coalescable. } + if (DisablePhysicalJoin && CP.isPhys()) { + DEBUG(dbgs() << "\tPhysical joins disabled.\n"); + return false; + } + DEBUG(dbgs() << "\tConsidering merging %reg" << CP.getSrcReg()); // Enforce policies. if (CP.isPhys()) { DEBUG(dbgs() <<" with physreg %" << tri_->getName(CP.getDstReg()) << "\n"); // Only coalesce to allocatable physreg. - if (!allocatableRegs_[CP.getDstReg()]) { + if (!li_->isAllocatable(CP.getDstReg())) { DEBUG(dbgs() << "\tRegister is an unallocatable physreg.\n"); return false; // Not coalescable. } @@ -1137,7 +1099,6 @@ bool SimpleRegisterCoalescing::JoinCopy(CopyRec &TheCopy, bool &Again) { // happens. if (li_->hasInterval(CP.getDstReg()) && li_->getInterval(CP.getDstReg()).ranges.size() > 1000) { - mri_->setRegAllocationHint(CP.getSrcReg(), 0, CP.getDstReg()); ++numAborts; DEBUG(dbgs() << "\tPhysical register live interval too complicated, abort!\n"); @@ -1156,7 +1117,6 @@ bool SimpleRegisterCoalescing::JoinCopy(CopyRec &TheCopy, bool &Again) { ReMaterializeTrivialDef(JoinVInt, CP.getDstReg(), 0, CopyMI)) return true; - mri_->setRegAllocationHint(CP.getSrcReg(), 0, CP.getDstReg()); ++numAborts; DEBUG(dbgs() << "\tMay tie down a physical register, abort!\n"); Again = true; // May be possible to coalesce later. @@ -1543,21 +1503,19 @@ void SimpleRegisterCoalescing::CopyCoalesceInMBB(MachineBasicBlock *MBB, MachineInstr *Inst = MII++; // If this isn't a copy nor a extract_subreg, we can't join intervals. - unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx; - bool isInsUndef = false; + unsigned SrcReg, DstReg; if (Inst->isCopy()) { DstReg = Inst->getOperand(0).getReg(); SrcReg = Inst->getOperand(1).getReg(); } else if (Inst->isSubregToReg()) { DstReg = Inst->getOperand(0).getReg(); SrcReg = Inst->getOperand(2).getReg(); - } else if (!tii_->isMoveInstr(*Inst, SrcReg, DstReg, SrcSubIdx, DstSubIdx)) + } else continue; bool SrcIsPhys = TargetRegisterInfo::isPhysicalRegister(SrcReg); bool DstIsPhys = TargetRegisterInfo::isPhysicalRegister(DstReg); - if (isInsUndef || - (li_->hasInterval(SrcReg) && li_->getInterval(SrcReg).empty())) + if (li_->hasInterval(SrcReg) && li_->getInterval(SrcReg).empty()) ImpDefCopies.push_back(CopyRec(Inst, 0)); else if (SrcIsPhys || DstIsPhys) PhysCopies.push_back(CopyRec(Inst, 0)); @@ -1679,11 +1637,6 @@ SimpleRegisterCoalescing::lastRegisterUse(SlotIndex Start, MachineInstr *UseMI = Use.getParent(); if (UseMI->isIdentityCopy()) continue; - unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx; - if (tii_->isMoveInstr(*UseMI, SrcReg, DstReg, SrcSubIdx, DstSubIdx) && - SrcReg == DstReg && SrcSubIdx == DstSubIdx) - // Ignore identity copies. - continue; SlotIndex Idx = li_->getInstructionIndex(UseMI); // FIXME: Should this be Idx != UseIdx? SlotIndex() will return something // that compares higher than any other interval. @@ -1708,10 +1661,7 @@ SimpleRegisterCoalescing::lastRegisterUse(SlotIndex Start, return NULL; // Ignore identity copies. - unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx; - if (!MI->isIdentityCopy() && - !(tii_->isMoveInstr(*MI, SrcReg, DstReg, SrcSubIdx, DstSubIdx) && - SrcReg == DstReg && SrcSubIdx == DstSubIdx)) + if (!MI->isIdentityCopy()) for (unsigned i = 0, NumOps = MI->getNumOperands(); i != NumOps; ++i) { MachineOperand &Use = MI->getOperand(i); if (Use.isReg() && Use.isUse() && Use.getReg() && @@ -1747,7 +1697,6 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) { << "********** Function: " << ((Value*)mf_->getFunction())->getName() << '\n'); - allocatableRegs_ = tri_->getAllocatableSet(fn); for (TargetRegisterInfo::regclass_iterator I = tri_->regclass_begin(), E = tri_->regclass_end(); I != E; ++I) allocatableRCRegs_.insert(std::make_pair(*I, @@ -1775,30 +1724,35 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) { for (MachineBasicBlock::iterator mii = mbb->begin(), mie = mbb->end(); mii != mie; ) { MachineInstr *MI = mii; - unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx; if (JoinedCopies.count(MI)) { // Delete all coalesced copies. bool DoDelete = true; - if (!tii_->isMoveInstr(*MI, SrcReg, DstReg, SrcSubIdx, DstSubIdx)) { - assert(MI->isCopyLike() && "Unrecognized copy instruction"); - SrcReg = MI->getOperand(MI->isSubregToReg() ? 2 : 1).getReg(); - if (TargetRegisterInfo::isPhysicalRegister(SrcReg)) - // Do not delete extract_subreg, insert_subreg of physical - // registers unless the definition is dead. e.g. - // %DO = INSERT_SUBREG %D0, %S0, 1 - // or else the scavenger may complain. LowerSubregs will - // delete them later. - DoDelete = false; - } + assert(MI->isCopyLike() && "Unrecognized copy instruction"); + unsigned SrcReg = MI->getOperand(MI->isSubregToReg() ? 2 : 1).getReg(); + if (TargetRegisterInfo::isPhysicalRegister(SrcReg) && + MI->getNumOperands() > 2) + // Do not delete extract_subreg, insert_subreg of physical + // registers unless the definition is dead. e.g. + // %DO = INSERT_SUBREG %D0, %S0, 1 + // or else the scavenger may complain. LowerSubregs will + // delete them later. + DoDelete = false; + if (MI->allDefsAreDead()) { LiveInterval &li = li_->getInterval(SrcReg); if (!ShortenDeadCopySrcLiveRange(li, MI)) ShortenDeadCopyLiveRange(li, MI); DoDelete = true; } - if (!DoDelete) + if (!DoDelete) { + // We need the instruction to adjust liveness, so make it a KILL. + if (MI->isSubregToReg()) { + MI->RemoveOperand(3); + MI->RemoveOperand(1); + } + MI->setDesc(tii_->get(TargetOpcode::KILL)); mii = llvm::next(mii); - else { + } else { li_->RemoveMachineInstrFromMaps(MI); mii = mbbi->erase(mii); ++numPeep; @@ -1840,9 +1794,8 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) { } // If the move will be an identity move delete it - bool isMove= tii_->isMoveInstr(*MI, SrcReg, DstReg, SrcSubIdx, DstSubIdx); - if (MI->isIdentityCopy() || - (isMove && SrcReg == DstReg && SrcSubIdx == DstSubIdx)) { + if (MI->isIdentityCopy()) { + unsigned SrcReg = MI->getOperand(1).getReg(); if (li_->hasInterval(SrcReg)) { LiveInterval &RegInt = li_->getInterval(SrcReg); // If def of this move instruction is dead, remove its live range diff --git a/lib/CodeGen/SimpleRegisterCoalescing.h b/lib/CodeGen/SimpleRegisterCoalescing.h index e154da6..855bdb9 100644 --- a/lib/CodeGen/SimpleRegisterCoalescing.h +++ b/lib/CodeGen/SimpleRegisterCoalescing.h @@ -47,7 +47,6 @@ namespace llvm { const MachineLoopInfo* loopInfo; AliasAnalysis *AA; - BitVector allocatableRegs_; DenseMap allocatableRCRegs_; /// JoinedCopies - Keep track of copies eliminated due to coalescing. @@ -64,7 +63,7 @@ namespace llvm { public: static char ID; // Pass identifcation, replacement for typeid - SimpleRegisterCoalescing() : MachineFunctionPass(&ID) {} + SimpleRegisterCoalescing() : MachineFunctionPass(ID) {} struct InstrSlots { enum { diff --git a/lib/CodeGen/SjLjEHPrepare.cpp b/lib/CodeGen/SjLjEHPrepare.cpp index e90869d..b637980 100644 --- a/lib/CodeGen/SjLjEHPrepare.cpp +++ b/lib/CodeGen/SjLjEHPrepare.cpp @@ -58,7 +58,7 @@ namespace { public: static char ID; // Pass identification, replacement for typeid explicit SjLjEHPass(const TargetLowering *tli = NULL) - : FunctionPass(&ID), TLI(tli) { } + : FunctionPass(ID), TLI(tli) { } bool doInitialization(Module &M); bool runOnFunction(Function &F); diff --git a/lib/CodeGen/SlotIndexes.cpp b/lib/CodeGen/SlotIndexes.cpp index 7a227cf..1bc148f 100644 --- a/lib/CodeGen/SlotIndexes.cpp +++ b/lib/CodeGen/SlotIndexes.cpp @@ -40,7 +40,8 @@ namespace { } char SlotIndexes::ID = 0; -static RegisterPass X("slotindexes", "Slot index numbering"); +INITIALIZE_PASS(SlotIndexes, "slotindexes", + "Slot index numbering", false, false); IndexListEntry* IndexListEntry::getEmptyKeyEntry() { return &*IndexListEntryEmptyKey; diff --git a/lib/CodeGen/Spiller.cpp b/lib/CodeGen/Spiller.cpp index 56bcb28..59d5ab3 100644 --- a/lib/CodeGen/Spiller.cpp +++ b/lib/CodeGen/Spiller.cpp @@ -15,6 +15,7 @@ #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" @@ -49,29 +50,31 @@ namespace { /// Utility class for spillers. class SpillerBase : public Spiller { protected: + MachineFunctionPass *pass; MachineFunction *mf; + VirtRegMap *vrm; LiveIntervals *lis; MachineFrameInfo *mfi; MachineRegisterInfo *mri; const TargetInstrInfo *tii; const TargetRegisterInfo *tri; - VirtRegMap *vrm; /// Construct a spiller base. - SpillerBase(MachineFunction *mf, LiveIntervals *lis, VirtRegMap *vrm) - : mf(mf), lis(lis), vrm(vrm) + SpillerBase(MachineFunctionPass &pass, MachineFunction &mf, VirtRegMap &vrm) + : pass(&pass), mf(&mf), vrm(&vrm) { - mfi = mf->getFrameInfo(); - mri = &mf->getRegInfo(); - tii = mf->getTarget().getInstrInfo(); - tri = mf->getTarget().getRegisterInfo(); + lis = &pass.getAnalysis(); + mfi = mf.getFrameInfo(); + mri = &mf.getRegInfo(); + tii = mf.getTarget().getInstrInfo(); + tri = mf.getTarget().getRegisterInfo(); } /// Add spill ranges for every use/def of the live interval, inserting loads /// immediately before each use, and stores after each def. No folding or /// remat is attempted. void trivialSpillEverywhere(LiveInterval *li, - std::vector &newIntervals) { + SmallVectorImpl &newIntervals) { DEBUG(dbgs() << "Spilling everywhere " << *li << "\n"); assert(li->weight != HUGE_VALF && @@ -173,13 +176,13 @@ namespace { class TrivialSpiller : public SpillerBase { public: - TrivialSpiller(MachineFunction *mf, LiveIntervals *lis, VirtRegMap *vrm) - : SpillerBase(mf, lis, vrm) {} + TrivialSpiller(MachineFunctionPass &pass, MachineFunction &mf, + VirtRegMap &vrm) + : SpillerBase(pass, mf, vrm) {} void spill(LiveInterval *li, - std::vector &newIntervals, - SmallVectorImpl &, - SlotIndex*) { + SmallVectorImpl &newIntervals, + SmallVectorImpl &) { // Ignore spillIs - we don't use it. trivialSpillEverywhere(li, newIntervals); } @@ -193,18 +196,19 @@ namespace { class StandardSpiller : public Spiller { protected: LiveIntervals *lis; - const MachineLoopInfo *loopInfo; + MachineLoopInfo *loopInfo; VirtRegMap *vrm; public: - StandardSpiller(LiveIntervals *lis, const MachineLoopInfo *loopInfo, - VirtRegMap *vrm) - : lis(lis), loopInfo(loopInfo), vrm(vrm) {} + StandardSpiller(MachineFunctionPass &pass, MachineFunction &mf, + VirtRegMap &vrm) + : lis(&pass.getAnalysis()), + loopInfo(pass.getAnalysisIfAvailable()), + vrm(&vrm) {} /// Falls back on LiveIntervals::addIntervalsForSpills. void spill(LiveInterval *li, - std::vector &newIntervals, - SmallVectorImpl &spillIs, - SlotIndex*) { + SmallVectorImpl &newIntervals, + SmallVectorImpl &spillIs) { std::vector added = lis->addIntervalsForSpills(*li, spillIs, loopInfo, *vrm); newIntervals.insert(newIntervals.end(), added.begin(), added.end()); @@ -221,23 +225,21 @@ namespace { /// then the spiller falls back on the standard spilling mechanism. class SplittingSpiller : public StandardSpiller { public: - SplittingSpiller(MachineFunction *mf, LiveIntervals *lis, - const MachineLoopInfo *loopInfo, VirtRegMap *vrm) - : StandardSpiller(lis, loopInfo, vrm) { - - mri = &mf->getRegInfo(); - tii = mf->getTarget().getInstrInfo(); - tri = mf->getTarget().getRegisterInfo(); + SplittingSpiller(MachineFunctionPass &pass, MachineFunction &mf, + VirtRegMap &vrm) + : StandardSpiller(pass, mf, vrm) { + mri = &mf.getRegInfo(); + tii = mf.getTarget().getInstrInfo(); + tri = mf.getTarget().getRegisterInfo(); } void spill(LiveInterval *li, - std::vector &newIntervals, - SmallVectorImpl &spillIs, - SlotIndex *earliestStart) { + SmallVectorImpl &newIntervals, + SmallVectorImpl &spillIs) { if (worthTryingToSplit(li)) - tryVNISplit(li, earliestStart); + tryVNISplit(li); else - StandardSpiller::spill(li, newIntervals, spillIs, earliestStart); + StandardSpiller::spill(li, newIntervals, spillIs); } private: @@ -252,8 +254,7 @@ private: } /// Try to break a LiveInterval into its component values. - std::vector tryVNISplit(LiveInterval *li, - SlotIndex *earliestStart) { + std::vector tryVNISplit(LiveInterval *li) { DEBUG(dbgs() << "Trying VNI split of %reg" << *li << "\n"); @@ -277,10 +278,6 @@ private: DEBUG(dbgs() << *splitInterval << "\n"); added.push_back(splitInterval); alreadySplit.insert(splitInterval); - if (earliestStart != 0) { - if (splitInterval->beginIndex() < *earliestStart) - *earliestStart = splitInterval->beginIndex(); - } } else { DEBUG(dbgs() << "0\n"); } @@ -293,10 +290,6 @@ private: if (!li->empty()) { added.push_back(li); alreadySplit.insert(li); - if (earliestStart != 0) { - if (li->beginIndex() < *earliestStart) - *earliestStart = li->beginIndex(); - } } return added; @@ -506,20 +499,19 @@ private: namespace llvm { -Spiller *createInlineSpiller(MachineFunction*, - LiveIntervals*, - const MachineLoopInfo*, - VirtRegMap*); +Spiller *createInlineSpiller(MachineFunctionPass &pass, + MachineFunction &mf, + VirtRegMap &vrm); } -llvm::Spiller* llvm::createSpiller(MachineFunction *mf, LiveIntervals *lis, - const MachineLoopInfo *loopInfo, - VirtRegMap *vrm) { +llvm::Spiller* llvm::createSpiller(MachineFunctionPass &pass, + MachineFunction &mf, + VirtRegMap &vrm) { switch (spillerOpt) { default: assert(0 && "unknown spiller"); - case trivial: return new TrivialSpiller(mf, lis, vrm); - case standard: return new StandardSpiller(lis, loopInfo, vrm); - case splitting: return new SplittingSpiller(mf, lis, loopInfo, vrm); - case inline_: return createInlineSpiller(mf, lis, loopInfo, vrm); + case trivial: return new TrivialSpiller(pass, mf, vrm); + case standard: return new StandardSpiller(pass, mf, vrm); + case splitting: return new SplittingSpiller(pass, mf, vrm); + case inline_: return createInlineSpiller(pass, mf, vrm); } } diff --git a/lib/CodeGen/Spiller.h b/lib/CodeGen/Spiller.h index 450447b..59bc0ec 100644 --- a/lib/CodeGen/Spiller.h +++ b/lib/CodeGen/Spiller.h @@ -11,19 +11,14 @@ #define LLVM_CODEGEN_SPILLER_H #include "llvm/ADT/SmallVector.h" -#include namespace llvm { class LiveInterval; - class LiveIntervals; - class LiveStacks; class MachineFunction; - class MachineInstr; - class MachineLoopInfo; + class MachineFunctionPass; class SlotIndex; class VirtRegMap; - class VNInfo; /// Spiller interface. /// @@ -40,18 +35,16 @@ namespace llvm { /// @param spillIs A list of intervals that are about to be spilled, /// and so cannot be used for remat etc. /// @param newIntervals The newly created intervals will be appended here. - /// @param earliestIndex The earliest point for splitting. (OK, it's another - /// pointer to the allocator guts). virtual void spill(LiveInterval *li, - std::vector &newIntervals, - SmallVectorImpl &spillIs, - SlotIndex *earliestIndex = 0) = 0; + SmallVectorImpl &newIntervals, + SmallVectorImpl &spillIs) = 0; }; /// Create and return a spiller object, as specified on the command line. - Spiller* createSpiller(MachineFunction *mf, LiveIntervals *li, - const MachineLoopInfo *loopInfo, VirtRegMap *vrm); + Spiller* createSpiller(MachineFunctionPass &pass, + MachineFunction &mf, + VirtRegMap &vrm); } #endif diff --git a/lib/CodeGen/SplitKit.cpp b/lib/CodeGen/SplitKit.cpp new file mode 100644 index 0000000..29474f0 --- /dev/null +++ b/lib/CodeGen/SplitKit.cpp @@ -0,0 +1,1097 @@ +//===---------- SplitKit.cpp - Toolkit for splitting live ranges ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the SplitAnalysis class as well as mutator functions for +// live range splitting. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "splitter" +#include "SplitKit.h" +#include "VirtRegMap.h" +#include "llvm/CodeGen/CalcSpillWeights.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" + +using namespace llvm; + +static cl::opt +AllowSplit("spiller-splits-edges", + cl::desc("Allow critical edge splitting during spilling")); + +//===----------------------------------------------------------------------===// +// Split Analysis +//===----------------------------------------------------------------------===// + +SplitAnalysis::SplitAnalysis(const MachineFunction &mf, + const LiveIntervals &lis, + const MachineLoopInfo &mli) + : mf_(mf), + lis_(lis), + loops_(mli), + tii_(*mf.getTarget().getInstrInfo()), + curli_(0) {} + +void SplitAnalysis::clear() { + usingInstrs_.clear(); + usingBlocks_.clear(); + usingLoops_.clear(); + curli_ = 0; +} + +bool SplitAnalysis::canAnalyzeBranch(const MachineBasicBlock *MBB) { + MachineBasicBlock *T, *F; + SmallVector Cond; + return !tii_.AnalyzeBranch(const_cast(*MBB), T, F, Cond); +} + +/// analyzeUses - Count instructions, basic blocks, and loops using curli. +void SplitAnalysis::analyzeUses() { + const MachineRegisterInfo &MRI = mf_.getRegInfo(); + for (MachineRegisterInfo::reg_iterator I = MRI.reg_begin(curli_->reg); + MachineInstr *MI = I.skipInstruction();) { + if (MI->isDebugValue() || !usingInstrs_.insert(MI)) + continue; + MachineBasicBlock *MBB = MI->getParent(); + if (usingBlocks_[MBB]++) + continue; + if (MachineLoop *Loop = loops_.getLoopFor(MBB)) + usingLoops_[Loop]++; + } + DEBUG(dbgs() << " counted " + << usingInstrs_.size() << " instrs, " + << usingBlocks_.size() << " blocks, " + << usingLoops_.size() << " loops.\n"); +} + +/// removeUse - Update statistics by noting that MI no longer uses curli. +void SplitAnalysis::removeUse(const MachineInstr *MI) { + if (!usingInstrs_.erase(MI)) + return; + + // Decrement MBB count. + const MachineBasicBlock *MBB = MI->getParent(); + BlockCountMap::iterator bi = usingBlocks_.find(MBB); + assert(bi != usingBlocks_.end() && "MBB missing"); + assert(bi->second && "0 count in map"); + if (--bi->second) + return; + // No more uses in MBB. + usingBlocks_.erase(bi); + + // Decrement loop count. + MachineLoop *Loop = loops_.getLoopFor(MBB); + if (!Loop) + return; + LoopCountMap::iterator li = usingLoops_.find(Loop); + assert(li != usingLoops_.end() && "Loop missing"); + assert(li->second && "0 count in map"); + if (--li->second) + return; + // No more blocks in Loop. + usingLoops_.erase(li); +} + +// Get three sets of basic blocks surrounding a loop: Blocks inside the loop, +// predecessor blocks, and exit blocks. +void SplitAnalysis::getLoopBlocks(const MachineLoop *Loop, LoopBlocks &Blocks) { + Blocks.clear(); + + // Blocks in the loop. + Blocks.Loop.insert(Loop->block_begin(), Loop->block_end()); + + // Predecessor blocks. + const MachineBasicBlock *Header = Loop->getHeader(); + for (MachineBasicBlock::const_pred_iterator I = Header->pred_begin(), + E = Header->pred_end(); I != E; ++I) + if (!Blocks.Loop.count(*I)) + Blocks.Preds.insert(*I); + + // Exit blocks. + for (MachineLoop::block_iterator I = Loop->block_begin(), + E = Loop->block_end(); I != E; ++I) { + const MachineBasicBlock *MBB = *I; + for (MachineBasicBlock::const_succ_iterator SI = MBB->succ_begin(), + SE = MBB->succ_end(); SI != SE; ++SI) + if (!Blocks.Loop.count(*SI)) + Blocks.Exits.insert(*SI); + } +} + +/// analyzeLoopPeripheralUse - Return an enum describing how curli_ is used in +/// and around the Loop. +SplitAnalysis::LoopPeripheralUse SplitAnalysis:: +analyzeLoopPeripheralUse(const SplitAnalysis::LoopBlocks &Blocks) { + LoopPeripheralUse use = ContainedInLoop; + for (BlockCountMap::iterator I = usingBlocks_.begin(), E = usingBlocks_.end(); + I != E; ++I) { + const MachineBasicBlock *MBB = I->first; + // Is this a peripheral block? + if (use < MultiPeripheral && + (Blocks.Preds.count(MBB) || Blocks.Exits.count(MBB))) { + if (I->second > 1) use = MultiPeripheral; + else use = SinglePeripheral; + continue; + } + // Is it a loop block? + if (Blocks.Loop.count(MBB)) + continue; + // It must be an unrelated block. + return OutsideLoop; + } + return use; +} + +/// getCriticalExits - It may be necessary to partially break critical edges +/// leaving the loop if an exit block has phi uses of curli. Collect the exit +/// blocks that need special treatment into CriticalExits. +void SplitAnalysis::getCriticalExits(const SplitAnalysis::LoopBlocks &Blocks, + BlockPtrSet &CriticalExits) { + CriticalExits.clear(); + + // A critical exit block contains a phi def of curli, and has a predecessor + // that is not in the loop nor a loop predecessor. + // For such an exit block, the edges carrying the new variable must be moved + // to a new pre-exit block. + for (BlockPtrSet::iterator I = Blocks.Exits.begin(), E = Blocks.Exits.end(); + I != E; ++I) { + const MachineBasicBlock *Succ = *I; + SlotIndex SuccIdx = lis_.getMBBStartIdx(Succ); + VNInfo *SuccVNI = curli_->getVNInfoAt(SuccIdx); + // This exit may not have curli live in at all. No need to split. + if (!SuccVNI) + continue; + // If this is not a PHI def, it is either using a value from before the + // loop, or a value defined inside the loop. Both are safe. + if (!SuccVNI->isPHIDef() || SuccVNI->def.getBaseIndex() != SuccIdx) + continue; + // This exit block does have a PHI. Does it also have a predecessor that is + // not a loop block or loop predecessor? + for (MachineBasicBlock::const_pred_iterator PI = Succ->pred_begin(), + PE = Succ->pred_end(); PI != PE; ++PI) { + const MachineBasicBlock *Pred = *PI; + if (Blocks.Loop.count(Pred) || Blocks.Preds.count(Pred)) + continue; + // This is a critical exit block, and we need to split the exit edge. + CriticalExits.insert(Succ); + break; + } + } +} + +/// canSplitCriticalExits - Return true if it is possible to insert new exit +/// blocks before the blocks in CriticalExits. +bool +SplitAnalysis::canSplitCriticalExits(const SplitAnalysis::LoopBlocks &Blocks, + BlockPtrSet &CriticalExits) { + // If we don't allow critical edge splitting, require no critical exits. + if (!AllowSplit) + return CriticalExits.empty(); + + for (BlockPtrSet::iterator I = CriticalExits.begin(), E = CriticalExits.end(); + I != E; ++I) { + const MachineBasicBlock *Succ = *I; + // We want to insert a new pre-exit MBB before Succ, and change all the + // in-loop blocks to branch to the pre-exit instead of Succ. + // Check that all the in-loop predecessors can be changed. + for (MachineBasicBlock::const_pred_iterator PI = Succ->pred_begin(), + PE = Succ->pred_end(); PI != PE; ++PI) { + const MachineBasicBlock *Pred = *PI; + // The external predecessors won't be altered. + if (!Blocks.Loop.count(Pred) && !Blocks.Preds.count(Pred)) + continue; + if (!canAnalyzeBranch(Pred)) + return false; + } + + // If Succ's layout predecessor falls through, that too must be analyzable. + // We need to insert the pre-exit block in the gap. + MachineFunction::const_iterator MFI = Succ; + if (MFI == mf_.begin()) + continue; + if (!canAnalyzeBranch(--MFI)) + return false; + } + // No problems found. + return true; +} + +void SplitAnalysis::analyze(const LiveInterval *li) { + clear(); + curli_ = li; + analyzeUses(); +} + +const MachineLoop *SplitAnalysis::getBestSplitLoop() { + assert(curli_ && "Call analyze() before getBestSplitLoop"); + if (usingLoops_.empty()) + return 0; + + LoopPtrSet Loops, SecondLoops; + LoopBlocks Blocks; + BlockPtrSet CriticalExits; + + // Find first-class and second class candidate loops. + // We prefer to split around loops where curli is used outside the periphery. + for (LoopCountMap::const_iterator I = usingLoops_.begin(), + E = usingLoops_.end(); I != E; ++I) { + const MachineLoop *Loop = I->first; + getLoopBlocks(Loop, Blocks); + + // FIXME: We need an SSA updater to properly handle multiple exit blocks. + if (Blocks.Exits.size() > 1) { + DEBUG(dbgs() << " multiple exits from " << *Loop); + continue; + } + + LoopPtrSet *LPS = 0; + switch(analyzeLoopPeripheralUse(Blocks)) { + case OutsideLoop: + LPS = &Loops; + break; + case MultiPeripheral: + LPS = &SecondLoops; + break; + case ContainedInLoop: + DEBUG(dbgs() << " contained in " << *Loop); + continue; + case SinglePeripheral: + DEBUG(dbgs() << " single peripheral use in " << *Loop); + continue; + } + // Will it be possible to split around this loop? + getCriticalExits(Blocks, CriticalExits); + DEBUG(dbgs() << " " << CriticalExits.size() << " critical exits from " + << *Loop); + if (!canSplitCriticalExits(Blocks, CriticalExits)) + continue; + // This is a possible split. + assert(LPS); + LPS->insert(Loop); + } + + DEBUG(dbgs() << " getBestSplitLoop found " << Loops.size() << " + " + << SecondLoops.size() << " candidate loops.\n"); + + // If there are no first class loops available, look at second class loops. + if (Loops.empty()) + Loops = SecondLoops; + + if (Loops.empty()) + return 0; + + // Pick the earliest loop. + // FIXME: Are there other heuristics to consider? + const MachineLoop *Best = 0; + SlotIndex BestIdx; + for (LoopPtrSet::const_iterator I = Loops.begin(), E = Loops.end(); I != E; + ++I) { + SlotIndex Idx = lis_.getMBBStartIdx((*I)->getHeader()); + if (!Best || Idx < BestIdx) + Best = *I, BestIdx = Idx; + } + DEBUG(dbgs() << " getBestSplitLoop found " << *Best); + return Best; +} + +/// getMultiUseBlocks - if curli has more than one use in a basic block, it +/// may be an advantage to split curli for the duration of the block. +bool SplitAnalysis::getMultiUseBlocks(BlockPtrSet &Blocks) { + // If curli is local to one block, there is no point to splitting it. + if (usingBlocks_.size() <= 1) + return false; + // Add blocks with multiple uses. + for (BlockCountMap::iterator I = usingBlocks_.begin(), E = usingBlocks_.end(); + I != E; ++I) + switch (I->second) { + case 0: + case 1: + continue; + case 2: { + // It doesn't pay to split a 2-instr block if it redefines curli. + VNInfo *VN1 = curli_->getVNInfoAt(lis_.getMBBStartIdx(I->first)); + VNInfo *VN2 = + curli_->getVNInfoAt(lis_.getMBBEndIdx(I->first).getPrevIndex()); + // live-in and live-out with a different value. + if (VN1 && VN2 && VN1 != VN2) + continue; + } // Fall through. + default: + Blocks.insert(I->first); + } + return !Blocks.empty(); +} + +//===----------------------------------------------------------------------===// +// LiveIntervalMap +//===----------------------------------------------------------------------===// + +// defValue - Introduce a li_ def for ParentVNI that could be later than +// ParentVNI->def. +VNInfo *LiveIntervalMap::defValue(const VNInfo *ParentVNI, SlotIndex Idx) { + assert(ParentVNI && "Mapping NULL value"); + assert(Idx.isValid() && "Invalid SlotIndex"); + assert(parentli_.getVNInfoAt(Idx) == ParentVNI && "Bad ParentVNI"); + + // Is this a simple 1-1 mapping? Not likely. + if (Idx == ParentVNI->def) + return mapValue(ParentVNI, Idx); + + // This is a complex def. Mark with a NULL in valueMap. + VNInfo *OldVNI = + valueMap_.insert( + ValueMap::value_type(ParentVNI, static_cast(0))).first->second; + // The static_cast is only needed to work around a bug in an + // old version of the C++0x standard which the following compilers + // implemented and have yet to fix: + // + // Microsoft Visual Studio 2010 Version 10.0.30319.1 RTMRel + // Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 + // + // If/When we move to C++0x, this can be replaced by nullptr. + (void)OldVNI; + assert(OldVNI == 0 && "Simple/Complex values mixed"); + + // Should we insert a minimal snippet of VNI LiveRange, or can we count on + // callers to do that? We need it for lookups of complex values. + VNInfo *VNI = li_.getNextValue(Idx, 0, true, lis_.getVNInfoAllocator()); + return VNI; +} + +// mapValue - Find the mapped value for ParentVNI at Idx. +// Potentially create phi-def values. +VNInfo *LiveIntervalMap::mapValue(const VNInfo *ParentVNI, SlotIndex Idx) { + assert(ParentVNI && "Mapping NULL value"); + assert(Idx.isValid() && "Invalid SlotIndex"); + assert(parentli_.getVNInfoAt(Idx) == ParentVNI && "Bad ParentVNI"); + + // Use insert for lookup, so we can add missing values with a second lookup. + std::pair InsP = + valueMap_.insert(ValueMap::value_type(ParentVNI, static_cast(0))); + // The static_cast is only needed to work around a bug in an + // old version of the C++0x standard which the following compilers + // implemented and have yet to fix: + // + // Microsoft Visual Studio 2010 Version 10.0.30319.1 RTMRel + // Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 + // + // If/When we move to C++0x, this can be replaced by nullptr. + + // This was an unknown value. Create a simple mapping. + if (InsP.second) + return InsP.first->second = li_.createValueCopy(ParentVNI, + lis_.getVNInfoAllocator()); + // This was a simple mapped value. + if (InsP.first->second) + return InsP.first->second; + + // This is a complex mapped value. There may be multiple defs, and we may need + // to create phi-defs. + MachineBasicBlock *IdxMBB = lis_.getMBBFromIndex(Idx); + assert(IdxMBB && "No MBB at Idx"); + + // Is there a def in the same MBB we can extend? + if (VNInfo *VNI = extendTo(IdxMBB, Idx)) + return VNI; + + // Now for the fun part. We know that ParentVNI potentially has multiple defs, + // and we may need to create even more phi-defs to preserve VNInfo SSA form. + // Perform a depth-first search for predecessor blocks where we know the + // dominating VNInfo. Insert phi-def VNInfos along the path back to IdxMBB. + + // Track MBBs where we have created or learned the dominating value. + // This may change during the DFS as we create new phi-defs. + typedef DenseMap MBBValueMap; + MBBValueMap DomValue; + + for (idf_iterator + IDFI = idf_begin(IdxMBB), + IDFE = idf_end(IdxMBB); IDFI != IDFE;) { + MachineBasicBlock *MBB = *IDFI; + SlotIndex End = lis_.getMBBEndIdx(MBB); + + // We are operating on the restricted CFG where ParentVNI is live. + if (parentli_.getVNInfoAt(End.getPrevSlot()) != ParentVNI) { + IDFI.skipChildren(); + continue; + } + + // Do we have a dominating value in this block? + VNInfo *VNI = extendTo(MBB, End); + if (!VNI) { + ++IDFI; + continue; + } + + // Yes, VNI dominates MBB. Track the path back to IdxMBB, creating phi-defs + // as needed along the way. + for (unsigned PI = IDFI.getPathLength()-1; PI != 0; --PI) { + // Start from MBB's immediate successor. End at IdxMBB. + MachineBasicBlock *Succ = IDFI.getPath(PI-1); + std::pair InsP = + DomValue.insert(MBBValueMap::value_type(Succ, VNI)); + + // This is the first time we backtrack to Succ. + if (InsP.second) + continue; + + // We reached Succ again with the same VNI. Nothing is going to change. + VNInfo *OVNI = InsP.first->second; + if (OVNI == VNI) + break; + + // Succ already has a phi-def. No need to continue. + SlotIndex Start = lis_.getMBBStartIdx(Succ); + if (OVNI->def == Start) + break; + + // We have a collision between the old and new VNI at Succ. That means + // neither dominates and we need a new phi-def. + VNI = li_.getNextValue(Start, 0, true, lis_.getVNInfoAllocator()); + VNI->setIsPHIDef(true); + InsP.first->second = VNI; + + // Replace OVNI with VNI in the remaining path. + for (; PI > 1 ; --PI) { + MBBValueMap::iterator I = DomValue.find(IDFI.getPath(PI-2)); + if (I == DomValue.end() || I->second != OVNI) + break; + I->second = VNI; + } + } + + // No need to search the children, we found a dominating value. + IDFI.skipChildren(); + } + + // The search should at least find a dominating value for IdxMBB. + assert(!DomValue.empty() && "Couldn't find a reaching definition"); + + // Since we went through the trouble of a full DFS visiting all reaching defs, + // the values in DomValue are now accurate. No more phi-defs are needed for + // these blocks, so we can color the live ranges. + // This makes the next mapValue call much faster. + VNInfo *IdxVNI = 0; + for (MBBValueMap::iterator I = DomValue.begin(), E = DomValue.end(); I != E; + ++I) { + MachineBasicBlock *MBB = I->first; + VNInfo *VNI = I->second; + SlotIndex Start = lis_.getMBBStartIdx(MBB); + if (MBB == IdxMBB) { + // Don't add full liveness to IdxMBB, stop at Idx. + if (Start != Idx) + li_.addRange(LiveRange(Start, Idx, VNI)); + // The caller had better add some liveness to IdxVNI, or it leaks. + IdxVNI = VNI; + } else + li_.addRange(LiveRange(Start, lis_.getMBBEndIdx(MBB), VNI)); + } + + assert(IdxVNI && "Didn't find value for Idx"); + return IdxVNI; +} + +// extendTo - Find the last li_ value defined in MBB at or before Idx. The +// parentli_ is assumed to be live at Idx. Extend the live range to Idx. +// Return the found VNInfo, or NULL. +VNInfo *LiveIntervalMap::extendTo(MachineBasicBlock *MBB, SlotIndex Idx) { + LiveInterval::iterator I = std::upper_bound(li_.begin(), li_.end(), Idx); + if (I == li_.begin()) + return 0; + --I; + if (I->start < lis_.getMBBStartIdx(MBB)) + return 0; + if (I->end < Idx) + I->end = Idx; + return I->valno; +} + +// addSimpleRange - Add a simple range from parentli_ to li_. +// ParentVNI must be live in the [Start;End) interval. +void LiveIntervalMap::addSimpleRange(SlotIndex Start, SlotIndex End, + const VNInfo *ParentVNI) { + VNInfo *VNI = mapValue(ParentVNI, Start); + // A simple mappoing is easy. + if (VNI->def == ParentVNI->def) { + li_.addRange(LiveRange(Start, End, VNI)); + return; + } + + // ParentVNI is a complex value. We must map per MBB. + MachineFunction::iterator MBB = lis_.getMBBFromIndex(Start); + MachineFunction::iterator MBBE = lis_.getMBBFromIndex(End); + + if (MBB == MBBE) { + li_.addRange(LiveRange(Start, End, VNI)); + return; + } + + // First block. + li_.addRange(LiveRange(Start, lis_.getMBBEndIdx(MBB), VNI)); + + // Run sequence of full blocks. + for (++MBB; MBB != MBBE; ++MBB) { + Start = lis_.getMBBStartIdx(MBB); + li_.addRange(LiveRange(Start, lis_.getMBBEndIdx(MBB), + mapValue(ParentVNI, Start))); + } + + // Final block. + Start = lis_.getMBBStartIdx(MBB); + if (Start != End) + li_.addRange(LiveRange(Start, End, mapValue(ParentVNI, Start))); +} + +/// addRange - Add live ranges to li_ where [Start;End) intersects parentli_. +/// All needed values whose def is not inside [Start;End) must be defined +/// beforehand so mapValue will work. +void LiveIntervalMap::addRange(SlotIndex Start, SlotIndex End) { + LiveInterval::const_iterator B = parentli_.begin(), E = parentli_.end(); + LiveInterval::const_iterator I = std::lower_bound(B, E, Start); + + // Check if --I begins before Start and overlaps. + if (I != B) { + --I; + if (I->end > Start) + addSimpleRange(Start, std::min(End, I->end), I->valno); + ++I; + } + + // The remaining ranges begin after Start. + for (;I != E && I->start < End; ++I) + addSimpleRange(I->start, std::min(End, I->end), I->valno); +} + +//===----------------------------------------------------------------------===// +// Split Editor +//===----------------------------------------------------------------------===// + +/// Create a new SplitEditor for editing the LiveInterval analyzed by SA. +SplitEditor::SplitEditor(SplitAnalysis &sa, LiveIntervals &lis, VirtRegMap &vrm, + SmallVectorImpl &intervals) + : sa_(sa), lis_(lis), vrm_(vrm), + mri_(vrm.getMachineFunction().getRegInfo()), + tii_(*vrm.getMachineFunction().getTarget().getInstrInfo()), + curli_(sa_.getCurLI()), + dupli_(0), openli_(0), + intervals_(intervals), + firstInterval(intervals_.size()) +{ + assert(curli_ && "SplitEditor created from empty SplitAnalysis"); + + // Make sure curli_ is assigned a stack slot, so all our intervals get the + // same slot as curli_. + if (vrm_.getStackSlot(curli_->reg) == VirtRegMap::NO_STACK_SLOT) + vrm_.assignVirt2StackSlot(curli_->reg); + +} + +LiveInterval *SplitEditor::createInterval() { + unsigned curli = sa_.getCurLI()->reg; + unsigned Reg = mri_.createVirtualRegister(mri_.getRegClass(curli)); + LiveInterval &Intv = lis_.getOrCreateInterval(Reg); + vrm_.grow(); + vrm_.assignVirt2StackSlot(Reg, vrm_.getStackSlot(curli)); + return &Intv; +} + +LiveInterval *SplitEditor::getDupLI() { + if (!dupli_) { + // Create an interval for dupli that is a copy of curli. + dupli_ = createInterval(); + dupli_->Copy(*curli_, &mri_, lis_.getVNInfoAllocator()); + } + return dupli_; +} + +VNInfo *SplitEditor::mapValue(const VNInfo *curliVNI) { + VNInfo *&VNI = valueMap_[curliVNI]; + if (!VNI) + VNI = openli_->createValueCopy(curliVNI, lis_.getVNInfoAllocator()); + return VNI; +} + +/// Insert a COPY instruction curli -> li. Allocate a new value from li +/// defined by the COPY. Note that rewrite() will deal with the curli +/// register, so this function can be used to copy from any interval - openli, +/// curli, or dupli. +VNInfo *SplitEditor::insertCopy(LiveInterval &LI, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) { + MachineInstr *MI = BuildMI(MBB, I, DebugLoc(), tii_.get(TargetOpcode::COPY), + LI.reg).addReg(curli_->reg); + SlotIndex DefIdx = lis_.InsertMachineInstrInMaps(MI).getDefIndex(); + return LI.getNextValue(DefIdx, MI, true, lis_.getVNInfoAllocator()); +} + +/// Create a new virtual register and live interval. +void SplitEditor::openIntv() { + assert(!openli_ && "Previous LI not closed before openIntv"); + openli_ = createInterval(); + intervals_.push_back(openli_); + liveThrough_ = false; +} + +/// enterIntvBefore - Enter openli before the instruction at Idx. If curli is +/// not live before Idx, a COPY is not inserted. +void SplitEditor::enterIntvBefore(SlotIndex Idx) { + assert(openli_ && "openIntv not called before enterIntvBefore"); + + // Copy from curli_ if it is live. + if (VNInfo *CurVNI = curli_->getVNInfoAt(Idx.getUseIndex())) { + MachineInstr *MI = lis_.getInstructionFromIndex(Idx); + assert(MI && "enterIntvBefore called with invalid index"); + VNInfo *VNI = insertCopy(*openli_, *MI->getParent(), MI); + openli_->addRange(LiveRange(VNI->def, Idx.getDefIndex(), VNI)); + + // Make sure CurVNI is properly mapped. + VNInfo *&mapVNI = valueMap_[CurVNI]; + // We dont have SSA update yet, so only one entry per value is allowed. + assert(!mapVNI && "enterIntvBefore called more than once for the same value"); + mapVNI = VNI; + } + DEBUG(dbgs() << " enterIntvBefore " << Idx << ": " << *openli_ << '\n'); +} + +/// enterIntvAtEnd - Enter openli at the end of MBB. +/// PhiMBB is a successor inside openli where a PHI value is created. +/// Currently, all entries must share the same PhiMBB. +void SplitEditor::enterIntvAtEnd(MachineBasicBlock &A, MachineBasicBlock &B) { + assert(openli_ && "openIntv not called before enterIntvAtEnd"); + + SlotIndex EndA = lis_.getMBBEndIdx(&A); + VNInfo *CurVNIA = curli_->getVNInfoAt(EndA.getPrevIndex()); + if (!CurVNIA) { + DEBUG(dbgs() << " enterIntvAtEnd, curli not live out of BB#" + << A.getNumber() << ".\n"); + return; + } + + // Add a phi kill value and live range out of A. + VNInfo *VNIA = insertCopy(*openli_, A, A.getFirstTerminator()); + openli_->addRange(LiveRange(VNIA->def, EndA, VNIA)); + + // FIXME: If this is the only entry edge, we don't need the extra PHI value. + // FIXME: If there are multiple entry blocks (so not a loop), we need proper + // SSA update. + + // Now look at the start of B. + SlotIndex StartB = lis_.getMBBStartIdx(&B); + SlotIndex EndB = lis_.getMBBEndIdx(&B); + const LiveRange *CurB = curli_->getLiveRangeContaining(StartB); + if (!CurB) { + DEBUG(dbgs() << " enterIntvAtEnd: curli not live in to BB#" + << B.getNumber() << ".\n"); + return; + } + + VNInfo *VNIB = openli_->getVNInfoAt(StartB); + if (!VNIB) { + // Create a phi value. + VNIB = openli_->getNextValue(SlotIndex(StartB, true), 0, false, + lis_.getVNInfoAllocator()); + VNIB->setIsPHIDef(true); + VNInfo *&mapVNI = valueMap_[CurB->valno]; + if (mapVNI) { + // Multiple copies - must create PHI value. + abort(); + } else { + // This is the first copy of dupLR. Mark the mapping. + mapVNI = VNIB; + } + + } + + DEBUG(dbgs() << " enterIntvAtEnd: " << *openli_ << '\n'); +} + +/// useIntv - indicate that all instructions in MBB should use openli. +void SplitEditor::useIntv(const MachineBasicBlock &MBB) { + useIntv(lis_.getMBBStartIdx(&MBB), lis_.getMBBEndIdx(&MBB)); +} + +void SplitEditor::useIntv(SlotIndex Start, SlotIndex End) { + assert(openli_ && "openIntv not called before useIntv"); + + // Map the curli values from the interval into openli_ + LiveInterval::const_iterator B = curli_->begin(), E = curli_->end(); + LiveInterval::const_iterator I = std::lower_bound(B, E, Start); + + if (I != B) { + --I; + // I begins before Start, but overlaps. + if (I->end > Start) + openli_->addRange(LiveRange(Start, std::min(End, I->end), + mapValue(I->valno))); + ++I; + } + + // The remaining ranges begin after Start. + for (;I != E && I->start < End; ++I) + openli_->addRange(LiveRange(I->start, std::min(End, I->end), + mapValue(I->valno))); + DEBUG(dbgs() << " use [" << Start << ';' << End << "): " << *openli_ + << '\n'); +} + +/// leaveIntvAfter - Leave openli after the instruction at Idx. +void SplitEditor::leaveIntvAfter(SlotIndex Idx) { + assert(openli_ && "openIntv not called before leaveIntvAfter"); + + const LiveRange *CurLR = curli_->getLiveRangeContaining(Idx.getDefIndex()); + if (!CurLR || CurLR->end <= Idx.getBoundaryIndex()) { + DEBUG(dbgs() << " leaveIntvAfter " << Idx << ": not live\n"); + return; + } + + // Was this value of curli live through openli? + if (!openli_->liveAt(CurLR->valno->def)) { + DEBUG(dbgs() << " leaveIntvAfter " << Idx << ": using external value\n"); + liveThrough_ = true; + return; + } + + // We are going to insert a back copy, so we must have a dupli_. + LiveRange *DupLR = getDupLI()->getLiveRangeContaining(Idx.getDefIndex()); + assert(DupLR && "dupli not live into black, but curli is?"); + + // Insert the COPY instruction. + MachineBasicBlock::iterator I = lis_.getInstructionFromIndex(Idx); + MachineInstr *MI = BuildMI(*I->getParent(), llvm::next(I), I->getDebugLoc(), + tii_.get(TargetOpcode::COPY), dupli_->reg) + .addReg(openli_->reg); + SlotIndex CopyIdx = lis_.InsertMachineInstrInMaps(MI).getDefIndex(); + openli_->addRange(LiveRange(Idx.getDefIndex(), CopyIdx, + mapValue(CurLR->valno))); + DupLR->valno->def = CopyIdx; + DEBUG(dbgs() << " leaveIntvAfter " << Idx << ": " << *openli_ << '\n'); +} + +/// leaveIntvAtTop - Leave the interval at the top of MBB. +/// Currently, only one value can leave the interval. +void SplitEditor::leaveIntvAtTop(MachineBasicBlock &MBB) { + assert(openli_ && "openIntv not called before leaveIntvAtTop"); + + SlotIndex Start = lis_.getMBBStartIdx(&MBB); + const LiveRange *CurLR = curli_->getLiveRangeContaining(Start); + + // Is curli even live-in to MBB? + if (!CurLR) { + DEBUG(dbgs() << " leaveIntvAtTop at " << Start << ": not live\n"); + return; + } + + // Is curli defined by PHI at the beginning of MBB? + bool isPHIDef = CurLR->valno->isPHIDef() && + CurLR->valno->def.getBaseIndex() == Start; + + // If MBB is using a value of curli that was defined outside the openli range, + // we don't want to copy it back here. + if (!isPHIDef && !openli_->liveAt(CurLR->valno->def)) { + DEBUG(dbgs() << " leaveIntvAtTop at " << Start + << ": using external value\n"); + liveThrough_ = true; + return; + } + + // We are going to insert a back copy, so we must have a dupli_. + LiveRange *DupLR = getDupLI()->getLiveRangeContaining(Start); + assert(DupLR && "dupli not live into black, but curli is?"); + + // Insert the COPY instruction. + MachineInstr *MI = BuildMI(MBB, MBB.begin(), DebugLoc(), + tii_.get(TargetOpcode::COPY), dupli_->reg) + .addReg(openli_->reg); + SlotIndex Idx = lis_.InsertMachineInstrInMaps(MI).getDefIndex(); + + // Adjust dupli and openli values. + if (isPHIDef) { + // dupli was already a PHI on entry to MBB. Simply insert an openli PHI, + // and shift the dupli def down to the COPY. + VNInfo *VNI = openli_->getNextValue(SlotIndex(Start, true), 0, false, + lis_.getVNInfoAllocator()); + VNI->setIsPHIDef(true); + openli_->addRange(LiveRange(VNI->def, Idx, VNI)); + + dupli_->removeRange(Start, Idx); + DupLR->valno->def = Idx; + DupLR->valno->setIsPHIDef(false); + } else { + // The dupli value was defined somewhere inside the openli range. + DEBUG(dbgs() << " leaveIntvAtTop source value defined at " + << DupLR->valno->def << "\n"); + // FIXME: We may not need a PHI here if all predecessors have the same + // value. + VNInfo *VNI = openli_->getNextValue(SlotIndex(Start, true), 0, false, + lis_.getVNInfoAllocator()); + VNI->setIsPHIDef(true); + openli_->addRange(LiveRange(VNI->def, Idx, VNI)); + + // FIXME: What if DupLR->valno is used by multiple exits? SSA Update. + + // closeIntv is going to remove the superfluous live ranges. + DupLR->valno->def = Idx; + DupLR->valno->setIsPHIDef(false); + } + + DEBUG(dbgs() << " leaveIntvAtTop at " << Idx << ": " << *openli_ << '\n'); +} + +/// closeIntv - Indicate that we are done editing the currently open +/// LiveInterval, and ranges can be trimmed. +void SplitEditor::closeIntv() { + assert(openli_ && "openIntv not called before closeIntv"); + + DEBUG(dbgs() << " closeIntv cleaning up\n"); + DEBUG(dbgs() << " open " << *openli_ << '\n'); + + if (liveThrough_) { + DEBUG(dbgs() << " value live through region, leaving dupli as is.\n"); + } else { + // live out with copies inserted, or killed by region. Either way we need to + // remove the overlapping region from dupli. + getDupLI(); + for (LiveInterval::iterator I = openli_->begin(), E = openli_->end(); + I != E; ++I) { + dupli_->removeRange(I->start, I->end); + } + // FIXME: A block branching to the entry block may also branch elsewhere + // curli is live. We need both openli and curli to be live in that case. + DEBUG(dbgs() << " dup2 " << *dupli_ << '\n'); + } + openli_ = 0; + valueMap_.clear(); +} + +/// rewrite - after all the new live ranges have been created, rewrite +/// instructions using curli to use the new intervals. +void SplitEditor::rewrite() { + assert(!openli_ && "Previous LI not closed before rewrite"); + const LiveInterval *curli = sa_.getCurLI(); + for (MachineRegisterInfo::reg_iterator RI = mri_.reg_begin(curli->reg), + RE = mri_.reg_end(); RI != RE;) { + MachineOperand &MO = RI.getOperand(); + MachineInstr *MI = MO.getParent(); + ++RI; + if (MI->isDebugValue()) { + DEBUG(dbgs() << "Zapping " << *MI); + // FIXME: We can do much better with debug values. + MO.setReg(0); + continue; + } + SlotIndex Idx = lis_.getInstructionIndex(MI); + Idx = MO.isUse() ? Idx.getUseIndex() : Idx.getDefIndex(); + LiveInterval *LI = dupli_; + for (unsigned i = firstInterval, e = intervals_.size(); i != e; ++i) { + LiveInterval *testli = intervals_[i]; + if (testli->liveAt(Idx)) { + LI = testli; + break; + } + } + if (LI) { + MO.setReg(LI->reg); + sa_.removeUse(MI); + DEBUG(dbgs() << " rewrite " << Idx << '\t' << *MI); + } + } + + // dupli_ goes in last, after rewriting. + if (dupli_) { + if (dupli_->empty()) { + DEBUG(dbgs() << " dupli became empty?\n"); + lis_.removeInterval(dupli_->reg); + dupli_ = 0; + } else { + dupli_->RenumberValues(lis_); + intervals_.push_back(dupli_); + } + } + + // Calculate spill weight and allocation hints for new intervals. + VirtRegAuxInfo vrai(vrm_.getMachineFunction(), lis_, sa_.loops_); + for (unsigned i = firstInterval, e = intervals_.size(); i != e; ++i) { + LiveInterval &li = *intervals_[i]; + vrai.CalculateRegClass(li.reg); + vrai.CalculateWeightAndHint(li); + DEBUG(dbgs() << " new interval " << mri_.getRegClass(li.reg)->getName() + << ":" << li << '\n'); + } +} + + +//===----------------------------------------------------------------------===// +// Loop Splitting +//===----------------------------------------------------------------------===// + +bool SplitEditor::splitAroundLoop(const MachineLoop *Loop) { + SplitAnalysis::LoopBlocks Blocks; + sa_.getLoopBlocks(Loop, Blocks); + + // Break critical edges as needed. + SplitAnalysis::BlockPtrSet CriticalExits; + sa_.getCriticalExits(Blocks, CriticalExits); + assert(CriticalExits.empty() && "Cannot break critical exits yet"); + + // Create new live interval for the loop. + openIntv(); + + // Insert copies in the predecessors. + for (SplitAnalysis::BlockPtrSet::iterator I = Blocks.Preds.begin(), + E = Blocks.Preds.end(); I != E; ++I) { + MachineBasicBlock &MBB = const_cast(**I); + enterIntvAtEnd(MBB, *Loop->getHeader()); + } + + // Switch all loop blocks. + for (SplitAnalysis::BlockPtrSet::iterator I = Blocks.Loop.begin(), + E = Blocks.Loop.end(); I != E; ++I) + useIntv(**I); + + // Insert back copies in the exit blocks. + for (SplitAnalysis::BlockPtrSet::iterator I = Blocks.Exits.begin(), + E = Blocks.Exits.end(); I != E; ++I) { + MachineBasicBlock &MBB = const_cast(**I); + leaveIntvAtTop(MBB); + } + + // Done. + closeIntv(); + rewrite(); + return dupli_; +} + + +//===----------------------------------------------------------------------===// +// Single Block Splitting +//===----------------------------------------------------------------------===// + +/// splitSingleBlocks - Split curli into a separate live interval inside each +/// basic block in Blocks. Return true if curli has been completely replaced, +/// false if curli is still intact, and needs to be spilled or split further. +bool SplitEditor::splitSingleBlocks(const SplitAnalysis::BlockPtrSet &Blocks) { + DEBUG(dbgs() << " splitSingleBlocks for " << Blocks.size() << " blocks.\n"); + // Determine the first and last instruction using curli in each block. + typedef std::pair IndexPair; + typedef DenseMap IndexPairMap; + IndexPairMap MBBRange; + for (SplitAnalysis::InstrPtrSet::const_iterator I = sa_.usingInstrs_.begin(), + E = sa_.usingInstrs_.end(); I != E; ++I) { + const MachineBasicBlock *MBB = (*I)->getParent(); + if (!Blocks.count(MBB)) + continue; + SlotIndex Idx = lis_.getInstructionIndex(*I); + DEBUG(dbgs() << " BB#" << MBB->getNumber() << '\t' << Idx << '\t' << **I); + IndexPair &IP = MBBRange[MBB]; + if (!IP.first.isValid() || Idx < IP.first) + IP.first = Idx; + if (!IP.second.isValid() || Idx > IP.second) + IP.second = Idx; + } + + // Create a new interval for each block. + for (SplitAnalysis::BlockPtrSet::const_iterator I = Blocks.begin(), + E = Blocks.end(); I != E; ++I) { + IndexPair &IP = MBBRange[*I]; + DEBUG(dbgs() << " splitting for BB#" << (*I)->getNumber() << ": [" + << IP.first << ';' << IP.second << ")\n"); + assert(IP.first.isValid() && IP.second.isValid()); + + openIntv(); + enterIntvBefore(IP.first); + useIntv(IP.first.getBaseIndex(), IP.second.getBoundaryIndex()); + leaveIntvAfter(IP.second); + closeIntv(); + } + rewrite(); + return dupli_; +} + + +//===----------------------------------------------------------------------===// +// Sub Block Splitting +//===----------------------------------------------------------------------===// + +/// getBlockForInsideSplit - If curli is contained inside a single basic block, +/// and it wou pay to subdivide the interval inside that block, return it. +/// Otherwise return NULL. The returned block can be passed to +/// SplitEditor::splitInsideBlock. +const MachineBasicBlock *SplitAnalysis::getBlockForInsideSplit() { + // The interval must be exclusive to one block. + if (usingBlocks_.size() != 1) + return 0; + // Don't to this for less than 4 instructions. We want to be sure that + // splitting actually reduces the instruction count per interval. + if (usingInstrs_.size() < 4) + return 0; + return usingBlocks_.begin()->first; +} + +/// splitInsideBlock - Split curli into multiple intervals inside MBB. Return +/// true if curli has been completely replaced, false if curli is still +/// intact, and needs to be spilled or split further. +bool SplitEditor::splitInsideBlock(const MachineBasicBlock *MBB) { + SmallVector Uses; + Uses.reserve(sa_.usingInstrs_.size()); + for (SplitAnalysis::InstrPtrSet::const_iterator I = sa_.usingInstrs_.begin(), + E = sa_.usingInstrs_.end(); I != E; ++I) + if ((*I)->getParent() == MBB) + Uses.push_back(lis_.getInstructionIndex(*I)); + DEBUG(dbgs() << " splitInsideBlock BB#" << MBB->getNumber() << " for " + << Uses.size() << " instructions.\n"); + assert(Uses.size() >= 3 && "Need at least 3 instructions"); + array_pod_sort(Uses.begin(), Uses.end()); + + // Simple algorithm: Find the largest gap between uses as determined by slot + // indices. Create new intervals for instructions before the gap and after the + // gap. + unsigned bestPos = 0; + int bestGap = 0; + DEBUG(dbgs() << " dist (" << Uses[0]); + for (unsigned i = 1, e = Uses.size(); i != e; ++i) { + int g = Uses[i-1].distance(Uses[i]); + DEBUG(dbgs() << ") -" << g << "- (" << Uses[i]); + if (g > bestGap) + bestPos = i, bestGap = g; + } + DEBUG(dbgs() << "), best: -" << bestGap << "-\n"); + + // bestPos points to the first use after the best gap. + assert(bestPos > 0 && "Invalid gap"); + + // FIXME: Don't create intervals for low densities. + + // First interval before the gap. Don't create single-instr intervals. + if (bestPos > 1) { + openIntv(); + enterIntvBefore(Uses.front()); + useIntv(Uses.front().getBaseIndex(), Uses[bestPos-1].getBoundaryIndex()); + leaveIntvAfter(Uses[bestPos-1]); + closeIntv(); + } + + // Second interval after the gap. + if (bestPos < Uses.size()-1) { + openIntv(); + enterIntvBefore(Uses[bestPos]); + useIntv(Uses[bestPos].getBaseIndex(), Uses.back().getBoundaryIndex()); + leaveIntvAfter(Uses.back()); + closeIntv(); + } + + rewrite(); + return dupli_; +} diff --git a/lib/CodeGen/SplitKit.h b/lib/CodeGen/SplitKit.h new file mode 100644 index 0000000..ddef746 --- /dev/null +++ b/lib/CodeGen/SplitKit.h @@ -0,0 +1,321 @@ +//===---------- SplitKit.cpp - Toolkit for splitting live ranges ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the SplitAnalysis class as well as mutator functions for +// live range splitting. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/CodeGen/SlotIndexes.h" + +namespace llvm { + +class LiveInterval; +class LiveIntervals; +class MachineInstr; +class MachineLoop; +class MachineLoopInfo; +class MachineRegisterInfo; +class TargetInstrInfo; +class VirtRegMap; +class VNInfo; + +/// SplitAnalysis - Analyze a LiveInterval, looking for live range splitting +/// opportunities. +class SplitAnalysis { +public: + const MachineFunction &mf_; + const LiveIntervals &lis_; + const MachineLoopInfo &loops_; + const TargetInstrInfo &tii_; + + // Instructions using the the current register. + typedef SmallPtrSet InstrPtrSet; + InstrPtrSet usingInstrs_; + + // The number of instructions using curli in each basic block. + typedef DenseMap BlockCountMap; + BlockCountMap usingBlocks_; + + // The number of basic block using curli in each loop. + typedef DenseMap LoopCountMap; + LoopCountMap usingLoops_; + +private: + // Current live interval. + const LiveInterval *curli_; + + // Sumarize statistics by counting instructions using curli_. + void analyzeUses(); + + /// canAnalyzeBranch - Return true if MBB ends in a branch that can be + /// analyzed. + bool canAnalyzeBranch(const MachineBasicBlock *MBB); + +public: + SplitAnalysis(const MachineFunction &mf, const LiveIntervals &lis, + const MachineLoopInfo &mli); + + /// analyze - set curli to the specified interval, and analyze how it may be + /// split. + void analyze(const LiveInterval *li); + + /// removeUse - Update statistics by noting that mi no longer uses curli. + void removeUse(const MachineInstr *mi); + + const LiveInterval *getCurLI() { return curli_; } + + /// clear - clear all data structures so SplitAnalysis is ready to analyze a + /// new interval. + void clear(); + + typedef SmallPtrSet BlockPtrSet; + typedef SmallPtrSet LoopPtrSet; + + // Sets of basic blocks surrounding a machine loop. + struct LoopBlocks { + BlockPtrSet Loop; // Blocks in the loop. + BlockPtrSet Preds; // Loop predecessor blocks. + BlockPtrSet Exits; // Loop exit blocks. + + void clear() { + Loop.clear(); + Preds.clear(); + Exits.clear(); + } + }; + + // Calculate the block sets surrounding the loop. + void getLoopBlocks(const MachineLoop *Loop, LoopBlocks &Blocks); + + /// LoopPeripheralUse - how is a variable used in and around a loop? + /// Peripheral blocks are the loop predecessors and exit blocks. + enum LoopPeripheralUse { + ContainedInLoop, // All uses are inside the loop. + SinglePeripheral, // At most one instruction per peripheral block. + MultiPeripheral, // Multiple instructions in some peripheral blocks. + OutsideLoop // Uses outside loop periphery. + }; + + /// analyzeLoopPeripheralUse - Return an enum describing how curli_ is used in + /// and around the Loop. + LoopPeripheralUse analyzeLoopPeripheralUse(const LoopBlocks&); + + /// getCriticalExits - It may be necessary to partially break critical edges + /// leaving the loop if an exit block has phi uses of curli. Collect the exit + /// blocks that need special treatment into CriticalExits. + void getCriticalExits(const LoopBlocks &Blocks, BlockPtrSet &CriticalExits); + + /// canSplitCriticalExits - Return true if it is possible to insert new exit + /// blocks before the blocks in CriticalExits. + bool canSplitCriticalExits(const LoopBlocks &Blocks, + BlockPtrSet &CriticalExits); + + /// getBestSplitLoop - Return the loop where curli may best be split to a + /// separate register, or NULL. + const MachineLoop *getBestSplitLoop(); + + /// getMultiUseBlocks - Add basic blocks to Blocks that may benefit from + /// having curli split to a new live interval. Return true if Blocks can be + /// passed to SplitEditor::splitSingleBlocks. + bool getMultiUseBlocks(BlockPtrSet &Blocks); + + /// getBlockForInsideSplit - If curli is contained inside a single basic block, + /// and it wou pay to subdivide the interval inside that block, return it. + /// Otherwise return NULL. The returned block can be passed to + /// SplitEditor::splitInsideBlock. + const MachineBasicBlock *getBlockForInsideSplit(); +}; + + +/// LiveIntervalMap - Map values from a large LiveInterval into a small +/// interval that is a subset. Insert phi-def values as needed. This class is +/// used by SplitEditor to create new smaller LiveIntervals. +/// +/// parentli_ is the larger interval, li_ is the subset interval. Every value +/// in li_ corresponds to exactly one value in parentli_, and the live range +/// of the value is contained within the live range of the parentli_ value. +/// Values in parentli_ may map to any number of openli_ values, including 0. +class LiveIntervalMap { + LiveIntervals &lis_; + + // The parent interval is never changed. + const LiveInterval &parentli_; + + // The child interval's values are fully contained inside parentli_ values. + LiveInterval &li_; + + typedef DenseMap ValueMap; + + // Map parentli_ values to simple values in li_ that are defined at the same + // SlotIndex, or NULL for parentli_ values that have complex li_ defs. + // Note there is a difference between values mapping to NULL (complex), and + // values not present (unknown/unmapped). + ValueMap valueMap_; + + // extendTo - Find the last li_ value defined in MBB at or before Idx. The + // parentli_ is assumed to be live at Idx. Extend the live range to Idx. + // Return the found VNInfo, or NULL. + VNInfo *extendTo(MachineBasicBlock *MBB, SlotIndex Idx); + + // addSimpleRange - Add a simple range from parentli_ to li_. + // ParentVNI must be live in the [Start;End) interval. + void addSimpleRange(SlotIndex Start, SlotIndex End, const VNInfo *ParentVNI); + +public: + LiveIntervalMap(LiveIntervals &lis, + const LiveInterval &parentli, + LiveInterval &li) + : lis_(lis), parentli_(parentli), li_(li) {} + + /// defValue - define a value in li_ from the parentli_ value VNI and Idx. + /// Idx does not have to be ParentVNI->def, but it must be contained within + /// ParentVNI's live range in parentli_. + /// Return the new li_ value. + VNInfo *defValue(const VNInfo *ParentVNI, SlotIndex Idx); + + /// mapValue - map ParentVNI to the corresponding li_ value at Idx. It is + /// assumed that ParentVNI is live at Idx. + /// If ParentVNI has not been defined by defValue, it is assumed that + /// ParentVNI->def dominates Idx. + /// If ParentVNI has been defined by defValue one or more times, a value that + /// dominates Idx will be returned. This may require creating extra phi-def + /// values and adding live ranges to li_. + VNInfo *mapValue(const VNInfo *ParentVNI, SlotIndex Idx); + + /// addRange - Add live ranges to li_ where [Start;End) intersects parentli_. + /// All needed values whose def is not inside [Start;End) must be defined + /// beforehand so mapValue will work. + void addRange(SlotIndex Start, SlotIndex End); +}; + + +/// SplitEditor - Edit machine code and LiveIntervals for live range +/// splitting. +/// +/// - Create a SplitEditor from a SplitAnalysis. +/// - Start a new live interval with openIntv. +/// - Mark the places where the new interval is entered using enterIntv* +/// - Mark the ranges where the new interval is used with useIntv* +/// - Mark the places where the interval is exited with exitIntv*. +/// - Finish the current interval with closeIntv and repeat from 2. +/// - Rewrite instructions with rewrite(). +/// +class SplitEditor { + SplitAnalysis &sa_; + LiveIntervals &lis_; + VirtRegMap &vrm_; + MachineRegisterInfo &mri_; + const TargetInstrInfo &tii_; + + /// curli_ - The immutable interval we are currently splitting. + const LiveInterval *const curli_; + + /// dupli_ - Created as a copy of curli_, ranges are carved out as new + /// intervals get added through openIntv / closeIntv. This is used to avoid + /// editing curli_. + LiveInterval *dupli_; + + /// Currently open LiveInterval. + LiveInterval *openli_; + + /// createInterval - Create a new virtual register and LiveInterval with same + /// register class and spill slot as curli. + LiveInterval *createInterval(); + + /// getDupLI - Ensure dupli is created and return it. + LiveInterval *getDupLI(); + + /// valueMap_ - Map values in cupli to values in openli. These are direct 1-1 + /// mappings, and do not include values created by inserted copies. + DenseMap valueMap_; + + /// mapValue - Return the openIntv value that corresponds to the given curli + /// value. + VNInfo *mapValue(const VNInfo *curliVNI); + + /// A dupli value is live through openIntv. + bool liveThrough_; + + /// All the new intervals created for this split are added to intervals_. + SmallVectorImpl &intervals_; + + /// The index into intervals_ of the first interval we added. There may be + /// others from before we got it. + unsigned firstInterval; + + /// Insert a COPY instruction curli -> li. Allocate a new value from li + /// defined by the COPY + VNInfo *insertCopy(LiveInterval &LI, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I); + +public: + /// Create a new SplitEditor for editing the LiveInterval analyzed by SA. + /// Newly created intervals will be appended to newIntervals. + SplitEditor(SplitAnalysis &SA, LiveIntervals&, VirtRegMap&, + SmallVectorImpl &newIntervals); + + /// getAnalysis - Get the corresponding analysis. + SplitAnalysis &getAnalysis() { return sa_; } + + /// Create a new virtual register and live interval. + void openIntv(); + + /// enterIntvBefore - Enter openli before the instruction at Idx. If curli is + /// not live before Idx, a COPY is not inserted. + void enterIntvBefore(SlotIndex Idx); + + /// enterIntvAtEnd - Enter openli at the end of MBB. + /// PhiMBB is a successor inside openli where a PHI value is created. + /// Currently, all entries must share the same PhiMBB. + void enterIntvAtEnd(MachineBasicBlock &MBB, MachineBasicBlock &PhiMBB); + + /// useIntv - indicate that all instructions in MBB should use openli. + void useIntv(const MachineBasicBlock &MBB); + + /// useIntv - indicate that all instructions in range should use openli. + void useIntv(SlotIndex Start, SlotIndex End); + + /// leaveIntvAfter - Leave openli after the instruction at Idx. + void leaveIntvAfter(SlotIndex Idx); + + /// leaveIntvAtTop - Leave the interval at the top of MBB. + /// Currently, only one value can leave the interval. + void leaveIntvAtTop(MachineBasicBlock &MBB); + + /// closeIntv - Indicate that we are done editing the currently open + /// LiveInterval, and ranges can be trimmed. + void closeIntv(); + + /// rewrite - after all the new live ranges have been created, rewrite + /// instructions using curli to use the new intervals. + void rewrite(); + + // ===--- High level methods ---=== + + /// splitAroundLoop - Split curli into a separate live interval inside + /// the loop. Return true if curli has been completely replaced, false if + /// curli is still intact, and needs to be spilled or split further. + bool splitAroundLoop(const MachineLoop*); + + /// splitSingleBlocks - Split curli into a separate live interval inside each + /// basic block in Blocks. Return true if curli has been completely replaced, + /// false if curli is still intact, and needs to be spilled or split further. + bool splitSingleBlocks(const SplitAnalysis::BlockPtrSet &Blocks); + + /// splitInsideBlock - Split curli into multiple intervals inside MBB. Return + /// true if curli has been completely replaced, false if curli is still + /// intact, and needs to be spilled or split further. + bool splitInsideBlock(const MachineBasicBlock *); +}; + +} diff --git a/lib/CodeGen/Splitter.cpp b/lib/CodeGen/Splitter.cpp new file mode 100644 index 0000000..38f3b1f --- /dev/null +++ b/lib/CodeGen/Splitter.cpp @@ -0,0 +1,817 @@ +//===-- llvm/CodeGen/Splitter.cpp - Splitter -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "loopsplitter" + +#include "Splitter.h" + +#include "SimpleRegisterCoalescing.h" +#include "llvm/Module.h" +#include "llvm/CodeGen/CalcSpillWeights.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/LiveStackAnalysis.h" +#include "llvm/CodeGen/MachineDominators.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SlotIndexes.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetInstrInfo.h" + +using namespace llvm; + +char LoopSplitter::ID = 0; +INITIALIZE_PASS(LoopSplitter, "loop-splitting", + "Split virtual regists across loop boundaries.", false, false); + +namespace llvm { + + class StartSlotComparator { + public: + StartSlotComparator(LiveIntervals &lis) : lis(lis) {} + bool operator()(const MachineBasicBlock *mbb1, + const MachineBasicBlock *mbb2) const { + return lis.getMBBStartIdx(mbb1) < lis.getMBBStartIdx(mbb2); + } + private: + LiveIntervals &lis; + }; + + class LoopSplit { + public: + LoopSplit(LoopSplitter &ls, LiveInterval &li, MachineLoop &loop) + : ls(ls), li(li), loop(loop), valid(true), inSplit(false), newLI(0) { + assert(TargetRegisterInfo::isVirtualRegister(li.reg) && + "Cannot split physical registers."); + } + + LiveInterval& getLI() const { return li; } + + MachineLoop& getLoop() const { return loop; } + + bool isValid() const { return valid; } + + bool isWorthwhile() const { return valid && (inSplit || !outSplits.empty()); } + + void invalidate() { valid = false; } + + void splitIncoming() { inSplit = true; } + + void splitOutgoing(MachineLoop::Edge &edge) { outSplits.insert(edge); } + + void addLoopInstr(MachineInstr *i) { loopInstrs.push_back(i); } + + void apply() { + assert(valid && "Attempt to apply invalid split."); + applyIncoming(); + applyOutgoing(); + copyRanges(); + renameInside(); + } + + private: + LoopSplitter &ls; + LiveInterval &li; + MachineLoop &loop; + bool valid, inSplit; + std::set outSplits; + std::vector loopInstrs; + + LiveInterval *newLI; + std::map vniMap; + + LiveInterval* getNewLI() { + if (newLI == 0) { + const TargetRegisterClass *trc = ls.mri->getRegClass(li.reg); + unsigned vreg = ls.mri->createVirtualRegister(trc); + newLI = &ls.lis->getOrCreateInterval(vreg); + } + return newLI; + } + + VNInfo* getNewVNI(VNInfo *oldVNI) { + VNInfo *newVNI = vniMap[oldVNI]; + + if (newVNI == 0) { + newVNI = getNewLI()->createValueCopy(oldVNI, + ls.lis->getVNInfoAllocator()); + vniMap[oldVNI] = newVNI; + } + + return newVNI; + } + + void applyIncoming() { + if (!inSplit) { + return; + } + + MachineBasicBlock *preHeader = loop.getLoopPreheader(); + if (preHeader == 0) { + assert(ls.canInsertPreHeader(loop) && + "Can't insert required preheader."); + preHeader = &ls.insertPreHeader(loop); + } + + LiveRange *preHeaderRange = + ls.lis->findExitingRange(li, preHeader); + assert(preHeaderRange != 0 && "Range not live into preheader."); + + // Insert the new copy. + MachineInstr *copy = BuildMI(*preHeader, + preHeader->getFirstTerminator(), + DebugLoc(), + ls.tii->get(TargetOpcode::COPY)) + .addReg(getNewLI()->reg, RegState::Define) + .addReg(li.reg, RegState::Kill); + + ls.lis->InsertMachineInstrInMaps(copy); + + SlotIndex copyDefIdx = ls.lis->getInstructionIndex(copy).getDefIndex(); + + VNInfo *newVal = getNewVNI(preHeaderRange->valno); + newVal->def = copyDefIdx; + newVal->setCopy(copy); + newVal->setIsDefAccurate(true); + li.removeRange(copyDefIdx, ls.lis->getMBBEndIdx(preHeader), true); + + getNewLI()->addRange(LiveRange(copyDefIdx, + ls.lis->getMBBEndIdx(preHeader), + newVal)); + } + + void applyOutgoing() { + + for (std::set::iterator osItr = outSplits.begin(), + osEnd = outSplits.end(); + osItr != osEnd; ++osItr) { + MachineLoop::Edge edge = *osItr; + MachineBasicBlock *outBlock = edge.second; + if (ls.isCriticalEdge(edge)) { + assert(ls.canSplitEdge(edge) && "Unsplitable critical edge."); + outBlock = &ls.splitEdge(edge, loop); + } + LiveRange *outRange = ls.lis->findEnteringRange(li, outBlock); + assert(outRange != 0 && "No exiting range?"); + + MachineInstr *copy = BuildMI(*outBlock, outBlock->begin(), + DebugLoc(), + ls.tii->get(TargetOpcode::COPY)) + .addReg(li.reg, RegState::Define) + .addReg(getNewLI()->reg, RegState::Kill); + + ls.lis->InsertMachineInstrInMaps(copy); + + SlotIndex copyDefIdx = ls.lis->getInstructionIndex(copy).getDefIndex(); + + // Blow away output range definition. + outRange->valno->def = ls.lis->getInvalidIndex(); + outRange->valno->setIsDefAccurate(false); + li.removeRange(ls.lis->getMBBStartIdx(outBlock), copyDefIdx); + + VNInfo *newVal = + getNewLI()->getNextValue(SlotIndex(ls.lis->getMBBStartIdx(outBlock), + true), + 0, false, ls.lis->getVNInfoAllocator()); + + getNewLI()->addRange(LiveRange(ls.lis->getMBBStartIdx(outBlock), + copyDefIdx, newVal)); + + } + } + + void copyRange(LiveRange &lr) { + std::pair lsr = + ls.getLoopSubRange(lr, loop); + + if (!lsr.first) + return; + + LiveRange loopRange(lsr.second.first, lsr.second.second, + getNewVNI(lr.valno)); + + li.removeRange(loopRange.start, loopRange.end, true); + + getNewLI()->addRange(loopRange); + } + + void copyRanges() { + for (std::vector::iterator iItr = loopInstrs.begin(), + iEnd = loopInstrs.end(); + iItr != iEnd; ++iItr) { + MachineInstr &instr = **iItr; + SlotIndex instrIdx = ls.lis->getInstructionIndex(&instr); + if (instr.modifiesRegister(li.reg, 0)) { + LiveRange *defRange = + li.getLiveRangeContaining(instrIdx.getDefIndex()); + if (defRange != 0) // May have caught this already. + copyRange(*defRange); + } + if (instr.readsRegister(li.reg, 0)) { + LiveRange *useRange = + li.getLiveRangeContaining(instrIdx.getUseIndex()); + if (useRange != 0) { // May have caught this already. + copyRange(*useRange); + } + } + } + + for (MachineLoop::block_iterator bbItr = loop.block_begin(), + bbEnd = loop.block_end(); + bbItr != bbEnd; ++bbItr) { + MachineBasicBlock &loopBlock = **bbItr; + LiveRange *enteringRange = + ls.lis->findEnteringRange(li, &loopBlock); + if (enteringRange != 0) { + copyRange(*enteringRange); + } + } + } + + void renameInside() { + for (std::vector::iterator iItr = loopInstrs.begin(), + iEnd = loopInstrs.end(); + iItr != iEnd; ++iItr) { + MachineInstr &instr = **iItr; + for (unsigned i = 0; i < instr.getNumOperands(); ++i) { + MachineOperand &mop = instr.getOperand(i); + if (mop.isReg() && mop.getReg() == li.reg) { + mop.setReg(getNewLI()->reg); + } + } + } + } + + }; + + void LoopSplitter::getAnalysisUsage(AnalysisUsage &au) const { + au.addRequired(); + au.addPreserved(); + au.addRequired(); + au.addPreserved(); + au.addPreserved(); + au.addPreserved(); + au.addPreserved(); + au.addRequired(); + au.addPreserved(); + au.addRequired(); + au.addPreserved(); + MachineFunctionPass::getAnalysisUsage(au); + } + + bool LoopSplitter::runOnMachineFunction(MachineFunction &fn) { + + mf = &fn; + mri = &mf->getRegInfo(); + tii = mf->getTarget().getInstrInfo(); + tri = mf->getTarget().getRegisterInfo(); + sis = &getAnalysis(); + lis = &getAnalysis(); + mli = &getAnalysis(); + mdt = &getAnalysis(); + + fqn = mf->getFunction()->getParent()->getModuleIdentifier() + "." + + mf->getFunction()->getName().str(); + + dbgs() << "Splitting " << mf->getFunction()->getName() << "."; + + dumpOddTerminators(); + +// dbgs() << "----------------------------------------\n"; +// lis->dump(); +// dbgs() << "----------------------------------------\n"; + +// std::deque loops; +// std::copy(mli->begin(), mli->end(), std::back_inserter(loops)); +// dbgs() << "Loops:\n"; +// while (!loops.empty()) { +// MachineLoop &loop = *loops.front(); +// loops.pop_front(); +// std::copy(loop.begin(), loop.end(), std::back_inserter(loops)); + +// dumpLoopInfo(loop); +// } + + //lis->dump(); + //exit(0); + + // Setup initial intervals. + for (LiveIntervals::iterator liItr = lis->begin(), liEnd = lis->end(); + liItr != liEnd; ++liItr) { + LiveInterval *li = liItr->second; + + if (TargetRegisterInfo::isVirtualRegister(li->reg) && + !lis->intervalIsInOneMBB(*li)) { + intervals.push_back(li); + } + } + + processIntervals(); + + intervals.clear(); + +// dbgs() << "----------------------------------------\n"; +// lis->dump(); +// dbgs() << "----------------------------------------\n"; + + dumpOddTerminators(); + + //exit(1); + + return false; + } + + void LoopSplitter::releaseMemory() { + fqn.clear(); + intervals.clear(); + loopRangeMap.clear(); + } + + void LoopSplitter::dumpOddTerminators() { + for (MachineFunction::iterator bbItr = mf->begin(), bbEnd = mf->end(); + bbItr != bbEnd; ++bbItr) { + MachineBasicBlock *mbb = &*bbItr; + MachineBasicBlock *a = 0, *b = 0; + SmallVector c; + if (tii->AnalyzeBranch(*mbb, a, b, c)) { + dbgs() << "MBB#" << mbb->getNumber() << " has multiway terminator.\n"; + dbgs() << " Terminators:\n"; + for (MachineBasicBlock::iterator iItr = mbb->begin(), iEnd = mbb->end(); + iItr != iEnd; ++iItr) { + MachineInstr *instr= &*iItr; + dbgs() << " " << *instr << ""; + } + dbgs() << "\n Listed successors: [ "; + for (MachineBasicBlock::succ_iterator sItr = mbb->succ_begin(), sEnd = mbb->succ_end(); + sItr != sEnd; ++sItr) { + MachineBasicBlock *succMBB = *sItr; + dbgs() << succMBB->getNumber() << " "; + } + dbgs() << "]\n\n"; + } + } + } + + void LoopSplitter::dumpLoopInfo(MachineLoop &loop) { + MachineBasicBlock &headerBlock = *loop.getHeader(); + typedef SmallVector ExitEdgesList; + ExitEdgesList exitEdges; + loop.getExitEdges(exitEdges); + + dbgs() << " Header: BB#" << headerBlock.getNumber() << ", Contains: [ "; + for (std::vector::const_iterator + subBlockItr = loop.getBlocks().begin(), + subBlockEnd = loop.getBlocks().end(); + subBlockItr != subBlockEnd; ++subBlockItr) { + MachineBasicBlock &subBlock = **subBlockItr; + dbgs() << "BB#" << subBlock.getNumber() << " "; + } + dbgs() << "], Exit edges: [ "; + for (ExitEdgesList::iterator exitEdgeItr = exitEdges.begin(), + exitEdgeEnd = exitEdges.end(); + exitEdgeItr != exitEdgeEnd; ++exitEdgeItr) { + MachineLoop::Edge &exitEdge = *exitEdgeItr; + dbgs() << "(MBB#" << exitEdge.first->getNumber() + << ", MBB#" << exitEdge.second->getNumber() << ") "; + } + dbgs() << "], Sub-Loop Headers: [ "; + for (MachineLoop::iterator subLoopItr = loop.begin(), + subLoopEnd = loop.end(); + subLoopItr != subLoopEnd; ++subLoopItr) { + MachineLoop &subLoop = **subLoopItr; + MachineBasicBlock &subLoopBlock = *subLoop.getHeader(); + dbgs() << "BB#" << subLoopBlock.getNumber() << " "; + } + dbgs() << "]\n"; + } + + void LoopSplitter::updateTerminators(MachineBasicBlock &mbb) { + mbb.updateTerminator(); + + for (MachineBasicBlock::iterator miItr = mbb.begin(), miEnd = mbb.end(); + miItr != miEnd; ++miItr) { + if (lis->isNotInMIMap(miItr)) { + lis->InsertMachineInstrInMaps(miItr); + } + } + } + + bool LoopSplitter::canInsertPreHeader(MachineLoop &loop) { + MachineBasicBlock *header = loop.getHeader(); + MachineBasicBlock *a = 0, *b = 0; + SmallVector c; + + for (MachineBasicBlock::pred_iterator pbItr = header->pred_begin(), + pbEnd = header->pred_end(); + pbItr != pbEnd; ++pbItr) { + MachineBasicBlock *predBlock = *pbItr; + if (!!tii->AnalyzeBranch(*predBlock, a, b, c)) { + return false; + } + } + + MachineFunction::iterator headerItr(header); + if (headerItr == mf->begin()) + return true; + MachineBasicBlock *headerLayoutPred = llvm::prior(headerItr); + assert(headerLayoutPred != 0 && "Header should have layout pred."); + + return (!tii->AnalyzeBranch(*headerLayoutPred, a, b, c)); + } + + MachineBasicBlock& LoopSplitter::insertPreHeader(MachineLoop &loop) { + assert(loop.getLoopPreheader() == 0 && "Loop already has preheader."); + + MachineBasicBlock &header = *loop.getHeader(); + + // Save the preds - we'll need to update them once we insert the preheader. + typedef std::set HeaderPreds; + HeaderPreds headerPreds; + + for (MachineBasicBlock::pred_iterator predItr = header.pred_begin(), + predEnd = header.pred_end(); + predItr != predEnd; ++predItr) { + if (!loop.contains(*predItr)) + headerPreds.insert(*predItr); + } + + assert(!headerPreds.empty() && "No predecessors for header?"); + + //dbgs() << fqn << " MBB#" << header.getNumber() << " inserting preheader..."; + + MachineBasicBlock *preHeader = + mf->CreateMachineBasicBlock(header.getBasicBlock()); + + assert(preHeader != 0 && "Failed to create pre-header."); + + mf->insert(header, preHeader); + + for (HeaderPreds::iterator hpItr = headerPreds.begin(), + hpEnd = headerPreds.end(); + hpItr != hpEnd; ++hpItr) { + assert(*hpItr != 0 && "How'd a null predecessor get into this set?"); + MachineBasicBlock &hp = **hpItr; + hp.ReplaceUsesOfBlockWith(&header, preHeader); + } + preHeader->addSuccessor(&header); + + MachineBasicBlock *oldLayoutPred = + llvm::prior(MachineFunction::iterator(preHeader)); + if (oldLayoutPred != 0) { + updateTerminators(*oldLayoutPred); + } + + lis->InsertMBBInMaps(preHeader); + + if (MachineLoop *parentLoop = loop.getParentLoop()) { + assert(parentLoop->getHeader() != loop.getHeader() && + "Parent loop has same header?"); + parentLoop->addBasicBlockToLoop(preHeader, mli->getBase()); + + // Invalidate all parent loop ranges. + while (parentLoop != 0) { + loopRangeMap.erase(parentLoop); + parentLoop = parentLoop->getParentLoop(); + } + } + + for (LiveIntervals::iterator liItr = lis->begin(), + liEnd = lis->end(); + liItr != liEnd; ++liItr) { + LiveInterval &li = *liItr->second; + + // Is this safe for physregs? + // TargetRegisterInfo::isPhysicalRegister(li.reg) || + if (!lis->isLiveInToMBB(li, &header)) + continue; + + if (lis->isLiveInToMBB(li, preHeader)) { + assert(lis->isLiveOutOfMBB(li, preHeader) && + "Range terminates in newly added preheader?"); + continue; + } + + bool insertRange = false; + + for (MachineBasicBlock::pred_iterator predItr = preHeader->pred_begin(), + predEnd = preHeader->pred_end(); + predItr != predEnd; ++predItr) { + MachineBasicBlock *predMBB = *predItr; + if (lis->isLiveOutOfMBB(li, predMBB)) { + insertRange = true; + break; + } + } + + if (!insertRange) + continue; + + VNInfo *newVal = li.getNextValue(lis->getMBBStartIdx(preHeader), + 0, false, lis->getVNInfoAllocator()); + li.addRange(LiveRange(lis->getMBBStartIdx(preHeader), + lis->getMBBEndIdx(preHeader), + newVal)); + } + + + //dbgs() << "Dumping SlotIndexes:\n"; + //sis->dump(); + + //dbgs() << "done. (Added MBB#" << preHeader->getNumber() << ")\n"; + + return *preHeader; + } + + bool LoopSplitter::isCriticalEdge(MachineLoop::Edge &edge) { + assert(edge.first->succ_size() > 1 && "Non-sensical edge."); + if (edge.second->pred_size() > 1) + return true; + return false; + } + + bool LoopSplitter::canSplitEdge(MachineLoop::Edge &edge) { + MachineFunction::iterator outBlockItr(edge.second); + if (outBlockItr == mf->begin()) + return true; + MachineBasicBlock *outBlockLayoutPred = llvm::prior(outBlockItr); + assert(outBlockLayoutPred != 0 && "Should have a layout pred if out!=begin."); + MachineBasicBlock *a = 0, *b = 0; + SmallVector c; + return (!tii->AnalyzeBranch(*outBlockLayoutPred, a, b, c) && + !tii->AnalyzeBranch(*edge.first, a, b, c)); + } + + MachineBasicBlock& LoopSplitter::splitEdge(MachineLoop::Edge &edge, + MachineLoop &loop) { + + MachineBasicBlock &inBlock = *edge.first; + MachineBasicBlock &outBlock = *edge.second; + + assert((inBlock.succ_size() > 1) && (outBlock.pred_size() > 1) && + "Splitting non-critical edge?"); + + //dbgs() << fqn << " Splitting edge (MBB#" << inBlock.getNumber() + // << " -> MBB#" << outBlock.getNumber() << ")..."; + + MachineBasicBlock *splitBlock = + mf->CreateMachineBasicBlock(); + + assert(splitBlock != 0 && "Failed to create split block."); + + mf->insert(&outBlock, splitBlock); + + inBlock.ReplaceUsesOfBlockWith(&outBlock, splitBlock); + splitBlock->addSuccessor(&outBlock); + + MachineBasicBlock *oldLayoutPred = + llvm::prior(MachineFunction::iterator(splitBlock)); + if (oldLayoutPred != 0) { + updateTerminators(*oldLayoutPred); + } + + lis->InsertMBBInMaps(splitBlock); + + loopRangeMap.erase(&loop); + + MachineLoop *splitParentLoop = loop.getParentLoop(); + while (splitParentLoop != 0 && + !splitParentLoop->contains(&outBlock)) { + splitParentLoop = splitParentLoop->getParentLoop(); + } + + if (splitParentLoop != 0) { + assert(splitParentLoop->contains(&loop) && + "Split-block parent doesn't contain original loop?"); + splitParentLoop->addBasicBlockToLoop(splitBlock, mli->getBase()); + + // Invalidate all parent loop ranges. + while (splitParentLoop != 0) { + loopRangeMap.erase(splitParentLoop); + splitParentLoop = splitParentLoop->getParentLoop(); + } + } + + + for (LiveIntervals::iterator liItr = lis->begin(), + liEnd = lis->end(); + liItr != liEnd; ++liItr) { + LiveInterval &li = *liItr->second; + bool intersects = lis->isLiveOutOfMBB(li, &inBlock) && + lis->isLiveInToMBB(li, &outBlock); + if (lis->isLiveInToMBB(li, splitBlock)) { + if (!intersects) { + li.removeRange(lis->getMBBStartIdx(splitBlock), + lis->getMBBEndIdx(splitBlock), true); + } + } else if (intersects) { + VNInfo *newVal = li.getNextValue(lis->getMBBStartIdx(splitBlock), + 0, false, lis->getVNInfoAllocator()); + li.addRange(LiveRange(lis->getMBBStartIdx(splitBlock), + lis->getMBBEndIdx(splitBlock), + newVal)); + } + } + + //dbgs() << "done. (Added MBB#" << splitBlock->getNumber() << ")\n"; + + return *splitBlock; + } + + LoopSplitter::LoopRanges& LoopSplitter::getLoopRanges(MachineLoop &loop) { + typedef std::set LoopMBBSet; + LoopRangeMap::iterator lrItr = loopRangeMap.find(&loop); + if (lrItr == loopRangeMap.end()) { + LoopMBBSet loopMBBs((StartSlotComparator(*lis))); + std::copy(loop.block_begin(), loop.block_end(), + std::inserter(loopMBBs, loopMBBs.begin())); + + assert(!loopMBBs.empty() && "No blocks in loop?"); + + LoopRanges &loopRanges = loopRangeMap[&loop]; + assert(loopRanges.empty() && "Loop encountered but not processed?"); + SlotIndex oldEnd = lis->getMBBEndIdx(*loopMBBs.begin()); + loopRanges.push_back( + std::make_pair(lis->getMBBStartIdx(*loopMBBs.begin()), + lis->getInvalidIndex())); + for (LoopMBBSet::iterator curBlockItr = llvm::next(loopMBBs.begin()), + curBlockEnd = loopMBBs.end(); + curBlockItr != curBlockEnd; ++curBlockItr) { + SlotIndex newStart = lis->getMBBStartIdx(*curBlockItr); + if (newStart != oldEnd) { + loopRanges.back().second = oldEnd; + loopRanges.push_back(std::make_pair(newStart, + lis->getInvalidIndex())); + } + oldEnd = lis->getMBBEndIdx(*curBlockItr); + } + + loopRanges.back().second = + lis->getMBBEndIdx(*llvm::prior(loopMBBs.end())); + + return loopRanges; + } + return lrItr->second; + } + + std::pair LoopSplitter::getLoopSubRange( + const LiveRange &lr, + MachineLoop &loop) { + LoopRanges &loopRanges = getLoopRanges(loop); + LoopRanges::iterator lrItr = loopRanges.begin(), + lrEnd = loopRanges.end(); + while (lrItr != lrEnd && lr.start >= lrItr->second) { + ++lrItr; + } + + if (lrItr == lrEnd) { + SlotIndex invalid = lis->getInvalidIndex(); + return std::make_pair(false, SlotPair(invalid, invalid)); + } + + SlotIndex srStart(lr.start < lrItr->first ? lrItr->first : lr.start); + SlotIndex srEnd(lr.end > lrItr->second ? lrItr->second : lr.end); + + return std::make_pair(true, SlotPair(srStart, srEnd)); + } + + void LoopSplitter::dumpLoopRanges(MachineLoop &loop) { + LoopRanges &loopRanges = getLoopRanges(loop); + dbgs() << "For loop MBB#" << loop.getHeader()->getNumber() << ", subranges are: [ "; + for (LoopRanges::iterator lrItr = loopRanges.begin(), lrEnd = loopRanges.end(); + lrItr != lrEnd; ++lrItr) { + dbgs() << "[" << lrItr->first << ", " << lrItr->second << ") "; + } + dbgs() << "]\n"; + } + + void LoopSplitter::processHeader(LoopSplit &split) { + MachineBasicBlock &header = *split.getLoop().getHeader(); + //dbgs() << " Processing loop header BB#" << header.getNumber() << "\n"; + + if (!lis->isLiveInToMBB(split.getLI(), &header)) + return; // Not live in, but nothing wrong so far. + + MachineBasicBlock *preHeader = split.getLoop().getLoopPreheader(); + if (!preHeader) { + + if (!canInsertPreHeader(split.getLoop())) { + split.invalidate(); + return; // Couldn't insert a pre-header. Bail on this interval. + } + + for (MachineBasicBlock::pred_iterator predItr = header.pred_begin(), + predEnd = header.pred_end(); + predItr != predEnd; ++predItr) { + if (lis->isLiveOutOfMBB(split.getLI(), *predItr)) { + split.splitIncoming(); + break; + } + } + } else if (lis->isLiveOutOfMBB(split.getLI(), preHeader)) { + split.splitIncoming(); + } + } + + void LoopSplitter::processLoopExits(LoopSplit &split) { + typedef SmallVector ExitEdgesList; + ExitEdgesList exitEdges; + split.getLoop().getExitEdges(exitEdges); + + //dbgs() << " Processing loop exits:\n"; + + for (ExitEdgesList::iterator exitEdgeItr = exitEdges.begin(), + exitEdgeEnd = exitEdges.end(); + exitEdgeItr != exitEdgeEnd; ++exitEdgeItr) { + MachineLoop::Edge exitEdge = *exitEdgeItr; + + LiveRange *outRange = + split.getLI().getLiveRangeContaining(lis->getMBBStartIdx(exitEdge.second)); + + if (outRange != 0) { + if (isCriticalEdge(exitEdge) && !canSplitEdge(exitEdge)) { + split.invalidate(); + return; + } + + split.splitOutgoing(exitEdge); + } + } + } + + void LoopSplitter::processLoopUses(LoopSplit &split) { + std::set processed; + + for (MachineRegisterInfo::reg_iterator + rItr = mri->reg_begin(split.getLI().reg), + rEnd = mri->reg_end(); + rItr != rEnd; ++rItr) { + MachineInstr &instr = *rItr; + if (split.getLoop().contains(&instr) && processed.count(&instr) == 0) { + split.addLoopInstr(&instr); + processed.insert(&instr); + } + } + + //dbgs() << " Rewriting reg" << li.reg << " to reg" << newLI->reg + // << " in blocks [ "; + //dbgs() << "]\n"; + } + + bool LoopSplitter::splitOverLoop(LiveInterval &li, MachineLoop &loop) { + assert(TargetRegisterInfo::isVirtualRegister(li.reg) && + "Attempt to split physical register."); + + LoopSplit split(*this, li, loop); + processHeader(split); + if (split.isValid()) + processLoopExits(split); + if (split.isValid()) + processLoopUses(split); + if (split.isValid() /* && split.isWorthwhile() */) { + split.apply(); + DEBUG(dbgs() << "Success.\n"); + return true; + } + DEBUG(dbgs() << "Failed.\n"); + return false; + } + + void LoopSplitter::processInterval(LiveInterval &li) { + std::deque loops; + std::copy(mli->begin(), mli->end(), std::back_inserter(loops)); + + while (!loops.empty()) { + MachineLoop &loop = *loops.front(); + loops.pop_front(); + DEBUG( + dbgs() << fqn << " reg" << li.reg << " " << li.weight << " BB#" + << loop.getHeader()->getNumber() << " "; + ); + if (!splitOverLoop(li, loop)) { + // Couldn't split over outer loop, schedule sub-loops to be checked. + std::copy(loop.begin(), loop.end(), std::back_inserter(loops)); + } + } + } + + void LoopSplitter::processIntervals() { + while (!intervals.empty()) { + LiveInterval &li = *intervals.front(); + intervals.pop_front(); + + assert(!lis->intervalIsInOneMBB(li) && + "Single interval in process worklist."); + + processInterval(li); + } + } + +} diff --git a/lib/CodeGen/Splitter.h b/lib/CodeGen/Splitter.h new file mode 100644 index 0000000..a726a7b --- /dev/null +++ b/lib/CodeGen/Splitter.h @@ -0,0 +1,99 @@ +//===-- llvm/CodeGen/Splitter.h - Splitter -*- C++ -*----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_SPLITTER_H +#define LLVM_CODEGEN_SPLITTER_H + +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/SlotIndexes.h" + +#include +#include +#include +#include + +namespace llvm { + + class LiveInterval; + class LiveIntervals; + struct LiveRange; + class LoopSplit; + class MachineDominatorTree; + class MachineRegisterInfo; + class SlotIndexes; + class TargetInstrInfo; + class VNInfo; + + class LoopSplitter : public MachineFunctionPass { + friend class LoopSplit; + public: + static char ID; + + LoopSplitter() : MachineFunctionPass(ID) {} + + virtual void getAnalysisUsage(AnalysisUsage &au) const; + + virtual bool runOnMachineFunction(MachineFunction &fn); + + virtual void releaseMemory(); + + + private: + + MachineFunction *mf; + LiveIntervals *lis; + MachineLoopInfo *mli; + MachineRegisterInfo *mri; + MachineDominatorTree *mdt; + SlotIndexes *sis; + const TargetInstrInfo *tii; + const TargetRegisterInfo *tri; + + std::string fqn; + std::deque intervals; + + typedef std::pair SlotPair; + typedef std::vector LoopRanges; + typedef std::map LoopRangeMap; + LoopRangeMap loopRangeMap; + + void dumpLoopInfo(MachineLoop &loop); + + void dumpOddTerminators(); + + void updateTerminators(MachineBasicBlock &mbb); + + bool canInsertPreHeader(MachineLoop &loop); + MachineBasicBlock& insertPreHeader(MachineLoop &loop); + + bool isCriticalEdge(MachineLoop::Edge &edge); + bool canSplitEdge(MachineLoop::Edge &edge); + MachineBasicBlock& splitEdge(MachineLoop::Edge &edge, MachineLoop &loop); + + LoopRanges& getLoopRanges(MachineLoop &loop); + std::pair getLoopSubRange(const LiveRange &lr, + MachineLoop &loop); + + void dumpLoopRanges(MachineLoop &loop); + + void processHeader(LoopSplit &split); + void processLoopExits(LoopSplit &split); + void processLoopUses(LoopSplit &split); + + bool splitOverLoop(LiveInterval &li, MachineLoop &loop); + + void processInterval(LiveInterval &li); + + void processIntervals(); + }; + +} + +#endif diff --git a/lib/CodeGen/StackProtector.cpp b/lib/CodeGen/StackProtector.cpp index ca5c28c..9f51778 100644 --- a/lib/CodeGen/StackProtector.cpp +++ b/lib/CodeGen/StackProtector.cpp @@ -62,17 +62,17 @@ namespace { bool RequiresStackProtector() const; public: static char ID; // Pass identification, replacement for typeid. - StackProtector() : FunctionPass(&ID), TLI(0) {} + StackProtector() : FunctionPass(ID), TLI(0) {} StackProtector(const TargetLowering *tli) - : FunctionPass(&ID), TLI(tli) {} + : FunctionPass(ID), TLI(tli) {} virtual bool runOnFunction(Function &Fn); }; } // end anonymous namespace char StackProtector::ID = 0; -static RegisterPass -X("stack-protector", "Insert stack protectors"); +INITIALIZE_PASS(StackProtector, "stack-protector", + "Insert stack protectors", false, false); FunctionPass *llvm::createStackProtectorPass(const TargetLowering *tli) { return new StackProtector(tli); diff --git a/lib/CodeGen/StackSlotColoring.cpp b/lib/CodeGen/StackSlotColoring.cpp index eff3c33..8d57ae9 100644 --- a/lib/CodeGen/StackSlotColoring.cpp +++ b/lib/CodeGen/StackSlotColoring.cpp @@ -95,9 +95,9 @@ namespace { public: static char ID; // Pass identification StackSlotColoring() : - MachineFunctionPass(&ID), ColorWithRegs(false), NextColor(-1) {} + MachineFunctionPass(ID), ColorWithRegs(false), NextColor(-1) {} StackSlotColoring(bool RegColor) : - MachineFunctionPass(&ID), ColorWithRegs(RegColor), NextColor(-1) {} + MachineFunctionPass(ID), ColorWithRegs(RegColor), NextColor(-1) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); @@ -119,7 +119,6 @@ namespace { private: void InitializeSlots(); - bool CheckForSetJmpCall(const MachineFunction &MF) const; void ScanForSpillSlotRefs(MachineFunction &MF); bool OverlapWithAssignments(LiveInterval *li, int Color) const; int ColorSlot(LiveInterval *li); @@ -146,8 +145,8 @@ namespace { char StackSlotColoring::ID = 0; -static RegisterPass -X("stack-slot-coloring", "Stack Slot Coloring"); +INITIALIZE_PASS(StackSlotColoring, "stack-slot-coloring", + "Stack Slot Coloring", false, false); FunctionPass *llvm::createStackSlotColoringPass(bool RegColor) { return new StackSlotColoring(RegColor); diff --git a/lib/CodeGen/StrongPHIElimination.cpp b/lib/CodeGen/StrongPHIElimination.cpp index 59315cf..894dbfa 100644 --- a/lib/CodeGen/StrongPHIElimination.cpp +++ b/lib/CodeGen/StrongPHIElimination.cpp @@ -39,7 +39,7 @@ using namespace llvm; namespace { struct StrongPHIElimination : public MachineFunctionPass { static char ID; // Pass identification, replacement for typeid - StrongPHIElimination() : MachineFunctionPass(&ID) {} + StrongPHIElimination() : MachineFunctionPass(ID) {} // Waiting stores, for each MBB, the set of copies that need to // be inserted into that MBB @@ -150,11 +150,10 @@ namespace { } char StrongPHIElimination::ID = 0; -static RegisterPass -X("strong-phi-node-elimination", - "Eliminate PHI nodes for register allocation, intelligently"); +INITIALIZE_PASS(StrongPHIElimination, "strong-phi-node-elimination", + "Eliminate PHI nodes for register allocation, intelligently", false, false); -const PassInfo *const llvm::StrongPHIEliminationID = &X; +char &llvm::StrongPHIEliminationID = StrongPHIElimination::ID; /// computeDFS - Computes the DFS-in and DFS-out numbers of the dominator tree /// of the given MachineFunction. These numbers are then used in other parts diff --git a/lib/CodeGen/TailDuplication.cpp b/lib/CodeGen/TailDuplication.cpp index 075db80..a815b36 100644 --- a/lib/CodeGen/TailDuplication.cpp +++ b/lib/CodeGen/TailDuplication.cpp @@ -69,7 +69,7 @@ namespace { public: static char ID; explicit TailDuplicatePass(bool PreRA) : - MachineFunctionPass(&ID), PreRegAlloc(PreRA) {} + MachineFunctionPass(ID), PreRegAlloc(PreRA) {} virtual bool runOnMachineFunction(MachineFunction &MF); virtual const char *getPassName() const { return "Tail Duplication"; } @@ -254,14 +254,15 @@ bool TailDuplicatePass::TailDuplicateBlocks(MachineFunction &MF) { // SSA form. for (unsigned i = 0, e = Copies.size(); i != e; ++i) { MachineInstr *Copy = Copies[i]; - unsigned Src, Dst, SrcSR, DstSR; - if (TII->isMoveInstr(*Copy, Src, Dst, SrcSR, DstSR)) { - MachineRegisterInfo::use_iterator UI = MRI->use_begin(Src); - if (++UI == MRI->use_end()) { - // Copy is the only use. Do trivial copy propagation here. - MRI->replaceRegWith(Dst, Src); - Copy->eraseFromParent(); - } + if (!Copy->isCopy()) + continue; + unsigned Dst = Copy->getOperand(0).getReg(); + unsigned Src = Copy->getOperand(1).getReg(); + MachineRegisterInfo::use_iterator UI = MRI->use_begin(Src); + if (++UI == MRI->use_end()) { + // Copy is the only use. Do trivial copy propagation here. + MRI->replaceRegWith(Dst, Src); + Copy->eraseFromParent(); } } diff --git a/lib/CodeGen/TargetInstrInfoImpl.cpp b/lib/CodeGen/TargetInstrInfoImpl.cpp index cdacb98..6e4a0d8 100644 --- a/lib/CodeGen/TargetInstrInfoImpl.cpp +++ b/lib/CodeGen/TargetInstrInfoImpl.cpp @@ -178,19 +178,6 @@ MachineInstr *TargetInstrInfoImpl::duplicate(MachineInstr *Orig, return MF.CloneMachineInstr(Orig); } -unsigned -TargetInstrInfoImpl::GetFunctionSizeInBytes(const MachineFunction &MF) const { - unsigned FnSize = 0; - for (MachineFunction::const_iterator MBBI = MF.begin(), E = MF.end(); - MBBI != E; ++MBBI) { - const MachineBasicBlock &MBB = *MBBI; - for (MachineBasicBlock::const_iterator I = MBB.begin(),E = MBB.end(); - I != E; ++I) - FnSize += GetInstSizeInBytes(I); - } - return FnSize; -} - // If the COPY instruction in MI can be folded to a stack operation, return // the register class to use. static const TargetRegisterClass *canFoldCopy(const MachineInstr *MI, diff --git a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index a80cfc4..f1e10ee 100644 --- a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -519,11 +519,7 @@ void TargetLoweringObjectFileMachO::Initialize(MCContext &Ctx, ConstTextCoalSection = getContext().getMachOSection("__TEXT", "__const_coal", MCSectionMachO::S_COALESCED, - SectionKind::getText()); - ConstDataCoalSection - = getContext().getMachOSection("__DATA","__const_coal", - MCSectionMachO::S_COALESCED, - SectionKind::getText()); + SectionKind::getReadOnly()); ConstDataSection // .const_data = getContext().getMachOSection("__DATA", "__const", 0, SectionKind::getReadOnlyWithRel()); diff --git a/lib/CodeGen/TwoAddressInstructionPass.cpp b/lib/CodeGen/TwoAddressInstructionPass.cpp index 5649143..78989c5 100644 --- a/lib/CodeGen/TwoAddressInstructionPass.cpp +++ b/lib/CodeGen/TwoAddressInstructionPass.cpp @@ -138,7 +138,7 @@ namespace { public: static char ID; // Pass identification, replacement for typeid - TwoAddressInstructionPass() : MachineFunctionPass(&ID) {} + TwoAddressInstructionPass() : MachineFunctionPass(ID) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); @@ -159,10 +159,10 @@ namespace { } char TwoAddressInstructionPass::ID = 0; -static RegisterPass -X("twoaddressinstruction", "Two-Address instruction pass"); +INITIALIZE_PASS(TwoAddressInstructionPass, "twoaddressinstruction", + "Two-Address instruction pass", false, false); -const PassInfo *const llvm::TwoAddressInstructionPassID = &X; +char &llvm::TwoAddressInstructionPassID = TwoAddressInstructionPass::ID; /// Sink3AddrInstruction - A two-address instruction has been converted to a /// three-address instruction to avoid clobbering a register. Try to sink it @@ -380,26 +380,18 @@ static bool isCopyToReg(MachineInstr &MI, const TargetInstrInfo *TII, bool &IsSrcPhys, bool &IsDstPhys) { SrcReg = 0; DstReg = 0; - unsigned SrcSubIdx, DstSubIdx; - if (!TII->isMoveInstr(MI, SrcReg, DstReg, SrcSubIdx, DstSubIdx)) { - if (MI.isCopy()) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(1).getReg(); - } else if (MI.isInsertSubreg()) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(2).getReg(); - } else if (MI.isSubregToReg()) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(2).getReg(); - } - } + if (MI.isCopy()) { + DstReg = MI.getOperand(0).getReg(); + SrcReg = MI.getOperand(1).getReg(); + } else if (MI.isInsertSubreg() || MI.isSubregToReg()) { + DstReg = MI.getOperand(0).getReg(); + SrcReg = MI.getOperand(2).getReg(); + } else + return false; - if (DstReg) { - IsSrcPhys = TargetRegisterInfo::isPhysicalRegister(SrcReg); - IsDstPhys = TargetRegisterInfo::isPhysicalRegister(DstReg); - return true; - } - return false; + IsSrcPhys = TargetRegisterInfo::isPhysicalRegister(SrcReg); + IsDstPhys = TargetRegisterInfo::isPhysicalRegister(DstReg); + return true; } /// isKilled - Test if the given register value, which is used by the given @@ -1454,7 +1446,17 @@ bool TwoAddressInstructionPass::EliminateRegSequences() { // // If the REG_SEQUENCE doesn't kill its source, keeping live variables // correctly up to date becomes very difficult. Insert a copy. - // + + // Defer any kill flag to the last operand using SrcReg. Otherwise, we + // might insert a COPY that uses SrcReg after is was killed. + if (isKill) + for (unsigned j = i + 2; j < e; j += 2) + if (MI->getOperand(j).getReg() == SrcReg) { + MI->getOperand(j).setIsKill(); + isKill = false; + break; + } + MachineBasicBlock::iterator InsertLoc = MI; MachineInstr *CopyMI = BuildMI(*MI->getParent(), InsertLoc, MI->getDebugLoc(), TII->get(TargetOpcode::COPY)) diff --git a/lib/CodeGen/UnreachableBlockElim.cpp b/lib/CodeGen/UnreachableBlockElim.cpp index 7b33812..6dd3333 100644 --- a/lib/CodeGen/UnreachableBlockElim.cpp +++ b/lib/CodeGen/UnreachableBlockElim.cpp @@ -43,7 +43,7 @@ namespace { virtual bool runOnFunction(Function &F); public: static char ID; // Pass identification, replacement for typeid - UnreachableBlockElim() : FunctionPass(&ID) {} + UnreachableBlockElim() : FunctionPass(ID) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.addPreserved(); @@ -51,8 +51,8 @@ namespace { }; } char UnreachableBlockElim::ID = 0; -static RegisterPass -X("unreachableblockelim", "Remove unreachable blocks from the CFG"); +INITIALIZE_PASS(UnreachableBlockElim, "unreachableblockelim", + "Remove unreachable blocks from the CFG", false, false); FunctionPass *llvm::createUnreachableBlockEliminationPass() { return new UnreachableBlockElim(); @@ -100,16 +100,15 @@ namespace { MachineModuleInfo *MMI; public: static char ID; // Pass identification, replacement for typeid - UnreachableMachineBlockElim() : MachineFunctionPass(&ID) {} + UnreachableMachineBlockElim() : MachineFunctionPass(ID) {} }; } char UnreachableMachineBlockElim::ID = 0; -static RegisterPass -Y("unreachable-mbb-elimination", - "Remove unreachable machine basic blocks"); +INITIALIZE_PASS(UnreachableMachineBlockElim, "unreachable-mbb-elimination", + "Remove unreachable machine basic blocks", false, false); -const PassInfo *const llvm::UnreachableMachineBlockElimID = &Y; +char &llvm::UnreachableMachineBlockElimID = UnreachableMachineBlockElim::ID; void UnreachableMachineBlockElim::getAnalysisUsage(AnalysisUsage &AU) const { AU.addPreserved(); diff --git a/lib/CodeGen/VirtRegMap.cpp b/lib/CodeGen/VirtRegMap.cpp index ed02696..20ffcff 100644 --- a/lib/CodeGen/VirtRegMap.cpp +++ b/lib/CodeGen/VirtRegMap.cpp @@ -48,8 +48,7 @@ STATISTIC(NumSpills , "Number of register spills"); char VirtRegMap::ID = 0; -static RegisterPass -X("virtregmap", "Virtual Register Map"); +INITIALIZE_PASS(VirtRegMap, "virtregmap", "Virtual Register Map", false, false); bool VirtRegMap::runOnMachineFunction(MachineFunction &mf) { MRI = &mf.getRegInfo(); diff --git a/lib/CodeGen/VirtRegMap.h b/lib/CodeGen/VirtRegMap.h index a5599f6..8b6082d 100644 --- a/lib/CodeGen/VirtRegMap.h +++ b/lib/CodeGen/VirtRegMap.h @@ -139,7 +139,7 @@ namespace llvm { public: static char ID; - VirtRegMap() : MachineFunctionPass(&ID), Virt2PhysMap(NO_PHYS_REG), + VirtRegMap() : MachineFunctionPass(ID), Virt2PhysMap(NO_PHYS_REG), Virt2StackSlotMap(NO_STACK_SLOT), Virt2ReMatIdMap(NO_STACK_SLOT), Virt2SplitMap(0), Virt2SplitKillMap(SlotIndex()), ReMatMap(NULL), @@ -152,6 +152,11 @@ namespace llvm { MachineFunctionPass::getAnalysisUsage(AU); } + MachineFunction &getMachineFunction() const { + assert(MF && "getMachineFunction called before runOnMAchineFunction"); + return *MF; + } + void grow(); /// @brief returns true if the specified virtual register is diff --git a/lib/CodeGen/VirtRegRewriter.cpp b/lib/CodeGen/VirtRegRewriter.cpp index 57a1500..240d28c 100644 --- a/lib/CodeGen/VirtRegRewriter.cpp +++ b/lib/CodeGen/VirtRegRewriter.cpp @@ -67,23 +67,16 @@ VirtRegRewriter::~VirtRegRewriter() {} /// Note that operands may be added, so the MO reference is no longer valid. static void substitutePhysReg(MachineOperand &MO, unsigned Reg, const TargetRegisterInfo &TRI) { - if (unsigned SubIdx = MO.getSubReg()) { - // Insert the physical subreg and reset the subreg field. - MO.setReg(TRI.getSubReg(Reg, SubIdx)); - MO.setSubReg(0); - - // Any def, dead, and kill flags apply to the full virtual register, so they - // also apply to the full physical register. Add imp-def/dead and imp-kill - // as needed. + if (MO.getSubReg()) { + MO.substPhysReg(Reg, TRI); + + // Any kill flags apply to the full virtual register, so they also apply to + // the full physical register. + // We assume that partial defs have already been decorated with a super-reg + // operand by LiveIntervals. MachineInstr &MI = *MO.getParent(); - if (MO.isDef()) - if (MO.isDead()) - MI.addRegisterDead(Reg, &TRI, /*AddIfNotFound=*/ true); - else - MI.addRegisterDefined(Reg, &TRI); - else if (!MO.isUndef() && - (MO.isKill() || - MI.isRegTiedToDefOperand(&MO-&MI.getOperand(0)))) + if (MO.isUse() && !MO.isUndef() && + (MO.isKill() || MI.isRegTiedToDefOperand(&MO-&MI.getOperand(0)))) MI.addRegisterKilled(Reg, &TRI, /*AddIfNotFound=*/ true); } else { MO.setReg(Reg); @@ -460,7 +453,7 @@ public: /// blocks each of which is a successor of the specified BB and has no other /// predecessor. static void findSinglePredSuccessor(MachineBasicBlock *MBB, - SmallVectorImpl &Succs) { + SmallVectorImpl &Succs){ for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(), SE = MBB->succ_end(); SI != SE; ++SI) { MachineBasicBlock *SuccMBB = *SI; @@ -852,8 +845,8 @@ unsigned ReuseInfo::GetRegForReload(const TargetRegisterClass *RC, // Yup, use the reload register that we didn't use before. unsigned NewReg = Op.AssignedPhysReg; Rejected.insert(PhysReg); - return GetRegForReload(RC, NewReg, MF, MI, Spills, MaybeDeadStores, Rejected, - RegKills, KillOps, VRM); + return GetRegForReload(RC, NewReg, MF, MI, Spills, MaybeDeadStores, + Rejected, RegKills, KillOps, VRM); } else { // Otherwise, we might also have a problem if a previously reused // value aliases the new register. If so, codegen the previous reload @@ -1864,7 +1857,7 @@ bool LocalRewriter::InsertSpills(MachineInstr *MI) { /// rewriteMBB - Keep track of which spills are available even after the -/// register allocator is done with them. If possible, avid reloading vregs. +/// register allocator is done with them. If possible, avoid reloading vregs. void LocalRewriter::RewriteMBB(LiveIntervals *LIs, AvailableSpills &Spills, BitVector &RegKills, @@ -1914,7 +1907,6 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, if (InsertSpills(MII)) NextMII = llvm::next(MII); - VirtRegMap::MI2VirtMapTy::const_iterator I, End; bool Erased = false; bool BackTracked = false; MachineInstr &MI = *MII; @@ -2028,14 +2020,16 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, CanReuse = !ReusedOperands.isClobbered(PhysReg) && Spills.canClobberPhysReg(PhysReg); } - // If this is an asm, and PhysReg is used elsewhere as an earlyclobber - // operand, we can't also use it as an input. (Outputs always come - // before inputs, so we can stop looking at i.) + // If this is an asm, and a PhysReg alias is used elsewhere as an + // earlyclobber operand, we can't also use it as an input. if (MI.isInlineAsm()) { - for (unsigned k=0; kregsOverlap(MOk.getReg(), PhysReg)) { CanReuse = false; + DEBUG(dbgs() << "Not reusing physreg " << TRI->getName(PhysReg) + << " for vreg" << VirtReg << ": " << MOk << '\n'); break; } } @@ -2248,15 +2242,22 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, // If we have folded references to memory operands, make sure we clear all // physical registers that may contain the value of the spilled virtual // register + + // Copy the folded virts to a small vector, we may change MI2VirtMap. + SmallVector, 4> FoldedVirts; + // C++0x FTW! + for (std::pair FVRange = + VRM->getFoldedVirts(&MI); + FVRange.first != FVRange.second; ++FVRange.first) + FoldedVirts.push_back(FVRange.first->second); + SmallSet FoldedSS; - for (tie(I, End) = VRM->getFoldedVirts(&MI); I != End; ) { - unsigned VirtReg = I->second.first; - VirtRegMap::ModRef MR = I->second.second; + for (unsigned FVI = 0, FVE = FoldedVirts.size(); FVI != FVE; ++FVI) { + unsigned VirtReg = FoldedVirts[FVI].first; + VirtRegMap::ModRef MR = FoldedVirts[FVI].second; DEBUG(dbgs() << "Folded vreg: " << VirtReg << " MR: " << MR); - // MI2VirtMap be can updated which invalidate the iterator. - // Increment the iterator first. - ++I; int SS = VRM->getStackSlot(VirtReg); if (SS == VirtRegMap::NO_STACK_SLOT) continue; @@ -2302,7 +2303,7 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, unsigned PhysReg = Spills.getSpillSlotOrReMatPhysReg(SS); SmallVector NewMIs; if (PhysReg && - TII->unfoldMemoryOperand(MF, &MI, PhysReg, false, false, NewMIs)) { + TII->unfoldMemoryOperand(MF, &MI, PhysReg, false, false, NewMIs)){ MBB->insert(MII, NewMIs[0]); InvalidateKills(MI, TRI, RegKills, KillOps); VRM->RemoveMachineInstrFromMaps(&MI); @@ -2442,28 +2443,6 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, Spills.disallowClobberPhysReg(VirtReg); goto ProcessNextInst; } - unsigned Src, Dst, SrcSR, DstSR; - if (TII->isMoveInstr(MI, Src, Dst, SrcSR, DstSR) && - Src == Dst && SrcSR == DstSR && - !MI.findRegisterUseOperand(Src)->isUndef()) { - ++NumDCE; - DEBUG(dbgs() << "Removing now-noop copy: " << MI); - SmallVector KillRegs; - InvalidateKills(MI, TRI, RegKills, KillOps, &KillRegs); - if (MO.isDead() && !KillRegs.empty()) { - // Source register or an implicit super/sub-register use is killed. - assert(KillRegs[0] == Dst || - TRI->isSubRegister(KillRegs[0], Dst) || - TRI->isSuperRegister(KillRegs[0], Dst)); - // Last def is now dead. - TransferDeadness(Src, RegKills, KillOps); - } - VRM->RemoveMachineInstrFromMaps(&MI); - MBB->erase(&MI); - Erased = true; - Spills.disallowClobberPhysReg(VirtReg); - goto ProcessNextInst; - } // If it's not a no-op copy, it clobbers the value in the destreg. Spills.ClobberPhysReg(VirtReg); @@ -2541,20 +2520,6 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, UpdateKills(*LastStore, TRI, RegKills, KillOps); goto ProcessNextInst; } - { - unsigned Src, Dst, SrcSR, DstSR; - if (TII->isMoveInstr(MI, Src, Dst, SrcSR, DstSR) && - Src == Dst && SrcSR == DstSR) { - ++NumDCE; - DEBUG(dbgs() << "Removing now-noop copy: " << MI); - InvalidateKills(MI, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(&MI); - MBB->erase(&MI); - Erased = true; - UpdateKills(*LastStore, TRI, RegKills, KillOps); - goto ProcessNextInst; - } - } } } ProcessNextInst: diff --git a/lib/CompilerDriver/Action.cpp b/lib/CompilerDriver/Action.cpp index 5f30dce..0be8049 100644 --- a/lib/CompilerDriver/Action.cpp +++ b/lib/CompilerDriver/Action.cpp @@ -13,6 +13,7 @@ #include "llvm/CompilerDriver/Action.h" #include "llvm/CompilerDriver/BuiltinOptions.h" +#include "llvm/CompilerDriver/Error.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SystemUtils.h" @@ -58,11 +59,15 @@ namespace { if (prog.isEmpty()) { prog = FindExecutable(name, ProgramName, (void *)(intptr_t)&Main); - if (prog.isEmpty()) - throw std::runtime_error("Can't find program '" + name + "'"); + if (prog.isEmpty()) { + PrintError("Can't find program '" + name + "'"); + return -1; + } + } + if (!prog.canExecute()) { + PrintError("Program '" + name + "' is not executable."); + return -1; } - if (!prog.canExecute()) - throw std::runtime_error("Program '" + name + "' is not executable."); // Build the command line vector and the redirects array. const sys::Path* redirects[3] = {0,0,0}; diff --git a/lib/CompilerDriver/BuiltinOptions.cpp b/lib/CompilerDriver/BuiltinOptions.cpp index d1ac8c9..3844203 100644 --- a/lib/CompilerDriver/BuiltinOptions.cpp +++ b/lib/CompilerDriver/BuiltinOptions.cpp @@ -19,7 +19,7 @@ namespace cl = llvm::cl; -// External linkage here is intentional. +namespace llvmc { cl::list InputFilenames(cl::Positional, cl::desc(""), cl::ZeroOrMore); @@ -57,3 +57,5 @@ cl::opt SaveTemps clEnumValN(SaveTempsEnum::Obj, "", "Same as 'cwd'"), clEnumValEnd), cl::ValueOptional); + +} // End namespace llvmc. diff --git a/lib/CompilerDriver/CompilationGraph.cpp b/lib/CompilerDriver/CompilationGraph.cpp index 7d1c7fe..d0c0e15 100644 --- a/lib/CompilerDriver/CompilationGraph.cpp +++ b/lib/CompilerDriver/CompilationGraph.cpp @@ -25,39 +25,46 @@ #include #include #include -#include using namespace llvm; using namespace llvmc; namespace llvmc { - const std::string& LanguageMap::GetLanguage(const sys::Path& File) const { + const std::string* LanguageMap::GetLanguage(const sys::Path& File) const { StringRef suf = File.getSuffix(); LanguageMap::const_iterator Lang = this->find(suf.empty() ? "*empty*" : suf); - if (Lang == this->end()) - throw std::runtime_error("File '" + File.str() + - "' has unknown suffix '" + suf.str() + '\''); - return Lang->second; + if (Lang == this->end()) { + PrintError("File '" + File.str() + "' has unknown suffix '" + + suf.str() + '\''); + return 0; + } + return &Lang->second; } } namespace { - /// ChooseEdge - Return the edge with the maximum weight. + /// ChooseEdge - Return the edge with the maximum weight. Returns 0 on error. template const Edge* ChooseEdge(const C& EdgesContainer, const InputLanguagesSet& InLangs, const std::string& NodeName = "root") { const Edge* MaxEdge = 0; - unsigned MaxWeight = 0; + int MaxWeight = 0; bool SingleMax = true; + // TODO: fix calculation of SingleMax. for (typename C::const_iterator B = EdgesContainer.begin(), E = EdgesContainer.end(); B != E; ++B) { const Edge* e = B->getPtr(); - unsigned EW = e->Weight(InLangs); + int EW = e->Weight(InLangs); + if (EW < 0) { + // (error) invocation in TableGen -> we don't need to print an error + // message. + return 0; + } if (EW > MaxWeight) { MaxEdge = e; MaxWeight = EW; @@ -67,14 +74,16 @@ namespace { } } - if (!SingleMax) - throw std::runtime_error("Node " + NodeName + - ": multiple maximal outward edges found!" - " Most probably a specification error."); - if (!MaxEdge) - throw std::runtime_error("Node " + NodeName + - ": no maximal outward edge found!" - " Most probably a specification error."); + if (!SingleMax) { + PrintError("Node " + NodeName + ": multiple maximal outward edges found!" + " Most probably a specification error."); + return 0; + } + if (!MaxEdge) { + PrintError("Node " + NodeName + ": no maximal outward edge found!" + " Most probably a specification error."); + return 0; + } return MaxEdge; } @@ -98,29 +107,34 @@ CompilationGraph::CompilationGraph() { NodesMap["root"] = Node(this); } -Node& CompilationGraph::getNode(const std::string& ToolName) { +Node* CompilationGraph::getNode(const std::string& ToolName) { nodes_map_type::iterator I = NodesMap.find(ToolName); - if (I == NodesMap.end()) - throw std::runtime_error("Node " + ToolName + " is not in the graph"); - return I->second; + if (I == NodesMap.end()) { + PrintError("Node " + ToolName + " is not in the graph"); + return 0; + } + return &I->second; } -const Node& CompilationGraph::getNode(const std::string& ToolName) const { +const Node* CompilationGraph::getNode(const std::string& ToolName) const { nodes_map_type::const_iterator I = NodesMap.find(ToolName); - if (I == NodesMap.end()) - throw std::runtime_error("Node " + ToolName + " is not in the graph!"); - return I->second; + if (I == NodesMap.end()) { + PrintError("Node " + ToolName + " is not in the graph!"); + return 0; + } + return &I->second; } // Find the tools list corresponding to the given language name. -const CompilationGraph::tools_vector_type& +const CompilationGraph::tools_vector_type* CompilationGraph::getToolsVector(const std::string& LangName) const { tools_map_type::const_iterator I = ToolsMap.find(LangName); - if (I == ToolsMap.end()) - throw std::runtime_error("No tool corresponding to the language " - + LangName + " found"); - return I->second; + if (I == ToolsMap.end()) { + PrintError("No tool corresponding to the language " + LangName + " found"); + return 0; + } + return &I->second; } void CompilationGraph::insertNode(Tool* V) { @@ -128,29 +142,37 @@ void CompilationGraph::insertNode(Tool* V) { NodesMap[V->Name()] = Node(this, V); } -void CompilationGraph::insertEdge(const std::string& A, Edge* Edg) { - Node& B = getNode(Edg->ToolName()); +int CompilationGraph::insertEdge(const std::string& A, Edge* Edg) { + Node* B = getNode(Edg->ToolName()); + if (B == 0) + return 1; + if (A == "root") { - const char** InLangs = B.ToolPtr->InputLanguages(); + const char** InLangs = B->ToolPtr->InputLanguages(); for (;*InLangs; ++InLangs) ToolsMap[*InLangs].push_back(IntrusiveRefCntPtr(Edg)); NodesMap["root"].AddEdge(Edg); } else { - Node& N = getNode(A); - N.AddEdge(Edg); + Node* N = getNode(A); + if (N == 0) + return 1; + + N->AddEdge(Edg); } // Increase the inward edge counter. - B.IncrInEdges(); + B->IncrInEdges(); + + return 0; } // Pass input file through the chain until we bump into a Join node or // a node that says that it is the last. -void CompilationGraph::PassThroughGraph (const sys::Path& InFile, - const Node* StartNode, - const InputLanguagesSet& InLangs, - const sys::Path& TempDir, - const LanguageMap& LangMap) const { +int CompilationGraph::PassThroughGraph (const sys::Path& InFile, + const Node* StartNode, + const InputLanguagesSet& InLangs, + const sys::Path& TempDir, + const LanguageMap& LangMap) const { sys::Path In = InFile; const Node* CurNode = StartNode; @@ -158,25 +180,35 @@ void CompilationGraph::PassThroughGraph (const sys::Path& InFile, Tool* CurTool = CurNode->ToolPtr.getPtr(); if (CurTool->IsJoin()) { - JoinTool& JT = dynamic_cast(*CurTool); + JoinTool& JT = static_cast(*CurTool); JT.AddToJoinList(In); break; } - Action CurAction = CurTool->GenerateAction(In, CurNode->HasChildren(), - TempDir, InLangs, LangMap); + Action CurAction; + if (int ret = CurTool->GenerateAction(CurAction, In, CurNode->HasChildren(), + TempDir, InLangs, LangMap)) { + return ret; + } if (int ret = CurAction.Execute()) - throw error_code(ret); + return ret; if (CurAction.StopCompilation()) - return; + return 0; + + const Edge* Edg = ChooseEdge(CurNode->OutEdges, InLangs, CurNode->Name()); + if (Edg == 0) + return 1; + + CurNode = getNode(Edg->ToolName()); + if (CurNode == 0) + return 1; - CurNode = &getNode(ChooseEdge(CurNode->OutEdges, - InLangs, - CurNode->Name())->ToolName()); In = CurAction.OutFile(); } + + return 0; } // Find the head of the toolchain corresponding to the given file. @@ -186,26 +218,39 @@ FindToolChain(const sys::Path& In, const std::string* ForceLanguage, InputLanguagesSet& InLangs, const LanguageMap& LangMap) const { // Determine the input language. - const std::string& InLanguage = - ForceLanguage ? *ForceLanguage : LangMap.GetLanguage(In); + const std::string* InLang = LangMap.GetLanguage(In); + if (InLang == 0) + return 0; + const std::string& InLanguage = (ForceLanguage ? *ForceLanguage : *InLang); // Add the current input language to the input language set. InLangs.insert(InLanguage); // Find the toolchain for the input language. - const tools_vector_type& TV = getToolsVector(InLanguage); - if (TV.empty()) - throw std::runtime_error("No toolchain corresponding to language " - + InLanguage + " found"); - return &getNode(ChooseEdge(TV, InLangs)->ToolName()); + const tools_vector_type* pTV = getToolsVector(InLanguage); + if (pTV == 0) + return 0; + + const tools_vector_type& TV = *pTV; + if (TV.empty()) { + PrintError("No toolchain corresponding to language " + + InLanguage + " found"); + return 0; + } + + const Edge* Edg = ChooseEdge(TV, InLangs); + if (Edg == 0) + return 0; + + return getNode(Edg->ToolName()); } // Helper function used by Build(). // Traverses initial portions of the toolchains (up to the first Join node). // This function is also responsible for handling the -x option. -void CompilationGraph::BuildInitial (InputLanguagesSet& InLangs, - const sys::Path& TempDir, - const LanguageMap& LangMap) { +int CompilationGraph::BuildInitial (InputLanguagesSet& InLangs, + const sys::Path& TempDir, + const LanguageMap& LangMap) { // This is related to -x option handling. cl::list::const_iterator xIter = Languages.begin(), xBegin = xIter, xEnd = Languages.end(); @@ -255,15 +300,25 @@ void CompilationGraph::BuildInitial (InputLanguagesSet& InLangs, // Find the toolchain corresponding to this file. const Node* N = FindToolChain(In, xLanguage, InLangs, LangMap); + if (N == 0) + return 1; // Pass file through the chain starting at head. - PassThroughGraph(In, N, InLangs, TempDir, LangMap); + if (int ret = PassThroughGraph(In, N, InLangs, TempDir, LangMap)) + return ret; } + + return 0; } // Sort the nodes in topological order. -void CompilationGraph::TopologicalSort(std::vector& Out) { +int CompilationGraph::TopologicalSort(std::vector& Out) { std::queue Q; - Q.push(&getNode("root")); + + Node* Root = getNode("root"); + if (Root == 0) + return 1; + + Q.push(Root); while (!Q.empty()) { const Node* A = Q.front(); @@ -271,12 +326,17 @@ void CompilationGraph::TopologicalSort(std::vector& Out) { Out.push_back(A); for (Node::const_iterator EB = A->EdgesBegin(), EE = A->EdgesEnd(); EB != EE; ++EB) { - Node* B = &getNode((*EB)->ToolName()); + Node* B = getNode((*EB)->ToolName()); + if (B == 0) + return 1; + B->DecrInEdges(); if (B->HasNoInEdges()) Q.push(B); } } + + return 0; } namespace { @@ -287,49 +347,71 @@ namespace { // Call TopologicalSort and filter the resulting list to include // only Join nodes. -void CompilationGraph:: +int CompilationGraph:: TopologicalSortFilterJoinNodes(std::vector& Out) { std::vector TopSorted; - TopologicalSort(TopSorted); + if (int ret = TopologicalSort(TopSorted)) + return ret; std::remove_copy_if(TopSorted.begin(), TopSorted.end(), std::back_inserter(Out), NotJoinNode); + + return 0; } int CompilationGraph::Build (const sys::Path& TempDir, const LanguageMap& LangMap) { - InputLanguagesSet InLangs; + bool WasSomeActionGenerated = !InputFilenames.empty(); // Traverse initial parts of the toolchains and fill in InLangs. - BuildInitial(InLangs, TempDir, LangMap); + if (int ret = BuildInitial(InLangs, TempDir, LangMap)) + return ret; std::vector JTV; - TopologicalSortFilterJoinNodes(JTV); + if (int ret = TopologicalSortFilterJoinNodes(JTV)) + return ret; // For all join nodes in topological order: for (std::vector::iterator B = JTV.begin(), E = JTV.end(); B != E; ++B) { const Node* CurNode = *B; - JoinTool* JT = &dynamic_cast(*CurNode->ToolPtr.getPtr()); + JoinTool* JT = &static_cast(*CurNode->ToolPtr.getPtr()); // Are there any files in the join list? if (JT->JoinListEmpty() && !(JT->WorksOnEmpty() && InputFilenames.empty())) continue; - Action CurAction = JT->GenerateAction(CurNode->HasChildren(), - TempDir, InLangs, LangMap); + WasSomeActionGenerated = true; + Action CurAction; + if (int ret = JT->GenerateAction(CurAction, CurNode->HasChildren(), + TempDir, InLangs, LangMap)) { + return ret; + } if (int ret = CurAction.Execute()) - throw error_code(ret); + return ret; if (CurAction.StopCompilation()) return 0; - const Node* NextNode = &getNode(ChooseEdge(CurNode->OutEdges, InLangs, - CurNode->Name())->ToolName()); - PassThroughGraph(sys::Path(CurAction.OutFile()), NextNode, - InLangs, TempDir, LangMap); + const Edge* Edg = ChooseEdge(CurNode->OutEdges, InLangs, CurNode->Name()); + if (Edg == 0) + return 1; + + const Node* NextNode = getNode(Edg->ToolName()); + if (NextNode == 0) + return 1; + + if (int ret = PassThroughGraph(sys::Path(CurAction.OutFile()), NextNode, + InLangs, TempDir, LangMap)) { + return ret; + } + } + + if (!WasSomeActionGenerated) { + PrintError("no input files"); + return 1; } return 0; @@ -337,6 +419,7 @@ int CompilationGraph::Build (const sys::Path& TempDir, int CompilationGraph::CheckLanguageNames() const { int ret = 0; + // Check that names for output and input languages on all edges do match. for (const_nodes_iterator B = this->NodesMap.begin(), E = this->NodesMap.end(); B != E; ++B) { @@ -345,9 +428,11 @@ int CompilationGraph::CheckLanguageNames() const { if (N1.ToolPtr) { for (Node::const_iterator EB = N1.EdgesBegin(), EE = N1.EdgesEnd(); EB != EE; ++EB) { - const Node& N2 = this->getNode((*EB)->ToolName()); + const Node* N2 = this->getNode((*EB)->ToolName()); + if (N2 == 0) + return 1; - if (!N2.ToolPtr) { + if (!N2->ToolPtr) { ++ret; errs() << "Error: there is an edge from '" << N1.ToolPtr->Name() << "' back to the root!\n\n"; @@ -355,7 +440,7 @@ int CompilationGraph::CheckLanguageNames() const { } const char* OutLang = N1.ToolPtr->OutputLanguage(); - const char** InLangs = N2.ToolPtr->InputLanguages(); + const char** InLangs = N2->ToolPtr->InputLanguages(); bool eq = false; for (;*InLangs; ++InLangs) { if (std::strcmp(OutLang, *InLangs) == 0) { @@ -367,11 +452,11 @@ int CompilationGraph::CheckLanguageNames() const { if (!eq) { ++ret; errs() << "Error: Output->input language mismatch in the edge '" - << N1.ToolPtr->Name() << "' -> '" << N2.ToolPtr->Name() + << N1.ToolPtr->Name() << "' -> '" << N2->ToolPtr->Name() << "'!\n" << "Expected one of { "; - InLangs = N2.ToolPtr->InputLanguages(); + InLangs = N2->ToolPtr->InputLanguages(); for (;*InLangs; ++InLangs) { errs() << '\'' << *InLangs << (*(InLangs+1) ? "', " : "'"); } @@ -395,7 +480,7 @@ int CompilationGraph::CheckMultipleDefaultEdges() const { for (const_nodes_iterator B = this->NodesMap.begin(), E = this->NodesMap.end(); B != E; ++B) { const Node& N = B->second; - unsigned MaxWeight = 0; + int MaxWeight = 0; // Ignore the root node. if (!N.ToolPtr) @@ -403,7 +488,7 @@ int CompilationGraph::CheckMultipleDefaultEdges() const { for (Node::const_iterator EB = N.EdgesBegin(), EE = N.EdgesEnd(); EB != EE; ++EB) { - unsigned EdgeWeight = (*EB)->Weight(Dummy); + int EdgeWeight = (*EB)->Weight(Dummy); if (EdgeWeight > MaxWeight) { MaxWeight = EdgeWeight; } @@ -422,7 +507,12 @@ int CompilationGraph::CheckMultipleDefaultEdges() const { int CompilationGraph::CheckCycles() { unsigned deleted = 0; std::queue Q; - Q.push(&getNode("root")); + + Node* Root = getNode("root"); + if (Root == 0) + return 1; + + Q.push(Root); // Try to delete all nodes that have no ingoing edges, starting from the // root. If there are any nodes left after this operation, then we have a @@ -434,7 +524,10 @@ int CompilationGraph::CheckCycles() { for (Node::iterator EB = A->EdgesBegin(), EE = A->EdgesEnd(); EB != EE; ++EB) { - Node* B = &getNode((*EB)->ToolName()); + Node* B = getNode((*EB)->ToolName()); + if (B == 0) + return 1; + B->DecrInEdges(); if (B->HasNoInEdges()) Q.push(B); @@ -453,18 +546,28 @@ int CompilationGraph::CheckCycles() { int CompilationGraph::Check () { // We try to catch as many errors as we can in one go. + int errs = 0; int ret = 0; // Check that output/input language names match. - ret += this->CheckLanguageNames(); + ret = this->CheckLanguageNames(); + if (ret < 0) + return 1; + errs += ret; // Check for multiple default edges. - ret += this->CheckMultipleDefaultEdges(); + ret = this->CheckMultipleDefaultEdges(); + if (ret < 0) + return 1; + errs += ret; // Check for cycles. - ret += this->CheckCycles(); + ret = this->CheckCycles(); + if (ret < 0) + return 1; + errs += ret; - return ret; + return errs; } // Code related to graph visualization. @@ -516,7 +619,7 @@ namespace llvm { } -void CompilationGraph::writeGraph(const std::string& OutputFilename) { +int CompilationGraph::writeGraph(const std::string& OutputFilename) { std::string ErrorInfo; raw_fd_ostream O(OutputFilename.c_str(), ErrorInfo); @@ -526,9 +629,11 @@ void CompilationGraph::writeGraph(const std::string& OutputFilename) { errs() << "done.\n"; } else { - throw std::runtime_error("Error opening file '" + OutputFilename - + "' for writing!"); + PrintError("Error opening file '" + OutputFilename + "' for writing!"); + return 1; } + + return 0; } void CompilationGraph::viewGraph() { diff --git a/lib/CompilerDriver/Main.cpp b/lib/CompilerDriver/Main.cpp index b5e507d..0a6613a 100644 --- a/lib/CompilerDriver/Main.cpp +++ b/lib/CompilerDriver/Main.cpp @@ -11,16 +11,15 @@ // //===----------------------------------------------------------------------===// +#include "llvm/CompilerDriver/AutoGenerated.h" #include "llvm/CompilerDriver/BuiltinOptions.h" #include "llvm/CompilerDriver/CompilationGraph.h" #include "llvm/CompilerDriver/Error.h" -#include "llvm/CompilerDriver/Plugin.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include -#include #include namespace cl = llvm::cl; @@ -31,9 +30,9 @@ namespace { std::stringstream* GlobalTimeLog; - sys::Path getTempDir() { - sys::Path tempDir; - + /// GetTempDir - Get the temporary directory location. Returns non-zero value + /// on error. + int GetTempDir(sys::Path& tempDir) { // The --temp-dir option. if (!TempDirname.empty()) { tempDir = TempDirname; @@ -41,7 +40,7 @@ namespace { // GCC 4.5-style -save-temps handling. else if (SaveTemps == SaveTempsEnum::Unset) { tempDir = sys::Path::GetTemporaryDirectory(); - return tempDir; + return 0; } else if (SaveTemps == SaveTempsEnum::Obj && !OutputFilename.empty()) { tempDir = OutputFilename; @@ -49,35 +48,35 @@ namespace { } else { // SaveTemps == Cwd --> use current dir (leave tempDir empty). - return tempDir; + return 0; } if (!tempDir.exists()) { std::string ErrMsg; - if (tempDir.createDirectoryOnDisk(true, &ErrMsg)) - throw std::runtime_error(ErrMsg); + if (tempDir.createDirectoryOnDisk(true, &ErrMsg)) { + PrintError(ErrMsg); + return 1; + } } - return tempDir; + return 0; } - /// BuildTargets - A small wrapper for CompilationGraph::Build. + /// BuildTargets - A small wrapper for CompilationGraph::Build. Returns + /// non-zero value in case of error. int BuildTargets(CompilationGraph& graph, const LanguageMap& langMap) { int ret; - const sys::Path& tempDir = getTempDir(); + sys::Path tempDir; bool toDelete = (SaveTemps == SaveTempsEnum::Unset); - try { - ret = graph.Build(tempDir, langMap); - } - catch(...) { - if (toDelete) - tempDir.eraseFromDisk(true); - throw; - } + if (int ret = GetTempDir(tempDir)) + return ret; + + ret = graph.Build(tempDir, langMap); if (toDelete) tempDir.eraseFromDisk(true); + return ret; } } @@ -89,68 +88,58 @@ void AppendToGlobalTimeLog(const std::string& cmd, double time) { *GlobalTimeLog << "# " << cmd << ' ' << time << '\n'; } -// Sometimes plugins want to condition on the value in argv[0]. +// Sometimes user code wants to access the argv[0] value. const char* ProgramName; int Main(int argc, char** argv) { - try { - LanguageMap langMap; - CompilationGraph graph; - - ProgramName = argv[0]; + int ret = 0; + LanguageMap langMap; + CompilationGraph graph; - cl::ParseCommandLineOptions - (argc, argv, "LLVM Compiler Driver (Work In Progress)", - /* ReadResponseFiles = */ false); + ProgramName = argv[0]; - PluginLoader Plugins; - Plugins.RunInitialization(langMap, graph); + cl::ParseCommandLineOptions + (argc, argv, + /* Overview = */ "LLVM Compiler Driver (Work In Progress)", + /* ReadResponseFiles = */ false); - if (CheckGraph) { - int ret = graph.Check(); - if (!ret) - llvm::errs() << "check-graph: no errors found.\n"; + if (int ret = autogenerated::RunInitialization(langMap, graph)) + return ret; - return ret; - } + if (CheckGraph) { + ret = graph.Check(); + if (!ret) + llvm::errs() << "check-graph: no errors found.\n"; - if (ViewGraph) { - graph.viewGraph(); - if (!WriteGraph) - return 0; - } + return ret; + } - if (WriteGraph) { - graph.writeGraph(OutputFilename.empty() - ? std::string("compilation-graph.dot") - : OutputFilename); + if (ViewGraph) { + graph.viewGraph(); + if (!WriteGraph) return 0; - } + } - if (Time) { - GlobalTimeLog = new std::stringstream; - GlobalTimeLog->precision(2); - } + if (WriteGraph) { + const std::string& Out = (OutputFilename.empty() + ? std::string("compilation-graph.dot") + : OutputFilename); + return graph.writeGraph(Out); + } - int ret = BuildTargets(graph, langMap); + if (Time) { + GlobalTimeLog = new std::stringstream; + GlobalTimeLog->precision(2); + } - if (Time) { - llvm::errs() << GlobalTimeLog->str(); - delete GlobalTimeLog; - } + ret = BuildTargets(graph, langMap); - return ret; - } - catch(llvmc::error_code& ec) { - return ec.code(); + if (Time) { + llvm::errs() << GlobalTimeLog->str(); + delete GlobalTimeLog; } - catch(const std::exception& ex) { - llvm::errs() << argv[0] << ": " << ex.what() << '\n'; - } - catch(...) { - llvm::errs() << argv[0] << ": unknown error!\n"; - } - return 1; + + return ret; } } // end namespace llvmc diff --git a/lib/CompilerDriver/Makefile b/lib/CompilerDriver/Makefile index 66c6d11..8e8b73c 100644 --- a/lib/CompilerDriver/Makefile +++ b/lib/CompilerDriver/Makefile @@ -10,39 +10,11 @@ LEVEL = ../.. # We don't want this library to appear in `llvm-config --libs` output, so its -# name doesn't start with "LLVM". +# name doesn't start with "LLVM" and NO_LLVM_CONFIG is set. -ifeq ($(ENABLE_LLVMC_DYNAMIC),1) - LIBRARYNAME = libCompilerDriver - LLVMLIBS = LLVMSupport.a LLVMSystem.a - LOADABLE_MODULE := 1 -else - LIBRARYNAME = CompilerDriver - LINK_COMPONENTS = support system -endif +LIBRARYNAME = CompilerDriver +LINK_COMPONENTS = support system +NO_LLVM_CONFIG = 1 -REQUIRES_EH := 1 -REQUIRES_RTTI := 1 include $(LEVEL)/Makefile.common - -ifeq ($(ENABLE_LLVMC_DYNAMIC_PLUGINS), 1) - CPP.Flags += -DENABLE_LLVMC_DYNAMIC_PLUGINS -endif - -# Copy libCompilerDriver to the bin dir so that llvmc can find it. -ifeq ($(ENABLE_LLVMC_DYNAMIC),1) - -FullLibName = $(LIBRARYNAME)$(SHLIBEXT) - -all-local:: $(ToolDir)/$(FullLibName) - -$(ToolDir)/$(FullLibName): $(LibDir)/$(FullLibName) $(ToolDir)/.dir - $(Echo) Copying $(BuildMode) Shared Library $(FullLibName) to $@ - -$(Verb) $(CP) $< $@ - -clean-local:: - $(Echo) Removing $(BuildMode) Shared Library $(FullLibName) \ - from $(ToolDir) - -$(Verb) $(RM) -f $(ToolDir)/$(FullLibName) -endif diff --git a/lib/CompilerDriver/Plugin.cpp b/lib/CompilerDriver/Plugin.cpp deleted file mode 100644 index 0fdfef4..0000000 --- a/lib/CompilerDriver/Plugin.cpp +++ /dev/null @@ -1,78 +0,0 @@ -//===--- Plugin.cpp - The LLVM Compiler Driver ------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open -// Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Plugin support. -// -//===----------------------------------------------------------------------===// - -#include "llvm/CompilerDriver/Plugin.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/System/Mutex.h" -#include -#include - -namespace { - - // Registry::Add<> does not do lifetime management (probably issues - // with static constructor/destructor ordering), so we have to - // implement it here. - // - // All this static registration/life-before-main model seems - // unnecessary convoluted to me. - - static bool pluginListInitialized = false; - typedef std::vector PluginList; - static PluginList Plugins; - static llvm::ManagedStatic > PluginMutex; - - struct ByPriority { - bool operator()(const llvmc::BasePlugin* lhs, - const llvmc::BasePlugin* rhs) { - return lhs->Priority() < rhs->Priority(); - } - }; -} - -namespace llvmc { - - PluginLoader::PluginLoader() { - llvm::sys::SmartScopedLock Lock(*PluginMutex); - if (!pluginListInitialized) { - for (PluginRegistry::iterator B = PluginRegistry::begin(), - E = PluginRegistry::end(); B != E; ++B) - Plugins.push_back(B->instantiate()); - std::sort(Plugins.begin(), Plugins.end(), ByPriority()); - } - pluginListInitialized = true; - } - - PluginLoader::~PluginLoader() { - llvm::sys::SmartScopedLock Lock(*PluginMutex); - if (pluginListInitialized) { - for (PluginList::iterator B = Plugins.begin(), E = Plugins.end(); - B != E; ++B) - delete (*B); - } - pluginListInitialized = false; - } - - void PluginLoader::RunInitialization(LanguageMap& langMap, - CompilationGraph& graph) const - { - llvm::sys::SmartScopedLock Lock(*PluginMutex); - for (PluginList::iterator B = Plugins.begin(), E = Plugins.end(); - B != E; ++B) { - const BasePlugin* BP = *B; - BP->PreprocessOptions(); - BP->PopulateLanguageMap(langMap); - BP->PopulateCompilationGraph(graph); - } - } - -} diff --git a/lib/ExecutionEngine/ExecutionEngineBindings.cpp b/lib/ExecutionEngine/ExecutionEngineBindings.cpp index c7495d4..f8f1f4a 100644 --- a/lib/ExecutionEngine/ExecutionEngineBindings.cpp +++ b/lib/ExecutionEngine/ExecutionEngineBindings.cpp @@ -236,6 +236,10 @@ LLVMBool LLVMFindFunction(LLVMExecutionEngineRef EE, const char *Name, return 1; } +void *LLVMRecompileAndRelinkFunction(LLVMExecutionEngineRef EE, LLVMValueRef Fn) { + return unwrap(EE)->recompileAndRelinkFunction(unwrap(Fn)); +} + LLVMTargetDataRef LLVMGetExecutionEngineTargetData(LLVMExecutionEngineRef EE) { return wrap(unwrap(EE)->getTargetData()); } diff --git a/lib/ExecutionEngine/JIT/Intercept.cpp b/lib/ExecutionEngine/JIT/Intercept.cpp index b367033..274f816 100644 --- a/lib/ExecutionEngine/JIT/Intercept.cpp +++ b/lib/ExecutionEngine/JIT/Intercept.cpp @@ -89,6 +89,10 @@ static int jit_atexit(void (*Fn)()) { return 0; // Always successful } +static int jit_noop() { + return 0; +} + //===----------------------------------------------------------------------===// // /// getPointerToNamedFunction - This method returns the address of the specified @@ -104,6 +108,14 @@ void *JIT::getPointerToNamedFunction(const std::string &Name, if (Name == "exit") return (void*)(intptr_t)&jit_exit; if (Name == "atexit") return (void*)(intptr_t)&jit_atexit; + // We should not invoke parent's ctors/dtors from generated main()! + // On Mingw and Cygwin, the symbol __main is resolved to + // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors + // (and register wrong callee's dtors with atexit(3)). + // We expect ExecutionEngine::runStaticConstructorsDestructors() + // is called before ExecutionEngine::runFunctionAsMain() is called. + if (Name == "__main") return (void*)(intptr_t)&jit_noop; + const char *NameStr = Name.c_str(); // If this is an asm specifier, skip the sentinal. if (NameStr[0] == 1) ++NameStr; diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp index 67bd3ed..63125b7 100644 --- a/lib/ExecutionEngine/JIT/JIT.cpp +++ b/lib/ExecutionEngine/JIT/JIT.cpp @@ -67,7 +67,7 @@ extern "C" void LLVMLinkInJIT() { } -#if defined(__GNUC__) && !defined(__ARM__EABI__) +#if defined(__GNUC__) && !defined(__ARM_EABI__) && !defined(__USING_SJLJ_EXCEPTIONS__) // libgcc defines the __register_frame function to dynamically register new // dwarf frames for exception handling. This functionality is not portable @@ -219,10 +219,8 @@ ExecutionEngine *JIT::createJIT(Module *M, StringRef MArch, StringRef MCPU, const SmallVectorImpl& MAttrs) { - // Make sure we can resolve symbols in the program as well. The zero arg - // to the function tells DynamicLibrary to load the program, not a library. - if (sys::DynamicLibrary::LoadLibraryPermanently(0, ErrorStr)) - return 0; + // Try to register the program as a source of symbols to resolve against. + sys::DynamicLibrary::LoadLibraryPermanently(0, NULL); // Pick a target either via -march or by guessing the native arch. TargetMachine *TM = JIT::selectTarget(M, MArch, MCPU, MAttrs, ErrorStr); @@ -308,7 +306,7 @@ JIT::JIT(Module *M, TargetMachine &tm, TargetJITInfo &tji, } // Register routine for informing unwinding runtime about new EH frames -#if defined(__GNUC__) && !defined(__ARM_EABI__) +#if defined(__GNUC__) && !defined(__ARM_EABI__) && !defined(__USING_SJLJ_EXCEPTIONS__) #if USE_KEYMGR struct LibgccObjectInfo* LOI = (struct LibgccObjectInfo*) _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST); diff --git a/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp b/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp index 749a57d..6e11a3c 100644 --- a/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp +++ b/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp @@ -90,8 +90,8 @@ std::string JITDebugRegisterer::MakeELF(const Function *F, DebugInfo &I) { // section. This allows GDB to get a good stack trace, particularly on // linux x86_64. Mark this as a PROGBITS section that needs to be loaded // into memory at runtime. - ELFSection &EH = EW.getSection(".eh_frame", ELFSection::SHT_PROGBITS, - ELFSection::SHF_ALLOC); + ELFSection &EH = EW.getSection(".eh_frame", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC); // Pointers in the DWARF EH info are all relative to the EH frame start, // which is stored here. EH.Addr = (uint64_t)I.EhStart; @@ -102,9 +102,9 @@ std::string JITDebugRegisterer::MakeELF(const Function *F, DebugInfo &I) { // Add this single function to the symbol table, so the debugger prints the // name instead of '???'. We give the symbol default global visibility. ELFSym *FnSym = ELFSym::getGV(F, - ELFSym::STB_GLOBAL, - ELFSym::STT_FUNC, - ELFSym::STV_DEFAULT); + ELF::STB_GLOBAL, + ELF::STT_FUNC, + ELF::STV_DEFAULT); FnSym->SectionIdx = Text.SectionIdx; FnSym->Size = I.FnEnd - I.FnStart; FnSym->Value = 0; // Offset from start of section. diff --git a/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp b/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp index 4b3ca87..1105bcc 100644 --- a/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp @@ -595,443 +595,3 @@ JITDwarfEmitter::EmitEHFrame(const Function* Personality, return StartEHPtr; } - -unsigned JITDwarfEmitter::GetDwarfTableSizeInBytes(MachineFunction& F, - JITCodeEmitter& jce, - unsigned char* StartFunction, - unsigned char* EndFunction) { - const TargetMachine& TM = F.getTarget(); - TD = TM.getTargetData(); - stackGrowthDirection = TM.getFrameInfo()->getStackGrowthDirection(); - RI = TM.getRegisterInfo(); - JCE = &jce; - unsigned FinalSize = 0; - - FinalSize += GetExceptionTableSizeInBytes(&F); - - const std::vector Personalities = MMI->getPersonalities(); - FinalSize += - GetCommonEHFrameSizeInBytes(Personalities[MMI->getPersonalityIndex()]); - - FinalSize += GetEHFrameSizeInBytes(Personalities[MMI->getPersonalityIndex()], - StartFunction); - - return FinalSize; -} - -/// RoundUpToAlign - Add the specified alignment to FinalSize and returns -/// the new value. -static unsigned RoundUpToAlign(unsigned FinalSize, unsigned Alignment) { - if (Alignment == 0) Alignment = 1; - // Since we do not know where the buffer will be allocated, be pessimistic. - return FinalSize + Alignment; -} - -unsigned -JITDwarfEmitter::GetEHFrameSizeInBytes(const Function* Personality, - unsigned char* StartFunction) const { - unsigned PointerSize = TD->getPointerSize(); - unsigned FinalSize = 0; - // EH frame header. - FinalSize += PointerSize; - // FDE CIE Offset - FinalSize += 3 * PointerSize; - // If there is a personality and landing pads then point to the language - // specific data area in the exception table. - if (Personality) { - FinalSize += MCAsmInfo::getULEB128Size(4); - FinalSize += PointerSize; - } else { - FinalSize += MCAsmInfo::getULEB128Size(0); - } - - // Indicate locations of function specific callee saved registers in - // frame. - FinalSize += GetFrameMovesSizeInBytes((intptr_t)StartFunction, - MMI->getFrameMoves()); - - FinalSize = RoundUpToAlign(FinalSize, 4); - - // Double zeroes for the unwind runtime - FinalSize += 2 * PointerSize; - - return FinalSize; -} - -unsigned JITDwarfEmitter::GetCommonEHFrameSizeInBytes(const Function* Personality) - const { - - unsigned PointerSize = TD->getPointerSize(); - int stackGrowth = stackGrowthDirection == TargetFrameInfo::StackGrowsUp ? - PointerSize : -PointerSize; - unsigned FinalSize = 0; - // EH Common Frame header - FinalSize += PointerSize; - FinalSize += 4; - FinalSize += 1; - FinalSize += Personality ? 5 : 3; // "zPLR" or "zR" - FinalSize += MCAsmInfo::getULEB128Size(1); - FinalSize += MCAsmInfo::getSLEB128Size(stackGrowth); - FinalSize += 1; - - if (Personality) { - FinalSize += MCAsmInfo::getULEB128Size(7); - - // Encoding - FinalSize+= 1; - //Personality - FinalSize += PointerSize; - - FinalSize += MCAsmInfo::getULEB128Size(dwarf::DW_EH_PE_pcrel); - FinalSize += MCAsmInfo::getULEB128Size(dwarf::DW_EH_PE_pcrel); - - } else { - FinalSize += MCAsmInfo::getULEB128Size(1); - FinalSize += MCAsmInfo::getULEB128Size(dwarf::DW_EH_PE_pcrel); - } - - std::vector Moves; - RI->getInitialFrameState(Moves); - FinalSize += GetFrameMovesSizeInBytes(0, Moves); - FinalSize = RoundUpToAlign(FinalSize, 4); - return FinalSize; -} - -unsigned -JITDwarfEmitter::GetFrameMovesSizeInBytes(intptr_t BaseLabelPtr, - const std::vector &Moves) const { - unsigned PointerSize = TD->getPointerSize(); - int stackGrowth = stackGrowthDirection == TargetFrameInfo::StackGrowsUp ? - PointerSize : -PointerSize; - bool IsLocal = BaseLabelPtr; - unsigned FinalSize = 0; - - for (unsigned i = 0, N = Moves.size(); i < N; ++i) { - const MachineMove &Move = Moves[i]; - MCSymbol *Label = Move.getLabel(); - - // Throw out move if the label is invalid. - if (Label && (*JCE->getLabelLocations())[Label] == 0) - continue; - - intptr_t LabelPtr = 0; - if (Label) LabelPtr = JCE->getLabelAddress(Label); - - const MachineLocation &Dst = Move.getDestination(); - const MachineLocation &Src = Move.getSource(); - - // Advance row if new location. - if (BaseLabelPtr && Label && (BaseLabelPtr != LabelPtr || !IsLocal)) { - FinalSize++; - FinalSize += PointerSize; - BaseLabelPtr = LabelPtr; - IsLocal = true; - } - - // If advancing cfa. - if (Dst.isReg() && Dst.getReg() == MachineLocation::VirtualFP) { - if (!Src.isReg()) { - if (Src.getReg() == MachineLocation::VirtualFP) { - ++FinalSize; - } else { - ++FinalSize; - unsigned RegNum = RI->getDwarfRegNum(Src.getReg(), true); - FinalSize += MCAsmInfo::getULEB128Size(RegNum); - } - - int Offset = -Src.getOffset(); - - FinalSize += MCAsmInfo::getULEB128Size(Offset); - } else { - llvm_unreachable("Machine move no supported yet."); - } - } else if (Src.isReg() && - Src.getReg() == MachineLocation::VirtualFP) { - if (Dst.isReg()) { - ++FinalSize; - unsigned RegNum = RI->getDwarfRegNum(Dst.getReg(), true); - FinalSize += MCAsmInfo::getULEB128Size(RegNum); - } else { - llvm_unreachable("Machine move no supported yet."); - } - } else { - unsigned Reg = RI->getDwarfRegNum(Src.getReg(), true); - int Offset = Dst.getOffset() / stackGrowth; - - if (Offset < 0) { - ++FinalSize; - FinalSize += MCAsmInfo::getULEB128Size(Reg); - FinalSize += MCAsmInfo::getSLEB128Size(Offset); - } else if (Reg < 64) { - ++FinalSize; - FinalSize += MCAsmInfo::getULEB128Size(Offset); - } else { - ++FinalSize; - FinalSize += MCAsmInfo::getULEB128Size(Reg); - FinalSize += MCAsmInfo::getULEB128Size(Offset); - } - } - } - return FinalSize; -} - -unsigned -JITDwarfEmitter::GetExceptionTableSizeInBytes(MachineFunction* MF) const { - unsigned FinalSize = 0; - - // Map all labels and get rid of any dead landing pads. - MMI->TidyLandingPads(JCE->getLabelLocations()); - - const std::vector &TypeInfos = MMI->getTypeInfos(); - const std::vector &FilterIds = MMI->getFilterIds(); - const std::vector &PadInfos = MMI->getLandingPads(); - if (PadInfos.empty()) return 0; - - // Sort the landing pads in order of their type ids. This is used to fold - // duplicate actions. - SmallVector LandingPads; - LandingPads.reserve(PadInfos.size()); - for (unsigned i = 0, N = PadInfos.size(); i != N; ++i) - LandingPads.push_back(&PadInfos[i]); - std::sort(LandingPads.begin(), LandingPads.end(), PadLT); - - // Negative type ids index into FilterIds, positive type ids index into - // TypeInfos. The value written for a positive type id is just the type - // id itself. For a negative type id, however, the value written is the - // (negative) byte offset of the corresponding FilterIds entry. The byte - // offset is usually equal to the type id, because the FilterIds entries - // are written using a variable width encoding which outputs one byte per - // entry as long as the value written is not too large, but can differ. - // This kind of complication does not occur for positive type ids because - // type infos are output using a fixed width encoding. - // FilterOffsets[i] holds the byte offset corresponding to FilterIds[i]. - SmallVector FilterOffsets; - FilterOffsets.reserve(FilterIds.size()); - int Offset = -1; - for(std::vector::const_iterator I = FilterIds.begin(), - E = FilterIds.end(); I != E; ++I) { - FilterOffsets.push_back(Offset); - Offset -= MCAsmInfo::getULEB128Size(*I); - } - - // Compute the actions table and gather the first action index for each - // landing pad site. - SmallVector Actions; - SmallVector FirstActions; - FirstActions.reserve(LandingPads.size()); - - int FirstAction = 0; - unsigned SizeActions = 0; - for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { - const LandingPadInfo *LP = LandingPads[i]; - const std::vector &TypeIds = LP->TypeIds; - const unsigned NumShared = i ? SharedTypeIds(LP, LandingPads[i-1]) : 0; - unsigned SizeSiteActions = 0; - - if (NumShared < TypeIds.size()) { - unsigned SizeAction = 0; - ActionEntry *PrevAction = 0; - - if (NumShared) { - const unsigned SizePrevIds = LandingPads[i-1]->TypeIds.size(); - assert(Actions.size()); - PrevAction = &Actions.back(); - SizeAction = MCAsmInfo::getSLEB128Size(PrevAction->NextAction) + - MCAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID); - for (unsigned j = NumShared; j != SizePrevIds; ++j) { - SizeAction -= MCAsmInfo::getSLEB128Size(PrevAction->ValueForTypeID); - SizeAction += -PrevAction->NextAction; - PrevAction = PrevAction->Previous; - } - } - - // Compute the actions. - for (unsigned I = NumShared, M = TypeIds.size(); I != M; ++I) { - int TypeID = TypeIds[I]; - assert(-1-TypeID < (int)FilterOffsets.size() && "Unknown filter id!"); - int ValueForTypeID = TypeID < 0 ? FilterOffsets[-1 - TypeID] : TypeID; - unsigned SizeTypeID = MCAsmInfo::getSLEB128Size(ValueForTypeID); - - int NextAction = SizeAction ? -(SizeAction + SizeTypeID) : 0; - SizeAction = SizeTypeID + MCAsmInfo::getSLEB128Size(NextAction); - SizeSiteActions += SizeAction; - - ActionEntry Action = {ValueForTypeID, NextAction, PrevAction}; - Actions.push_back(Action); - - PrevAction = &Actions.back(); - } - - // Record the first action of the landing pad site. - FirstAction = SizeActions + SizeSiteActions - SizeAction + 1; - } // else identical - re-use previous FirstAction - - FirstActions.push_back(FirstAction); - - // Compute this sites contribution to size. - SizeActions += SizeSiteActions; - } - - // Compute the call-site table. Entries must be ordered by address. - SmallVector CallSites; - - RangeMapType PadMap; - for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { - const LandingPadInfo *LandingPad = LandingPads[i]; - for (unsigned j=0, E = LandingPad->BeginLabels.size(); j != E; ++j) { - MCSymbol *BeginLabel = LandingPad->BeginLabels[j]; - assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!"); - PadRange P = { i, j }; - PadMap[BeginLabel] = P; - } - } - - bool MayThrow = false; - MCSymbol *LastLabel = 0; - for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); - I != E; ++I) { - for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end(); - MI != E; ++MI) { - if (!MI->isLabel()) { - MayThrow |= MI->getDesc().isCall(); - continue; - } - - MCSymbol *BeginLabel = MI->getOperand(0).getMCSymbol(); - - if (BeginLabel == LastLabel) - MayThrow = false; - - RangeMapType::iterator L = PadMap.find(BeginLabel); - - if (L == PadMap.end()) - continue; - - PadRange P = L->second; - const LandingPadInfo *LandingPad = LandingPads[P.PadIndex]; - - assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] && - "Inconsistent landing pad map!"); - - // If some instruction between the previous try-range and this one may - // throw, create a call-site entry with no landing pad for the region - // between the try-ranges. - if (MayThrow) { - CallSiteEntry Site = {LastLabel, BeginLabel, 0, 0}; - CallSites.push_back(Site); - } - - LastLabel = LandingPad->EndLabels[P.RangeIndex]; - CallSiteEntry Site = {BeginLabel, LastLabel, - LandingPad->LandingPadLabel, FirstActions[P.PadIndex]}; - - assert(Site.BeginLabel && Site.EndLabel && Site.PadLabel && - "Invalid landing pad!"); - - // Try to merge with the previous call-site. - if (CallSites.size()) { - CallSiteEntry &Prev = CallSites.back(); - if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) { - // Extend the range of the previous entry. - Prev.EndLabel = Site.EndLabel; - continue; - } - } - - // Otherwise, create a new call-site. - CallSites.push_back(Site); - } - } - // If some instruction between the previous try-range and the end of the - // function may throw, create a call-site entry with no landing pad for the - // region following the try-range. - if (MayThrow) { - CallSiteEntry Site = {LastLabel, 0, 0, 0}; - CallSites.push_back(Site); - } - - // Final tallies. - unsigned SizeSites = CallSites.size() * (sizeof(int32_t) + // Site start. - sizeof(int32_t) + // Site length. - sizeof(int32_t)); // Landing pad. - for (unsigned i = 0, e = CallSites.size(); i < e; ++i) - SizeSites += MCAsmInfo::getULEB128Size(CallSites[i].Action); - - unsigned SizeTypes = TypeInfos.size() * TD->getPointerSize(); - - unsigned TypeOffset = sizeof(int8_t) + // Call site format - // Call-site table length - MCAsmInfo::getULEB128Size(SizeSites) + - SizeSites + SizeActions + SizeTypes; - - unsigned TotalSize = sizeof(int8_t) + // LPStart format - sizeof(int8_t) + // TType format - MCAsmInfo::getULEB128Size(TypeOffset) + // TType base offset - TypeOffset; - - unsigned SizeAlign = (4 - TotalSize) & 3; - - // Begin the exception table. - FinalSize = RoundUpToAlign(FinalSize, 4); - for (unsigned i = 0; i != SizeAlign; ++i) { - ++FinalSize; - } - - unsigned PointerSize = TD->getPointerSize(); - - // Emit the header. - ++FinalSize; - // Asm->EOL("LPStart format (DW_EH_PE_omit)"); - ++FinalSize; - // Asm->EOL("TType format (DW_EH_PE_absptr)"); - ++FinalSize; - // Asm->EOL("TType base offset"); - ++FinalSize; - // Asm->EOL("Call site format (DW_EH_PE_udata4)"); - ++FinalSize; - // Asm->EOL("Call-site table length"); - - // Emit the landing pad site information. - for (unsigned i = 0; i < CallSites.size(); ++i) { - CallSiteEntry &S = CallSites[i]; - - // Asm->EOL("Region start"); - FinalSize += PointerSize; - - //Asm->EOL("Region length"); - FinalSize += PointerSize; - - // Asm->EOL("Landing pad"); - FinalSize += PointerSize; - - FinalSize += MCAsmInfo::getULEB128Size(S.Action); - // Asm->EOL("Action"); - } - - // Emit the actions. - for (unsigned I = 0, N = Actions.size(); I != N; ++I) { - ActionEntry &Action = Actions[I]; - - //Asm->EOL("TypeInfo index"); - FinalSize += MCAsmInfo::getSLEB128Size(Action.ValueForTypeID); - //Asm->EOL("Next action"); - FinalSize += MCAsmInfo::getSLEB128Size(Action.NextAction); - } - - // Emit the type ids. - for (unsigned M = TypeInfos.size(); M; --M) { - // Asm->EOL("TypeInfo"); - FinalSize += PointerSize; - } - - // Emit the filter typeids. - for (unsigned j = 0, M = FilterIds.size(); j < M; ++j) { - unsigned TypeID = FilterIds[j]; - FinalSize += MCAsmInfo::getULEB128Size(TypeID); - //Asm->EOL("Filter TypeInfo index"); - } - - FinalSize = RoundUpToAlign(FinalSize, 4); - - return FinalSize; -} diff --git a/lib/ExecutionEngine/JIT/JITDwarfEmitter.h b/lib/ExecutionEngine/JIT/JITDwarfEmitter.h index e627550..3095682 100644 --- a/lib/ExecutionEngine/JIT/JITDwarfEmitter.h +++ b/lib/ExecutionEngine/JIT/JITDwarfEmitter.h @@ -49,17 +49,6 @@ class JITDwarfEmitter { unsigned char* EndFunction, unsigned char* ExceptionTable) const; - unsigned GetExceptionTableSizeInBytes(MachineFunction* MF) const; - - unsigned - GetFrameMovesSizeInBytes(intptr_t BaseLabelPtr, - const std::vector &Moves) const; - - unsigned GetCommonEHFrameSizeInBytes(const Function* Personality) const; - - unsigned GetEHFrameSizeInBytes(const Function* Personality, - unsigned char* StartFunction) const; - public: JITDwarfEmitter(JIT& jit); @@ -71,11 +60,6 @@ public: unsigned char* &EHFramePtr); - unsigned GetDwarfTableSizeInBytes(MachineFunction& F, - JITCodeEmitter& JCE, - unsigned char* StartFunction, - unsigned char* EndFunction); - void setModuleInfo(MachineModuleInfo* Info) { MMI = Info; } diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index 28d79da..4c0d078 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -152,16 +152,6 @@ namespace { FunctionToCallSitesMap[F].insert(CallSite); } - // Returns the Function of the stub if a stub was erased, or NULL if there - // was no stub. This function uses the call-site->function map to find a - // relevant function, but asserts that only stubs and not other call sites - // will be passed in. - Function *EraseStub(const MutexGuard &locked, void *Stub); - - void EraseAllCallSitesFor(const MutexGuard &locked, Function *F) { - assert(locked.holds(TheJIT->lock)); - EraseAllCallSitesForPrelocked(F); - } void EraseAllCallSitesForPrelocked(Function *F); // Erases _all_ call sites regardless of their function. This is used to @@ -223,9 +213,6 @@ namespace { /// specified GV address. void *getGlobalValueIndirectSym(GlobalValue *V, void *GVAddress); - void getRelocatableGVs(SmallVectorImpl &GVs, - SmallVectorImpl &Ptrs); - /// getGOTIndexForAddress - Return a new or existing index in the GOT for /// an address. This function only manages slots, it does not manage the /// contents of the slots or the memory associated with the GOT. @@ -398,7 +385,6 @@ namespace { /// classof - Methods for support type inquiry through isa, cast, and /// dyn_cast: /// - static inline bool classof(const JITEmitter*) { return true; } static inline bool classof(const MachineCodeEmitter*) { return true; } JITResolver &getJITResolver() { return Resolver; } @@ -480,26 +466,10 @@ namespace { if (DE.get()) DE->setModuleInfo(Info); } - void setMemoryExecutable() { - MemMgr->setMemoryExecutable(); - } - - JITMemoryManager *getMemMgr() const { return MemMgr; } - private: void *getPointerToGlobal(GlobalValue *GV, void *Reference, bool MayNeedFarStub); void *getPointerToGVIndirectSym(GlobalValue *V, void *Reference); - unsigned addSizeOfGlobal(const GlobalVariable *GV, unsigned Size); - unsigned addSizeOfGlobalsInConstantVal( - const Constant *C, unsigned Size, - SmallPtrSet &SeenGlobals, - SmallVectorImpl &Worklist); - unsigned addSizeOfGlobalsInInitializer( - const Constant *Init, unsigned Size, - SmallPtrSet &SeenGlobals, - SmallVectorImpl &Worklist); - unsigned GetSizeOfGlobalsInBytes(MachineFunction &MF); }; } @@ -507,39 +477,6 @@ void CallSiteValueMapConfig::onDelete(JITResolverState *JRS, Function *F) { JRS->EraseAllCallSitesForPrelocked(F); } -Function *JITResolverState::EraseStub(const MutexGuard &locked, void *Stub) { - CallSiteToFunctionMapTy::iterator C2F_I = - CallSiteToFunctionMap.find(Stub); - if (C2F_I == CallSiteToFunctionMap.end()) { - // Not a stub. - return NULL; - } - - StubToResolverMap->UnregisterStubResolver(Stub); - - Function *const F = C2F_I->second; -#ifndef NDEBUG - void *RealStub = FunctionToLazyStubMap.lookup(F); - assert(RealStub == Stub && - "Call-site that wasn't a stub passed in to EraseStub"); -#endif - FunctionToLazyStubMap.erase(F); - CallSiteToFunctionMap.erase(C2F_I); - - // Remove the stub from the function->call-sites map, and remove the whole - // entry from the map if that was the last call site. - FunctionToCallSitesMapTy::iterator F2C_I = FunctionToCallSitesMap.find(F); - assert(F2C_I != FunctionToCallSitesMap.end() && - "FunctionToCallSitesMap broken"); - bool Erased = F2C_I->second.erase(Stub); - (void)Erased; - assert(Erased && "FunctionToCallSitesMap broken"); - if (F2C_I->second.empty()) - FunctionToCallSitesMap.erase(F2C_I); - - return F; -} - void JITResolverState::EraseAllCallSitesForPrelocked(Function *F) { FunctionToCallSitesMapTy::iterator F2C = FunctionToCallSitesMap.find(F); if (F2C == FunctionToCallSitesMap.end()) @@ -690,28 +627,6 @@ unsigned JITResolver::getGOTIndexForAddr(void* addr) { return idx; } -void JITResolver::getRelocatableGVs(SmallVectorImpl &GVs, - SmallVectorImpl &Ptrs) { - MutexGuard locked(TheJIT->lock); - - const FunctionToLazyStubMapTy &FM = state.getFunctionToLazyStubMap(locked); - GlobalToIndirectSymMapTy &GM = state.getGlobalToIndirectSymMap(locked); - - for (FunctionToLazyStubMapTy::const_iterator i = FM.begin(), e = FM.end(); - i != e; ++i){ - Function *F = i->first; - if (F->isDeclaration() && F->hasExternalLinkage()) { - GVs.push_back(i->first); - Ptrs.push_back(i->second); - } - } - for (GlobalToIndirectSymMapTy::iterator i = GM.begin(), e = GM.end(); - i != e; ++i) { - GVs.push_back(i->first); - Ptrs.push_back(i->second); - } -} - /// JITCompilerFn - This function is called when a lazy compilation stub has /// been entered. It looks up which function this stub corresponds to, compiles /// it if necessary, then returns the resultant function pointer. @@ -831,7 +746,7 @@ void JITEmitter::processDebugLoc(DebugLoc DL, bool BeforePrintingInsn) { if (DL.isUnknown()) return; if (!BeforePrintingInsn) return; - const LLVMContext& Context = EmissionDetails.MF->getFunction()->getContext(); + const LLVMContext &Context = EmissionDetails.MF->getFunction()->getContext(); if (DL.getScope(Context) != 0 && PrevDL != DL) { JITEvent_EmittedFunctionDetails::LineStart NextLine; @@ -859,184 +774,6 @@ static unsigned GetConstantPoolSizeInBytes(MachineConstantPool *MCP, return Size; } -static unsigned GetJumpTableSizeInBytes(MachineJumpTableInfo *MJTI, JIT *jit) { - const std::vector &JT = MJTI->getJumpTables(); - if (JT.empty()) return 0; - - unsigned NumEntries = 0; - for (unsigned i = 0, e = JT.size(); i != e; ++i) - NumEntries += JT[i].MBBs.size(); - - return NumEntries * MJTI->getEntrySize(*jit->getTargetData()); -} - -static uintptr_t RoundUpToAlign(uintptr_t Size, unsigned Alignment) { - if (Alignment == 0) Alignment = 1; - // Since we do not know where the buffer will be allocated, be pessimistic. - return Size + Alignment; -} - -/// addSizeOfGlobal - add the size of the global (plus any alignment padding) -/// into the running total Size. - -unsigned JITEmitter::addSizeOfGlobal(const GlobalVariable *GV, unsigned Size) { - const Type *ElTy = GV->getType()->getElementType(); - size_t GVSize = (size_t)TheJIT->getTargetData()->getTypeAllocSize(ElTy); - size_t GVAlign = - (size_t)TheJIT->getTargetData()->getPreferredAlignment(GV); - DEBUG(dbgs() << "JIT: Adding in size " << GVSize << " alignment " << GVAlign); - DEBUG(GV->dump()); - // Assume code section ends with worst possible alignment, so first - // variable needs maximal padding. - if (Size==0) - Size = 1; - Size = ((Size+GVAlign-1)/GVAlign)*GVAlign; - Size += GVSize; - return Size; -} - -/// addSizeOfGlobalsInConstantVal - find any globals that we haven't seen yet -/// but are referenced from the constant; put them in SeenGlobals and the -/// Worklist, and add their size into the running total Size. - -unsigned JITEmitter::addSizeOfGlobalsInConstantVal( - const Constant *C, - unsigned Size, - SmallPtrSet &SeenGlobals, - SmallVectorImpl &Worklist) { - // If its undefined, return the garbage. - if (isa(C)) - return Size; - - // If the value is a ConstantExpr - if (const ConstantExpr *CE = dyn_cast(C)) { - Constant *Op0 = CE->getOperand(0); - switch (CE->getOpcode()) { - case Instruction::GetElementPtr: - case Instruction::Trunc: - case Instruction::ZExt: - case Instruction::SExt: - case Instruction::FPTrunc: - case Instruction::FPExt: - case Instruction::UIToFP: - case Instruction::SIToFP: - case Instruction::FPToUI: - case Instruction::FPToSI: - case Instruction::PtrToInt: - case Instruction::IntToPtr: - case Instruction::BitCast: { - Size = addSizeOfGlobalsInConstantVal(Op0, Size, SeenGlobals, Worklist); - break; - } - case Instruction::Add: - case Instruction::FAdd: - case Instruction::Sub: - case Instruction::FSub: - case Instruction::Mul: - case Instruction::FMul: - case Instruction::UDiv: - case Instruction::SDiv: - case Instruction::URem: - case Instruction::SRem: - case Instruction::And: - case Instruction::Or: - case Instruction::Xor: { - Size = addSizeOfGlobalsInConstantVal(Op0, Size, SeenGlobals, Worklist); - Size = addSizeOfGlobalsInConstantVal(CE->getOperand(1), Size, - SeenGlobals, Worklist); - break; - } - default: { - std::string msg; - raw_string_ostream Msg(msg); - Msg << "ConstantExpr not handled: " << *CE; - report_fatal_error(Msg.str()); - } - } - } - - if (C->getType()->getTypeID() == Type::PointerTyID) - if (const GlobalVariable* GV = dyn_cast(C)) - if (SeenGlobals.insert(GV)) { - Worklist.push_back(GV); - Size = addSizeOfGlobal(GV, Size); - } - - return Size; -} - -/// addSizeOfGLobalsInInitializer - handle any globals that we haven't seen yet -/// but are referenced from the given initializer. - -unsigned JITEmitter::addSizeOfGlobalsInInitializer( - const Constant *Init, - unsigned Size, - SmallPtrSet &SeenGlobals, - SmallVectorImpl &Worklist) { - if (!isa(Init) && - !isa(Init) && - !isa(Init) && - !isa(Init) && - !isa(Init) && - Init->getType()->isFirstClassType()) - Size = addSizeOfGlobalsInConstantVal(Init, Size, SeenGlobals, Worklist); - return Size; -} - -/// GetSizeOfGlobalsInBytes - walk the code for the function, looking for -/// globals; then walk the initializers of those globals looking for more. -/// If their size has not been considered yet, add it into the running total -/// Size. - -unsigned JITEmitter::GetSizeOfGlobalsInBytes(MachineFunction &MF) { - unsigned Size = 0; - SmallPtrSet SeenGlobals; - - for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); - MBB != E; ++MBB) { - for (MachineBasicBlock::const_iterator I = MBB->begin(), E = MBB->end(); - I != E; ++I) { - const TargetInstrDesc &Desc = I->getDesc(); - const MachineInstr &MI = *I; - unsigned NumOps = Desc.getNumOperands(); - for (unsigned CurOp = 0; CurOp < NumOps; CurOp++) { - const MachineOperand &MO = MI.getOperand(CurOp); - if (MO.isGlobal()) { - const GlobalValue* V = MO.getGlobal(); - const GlobalVariable *GV = dyn_cast(V); - if (!GV) - continue; - // If seen in previous function, it will have an entry here. - if (TheJIT->getPointerToGlobalIfAvailable( - const_cast(GV))) - continue; - // If seen earlier in this function, it will have an entry here. - // FIXME: it should be possible to combine these tables, by - // assuming the addresses of the new globals in this module - // start at 0 (or something) and adjusting them after codegen - // complete. Another possibility is to grab a marker bit in GV. - if (SeenGlobals.insert(GV)) - // A variable as yet unseen. Add in its size. - Size = addSizeOfGlobal(GV, Size); - } - } - } - } - DEBUG(dbgs() << "JIT: About to look through initializers\n"); - // Look for more globals that are referenced only from initializers. - SmallVector Worklist( - SeenGlobals.begin(), SeenGlobals.end()); - while (!Worklist.empty()) { - const GlobalVariable* GV = Worklist.back(); - Worklist.pop_back(); - if (GV->hasInitializer()) - Size = addSizeOfGlobalsInInitializer(GV->getInitializer(), Size, - SeenGlobals, Worklist); - } - - return Size; -} - void JITEmitter::startFunction(MachineFunction &F) { DEBUG(dbgs() << "JIT: Starting CodeGen of Function " << F.getFunction()->getName() << "\n"); @@ -1044,43 +781,8 @@ void JITEmitter::startFunction(MachineFunction &F) { uintptr_t ActualSize = 0; // Set the memory writable, if it's not already MemMgr->setMemoryWritable(); - if (MemMgr->NeedsExactSize()) { - DEBUG(dbgs() << "JIT: ExactSize\n"); - const TargetInstrInfo* TII = F.getTarget().getInstrInfo(); - MachineConstantPool *MCP = F.getConstantPool(); - - // Ensure the constant pool/jump table info is at least 4-byte aligned. - ActualSize = RoundUpToAlign(ActualSize, 16); - - // Add the alignment of the constant pool - ActualSize = RoundUpToAlign(ActualSize, MCP->getConstantPoolAlignment()); - - // Add the constant pool size - ActualSize += GetConstantPoolSizeInBytes(MCP, TheJIT->getTargetData()); - - if (MachineJumpTableInfo *MJTI = F.getJumpTableInfo()) { - // Add the aligment of the jump table info - ActualSize = RoundUpToAlign(ActualSize, - MJTI->getEntryAlignment(*TheJIT->getTargetData())); - - // Add the jump table size - ActualSize += GetJumpTableSizeInBytes(MJTI, TheJIT); - } - - // Add the alignment for the function - ActualSize = RoundUpToAlign(ActualSize, - std::max(F.getFunction()->getAlignment(), 8U)); - - // Add the function size - ActualSize += TII->GetFunctionSizeInBytes(F); - - DEBUG(dbgs() << "JIT: ActualSize before globals " << ActualSize << "\n"); - // Add the size of the globals that will be allocated after this function. - // These are all the ones referenced from this function that were not - // previously allocated. - ActualSize += GetSizeOfGlobalsInBytes(F); - DEBUG(dbgs() << "JIT: ActualSize after globals " << ActualSize << "\n"); - } else if (SizeEstimate > 0) { + + if (SizeEstimate > 0) { // SizeEstimate will be non-zero on reallocation attempts. ActualSize = SizeEstimate; } @@ -1268,9 +970,6 @@ bool JITEmitter::finishFunction(MachineFunction &F) { SavedBufferEnd = BufferEnd; SavedCurBufferPtr = CurBufferPtr; - if (MemMgr->NeedsExactSize()) - ActualSize = DE->GetDwarfTableSizeInBytes(F, *this, FnStart, FnEnd); - BufferBegin = CurBufferPtr = MemMgr->startExceptionTable(F.getFunction(), ActualSize); BufferEnd = BufferBegin+ActualSize; diff --git a/lib/Linker/LinkModules.cpp b/lib/Linker/LinkModules.cpp index 8487c83..7e8245a 100644 --- a/lib/Linker/LinkModules.cpp +++ b/lib/Linker/LinkModules.cpp @@ -29,6 +29,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" +#include "llvm/Transforms/Utils/ValueMapper.h" #include "llvm/ADT/DenseMap.h" using namespace llvm; @@ -96,15 +97,6 @@ public: return 0; } - /// erase - Remove the specified type, returning true if it was in the set. - bool erase(const Type *Ty) { - if (!TheMap.erase(Ty)) - return false; - if (Ty->isAbstract()) - Ty->removeAbstractTypeUser(this); - return true; - } - /// insert - This returns true if the pointer was new to the set, false if it /// was already in the set. bool insert(const Type *Src, const Type *Dst) { @@ -334,97 +326,6 @@ static bool LinkTypes(Module *Dest, const Module *Src, std::string *Err) { return false; } -#ifndef NDEBUG -static void PrintMap(const std::map &M) { - for (std::map::const_iterator I = M.begin(), E =M.end(); - I != E; ++I) { - dbgs() << " Fr: " << (void*)I->first << " "; - I->first->dump(); - dbgs() << " To: " << (void*)I->second << " "; - I->second->dump(); - dbgs() << "\n"; - } -} -#endif - - -// RemapOperand - Use ValueMap to convert constants from one module to another. -static Value *RemapOperand(const Value *In, - std::map &ValueMap) { - std::map::const_iterator I = ValueMap.find(In); - if (I != ValueMap.end()) - return I->second; - - // Check to see if it's a constant that we are interested in transforming. - Value *Result = 0; - if (const Constant *CPV = dyn_cast(In)) { - if ((!isa(CPV->getType()) && !isa(CPV)) || - isa(CPV) || isa(CPV)) - return const_cast(CPV); // Simple constants stay identical. - - if (const ConstantArray *CPA = dyn_cast(CPV)) { - std::vector Operands(CPA->getNumOperands()); - for (unsigned i = 0, e = CPA->getNumOperands(); i != e; ++i) - Operands[i] =cast(RemapOperand(CPA->getOperand(i), ValueMap)); - Result = ConstantArray::get(cast(CPA->getType()), Operands); - } else if (const ConstantStruct *CPS = dyn_cast(CPV)) { - std::vector Operands(CPS->getNumOperands()); - for (unsigned i = 0, e = CPS->getNumOperands(); i != e; ++i) - Operands[i] =cast(RemapOperand(CPS->getOperand(i), ValueMap)); - Result = ConstantStruct::get(cast(CPS->getType()), Operands); - } else if (isa(CPV) || isa(CPV)) { - Result = const_cast(CPV); - } else if (const ConstantVector *CP = dyn_cast(CPV)) { - std::vector Operands(CP->getNumOperands()); - for (unsigned i = 0, e = CP->getNumOperands(); i != e; ++i) - Operands[i] = cast(RemapOperand(CP->getOperand(i), ValueMap)); - Result = ConstantVector::get(Operands); - } else if (const ConstantExpr *CE = dyn_cast(CPV)) { - std::vector Ops; - for (unsigned i = 0, e = CE->getNumOperands(); i != e; ++i) - Ops.push_back(cast(RemapOperand(CE->getOperand(i),ValueMap))); - Result = CE->getWithOperands(Ops); - } else if (const BlockAddress *CE = dyn_cast(CPV)) { - Result = BlockAddress::get( - cast(RemapOperand(CE->getFunction(), ValueMap)), - CE->getBasicBlock()); - } else { - assert(!isa(CPV) && "Unmapped global?"); - llvm_unreachable("Unknown type of derived type constant value!"); - } - } else if (const MDNode *MD = dyn_cast(In)) { - if (MD->isFunctionLocal()) { - SmallVector Elts; - for (unsigned i = 0, e = MD->getNumOperands(); i != e; ++i) { - if (MD->getOperand(i)) - Elts.push_back(RemapOperand(MD->getOperand(i), ValueMap)); - else - Elts.push_back(NULL); - } - Result = MDNode::get(In->getContext(), Elts.data(), MD->getNumOperands()); - } else { - Result = const_cast(In); - } - } else if (isa(In) || isa(In) || isa(In)) { - Result = const_cast(In); - } - - // Cache the mapping in our local map structure - if (Result) { - ValueMap[In] = Result; - return Result; - } - -#ifndef NDEBUG - dbgs() << "LinkModules ValueMap: \n"; - PrintMap(ValueMap); - - dbgs() << "Couldn't remap value: " << (void*)In << " " << *In << "\n"; - llvm_unreachable("Couldn't remap value!"); -#endif - return 0; -} - /// ForceRenaming - The LLVM SymbolTable class autorenames globals that conflict /// in the symbol table. This is good for all clients except for us. Go /// through the trouble to force this back. @@ -541,25 +442,24 @@ static bool GetLinkageResult(GlobalValue *Dest, const GlobalValue *Src, } // Insert all of the named mdnoes in Src into the Dest module. -static void LinkNamedMDNodes(Module *Dest, Module *Src) { +static void LinkNamedMDNodes(Module *Dest, Module *Src, + ValueToValueMapTy &ValueMap) { for (Module::const_named_metadata_iterator I = Src->named_metadata_begin(), E = Src->named_metadata_end(); I != E; ++I) { const NamedMDNode *SrcNMD = I; - NamedMDNode *DestNMD = Dest->getNamedMetadata(SrcNMD->getName()); - if (!DestNMD) - NamedMDNode::Create(SrcNMD, Dest); - else { - // Add Src elements into Dest node. - for (unsigned i = 0, e = SrcNMD->getNumOperands(); i != e; ++i) - DestNMD->addOperand(SrcNMD->getOperand(i)); - } + NamedMDNode *DestNMD = Dest->getOrInsertNamedMetadata(SrcNMD->getName()); + // Add Src elements into Dest node. + for (unsigned i = 0, e = SrcNMD->getNumOperands(); i != e; ++i) + DestNMD->addOperand(cast(MapValue(SrcNMD->getOperand(i), + ValueMap, + true))); } } // LinkGlobals - Loop through the global variables in the src module and merge // them into the dest module. static bool LinkGlobals(Module *Dest, const Module *Src, - std::map &ValueMap, + ValueToValueMapTy &ValueMap, std::multimap &AppendingVars, std::string *Err) { ValueSymbolTable &DestSymTab = Dest->getValueSymbolTable(); @@ -735,6 +635,12 @@ CalculateAliasLinkage(const GlobalValue *SGV, const GlobalValue *DGV) { else if (SL == GlobalValue::LinkerPrivateLinkage && DL == GlobalValue::LinkerPrivateLinkage) return GlobalValue::LinkerPrivateLinkage; + else if (SL == GlobalValue::LinkerPrivateWeakLinkage && + DL == GlobalValue::LinkerPrivateWeakLinkage) + return GlobalValue::LinkerPrivateWeakLinkage; + else if (SL == GlobalValue::LinkerPrivateWeakDefAutoLinkage && + DL == GlobalValue::LinkerPrivateWeakDefAutoLinkage) + return GlobalValue::LinkerPrivateWeakDefAutoLinkage; else { assert (SL == GlobalValue::PrivateLinkage && DL == GlobalValue::PrivateLinkage && "Unexpected linkage type"); @@ -746,7 +652,7 @@ CalculateAliasLinkage(const GlobalValue *SGV, const GlobalValue *DGV) { // dest module. We're assuming, that all functions/global variables were already // linked in. static bool LinkAlias(Module *Dest, const Module *Src, - std::map &ValueMap, + ValueToValueMapTy &ValueMap, std::string *Err) { // Loop over all alias in the src module for (Module::const_alias_iterator I = Src->alias_begin(), @@ -757,7 +663,7 @@ static bool LinkAlias(Module *Dest, const Module *Src, // Globals were already linked, thus we can just query ValueMap for variant // of SAliasee in Dest. - std::map::const_iterator VMI = ValueMap.find(SAliasee); + ValueToValueMapTy::const_iterator VMI = ValueMap.find(SAliasee); assert(VMI != ValueMap.end() && "Aliasee not linked"); GlobalValue* DAliasee = cast(VMI->second); GlobalValue* DGV = NULL; @@ -888,7 +794,7 @@ static bool LinkAlias(Module *Dest, const Module *Src, ForceRenaming(NewGA, SGA->getName()); // Remember this mapping so uses in the source module get remapped - // later by RemapOperand. + // later by MapValue. ValueMap[SGA] = NewGA; } @@ -899,7 +805,7 @@ static bool LinkAlias(Module *Dest, const Module *Src, // LinkGlobalInits - Update the initializers in the Dest module now that all // globals that may be referenced are in Dest. static bool LinkGlobalInits(Module *Dest, const Module *Src, - std::map &ValueMap, + ValueToValueMapTy &ValueMap, std::string *Err) { // Loop over all of the globals in the src module, mapping them over as we go for (Module::const_global_iterator I = Src->global_begin(), @@ -909,7 +815,7 @@ static bool LinkGlobalInits(Module *Dest, const Module *Src, if (SGV->hasInitializer()) { // Only process initialized GV's // Figure out what the initializer looks like in the dest module... Constant *SInit = - cast(RemapOperand(SGV->getInitializer(), ValueMap)); + cast(MapValue(SGV->getInitializer(), ValueMap, true)); // Grab destination global variable or alias. GlobalValue *DGV = cast(ValueMap[SGV]->stripPointerCasts()); @@ -954,7 +860,7 @@ static bool LinkGlobalInits(Module *Dest, const Module *Src, // to the Dest function... // static bool LinkFunctionProtos(Module *Dest, const Module *Src, - std::map &ValueMap, + ValueToValueMapTy &ValueMap, std::string *Err) { ValueSymbolTable &DestSymTab = Dest->getValueSymbolTable(); @@ -1039,7 +945,7 @@ static bool LinkFunctionProtos(Module *Dest, const Module *Src, ForceRenaming(NewDF, SF->getName()); // Remember this mapping so uses in the source module get remapped - // later by RemapOperand. + // later by MapValue. ValueMap[SF] = NewDF; continue; } @@ -1069,7 +975,7 @@ static bool LinkFunctionProtos(Module *Dest, const Module *Src, // fix up references to values. At this point we know that Dest is an external // function, and that Src is not. static bool LinkFunctionBody(Function *Dest, Function *Src, - std::map &ValueMap, + ValueToValueMapTy &ValueMap, std::string *Err) { assert(Src && Dest && Dest->isDeclaration() && !Src->isDeclaration()); @@ -1091,12 +997,30 @@ static bool LinkFunctionBody(Function *Dest, Function *Src, // the Source function as operands. Loop through all of the operands of the // functions and patch them up to point to the local versions... // + // This is the same as RemapInstruction, except that it avoids remapping + // instruction and basic block operands. + // for (Function::iterator BB = Dest->begin(), BE = Dest->end(); BB != BE; ++BB) - for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { + // Remap operands. for (Instruction::op_iterator OI = I->op_begin(), OE = I->op_end(); OI != OE; ++OI) if (!isa(*OI) && !isa(*OI)) - *OI = RemapOperand(*OI, ValueMap); + *OI = MapValue(*OI, ValueMap, true); + + // Remap attached metadata. + SmallVector, 4> MDs; + I->getAllMetadata(MDs); + for (SmallVectorImpl >::iterator + MI = MDs.begin(), ME = MDs.end(); MI != ME; ++MI) { + Value *Old = MI->second; + if (!isa(Old) && !isa(Old)) { + Value *New = MapValue(Old, ValueMap, true); + if (New != Old) + I->setMetadata(MI->first, cast(New)); + } + } + } // There is no need to map the arguments anymore. for (Function::arg_iterator I = Src->arg_begin(), E = Src->arg_end(); @@ -1111,7 +1035,7 @@ static bool LinkFunctionBody(Function *Dest, Function *Src, // source module into the DestModule. This consists basically of copying the // function over and fixing up references to values. static bool LinkFunctionBodies(Module *Dest, Module *Src, - std::map &ValueMap, + ValueToValueMapTy &ValueMap, std::string *Err) { // Loop over all of the functions in the src module, mapping them over as we @@ -1319,8 +1243,10 @@ Linker::LinkModules(Module *Dest, Module *Src, std::string *ErrorMsg) { return true; // ValueMap - Mapping of values from what they used to be in Src, to what they - // are now in Dest. - std::map ValueMap; + // are now in Dest. ValueToValueMapTy is a ValueMap, which involves some + // overhead due to the use of Value handles which the Linker doesn't actually + // need, but this allows us to reuse the ValueMapper code. + ValueToValueMapTy ValueMap; // AppendingVars - Keep track of global variables in the destination module // with appending linkage. After the module is linked together, they are @@ -1334,9 +1260,6 @@ Linker::LinkModules(Module *Dest, Module *Src, std::string *ErrorMsg) { AppendingVars.insert(std::make_pair(I->getName(), I)); } - // Insert all of the named mdnoes in Src into the Dest module. - LinkNamedMDNodes(Dest, Src); - // Insert all of the globals in src into the Dest module... without linking // initializers (which could refer to functions not yet mapped over). if (LinkGlobals(Dest, Src, ValueMap, AppendingVars, ErrorMsg)) @@ -1370,6 +1293,11 @@ Linker::LinkModules(Module *Dest, Module *Src, std::string *ErrorMsg) { // Resolve all uses of aliases with aliasees if (ResolveAliases(Dest)) return true; + // Remap all of the named mdnoes in Src into the Dest module. We do this + // after linking GlobalValues so that MDNodes that reference GlobalValues + // are properly remapped. + LinkNamedMDNodes(Dest, Src, ValueMap); + // If the source library's module id is in the dependent library list of the // destination library, remove it since that module is now linked in. sys::Path modId; diff --git a/lib/MC/CMakeLists.txt b/lib/MC/CMakeLists.txt index fc4f3c6..60a3a3e 100644 --- a/lib/MC/CMakeLists.txt +++ b/lib/MC/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_library(LLVMMC + ELFObjectWriter.cpp MCAsmInfo.cpp MCAsmInfoCOFF.cpp MCAsmInfoDarwin.cpp @@ -7,10 +8,12 @@ add_llvm_library(LLVMMC MCCodeEmitter.cpp MCContext.cpp MCDisassembler.cpp + MCELFStreamer.cpp MCExpr.cpp MCInst.cpp MCInstPrinter.cpp MCLabel.cpp + MCDwarf.cpp MCLoggingStreamer.cpp MCMachOStreamer.cpp MCNullStreamer.cpp diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp new file mode 100644 index 0000000..cf35b45 --- /dev/null +++ b/lib/MC/ELFObjectWriter.cpp @@ -0,0 +1,973 @@ +//===- lib/MC/ELFObjectWriter.cpp - ELF File Writer -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements ELF object file writer information. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/ELFObjectWriter.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCELFSymbolFlags.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ELF.h" +#include "llvm/Target/TargetAsmBackend.h" + +#include "../Target/X86/X86FixupKinds.h" + +#include +using namespace llvm; + +namespace { + + class ELFObjectWriterImpl { + static bool isFixupKindX86PCRel(unsigned Kind) { + switch (Kind) { + default: + return false; + case X86::reloc_pcrel_1byte: + case X86::reloc_pcrel_4byte: + case X86::reloc_riprel_4byte: + case X86::reloc_riprel_4byte_movq_load: + return true; + } + } + + /*static bool isFixupKindX86RIPRel(unsigned Kind) { + return Kind == X86::reloc_riprel_4byte || + Kind == X86::reloc_riprel_4byte_movq_load; + }*/ + + + /// ELFSymbolData - Helper struct for containing some precomputed information + /// on symbols. + struct ELFSymbolData { + MCSymbolData *SymbolData; + uint64_t StringIndex; + uint32_t SectionIndex; + + // Support lexicographic sorting. + bool operator<(const ELFSymbolData &RHS) const { + return SymbolData->getSymbol().getName() < + RHS.SymbolData->getSymbol().getName(); + } + }; + + /// @name Relocation Data + /// @{ + + struct ELFRelocationEntry { + // Make these big enough for both 32-bit and 64-bit + uint64_t r_offset; + uint64_t r_info; + uint64_t r_addend; + + // Support lexicographic sorting. + bool operator<(const ELFRelocationEntry &RE) const { + return RE.r_offset < r_offset; + } + }; + + llvm::DenseMap > Relocations; + DenseMap SectionStringTableIndex; + + /// @} + /// @name Symbol Table Data + /// @{ + + SmallString<256> StringTable; + std::vector LocalSymbolData; + std::vector ExternalSymbolData; + std::vector UndefinedSymbolData; + + /// @} + + ELFObjectWriter *Writer; + + raw_ostream &OS; + + // This holds the current offset into the object file. + size_t FileOff; + + unsigned Is64Bit : 1; + + bool HasRelocationAddend; + + // This holds the symbol table index of the last local symbol. + unsigned LastLocalSymbolIndex; + // This holds the .strtab section index. + unsigned StringTableIndex; + + unsigned ShstrtabIndex; + + public: + ELFObjectWriterImpl(ELFObjectWriter *_Writer, bool _Is64Bit, + bool _HasRelAddend) + : Writer(_Writer), OS(Writer->getStream()), FileOff(0), + Is64Bit(_Is64Bit), HasRelocationAddend(_HasRelAddend) { + } + + void Write8(uint8_t Value) { Writer->Write8(Value); } + void Write16(uint16_t Value) { Writer->Write16(Value); } + void Write32(uint32_t Value) { Writer->Write32(Value); } + //void Write64(uint64_t Value) { Writer->Write64(Value); } + void WriteZeros(unsigned N) { Writer->WriteZeros(N); } + //void WriteBytes(StringRef Str, unsigned ZeroFillSize = 0) { + // Writer->WriteBytes(Str, ZeroFillSize); + //} + + void WriteWord(uint64_t W) { + if (Is64Bit) + Writer->Write64(W); + else + Writer->Write32(W); + } + + void String8(char *buf, uint8_t Value) { + buf[0] = Value; + } + + void StringLE16(char *buf, uint16_t Value) { + buf[0] = char(Value >> 0); + buf[1] = char(Value >> 8); + } + + void StringLE32(char *buf, uint32_t Value) { + StringLE16(buf, uint16_t(Value >> 0)); + StringLE16(buf + 2, uint16_t(Value >> 16)); + } + + void StringLE64(char *buf, uint64_t Value) { + StringLE32(buf, uint32_t(Value >> 0)); + StringLE32(buf + 4, uint32_t(Value >> 32)); + } + + void StringBE16(char *buf ,uint16_t Value) { + buf[0] = char(Value >> 8); + buf[1] = char(Value >> 0); + } + + void StringBE32(char *buf, uint32_t Value) { + StringBE16(buf, uint16_t(Value >> 16)); + StringBE16(buf + 2, uint16_t(Value >> 0)); + } + + void StringBE64(char *buf, uint64_t Value) { + StringBE32(buf, uint32_t(Value >> 32)); + StringBE32(buf + 4, uint32_t(Value >> 0)); + } + + void String16(char *buf, uint16_t Value) { + if (Writer->isLittleEndian()) + StringLE16(buf, Value); + else + StringBE16(buf, Value); + } + + void String32(char *buf, uint32_t Value) { + if (Writer->isLittleEndian()) + StringLE32(buf, Value); + else + StringBE32(buf, Value); + } + + void String64(char *buf, uint64_t Value) { + if (Writer->isLittleEndian()) + StringLE64(buf, Value); + else + StringBE64(buf, Value); + } + + void WriteHeader(uint64_t SectionDataSize, unsigned NumberOfSections); + + void WriteSymbolEntry(MCDataFragment *F, uint64_t name, uint8_t info, + uint64_t value, uint64_t size, + uint8_t other, uint16_t shndx); + + void WriteSymbol(MCDataFragment *F, ELFSymbolData &MSD, + const MCAsmLayout &Layout); + + void WriteSymbolTable(MCDataFragment *F, const MCAssembler &Asm, + const MCAsmLayout &Layout); + + void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFragment *Fragment, const MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue); + + uint64_t getSymbolIndexInSymbolTable(const MCAssembler &Asm, + const MCSymbol *S); + + /// ComputeSymbolTable - Compute the symbol table data + /// + /// \param StringTable [out] - The string table data. + /// \param StringIndexMap [out] - Map from symbol names to offsets in the + /// string table. + void ComputeSymbolTable(MCAssembler &Asm); + + void WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, + const MCSectionData &SD); + + void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout) { + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + WriteRelocation(Asm, Layout, *it); + } + } + + void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout); + + void ExecutePostLayoutBinding(MCAssembler &Asm) { + // Compute symbol table information. + ComputeSymbolTable(Asm); + } + + void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, + uint64_t Address, uint64_t Offset, + uint64_t Size, uint32_t Link, uint32_t Info, + uint64_t Alignment, uint64_t EntrySize); + + void WriteRelocationsFragment(const MCAssembler &Asm, MCDataFragment *F, + const MCSectionData *SD); + + void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout); + }; + +} + +// Emit the ELF header. +void ELFObjectWriterImpl::WriteHeader(uint64_t SectionDataSize, + unsigned NumberOfSections) { + // ELF Header + // ---------- + // + // Note + // ---- + // emitWord method behaves differently for ELF32 and ELF64, writing + // 4 bytes in the former and 8 in the latter. + + Write8(0x7f); // e_ident[EI_MAG0] + Write8('E'); // e_ident[EI_MAG1] + Write8('L'); // e_ident[EI_MAG2] + Write8('F'); // e_ident[EI_MAG3] + + Write8(Is64Bit ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS] + + // e_ident[EI_DATA] + Write8(Writer->isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB); + + Write8(ELF::EV_CURRENT); // e_ident[EI_VERSION] + Write8(ELF::ELFOSABI_LINUX); // e_ident[EI_OSABI] + Write8(0); // e_ident[EI_ABIVERSION] + + WriteZeros(ELF::EI_NIDENT - ELF::EI_PAD); + + Write16(ELF::ET_REL); // e_type + + // FIXME: Make this configurable + Write16(Is64Bit ? ELF::EM_X86_64 : ELF::EM_386); // e_machine = target + + Write32(ELF::EV_CURRENT); // e_version + WriteWord(0); // e_entry, no entry point in .o file + WriteWord(0); // e_phoff, no program header for .o + WriteWord(SectionDataSize + (Is64Bit ? sizeof(ELF::Elf64_Ehdr) : + sizeof(ELF::Elf32_Ehdr))); // e_shoff = sec hdr table off in bytes + + // FIXME: Make this configurable. + Write32(0); // e_flags = whatever the target wants + + // e_ehsize = ELF header size + Write16(Is64Bit ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr)); + + Write16(0); // e_phentsize = prog header entry size + Write16(0); // e_phnum = # prog header entries = 0 + + // e_shentsize = Section header entry size + Write16(Is64Bit ? sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr)); + + // e_shnum = # of section header ents + Write16(NumberOfSections); + + // e_shstrndx = Section # of '.shstrtab' + Write16(ShstrtabIndex); +} + +void ELFObjectWriterImpl::WriteSymbolEntry(MCDataFragment *F, uint64_t name, + uint8_t info, uint64_t value, + uint64_t size, uint8_t other, + uint16_t shndx) { + if (Is64Bit) { + char buf[8]; + + String32(buf, name); + F->getContents() += StringRef(buf, 4); // st_name + + String8(buf, info); + F->getContents() += StringRef(buf, 1); // st_info + + String8(buf, other); + F->getContents() += StringRef(buf, 1); // st_other + + String16(buf, shndx); + F->getContents() += StringRef(buf, 2); // st_shndx + + String64(buf, value); + F->getContents() += StringRef(buf, 8); // st_value + + String64(buf, size); + F->getContents() += StringRef(buf, 8); // st_size + } else { + char buf[4]; + + String32(buf, name); + F->getContents() += StringRef(buf, 4); // st_name + + String32(buf, value); + F->getContents() += StringRef(buf, 4); // st_value + + String32(buf, size); + F->getContents() += StringRef(buf, 4); // st_size + + String8(buf, info); + F->getContents() += StringRef(buf, 1); // st_info + + String8(buf, other); + F->getContents() += StringRef(buf, 1); // st_other + + String16(buf, shndx); + F->getContents() += StringRef(buf, 2); // st_shndx + } +} + +void ELFObjectWriterImpl::WriteSymbol(MCDataFragment *F, ELFSymbolData &MSD, + const MCAsmLayout &Layout) { + MCSymbolData &Data = *MSD.SymbolData; + uint8_t Info = (Data.getFlags() & 0xff); + uint8_t Other = ((Data.getFlags() & 0xf00) >> ELF_STV_Shift); + uint64_t Value = 0; + uint64_t Size = 0; + const MCExpr *ESize; + + if (Data.isCommon() && Data.isExternal()) + Value = Data.getCommonAlignment(); + + if (!Data.isCommon()) + if (MCFragment *FF = Data.getFragment()) + Value = Layout.getSymbolAddress(&Data) - + Layout.getSectionAddress(FF->getParent()); + + ESize = Data.getSize(); + if (Data.getSize()) { + MCValue Res; + if (ESize->getKind() == MCExpr::Binary) { + const MCBinaryExpr *BE = static_cast(ESize); + + if (BE->EvaluateAsRelocatable(Res, &Layout)) { + MCSymbolData &A = + Layout.getAssembler().getSymbolData(Res.getSymA()->getSymbol()); + MCSymbolData &B = + Layout.getAssembler().getSymbolData(Res.getSymB()->getSymbol()); + + Size = Layout.getSymbolAddress(&A) - Layout.getSymbolAddress(&B); + } + } else if (ESize->getKind() == MCExpr::Constant) { + Size = static_cast(ESize)->getValue(); + } else { + assert(0 && "Unsupported size expression"); + } + } + + // Write out the symbol table entry + WriteSymbolEntry(F, MSD.StringIndex, Info, Value, + Size, Other, MSD.SectionIndex); +} + +void ELFObjectWriterImpl::WriteSymbolTable(MCDataFragment *F, + const MCAssembler &Asm, + const MCAsmLayout &Layout) { + // The string table must be emitted first because we need the index + // into the string table for all the symbol names. + assert(StringTable.size() && "Missing string table"); + + // FIXME: Make sure the start of the symbol table is aligned. + + // The first entry is the undefined symbol entry. + unsigned EntrySize = Is64Bit ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; + F->getContents().append(EntrySize, '\x00'); + + // Write the symbol table entries. + LastLocalSymbolIndex = LocalSymbolData.size() + 1; + for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) { + ELFSymbolData &MSD = LocalSymbolData[i]; + WriteSymbol(F, MSD, Layout); + } + + // Write out a symbol table entry for each section. + // leaving out the just added .symtab which is at + // the very end + unsigned Index = 1; + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it, ++Index) { + const MCSectionELF &Section = + static_cast(it->getSection()); + // Leave out relocations so we don't have indexes within + // the relocations messed up + if (Section.getType() == ELF::SHT_RELA || Section.getType() == ELF::SHT_REL) + continue; + if (Index == Asm.size()) + continue; + WriteSymbolEntry(F, 0, ELF::STT_SECTION, 0, 0, ELF::STV_DEFAULT, Index); + LastLocalSymbolIndex++; + } + + for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) { + ELFSymbolData &MSD = ExternalSymbolData[i]; + MCSymbolData &Data = *MSD.SymbolData; + assert((Data.getFlags() & ELF_STB_Global) && + "External symbol requires STB_GLOBAL flag"); + WriteSymbol(F, MSD, Layout); + if (Data.getFlags() & ELF_STB_Local) + LastLocalSymbolIndex++; + } + + for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) { + ELFSymbolData &MSD = UndefinedSymbolData[i]; + MCSymbolData &Data = *MSD.SymbolData; + Data.setFlags(Data.getFlags() | ELF_STB_Global); + WriteSymbol(F, MSD, Layout); + if (Data.getFlags() & ELF_STB_Local) + LastLocalSymbolIndex++; + } +} + +// FIXME: this is currently X86/X86_64 only +void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, + MCValue Target, + uint64_t &FixedValue) { + int64_t Addend = 0; + unsigned Index = 0; + int64_t Value = Target.getConstant(); + + if (!Target.isAbsolute()) { + const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); + MCSymbolData &SD = Asm.getSymbolData(*Symbol); + const MCSymbolData *Base = Asm.getAtom(Layout, &SD); + MCFragment *F = SD.getFragment(); + + if (Base) { + if (F && (!Symbol->isInSection() || SD.isCommon()) && !SD.isExternal()) { + Index = F->getParent()->getOrdinal() + LocalSymbolData.size() + 1; + Value += Layout.getSymbolAddress(&SD); + } else + Index = getSymbolIndexInSymbolTable(Asm, Symbol); + if (Base != &SD) + Value += Layout.getSymbolAddress(&SD) - Layout.getSymbolAddress(Base); + Addend = Value; + // Compensate for the addend on i386. + if (Is64Bit) + Value = 0; + } else { + if (F) { + // Index of the section in .symtab against this symbol + // is being relocated + 2 (empty section + abs. symbols). + Index = F->getParent()->getOrdinal() + LocalSymbolData.size() + 1; + + MCSectionData *FSD = F->getParent(); + // Offset of the symbol in the section + Addend = Layout.getSymbolAddress(&SD) - Layout.getSectionAddress(FSD); + } else { + FixedValue = Value; + return; + } + } + } + + FixedValue = Value; + + // determine the type of the relocation + bool IsPCRel = isFixupKindX86PCRel(Fixup.getKind()); + unsigned Type; + if (Is64Bit) { + if (IsPCRel) { + Type = ELF::R_X86_64_PC32; + } else { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + case FK_Data_8: Type = ELF::R_X86_64_64; break; + case X86::reloc_pcrel_4byte: + case FK_Data_4: + // check that the offset fits within a signed long + if (isInt<32>(Target.getConstant())) + Type = ELF::R_X86_64_32S; + else + Type = ELF::R_X86_64_32; + break; + case FK_Data_2: Type = ELF::R_X86_64_16; break; + case X86::reloc_pcrel_1byte: + case FK_Data_1: Type = ELF::R_X86_64_8; break; + } + } + } else { + if (IsPCRel) { + Type = ELF::R_386_PC32; + } else { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + case X86::reloc_pcrel_4byte: + case FK_Data_4: Type = ELF::R_386_32; break; + case FK_Data_2: Type = ELF::R_386_16; break; + case X86::reloc_pcrel_1byte: + case FK_Data_1: Type = ELF::R_386_8; break; + } + } + } + + ELFRelocationEntry ERE; + + if (Is64Bit) { + struct ELF::Elf64_Rela ERE64; + ERE64.setSymbolAndType(Index, Type); + ERE.r_info = ERE64.r_info; + } else { + struct ELF::Elf32_Rela ERE32; + ERE32.setSymbolAndType(Index, Type); + ERE.r_info = ERE32.r_info; + } + + ERE.r_offset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + + if (HasRelocationAddend) + ERE.r_addend = Addend; + else + ERE.r_addend = 0; // Silence compiler warning. + + Relocations[Fragment->getParent()].push_back(ERE); +} + +uint64_t +ELFObjectWriterImpl::getSymbolIndexInSymbolTable(const MCAssembler &Asm, + const MCSymbol *S) { + MCSymbolData &SD = Asm.getSymbolData(*S); + + // Local symbol. + if (!SD.isExternal() && !S->isUndefined()) + return SD.getIndex() + /* empty symbol */ 1; + + // External or undefined symbol. + return SD.getIndex() + Asm.size() + /* empty symbol */ 1; +} + +void ELFObjectWriterImpl::ComputeSymbolTable(MCAssembler &Asm) { + // Build section lookup table. + DenseMap SectionIndexMap; + unsigned Index = 1; + for (MCAssembler::iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it, ++Index) + SectionIndexMap[&it->getSection()] = Index; + + // Index 0 is always the empty string. + StringMap StringIndexMap; + StringTable += '\x00'; + + // Add the data for local symbols. + for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) { + const MCSymbol &Symbol = it->getSymbol(); + + // Ignore non-linker visible symbols. + if (!Asm.isSymbolLinkerVisible(Symbol)) + continue; + + if (it->isExternal() || Symbol.isUndefined()) + continue; + + uint64_t &Entry = StringIndexMap[Symbol.getName()]; + if (!Entry) { + Entry = StringTable.size(); + StringTable += Symbol.getName(); + StringTable += '\x00'; + } + + ELFSymbolData MSD; + MSD.SymbolData = it; + MSD.StringIndex = Entry; + + if (Symbol.isAbsolute()) { + MSD.SectionIndex = ELF::SHN_ABS; + LocalSymbolData.push_back(MSD); + } else { + MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); + assert(MSD.SectionIndex && "Invalid section index!"); + LocalSymbolData.push_back(MSD); + } + } + + // Now add non-local symbols. + for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) { + const MCSymbol &Symbol = it->getSymbol(); + + // Ignore non-linker visible symbols. + if (!Asm.isSymbolLinkerVisible(Symbol)) + continue; + + if (!it->isExternal() && !Symbol.isUndefined()) + continue; + + uint64_t &Entry = StringIndexMap[Symbol.getName()]; + if (!Entry) { + Entry = StringTable.size(); + StringTable += Symbol.getName(); + StringTable += '\x00'; + } + + ELFSymbolData MSD; + MSD.SymbolData = it; + MSD.StringIndex = Entry; + + if (Symbol.isUndefined()) { + MSD.SectionIndex = ELF::SHN_UNDEF; + // XXX: for some reason we dont Emit* this + it->setFlags(it->getFlags() | ELF_STB_Global); + UndefinedSymbolData.push_back(MSD); + } else if (Symbol.isAbsolute()) { + MSD.SectionIndex = ELF::SHN_ABS; + ExternalSymbolData.push_back(MSD); + } else if (it->isCommon()) { + MSD.SectionIndex = ELF::SHN_COMMON; + ExternalSymbolData.push_back(MSD); + } else { + MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); + assert(MSD.SectionIndex && "Invalid section index!"); + ExternalSymbolData.push_back(MSD); + } + } + + // Symbols are required to be in lexicographic order. + array_pod_sort(LocalSymbolData.begin(), LocalSymbolData.end()); + array_pod_sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); + array_pod_sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); + + // Set the symbol indices. Local symbols must come before all other + // symbols with non-local bindings. + Index = 0; + for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) + LocalSymbolData[i].SymbolData->setIndex(Index++); + for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) + ExternalSymbolData[i].SymbolData->setIndex(Index++); + for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) + UndefinedSymbolData[i].SymbolData->setIndex(Index++); +} + +void ELFObjectWriterImpl::WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, + const MCSectionData &SD) { + if (!Relocations[&SD].empty()) { + MCContext &Ctx = Asm.getContext(); + const MCSection *RelaSection; + const MCSectionELF &Section = + static_cast(SD.getSection()); + + const StringRef SectionName = Section.getSectionName(); + std::string RelaSectionName = HasRelocationAddend ? ".rela" : ".rel"; + RelaSectionName += SectionName; + + unsigned EntrySize; + if (HasRelocationAddend) + EntrySize = Is64Bit ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela); + else + EntrySize = Is64Bit ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf32_Rel); + + RelaSection = Ctx.getELFSection(RelaSectionName, HasRelocationAddend ? + ELF::SHT_RELA : ELF::SHT_REL, 0, + SectionKind::getReadOnly(), + false, EntrySize); + + MCSectionData &RelaSD = Asm.getOrCreateSectionData(*RelaSection); + RelaSD.setAlignment(1); + + MCDataFragment *F = new MCDataFragment(&RelaSD); + + WriteRelocationsFragment(Asm, F, &SD); + + Asm.AddSectionToTheEnd(RelaSD, Layout); + } +} + +void ELFObjectWriterImpl::WriteSecHdrEntry(uint32_t Name, uint32_t Type, + uint64_t Flags, uint64_t Address, + uint64_t Offset, uint64_t Size, + uint32_t Link, uint32_t Info, + uint64_t Alignment, + uint64_t EntrySize) { + Write32(Name); // sh_name: index into string table + Write32(Type); // sh_type + WriteWord(Flags); // sh_flags + WriteWord(Address); // sh_addr + WriteWord(Offset); // sh_offset + WriteWord(Size); // sh_size + Write32(Link); // sh_link + Write32(Info); // sh_info + WriteWord(Alignment); // sh_addralign + WriteWord(EntrySize); // sh_entsize +} + +void ELFObjectWriterImpl::WriteRelocationsFragment(const MCAssembler &Asm, + MCDataFragment *F, + const MCSectionData *SD) { + std::vector &Relocs = Relocations[SD]; + // sort by the r_offset just like gnu as does + array_pod_sort(Relocs.begin(), Relocs.end()); + + for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { + ELFRelocationEntry entry = Relocs[e - i - 1]; + + unsigned WordSize = Is64Bit ? 8 : 4; + F->getContents() += StringRef((const char *)&entry.r_offset, WordSize); + F->getContents() += StringRef((const char *)&entry.r_info, WordSize); + + if (HasRelocationAddend) + F->getContents() += StringRef((const char *)&entry.r_addend, WordSize); + } +} + +void ELFObjectWriterImpl::CreateMetadataSections(MCAssembler &Asm, + MCAsmLayout &Layout) { + MCContext &Ctx = Asm.getContext(); + MCDataFragment *F; + + WriteRelocations(Asm, Layout); + + const MCSection *SymtabSection; + unsigned EntrySize = Is64Bit ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; + + SymtabSection = Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, + SectionKind::getReadOnly(), + false, EntrySize); + + MCSectionData &SymtabSD = Asm.getOrCreateSectionData(*SymtabSection); + + SymtabSD.setAlignment(Is64Bit ? 8 : 4); + + F = new MCDataFragment(&SymtabSD); + + // Symbol table + WriteSymbolTable(F, Asm, Layout); + Asm.AddSectionToTheEnd(SymtabSD, Layout); + + const MCSection *StrtabSection; + StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0, + SectionKind::getReadOnly(), false); + + MCSectionData &StrtabSD = Asm.getOrCreateSectionData(*StrtabSection); + StrtabSD.setAlignment(1); + + // FIXME: This isn't right. If the sections get rearranged this will + // be wrong. We need a proper lookup. + StringTableIndex = Asm.size(); + + F = new MCDataFragment(&StrtabSD); + F->getContents().append(StringTable.begin(), StringTable.end()); + Asm.AddSectionToTheEnd(StrtabSD, Layout); + + const MCSection *ShstrtabSection; + ShstrtabSection = Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0, + SectionKind::getReadOnly(), false); + + MCSectionData &ShstrtabSD = Asm.getOrCreateSectionData(*ShstrtabSection); + ShstrtabSD.setAlignment(1); + + F = new MCDataFragment(&ShstrtabSD); + + // FIXME: This isn't right. If the sections get rearranged this will + // be wrong. We need a proper lookup. + ShstrtabIndex = Asm.size(); + + // Section header string table. + // + // The first entry of a string table holds a null character so skip + // section 0. + uint64_t Index = 1; + F->getContents() += '\x00'; + + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionELF &Section = + static_cast(it->getSection()); + + // Remember the index into the string table so we can write it + // into the sh_name field of the section header table. + SectionStringTableIndex[&it->getSection()] = Index; + + Index += Section.getSectionName().size() + 1; + F->getContents() += Section.getSectionName(); + F->getContents() += '\x00'; + } + + Asm.AddSectionToTheEnd(ShstrtabSD, Layout); +} + +void ELFObjectWriterImpl::WriteObject(const MCAssembler &Asm, + const MCAsmLayout &Layout) { + CreateMetadataSections(const_cast(Asm), + const_cast(Layout)); + + // Add 1 for the null section. + unsigned NumSections = Asm.size() + 1; + + uint64_t SectionDataSize = 0; + + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionData &SD = *it; + + // Get the size of the section in the output file (including padding). + uint64_t Size = Layout.getSectionFileSize(&SD); + SectionDataSize += Size; + } + + // Write out the ELF header ... + WriteHeader(SectionDataSize, NumSections); + FileOff = Is64Bit ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr); + + // ... then all of the sections ... + DenseMap SectionOffsetMap; + + DenseMap SectionIndexMap; + + unsigned Index = 1; + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + // Remember the offset into the file for this section. + SectionOffsetMap[&it->getSection()] = FileOff; + + SectionIndexMap[&it->getSection()] = Index++; + + const MCSectionData &SD = *it; + FileOff += Layout.getSectionFileSize(&SD); + + Asm.WriteSectionData(it, Layout, Writer); + } + + // ... and then the section header table. + // Should we align the section header table? + // + // Null section first. + WriteSecHdrEntry(0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionData &SD = *it; + const MCSectionELF &Section = + static_cast(SD.getSection()); + + uint64_t sh_link = 0; + uint64_t sh_info = 0; + + switch(Section.getType()) { + case ELF::SHT_DYNAMIC: + sh_link = SectionStringTableIndex[&it->getSection()]; + sh_info = 0; + break; + + case ELF::SHT_REL: + case ELF::SHT_RELA: { + const MCSection *SymtabSection; + const MCSection *InfoSection; + + SymtabSection = Asm.getContext().getELFSection(".symtab", ELF::SHT_SYMTAB, 0, + SectionKind::getReadOnly(), + false); + sh_link = SectionIndexMap[SymtabSection]; + + // Remove ".rel" and ".rela" prefixes. + unsigned SecNameLen = (Section.getType() == ELF::SHT_REL) ? 4 : 5; + StringRef SectionName = Section.getSectionName().substr(SecNameLen); + + InfoSection = Asm.getContext().getELFSection(SectionName, + ELF::SHT_PROGBITS, 0, + SectionKind::getReadOnly(), + false); + sh_info = SectionIndexMap[InfoSection]; + break; + } + + case ELF::SHT_SYMTAB: + case ELF::SHT_DYNSYM: + sh_link = StringTableIndex; + sh_info = LastLocalSymbolIndex; + break; + + case ELF::SHT_PROGBITS: + case ELF::SHT_STRTAB: + case ELF::SHT_NOBITS: + case ELF::SHT_NULL: + // Nothing to do. + break; + + case ELF::SHT_HASH: + case ELF::SHT_GROUP: + case ELF::SHT_SYMTAB_SHNDX: + default: + assert(0 && "FIXME: sh_type value not supported!"); + break; + } + + WriteSecHdrEntry(SectionStringTableIndex[&it->getSection()], + Section.getType(), Section.getFlags(), + Layout.getSectionAddress(&SD), + SectionOffsetMap.lookup(&SD.getSection()), + Layout.getSectionSize(&SD), sh_link, + sh_info, SD.getAlignment(), + Section.getEntrySize()); + } +} + +ELFObjectWriter::ELFObjectWriter(raw_ostream &OS, + bool Is64Bit, + bool IsLittleEndian, + bool HasRelocationAddend) + : MCObjectWriter(OS, IsLittleEndian) +{ + Impl = new ELFObjectWriterImpl(this, Is64Bit, HasRelocationAddend); +} + +ELFObjectWriter::~ELFObjectWriter() { + delete (ELFObjectWriterImpl*) Impl; +} + +void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { + ((ELFObjectWriterImpl*) Impl)->ExecutePostLayoutBinding(Asm); +} + +void ELFObjectWriter::RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + uint64_t &FixedValue) { + ((ELFObjectWriterImpl*) Impl)->RecordRelocation(Asm, Layout, Fragment, Fixup, + Target, FixedValue); +} + +void ELFObjectWriter::WriteObject(const MCAssembler &Asm, + const MCAsmLayout &Layout) { + ((ELFObjectWriterImpl*) Impl)->WriteObject(Asm, Layout); +} diff --git a/lib/MC/MCAsmInfo.cpp b/lib/MC/MCAsmInfo.cpp index a275be2..670b2e9 100644 --- a/lib/MC/MCAsmInfo.cpp +++ b/lib/MC/MCAsmInfo.cpp @@ -68,7 +68,9 @@ MCAsmInfo::MCAsmInfo() { ExceptionsType = ExceptionHandling::None; DwarfRequiresFrameSection = true; DwarfUsesInlineInfoSection = false; + DwarfUsesAbsoluteLabelForStmtList = true; DwarfSectionOffsetDirective = 0; + DwarfUsesLabelOffsetForRanges = true; HasMicrosoftFastStdCallMangling = false; AsmTransCBE = 0; diff --git a/lib/MC/MCAsmInfoDarwin.cpp b/lib/MC/MCAsmInfoDarwin.cpp index 0bd3b2d..e0e261a 100644 --- a/lib/MC/MCAsmInfoDarwin.cpp +++ b/lib/MC/MCAsmInfoDarwin.cpp @@ -44,5 +44,8 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() { HasDotTypeDotSizeDirective = false; HasNoDeadStrip = true; + + DwarfUsesAbsoluteLabelForStmtList = false; + DwarfUsesLabelOffsetForRanges = false; } diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index e272b60..1cc8fb0 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -31,7 +31,7 @@ class MCAsmStreamer : public MCStreamer { formatted_raw_ostream &OS; const MCAsmInfo &MAI; OwningPtr InstPrinter; - MCCodeEmitter *Emitter; + OwningPtr Emitter; SmallString<128> CommentToEmit; raw_svector_ostream CommentStream; @@ -217,6 +217,7 @@ static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) { void MCAsmStreamer::SwitchSection(const MCSection *Section) { assert(Section && "Cannot switch to a null section!"); if (Section != CurSection) { + PrevSection = CurSection; CurSection = Section; Section->PrintSwitchToSection(MAI, OS); } diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 7d84554..f0e1d7f 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -178,8 +178,12 @@ uint64_t MCAsmLayout::getSectionSize(const MCSectionData *SD) const { MCFragment::MCFragment() : Kind(FragmentType(~0)) { } +MCFragment::~MCFragment() { +} + MCFragment::MCFragment(FragmentType _Kind, MCSectionData *_Parent) - : Kind(_Kind), Parent(_Parent), Atom(0), EffectiveSize(~UINT64_C(0)) + : Kind(_Kind), Parent(_Parent), Atom(0), Offset(~UINT64_C(0)), + EffectiveSize(~UINT64_C(0)) { if (Parent) Parent->getFragmentList().push_back(this); @@ -207,7 +211,8 @@ MCSymbolData::MCSymbolData(const MCSymbol &_Symbol, MCFragment *_Fragment, uint64_t _Offset, MCAssembler *A) : Symbol(&_Symbol), Fragment(_Fragment), Offset(_Offset), IsExternal(false), IsPrivateExtern(false), - CommonSize(0), CommonAlign(0), Flags(0), Index(0) + CommonSize(0), SymbolSize(0), CommonAlign(0), + Flags(0), Index(0) { if (A) A->getSymbolList().push_back(this); @@ -623,8 +628,23 @@ void MCAssembler::WriteSectionData(const MCSectionData *SD, switch (it->getKind()) { default: assert(0 && "Invalid fragment in virtual section!"); + case MCFragment::FT_Data: { + // Check that we aren't trying to write a non-zero contents (or fixups) + // into a virtual section. This is to support clients which use standard + // directives to fill the contents of virtual sections. + MCDataFragment &DF = cast(*it); + assert(DF.fixup_begin() == DF.fixup_end() && + "Cannot have fixups in virtual section!"); + for (unsigned i = 0, e = DF.getContents().size(); i != e; ++i) + assert(DF.getContents()[i] == 0 && + "Invalid data value for virtual section!"); + break; + } case MCFragment::FT_Align: - assert(!cast(it)->getValueSize() && + // Check that we aren't trying to write a non-zero value into a virtual + // section. + assert((!cast(it)->getValueSize() || + !cast(it)->getValue()) && "Invalid align in virtual section!"); break; case MCFragment::FT_Fill: @@ -647,7 +667,41 @@ void MCAssembler::WriteSectionData(const MCSectionData *SD, assert(OW->getStream().tell() - Start == Layout.getSectionFileSize(SD)); } -void MCAssembler::Finish() { +void MCAssembler::AddSectionToTheEnd(MCSectionData &SD, MCAsmLayout &Layout) { + // Create dummy fragments and assign section ordinals. + unsigned SectionIndex = 0; + for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) + SectionIndex++; + + SD.setOrdinal(SectionIndex); + + // Assign layout order indices to sections and fragments. + unsigned FragmentIndex = 0; + unsigned i = 0; + for (unsigned e = Layout.getSectionOrder().size(); i != e; ++i) { + MCSectionData *SD = Layout.getSectionOrder()[i]; + + for (MCSectionData::iterator it2 = SD->begin(), + ie2 = SD->end(); it2 != ie2; ++it2) + FragmentIndex++; + } + + SD.setLayoutOrder(i); + for (MCSectionData::iterator it2 = SD.begin(), + ie2 = SD.end(); it2 != ie2; ++it2) { + it2->setLayoutOrder(FragmentIndex++); + } + Layout.getSectionOrder().push_back(&SD); + + Layout.LayoutSection(&SD); + + // Layout until everything fits. + while (LayoutOnce(Layout)) + continue; + +} + +void MCAssembler::Finish(MCObjectWriter *Writer) { DEBUG_WITH_TYPE("mc-dump", { llvm::errs() << "assembler backend - pre-layout\n--\n"; dump(); }); @@ -717,9 +771,15 @@ void MCAssembler::Finish() { dump(); }); uint64_t StartOffset = OS.tell(); - llvm::OwningPtr Writer(getBackend().createObjectWriter(OS)); - if (!Writer) - report_fatal_error("unable to create object writer!"); + + llvm::OwningPtr OwnWriter(0); + if (Writer == 0) { + //no custom Writer_ : create the default one life-managed by OwningPtr + OwnWriter.reset(getBackend().createObjectWriter(OS)); + Writer = OwnWriter.get(); + if (!Writer) + report_fatal_error("unable to create object writer!"); + } // Allow the object writer a chance to perform post-layout binding (for // example, to set the index fields in the symbol data). diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index 1137064..e5586a0 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -14,6 +14,7 @@ #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCLabel.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" using namespace llvm; @@ -23,7 +24,8 @@ typedef StringMap ELFUniqueMapTy; typedef StringMap COFFUniqueMapTy; -MCContext::MCContext(const MCAsmInfo &mai) : MAI(mai), NextUniqueID(0) { +MCContext::MCContext(const MCAsmInfo &mai) : MAI(mai), NextUniqueID(0), + CurrentDwarfLoc(0,0,0,0,0) { MachOUniquingMap = 0; ELFUniquingMap = 0; COFFUniquingMap = 0; @@ -31,6 +33,8 @@ MCContext::MCContext(const MCAsmInfo &mai) : MAI(mai), NextUniqueID(0) { SecureLogFile = getenv("AS_SECURE_LOG_FILE"); SecureLog = 0; SecureLogUsed = false; + + DwarfLocSeen = false; } MCContext::~MCContext() { @@ -147,7 +151,7 @@ getMachOSection(StringRef Segment, StringRef Section, const MCSection *MCContext:: getELFSection(StringRef Section, unsigned Type, unsigned Flags, - SectionKind Kind, bool IsExplicit) { + SectionKind Kind, bool IsExplicit, unsigned EntrySize) { if (ELFUniquingMap == 0) ELFUniquingMap = new ELFUniqueMapTy(); ELFUniqueMapTy &Map = *(ELFUniqueMapTy*)ELFUniquingMap; @@ -157,7 +161,7 @@ getELFSection(StringRef Section, unsigned Type, unsigned Flags, if (Entry.getValue()) return Entry.getValue(); MCSectionELF *Result = new (*this) MCSectionELF(Entry.getKey(), Type, Flags, - Kind, IsExplicit); + Kind, IsExplicit, EntrySize); Entry.setValue(Result); return Result; } @@ -181,3 +185,81 @@ const MCSection *MCContext::getCOFFSection(StringRef Section, Entry.setValue(Result); return Result; } + +//===----------------------------------------------------------------------===// +// Dwarf Management +//===----------------------------------------------------------------------===// + +/// GetDwarfFile - takes a file name an number to place in the dwarf file and +/// directory tables. If the file number has already been allocated it is an +/// error and zero is returned and the client reports the error, else the +/// allocated file number is returned. The file numbers may be in any order. +unsigned MCContext::GetDwarfFile(StringRef FileName, unsigned FileNumber) { + // TODO: a FileNumber of zero says to use the next available file number. + // Note: in GenericAsmParser::ParseDirectiveFile() FileNumber was checked + // to not be less than one. This needs to be change to be not less than zero. + + // Make space for this FileNumber in the MCDwarfFiles vector if needed. + if (FileNumber >= MCDwarfFiles.size()) { + MCDwarfFiles.resize(FileNumber + 1); + } else { + MCDwarfFile *&ExistingFile = MCDwarfFiles[FileNumber]; + if (ExistingFile) + // It is an error to use see the same number more than once. + return 0; + } + + // Get the new MCDwarfFile slot for this FileNumber. + MCDwarfFile *&File = MCDwarfFiles[FileNumber]; + + // Separate the directory part from the basename of the FileName. + std::pair Slash = FileName.rsplit('/'); + + // Find or make a entry in the MCDwarfDirs vector for this Directory. + StringRef Name; + unsigned DirIndex; + // Capture directory name. + if (Slash.second.empty()) { + Name = Slash.first; + DirIndex = 0; // For FileNames with no directories a DirIndex of 0 is used. + } else { + StringRef Directory = Slash.first; + Name = Slash.second; + for (DirIndex = 0; DirIndex < MCDwarfDirs.size(); DirIndex++) { + if (Directory == MCDwarfDirs[DirIndex]) + break; + } + if (DirIndex >= MCDwarfDirs.size()) { + char *Buf = static_cast(Allocate(Directory.size())); + memcpy(Buf, Directory.data(), Directory.size()); + MCDwarfDirs.push_back(StringRef(Buf, Directory.size())); + } + // The DirIndex is one based, as DirIndex of 0 is used for FileNames with + // no directories. MCDwarfDirs[] is unlike MCDwarfFiles[] in that the + // directory names are stored at MCDwarfDirs[DirIndex-1] where FileNames are + // stored at MCDwarfFiles[FileNumber].Name . + DirIndex++; + } + + // Now make the MCDwarfFile entry and place it in the slot in the MCDwarfFiles + // vector. + char *Buf = static_cast(Allocate(Name.size())); + memcpy(Buf, Name.data(), Name.size()); + File = new (*this) MCDwarfFile(StringRef(Buf, Name.size()), DirIndex); + + // return the allocated FileNumber. + return FileNumber; +} + +/// ValidateDwarfFileNumber - takes a dwarf file number and returns true if it +/// currently is assigned and false otherwise. +bool MCContext::ValidateDwarfFileNumber(unsigned FileNumber) { + if(FileNumber == 0 || FileNumber >= MCDwarfFiles.size()) + return false; + + MCDwarfFile *&ExistingFile = MCDwarfFiles[FileNumber]; + if (ExistingFile) + return true; + else + return false; +} diff --git a/lib/MC/MCDisassembler/CMakeLists.txt b/lib/MC/MCDisassembler/CMakeLists.txt new file mode 100644 index 0000000..5fa7b70 --- /dev/null +++ b/lib/MC/MCDisassembler/CMakeLists.txt @@ -0,0 +1,7 @@ + +add_llvm_library(LLVMMCDisassembler + EDDisassembler.cpp + EDOperand.cpp + EDInst.cpp + EDToken.cpp + ) diff --git a/lib/MC/MCDisassembler/EDDisassembler.cpp b/lib/MC/MCDisassembler/EDDisassembler.cpp new file mode 100644 index 0000000..697b3d9 --- /dev/null +++ b/lib/MC/MCDisassembler/EDDisassembler.cpp @@ -0,0 +1,402 @@ +//===-EDDisassembler.cpp - LLVM Enhanced Disassembler ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Enhanced Disassembly library's disassembler class. +// The disassembler is responsible for vending individual instructions according +// to a given architecture and disassembly syntax. +// +//===----------------------------------------------------------------------===// + +#include "EDDisassembler.h" +#include "EDInst.h" +#include "llvm/MC/EDInstInfo.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCParser/AsmLexer.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Target/TargetAsmLexer.h" +#include "llvm/Target/TargetAsmParser.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSelect.h" +using namespace llvm; + +bool EDDisassembler::sInitialized = false; +EDDisassembler::DisassemblerMap_t EDDisassembler::sDisassemblers; + +struct TripleMap { + Triple::ArchType Arch; + const char *String; +}; + +static struct TripleMap triplemap[] = { + { Triple::x86, "i386-unknown-unknown" }, + { Triple::x86_64, "x86_64-unknown-unknown" }, + { Triple::arm, "arm-unknown-unknown" }, + { Triple::thumb, "thumb-unknown-unknown" }, + { Triple::InvalidArch, NULL, } +}; + +/// infoFromArch - Returns the TripleMap corresponding to a given architecture, +/// or NULL if there is an error +/// +/// @arg arch - The Triple::ArchType for the desired architecture +static const char *tripleFromArch(Triple::ArchType arch) { + unsigned int infoIndex; + + for (infoIndex = 0; triplemap[infoIndex].String != NULL; ++infoIndex) { + if (arch == triplemap[infoIndex].Arch) + return triplemap[infoIndex].String; + } + + return NULL; +} + +/// getLLVMSyntaxVariant - gets the constant to use to get an assembly printer +/// for the desired assembly syntax, suitable for passing to +/// Target::createMCInstPrinter() +/// +/// @arg arch - The target architecture +/// @arg syntax - The assembly syntax in sd form +static int getLLVMSyntaxVariant(Triple::ArchType arch, + EDDisassembler::AssemblySyntax syntax) { + switch (syntax) { + default: + return -1; + // Mappings below from X86AsmPrinter.cpp + case EDDisassembler::kEDAssemblySyntaxX86ATT: + if (arch == Triple::x86 || arch == Triple::x86_64) + return 0; + else + return -1; + case EDDisassembler::kEDAssemblySyntaxX86Intel: + if (arch == Triple::x86 || arch == Triple::x86_64) + return 1; + else + return -1; + case EDDisassembler::kEDAssemblySyntaxARMUAL: + if (arch == Triple::arm || arch == Triple::thumb) + return 0; + else + return -1; + } +} + +void EDDisassembler::initialize() { + if (sInitialized) + return; + + sInitialized = true; + + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + InitializeAllDisassemblers(); +} + +#undef BRINGUP_TARGET + +EDDisassembler *EDDisassembler::getDisassembler(Triple::ArchType arch, + AssemblySyntax syntax) { + CPUKey key; + key.Arch = arch; + key.Syntax = syntax; + + EDDisassembler::DisassemblerMap_t::iterator i = sDisassemblers.find(key); + + if (i != sDisassemblers.end()) { + return i->second; + } else { + EDDisassembler* sdd = new EDDisassembler(key); + if (!sdd->valid()) { + delete sdd; + return NULL; + } + + sDisassemblers[key] = sdd; + + return sdd; + } + + return NULL; +} + +EDDisassembler *EDDisassembler::getDisassembler(StringRef str, + AssemblySyntax syntax) { + return getDisassembler(Triple(str).getArch(), syntax); +} + +EDDisassembler::EDDisassembler(CPUKey &key) : + Valid(false), + HasSemantics(false), + ErrorStream(nulls()), + Key(key) { + const char *triple = tripleFromArch(key.Arch); + + if (!triple) + return; + + LLVMSyntaxVariant = getLLVMSyntaxVariant(key.Arch, key.Syntax); + + if (LLVMSyntaxVariant < 0) + return; + + std::string tripleString(triple); + std::string errorString; + + Tgt = TargetRegistry::lookupTarget(tripleString, + errorString); + + if (!Tgt) + return; + + std::string featureString; + + TargetMachine.reset(Tgt->createTargetMachine(tripleString, + featureString)); + + const TargetRegisterInfo *registerInfo = TargetMachine->getRegisterInfo(); + + if (!registerInfo) + return; + + initMaps(*registerInfo); + + AsmInfo.reset(Tgt->createAsmInfo(tripleString)); + + if (!AsmInfo) + return; + + Disassembler.reset(Tgt->createMCDisassembler()); + + if (!Disassembler) + return; + + InstInfos = Disassembler->getEDInfo(); + + InstString.reset(new std::string); + InstStream.reset(new raw_string_ostream(*InstString)); + InstPrinter.reset(Tgt->createMCInstPrinter(LLVMSyntaxVariant, *AsmInfo)); + + if (!InstPrinter) + return; + + GenericAsmLexer.reset(new AsmLexer(*AsmInfo)); + SpecificAsmLexer.reset(Tgt->createAsmLexer(*AsmInfo)); + SpecificAsmLexer->InstallLexer(*GenericAsmLexer); + + initMaps(*TargetMachine->getRegisterInfo()); + + Valid = true; +} + +EDDisassembler::~EDDisassembler() { + if (!valid()) + return; +} + +namespace { + /// EDMemoryObject - a subclass of MemoryObject that allows use of a callback + /// as provided by the sd interface. See MemoryObject. + class EDMemoryObject : public llvm::MemoryObject { + private: + EDByteReaderCallback Callback; + void *Arg; + public: + EDMemoryObject(EDByteReaderCallback callback, + void *arg) : Callback(callback), Arg(arg) { } + ~EDMemoryObject() { } + uint64_t getBase() const { return 0x0; } + uint64_t getExtent() const { return (uint64_t)-1; } + int readByte(uint64_t address, uint8_t *ptr) const { + if (!Callback) + return -1; + + if (Callback(ptr, address, Arg)) + return -1; + + return 0; + } + }; +} + +EDInst *EDDisassembler::createInst(EDByteReaderCallback byteReader, + uint64_t address, + void *arg) { + EDMemoryObject memoryObject(byteReader, arg); + + MCInst* inst = new MCInst; + uint64_t byteSize; + + if (!Disassembler->getInstruction(*inst, + byteSize, + memoryObject, + address, + ErrorStream)) { + delete inst; + return NULL; + } else { + const llvm::EDInstInfo *thisInstInfo; + + thisInstInfo = &InstInfos[inst->getOpcode()]; + + EDInst* sdInst = new EDInst(inst, byteSize, *this, thisInstInfo); + return sdInst; + } +} + +void EDDisassembler::initMaps(const TargetRegisterInfo ®isterInfo) { + unsigned numRegisters = registerInfo.getNumRegs(); + unsigned registerIndex; + + for (registerIndex = 0; registerIndex < numRegisters; ++registerIndex) { + const char* registerName = registerInfo.get(registerIndex).Name; + + RegVec.push_back(registerName); + RegRMap[registerName] = registerIndex; + } + + switch (Key.Arch) { + default: + break; + case Triple::x86: + case Triple::x86_64: + stackPointers.insert(registerIDWithName("SP")); + stackPointers.insert(registerIDWithName("ESP")); + stackPointers.insert(registerIDWithName("RSP")); + + programCounters.insert(registerIDWithName("IP")); + programCounters.insert(registerIDWithName("EIP")); + programCounters.insert(registerIDWithName("RIP")); + break; + case Triple::arm: + case Triple::thumb: + stackPointers.insert(registerIDWithName("SP")); + + programCounters.insert(registerIDWithName("PC")); + break; + } +} + +const char *EDDisassembler::nameWithRegisterID(unsigned registerID) const { + if (registerID >= RegVec.size()) + return NULL; + else + return RegVec[registerID].c_str(); +} + +unsigned EDDisassembler::registerIDWithName(const char *name) const { + regrmap_t::const_iterator iter = RegRMap.find(std::string(name)); + if (iter == RegRMap.end()) + return 0; + else + return (*iter).second; +} + +bool EDDisassembler::registerIsStackPointer(unsigned registerID) { + return (stackPointers.find(registerID) != stackPointers.end()); +} + +bool EDDisassembler::registerIsProgramCounter(unsigned registerID) { + return (programCounters.find(registerID) != programCounters.end()); +} + +int EDDisassembler::printInst(std::string &str, MCInst &inst) { + PrinterMutex.acquire(); + + InstPrinter->printInst(&inst, *InstStream); + InstStream->flush(); + str = *InstString; + InstString->clear(); + + PrinterMutex.release(); + + return 0; +} + +int EDDisassembler::parseInst(SmallVectorImpl &operands, + SmallVectorImpl &tokens, + const std::string &str) { + int ret = 0; + + switch (Key.Arch) { + default: + return -1; + case Triple::x86: + case Triple::x86_64: + case Triple::arm: + case Triple::thumb: + break; + } + + const char *cStr = str.c_str(); + MemoryBuffer *buf = MemoryBuffer::getMemBuffer(cStr, cStr + strlen(cStr)); + + StringRef instName; + SMLoc instLoc; + + SourceMgr sourceMgr; + sourceMgr.AddNewSourceBuffer(buf, SMLoc()); // ownership of buf handed over + MCContext context(*AsmInfo); + OwningPtr streamer(createNullStreamer(context)); + OwningPtr genericParser(createMCAsmParser(*Tgt, sourceMgr, + context, *streamer, + *AsmInfo)); + OwningPtr TargetParser(Tgt->createAsmParser(*genericParser, + *TargetMachine)); + + AsmToken OpcodeToken = genericParser->Lex(); + AsmToken NextToken = genericParser->Lex(); // consume next token, because specificParser expects us to + + if (OpcodeToken.is(AsmToken::Identifier)) { + instName = OpcodeToken.getString(); + instLoc = OpcodeToken.getLoc(); + + if (NextToken.isNot(AsmToken::Eof) && + TargetParser->ParseInstruction(instName, instLoc, operands)) + ret = -1; + } else { + ret = -1; + } + + ParserMutex.acquire(); + + if (!ret) { + GenericAsmLexer->setBuffer(buf); + + while (SpecificAsmLexer->Lex(), + SpecificAsmLexer->isNot(AsmToken::Eof) && + SpecificAsmLexer->isNot(AsmToken::EndOfStatement)) { + if (SpecificAsmLexer->is(AsmToken::Error)) { + ret = -1; + break; + } + tokens.push_back(SpecificAsmLexer->getTok()); + } + } + + ParserMutex.release(); + + return ret; +} + +int EDDisassembler::llvmSyntaxVariant() const { + return LLVMSyntaxVariant; +} diff --git a/lib/MC/MCDisassembler/EDDisassembler.h b/lib/MC/MCDisassembler/EDDisassembler.h new file mode 100644 index 0000000..e2f850b --- /dev/null +++ b/lib/MC/MCDisassembler/EDDisassembler.h @@ -0,0 +1,271 @@ +//===-- EDDisassembler.h - LLVM Enhanced Disassembler -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface for the Enhanced Disassembly library's +// disassembler class. The disassembler is responsible for vending individual +// instructions according to a given architecture and disassembly syntax. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EDDISASSEMBLER_H +#define LLVM_EDDISASSEMBLER_H + +#include "EDInfo.h" + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Mutex.h" + +#include +#include +#include + +namespace llvm { +class AsmLexer; +class AsmToken; +class MCContext; +class MCAsmInfo; +class MCAsmLexer; +class AsmParser; +class TargetAsmLexer; +class TargetAsmParser; +class MCDisassembler; +class MCInstPrinter; +class MCInst; +class MCParsedAsmOperand; +class MCStreamer; +template class SmallVectorImpl; +class SourceMgr; +class Target; +class TargetMachine; +class TargetRegisterInfo; + +struct EDInstInfo; +struct EDInst; +struct EDOperand; +struct EDToken; + +typedef int (*EDByteReaderCallback)(uint8_t *byte, uint64_t address, void *arg); + +/// EDDisassembler - Encapsulates a disassembler for a single architecture and +/// disassembly syntax. Also manages the static disassembler registry. +struct EDDisassembler { + typedef enum { + /*! @constant kEDAssemblySyntaxX86Intel Intel syntax for i386 and x86_64. */ + kEDAssemblySyntaxX86Intel = 0, + /*! @constant kEDAssemblySyntaxX86ATT AT&T syntax for i386 and x86_64. */ + kEDAssemblySyntaxX86ATT = 1, + kEDAssemblySyntaxARMUAL = 2 + } AssemblySyntax; + + + //////////////////// + // Static members // + //////////////////// + + /// CPUKey - Encapsulates the descriptor of an architecture/disassembly-syntax + /// pair + struct CPUKey { + /// The architecture type + llvm::Triple::ArchType Arch; + + /// The assembly syntax + AssemblySyntax Syntax; + + /// operator== - Equality operator + bool operator==(const CPUKey &key) const { + return (Arch == key.Arch && + Syntax == key.Syntax); + } + + /// operator< - Less-than operator + bool operator<(const CPUKey &key) const { + if(Arch > key.Arch) + return false; + if(Syntax >= key.Syntax) + return false; + return true; + } + }; + + typedef std::map DisassemblerMap_t; + + /// True if the disassembler registry has been initialized; false if not + static bool sInitialized; + /// A map from disassembler specifications to disassemblers. Populated + /// lazily. + static DisassemblerMap_t sDisassemblers; + + /// getDisassembler - Returns the specified disassemble, or NULL on failure + /// + /// @arg arch - The desired architecture + /// @arg syntax - The desired disassembly syntax + static EDDisassembler *getDisassembler(llvm::Triple::ArchType arch, + AssemblySyntax syntax); + + /// getDisassembler - Returns the disassembler for a given combination of + /// CPU type, CPU subtype, and assembly syntax, or NULL on failure + /// + /// @arg str - The string representation of the architecture triple, e.g., + /// "x86_64-apple-darwin" + /// @arg syntax - The disassembly syntax for the required disassembler + static EDDisassembler *getDisassembler(llvm::StringRef str, + AssemblySyntax syntax); + + /// initialize - Initializes the disassembler registry and the LLVM backend + static void initialize(); + + //////////////////////// + // Per-object members // + //////////////////////// + + /// True only if the object has been successfully initialized + bool Valid; + /// True if the disassembler can provide semantic information + bool HasSemantics; + + /// The stream to write errors to + llvm::raw_ostream &ErrorStream; + + /// The architecture/syntax pair for the current architecture + CPUKey Key; + /// The LLVM target corresponding to the disassembler + const llvm::Target *Tgt; + /// The target machine instance. + llvm::OwningPtr TargetMachine; + /// The assembly information for the target architecture + llvm::OwningPtr AsmInfo; + /// The disassembler for the target architecture + llvm::OwningPtr Disassembler; + /// The output string for the instruction printer; must be guarded with + /// PrinterMutex + llvm::OwningPtr InstString; + /// The output stream for the disassembler; must be guarded with + /// PrinterMutex + llvm::OwningPtr InstStream; + /// The instruction printer for the target architecture; must be guarded with + /// PrinterMutex when printing + llvm::OwningPtr InstPrinter; + /// The mutex that guards the instruction printer's printing functions, which + /// use a shared stream + llvm::sys::Mutex PrinterMutex; + /// The array of instruction information provided by the TableGen backend for + /// the target architecture + const llvm::EDInstInfo *InstInfos; + /// The target-specific lexer for use in tokenizing strings, in + /// target-independent and target-specific portions + llvm::OwningPtr GenericAsmLexer; + llvm::OwningPtr SpecificAsmLexer; + /// The guard for the above + llvm::sys::Mutex ParserMutex; + /// The LLVM number used for the target disassembly syntax variant + int LLVMSyntaxVariant; + + typedef std::vector regvec_t; + typedef std::map regrmap_t; + + /// A vector of registers for quick mapping from LLVM register IDs to names + regvec_t RegVec; + /// A map of registers for quick mapping from register names to LLVM IDs + regrmap_t RegRMap; + + /// A set of register IDs for aliases of the stack pointer for the current + /// architecture + std::set stackPointers; + /// A set of register IDs for aliases of the program counter for the current + /// architecture + std::set programCounters; + + /// Constructor - initializes a disassembler with all the necessary objects, + /// which come pre-allocated from the registry accessor function + /// + /// @arg key - the architecture and disassembly syntax for the + /// disassembler + EDDisassembler(CPUKey& key); + + /// valid - reports whether there was a failure in the constructor. + bool valid() { + return Valid; + } + + /// hasSemantics - reports whether the disassembler can provide operands and + /// tokens. + bool hasSemantics() { + return HasSemantics; + } + + ~EDDisassembler(); + + /// createInst - creates and returns an instruction given a callback and + /// memory address, or NULL on failure + /// + /// @arg byteReader - A callback function that provides machine code bytes + /// @arg address - The address of the first byte of the instruction, + /// suitable for passing to byteReader + /// @arg arg - An opaque argument for byteReader + EDInst *createInst(EDByteReaderCallback byteReader, + uint64_t address, + void *arg); + + /// initMaps - initializes regVec and regRMap using the provided register + /// info + /// + /// @arg registerInfo - the register information to use as a source + void initMaps(const llvm::TargetRegisterInfo ®isterInfo); + /// nameWithRegisterID - Returns the name (owned by the EDDisassembler) of a + /// register for a given register ID, or NULL on failure + /// + /// @arg registerID - the ID of the register to be queried + const char *nameWithRegisterID(unsigned registerID) const; + /// registerIDWithName - Returns the ID of a register for a given register + /// name, or (unsigned)-1 on failure + /// + /// @arg name - The name of the register + unsigned registerIDWithName(const char *name) const; + + /// registerIsStackPointer - reports whether a register ID is an alias for the + /// stack pointer register + /// + /// @arg registerID - The LLVM register ID + bool registerIsStackPointer(unsigned registerID); + /// registerIsStackPointer - reports whether a register ID is an alias for the + /// stack pointer register + /// + /// @arg registerID - The LLVM register ID + bool registerIsProgramCounter(unsigned registerID); + + /// printInst - prints an MCInst to a string, returning 0 on success, or -1 + /// otherwise + /// + /// @arg str - A reference to a string which is filled in with the string + /// representation of the instruction + /// @arg inst - A reference to the MCInst to be printed + int printInst(std::string& str, + llvm::MCInst& inst); + + /// parseInst - extracts operands and tokens from a string for use in + /// tokenizing the string. Returns 0 on success, or -1 otherwise. + /// + /// @arg operands - A reference to a vector that will be filled in with the + /// parsed operands + /// @arg tokens - A reference to a vector that will be filled in with the + /// tokens + /// @arg str - The string representation of the instruction + int parseInst(llvm::SmallVectorImpl &operands, + llvm::SmallVectorImpl &tokens, + const std::string &str); + + /// llvmSyntaxVariant - returns the LLVM syntax variant for this disassembler + int llvmSyntaxVariant() const; +}; + +} // end namespace llvm + +#endif diff --git a/lib/MC/MCDisassembler/EDInfo.h b/lib/MC/MCDisassembler/EDInfo.h new file mode 100644 index 0000000..627c066 --- /dev/null +++ b/lib/MC/MCDisassembler/EDInfo.h @@ -0,0 +1,73 @@ +//===-- EDInfo.h - LLVM Enhanced Disassembler -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EDINFO_H +#define LLVM_EDINFO_H + +enum { + EDIS_MAX_OPERANDS = 13, + EDIS_MAX_SYNTAXES = 2 +}; + +enum OperandTypes { + kOperandTypeNone, + kOperandTypeImmediate, + kOperandTypeRegister, + kOperandTypeX86Memory, + kOperandTypeX86EffectiveAddress, + kOperandTypeX86PCRelative, + kOperandTypeARMBranchTarget, + kOperandTypeARMSoReg, + kOperandTypeARMSoImm, + kOperandTypeARMSoImm2Part, + kOperandTypeARMPredicate, + kOperandTypeARMAddrMode2, + kOperandTypeARMAddrMode2Offset, + kOperandTypeARMAddrMode3, + kOperandTypeARMAddrMode3Offset, + kOperandTypeARMAddrMode4, + kOperandTypeARMAddrMode5, + kOperandTypeARMAddrMode6, + kOperandTypeARMAddrMode6Offset, + kOperandTypeARMAddrModePC, + kOperandTypeARMRegisterList, + kOperandTypeARMTBAddrMode, + kOperandTypeThumbITMask, + kOperandTypeThumbAddrModeS1, + kOperandTypeThumbAddrModeS2, + kOperandTypeThumbAddrModeS4, + kOperandTypeThumbAddrModeRR, + kOperandTypeThumbAddrModeSP, + kOperandTypeThumb2SoReg, + kOperandTypeThumb2SoImm, + kOperandTypeThumb2AddrModeImm8, + kOperandTypeThumb2AddrModeImm8Offset, + kOperandTypeThumb2AddrModeImm12, + kOperandTypeThumb2AddrModeSoReg, + kOperandTypeThumb2AddrModeImm8s4, + kOperandTypeThumb2AddrModeImm8s4Offset +}; + +enum OperandFlags { + kOperandFlagSource = 0x1, + kOperandFlagTarget = 0x2 +}; + +enum InstructionTypes { + kInstructionTypeNone, + kInstructionTypeMove, + kInstructionTypeBranch, + kInstructionTypePush, + kInstructionTypePop, + kInstructionTypeCall, + kInstructionTypeReturn +}; + + +#endif diff --git a/lib/MC/MCDisassembler/EDInst.cpp b/lib/MC/MCDisassembler/EDInst.cpp new file mode 100644 index 0000000..e22408f --- /dev/null +++ b/lib/MC/MCDisassembler/EDInst.cpp @@ -0,0 +1,207 @@ +//===-EDInst.cpp - LLVM Enhanced Disassembler -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Enhanced Disassembly library's instruction class. +// The instruction is responsible for vending the string representation, +// individual tokens, and operands for a single instruction. +// +//===----------------------------------------------------------------------===// + +#include "EDInst.h" +#include "EDDisassembler.h" +#include "EDOperand.h" +#include "EDToken.h" + +#include "llvm/MC/EDInstInfo.h" +#include "llvm/MC/MCInst.h" + +using namespace llvm; + +EDInst::EDInst(llvm::MCInst *inst, + uint64_t byteSize, + EDDisassembler &disassembler, + const llvm::EDInstInfo *info) : + Disassembler(disassembler), + Inst(inst), + ThisInstInfo(info), + ByteSize(byteSize), + BranchTarget(-1), + MoveSource(-1), + MoveTarget(-1) { + OperandOrder = ThisInstInfo->operandOrders[Disassembler.llvmSyntaxVariant()]; +} + +EDInst::~EDInst() { + unsigned int index; + unsigned int numOperands = Operands.size(); + + for (index = 0; index < numOperands; ++index) + delete Operands[index]; + + unsigned int numTokens = Tokens.size(); + + for (index = 0; index < numTokens; ++index) + delete Tokens[index]; + + delete Inst; +} + +uint64_t EDInst::byteSize() { + return ByteSize; +} + +int EDInst::stringify() { + if (StringifyResult.valid()) + return StringifyResult.result(); + + if (Disassembler.printInst(String, *Inst)) + return StringifyResult.setResult(-1); + + return StringifyResult.setResult(0); +} + +int EDInst::getString(const char*& str) { + if (stringify()) + return -1; + + str = String.c_str(); + + return 0; +} + +unsigned EDInst::instID() { + return Inst->getOpcode(); +} + +bool EDInst::isBranch() { + if (ThisInstInfo) + return + ThisInstInfo->instructionType == kInstructionTypeBranch || + ThisInstInfo->instructionType == kInstructionTypeCall; + else + return false; +} + +bool EDInst::isMove() { + if (ThisInstInfo) + return ThisInstInfo->instructionType == kInstructionTypeMove; + else + return false; +} + +int EDInst::parseOperands() { + if (ParseResult.valid()) + return ParseResult.result(); + + if (!ThisInstInfo) + return ParseResult.setResult(-1); + + unsigned int opIndex; + unsigned int mcOpIndex = 0; + + for (opIndex = 0; opIndex < ThisInstInfo->numOperands; ++opIndex) { + if (isBranch() && + (ThisInstInfo->operandFlags[opIndex] & kOperandFlagTarget)) { + BranchTarget = opIndex; + } + else if (isMove()) { + if (ThisInstInfo->operandFlags[opIndex] & kOperandFlagSource) + MoveSource = opIndex; + else if (ThisInstInfo->operandFlags[opIndex] & kOperandFlagTarget) + MoveTarget = opIndex; + } + + EDOperand *operand = new EDOperand(Disassembler, *this, opIndex, mcOpIndex); + + Operands.push_back(operand); + } + + return ParseResult.setResult(0); +} + +int EDInst::branchTargetID() { + if (parseOperands()) + return -1; + return BranchTarget; +} + +int EDInst::moveSourceID() { + if (parseOperands()) + return -1; + return MoveSource; +} + +int EDInst::moveTargetID() { + if (parseOperands()) + return -1; + return MoveTarget; +} + +int EDInst::numOperands() { + if (parseOperands()) + return -1; + return Operands.size(); +} + +int EDInst::getOperand(EDOperand *&operand, unsigned int index) { + if (parseOperands()) + return -1; + + if (index >= Operands.size()) + return -1; + + operand = Operands[index]; + return 0; +} + +int EDInst::tokenize() { + if (TokenizeResult.valid()) + return TokenizeResult.result(); + + if (stringify()) + return TokenizeResult.setResult(-1); + + return TokenizeResult.setResult(EDToken::tokenize(Tokens, + String, + OperandOrder, + Disassembler)); + +} + +int EDInst::numTokens() { + if (tokenize()) + return -1; + return Tokens.size(); +} + +int EDInst::getToken(EDToken *&token, unsigned int index) { + if (tokenize()) + return -1; + token = Tokens[index]; + return 0; +} + +#ifdef __BLOCKS__ +int EDInst::visitTokens(EDTokenVisitor_t visitor) { + if (tokenize()) + return -1; + + tokvec_t::iterator iter; + + for (iter = Tokens.begin(); iter != Tokens.end(); ++iter) { + int ret = visitor(*iter); + if (ret == 1) + return 0; + if (ret != 0) + return -1; + } + + return 0; +} +#endif diff --git a/lib/MC/MCDisassembler/EDInst.h b/lib/MC/MCDisassembler/EDInst.h new file mode 100644 index 0000000..39d264f --- /dev/null +++ b/lib/MC/MCDisassembler/EDInst.h @@ -0,0 +1,182 @@ +//===-- EDInst.h - LLVM Enhanced Disassembler -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface for the Enhanced Disassembly library's +// instruction class. The instruction is responsible for vending the string +// representation, individual tokens and operands for a single instruction. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EDINST_H +#define LLVM_EDINST_H + +#include "llvm/System/DataTypes.h" +#include "llvm/ADT/SmallVector.h" +#include +#include + +namespace llvm { + class MCInst; + struct EDInstInfo; + struct EDToken; + struct EDDisassembler; + struct EDOperand; + +#ifdef __BLOCKS__ + typedef int (^EDTokenVisitor_t)(EDToken *token); +#endif + +/// CachedResult - Encapsulates the result of a function along with the validity +/// of that result, so that slow functions don't need to run twice +struct CachedResult { + /// True if the result has been obtained by executing the function + bool Valid; + /// The result last obtained from the function + int Result; + + /// Constructor - Initializes an invalid result + CachedResult() : Valid(false) { } + /// valid - Returns true if the result has been obtained by executing the + /// function and false otherwise + bool valid() { return Valid; } + /// result - Returns the result of the function or an undefined value if + /// valid() is false + int result() { return Result; } + /// setResult - Sets the result of the function and declares it valid + /// returning the result (so that setResult() can be called from inside a + /// return statement) + /// @arg result - The result of the function + int setResult(int result) { Result = result; Valid = true; return result; } +}; + +/// EDInst - Encapsulates a single instruction, which can be queried for its +/// string representation, as well as its operands and tokens +struct EDInst { + /// The parent disassembler + EDDisassembler &Disassembler; + /// The containing MCInst + llvm::MCInst *Inst; + /// The instruction information provided by TableGen for this instruction + const llvm::EDInstInfo *ThisInstInfo; + /// The number of bytes for the machine code representation of the instruction + uint64_t ByteSize; + + /// The result of the stringify() function + CachedResult StringifyResult; + /// The string representation of the instruction + std::string String; + /// The order in which operands from the InstInfo's operand information appear + /// in String + const char* OperandOrder; + + /// The result of the parseOperands() function + CachedResult ParseResult; + typedef llvm::SmallVector opvec_t; + /// The instruction's operands + opvec_t Operands; + /// The operand corresponding to the target, if the instruction is a branch + int BranchTarget; + /// The operand corresponding to the source, if the instruction is a move + int MoveSource; + /// The operand corresponding to the target, if the instruction is a move + int MoveTarget; + + /// The result of the tokenize() function + CachedResult TokenizeResult; + typedef std::vector tokvec_t; + /// The instruction's tokens + tokvec_t Tokens; + + /// Constructor - initializes an instruction given the output of the LLVM + /// C++ disassembler + /// + /// @arg inst - The MCInst, which will now be owned by this object + /// @arg byteSize - The size of the consumed instruction, in bytes + /// @arg disassembler - The parent disassembler + /// @arg instInfo - The instruction information produced by the table + /// generator for this instruction + EDInst(llvm::MCInst *inst, + uint64_t byteSize, + EDDisassembler &disassembler, + const llvm::EDInstInfo *instInfo); + ~EDInst(); + + /// byteSize - returns the number of bytes consumed by the machine code + /// representation of the instruction + uint64_t byteSize(); + /// instID - returns the LLVM instruction ID of the instruction + unsigned instID(); + + /// stringify - populates the String and AsmString members of the instruction, + /// returning 0 on success or -1 otherwise + int stringify(); + /// getString - retrieves a pointer to the string representation of the + /// instructinon, returning 0 on success or -1 otherwise + /// + /// @arg str - A reference to a pointer that, on success, is set to point to + /// the string representation of the instruction; this string is still owned + /// by the instruction and will be deleted when it is + int getString(const char *&str); + + /// isBranch - Returns true if the instruction is a branch + bool isBranch(); + /// isMove - Returns true if the instruction is a move + bool isMove(); + + /// parseOperands - populates the Operands member of the instruction, + /// returning 0 on success or -1 otherwise + int parseOperands(); + /// branchTargetID - returns the ID (suitable for use with getOperand()) of + /// the target operand if the instruction is a branch, or -1 otherwise + int branchTargetID(); + /// moveSourceID - returns the ID of the source operand if the instruction + /// is a move, or -1 otherwise + int moveSourceID(); + /// moveTargetID - returns the ID of the target operand if the instruction + /// is a move, or -1 otherwise + int moveTargetID(); + + /// numOperands - returns the number of operands available to retrieve, or -1 + /// on error + int numOperands(); + /// getOperand - retrieves an operand from the instruction's operand list by + /// index, returning 0 on success or -1 on error + /// + /// @arg operand - A reference whose target is pointed at the operand on + /// success, although the operand is still owned by the EDInst + /// @arg index - The index of the operand in the instruction + int getOperand(EDOperand *&operand, unsigned int index); + + /// tokenize - populates the Tokens member of the instruction, returning 0 on + /// success or -1 otherwise + int tokenize(); + /// numTokens - returns the number of tokens in the instruction, or -1 on + /// error + int numTokens(); + /// getToken - retrieves a token from the instruction's token list by index, + /// returning 0 on success or -1 on error + /// + /// @arg token - A reference whose target is pointed at the token on success, + /// although the token is still owned by the EDInst + /// @arg index - The index of the token in the instrcutino + int getToken(EDToken *&token, unsigned int index); + +#ifdef __BLOCKS__ + /// visitTokens - Visits each token in turn and applies a block to it, + /// returning 0 if all blocks are visited and/or the block signals + /// termination by returning 1; returns -1 on error + /// + /// @arg visitor - The visitor block to apply to all tokens. + int visitTokens(EDTokenVisitor_t visitor); +#endif +}; + +} // end namespace llvm + +#endif diff --git a/lib/MC/MCDisassembler/EDOperand.cpp b/lib/MC/MCDisassembler/EDOperand.cpp new file mode 100644 index 0000000..2aed123 --- /dev/null +++ b/lib/MC/MCDisassembler/EDOperand.cpp @@ -0,0 +1,282 @@ +//===-- EDOperand.cpp - LLVM Enhanced Disassembler ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Enhanced Disassembly library's operand class. The +// operand is responsible for allowing evaluation given a particular register +// context. +// +//===----------------------------------------------------------------------===// + +#include "EDOperand.h" +#include "EDDisassembler.h" +#include "EDInst.h" +#include "llvm/MC/EDInstInfo.h" +#include "llvm/MC/MCInst.h" +using namespace llvm; + +EDOperand::EDOperand(const EDDisassembler &disassembler, + const EDInst &inst, + unsigned int opIndex, + unsigned int &mcOpIndex) : + Disassembler(disassembler), + Inst(inst), + OpIndex(opIndex), + MCOpIndex(mcOpIndex) { + unsigned int numMCOperands = 0; + + if (Disassembler.Key.Arch == Triple::x86 || + Disassembler.Key.Arch == Triple::x86_64) { + uint8_t operandType = inst.ThisInstInfo->operandTypes[opIndex]; + + switch (operandType) { + default: + break; + case kOperandTypeImmediate: + numMCOperands = 1; + break; + case kOperandTypeRegister: + numMCOperands = 1; + break; + case kOperandTypeX86Memory: + numMCOperands = 5; + break; + case kOperandTypeX86EffectiveAddress: + numMCOperands = 4; + break; + case kOperandTypeX86PCRelative: + numMCOperands = 1; + break; + } + } + else if (Disassembler.Key.Arch == Triple::arm || + Disassembler.Key.Arch == Triple::thumb) { + uint8_t operandType = inst.ThisInstInfo->operandTypes[opIndex]; + + switch (operandType) { + default: + case kOperandTypeARMRegisterList: + break; + case kOperandTypeImmediate: + case kOperandTypeRegister: + case kOperandTypeARMBranchTarget: + case kOperandTypeARMSoImm: + case kOperandTypeThumb2SoImm: + case kOperandTypeARMSoImm2Part: + case kOperandTypeARMPredicate: + case kOperandTypeThumbITMask: + case kOperandTypeThumb2AddrModeImm8Offset: + case kOperandTypeARMTBAddrMode: + case kOperandTypeThumb2AddrModeImm8s4Offset: + numMCOperands = 1; + break; + case kOperandTypeThumb2SoReg: + case kOperandTypeARMAddrMode2Offset: + case kOperandTypeARMAddrMode3Offset: + case kOperandTypeARMAddrMode4: + case kOperandTypeARMAddrMode5: + case kOperandTypeARMAddrModePC: + case kOperandTypeThumb2AddrModeImm8: + case kOperandTypeThumb2AddrModeImm12: + case kOperandTypeThumb2AddrModeImm8s4: + case kOperandTypeThumbAddrModeRR: + case kOperandTypeThumbAddrModeSP: + numMCOperands = 2; + break; + case kOperandTypeARMSoReg: + case kOperandTypeARMAddrMode2: + case kOperandTypeARMAddrMode3: + case kOperandTypeThumb2AddrModeSoReg: + case kOperandTypeThumbAddrModeS1: + case kOperandTypeThumbAddrModeS2: + case kOperandTypeThumbAddrModeS4: + case kOperandTypeARMAddrMode6Offset: + numMCOperands = 3; + break; + case kOperandTypeARMAddrMode6: + numMCOperands = 4; + break; + } + } + + mcOpIndex += numMCOperands; +} + +EDOperand::~EDOperand() { +} + +int EDOperand::evaluate(uint64_t &result, + EDRegisterReaderCallback callback, + void *arg) { + uint8_t operandType = Inst.ThisInstInfo->operandTypes[OpIndex]; + + switch (Disassembler.Key.Arch) { + default: + return -1; + case Triple::x86: + case Triple::x86_64: + switch (operandType) { + default: + return -1; + case kOperandTypeImmediate: + result = Inst.Inst->getOperand(MCOpIndex).getImm(); + return 0; + case kOperandTypeRegister: + { + unsigned reg = Inst.Inst->getOperand(MCOpIndex).getReg(); + return callback(&result, reg, arg); + } + case kOperandTypeX86PCRelative: + { + int64_t displacement = Inst.Inst->getOperand(MCOpIndex).getImm(); + + uint64_t ripVal; + + // TODO fix how we do this + + if (callback(&ripVal, Disassembler.registerIDWithName("RIP"), arg)) + return -1; + + result = ripVal + displacement; + return 0; + } + case kOperandTypeX86Memory: + case kOperandTypeX86EffectiveAddress: + { + unsigned baseReg = Inst.Inst->getOperand(MCOpIndex).getReg(); + uint64_t scaleAmount = Inst.Inst->getOperand(MCOpIndex+1).getImm(); + unsigned indexReg = Inst.Inst->getOperand(MCOpIndex+2).getReg(); + int64_t displacement = Inst.Inst->getOperand(MCOpIndex+3).getImm(); + //unsigned segmentReg = Inst.Inst->getOperand(MCOpIndex+4).getReg(); + + uint64_t addr = 0; + + if (baseReg) { + uint64_t baseVal; + if (callback(&baseVal, baseReg, arg)) + return -1; + addr += baseVal; + } + + if (indexReg) { + uint64_t indexVal; + if (callback(&indexVal, indexReg, arg)) + return -1; + addr += (scaleAmount * indexVal); + } + + addr += displacement; + + result = addr; + return 0; + } + } + break; + case Triple::arm: + case Triple::thumb: + switch (operandType) { + default: + return -1; + case kOperandTypeImmediate: + result = Inst.Inst->getOperand(MCOpIndex).getImm(); + return 0; + case kOperandTypeRegister: + { + unsigned reg = Inst.Inst->getOperand(MCOpIndex).getReg(); + return callback(&result, reg, arg); + } + case kOperandTypeARMBranchTarget: + { + int64_t displacement = Inst.Inst->getOperand(MCOpIndex).getImm(); + + uint64_t pcVal; + + if (callback(&pcVal, Disassembler.registerIDWithName("PC"), arg)) + return -1; + + result = pcVal + displacement; + return 0; + } + } + } + + return -1; +} + +int EDOperand::isRegister() { + return(Inst.ThisInstInfo->operandFlags[OpIndex] == kOperandTypeRegister); +} + +unsigned EDOperand::regVal() { + return Inst.Inst->getOperand(MCOpIndex).getReg(); +} + +int EDOperand::isImmediate() { + return(Inst.ThisInstInfo->operandFlags[OpIndex] == kOperandTypeImmediate); +} + +uint64_t EDOperand::immediateVal() { + return Inst.Inst->getOperand(MCOpIndex).getImm(); +} + +int EDOperand::isMemory() { + uint8_t operandType = Inst.ThisInstInfo->operandTypes[OpIndex]; + + switch (operandType) { + default: + return 0; + case kOperandTypeX86Memory: + case kOperandTypeX86PCRelative: + case kOperandTypeX86EffectiveAddress: + case kOperandTypeARMSoReg: + case kOperandTypeARMSoImm: + case kOperandTypeARMAddrMode2: + case kOperandTypeARMAddrMode2Offset: + case kOperandTypeARMAddrMode3: + case kOperandTypeARMAddrMode3Offset: + case kOperandTypeARMAddrMode4: + case kOperandTypeARMAddrMode5: + case kOperandTypeARMAddrMode6: + case kOperandTypeARMAddrModePC: + case kOperandTypeARMBranchTarget: + case kOperandTypeThumbAddrModeS1: + case kOperandTypeThumbAddrModeS2: + case kOperandTypeThumbAddrModeS4: + case kOperandTypeThumbAddrModeRR: + case kOperandTypeThumbAddrModeSP: + case kOperandTypeThumb2SoImm: + case kOperandTypeThumb2AddrModeImm8: + case kOperandTypeThumb2AddrModeImm8Offset: + case kOperandTypeThumb2AddrModeImm12: + case kOperandTypeThumb2AddrModeSoReg: + case kOperandTypeThumb2AddrModeImm8s4: + return 1; + } +} + +#ifdef __BLOCKS__ +struct RegisterReaderWrapper { + EDOperand::EDRegisterBlock_t regBlock; +}; + +int readerWrapperCallback(uint64_t *value, + unsigned regID, + void *arg) { + struct RegisterReaderWrapper *wrapper = (struct RegisterReaderWrapper *)arg; + return wrapper->regBlock(value, regID); +} + +int EDOperand::evaluate(uint64_t &result, + EDRegisterBlock_t regBlock) { + struct RegisterReaderWrapper wrapper; + wrapper.regBlock = regBlock; + return evaluate(result, + readerWrapperCallback, + (void*)&wrapper); +} +#endif diff --git a/lib/MC/MCDisassembler/EDOperand.h b/lib/MC/MCDisassembler/EDOperand.h new file mode 100644 index 0000000..6e69522 --- /dev/null +++ b/lib/MC/MCDisassembler/EDOperand.h @@ -0,0 +1,91 @@ +//===-EDOperand.h - LLVM Enhanced Disassembler ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface for the Enhanced Disassembly library's +// operand class. The operand is responsible for allowing evaluation given a +// particular register context. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EDOPERAND_H +#define LLVM_EDOPERAND_H + +#include "llvm/System/DataTypes.h" + +namespace llvm { + +struct EDDisassembler; +struct EDInst; + +typedef int (*EDRegisterReaderCallback)(uint64_t *value, unsigned regID, + void* arg); + + +/// EDOperand - Encapsulates a single operand, which can be evaluated by the +/// client +struct EDOperand { + /// The parent disassembler + const EDDisassembler &Disassembler; + /// The parent instruction + const EDInst &Inst; + + /// The index of the operand in the EDInst + unsigned int OpIndex; + /// The index of the first component of the operand in the MCInst + unsigned int MCOpIndex; + + /// Constructor - Initializes an EDOperand + /// + /// @arg disassembler - The disassembler responsible for the operand + /// @arg inst - The instruction containing this operand + /// @arg opIndex - The index of the operand in inst + /// @arg mcOpIndex - The index of the operand in the original MCInst + EDOperand(const EDDisassembler &disassembler, + const EDInst &inst, + unsigned int opIndex, + unsigned int &mcOpIndex); + ~EDOperand(); + + /// evaluate - Returns the numeric value of an operand to the extent possible, + /// returning 0 on success or -1 if there was some problem (such as a + /// register not being readable) + /// + /// @arg result - A reference whose target is filled in with the value of + /// the operand (the address if it is a memory operand) + /// @arg callback - A function to call to obtain register values + /// @arg arg - An opaque argument to pass to callback + int evaluate(uint64_t &result, + EDRegisterReaderCallback callback, + void *arg); + + /// isRegister - Returns 1 if the operand is a register or 0 otherwise + int isRegister(); + /// regVal - Returns the register value. + unsigned regVal(); + + /// isImmediate - Returns 1 if the operand is an immediate or 0 otherwise + int isImmediate(); + /// immediateVal - Returns the immediate value. + uint64_t immediateVal(); + + /// isMemory - Returns 1 if the operand is a memory location or 0 otherwise + int isMemory(); + +#ifdef __BLOCKS__ + typedef int (^EDRegisterBlock_t)(uint64_t *value, unsigned regID); + + /// evaluate - Like evaluate for a callback, but uses a block instead + int evaluate(uint64_t &result, + EDRegisterBlock_t regBlock); +#endif +}; + +} // end namespace llvm + +#endif diff --git a/lib/MC/MCDisassembler/EDToken.cpp b/lib/MC/MCDisassembler/EDToken.cpp new file mode 100644 index 0000000..400e164 --- /dev/null +++ b/lib/MC/MCDisassembler/EDToken.cpp @@ -0,0 +1,206 @@ +//===-- EDToken.cpp - LLVM Enhanced Disassembler --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Enhanced Disassembler library's token class. The +// token is responsible for vending information about the token, such as its +// type and logical value. +// +//===----------------------------------------------------------------------===// + +#include "EDToken.h" +#include "EDDisassembler.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/ADT/SmallVector.h" +using namespace llvm; + +EDToken::EDToken(StringRef str, + enum tokenType type, + uint64_t localType, + EDDisassembler &disassembler) : + Disassembler(disassembler), + Str(str), + Type(type), + LocalType(localType), + OperandID(-1) { +} + +EDToken::~EDToken() { +} + +void EDToken::makeLiteral(bool sign, uint64_t absoluteValue) { + Type = kTokenLiteral; + LiteralSign = sign; + LiteralAbsoluteValue = absoluteValue; +} + +void EDToken::makeRegister(unsigned registerID) { + Type = kTokenRegister; + RegisterID = registerID; +} + +void EDToken::setOperandID(int operandID) { + OperandID = operandID; +} + +enum EDToken::tokenType EDToken::type() const { + return Type; +} + +uint64_t EDToken::localType() const { + return LocalType; +} + +StringRef EDToken::string() const { + return Str; +} + +int EDToken::operandID() const { + return OperandID; +} + +int EDToken::literalSign() const { + if (Type != kTokenLiteral) + return -1; + return (LiteralSign ? 1 : 0); +} + +int EDToken::literalAbsoluteValue(uint64_t &value) const { + if (Type != kTokenLiteral) + return -1; + value = LiteralAbsoluteValue; + return 0; +} + +int EDToken::registerID(unsigned ®isterID) const { + if (Type != kTokenRegister) + return -1; + registerID = RegisterID; + return 0; +} + +int EDToken::tokenize(std::vector &tokens, + std::string &str, + const char *operandOrder, + EDDisassembler &disassembler) { + SmallVector parsedOperands; + SmallVector asmTokens; + + if (disassembler.parseInst(parsedOperands, asmTokens, str)) + return -1; + + SmallVectorImpl::iterator operandIterator; + unsigned int operandIndex; + SmallVectorImpl::iterator tokenIterator; + + operandIterator = parsedOperands.begin(); + operandIndex = 0; + + bool readOpcode = false; + + const char *wsPointer = asmTokens.begin()->getLoc().getPointer(); + + for (tokenIterator = asmTokens.begin(); + tokenIterator != asmTokens.end(); + ++tokenIterator) { + SMLoc tokenLoc = tokenIterator->getLoc(); + + const char *tokenPointer = tokenLoc.getPointer(); + + if (tokenPointer > wsPointer) { + unsigned long wsLength = tokenPointer - wsPointer; + + EDToken *whitespaceToken = new EDToken(StringRef(wsPointer, wsLength), + EDToken::kTokenWhitespace, + 0, + disassembler); + + tokens.push_back(whitespaceToken); + } + + wsPointer = tokenPointer + tokenIterator->getString().size(); + + while (operandIterator != parsedOperands.end() && + tokenLoc.getPointer() > + (*operandIterator)->getEndLoc().getPointer()) { + ++operandIterator; + ++operandIndex; + } + + EDToken *token; + + switch (tokenIterator->getKind()) { + case AsmToken::Identifier: + if (!readOpcode) { + token = new EDToken(tokenIterator->getString(), + EDToken::kTokenOpcode, + (uint64_t)tokenIterator->getKind(), + disassembler); + readOpcode = true; + break; + } + // any identifier that isn't an opcode is mere punctuation; so we fall + // through + default: + token = new EDToken(tokenIterator->getString(), + EDToken::kTokenPunctuation, + (uint64_t)tokenIterator->getKind(), + disassembler); + break; + case AsmToken::Integer: + { + token = new EDToken(tokenIterator->getString(), + EDToken::kTokenLiteral, + (uint64_t)tokenIterator->getKind(), + disassembler); + + int64_t intVal = tokenIterator->getIntVal(); + + if (intVal < 0) + token->makeLiteral(true, -intVal); + else + token->makeLiteral(false, intVal); + break; + } + case AsmToken::Register: + { + token = new EDToken(tokenIterator->getString(), + EDToken::kTokenLiteral, + (uint64_t)tokenIterator->getKind(), + disassembler); + + token->makeRegister((unsigned)tokenIterator->getRegVal()); + break; + } + } + + if (operandIterator != parsedOperands.end() && + tokenLoc.getPointer() >= + (*operandIterator)->getStartLoc().getPointer()) { + /// operandIndex == 0 means the operand is the instruction (which the + /// AsmParser treats as an operand but edis does not). We therefore skip + /// operandIndex == 0 and subtract 1 from all other operand indices. + + if (operandIndex > 0) + token->setOperandID(operandOrder[operandIndex - 1]); + } + + tokens.push_back(token); + } + + return 0; +} + +int EDToken::getString(const char*& buf) { + if (PermStr.length() == 0) { + PermStr = Str.str(); + } + buf = PermStr.c_str(); + return 0; +} diff --git a/lib/MC/MCDisassembler/EDToken.h b/lib/MC/MCDisassembler/EDToken.h new file mode 100644 index 0000000..6b2aeac --- /dev/null +++ b/lib/MC/MCDisassembler/EDToken.h @@ -0,0 +1,139 @@ +//===-EDToken.h - LLVM Enhanced Disassembler --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface for the Enhanced Disassembly library's token +// class. The token is responsible for vending information about the token, +// such as its type and logical value. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EDTOKEN_H +#define LLVM_EDTOKEN_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/System/DataTypes.h" +#include +#include + +namespace llvm { + +struct EDDisassembler; + +/// EDToken - Encapsulates a single token, which can provide a string +/// representation of itself or interpret itself in various ways, depending +/// on the token type. +struct EDToken { + enum tokenType { + kTokenWhitespace, + kTokenOpcode, + kTokenLiteral, + kTokenRegister, + kTokenPunctuation + }; + + /// The parent disassembler + EDDisassembler &Disassembler; + + /// The token's string representation + llvm::StringRef Str; + /// The token's string representation, but in a form suitable for export + std::string PermStr; + /// The type of the token, as exposed through the external API + enum tokenType Type; + /// The type of the token, as recorded by the syntax-specific tokenizer + uint64_t LocalType; + /// The operand corresponding to the token, or (unsigned int)-1 if not + /// part of an operand. + int OperandID; + + /// The sign if the token is a literal (1 if negative, 0 otherwise) + bool LiteralSign; + /// The absolute value if the token is a literal + uint64_t LiteralAbsoluteValue; + /// The LLVM register ID if the token is a register name + unsigned RegisterID; + + /// Constructor - Initializes an EDToken with the information common to all + /// tokens + /// + /// @arg str - The string corresponding to the token + /// @arg type - The token's type as exposed through the public API + /// @arg localType - The token's type as recorded by the tokenizer + /// @arg disassembler - The disassembler responsible for the token + EDToken(llvm::StringRef str, + enum tokenType type, + uint64_t localType, + EDDisassembler &disassembler); + + /// makeLiteral - Adds the information specific to a literal + /// @arg sign - The sign of the literal (1 if negative, 0 + /// otherwise) + /// + /// @arg absoluteValue - The absolute value of the literal + void makeLiteral(bool sign, uint64_t absoluteValue); + /// makeRegister - Adds the information specific to a register + /// + /// @arg registerID - The LLVM register ID + void makeRegister(unsigned registerID); + + /// setOperandID - Links the token to a numbered operand + /// + /// @arg operandID - The operand ID to link to + void setOperandID(int operandID); + + ~EDToken(); + + /// type - Returns the public type of the token + enum tokenType type() const; + /// localType - Returns the tokenizer-specific type of the token + uint64_t localType() const; + /// string - Returns the string representation of the token + llvm::StringRef string() const; + /// operandID - Returns the operand ID of the token + int operandID() const; + + /// literalSign - Returns the sign of the token + /// (1 if negative, 0 if positive or unsigned, -1 if it is not a literal) + int literalSign() const; + /// literalAbsoluteValue - Retrieves the absolute value of the token, and + /// returns -1 if the token is not a literal + /// @arg value - A reference to a value that is filled in with the absolute + /// value, if it is valid + int literalAbsoluteValue(uint64_t &value) const; + /// registerID - Retrieves the register ID of the token, and returns -1 if the + /// token is not a register + /// + /// @arg registerID - A reference to a value that is filled in with the + /// register ID, if it is valid + int registerID(unsigned ®isterID) const; + + /// tokenize - Tokenizes a string using the platform- and syntax-specific + /// tokenizer, and returns 0 on success (-1 on failure) + /// + /// @arg tokens - A vector that will be filled in with pointers to + /// allocated tokens + /// @arg str - The string, as outputted by the AsmPrinter + /// @arg operandOrder - The order of the operands from the operandFlags array + /// as they appear in str + /// @arg disassembler - The disassembler for the desired target and + // assembly syntax + static int tokenize(std::vector &tokens, + std::string &str, + const char *operandOrder, + EDDisassembler &disassembler); + + /// getString - Directs a character pointer to the string, returning 0 on + /// success (-1 on failure) + /// @arg buf - A reference to a pointer that is set to point to the string. + /// The string is still owned by the token. + int getString(const char*& buf); +}; + +} // end namespace llvm +#endif diff --git a/lib/MC/MCDisassembler/Makefile b/lib/MC/MCDisassembler/Makefile new file mode 100644 index 0000000..7d71cd3 --- /dev/null +++ b/lib/MC/MCDisassembler/Makefile @@ -0,0 +1,14 @@ +##===- lib/MC/MCDisassembler/Makefile ----------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME = LLVMMCDisassembler + +include $(LEVEL)/Makefile.common + diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp new file mode 100644 index 0000000..2da71f9 --- /dev/null +++ b/lib/MC/MCDwarf.cpp @@ -0,0 +1,21 @@ +//===- lib/MC/MCDwarf.cpp - MCDwarf implementation ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCDwarf.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +void MCDwarfFile::print(raw_ostream &OS) const { + OS << '"' << getName() << '"'; +} + +void MCDwarfFile::dump() const { + print(dbgs()); +} diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp new file mode 100644 index 0000000..570c391 --- /dev/null +++ b/lib/MC/MCELFStreamer.cpp @@ -0,0 +1,408 @@ +//===- lib/MC/MCELFStreamer.cpp - ELF Object Output ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file assembles .s files and emits ELF .o object files. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCStreamer.h" + +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCELFSymbolFlags.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetAsmBackend.h" + +using namespace llvm; + +namespace { + +class MCELFStreamer : public MCObjectStreamer { + void EmitInstToFragment(const MCInst &Inst); + void EmitInstToData(const MCInst &Inst); +public: + MCELFStreamer(MCContext &Context, TargetAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *Emitter) + : MCObjectStreamer(Context, TAB, OS, Emitter) {} + + ~MCELFStreamer() {} + + /// @name MCStreamer Interface + /// @{ + + virtual void EmitLabel(MCSymbol *Symbol); + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + assert(0 && "ELF doesn't support this directive"); + } + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); + virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) { + assert(0 && "ELF doesn't support this directive"); + } + + virtual void EmitCOFFSymbolStorageClass(int StorageClass) { + assert(0 && "ELF doesn't support this directive"); + } + + virtual void EmitCOFFSymbolType(int Type) { + assert(0 && "ELF doesn't support this directive"); + } + + virtual void EndCOFFSymbolDef() { + assert(0 && "ELF doesn't support this directive"); + } + + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SD.setSize(Value); + } + + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + assert(0 && "ELF doesn't support this directive"); + } + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, + unsigned Size = 0, unsigned ByteAlignment = 0) { + assert(0 && "ELF doesn't support this directive"); + } + virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment = 0) { + assert(0 && "ELF doesn't support this directive"); + } + virtual void EmitBytes(StringRef Data, unsigned AddrSpace); + virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace); + virtual void EmitGPRel32Value(const MCExpr *Value) { + assert(0 && "ELF doesn't support this directive"); + } + virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, + unsigned ValueSize = 1, + unsigned MaxBytesToEmit = 0); + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit = 0); + virtual void EmitValueToOffset(const MCExpr *Offset, + unsigned char Value = 0); + + virtual void EmitFileDirective(StringRef Filename); + virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { + DEBUG(dbgs() << "FIXME: MCELFStreamer:EmitDwarfFileDirective not implemented\n"); + } + + virtual void EmitInstruction(const MCInst &Inst); + virtual void Finish(); + + /// @} +}; + +} // end anonymous namespace. + +void MCELFStreamer::EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + + // FIXME: This is wasteful, we don't necessarily need to create a data + // fragment. Instead, we should mark the symbol as pointing into the data + // fragment if it exists, otherwise we should just queue the label and set its + // fragment pointer when we emit the next fragment. + MCDataFragment *F = getOrCreateDataFragment(); + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); + SD.setFragment(F); + SD.setOffset(F->getContents().size()); + + Symbol->setSection(*CurSection); +} + +void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { + switch (Flag) { + case MCAF_SubsectionsViaSymbols: + getAssembler().setSubsectionsViaSymbols(true); + return; + } + + assert(0 && "invalid assembler flag!"); +} + +void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + // FIXME: Lift context changes into super class. + getAssembler().getOrCreateSymbolData(*Symbol); + Symbol->setVariableValue(AddValueSymbols(Value)); +} + +void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, + MCSymbolAttr Attribute) { + // Indirect symbols are handled differently, to match how 'as' handles + // them. This makes writing matching .o files easier. + if (Attribute == MCSA_IndirectSymbol) { + // Note that we intentionally cannot use the symbol data here; this is + // important for matching the string table that 'as' generates. + IndirectSymbolData ISD; + ISD.Symbol = Symbol; + ISD.SectionData = getCurrentSectionData(); + getAssembler().getIndirectSymbols().push_back(ISD); + return; + } + + // Adding a symbol attribute always introduces the symbol, note that an + // important side effect of calling getOrCreateSymbolData here is to register + // the symbol with the assembler. + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + // The implementation of symbol attributes is designed to match 'as', but it + // leaves much to desired. It doesn't really make sense to arbitrarily add and + // remove flags, but 'as' allows this (in particular, see .desc). + // + // In the future it might be worth trying to make these operations more well + // defined. + switch (Attribute) { + case MCSA_LazyReference: + case MCSA_Reference: + case MCSA_NoDeadStrip: + case MCSA_PrivateExtern: + case MCSA_WeakDefinition: + case MCSA_WeakDefAutoPrivate: + case MCSA_Invalid: + case MCSA_ELF_TypeIndFunction: + case MCSA_IndirectSymbol: + assert(0 && "Invalid symbol attribute for ELF!"); + break; + + case MCSA_Global: + SD.setFlags(SD.getFlags() | ELF_STB_Global); + SD.setExternal(true); + break; + + case MCSA_WeakReference: + case MCSA_Weak: + SD.setFlags(SD.getFlags() | ELF_STB_Weak); + break; + + case MCSA_Local: + SD.setFlags(SD.getFlags() | ELF_STB_Local); + break; + + case MCSA_ELF_TypeFunction: + SD.setFlags(SD.getFlags() | ELF_STT_Func); + break; + + case MCSA_ELF_TypeObject: + SD.setFlags(SD.getFlags() | ELF_STT_Object); + break; + + case MCSA_ELF_TypeTLS: + SD.setFlags(SD.getFlags() | ELF_STT_Tls); + break; + + case MCSA_ELF_TypeCommon: + SD.setFlags(SD.getFlags() | ELF_STT_Common); + break; + + case MCSA_ELF_TypeNoType: + SD.setFlags(SD.getFlags() | ELF_STT_Notype); + break; + + case MCSA_Protected: + SD.setFlags(SD.getFlags() | ELF_STV_Protected); + break; + + case MCSA_Hidden: + SD.setFlags(SD.getFlags() | ELF_STV_Hidden); + break; + + case MCSA_Internal: + SD.setFlags(SD.getFlags() | ELF_STV_Internal); + break; + } +} + +void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + if ((SD.getFlags() & (0xf << ELF_STB_Shift)) == ELF_STB_Local) { + const MCSection *Section = getAssembler().getContext().getELFSection(".bss", + MCSectionELF::SHT_NOBITS, + MCSectionELF::SHF_WRITE | + MCSectionELF::SHF_ALLOC, + SectionKind::getBSS()); + + MCSectionData &SectData = getAssembler().getOrCreateSectionData(*Section); + MCFragment *F = new MCFillFragment(0, 0, Size, &SectData); + SD.setFragment(F); + Symbol->setSection(*Section); + SD.setSize(MCConstantExpr::Create(Size, getContext())); + } + + SD.setFlags(SD.getFlags() | ELF_STB_Global); + SD.setExternal(true); + + SD.setCommon(Size, ByteAlignment); +} + +void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); +} + +void MCELFStreamer::EmitValue(const MCExpr *Value, unsigned Size, + unsigned AddrSpace) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + MCDataFragment *DF = getOrCreateDataFragment(); + + // Avoid fixups when possible. + int64_t AbsValue; + if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue)) { + // FIXME: Endianness assumption. + for (unsigned i = 0; i != Size; ++i) + DF->getContents().push_back(uint8_t(AbsValue >> (i * 8))); + } else { + DF->addFixup(MCFixup::Create(DF->getContents().size(), AddValueSymbols(Value), + MCFixup::getKindForSize(Size))); + DF->getContents().resize(DF->getContents().size() + Size, 0); + } +} + +void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment, + int64_t Value, unsigned ValueSize, + unsigned MaxBytesToEmit) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit, + getCurrentSectionData()); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); +} + +void MCELFStreamer::EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + MCAlignFragment *F = new MCAlignFragment(ByteAlignment, 0, 1, MaxBytesToEmit, + getCurrentSectionData()); + F->setEmitNops(true); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); +} + +void MCELFStreamer::EmitValueToOffset(const MCExpr *Offset, + unsigned char Value) { + // TODO: This is exactly the same as MCMachOStreamer. Consider merging into + // MCObjectStreamer. + new MCOrgFragment(*Offset, Value, getCurrentSectionData()); +} + +// Add a symbol for the file name of this module. This is the second +// entry in the module's symbol table (the first being the null symbol). +void MCELFStreamer::EmitFileDirective(StringRef Filename) { + MCSymbol *Symbol = getAssembler().getContext().GetOrCreateSymbol(Filename); + Symbol->setSection(*CurSection); + Symbol->setAbsolute(); + + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + SD.setFlags(ELF_STT_File | ELF_STB_Local | ELF_STV_Default); +} + +void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) { + MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData()); + + // Add the fixups and data. + // + // FIXME: Revisit this design decision when relaxation is done, we may be + // able to get away with not storing any extra data in the MCInst. + SmallVector Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); + VecOS.flush(); + + IF->getCode() = Code; + IF->getFixups() = Fixups; +} + +void MCELFStreamer::EmitInstToData(const MCInst &Inst) { + MCDataFragment *DF = getOrCreateDataFragment(); + + SmallVector Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); + VecOS.flush(); + + // Add the fixups and data. + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { + Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); + DF->addFixup(Fixups[i]); + } + DF->getContents().append(Code.begin(), Code.end()); +} + +void MCELFStreamer::EmitInstruction(const MCInst &Inst) { + // Scan for values. + for (unsigned i = 0; i != Inst.getNumOperands(); ++i) + if (Inst.getOperand(i).isExpr()) + AddValueSymbols(Inst.getOperand(i).getExpr()); + + getCurrentSectionData()->setHasInstructions(true); + + // If this instruction doesn't need relaxation, just emit it as data. + if (!getAssembler().getBackend().MayNeedRelaxation(Inst)) { + EmitInstToData(Inst); + return; + } + + // Otherwise, if we are relaxing everything, relax the instruction as much as + // possible and emit it as data. + if (getAssembler().getRelaxAll()) { + MCInst Relaxed; + getAssembler().getBackend().RelaxInstruction(Inst, Relaxed); + while (getAssembler().getBackend().MayNeedRelaxation(Relaxed)) + getAssembler().getBackend().RelaxInstruction(Relaxed, Relaxed); + EmitInstToData(Relaxed); + return; + } + + // Otherwise emit to a separate fragment. + EmitInstToFragment(Inst); +} + +void MCELFStreamer::Finish() { + getAssembler().Finish(); +} + +MCStreamer *llvm::createELFStreamer(MCContext &Context, TargetAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *CE, + bool RelaxAll) { + MCELFStreamer *S = new MCELFStreamer(Context, TAB, OS, CE); + if (RelaxAll) + S->getAssembler().setRelaxAll(true); + return S; +} diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 44bc267..671874d 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -18,6 +18,8 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCMachOSymbolFlags.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmBackend.h" @@ -28,58 +30,19 @@ namespace { class MCMachOStreamer : public MCObjectStreamer { private: - MCFragment *getCurrentFragment() const { - assert(getCurrentSectionData() && "No current section!"); - - if (!getCurrentSectionData()->empty()) - return &getCurrentSectionData()->getFragmentList().back(); - - return 0; - } - - /// Get a data fragment to write into, creating a new one if the current - /// fragment is not a data fragment. - MCDataFragment *getOrCreateDataFragment() const { - MCDataFragment *F = dyn_cast_or_null(getCurrentFragment()); - if (!F) - F = new MCDataFragment(getCurrentSectionData()); - return F; - } - void EmitInstToFragment(const MCInst &Inst); void EmitInstToData(const MCInst &Inst); + // FIXME: These will likely moved to a better place. + void MakeLineEntryForSection(const MCSection *Section); + const MCExpr * MakeStartMinusEndExpr(MCSymbol *Start, MCSymbol *End, + int IntVal); + void EmitDwarfFileTable(void); public: MCMachOStreamer(MCContext &Context, TargetAsmBackend &TAB, raw_ostream &OS, MCCodeEmitter *Emitter) : MCObjectStreamer(Context, TAB, OS, Emitter) {} - const MCExpr *AddValueSymbols(const MCExpr *Value) { - switch (Value->getKind()) { - case MCExpr::Target: assert(0 && "Can't handle target exprs yet!"); - case MCExpr::Constant: - break; - - case MCExpr::Binary: { - const MCBinaryExpr *BE = cast(Value); - AddValueSymbols(BE->getLHS()); - AddValueSymbols(BE->getRHS()); - break; - } - - case MCExpr::SymbolRef: - getAssembler().getOrCreateSymbolData( - cast(Value)->getSymbol()); - break; - - case MCExpr::Unary: - AddValueSymbols(cast(Value)->getSubExpr()); - break; - } - - return Value; - } - /// @name MCStreamer Interface /// @{ @@ -126,10 +89,16 @@ public: unsigned char Value = 0); virtual void EmitFileDirective(StringRef Filename) { - report_fatal_error("unsupported directive: '.file'"); + // FIXME: Just ignore the .file; it isn't important enough to fail the + // entire assembly. + + //report_fatal_error("unsupported directive: '.file'"); } virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { - report_fatal_error("unsupported directive: '.file'"); + // FIXME: Just ignore the .file; it isn't important enough to fail the + // entire assembly. + + //report_fatal_error("unsupported directive: '.file'"); } virtual void EmitInstruction(const MCInst &Inst); @@ -142,6 +111,8 @@ public: } // end anonymous namespace. void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { + // TODO: This is almost exactly the same as WinCOFFStreamer. Consider merging + // into MCObjectStreamer. assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); assert(CurSection && "Cannot emit before setting section!"); @@ -185,6 +156,8 @@ void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { } void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. // FIXME: Lift context changes into super class. getAssembler().getOrCreateSymbolData(*Symbol); Symbol->setVariableValue(AddValueSymbols(Value)); @@ -335,11 +308,15 @@ void MCMachOStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, } void MCMachOStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); } void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size, unsigned AddrSpace) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. MCDataFragment *DF = getOrCreateDataFragment(); // Avoid fixups when possible. @@ -359,6 +336,8 @@ void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size, void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. if (MaxBytesToEmit == 0) MaxBytesToEmit = ByteAlignment; new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit, @@ -371,6 +350,8 @@ void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment, void MCMachOStreamer::EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. if (MaxBytesToEmit == 0) MaxBytesToEmit = ByteAlignment; MCAlignFragment *F = new MCAlignFragment(ByteAlignment, 0, 1, MaxBytesToEmit, @@ -429,6 +410,10 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { getCurrentSectionData()->setHasInstructions(true); + // Now that a machine instruction has been assembled into this section, make + // a line entry for any .loc directive that has been seen. + MakeLineEntryForSection(getCurrentSection()); + // If this instruction doesn't need relaxation, just emit it as data. if (!getAssembler().getBackend().MayNeedRelaxation(Inst)) { EmitInstToData(Inst); @@ -450,7 +435,207 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { EmitInstToFragment(Inst); } +// +// This is called when an instruction is assembled into the specified section +// and if there is information from the last .loc directive that has yet to have +// a line entry made for it is made. +// +void MCMachOStreamer::MakeLineEntryForSection(const MCSection *Section) { + if (!getContext().getDwarfLocSeen()) + return; + + // Create a symbol at in the current section for use in the line entry. + MCSymbol *LineSym = getContext().CreateTempSymbol(); + // Set the value of the symbol to use for the MCLineEntry. + EmitLabel(LineSym); + + // Get the current .loc info saved in the context. + const MCDwarfLoc &DwarfLoc = getContext().getCurrentDwarfLoc(); + + // Create a (local) line entry with the symbol and the current .loc info. + MCLineEntry LineEntry(LineSym, DwarfLoc); + + // clear DwarfLocSeen saying the current .loc info is now used. + getContext().clearDwarfLocSeen(); + + // Get the MCLineSection for this section, if one does not exist for this + // section create it. + DenseMap &MCLineSections = + getContext().getMCLineSections(); + MCLineSection *LineSection = MCLineSections[Section]; + if (!LineSection) { + // Create a new MCLineSection. This will be deleted after the dwarf line + // table is created using it by iterating through the MCLineSections + // DenseMap. + LineSection = new MCLineSection; + // Save a pointer to the new LineSection into the MCLineSections DenseMap. + MCLineSections[Section] = LineSection; + } + + // Add the line entry to this section's entries. + LineSection->addLineEntry(LineEntry); +} + +// +// This helper routine returns an expression of End - Start + IntVal for use +// by EmitDwarfFileTable() below. +// +const MCExpr * MCMachOStreamer::MakeStartMinusEndExpr(MCSymbol *Start, + MCSymbol *End, + int IntVal) { + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + const MCExpr *Res = + MCSymbolRefExpr::Create(End, Variant, getContext()); + const MCExpr *RHS = + MCSymbolRefExpr::Create(Start, Variant, getContext()); + const MCExpr *Res1 = + MCBinaryExpr::Create(MCBinaryExpr::Sub, Res, RHS,getContext()); + const MCExpr *Res2 = + MCConstantExpr::Create(IntVal, getContext()); + const MCExpr *Res3 = + MCBinaryExpr::Create(MCBinaryExpr::Sub, Res1, Res2, getContext()); + return Res3; +} + +// +// This emits the Dwarf file (and eventually the line) table. +// +void MCMachOStreamer::EmitDwarfFileTable(void) { + // For now make sure we don't put out the Dwarf file table if no .file + // directives were seen. + const std::vector &MCDwarfFiles = + getContext().getMCDwarfFiles(); + if (MCDwarfFiles.size() == 0) + return; + + // This is the Mach-O section, for ELF it is the .debug_line section. + SwitchSection(getContext().getMachOSection("__DWARF", "__debug_line", + MCSectionMachO::S_ATTR_DEBUG, + 0, SectionKind::getDataRelLocal())); + + // Create a symbol at the beginning of this section. + MCSymbol *LineStartSym = getContext().CreateTempSymbol(); + // Set the value of the symbol, as we are at the start of the section. + EmitLabel(LineStartSym); + + // Create a symbol for the end of the section (to be set when we get there). + MCSymbol *LineEndSym = getContext().CreateTempSymbol(); + + // The first 4 bytes is the total length of the information for this + // compilation unit (not including these 4 bytes for the length). + EmitValue(MakeStartMinusEndExpr(LineStartSym, LineEndSym, 4), 4, 0); + + // Next 2 bytes is the Version, which is Dwarf 2. + EmitIntValue(2, 2); + + // Create a symbol for the end of the prologue (to be set when we get there). + MCSymbol *ProEndSym = getContext().CreateTempSymbol(); // Lprologue_end + + // Length of the prologue, is the next 4 bytes. Which is the start of the + // section to the end of the prologue. Not including the 4 bytes for the + // total length, the 2 bytes for the version, and these 4 bytes for the + // length of the prologue. + EmitValue(MakeStartMinusEndExpr(LineStartSym, ProEndSym, (4 + 2 + 4)), 4, 0); + + // Parameters of the state machine, are next. + // Define the architecture-dependent minimum instruction length (in + // bytes). This value should be rather too small than too big. */ + // DWARF2_LINE_MIN_INSN_LENGTH + EmitIntValue(1, 1); + // Flag that indicates the initial value of the is_stmt_start flag. + // DWARF2_LINE_DEFAULT_IS_STMT + EmitIntValue(1, 1); + // Minimum line offset in a special line info. opcode. This value + // was chosen to give a reasonable range of values. */ + // DWARF2_LINE_BASE + EmitIntValue(uint64_t(-5), 1); + // Range of line offsets in a special line info. opcode. + // DWARF2_LINE_RANGE + EmitIntValue(14, 1); + // First special line opcode - leave room for the standard opcodes. + // DWARF2_LINE_OPCODE_BASE + EmitIntValue(13, 1); + + // Standard opcode lengths + EmitIntValue(0, 1); // length of DW_LNS_copy + EmitIntValue(1, 1); // length of DW_LNS_advance_pc + EmitIntValue(1, 1); // length of DW_LNS_advance_line + EmitIntValue(1, 1); // length of DW_LNS_set_file + EmitIntValue(1, 1); // length of DW_LNS_set_column + EmitIntValue(0, 1); // length of DW_LNS_negate_stmt + EmitIntValue(0, 1); // length of DW_LNS_set_basic_block + EmitIntValue(0, 1); // length of DW_LNS_const_add_pc + EmitIntValue(1, 1); // length of DW_LNS_fixed_advance_pc + EmitIntValue(0, 1); // length of DW_LNS_set_prologue_end + EmitIntValue(0, 1); // length of DW_LNS_set_epilogue_begin + EmitIntValue(1, 1); // DW_LNS_set_isa + + // Put out the directory and file tables. + + // First the directory table. + const std::vector &MCDwarfDirs = + getContext().getMCDwarfDirs(); + for (unsigned i = 0; i < MCDwarfDirs.size(); i++) { + EmitBytes(MCDwarfDirs[i], 0); // the DirectoryName + EmitBytes(StringRef("\0", 1), 0); // the null termination of the string + } + EmitIntValue(0, 1); // Terminate the directory list + + // Second the file table. + for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { + EmitBytes(MCDwarfFiles[i]->getName(), 0); // FileName + EmitBytes(StringRef("\0", 1), 0); // the null termination of the string + // FIXME the Directory number should be a .uleb128 not a .byte + EmitIntValue(MCDwarfFiles[i]->getDirIndex(), 1); + EmitIntValue(0, 1); // last modification timestamp (always 0) + EmitIntValue(0, 1); // filesize (always 0) + } + EmitIntValue(0, 1); // Terminate the file list + + // This is the end of the prologue, so set the value of the symbol at the + // end of the prologue (that was used in a previous expression). + EmitLabel(ProEndSym); + + // TODO: This is the point where the line tables would be emitted. + + // Delete the MCLineSections that were created in + // MCMachOStreamer::MakeLineEntryForSection() and used to emit the line + // tables. + DenseMap &MCLineSections = + getContext().getMCLineSections(); + for (DenseMap::iterator it = + MCLineSections.begin(), ie = MCLineSections.end(); it != ie; ++it) { + delete it->second; + } + + // If there are no line tables emited then we emit: + // The following DW_LNE_set_address sequence to set the address to zero + // TODO test for 32-bit or 64-bit output + // This is the sequence for 32-bit code + EmitIntValue(0, 1); + EmitIntValue(5, 1); + EmitIntValue(2, 1); + EmitIntValue(0, 1); + EmitIntValue(0, 1); + EmitIntValue(0, 1); + EmitIntValue(0, 1); + + // Lastly emit the DW_LNE_end_sequence which consists of 3 bytes '00 01 01' + // (00 is the code for extended opcodes, followed by a ULEB128 length of the + // extended opcode (01), and the DW_LNE_end_sequence (01). + EmitIntValue(0, 1); // DW_LNS_extended_op + EmitIntValue(1, 1); // ULEB128 length of the extended opcode + EmitIntValue(1, 1); // DW_LNE_end_sequence + + // This is the end of the section, so set the value of the symbol at the end + // of this section (that was used in a previous expression). + EmitLabel(LineEndSym); +} + void MCMachOStreamer::Finish() { + // Dump out the dwarf file and directory tables (soon to include line table) + EmitDwarfFileTable(); + // We have to set the fragment atom associations so we can relax properly for // Mach-O. diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp index 5332ade..f7a2f20 100644 --- a/lib/MC/MCNullStreamer.cpp +++ b/lib/MC/MCNullStreamer.cpp @@ -26,6 +26,7 @@ namespace { /// @{ virtual void SwitchSection(const MCSection *Section) { + PrevSection = CurSection; CurSection = Section; } diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index d3f7f77..2b2385e 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -9,7 +9,11 @@ #include "llvm/MC/MCObjectStreamer.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Target/TargetAsmBackend.h" using namespace llvm; MCObjectStreamer::MCObjectStreamer(MCContext &Context, TargetAsmBackend &TAB, @@ -21,15 +25,59 @@ MCObjectStreamer::MCObjectStreamer(MCContext &Context, TargetAsmBackend &TAB, } MCObjectStreamer::~MCObjectStreamer() { + delete &Assembler->getBackend(); + delete &Assembler->getEmitter(); delete Assembler; } +MCFragment *MCObjectStreamer::getCurrentFragment() const { + assert(getCurrentSectionData() && "No current section!"); + + if (!getCurrentSectionData()->empty()) + return &getCurrentSectionData()->getFragmentList().back(); + + return 0; +} + +MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() const { + MCDataFragment *F = dyn_cast_or_null(getCurrentFragment()); + if (!F) + F = new MCDataFragment(getCurrentSectionData()); + return F; +} + +const MCExpr *MCObjectStreamer::AddValueSymbols(const MCExpr *Value) { + switch (Value->getKind()) { + case MCExpr::Target: llvm_unreachable("Can't handle target exprs yet!"); + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast(Value); + AddValueSymbols(BE->getLHS()); + AddValueSymbols(BE->getRHS()); + break; + } + + case MCExpr::SymbolRef: + Assembler->getOrCreateSymbolData(cast(Value)->getSymbol()); + break; + + case MCExpr::Unary: + AddValueSymbols(cast(Value)->getSubExpr()); + break; + } + + return Value; +} + void MCObjectStreamer::SwitchSection(const MCSection *Section) { assert(Section && "Cannot switch to a null section!"); // If already in this section, then this is a noop. if (Section == CurSection) return; + PrevSection = CurSection; CurSection = Section; CurSectionData = &getAssembler().getOrCreateSectionData(*Section); } diff --git a/lib/MC/MCParser/AsmLexer.cpp b/lib/MC/MCParser/AsmLexer.cpp index 465d983..086df08 100644 --- a/lib/MC/MCParser/AsmLexer.cpp +++ b/lib/MC/MCParser/AsmLexer.cpp @@ -117,6 +117,13 @@ AsmToken AsmLexer::LexLineComment() { return AsmToken(AsmToken::EndOfStatement, StringRef(CurPtr, 0)); } +static void SkipIgnoredIntegerSuffix(const char *&CurPtr) { + if (CurPtr[0] == 'L' && CurPtr[1] == 'L') + CurPtr += 2; + if (CurPtr[0] == 'U' && CurPtr[1] == 'L' && CurPtr[2] == 'L') + CurPtr += 3; +} + /// LexDigit: First character is [0-9]. /// Local Label: [0-9][:] @@ -133,7 +140,7 @@ AsmToken AsmLexer::LexDigit() { ++CurPtr; StringRef Result(TokStart, CurPtr - TokStart); - + long long Value; if (Result.getAsInteger(10, Value)) { // We have to handle minint_as_a_positive_value specially, because @@ -143,6 +150,11 @@ AsmToken AsmLexer::LexDigit() { else return ReturnError(TokStart, "Invalid decimal number"); } + + // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL + // suffixes on integer literals. + SkipIgnoredIntegerSuffix(CurPtr); + return AsmToken(AsmToken::Integer, Result, Value); } @@ -165,9 +177,13 @@ AsmToken AsmLexer::LexDigit() { StringRef Result(TokStart, CurPtr - TokStart); long long Value; - if (Result.getAsInteger(2, Value)) + if (Result.substr(2).getAsInteger(2, Value)) return ReturnError(TokStart, "Invalid binary number"); + // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL + // suffixes on integer literals. + SkipIgnoredIntegerSuffix(CurPtr); + return AsmToken(AsmToken::Integer, Result, Value); } @@ -185,6 +201,10 @@ AsmToken AsmLexer::LexDigit() { if (StringRef(TokStart, CurPtr - TokStart).getAsInteger(0, Result)) return ReturnError(TokStart, "Invalid hexadecimal number"); + // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL + // suffixes on integer literals. + SkipIgnoredIntegerSuffix(CurPtr); + return AsmToken(AsmToken::Integer, StringRef(TokStart, CurPtr - TokStart), (int64_t)Result); } @@ -198,6 +218,10 @@ AsmToken AsmLexer::LexDigit() { if (Result.getAsInteger(8, Value)) return ReturnError(TokStart, "Invalid octal number"); + // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL + // suffixes on integer literals. + SkipIgnoredIntegerSuffix(CurPtr); + return AsmToken(AsmToken::Integer, Result, Value); } diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index e0949bd..f83cd5e 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -11,47 +11,237 @@ // //===----------------------------------------------------------------------===// -#include "llvm/MC/MCParser/AsmParser.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/AsmCond.h" +#include "llvm/MC/MCParser/AsmLexer.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/SourceMgr.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmParser.h" +#include using namespace llvm; namespace { +/// \brief Helper class for tracking macro definitions. +struct Macro { + StringRef Name; + StringRef Body; + +public: + Macro(StringRef N, StringRef B) : Name(N), Body(B) {} +}; + +/// \brief Helper class for storing information about an active macro +/// instantiation. +struct MacroInstantiation { + /// The macro being instantiated. + const Macro *TheMacro; + + /// The macro instantiation with substitutions. + MemoryBuffer *Instantiation; + + /// The location of the instantiation. + SMLoc InstantiationLoc; + + /// The location where parsing should resume upon instantiation completion. + SMLoc ExitLoc; + +public: + MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL, + const std::vector > &A); +}; + +/// \brief The concrete assembly parser instance. +class AsmParser : public MCAsmParser { + friend class GenericAsmParser; + + AsmParser(const AsmParser &); // DO NOT IMPLEMENT + void operator=(const AsmParser &); // DO NOT IMPLEMENT +private: + AsmLexer Lexer; + MCContext &Ctx; + MCStreamer &Out; + SourceMgr &SrcMgr; + MCAsmParserExtension *GenericParser; + MCAsmParserExtension *PlatformParser; + + /// This is the current buffer index we're lexing from as managed by the + /// SourceMgr object. + int CurBuffer; + + AsmCond TheCondState; + std::vector TheCondStack; + + /// DirectiveMap - This is a table handlers for directives. Each handler is + /// invoked after the directive identifier is read and is responsible for + /// parsing and validating the rest of the directive. The handler is passed + /// in the directive name and the location of the directive keyword. + StringMap > DirectiveMap; + + /// MacroMap - Map of currently defined macros. + StringMap MacroMap; + + /// ActiveMacros - Stack of active macro instantiations. + std::vector ActiveMacros; + + /// Boolean tracking whether macro substitution is enabled. + unsigned MacrosEnabled : 1; + +public: + AsmParser(const Target &T, SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, + const MCAsmInfo &MAI); + ~AsmParser(); + + virtual bool Run(bool NoInitialTextSection, bool NoFinalize = false); + + void AddDirectiveHandler(MCAsmParserExtension *Object, + StringRef Directive, + DirectiveHandler Handler) { + DirectiveMap[Directive] = std::make_pair(Object, Handler); + } + +public: + /// @name MCAsmParser Interface + /// { + + virtual SourceMgr &getSourceManager() { return SrcMgr; } + virtual MCAsmLexer &getLexer() { return Lexer; } + virtual MCContext &getContext() { return Ctx; } + virtual MCStreamer &getStreamer() { return Out; } + + virtual void Warning(SMLoc L, const Twine &Meg); + virtual bool Error(SMLoc L, const Twine &Msg); + + const AsmToken &Lex(); + + bool ParseExpression(const MCExpr *&Res); + virtual bool ParseExpression(const MCExpr *&Res, SMLoc &EndLoc); + virtual bool ParseParenExpression(const MCExpr *&Res, SMLoc &EndLoc); + virtual bool ParseAbsoluteExpression(int64_t &Res); + + /// } + +private: + bool ParseStatement(); + + bool HandleMacroEntry(StringRef Name, SMLoc NameLoc, const Macro *M); + void HandleMacroExit(); + + void PrintMacroInstantiations(); + void PrintMessage(SMLoc Loc, const std::string &Msg, const char *Type) const; + + /// EnterIncludeFile - Enter the specified file. This returns true on failure. + bool EnterIncludeFile(const std::string &Filename); + + /// \brief Reset the current lexer position to that given by \arg Loc. The + /// current token is not set; clients should ensure Lex() is called + /// subsequently. + void JumpToLoc(SMLoc Loc); + + void EatToEndOfStatement(); + + /// \brief Parse up to the end of statement and a return the contents from the + /// current token until the end of the statement; the current token on exit + /// will be either the EndOfStatement or EOF. + StringRef ParseStringToEndOfStatement(); + + bool ParseAssignment(StringRef Name); + + bool ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc); + bool ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc); + bool ParseParenExpr(const MCExpr *&Res, SMLoc &EndLoc); + + /// ParseIdentifier - Parse an identifier or string (as a quoted identifier) + /// and set \arg Res to the identifier contents. + bool ParseIdentifier(StringRef &Res); + + // Directive Parsing. + bool ParseDirectiveAscii(bool ZeroTerminated); // ".ascii", ".asciiz" + bool ParseDirectiveValue(unsigned Size); // ".byte", ".long", ... + bool ParseDirectiveFill(); // ".fill" + bool ParseDirectiveSpace(); // ".space" + bool ParseDirectiveSet(); // ".set" + bool ParseDirectiveOrg(); // ".org" + // ".align{,32}", ".p2align{,w,l}" + bool ParseDirectiveAlign(bool IsPow2, unsigned ValueSize); + + /// ParseDirectiveSymbolAttribute - Parse a directive like ".globl" which + /// accepts a single symbol (which should be a label or an external). + bool ParseDirectiveSymbolAttribute(MCSymbolAttr Attr); + bool ParseDirectiveELFType(); // ELF specific ".type" + + bool ParseDirectiveComm(bool IsLocal); // ".comm" and ".lcomm" + + bool ParseDirectiveAbort(); // ".abort" + bool ParseDirectiveInclude(); // ".include" + + bool ParseDirectiveIf(SMLoc DirectiveLoc); // ".if" + bool ParseDirectiveElseIf(SMLoc DirectiveLoc); // ".elseif" + bool ParseDirectiveElse(SMLoc DirectiveLoc); // ".else" + bool ParseDirectiveEndIf(SMLoc DirectiveLoc); // .endif + + /// ParseEscapedString - Parse the current token as a string which may include + /// escaped characters and return the string contents. + bool ParseEscapedString(std::string &Data); +}; + /// \brief Generic implementations of directive handling, etc. which is shared /// (or the default, at least) for all assembler parser. class GenericAsmParser : public MCAsmParserExtension { + template + void AddDirectiveHandler(StringRef Directive) { + getParser().AddDirectiveHandler(this, Directive, + HandleDirective); + } + public: GenericAsmParser() {} + AsmParser &getParser() { + return (AsmParser&) this->MCAsmParserExtension::getParser(); + } + virtual void Initialize(MCAsmParser &Parser) { // Call the base implementation. this->MCAsmParserExtension::Initialize(Parser); // Debugging directives. - Parser.AddDirectiveHandler(this, ".file", MCAsmParser::DirectiveHandler( - &GenericAsmParser::ParseDirectiveFile)); - Parser.AddDirectiveHandler(this, ".line", MCAsmParser::DirectiveHandler( - &GenericAsmParser::ParseDirectiveLine)); - Parser.AddDirectiveHandler(this, ".loc", MCAsmParser::DirectiveHandler( - &GenericAsmParser::ParseDirectiveLoc)); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveFile>(".file"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLine>(".line"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLoc>(".loc"); + + // Macro directives. + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacrosOnOff>( + ".macros_on"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacrosOnOff>( + ".macros_off"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacro>(".macro"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveEndMacro>(".endm"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveEndMacro>(".endmacro"); } - bool ParseDirectiveFile(StringRef, SMLoc DirectiveLoc); // ".file" - bool ParseDirectiveLine(StringRef, SMLoc DirectiveLoc); // ".line" - bool ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc); // ".loc" + bool ParseDirectiveFile(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveLine(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc); + + bool ParseDirectiveMacrosOnOff(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveMacro(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveEndMacro(StringRef, SMLoc DirectiveLoc); }; } @@ -69,7 +259,7 @@ AsmParser::AsmParser(const Target &T, SourceMgr &_SM, MCContext &_Ctx, MCStreamer &_Out, const MCAsmInfo &_MAI) : Lexer(_MAI), Ctx(_Ctx), Out(_Out), SrcMgr(_SM), GenericParser(new GenericAsmParser), PlatformParser(0), - TargetParser(0), CurBuffer(0) { + CurBuffer(0), MacrosEnabled(true) { Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)); // Initialize the generic parser. @@ -89,22 +279,33 @@ AsmParser::AsmParser(const Target &T, SourceMgr &_SM, MCContext &_Ctx, } AsmParser::~AsmParser() { + assert(ActiveMacros.empty() && "Unexpected active macro instantiation!"); + + // Destroy any macros. + for (StringMap::iterator it = MacroMap.begin(), + ie = MacroMap.end(); it != ie; ++it) + delete it->getValue(); + delete PlatformParser; delete GenericParser; } -void AsmParser::setTargetParser(TargetAsmParser &P) { - assert(!TargetParser && "Target parser is already initialized!"); - TargetParser = &P; - TargetParser->Initialize(*this); +void AsmParser::PrintMacroInstantiations() { + // Print the active macro instantiation stack. + for (std::vector::const_reverse_iterator + it = ActiveMacros.rbegin(), ie = ActiveMacros.rend(); it != ie; ++it) + PrintMessage((*it)->InstantiationLoc, "while in macro instantiation", + "note"); } void AsmParser::Warning(SMLoc L, const Twine &Msg) { PrintMessage(L, Msg.str(), "warning"); + PrintMacroInstantiations(); } bool AsmParser::Error(SMLoc L, const Twine &Msg) { PrintMessage(L, Msg.str(), "error"); + PrintMacroInstantiations(); return true; } @@ -124,7 +325,12 @@ bool AsmParser::EnterIncludeFile(const std::string &Filename) { return false; } - + +void AsmParser::JumpToLoc(SMLoc Loc) { + CurBuffer = SrcMgr.FindBufferContainingLoc(Loc); + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer), Loc.getPointer()); +} + const AsmToken &AsmParser::Lex() { const AsmToken *tok = &Lexer.Lex(); @@ -133,15 +339,13 @@ const AsmToken &AsmParser::Lex() { // include stack. SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer); if (ParentIncludeLoc != SMLoc()) { - CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc); - Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer), - ParentIncludeLoc.getPointer()); + JumpToLoc(ParentIncludeLoc); tok = &Lexer.Lex(); } } if (tok->is(AsmToken::Error)) - PrintMessage(Lexer.getErrLoc(), Lexer.getErr(), "error"); + Error(Lexer.getErrLoc(), Lexer.getErr()); return *tok; } @@ -174,6 +378,16 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { if (TheCondState.TheCond != StartingCondState.TheCond || TheCondState.Ignore != StartingCondState.Ignore) return TokError("unmatched .ifs or .elses"); + + // Check to see there are no empty DwarfFile slots. + const std::vector &MCDwarfFiles = + getContext().getMCDwarfFiles(); + for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { + if (!MCDwarfFiles[i]){ + TokError("unassigned file number: " + Twine(i) + " for .file directives"); + HadError = true; + } + } // Finalize the output stream if there are no errors and if the client wants // us to. @@ -194,6 +408,16 @@ void AsmParser::EatToEndOfStatement() { Lex(); } +StringRef AsmParser::ParseStringToEndOfStatement() { + const char *Start = getTok().getLoc().getPointer(); + + while (Lexer.isNot(AsmToken::EndOfStatement) && + Lexer.isNot(AsmToken::Eof)) + Lex(); + + const char *End = getTok().getLoc().getPointer(); + return StringRef(Start, End - Start); +} /// ParseParenExpr - Parse a paren expression and return it. /// NOTE: This assumes the leading '(' has already been consumed. @@ -225,10 +449,17 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { return true; Res = MCUnaryExpr::CreateLNot(Res, getContext()); return false; + case AsmToken::Dollar: case AsmToken::String: case AsmToken::Identifier: { + EndLoc = Lexer.getLoc(); + + StringRef Identifier; + if (ParseIdentifier(Identifier)) + return false; + // This is a symbol reference. - std::pair Split = getTok().getIdentifier().split('@'); + std::pair Split = Identifier.split('@'); MCSymbol *Sym = getContext().GetOrCreateSymbol(Split.first); // Mark the symbol as used in an expression. @@ -236,12 +467,9 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { // Lookup the symbol variant if used. MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; - if (Split.first.size() != getTok().getIdentifier().size()) + if (Split.first.size() != Identifier.size()) Variant = MCSymbolRefExpr::getVariantKindForName(Split.second); - EndLoc = Lexer.getLoc(); - Lex(); // Eat identifier. - // If this is an absolute variable reference, substitute it now to preserve // semantics in the face of reassignment. if (Sym->isVariable() && isa(Sym->getVariableValue())) { @@ -568,7 +796,12 @@ bool AsmParser::ParseStatement() { default: // Normal instruction or directive. break; } - + + // If macros are enabled, check to see if this is a macro instantiation. + if (MacrosEnabled) + if (const Macro *M = MacroMap.lookup(IDVal)) + return HandleMacroEntry(IDVal, IDLoc, M); + // Otherwise, we have a normal instruction or directive. if (IDVal[0] == '.') { // Assembler features @@ -591,11 +824,14 @@ bool AsmParser::ParseStatement() { if (IDVal == ".quad") return ParseDirectiveValue(8); - // FIXME: Target hooks for IsPow2. - if (IDVal == ".align") - return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1); - if (IDVal == ".align32") - return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4); + if (IDVal == ".align") { + bool IsPow2 = !getContext().getAsmInfo().getAlignmentIsInBytes(); + return ParseDirectiveAlign(IsPow2, /*ExprSize=*/1); + } + if (IDVal == ".align32") { + bool IsPow2 = !getContext().getAsmInfo().getAlignmentIsInBytes(); + return ParseDirectiveAlign(IsPow2, /*ExprSize=*/4); + } if (IDVal == ".balign") return ParseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/1); if (IDVal == ".balignw") @@ -662,7 +898,7 @@ bool AsmParser::ParseStatement() { std::pair Handler = DirectiveMap.lookup(IDVal); if (Handler.first) - return (Handler.first->*Handler.second)(IDVal, IDLoc); + return (*Handler.second)(Handler.first, IDVal, IDLoc); // Target hook for parsing target specific directives. if (!getTargetParser().ParseDirective(ID)) @@ -684,20 +920,29 @@ bool AsmParser::ParseStatement() { if (!HadError && Lexer.isNot(AsmToken::EndOfStatement)) HadError = TokError("unexpected token in argument list"); + // Dump the parsed representation, if requested. + if (getShowParsedOperands()) { + SmallString<256> Str; + raw_svector_ostream OS(Str); + OS << "parsed instruction: ["; + for (unsigned i = 0; i != ParsedOperands.size(); ++i) { + if (i != 0) + OS << ", "; + ParsedOperands[i]->dump(OS); + } + OS << "]"; + + PrintMessage(IDLoc, OS.str(), "note"); + } + // If parsing succeeded, match the instruction. if (!HadError) { MCInst Inst; - if (!getTargetParser().MatchInstruction(ParsedOperands, Inst)) { + if (!getTargetParser().MatchInstruction(IDLoc, ParsedOperands, Inst)) { // Emit the instruction on success. Out.EmitInstruction(Inst); - } else { - // Otherwise emit a diagnostic about the match failure and set the error - // flag. - // - // FIXME: We should give nicer diagnostics about the exact failure. - Error(IDLoc, "unrecognized instruction"); + } else HadError = true; - } } // If there was no error, consume the end-of-statement token. Otherwise this @@ -712,6 +957,132 @@ bool AsmParser::ParseStatement() { return HadError; } +MacroInstantiation::MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL, + const std::vector > &A) + : TheMacro(M), InstantiationLoc(IL), ExitLoc(EL) +{ + // Macro instantiation is lexical, unfortunately. We construct a new buffer + // to hold the macro body with substitutions. + SmallString<256> Buf; + raw_svector_ostream OS(Buf); + + StringRef Body = M->Body; + while (!Body.empty()) { + // Scan for the next substitution. + std::size_t End = Body.size(), Pos = 0; + for (; Pos != End; ++Pos) { + // Check for a substitution or escape. + if (Body[Pos] != '$' || Pos + 1 == End) + continue; + + char Next = Body[Pos + 1]; + if (Next == '$' || Next == 'n' || isdigit(Next)) + break; + } + + // Add the prefix. + OS << Body.slice(0, Pos); + + // Check if we reached the end. + if (Pos == End) + break; + + switch (Body[Pos+1]) { + // $$ => $ + case '$': + OS << '$'; + break; + + // $n => number of arguments + case 'n': + OS << A.size(); + break; + + // $[0-9] => argument + default: { + // Missing arguments are ignored. + unsigned Index = Body[Pos+1] - '0'; + if (Index >= A.size()) + break; + + // Otherwise substitute with the token values, with spaces eliminated. + for (std::vector::const_iterator it = A[Index].begin(), + ie = A[Index].end(); it != ie; ++it) + OS << it->getString(); + break; + } + } + + // Update the scan point. + Body = Body.substr(Pos + 2); + } + + // We include the .endmacro in the buffer as our queue to exit the macro + // instantiation. + OS << ".endmacro\n"; + + Instantiation = MemoryBuffer::getMemBufferCopy(OS.str(), ""); +} + +bool AsmParser::HandleMacroEntry(StringRef Name, SMLoc NameLoc, + const Macro *M) { + // Arbitrarily limit macro nesting depth, to match 'as'. We can eliminate + // this, although we should protect against infinite loops. + if (ActiveMacros.size() == 20) + return TokError("macros cannot be nested more than 20 levels deep"); + + // Parse the macro instantiation arguments. + std::vector > MacroArguments; + MacroArguments.push_back(std::vector()); + unsigned ParenLevel = 0; + for (;;) { + if (Lexer.is(AsmToken::Eof)) + return TokError("unexpected token in macro instantiation"); + if (Lexer.is(AsmToken::EndOfStatement)) + break; + + // If we aren't inside parentheses and this is a comma, start a new token + // list. + if (ParenLevel == 0 && Lexer.is(AsmToken::Comma)) { + MacroArguments.push_back(std::vector()); + } else { + // Adjust the current parentheses level. + if (Lexer.is(AsmToken::LParen)) + ++ParenLevel; + else if (Lexer.is(AsmToken::RParen) && ParenLevel) + --ParenLevel; + + // Append the token to the current argument list. + MacroArguments.back().push_back(getTok()); + } + Lex(); + } + + // Create the macro instantiation object and add to the current macro + // instantiation stack. + MacroInstantiation *MI = new MacroInstantiation(M, NameLoc, + getTok().getLoc(), + MacroArguments); + ActiveMacros.push_back(MI); + + // Jump to the macro instantiation and prime the lexer. + CurBuffer = SrcMgr.AddNewSourceBuffer(MI->Instantiation, SMLoc()); + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)); + Lex(); + + return false; +} + +void AsmParser::HandleMacroExit() { + // Jump to the EndOfStatement we should return to, and consume it. + JumpToLoc(ActiveMacros.back()->ExitLoc); + Lex(); + + // Pop the instantiation entry. + delete ActiveMacros.back(); + ActiveMacros.pop_back(); +} + bool AsmParser::ParseAssignment(StringRef Name) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Lexer.getLoc(); @@ -760,6 +1131,30 @@ bool AsmParser::ParseAssignment(StringRef Name) { /// ::= identifier /// ::= string bool AsmParser::ParseIdentifier(StringRef &Res) { + // The assembler has relaxed rules for accepting identifiers, in particular we + // allow things like '.globl $foo', which would normally be separate + // tokens. At this level, we have already lexed so we cannot (currently) + // handle this as a context dependent token, instead we detect adjacent tokens + // and return the combined identifier. + if (Lexer.is(AsmToken::Dollar)) { + SMLoc DollarLoc = getLexer().getLoc(); + + // Consume the dollar sign, and check for a following identifier. + Lex(); + if (Lexer.isNot(AsmToken::Identifier)) + return true; + + // We have a '$' followed by an identifier, make sure they are adjacent. + if (DollarLoc.getPointer() + 1 != getTok().getLoc().getPointer()) + return true; + + // Construct the joined identifier and consume the token. + Res = StringRef(DollarLoc.getPointer(), + getTok().getIdentifier().size() + 1); + Lex(); + return false; + } + if (Lexer.isNot(AsmToken::Identifier) && Lexer.isNot(AsmToken::String)) return true; @@ -1081,13 +1476,14 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { bool UseCodeAlign = false; if (const MCSectionMachO *S = dyn_cast( getStreamer().getCurrentSection())) - UseCodeAlign = S->hasAttribute(MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS); + UseCodeAlign = S->hasAttribute(MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS); if ((!HasFillExpr || Lexer.getMAI().getTextAlignFillValue() == FillExpr) && ValueSize == 1 && UseCodeAlign) { getStreamer().EmitCodeAlignment(Alignment, MaxBytesToFill); } else { // FIXME: Target specific behavior about how the "extra" bytes are filled. - getStreamer().EmitValueToAlignment(Alignment, FillExpr, ValueSize, MaxBytesToFill); + getStreamer().EmitValueToAlignment(Alignment, FillExpr, ValueSize, + MaxBytesToFill); } return false; @@ -1238,31 +1634,22 @@ bool AsmParser::ParseDirectiveComm(bool IsLocal) { } /// ParseDirectiveAbort -/// ::= .abort [ "abort_string" ] +/// ::= .abort [... message ...] bool AsmParser::ParseDirectiveAbort() { // FIXME: Use loc from directive. SMLoc Loc = getLexer().getLoc(); - StringRef Str = ""; - if (getLexer().isNot(AsmToken::EndOfStatement)) { - if (getLexer().isNot(AsmToken::String)) - return TokError("expected string in '.abort' directive"); - - Str = getTok().getString(); - - Lex(); - } - + StringRef Str = ParseStringToEndOfStatement(); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.abort' directive"); - + Lex(); - // FIXME: Handle here. if (Str.empty()) Error(Loc, ".abort detected. Assembly stopping."); else Error(Loc, ".abort '" + Str + "' detected. Assembly stopping."); + // FIXME: Actually abort assembly here. return false; } @@ -1286,9 +1673,7 @@ bool AsmParser::ParseDirectiveInclude() { // Attempt to switch the lexer to the included file before consuming the end // of statement to avoid losing it when we switch. if (EnterIncludeFile(Filename)) { - PrintMessage(IncludeLoc, - "Could not find include file '" + Filename + "'", - "error"); + Error(IncludeLoc, "Could not find include file '" + Filename + "'"); return true; } @@ -1401,6 +1786,7 @@ bool AsmParser::ParseDirectiveEndIf(SMLoc DirectiveLoc) { bool GenericAsmParser::ParseDirectiveFile(StringRef, SMLoc DirectiveLoc) { // FIXME: I'm not sure what this is. int64_t FileNumber = -1; + SMLoc FileNumberLoc = getLexer().getLoc(); if (getLexer().is(AsmToken::Integer)) { FileNumber = getTok().getIntVal(); Lex(); @@ -1421,8 +1807,11 @@ bool GenericAsmParser::ParseDirectiveFile(StringRef, SMLoc DirectiveLoc) { if (FileNumber == -1) getStreamer().EmitFileDirective(Filename); - else + else { + if (getContext().GetDwarfFile(Filename, FileNumber) == 0) + Error(FileNumberLoc, "file number already allocated"); getStreamer().EmitDwarfFileDirective(FileNumber, Filename); + } return false; } @@ -1449,40 +1838,193 @@ bool GenericAsmParser::ParseDirectiveLine(StringRef, SMLoc DirectiveLoc) { /// ParseDirectiveLoc -/// ::= .loc number [number [number]] +/// ::= .loc FileNumber [LineNumber] [ColumnPos] [basic_block] [prologue_end] +/// [epilogue_begin] [is_stmt VALUE] [isa VALUE] +/// The first number is a file number, must have been previously assigned with +/// a .file directive, the second number is the line number and optionally the +/// third number is a column position (zero if not specified). The remaining +/// optional items are .loc sub-directives. bool GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { + if (getLexer().isNot(AsmToken::Integer)) return TokError("unexpected token in '.loc' directive"); - - // FIXME: What are these fields? int64_t FileNumber = getTok().getIntVal(); - (void) FileNumber; - // FIXME: Validate file. - + if (FileNumber < 1) + return TokError("file number less than one in '.loc' directive"); + if (!getContext().ValidateDwarfFileNumber(FileNumber)) + return TokError("unassigned file number in '.loc' directive"); Lex(); - if (getLexer().isNot(AsmToken::EndOfStatement)) { - if (getLexer().isNot(AsmToken::Integer)) - return TokError("unexpected token in '.loc' directive"); - int64_t Param2 = getTok().getIntVal(); - (void) Param2; + int64_t LineNumber = 0; + if (getLexer().is(AsmToken::Integer)) { + LineNumber = getTok().getIntVal(); + if (LineNumber < 1) + return TokError("line number less than one in '.loc' directive"); Lex(); + } - if (getLexer().isNot(AsmToken::EndOfStatement)) { - if (getLexer().isNot(AsmToken::Integer)) + int64_t ColumnPos = 0; + if (getLexer().is(AsmToken::Integer)) { + ColumnPos = getTok().getIntVal(); + if (ColumnPos < 0) + return TokError("column position less than zero in '.loc' directive"); + Lex(); + } + + unsigned Flags = 0; + unsigned Isa = 0; + if (getLexer().isNot(AsmToken::EndOfStatement)) { + for (;;) { + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + StringRef Name; + SMLoc Loc = getTok().getLoc(); + if (getParser().ParseIdentifier(Name)) return TokError("unexpected token in '.loc' directive"); - int64_t Param3 = getTok().getIntVal(); - (void) Param3; - Lex(); + if (Name == "basic_block") + Flags |= DWARF2_FLAG_BASIC_BLOCK; + else if (Name == "prologue_end") + Flags |= DWARF2_FLAG_PROLOGUE_END; + else if (Name == "epilogue_begin") + Flags |= DWARF2_FLAG_EPILOGUE_BEGIN; + else if (Name == "is_stmt") { + SMLoc Loc = getTok().getLoc(); + const MCExpr *Value; + if (getParser().ParseExpression(Value)) + return true; + // The expression must be the constant 0 or 1. + if (const MCConstantExpr *MCE = dyn_cast(Value)) { + int Value = MCE->getValue(); + if (Value == 0) + Flags &= ~DWARF2_FLAG_IS_STMT; + else if (Value == 1) + Flags |= DWARF2_FLAG_IS_STMT; + else + return Error(Loc, "is_stmt value not 0 or 1"); + } + else { + return Error(Loc, "is_stmt value not the constant value of 0 or 1"); + } + } + else if (Name == "isa") { + SMLoc Loc = getTok().getLoc(); + const MCExpr *Value; + if (getParser().ParseExpression(Value)) + return true; + // The expression must be a constant greater or equal to 0. + if (const MCConstantExpr *MCE = dyn_cast(Value)) { + int Value = MCE->getValue(); + if (Value < 0) + return Error(Loc, "isa number less than zero"); + Isa = Value; + } + else { + return Error(Loc, "isa number not a constant value"); + } + } + else { + return Error(Loc, "unknown sub-directive in '.loc' directive"); + } - // FIXME: Do something with the .loc. + if (getLexer().is(AsmToken::EndOfStatement)) + break; } } + getContext().setCurrentDwarfLoc(FileNumber, LineNumber, ColumnPos, Flags,Isa); + + return false; +} + +/// ParseDirectiveMacrosOnOff +/// ::= .macros_on +/// ::= .macros_off +bool GenericAsmParser::ParseDirectiveMacrosOnOff(StringRef Directive, + SMLoc DirectiveLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.file' directive"); + return Error(getLexer().getLoc(), + "unexpected token in '" + Directive + "' directive"); + + getParser().MacrosEnabled = Directive == ".macros_on"; return false; } +/// ParseDirectiveMacro +/// ::= .macro name +bool GenericAsmParser::ParseDirectiveMacro(StringRef Directive, + SMLoc DirectiveLoc) { + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.macro' directive"); + + // Eat the end of statement. + Lex(); + + AsmToken EndToken, StartToken = getTok(); + + // Lex the macro definition. + for (;;) { + // Check whether we have reached the end of the file. + if (getLexer().is(AsmToken::Eof)) + return Error(DirectiveLoc, "no matching '.endmacro' in definition"); + + // Otherwise, check whether we have reach the .endmacro. + if (getLexer().is(AsmToken::Identifier) && + (getTok().getIdentifier() == ".endm" || + getTok().getIdentifier() == ".endmacro")) { + EndToken = getTok(); + Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '" + EndToken.getIdentifier() + + "' directive"); + break; + } + + // Otherwise, scan til the end of the statement. + getParser().EatToEndOfStatement(); + } + + if (getParser().MacroMap.lookup(Name)) { + return Error(DirectiveLoc, "macro '" + Name + "' is already defined"); + } + + const char *BodyStart = StartToken.getLoc().getPointer(); + const char *BodyEnd = EndToken.getLoc().getPointer(); + StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart); + getParser().MacroMap[Name] = new Macro(Name, Body); + return false; +} + +/// ParseDirectiveEndMacro +/// ::= .endm +/// ::= .endmacro +bool GenericAsmParser::ParseDirectiveEndMacro(StringRef Directive, + SMLoc DirectiveLoc) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '" + Directive + "' directive"); + + // If we are inside a macro instantiation, terminate the current + // instantiation. + if (!getParser().ActiveMacros.empty()) { + getParser().HandleMacroExit(); + return false; + } + + // Otherwise, this .endmacro is a stray entry in the file; well formed + // .endmacro directives are handled during the macro definition parsing. + return TokError("unexpected '" + Directive + "' in file, " + "no current macro definition"); +} + +/// \brief Create an MCAsmParser instance. +MCAsmParser *llvm::createMCAsmParser(const Target &T, SourceMgr &SM, + MCContext &C, MCStreamer &Out, + const MCAsmInfo &MAI) { + return new AsmParser(T, SM, C, Out, MAI); +} diff --git a/lib/MC/MCParser/DarwinAsmParser.cpp b/lib/MC/MCParser/DarwinAsmParser.cpp index 7d8639e..54ddb44 100644 --- a/lib/MC/MCParser/DarwinAsmParser.cpp +++ b/lib/MC/MCParser/DarwinAsmParser.cpp @@ -25,6 +25,12 @@ namespace { /// \brief Implementation of directive handling which is shared across all /// Darwin targets. class DarwinAsmParser : public MCAsmParserExtension { + template + void AddDirectiveHandler(StringRef Directive) { + getParser().AddDirectiveHandler(this, Directive, + HandleDirective); + } + bool ParseSectionSwitch(const char *Segment, const char *Section, unsigned TAA = 0, unsigned ImplicitAlign = 0, unsigned StubSize = 0); @@ -36,168 +42,70 @@ public: // Call the base implementation. this->MCAsmParserExtension::Initialize(Parser); - Parser.AddDirectiveHandler(this, ".desc", MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveDesc)); - Parser.AddDirectiveHandler(this, ".lsym", MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveLsym)); - Parser.AddDirectiveHandler(this, ".subsections_via_symbols", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveSubsectionsViaSymbols)); - Parser.AddDirectiveHandler(this, ".dump", MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveDumpOrLoad)); - Parser.AddDirectiveHandler(this, ".load", MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveDumpOrLoad)); - Parser.AddDirectiveHandler(this, ".section", MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveSection)); - Parser.AddDirectiveHandler(this, ".secure_log_unique", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveSecureLogUnique)); - Parser.AddDirectiveHandler(this, ".secure_log_reset", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveSecureLogReset)); - Parser.AddDirectiveHandler(this, ".tbss", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveTBSS)); - Parser.AddDirectiveHandler(this, ".zerofill", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveZerofill)); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveDesc>(".desc"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveLsym>(".lsym"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveSubsectionsViaSymbols>( + ".subsections_via_symbols"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveDumpOrLoad>(".dump"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveDumpOrLoad>(".load"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveSection>(".section"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveSecureLogUnique>( + ".secure_log_unique"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveSecureLogReset>( + ".secure_log_reset"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveTBSS>(".tbss"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveZerofill>(".zerofill"); // Special section directives. - Parser.AddDirectiveHandler(this, ".const", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveConst)); - Parser.AddDirectiveHandler(this, ".const_data", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveConstData)); - Parser.AddDirectiveHandler(this, ".constructor", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveConstructor)); - Parser.AddDirectiveHandler(this, ".cstring", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveCString)); - Parser.AddDirectiveHandler(this, ".data", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveData)); - Parser.AddDirectiveHandler(this, ".destructor", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveDestructor)); - Parser.AddDirectiveHandler(this, ".dyld", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveDyld)); - Parser.AddDirectiveHandler(this, ".fvmlib_init0", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveFVMLibInit0)); - Parser.AddDirectiveHandler(this, ".fvmlib_init1", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveFVMLibInit1)); - Parser.AddDirectiveHandler(this, ".lazy_symbol_pointer", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveLazySymbolPointers)); - Parser.AddDirectiveHandler(this, ".literal16", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveLiteral16)); - Parser.AddDirectiveHandler(this, ".literal4", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveLiteral4)); - Parser.AddDirectiveHandler(this, ".literal8", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveLiteral8)); - Parser.AddDirectiveHandler(this, ".mod_init_func", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveModInitFunc)); - Parser.AddDirectiveHandler(this, ".mod_term_func", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveModTermFunc)); - Parser.AddDirectiveHandler(this, ".non_lazy_symbol_pointer", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveNonLazySymbolPointers)); - Parser.AddDirectiveHandler(this, ".objc_cat_cls_meth", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCCatClsMeth)); - Parser.AddDirectiveHandler(this, ".objc_cat_inst_meth", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCCatInstMeth)); - Parser.AddDirectiveHandler(this, ".objc_category", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCCategory)); - Parser.AddDirectiveHandler(this, ".objc_class", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCClass)); - Parser.AddDirectiveHandler(this, ".objc_class_names", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCClassNames)); - Parser.AddDirectiveHandler(this, ".objc_class_vars", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCClassVars)); - Parser.AddDirectiveHandler(this, ".objc_cls_meth", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCClsMeth)); - Parser.AddDirectiveHandler(this, ".objc_cls_refs", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCClsRefs)); - Parser.AddDirectiveHandler(this, ".objc_inst_meth", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCInstMeth)); - Parser.AddDirectiveHandler(this, ".objc_instance_vars", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCInstanceVars)); - Parser.AddDirectiveHandler(this, ".objc_message_refs", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCMessageRefs)); - Parser.AddDirectiveHandler(this, ".objc_meta_class", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCMetaClass)); - Parser.AddDirectiveHandler(this, ".objc_meth_var_names", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCMethVarNames)); - Parser.AddDirectiveHandler(this, ".objc_meth_var_types", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCMethVarTypes)); - Parser.AddDirectiveHandler(this, ".objc_module_info", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCModuleInfo)); - Parser.AddDirectiveHandler(this, ".objc_protocol", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCProtocol)); - Parser.AddDirectiveHandler(this, ".objc_selector_strs", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCSelectorStrs)); - Parser.AddDirectiveHandler(this, ".objc_string_object", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCStringObject)); - Parser.AddDirectiveHandler(this, ".objc_symbols", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCSymbols)); - Parser.AddDirectiveHandler(this, ".picsymbol_stub", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectivePICSymbolStub)); - Parser.AddDirectiveHandler(this, ".static_const", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveStaticConst)); - Parser.AddDirectiveHandler(this, ".static_data", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveStaticData)); - Parser.AddDirectiveHandler(this, ".symbol_stub", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveSymbolStub)); - Parser.AddDirectiveHandler(this, ".tdata", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveTData)); - Parser.AddDirectiveHandler(this, ".text", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveText)); - Parser.AddDirectiveHandler(this, ".thread_init_func", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveThreadInitFunc)); - Parser.AddDirectiveHandler(this, ".tlv", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveTLV)); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveConst>(".const"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveConstData>(".const_data"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveConstructor>(".constructor"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveCString>(".cstring"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveData>(".data"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveDestructor>(".destructor"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveDyld>(".dyld"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveFVMLibInit0>(".fvmlib_init0"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveFVMLibInit1>(".fvmlib_init1"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveLazySymbolPointers>(".lazy_symbol_pointer"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveLiteral16>(".literal16"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveLiteral4>(".literal4"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveLiteral8>(".literal8"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveModInitFunc>(".mod_init_func"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveModTermFunc>(".mod_term_func"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveNonLazySymbolPointers>(".non_lazy_symbol_pointer"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCCatClsMeth>(".objc_cat_cls_meth"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCCatInstMeth>(".objc_cat_inst_meth"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCCategory>(".objc_category"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCClass>(".objc_class"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCClassNames>(".objc_class_names"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCClassVars>(".objc_class_vars"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCClsMeth>(".objc_cls_meth"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCClsRefs>(".objc_cls_refs"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCInstMeth>(".objc_inst_meth"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCInstanceVars>(".objc_instance_vars"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCMessageRefs>(".objc_message_refs"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCMetaClass>(".objc_meta_class"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCMethVarNames>(".objc_meth_var_names"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCMethVarTypes>(".objc_meth_var_types"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCModuleInfo>(".objc_module_info"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCProtocol>(".objc_protocol"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCSelectorStrs>(".objc_selector_strs"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCStringObject>(".objc_string_object"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveObjCSymbols>(".objc_symbols"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectivePICSymbolStub>(".picsymbol_stub"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveStaticConst>(".static_const"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveStaticData>(".static_data"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveSymbolStub>(".symbol_stub"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveTData>(".tdata"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveText>(".text"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveThreadInitFunc>(".thread_init_func"); + AddDirectiveHandler<&DarwinAsmParser::ParseSectionDirectiveTLV>(".tlv"); } bool ParseDirectiveDesc(StringRef, SMLoc); bool ParseDirectiveDumpOrLoad(StringRef, SMLoc); bool ParseDirectiveLsym(StringRef, SMLoc); - bool ParseDirectiveSection(); + bool ParseDirectiveSection(StringRef, SMLoc); bool ParseDirectiveSecureLogReset(StringRef, SMLoc); bool ParseDirectiveSecureLogUnique(StringRef, SMLoc); bool ParseDirectiveSubsectionsViaSymbols(StringRef, SMLoc); @@ -493,7 +401,7 @@ bool DarwinAsmParser::ParseDirectiveLsym(StringRef, SMLoc) { /// ParseDirectiveSection: /// ::= .section identifier (',' identifier)* -bool DarwinAsmParser::ParseDirectiveSection() { +bool DarwinAsmParser::ParseDirectiveSection(StringRef, SMLoc) { SMLoc Loc = getLexer().getLoc(); StringRef SectionName; @@ -537,28 +445,22 @@ bool DarwinAsmParser::ParseDirectiveSection() { } /// ParseDirectiveSecureLogUnique -/// ::= .secure_log_unique "log message" +/// ::= .secure_log_unique ... message ... bool DarwinAsmParser::ParseDirectiveSecureLogUnique(StringRef, SMLoc IDLoc) { - std::string LogMessage; - - if (getLexer().isNot(AsmToken::String)) - LogMessage = ""; - else{ - LogMessage = getTok().getString(); - Lex(); - } - + StringRef LogMessage = getParser().ParseStringToEndOfStatement(); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.secure_log_unique' directive"); if (getContext().getSecureLogUsed() != false) return Error(IDLoc, ".secure_log_unique specified multiple times"); - char *SecureLogFile = getContext().getSecureLogFile(); + // Get the secure log path. + const char *SecureLogFile = getContext().getSecureLogFile(); if (SecureLogFile == NULL) return Error(IDLoc, ".secure_log_unique used but AS_SECURE_LOG_FILE " "environment variable unset."); + // Open the secure log file if we haven't already. raw_ostream *OS = getContext().getSecureLog(); if (OS == NULL) { std::string Err; @@ -571,6 +473,7 @@ bool DarwinAsmParser::ParseDirectiveSecureLogUnique(StringRef, SMLoc IDLoc) { getContext().setSecureLog(OS); } + // Write the message. int CurBuf = getSourceManager().FindBufferContainingLoc(IDLoc); *OS << getSourceManager().getBufferInfo(CurBuf).Buffer->getBufferIdentifier() << ":" << getSourceManager().FindLineNumber(IDLoc, CurBuf) << ":" diff --git a/lib/MC/MCParser/ELFAsmParser.cpp b/lib/MC/MCParser/ELFAsmParser.cpp index 7a54dd3..f982fda 100644 --- a/lib/MC/MCParser/ELFAsmParser.cpp +++ b/lib/MC/MCParser/ELFAsmParser.cpp @@ -8,15 +8,24 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCParser/MCAsmParserExtension.h" -#include "llvm/MC/MCSectionELF.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" -#include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/ADT/Twine.h" using namespace llvm; namespace { class ELFAsmParser : public MCAsmParserExtension { + template + void AddDirectiveHandler(StringRef Directive) { + getParser().AddDirectiveHandler(this, Directive, + HandleDirective); + } + bool ParseSectionSwitch(StringRef Section, unsigned Type, unsigned Flags, SectionKind Kind); @@ -27,10 +36,21 @@ public: // Call the base implementation. this->MCAsmParserExtension::Initialize(Parser); - Parser.AddDirectiveHandler(this, ".data", MCAsmParser::DirectiveHandler( - &ELFAsmParser::ParseSectionDirectiveData)); - Parser.AddDirectiveHandler(this, ".text", MCAsmParser::DirectiveHandler( - &ELFAsmParser::ParseSectionDirectiveText)); + AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveData>(".data"); + AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveText>(".text"); + AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveBSS>(".bss"); + AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveRoData>(".rodata"); + AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTData>(".tdata"); + AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTBSS>(".tbss"); + AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveDataRel>(".data.rel"); + AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveDataRelRo>(".data.rel.ro"); + AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveDataRelRoLocal>(".data.rel.ro.local"); + AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveEhFrame>(".eh_frame"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSection>(".section"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSize>(".size"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveLEB128>(".sleb128"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveLEB128>(".uleb128"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectivePrevious>(".previous"); } bool ParseSectionDirectiveData(StringRef, SMLoc) { @@ -43,6 +63,56 @@ public: MCSectionELF::SHF_EXECINSTR | MCSectionELF::SHF_ALLOC, SectionKind::getText()); } + bool ParseSectionDirectiveBSS(StringRef, SMLoc) { + return ParseSectionSwitch(".bss", MCSectionELF::SHT_NOBITS, + MCSectionELF::SHF_WRITE | + MCSectionELF::SHF_ALLOC, SectionKind::getBSS()); + } + bool ParseSectionDirectiveRoData(StringRef, SMLoc) { + return ParseSectionSwitch(".rodata", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_ALLOC, + SectionKind::getReadOnly()); + } + bool ParseSectionDirectiveTData(StringRef, SMLoc) { + return ParseSectionSwitch(".tdata", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_ALLOC | + MCSectionELF::SHF_TLS | MCSectionELF::SHF_WRITE, + SectionKind::getThreadData()); + } + bool ParseSectionDirectiveTBSS(StringRef, SMLoc) { + return ParseSectionSwitch(".tbss", MCSectionELF::SHT_NOBITS, + MCSectionELF::SHF_ALLOC | + MCSectionELF::SHF_TLS | MCSectionELF::SHF_WRITE, + SectionKind::getThreadBSS()); + } + bool ParseSectionDirectiveDataRel(StringRef, SMLoc) { + return ParseSectionSwitch(".data.rel", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_ALLOC | + MCSectionELF::SHF_WRITE, + SectionKind::getDataRel()); + } + bool ParseSectionDirectiveDataRelRo(StringRef, SMLoc) { + return ParseSectionSwitch(".data.rel.ro", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_ALLOC | + MCSectionELF::SHF_WRITE, + SectionKind::getReadOnlyWithRel()); + } + bool ParseSectionDirectiveDataRelRoLocal(StringRef, SMLoc) { + return ParseSectionSwitch(".data.rel.ro.local", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_ALLOC | + MCSectionELF::SHF_WRITE, + SectionKind::getReadOnlyWithRelLocal()); + } + bool ParseSectionDirectiveEhFrame(StringRef, SMLoc) { + return ParseSectionSwitch(".eh_frame", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_ALLOC | + MCSectionELF::SHF_WRITE, + SectionKind::getDataRel()); + } + bool ParseDirectiveLEB128(StringRef, SMLoc); + bool ParseDirectiveSection(StringRef, SMLoc); + bool ParseDirectiveSize(StringRef, SMLoc); + bool ParseDirectivePrevious(StringRef, SMLoc); }; } @@ -59,6 +129,159 @@ bool ELFAsmParser::ParseSectionSwitch(StringRef Section, unsigned Type, return false; } +bool ELFAsmParser::ParseDirectiveSize(StringRef, SMLoc) { + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + const MCExpr *Expr; + if (getParser().ParseExpression(Expr)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + getStreamer().EmitELFSize(Sym, Expr); + return false; +} + +// FIXME: This is a work in progress. +bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { + StringRef SectionName; + // FIXME: This doesn't parse section names like ".note.GNU-stack" correctly. + if (getParser().ParseIdentifier(SectionName)) + return TokError("expected identifier in directive"); + + std::string FlagsStr; + StringRef TypeName; + int64_t Size = 0; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in directive"); + + FlagsStr = getTok().getStringContents(); + Lex(); + + AsmToken::TokenKind TypeStartToken; + if (getContext().getAsmInfo().getCommentString()[0] == '@') + TypeStartToken = AsmToken::Percent; + else + TypeStartToken = AsmToken::At; + + if (getLexer().is(AsmToken::Comma)) { + Lex(); + if (getLexer().is(TypeStartToken)) { + Lex(); + if (getParser().ParseIdentifier(TypeName)) + return TokError("expected identifier in directive"); + + if (getLexer().is(AsmToken::Comma)) { + Lex(); + + if (getParser().ParseAbsoluteExpression(Size)) + return true; + + if (Size <= 0) + return TokError("section size must be positive"); + } + } + } + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + unsigned Flags = 0; + for (unsigned i = 0; i < FlagsStr.size(); i++) { + switch (FlagsStr[i]) { + case 'a': + Flags |= MCSectionELF::SHF_ALLOC; + break; + case 'x': + Flags |= MCSectionELF::SHF_EXECINSTR; + break; + case 'w': + Flags |= MCSectionELF::SHF_WRITE; + break; + case 'M': + Flags |= MCSectionELF::SHF_MERGE; + break; + case 'S': + Flags |= MCSectionELF::SHF_STRINGS; + break; + case 'T': + Flags |= MCSectionELF::SHF_TLS; + break; + case 'c': + Flags |= MCSectionELF::XCORE_SHF_CP_SECTION; + break; + case 'd': + Flags |= MCSectionELF::XCORE_SHF_DP_SECTION; + break; + default: + return TokError("unknown flag"); + } + } + + unsigned Type = MCSectionELF::SHT_NULL; + if (!TypeName.empty()) { + if (TypeName == "init_array") + Type = MCSectionELF::SHT_INIT_ARRAY; + else if (TypeName == "fini_array") + Type = MCSectionELF::SHT_FINI_ARRAY; + else if (TypeName == "preinit_array") + Type = MCSectionELF::SHT_PREINIT_ARRAY; + else if (TypeName == "nobits") + Type = MCSectionELF::SHT_NOBITS; + else if (TypeName == "progbits") + Type = MCSectionELF::SHT_PROGBITS; + else + return TokError("unknown section type"); + } + + SectionKind Kind = (Flags & MCSectionELF::SHF_EXECINSTR) + ? SectionKind::getText() + : SectionKind::getDataRel(); + getStreamer().SwitchSection(getContext().getELFSection(SectionName, Type, + Flags, Kind, false)); + return false; +} + +bool ELFAsmParser::ParseDirectiveLEB128(StringRef DirName, SMLoc) { + int64_t Value; + if (getParser().ParseAbsoluteExpression(Value)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + // FIXME: Add proper MC support. + if (getContext().getAsmInfo().hasLEB128()) { + if (DirName[1] == 's') + getStreamer().EmitRawText("\t.sleb128\t" + Twine(Value)); + else + getStreamer().EmitRawText("\t.uleb128\t" + Twine(Value)); + return false; + } + // FIXME: This shouldn't be an error! + return TokError("LEB128 not supported yet"); +} + +bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) { + const MCSection *PreviousSection = getStreamer().getPreviousSection(); + if (PreviousSection != NULL) + getStreamer().SwitchSection(PreviousSection); + + return false; +} + namespace llvm { MCAsmParserExtension *createELFAsmParser() { diff --git a/lib/MC/MCParser/MCAsmParser.cpp b/lib/MC/MCParser/MCAsmParser.cpp index bee3064..70295ef 100644 --- a/lib/MC/MCParser/MCAsmParser.cpp +++ b/lib/MC/MCParser/MCAsmParser.cpp @@ -12,19 +12,26 @@ #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Target/TargetAsmParser.h" using namespace llvm; -MCAsmParser::MCAsmParser() { +MCAsmParser::MCAsmParser() : TargetParser(0), ShowParsedOperands(0) { } MCAsmParser::~MCAsmParser() { } +void MCAsmParser::setTargetParser(TargetAsmParser &P) { + assert(!TargetParser && "Target parser is already initialized!"); + TargetParser = &P; + TargetParser->Initialize(*this); +} + const AsmToken &MCAsmParser::getTok() { return getLexer().getTok(); } -bool MCAsmParser::TokError(const char *Msg) { +bool MCAsmParser::TokError(const Twine &Msg) { Error(getLexer().getLoc(), Msg); return true; } @@ -34,8 +41,4 @@ bool MCAsmParser::ParseExpression(const MCExpr *&Res) { return ParseExpression(Res, L); } -/// getStartLoc - Get the location of the first token of this operand. -SMLoc MCParsedAsmOperand::getStartLoc() const { return SMLoc(); } -SMLoc MCParsedAsmOperand::getEndLoc() const { return SMLoc(); } - diff --git a/lib/MC/MCParser/TargetAsmParser.cpp b/lib/MC/MCParser/TargetAsmParser.cpp index 05760c9..8d43c21 100644 --- a/lib/MC/MCParser/TargetAsmParser.cpp +++ b/lib/MC/MCParser/TargetAsmParser.cpp @@ -11,7 +11,7 @@ using namespace llvm; TargetAsmParser::TargetAsmParser(const Target &T) - : TheTarget(T) + : TheTarget(T), AvailableFeatures(0) { } diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp index 573f2a3..3e9d02e 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -15,7 +15,8 @@ #include using namespace llvm; -MCStreamer::MCStreamer(MCContext &_Context) : Context(_Context), CurSection(0) { +MCStreamer::MCStreamer(MCContext &Ctx) : Context(Ctx), CurSection(0), + PrevSection(0) { } MCStreamer::~MCStreamer() { diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp index 7ca0951..cffabfa 100644 --- a/lib/MC/MachObjectWriter.cpp +++ b/lib/MC/MachObjectWriter.cpp @@ -769,7 +769,7 @@ public: IsPCRel = 1; FixedValue = (FixupAddress - Layout.getSymbolAddress(SD_B) + Target.getConstant()); - FixedValue += 1 << Log2Size; + FixedValue += 1ULL << Log2Size; } else { FixedValue = 0; } diff --git a/lib/MC/Makefile b/lib/MC/Makefile index a661fa6..bf8b7c0 100644 --- a/lib/MC/Makefile +++ b/lib/MC/Makefile @@ -10,7 +10,7 @@ LEVEL = ../.. LIBRARYNAME = LLVMMC BUILD_ARCHIVE := 1 -PARALLEL_DIRS := MCParser +PARALLEL_DIRS := MCParser MCDisassembler include $(LEVEL)/Makefile.common diff --git a/lib/MC/WinCOFFObjectWriter.cpp b/lib/MC/WinCOFFObjectWriter.cpp index 6804766..eeb2b96 100644 --- a/lib/MC/WinCOFFObjectWriter.cpp +++ b/lib/MC/WinCOFFObjectWriter.cpp @@ -12,41 +12,552 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "WinCOFFObjectWriter" + #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCSectionCOFF.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" + +#include "llvm/Support/COFF.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" + +#include "llvm/System/TimeValue.h" + +#include "../Target/X86/X86FixupKinds.h" + +#include + using namespace llvm; namespace { +typedef llvm::SmallString name; + +enum AuxiliaryType { + ATFunctionDefinition, + ATbfAndefSymbol, + ATWeakExternal, + ATFile, + ATSectionDefinition +}; + +struct AuxSymbol { + AuxiliaryType AuxType; + COFF::Auxiliary Aux; +}; + +class COFFSymbol { +public: + COFF::symbol Data; + + typedef llvm::SmallVector AuxiliarySymbols; + + name Name; + size_t Index; + AuxiliarySymbols Aux; + COFFSymbol *Other; + + MCSymbolData const *MCData; + + COFFSymbol(llvm::StringRef name, size_t index); + size_t size() const; + void set_name_offset(uint32_t Offset); +}; + +// This class contains staging data for a COFF relocation entry. +struct COFFRelocation { + COFF::relocation Data; + COFFSymbol *Symb; + + COFFRelocation() : Symb(NULL) {} + static size_t size() { return COFF::RelocationSize; } +}; + +typedef std::vector relocations; + +class COFFSection { +public: + COFF::section Header; + + std::string Name; + size_t Number; + MCSectionData const *MCData; + COFFSymbol *Symb; + relocations Relocations; + + COFFSection(llvm::StringRef name, size_t Index); + static size_t size(); +}; + +// This class holds the COFF string table. +class StringTable { + typedef llvm::StringMap map; + map Map; + + void update_length(); +public: + std::vector Data; + + StringTable(); + size_t size() const; + size_t insert(llvm::StringRef String); +}; + +class WinCOFFObjectWriter : public MCObjectWriter { +public: + + typedef std::vector symbols; + typedef std::vector sections; + + typedef StringMap name_symbol_map; + typedef StringMap name_section_map; + + typedef DenseMap symbol_map; + typedef DenseMap section_map; + + // Root level file contents. + bool Is64Bit; + COFF::header Header; + sections Sections; + symbols Symbols; + StringTable Strings; + + // Maps used during object file creation. + section_map SectionMap; + symbol_map SymbolMap; + + WinCOFFObjectWriter(raw_ostream &OS, bool is64Bit); + ~WinCOFFObjectWriter(); + + COFFSymbol *createSymbol(llvm::StringRef Name); + COFFSection *createSection(llvm::StringRef Name); + + void InitCOFFEntity(COFFSymbol &Symbol); + void InitCOFFEntity(COFFSection &Section); + + template + object_t *createCOFFEntity(llvm::StringRef Name, list_t &List); + + void DefineSection(MCSectionData const &SectionData); + void DefineSymbol(MCSymbolData const &SymbolData, MCAssembler &Assembler); + + bool ExportSection(COFFSection *S); + bool ExportSymbol(MCSymbolData const &SymbolData, MCAssembler &Asm); + + // Entity writing methods. + + void WriteFileHeader(const COFF::header &Header); + void WriteSymbol(const COFFSymbol *S); + void WriteAuxiliarySymbols(const COFFSymbol::AuxiliarySymbols &S); + void WriteSectionHeader(const COFF::section &S); + void WriteRelocation(const COFF::relocation &R); + + // MCObjectWriter interface implementation. + + void ExecutePostLayoutBinding(MCAssembler &Asm); + + void RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, + MCValue Target, + uint64_t &FixedValue); + + void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout); +}; +} + +static inline void write_uint32_le(void *Data, uint32_t const &Value) { + uint8_t *Ptr = reinterpret_cast(Data); + Ptr[0] = (Value & 0x000000FF) >> 0; + Ptr[1] = (Value & 0x0000FF00) >> 8; + Ptr[2] = (Value & 0x00FF0000) >> 16; + Ptr[3] = (Value & 0xFF000000) >> 24; +} + +static inline void write_uint16_le(void *Data, uint16_t const &Value) { + uint8_t *Ptr = reinterpret_cast(Data); + Ptr[0] = (Value & 0x00FF) >> 0; + Ptr[1] = (Value & 0xFF00) >> 8; +} + +static inline void write_uint8_le(void *Data, uint8_t const &Value) { + uint8_t *Ptr = reinterpret_cast(Data); + Ptr[0] = (Value & 0xFF) >> 0; +} - class WinCOFFObjectWriter : public MCObjectWriter { - public: - WinCOFFObjectWriter(raw_ostream &OS); +//------------------------------------------------------------------------------ +// Symbol class implementation + +COFFSymbol::COFFSymbol(llvm::StringRef name, size_t index) + : Name(name.begin(), name.end()), Index(-1) + , Other(NULL), MCData(NULL) { + memset(&Data, 0, sizeof(Data)); +} + +size_t COFFSymbol::size() const { + return COFF::SymbolSize + (Data.NumberOfAuxSymbols * COFF::SymbolSize); +} + +// In the case that the name does not fit within 8 bytes, the offset +// into the string table is stored in the last 4 bytes instead, leaving +// the first 4 bytes as 0. +void COFFSymbol::set_name_offset(uint32_t Offset) { + write_uint32_le(Data.Name + 0, 0); + write_uint32_le(Data.Name + 4, Offset); +} + +//------------------------------------------------------------------------------ +// Section class implementation + +COFFSection::COFFSection(llvm::StringRef name, size_t Index) + : Name(name), Number(Index + 1) + , MCData(NULL), Symb(NULL) { + memset(&Header, 0, sizeof(Header)); +} + +size_t COFFSection::size() { + return COFF::SectionSize; +} + +//------------------------------------------------------------------------------ +// StringTable class implementation + +/// Write the length of the string table into Data. +/// The length of the string table includes uint32 length header. +void StringTable::update_length() { + write_uint32_le(&Data.front(), Data.size()); +} + +StringTable::StringTable() { + // The string table data begins with the length of the entire string table + // including the length header. Allocate space for this header. + Data.resize(4); +} + +size_t StringTable::size() const { + return Data.size(); +} + +/// Add String to the table iff it is not already there. +/// @returns the index into the string table where the string is now located. +size_t StringTable::insert(llvm::StringRef String) { + map::iterator i = Map.find(String); + + if (i != Map.end()) + return i->second; + + size_t Offset = Data.size(); - // MCObjectWriter interface implementation. + // Insert string data into string table. + Data.insert(Data.end(), String.begin(), String.end()); + Data.push_back('\0'); - void ExecutePostLayoutBinding(MCAssembler &Asm); + // Put a reference to it in the map. + Map[String] = Offset; - void RecordRelocation(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, - MCValue Target, - uint64_t &FixedValue); + // Update the internal length field. + update_length(); - void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout); - }; + return Offset; } -WinCOFFObjectWriter::WinCOFFObjectWriter(raw_ostream &OS) - : MCObjectWriter(OS, true) { +//------------------------------------------------------------------------------ +// WinCOFFObjectWriter class implementation + +WinCOFFObjectWriter::WinCOFFObjectWriter(raw_ostream &OS, bool is64Bit) + : MCObjectWriter(OS, true) + , Is64Bit(is64Bit) { + memset(&Header, 0, sizeof(Header)); + + Is64Bit ? Header.Machine = COFF::IMAGE_FILE_MACHINE_AMD64 + : Header.Machine = COFF::IMAGE_FILE_MACHINE_I386; +} + +WinCOFFObjectWriter::~WinCOFFObjectWriter() { + for (symbols::iterator I = Symbols.begin(), E = Symbols.end(); I != E; ++I) + delete *I; + for (sections::iterator I = Sections.begin(), E = Sections.end(); I != E; ++I) + delete *I; +} + +COFFSymbol *WinCOFFObjectWriter::createSymbol(llvm::StringRef Name) { + return createCOFFEntity(Name, Symbols); +} + +COFFSection *WinCOFFObjectWriter::createSection(llvm::StringRef Name) { + return createCOFFEntity(Name, Sections); +} + +/// This function initializes a symbol by entering its name into the string +/// table if it is too long to fit in the symbol table header. +void WinCOFFObjectWriter::InitCOFFEntity(COFFSymbol &S) { + if (S.Name.size() > COFF::NameSize) { + size_t StringTableEntry = Strings.insert(S.Name.c_str()); + + S.set_name_offset(StringTableEntry); + } else + memcpy(S.Data.Name, S.Name.c_str(), S.Name.size()); +} + +/// This function initializes a section by entering its name into the string +/// table if it is too long to fit in the section table header. +void WinCOFFObjectWriter::InitCOFFEntity(COFFSection &S) { + if (S.Name.size() > COFF::NameSize) { + size_t StringTableEntry = Strings.insert(S.Name.c_str()); + + // FIXME: Why is this number 999999? This number is never mentioned in the + // spec. I'm assuming this is due to the printed value needing to fit into + // the S.Header.Name field. In which case why not 9999999 (7 9's instead of + // 6)? The spec does not state if this entry should be null terminated in + // this case, and thus this seems to be the best way to do it. I think I + // just solved my own FIXME... + if (StringTableEntry > 999999) + report_fatal_error("COFF string table is greater than 999999 bytes."); + + sprintf(S.Header.Name, "/%d", (unsigned)StringTableEntry); + } else + memcpy(S.Header.Name, S.Name.c_str(), S.Name.size()); +} + +/// A template used to lookup or create a symbol/section, and initialize it if +/// needed. +template +object_t *WinCOFFObjectWriter::createCOFFEntity(llvm::StringRef Name, + list_t &List) { + object_t *Object = new object_t(Name, List.size()); + + InitCOFFEntity(*Object); + + List.push_back(Object); + + return Object; +} + +/// This function takes a section data object from the assembler +/// and creates the associated COFF section staging object. +void WinCOFFObjectWriter::DefineSection(MCSectionData const &SectionData) { + // FIXME: Not sure how to verify this (at least in a debug build). + MCSectionCOFF const &Sec = + static_cast(SectionData.getSection()); + + COFFSection *coff_section = createSection(Sec.getSectionName()); + COFFSymbol *coff_symbol = createSymbol(Sec.getSectionName()); + + coff_section->Symb = coff_symbol; + coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; + coff_symbol->Data.SectionNumber = coff_section->Number; + + // In this case the auxiliary symbol is a Section Definition. + coff_symbol->Aux.resize(1); + memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0])); + coff_symbol->Aux[0].AuxType = ATSectionDefinition; + coff_symbol->Aux[0].Aux.SectionDefinition.Number = coff_section->Number; + coff_symbol->Aux[0].Aux.SectionDefinition.Selection = Sec.getSelection(); + + coff_section->Header.Characteristics = Sec.getCharacteristics(); + + uint32_t &Characteristics = coff_section->Header.Characteristics; + switch (SectionData.getAlignment()) { + case 1: Characteristics |= COFF::IMAGE_SCN_ALIGN_1BYTES; break; + case 2: Characteristics |= COFF::IMAGE_SCN_ALIGN_2BYTES; break; + case 4: Characteristics |= COFF::IMAGE_SCN_ALIGN_4BYTES; break; + case 8: Characteristics |= COFF::IMAGE_SCN_ALIGN_8BYTES; break; + case 16: Characteristics |= COFF::IMAGE_SCN_ALIGN_16BYTES; break; + case 32: Characteristics |= COFF::IMAGE_SCN_ALIGN_32BYTES; break; + case 64: Characteristics |= COFF::IMAGE_SCN_ALIGN_64BYTES; break; + case 128: Characteristics |= COFF::IMAGE_SCN_ALIGN_128BYTES; break; + case 256: Characteristics |= COFF::IMAGE_SCN_ALIGN_256BYTES; break; + case 512: Characteristics |= COFF::IMAGE_SCN_ALIGN_512BYTES; break; + case 1024: Characteristics |= COFF::IMAGE_SCN_ALIGN_1024BYTES; break; + case 2048: Characteristics |= COFF::IMAGE_SCN_ALIGN_2048BYTES; break; + case 4096: Characteristics |= COFF::IMAGE_SCN_ALIGN_4096BYTES; break; + case 8192: Characteristics |= COFF::IMAGE_SCN_ALIGN_8192BYTES; break; + default: + llvm_unreachable("unsupported section alignment"); + } + + // Bind internal COFF section to MC section. + coff_section->MCData = &SectionData; + SectionMap[&SectionData] = coff_section; +} + +/// This function takes a section data object from the assembler +/// and creates the associated COFF symbol staging object. +void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData, + MCAssembler &Assembler) { + COFFSymbol *coff_symbol = createSymbol(SymbolData.getSymbol().getName()); + + coff_symbol->Data.Type = (SymbolData.getFlags() & 0x0000FFFF) >> 0; + coff_symbol->Data.StorageClass = (SymbolData.getFlags() & 0x00FF0000) >> 16; + + // If no storage class was specified in the streamer, define it here. + if (coff_symbol->Data.StorageClass == 0) { + bool external = SymbolData.isExternal() || (SymbolData.Fragment == NULL); + + coff_symbol->Data.StorageClass = + external ? COFF::IMAGE_SYM_CLASS_EXTERNAL : COFF::IMAGE_SYM_CLASS_STATIC; + } + + if (SymbolData.getFlags() & COFF::SF_WeakReference) { + coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; + + const MCExpr *Value = SymbolData.getSymbol().getVariableValue(); + + // FIXME: This assert message isn't very good. + assert(Value->getKind() == MCExpr::SymbolRef && + "Value must be a SymbolRef!"); + + const MCSymbolRefExpr *SymbolRef = + static_cast(Value); + + const MCSymbolData &OtherSymbolData = + Assembler.getSymbolData(SymbolRef->getSymbol()); + + // FIXME: This assert message isn't very good. + assert(SymbolMap.find(&OtherSymbolData) != SymbolMap.end() && + "OtherSymbolData must be in the symbol map!"); + + coff_symbol->Other = SymbolMap[&OtherSymbolData]; + + // Setup the Weak External auxiliary symbol. + coff_symbol->Aux.resize(1); + memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0])); + coff_symbol->Aux[0].AuxType = ATWeakExternal; + coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = 0; + coff_symbol->Aux[0].Aux.WeakExternal.Characteristics = + COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY; + } + + // Bind internal COFF symbol to MC symbol. + coff_symbol->MCData = &SymbolData; + SymbolMap[&SymbolData] = coff_symbol; +} + +bool WinCOFFObjectWriter::ExportSection(COFFSection *S) { + return (S->Header.Characteristics + & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0; +} + +bool WinCOFFObjectWriter::ExportSymbol(MCSymbolData const &SymbolData, + MCAssembler &Asm) { + // This doesn't seem to be right. Strings referred to from the .data section + // need symbols so they can be linked to code in the .text section right? + + // return Asm.isSymbolLinkerVisible (&SymbolData); + + // For now, all symbols are exported, the linker will sort it out for us. + return true; +} + +//------------------------------------------------------------------------------ +// entity writing methods + +void WinCOFFObjectWriter::WriteFileHeader(const COFF::header &Header) { + WriteLE16(Header.Machine); + WriteLE16(Header.NumberOfSections); + WriteLE32(Header.TimeDateStamp); + WriteLE32(Header.PointerToSymbolTable); + WriteLE32(Header.NumberOfSymbols); + WriteLE16(Header.SizeOfOptionalHeader); + WriteLE16(Header.Characteristics); +} + +void WinCOFFObjectWriter::WriteSymbol(const COFFSymbol *S) { + WriteBytes(StringRef(S->Data.Name, COFF::NameSize)); + WriteLE32(S->Data.Value); + WriteLE16(S->Data.SectionNumber); + WriteLE16(S->Data.Type); + Write8(S->Data.StorageClass); + Write8(S->Data.NumberOfAuxSymbols); + WriteAuxiliarySymbols(S->Aux); +} + +void WinCOFFObjectWriter::WriteAuxiliarySymbols( + const COFFSymbol::AuxiliarySymbols &S) { + for(COFFSymbol::AuxiliarySymbols::const_iterator i = S.begin(), e = S.end(); + i != e; ++i) { + switch(i->AuxType) { + case ATFunctionDefinition: + WriteLE32(i->Aux.FunctionDefinition.TagIndex); + WriteLE32(i->Aux.FunctionDefinition.TotalSize); + WriteLE32(i->Aux.FunctionDefinition.PointerToLinenumber); + WriteLE32(i->Aux.FunctionDefinition.PointerToNextFunction); + WriteZeros(sizeof(i->Aux.FunctionDefinition.unused)); + break; + case ATbfAndefSymbol: + WriteZeros(sizeof(i->Aux.bfAndefSymbol.unused1)); + WriteLE16(i->Aux.bfAndefSymbol.Linenumber); + WriteZeros(sizeof(i->Aux.bfAndefSymbol.unused2)); + WriteLE32(i->Aux.bfAndefSymbol.PointerToNextFunction); + WriteZeros(sizeof(i->Aux.bfAndefSymbol.unused3)); + break; + case ATWeakExternal: + WriteLE32(i->Aux.WeakExternal.TagIndex); + WriteLE32(i->Aux.WeakExternal.Characteristics); + WriteZeros(sizeof(i->Aux.WeakExternal.unused)); + break; + case ATFile: + WriteBytes(StringRef(reinterpret_cast(i->Aux.File.FileName), + sizeof(i->Aux.File.FileName))); + break; + case ATSectionDefinition: + WriteLE32(i->Aux.SectionDefinition.Length); + WriteLE16(i->Aux.SectionDefinition.NumberOfRelocations); + WriteLE16(i->Aux.SectionDefinition.NumberOfLinenumbers); + WriteLE32(i->Aux.SectionDefinition.CheckSum); + WriteLE16(i->Aux.SectionDefinition.Number); + Write8(i->Aux.SectionDefinition.Selection); + WriteZeros(sizeof(i->Aux.SectionDefinition.unused)); + break; + } + } +} + +void WinCOFFObjectWriter::WriteSectionHeader(const COFF::section &S) { + WriteBytes(StringRef(S.Name, COFF::NameSize)); + + WriteLE32(S.VirtualSize); + WriteLE32(S.VirtualAddress); + WriteLE32(S.SizeOfRawData); + WriteLE32(S.PointerToRawData); + WriteLE32(S.PointerToRelocations); + WriteLE32(S.PointerToLineNumbers); + WriteLE16(S.NumberOfRelocations); + WriteLE16(S.NumberOfLineNumbers); + WriteLE32(S.Characteristics); +} + +void WinCOFFObjectWriter::WriteRelocation(const COFF::relocation &R) { + WriteLE32(R.VirtualAddress); + WriteLE32(R.SymbolTableIndex); + WriteLE16(R.Type); } //////////////////////////////////////////////////////////////////////////////// // MCObjectWriter interface implementations void WinCOFFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { + // "Define" each section & symbol. This creates section & symbol + // entries in the staging area and gives them their final indexes. + + for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; i++) + DefineSection(*i); + + for (MCAssembler::const_symbol_iterator i = Asm.symbol_begin(), + e = Asm.symbol_end(); i != e; i++) { + if (ExportSymbol(*i, Asm)) + DefineSymbol(*i, Asm); + } } void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, @@ -55,17 +566,209 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { + assert(Target.getSymA() != NULL && "Relocation must reference a symbol!"); + + const MCSymbol *A = &Target.getSymA()->getSymbol(); + MCSymbolData &A_SD = Asm.getSymbolData(*A); + + MCSectionData const *SectionData = Fragment->getParent(); + + // Mark this symbol as requiring an entry in the symbol table. + assert(SectionMap.find(SectionData) != SectionMap.end() && + "Section must already have been defined in ExecutePostLayoutBinding!"); + assert(SymbolMap.find(&A_SD) != SymbolMap.end() && + "Symbol must already have been defined in ExecutePostLayoutBinding!"); + + COFFSection *coff_section = SectionMap[SectionData]; + COFFSymbol *coff_symbol = SymbolMap[&A_SD]; + + if (Target.getSymB()) { + const MCSymbol *B = &Target.getSymB()->getSymbol(); + MCSymbolData &B_SD = Asm.getSymbolData(*B); + + FixedValue = Layout.getSymbolAddress(&A_SD) - Layout.getSymbolAddress(&B_SD); + + // In the case where we have SymbA and SymB, we just need to store the delta + // between the two symbols. Update FixedValue to account for the delta, and + // skip recording the relocation. + return; + } else { + FixedValue = Target.getConstant(); + } + + COFFRelocation Reloc; + + Reloc.Data.SymbolTableIndex = 0; + Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment); + Reloc.Symb = coff_symbol; + + Reloc.Data.VirtualAddress += Fixup.getOffset(); + + switch (Fixup.getKind()) { + case X86::reloc_pcrel_4byte: + case X86::reloc_riprel_4byte: + case X86::reloc_riprel_4byte_movq_load: + Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_REL32 + : COFF::IMAGE_REL_I386_REL32; + // FIXME: Can anyone explain what this does other than adjust for the size + // of the offset? + FixedValue += 4; + break; + case FK_Data_4: + Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_ADDR32 + : COFF::IMAGE_REL_I386_DIR32; + break; + case FK_Data_8: + if (Is64Bit) + Reloc.Data.Type = COFF::IMAGE_REL_AMD64_ADDR64; + else + llvm_unreachable("unsupported relocation type"); + break; + default: + llvm_unreachable("unsupported relocation type"); + } + + coff_section->Relocations.push_back(Reloc); } void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout) { + // Assign symbol and section indexes and offsets. + + Header.NumberOfSymbols = 0; + + for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) { + COFFSymbol *coff_symbol = *i; + MCSymbolData const *SymbolData = coff_symbol->MCData; + + coff_symbol->Index = Header.NumberOfSymbols++; + + // Update section number & offset for symbols that have them. + if ((SymbolData != NULL) && (SymbolData->Fragment != NULL)) { + COFFSection *coff_section = SectionMap[SymbolData->Fragment->getParent()]; + + coff_symbol->Data.SectionNumber = coff_section->Number; + coff_symbol->Data.Value = Layout.getFragmentOffset(SymbolData->Fragment) + + SymbolData->Offset; + } + + // Update auxiliary symbol info. + coff_symbol->Data.NumberOfAuxSymbols = coff_symbol->Aux.size(); + Header.NumberOfSymbols += coff_symbol->Data.NumberOfAuxSymbols; + } + + // Fixup weak external references. + for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) { + COFFSymbol *symb = *i; + + if (symb->Other != NULL) { + assert(symb->Aux.size() == 1 && + "Symbol must contain one aux symbol!"); + assert(symb->Aux[0].AuxType == ATWeakExternal && + "Symbol's aux symbol must be a Weak External!"); + symb->Aux[0].Aux.WeakExternal.TagIndex = symb->Other->Index; + } + } + + // Assign file offsets to COFF object file structures. + + unsigned offset = 0; + + offset += COFF::HeaderSize; + offset += COFF::SectionSize * Asm.size(); + + Header.NumberOfSections = Sections.size(); + + for (MCAssembler::const_iterator i = Asm.begin(), + e = Asm.end(); + i != e; i++) { + COFFSection *Sec = SectionMap[i]; + + Sec->Header.SizeOfRawData = Layout.getSectionFileSize(i); + + if (ExportSection(Sec)) { + Sec->Header.PointerToRawData = offset; + + offset += Sec->Header.SizeOfRawData; + } + + if (Sec->Relocations.size() > 0) { + Sec->Header.NumberOfRelocations = Sec->Relocations.size(); + Sec->Header.PointerToRelocations = offset; + + offset += COFF::RelocationSize * Sec->Relocations.size(); + + for (relocations::iterator cr = Sec->Relocations.begin(), + er = Sec->Relocations.end(); + cr != er; cr++) { + (*cr).Data.SymbolTableIndex = (*cr).Symb->Index; + } + } + + assert(Sec->Symb->Aux.size() == 1 && "Section's symbol must have one aux!"); + AuxSymbol &Aux = Sec->Symb->Aux[0]; + assert(Aux.AuxType == ATSectionDefinition && + "Section's symbol's aux symbol must be a Section Definition!"); + Aux.Aux.SectionDefinition.Length = Sec->Header.SizeOfRawData; + Aux.Aux.SectionDefinition.NumberOfRelocations = + Sec->Header.NumberOfRelocations; + Aux.Aux.SectionDefinition.NumberOfLinenumbers = + Sec->Header.NumberOfLineNumbers; + } + + Header.PointerToSymbolTable = offset; + + Header.TimeDateStamp = sys::TimeValue::now().toEpochTime(); + + // Write it all to disk... + WriteFileHeader(Header); + + { + sections::iterator i, ie; + MCAssembler::const_iterator j, je; + + for (i = Sections.begin(), ie = Sections.end(); i != ie; i++) + WriteSectionHeader((*i)->Header); + + for (i = Sections.begin(), ie = Sections.end(), + j = Asm.begin(), je = Asm.end(); + (i != ie) && (j != je); i++, j++) { + if ((*i)->Header.PointerToRawData != 0) { + assert(OS.tell() == (*i)->Header.PointerToRawData && + "Section::PointerToRawData is insane!"); + + Asm.WriteSectionData(j, Layout, this); + } + + if ((*i)->Relocations.size() > 0) { + assert(OS.tell() == (*i)->Header.PointerToRelocations && + "Section::PointerToRelocations is insane!"); + + for (relocations::const_iterator k = (*i)->Relocations.begin(), + ke = (*i)->Relocations.end(); + k != ke; k++) { + WriteRelocation(k->Data); + } + } else + assert((*i)->Header.PointerToRelocations == 0 && + "Section::PointerToRelocations is insane!"); + } + } + + assert(OS.tell() == Header.PointerToSymbolTable && + "Header::PointerToSymbolTable is insane!"); + + for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) + WriteSymbol(*i); + + OS.write((char const *)&Strings.Data.front(), Strings.Data.size()); } //------------------------------------------------------------------------------ // WinCOFFObjectWriter factory function namespace llvm { - MCObjectWriter *createWinCOFFObjectWriter(raw_ostream &OS) { - return new WinCOFFObjectWriter(OS); + MCObjectWriter *createWinCOFFObjectWriter(raw_ostream &OS, bool is64Bit) { + return new WinCOFFObjectWriter(OS, is64Bit); } } diff --git a/lib/MC/WinCOFFStreamer.cpp b/lib/MC/WinCOFFStreamer.cpp index 1030cdb..8a194bf 100644 --- a/lib/MC/WinCOFFStreamer.cpp +++ b/lib/MC/WinCOFFStreamer.cpp @@ -18,27 +18,34 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCValue.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCSectionCOFF.h" +#include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetAsmBackend.h" +#include "llvm/ADT/StringMap.h" + #include "llvm/Support/COFF.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; -#define dbg_notimpl(x) \ - do { dbgs() << "not implemented, " << __FUNCTION__ << " (" << x << ")"; \ - abort(); } while (false); - namespace { class WinCOFFStreamer : public MCObjectStreamer { public: + MCSymbol const *CurSymbol; + WinCOFFStreamer(MCContext &Context, TargetAsmBackend &TAB, MCCodeEmitter &CE, raw_ostream &OS); + void AddCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment, bool External); + // MCStreamer interface virtual void EmitLabel(MCSymbol *Symbol); @@ -52,18 +59,18 @@ public: virtual void EndCOFFSymbolDef(); virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value); virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment); + unsigned ByteAlignment); virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol, - unsigned Size,unsigned ByteAlignment); + unsigned Size,unsigned ByteAlignment); virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, - uint64_t Size, unsigned ByteAlignment); + uint64_t Size, unsigned ByteAlignment); virtual void EmitBytes(StringRef Data, unsigned AddrSpace); - virtual void EmitValue(const MCExpr *Value, unsigned Size, + virtual void EmitValue(const MCExpr *Value, unsigned Size, unsigned AddrSpace); virtual void EmitGPRel32Value(const MCExpr *Value); virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, - unsigned ValueSize, unsigned MaxBytesToEmit); + unsigned ValueSize, unsigned MaxBytesToEmit); virtual void EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit); virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value); @@ -78,96 +85,224 @@ WinCOFFStreamer::WinCOFFStreamer(MCContext &Context, TargetAsmBackend &TAB, MCCodeEmitter &CE, raw_ostream &OS) - : MCObjectStreamer(Context, TAB, OS, &CE) { + : MCObjectStreamer(Context, TAB, OS, &CE) + , CurSymbol(NULL) { +} + +void WinCOFFStreamer::AddCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment, bool External) { + assert(!Symbol->isInSection() && "Symbol must not already have a section!"); + + std::string SectionName(".bss$linkonce"); + SectionName.append(Symbol->getName().begin(), Symbol->getName().end()); + + MCSymbolData &SymbolData = getAssembler().getOrCreateSymbolData(*Symbol); + + unsigned Characteristics = + COFF::IMAGE_SCN_LNK_COMDAT | + COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_WRITE; + + int Selection = COFF::IMAGE_COMDAT_SELECT_LARGEST; + + const MCSection *Section = MCStreamer::getContext().getCOFFSection( + SectionName, Characteristics, Selection, SectionKind::getBSS()); + + MCSectionData &SectionData = getAssembler().getOrCreateSectionData(*Section); + + if (SectionData.getAlignment() < ByteAlignment) + SectionData.setAlignment(ByteAlignment); + + SymbolData.setExternal(External); + + Symbol->setSection(*Section); + + if (ByteAlignment != 1) + new MCAlignFragment(ByteAlignment, 0, 0, ByteAlignment, &SectionData); + + SymbolData.setFragment(new MCFillFragment(0, 0, Size, &SectionData)); } // MCStreamer interface void WinCOFFStreamer::EmitLabel(MCSymbol *Symbol) { + // TODO: This is copied almost exactly from the MachOStreamer. Consider + // merging into MCObjectStreamer? + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); + assert(CurSection && "Cannot emit before setting section!"); + + Symbol->setSection(*CurSection); + + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + // FIXME: This is wasteful, we don't necessarily need to create a data + // fragment. Instead, we should mark the symbol as pointing into the data + // fragment if it exists, otherwise we should just queue the label and set its + // fragment pointer when we emit the next fragment. + MCDataFragment *DF = getOrCreateDataFragment(); + + assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); + SD.setFragment(DF); + SD.setOffset(DF->getContents().size()); } void WinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { - dbg_notimpl("Flag = " << Flag); + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + // TODO: This is exactly the same as MachOStreamer. Consider merging into + // MCObjectStreamer. + getAssembler().getOrCreateSymbolData(*Symbol); + AddValueSymbols(Value); + Symbol->setVariableValue(Value); } void WinCOFFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { + switch (Attribute) { + case MCSA_WeakReference: + getAssembler().getOrCreateSymbolData(*Symbol).modifyFlags( + COFF::SF_WeakReference, + COFF::SF_WeakReference); + break; + + case MCSA_Global: + getAssembler().getOrCreateSymbolData(*Symbol).setExternal(true); + break; + + default: + llvm_unreachable("unsupported attribute"); + break; + } } void WinCOFFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { - dbg_notimpl("Symbol = " << Symbol->getName() << ", DescValue = "<< DescValue); + llvm_unreachable("not implemented"); } void WinCOFFStreamer::BeginCOFFSymbolDef(MCSymbol const *Symbol) { + assert(CurSymbol == NULL && "EndCOFFSymbolDef must be called between calls " + "to BeginCOFFSymbolDef!"); + CurSymbol = Symbol; } void WinCOFFStreamer::EmitCOFFSymbolStorageClass(int StorageClass) { + assert(CurSymbol != NULL && "BeginCOFFSymbolDef must be called first!"); + assert((StorageClass & ~0xFF) == 0 && "StorageClass must only have data in " + "the first byte!"); + + getAssembler().getOrCreateSymbolData(*CurSymbol).modifyFlags( + StorageClass << COFF::SF_ClassShift, + COFF::SF_ClassMask); } void WinCOFFStreamer::EmitCOFFSymbolType(int Type) { + assert(CurSymbol != NULL && "BeginCOFFSymbolDef must be called first!"); + assert((Type & ~0xFFFF) == 0 && "Type must only have data in the first 2 " + "bytes"); + + getAssembler().getOrCreateSymbolData(*CurSymbol).modifyFlags( + Type << COFF::SF_TypeShift, + COFF::SF_TypeMask); } void WinCOFFStreamer::EndCOFFSymbolDef() { + assert(CurSymbol != NULL && "BeginCOFFSymbolDef must be called first!"); + CurSymbol = NULL; } void WinCOFFStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { - dbg_notimpl("Symbol = " << Symbol->getName() << ", Value = " << *Value); + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment) { + unsigned ByteAlignment) { + AddCommonSymbol(Symbol, Size, ByteAlignment, true); } void WinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + AddCommonSymbol(Symbol, Size, 1, false); } void WinCOFFStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, - unsigned Size,unsigned ByteAlignment) { - MCSectionCOFF const *SectionCOFF = - static_cast(Section); - - dbg_notimpl("Section = " << SectionCOFF->getSectionName() << ", Symbol = " << - Symbol->getName() << ", Size = " << Size << ", ByteAlignment = " - << ByteAlignment); + unsigned Size,unsigned ByteAlignment) { + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { - MCSectionCOFF const *SectionCOFF = - static_cast(Section); - - dbg_notimpl("Section = " << SectionCOFF->getSectionName() << ", Symbol = " << - Symbol->getName() << ", Size = " << Size << ", ByteAlignment = " - << ByteAlignment); + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { + // TODO: This is copied exactly from the MachOStreamer. Consider merging into + // MCObjectStreamer? + getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); } void WinCOFFStreamer::EmitValue(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) { + unsigned AddrSpace) { + assert(AddrSpace == 0 && "Address space must be 0!"); + + // TODO: This is copied exactly from the MachOStreamer. Consider merging into + // MCObjectStreamer? + MCDataFragment *DF = getOrCreateDataFragment(); + + // Avoid fixups when possible. + int64_t AbsValue; + if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue)) { + // FIXME: Endianness assumption. + for (unsigned i = 0; i != Size; ++i) + DF->getContents().push_back(uint8_t(AbsValue >> (i * 8))); + } else { + DF->addFixup(MCFixup::Create(DF->getContents().size(), + AddValueSymbols(Value), + MCFixup::getKindForSize(Size))); + DF->getContents().resize(DF->getContents().size() + Size, 0); + } } void WinCOFFStreamer::EmitGPRel32Value(const MCExpr *Value) { - dbg_notimpl("Value = '" << *Value); + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitValueToAlignment(unsigned ByteAlignment, - int64_t Value, - unsigned ValueSize, - unsigned MaxBytesToEmit) { + int64_t Value, + unsigned ValueSize, + unsigned MaxBytesToEmit) { + // TODO: This is copied exactly from the MachOStreamer. Consider merging into + // MCObjectStreamer? + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit, + getCurrentSectionData()); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); } void WinCOFFStreamer::EmitCodeAlignment(unsigned ByteAlignment, - unsigned MaxBytesToEmit = 0) { + unsigned MaxBytesToEmit) { + // TODO: This is copied exactly from the MachOStreamer. Consider merging into + // MCObjectStreamer? + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + MCAlignFragment *F = new MCAlignFragment(ByteAlignment, 0, 1, MaxBytesToEmit, + getCurrentSectionData()); + F->setEmitNops(true); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); } void WinCOFFStreamer::EmitValueToOffset(const MCExpr *Offset, - unsigned char Value = 0) { - dbg_notimpl("Offset = '" << *Offset << "', Value = " << Value); + unsigned char Value) { + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitFileDirective(StringRef Filename) { @@ -176,11 +311,24 @@ void WinCOFFStreamer::EmitFileDirective(StringRef Filename) { } void WinCOFFStreamer::EmitDwarfFileDirective(unsigned FileNo, - StringRef Filename) { - dbg_notimpl("FileNo = " << FileNo << ", Filename = '" << Filename << "'"); + StringRef Filename) { + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitInstruction(const MCInst &Instruction) { + for (unsigned i = 0, e = Instruction.getNumOperands(); i != e; ++i) + if (Instruction.getOperand(i).isExpr()) + AddValueSymbols(Instruction.getOperand(i).getExpr()); + + getCurrentSectionData()->setHasInstructions(true); + + MCInstFragment *Fragment = + new MCInstFragment(Instruction, getCurrentSectionData()); + + raw_svector_ostream VecOS(Fragment->getCode()); + + getAssembler().getEmitter().EncodeInstruction(Instruction, VecOS, + Fragment->getFixups()); } void WinCOFFStreamer::Finish() { @@ -192,7 +340,10 @@ namespace llvm MCStreamer *createWinCOFFStreamer(MCContext &Context, TargetAsmBackend &TAB, MCCodeEmitter &CE, - raw_ostream &OS) { - return new WinCOFFStreamer(Context, TAB, CE, OS); + raw_ostream &OS, + bool RelaxAll) { + WinCOFFStreamer *S = new WinCOFFStreamer(Context, TAB, CE, OS); + S->getAssembler().setRelaxAll(RelaxAll); + return S; } } diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index 2e78557..b87ddf9 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -153,6 +153,7 @@ readExponent(StringRef::iterator begin, StringRef::iterator end) value += absExponent * 10; if (absExponent >= overlargeExponent) { absExponent = overlargeExponent; + p = end; /* outwit assert below */ break; } absExponent = value; diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index 262fa42..8a212a2 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -2123,15 +2123,16 @@ void APInt::toString(SmallVectorImpl &Str, unsigned Radix, char *BufPtr = Buffer+65; uint64_t N; - if (Signed) { + if (!Signed) { + N = getZExtValue(); + } else { int64_t I = getSExtValue(); - if (I < 0) { + if (I >= 0) { + N = I; + } else { Str.push_back('-'); - I = -I; + N = -(uint64_t)I; } - N = I; - } else { - N = getZExtValue(); } while (N) { diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt index 366d2f7..0c70a40 100644 --- a/lib/Support/CMakeLists.txt +++ b/lib/Support/CMakeLists.txt @@ -6,6 +6,7 @@ add_llvm_library(LLVMSupport circular_raw_ostream.cpp CommandLine.cpp ConstantRange.cpp + CrashRecoveryContext.cpp Debug.cpp DeltaAlgorithm.cpp DAGDeltaAlgorithm.cpp @@ -23,7 +24,6 @@ add_llvm_library(LLVMSupport PluginLoader.cpp PrettyStackTrace.cpp Regex.cpp - SlowOperationInformer.cpp SmallPtrSet.cpp SmallVector.cpp SourceMgr.cpp diff --git a/lib/Support/ConstantRange.cpp b/lib/Support/ConstantRange.cpp index 2746f7a..8ef3785 100644 --- a/lib/Support/ConstantRange.cpp +++ b/lib/Support/ConstantRange.cpp @@ -21,6 +21,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Constants.h" #include "llvm/Support/ConstantRange.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -38,7 +39,7 @@ ConstantRange::ConstantRange(uint32_t BitWidth, bool Full) { /// Initialize a range to hold the single specified value. /// -ConstantRange::ConstantRange(const APInt & V) : Lower(V), Upper(V + 1) {} +ConstantRange::ConstantRange(const APInt &V) : Lower(V), Upper(V + 1) {} ConstantRange::ConstantRange(const APInt &L, const APInt &U) : Lower(L), Upper(U) { @@ -202,14 +203,12 @@ bool ConstantRange::contains(const APInt &V) const { } /// contains - Return true if the argument is a subset of this range. -/// Two equal set contain each other. The empty set is considered to be -/// contained by all other sets. +/// Two equal sets contain each other. The empty set contained by all other +/// sets. /// bool ConstantRange::contains(const ConstantRange &Other) const { - if (isFullSet()) return true; - if (Other.isFullSet()) return false; - if (Other.isEmptySet()) return true; - if (isEmptySet()) return false; + if (isFullSet() || Other.isEmptySet()) return true; + if (isEmptySet() || Other.isFullSet()) return false; if (!isWrappedSet()) { if (Other.isWrappedSet()) @@ -235,46 +234,6 @@ ConstantRange ConstantRange::subtract(const APInt &Val) const { return ConstantRange(Lower - Val, Upper - Val); } - -// intersect1Wrapped - This helper function is used to intersect two ranges when -// it is known that LHS is wrapped and RHS isn't. -// -ConstantRange -ConstantRange::intersect1Wrapped(const ConstantRange &LHS, - const ConstantRange &RHS) { - assert(LHS.isWrappedSet() && !RHS.isWrappedSet()); - - // Check to see if we overlap on the Left side of RHS... - // - if (RHS.Lower.ult(LHS.Upper)) { - // We do overlap on the left side of RHS, see if we overlap on the right of - // RHS... - if (RHS.Upper.ugt(LHS.Lower)) { - // Ok, the result overlaps on both the left and right sides. See if the - // resultant interval will be smaller if we wrap or not... - // - if (LHS.getSetSize().ult(RHS.getSetSize())) - return LHS; - else - return RHS; - - } else { - // No overlap on the right, just on the left. - return ConstantRange(RHS.Lower, LHS.Upper); - } - } else { - // We don't overlap on the left side of RHS, see if we overlap on the right - // of RHS... - if (RHS.Upper.ugt(LHS.Lower)) { - // Simple overlap... - return ConstantRange(LHS.Lower, RHS.Upper); - } else { - // No overlap... - return ConstantRange(LHS.getBitWidth(), false); - } - } -} - /// intersectWith - Return the range that results from the intersection of this /// range with another range. The resultant range is guaranteed to include all /// elements contained in both input ranges, and to have the smallest possible @@ -486,7 +445,7 @@ ConstantRange ConstantRange::truncate(uint32_t DstTySize) const { assert(SrcTySize > DstTySize && "Not a value truncation"); APInt Size(APInt::getLowBitsSet(SrcTySize, DstTySize)); if (isFullSet() || getSetSize().ugt(Size)) - return ConstantRange(DstTySize); + return ConstantRange(DstTySize, /*isFullSet=*/true); APInt L = Lower; L.trunc(DstTySize); APInt U = Upper; U.trunc(DstTySize); @@ -539,6 +498,27 @@ ConstantRange::add(const ConstantRange &Other) const { } ConstantRange +ConstantRange::sub(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + if (isFullSet() || Other.isFullSet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + APInt Spread_X = getSetSize(), Spread_Y = Other.getSetSize(); + APInt NewLower = getLower() - Other.getLower(); + APInt NewUpper = getUpper() - Other.getUpper() + 1; + if (NewLower == NewUpper) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + ConstantRange X = ConstantRange(NewLower, NewUpper); + if (X.getSetSize().ult(Spread_X) || X.getSetSize().ult(Spread_Y)) + // We've wrapped, therefore, full set. + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + + return X; +} + +ConstantRange ConstantRange::multiply(const ConstantRange &Other) const { // TODO: If either operand is a single element and the multiply is known to // be non-wrapping, round the result min and max value to the appropriate @@ -616,40 +596,42 @@ ConstantRange::udiv(const ConstantRange &RHS) const { } ConstantRange -ConstantRange::shl(const ConstantRange &Amount) const { - if (isEmptySet()) - return *this; +ConstantRange::shl(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); - APInt min = getUnsignedMin() << Amount.getUnsignedMin(); - APInt max = getUnsignedMax() << Amount.getUnsignedMax(); + APInt min = getUnsignedMin().shl(Other.getUnsignedMin()); + APInt max = getUnsignedMax().shl(Other.getUnsignedMax()); // there's no overflow! APInt Zeros(getBitWidth(), getUnsignedMax().countLeadingZeros()); - if (Zeros.uge(Amount.getUnsignedMax())) - return ConstantRange(min, max); + if (Zeros.ugt(Other.getUnsignedMax())) + return ConstantRange(min, max + 1); // FIXME: implement the other tricky cases - return ConstantRange(getBitWidth()); + return ConstantRange(getBitWidth(), /*isFullSet=*/true); } ConstantRange -ConstantRange::ashr(const ConstantRange &Amount) const { - if (isEmptySet()) - return *this; +ConstantRange::lshr(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + + APInt max = getUnsignedMax().lshr(Other.getUnsignedMin()); + APInt min = getUnsignedMin().lshr(Other.getUnsignedMax()); + if (min == max + 1) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); - APInt min = getUnsignedMax().ashr(Amount.getUnsignedMin()); - APInt max = getUnsignedMin().ashr(Amount.getUnsignedMax()); - return ConstantRange(min, max); + return ConstantRange(min, max + 1); } -ConstantRange -ConstantRange::lshr(const ConstantRange &Amount) const { - if (isEmptySet()) - return *this; - - APInt min = getUnsignedMax().lshr(Amount.getUnsignedMin()); - APInt max = getUnsignedMin().lshr(Amount.getUnsignedMax()); - return ConstantRange(min, max); +ConstantRange ConstantRange::inverse() const { + if (isFullSet()) { + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + } else if (isEmptySet()) { + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + } + return ConstantRange(Upper, Lower); } /// print - Print out the bounds to a stream... @@ -668,5 +650,3 @@ void ConstantRange::print(raw_ostream &OS) const { void ConstantRange::dump() const { print(dbgs()); } - - diff --git a/lib/Support/CrashRecoveryContext.cpp b/lib/Support/CrashRecoveryContext.cpp new file mode 100644 index 0000000..49258ede --- /dev/null +++ b/lib/Support/CrashRecoveryContext.cpp @@ -0,0 +1,204 @@ +//===--- CrashRecoveryContext.cpp - Crash Recovery ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Config/config.h" +#include "llvm/System/Mutex.h" +#include "llvm/System/ThreadLocal.h" +#include +#include +using namespace llvm; + +namespace { + +struct CrashRecoveryContextImpl; + +static sys::ThreadLocal CurrentContext; + +struct CrashRecoveryContextImpl { + CrashRecoveryContext *CRC; + std::string Backtrace; + ::jmp_buf JumpBuffer; + volatile unsigned Failed : 1; + +public: + CrashRecoveryContextImpl(CrashRecoveryContext *CRC) : CRC(CRC), + Failed(false) { + CurrentContext.set(this); + } + ~CrashRecoveryContextImpl() { + CurrentContext.erase(); + } + + void HandleCrash() { + // Eliminate the current context entry, to avoid re-entering in case the + // cleanup code crashes. + CurrentContext.erase(); + + assert(!Failed && "Crash recovery context already failed!"); + Failed = true; + + // FIXME: Stash the backtrace. + + // Jump back to the RunSafely we were called under. + longjmp(JumpBuffer, 1); + } +}; + +} + +static sys::Mutex gCrashRecoveryContexMutex; +static bool gCrashRecoveryEnabled = false; + +CrashRecoveryContext::~CrashRecoveryContext() { + CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; + delete CRCI; +} + +CrashRecoveryContext *CrashRecoveryContext::GetCurrent() { + const CrashRecoveryContextImpl *CRCI = CurrentContext.get(); + if (!CRCI) + return 0; + + return CRCI->CRC; +} + +#ifdef LLVM_ON_WIN32 + +// FIXME: No real Win32 implementation currently. + +void CrashRecoveryContext::Enable() { + sys::ScopedLock L(gCrashRecoveryContexMutex); + + if (gCrashRecoveryEnabled) + return; + + gCrashRecoveryEnabled = true; +} + +void CrashRecoveryContext::Disable() { + sys::ScopedLock L(gCrashRecoveryContexMutex); + + if (!gCrashRecoveryEnabled) + return; + + gCrashRecoveryEnabled = false; +} + +#else + +// Generic POSIX implementation. +// +// This implementation relies on synchronous signals being delivered to the +// current thread. We use a thread local object to keep track of the active +// crash recovery context, and install signal handlers to invoke HandleCrash on +// the active object. +// +// This implementation does not to attempt to chain signal handlers in any +// reliable fashion -- if we get a signal outside of a crash recovery context we +// simply disable crash recovery and raise the signal again. + +#include + +static int Signals[] = { SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGTRAP }; +static const unsigned NumSignals = sizeof(Signals) / sizeof(Signals[0]); +static struct sigaction PrevActions[NumSignals]; + +static void CrashRecoverySignalHandler(int Signal) { + // Lookup the current thread local recovery object. + const CrashRecoveryContextImpl *CRCI = CurrentContext.get(); + + if (!CRCI) { + // We didn't find a crash recovery context -- this means either we got a + // signal on a thread we didn't expect it on, the application got a signal + // outside of a crash recovery context, or something else went horribly + // wrong. + // + // Disable crash recovery and raise the signal again. The assumption here is + // that the enclosing application will terminate soon, and we won't want to + // attempt crash recovery again. + // + // This call of Disable isn't thread safe, but it doesn't actually matter. + CrashRecoveryContext::Disable(); + raise(Signal); + } + + // Unblock the signal we received. + sigset_t SigMask; + sigemptyset(&SigMask); + sigaddset(&SigMask, Signal); + sigprocmask(SIG_UNBLOCK, &SigMask, 0); + + if (CRCI) + const_cast(CRCI)->HandleCrash(); +} + +void CrashRecoveryContext::Enable() { + sys::ScopedLock L(gCrashRecoveryContexMutex); + + if (gCrashRecoveryEnabled) + return; + + gCrashRecoveryEnabled = true; + + // Setup the signal handler. + struct sigaction Handler; + Handler.sa_handler = CrashRecoverySignalHandler; + Handler.sa_flags = 0; + sigemptyset(&Handler.sa_mask); + + for (unsigned i = 0; i != NumSignals; ++i) { + sigaction(Signals[i], &Handler, &PrevActions[i]); + } +} + +void CrashRecoveryContext::Disable() { + sys::ScopedLock L(gCrashRecoveryContexMutex); + + if (!gCrashRecoveryEnabled) + return; + + gCrashRecoveryEnabled = false; + + // Restore the previous signal handlers. + for (unsigned i = 0; i != NumSignals; ++i) + sigaction(Signals[i], &PrevActions[i], 0); +} + +#endif + +bool CrashRecoveryContext::RunSafely(void (*Fn)(void*), void *UserData) { + // If crash recovery is disabled, do nothing. + if (gCrashRecoveryEnabled) { + assert(!Impl && "Crash recovery context already initialized!"); + CrashRecoveryContextImpl *CRCI = new CrashRecoveryContextImpl(this); + Impl = CRCI; + + if (setjmp(CRCI->JumpBuffer) != 0) { + return false; + } + } + + Fn(UserData); + return true; +} + +void CrashRecoveryContext::HandleCrash() { + CrashRecoveryContextImpl *CRCI = (CrashRecoveryContextImpl *) Impl; + assert(CRCI && "Crash recovery context never initialized!"); + CRCI->HandleCrash(); +} + +const std::string &CrashRecoveryContext::getBacktrace() const { + CrashRecoveryContextImpl *CRC = (CrashRecoveryContextImpl *) Impl; + assert(CRC && "Crash recovery context never initialized!"); + assert(CRC->Failed && "No crash was detected!"); + return CRC->Backtrace; +} diff --git a/lib/Support/ErrorHandling.cpp b/lib/Support/ErrorHandling.cpp index 7e7ca9d..0b7af3e 100644 --- a/lib/Support/ErrorHandling.cpp +++ b/lib/Support/ErrorHandling.cpp @@ -18,8 +18,19 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/System/Signals.h" #include "llvm/System/Threading.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Config/config.h" #include #include + +#if defined(HAVE_UNISTD_H) +# include +#endif +#if defined(_MSC_VER) +# include +# include +#endif + using namespace llvm; using namespace std; @@ -39,19 +50,26 @@ void llvm::remove_fatal_error_handler() { ErrorHandler = 0; } -void llvm::report_fatal_error(const char *reason) { - report_fatal_error(Twine(reason)); +void llvm::report_fatal_error(const char *Reason) { + report_fatal_error(Twine(Reason)); } -void llvm::report_fatal_error(const std::string &reason) { - report_fatal_error(Twine(reason)); +void llvm::report_fatal_error(const std::string &Reason) { + report_fatal_error(Twine(Reason)); } -void llvm::report_fatal_error(const Twine &reason) { - if (!ErrorHandler) { - errs() << "LLVM ERROR: " << reason << "\n"; +void llvm::report_fatal_error(const Twine &Reason) { + if (ErrorHandler) { + ErrorHandler(ErrorHandlerUserData, Reason.str()); } else { - ErrorHandler(ErrorHandlerUserData, reason.str()); + // Blast the result out to stderr. We don't try hard to make sure this + // succeeds (e.g. handling EINTR) and we can't use errs() here because + // raw ostreams can call report_fatal_error. + SmallVector Buffer; + raw_svector_ostream OS(Buffer); + OS << "LLVM ERROR: " << Reason << "\n"; + StringRef MessageStr = OS.str(); + (void)::write(2, MessageStr.data(), MessageStr.size()); } // If we reached here, we are failing ungracefully. Run the interrupt handlers diff --git a/lib/Support/FoldingSet.cpp b/lib/Support/FoldingSet.cpp index b8dca33..29b5952 100644 --- a/lib/Support/FoldingSet.cpp +++ b/lib/Support/FoldingSet.cpp @@ -23,6 +23,37 @@ using namespace llvm; //===----------------------------------------------------------------------===// +// FoldingSetNodeIDRef Implementation + +/// ComputeHash - Compute a strong hash value for this FoldingSetNodeIDRef, +/// used to lookup the node in the FoldingSetImpl. +unsigned FoldingSetNodeIDRef::ComputeHash() const { + // This is adapted from SuperFastHash by Paul Hsieh. + unsigned Hash = static_cast(Size); + for (const unsigned *BP = Data, *E = BP+Size; BP != E; ++BP) { + unsigned Data = *BP; + Hash += Data & 0xFFFF; + unsigned Tmp = ((Data >> 16) << 11) ^ Hash; + Hash = (Hash << 16) ^ Tmp; + Hash += Hash >> 11; + } + + // Force "avalanching" of final 127 bits. + Hash ^= Hash << 3; + Hash += Hash >> 5; + Hash ^= Hash << 4; + Hash += Hash >> 17; + Hash ^= Hash << 25; + Hash += Hash >> 6; + return Hash; +} + +bool FoldingSetNodeIDRef::operator==(FoldingSetNodeIDRef RHS) const { + if (Size != RHS.Size) return false; + return memcmp(Data, RHS.Data, Size*sizeof(*Data)) == 0; +} + +//===----------------------------------------------------------------------===// // FoldingSetNodeID Implementation /// Add* - Add various data types to Bit data. @@ -104,31 +135,19 @@ void FoldingSetNodeID::AddString(StringRef String) { /// ComputeHash - Compute a strong hash value for this FoldingSetNodeID, used to /// lookup the node in the FoldingSetImpl. unsigned FoldingSetNodeID::ComputeHash() const { - // This is adapted from SuperFastHash by Paul Hsieh. - unsigned Hash = static_cast(Bits.size()); - for (const unsigned *BP = &Bits[0], *E = BP+Bits.size(); BP != E; ++BP) { - unsigned Data = *BP; - Hash += Data & 0xFFFF; - unsigned Tmp = ((Data >> 16) << 11) ^ Hash; - Hash = (Hash << 16) ^ Tmp; - Hash += Hash >> 11; - } - - // Force "avalanching" of final 127 bits. - Hash ^= Hash << 3; - Hash += Hash >> 5; - Hash ^= Hash << 4; - Hash += Hash >> 17; - Hash ^= Hash << 25; - Hash += Hash >> 6; - return Hash; + return FoldingSetNodeIDRef(Bits.data(), Bits.size()).ComputeHash(); } /// operator== - Used to compare two nodes to each other. /// bool FoldingSetNodeID::operator==(const FoldingSetNodeID &RHS)const{ - if (Bits.size() != RHS.Bits.size()) return false; - return memcmp(&Bits[0], &RHS.Bits[0], Bits.size()*sizeof(Bits[0])) == 0; + return *this == FoldingSetNodeIDRef(RHS.Bits.data(), RHS.Bits.size()); +} + +/// operator== - Used to compare two nodes to each other. +/// +bool FoldingSetNodeID::operator==(FoldingSetNodeIDRef RHS) const { + return FoldingSetNodeIDRef(Bits.data(), Bits.size()) == RHS; } /// Intern - Copy this node's data to a memory region allocated from the @@ -168,10 +187,9 @@ static void **GetBucketPtr(void *NextInBucketPtr) { /// GetBucketFor - Hash the specified node ID and return the hash bucket for /// the specified ID. -static void **GetBucketFor(const FoldingSetNodeID &ID, - void **Buckets, unsigned NumBuckets) { +static void **GetBucketFor(unsigned Hash, void **Buckets, unsigned NumBuckets) { // NumBuckets is always a power of 2. - unsigned BucketNum = ID.ComputeHash() & (NumBuckets-1); + unsigned BucketNum = Hash & (NumBuckets-1); return Buckets + BucketNum; } @@ -219,7 +237,7 @@ void FoldingSetImpl::GrowHashTable() { NumNodes = 0; // Walk the old buckets, rehashing nodes into their new place. - FoldingSetNodeID ID; + FoldingSetNodeID TempID; for (unsigned i = 0; i != OldNumBuckets; ++i) { void *Probe = OldBuckets[i]; if (!Probe) continue; @@ -229,9 +247,10 @@ void FoldingSetImpl::GrowHashTable() { NodeInBucket->SetNextInBucket(0); // Insert the node into the new bucket, after recomputing the hash. - GetNodeProfile(ID, NodeInBucket); - InsertNode(NodeInBucket, GetBucketFor(ID, Buckets, NumBuckets)); - ID.clear(); + InsertNode(NodeInBucket, + GetBucketFor(ComputeNodeHash(NodeInBucket, TempID), + Buckets, NumBuckets)); + TempID.clear(); } } @@ -245,19 +264,18 @@ FoldingSetImpl::Node *FoldingSetImpl::FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) { - void **Bucket = GetBucketFor(ID, Buckets, NumBuckets); + void **Bucket = GetBucketFor(ID.ComputeHash(), Buckets, NumBuckets); void *Probe = *Bucket; InsertPos = 0; - FoldingSetNodeID OtherID; + FoldingSetNodeID TempID; while (Node *NodeInBucket = GetNextPtr(Probe)) { - GetNodeProfile(OtherID, NodeInBucket); - if (OtherID == ID) + if (NodeEquals(NodeInBucket, ID, TempID)) return NodeInBucket; + TempID.clear(); Probe = NodeInBucket->getNextInBucket(); - OtherID.clear(); } // Didn't find the node, return null with the bucket as the InsertPos. @@ -273,9 +291,8 @@ void FoldingSetImpl::InsertNode(Node *N, void *InsertPos) { // Do we need to grow the hashtable? if (NumNodes+1 > NumBuckets*2) { GrowHashTable(); - FoldingSetNodeID ID; - GetNodeProfile(ID, N); - InsertPos = GetBucketFor(ID, Buckets, NumBuckets); + FoldingSetNodeID TempID; + InsertPos = GetBucketFor(ComputeNodeHash(N, TempID), Buckets, NumBuckets); } ++NumNodes; @@ -341,7 +358,7 @@ bool FoldingSetImpl::RemoveNode(Node *N) { /// instead. FoldingSetImpl::Node *FoldingSetImpl::GetOrInsertNode(FoldingSetImpl::Node *N) { FoldingSetNodeID ID; - GetNodeProfile(ID, N); + GetNodeProfile(N, ID); void *IP; if (Node *E = FindNodeOrInsertPos(ID, IP)) return E; diff --git a/lib/Support/PrettyStackTrace.cpp b/lib/Support/PrettyStackTrace.cpp index a99ab2f..3c8a108 100644 --- a/lib/Support/PrettyStackTrace.cpp +++ b/lib/Support/PrettyStackTrace.cpp @@ -72,7 +72,7 @@ asm(".desc ___crashreporter_info__, 0x10"); /// CrashHandler - This callback is run if a fatal signal is delivered to the /// process, it prints the pretty stack trace. -static void CrashHandler(void *Cookie) { +static void CrashHandler(void *) { #ifndef __APPLE__ // On non-apple systems, just emit the crash stack trace to stderr. PrintCurStackTrace(errs()); @@ -89,7 +89,8 @@ static void CrashHandler(void *Cookie) { #ifndef HAVE_CRASHREPORTERCLIENT_H __crashreporter_info__ = strdup(std::string(TmpStr.str()).c_str()); #else - CRSetCrashLogMessage(std::string(TmpStr.str()).c_str()); + // Cast to void to avoid warning. + (void)CRSetCrashLogMessage(std::string(TmpStr.str()).c_str()); #endif errs() << TmpStr.str(); } diff --git a/lib/Support/SlowOperationInformer.cpp b/lib/Support/SlowOperationInformer.cpp deleted file mode 100644 index b4e9430..0000000 --- a/lib/Support/SlowOperationInformer.cpp +++ /dev/null @@ -1,67 +0,0 @@ -//===-- SlowOperationInformer.cpp - Keep the user informed ----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the SlowOperationInformer class for the LLVM debugger. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/SlowOperationInformer.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/System/Alarm.h" -#include -#include -using namespace llvm; - -SlowOperationInformer::SlowOperationInformer(const std::string &Name) - : OperationName(Name), LastPrintAmount(0) { - sys::SetupAlarm(1); -} - -SlowOperationInformer::~SlowOperationInformer() { - sys::TerminateAlarm(); - if (LastPrintAmount) { - // If we have printed something, make _sure_ we print the 100% amount, and - // also print a newline. - outs() << std::string(LastPrintAmount, '\b') << "Progress " - << OperationName << ": 100% \n"; - } -} - -/// progress - Clients should periodically call this method when they are in -/// an exception-safe state. The Amount variable should indicate how far -/// along the operation is, given in 1/10ths of a percent (in other words, -/// Amount should range from 0 to 1000). -bool SlowOperationInformer::progress(unsigned Amount) { - int status = sys::AlarmStatus(); - if (status == -1) { - outs() << "\n"; - LastPrintAmount = 0; - return true; - } - - // If we haven't spent enough time in this operation to warrant displaying the - // progress bar, don't do so yet. - if (status == 0) - return false; - - // Delete whatever we printed last time. - std::string ToPrint = std::string(LastPrintAmount, '\b'); - - std::ostringstream OS; - OS << "Progress " << OperationName << ": " << Amount/10; - if (unsigned Rem = Amount % 10) - OS << "." << Rem << "%"; - else - OS << "% "; - - LastPrintAmount = OS.str().size(); - outs() << ToPrint+OS.str(); - outs().flush(); - return false; -} diff --git a/lib/Support/SmallVector.cpp b/lib/Support/SmallVector.cpp index 2e17af8..a89f149 100644 --- a/lib/Support/SmallVector.cpp +++ b/lib/Support/SmallVector.cpp @@ -18,7 +18,7 @@ using namespace llvm; /// on POD-like datatypes and is out of line to reduce code duplication. void SmallVectorBase::grow_pod(size_t MinSizeInBytes, size_t TSize) { size_t CurSizeBytes = size_in_bytes(); - size_t NewCapacityInBytes = 2 * capacity_in_bytes(); + size_t NewCapacityInBytes = 2 * capacity_in_bytes() + TSize; // Always grow. if (NewCapacityInBytes < MinSizeInBytes) NewCapacityInBytes = MinSizeInBytes; diff --git a/lib/Support/Statistic.cpp b/lib/Support/Statistic.cpp index 7d5f65a..e32ab74 100644 --- a/lib/Support/Statistic.cpp +++ b/lib/Support/Statistic.cpp @@ -44,7 +44,7 @@ Enabled("stats", cl::desc("Enable statistics output from program")); namespace { /// StatisticInfo - This class is used in a ManagedStatic so that it is created -/// on demand (when the first statistic is bumped) and destroyed only when +/// on demand (when the first statistic is bumped) and destroyed only when /// llvm_shutdown is called. We print statistics from the destructor. class StatisticInfo { std::vector Stats; @@ -52,7 +52,7 @@ class StatisticInfo { friend void llvm::PrintStatistics(raw_ostream &OS); public: ~StatisticInfo(); - + void addStatistic(const Statistic *S) { Stats.push_back(S); } @@ -71,7 +71,7 @@ void Statistic::RegisterStatistic() { if (!Initialized) { if (Enabled) StatInfo->addStatistic(this); - + sys::MemoryFence(); // Remember we have been registered. Initialized = true; @@ -84,7 +84,7 @@ struct NameCompare { bool operator()(const Statistic *LHS, const Statistic *RHS) const { int Cmp = std::strcmp(LHS->getName(), RHS->getName()); if (Cmp != 0) return Cmp < 0; - + // Secondary key is the description. return std::strcmp(LHS->getDesc(), RHS->getDesc()) < 0; } @@ -112,7 +112,7 @@ void llvm::PrintStatistics(raw_ostream &OS) { MaxNameLen = std::max(MaxNameLen, (unsigned)std::strlen(Stats.Stats[i]->getName())); } - + // Sort the fields by name. std::stable_sort(Stats.Stats.begin(), Stats.Stats.end(), NameCompare()); @@ -120,7 +120,7 @@ void llvm::PrintStatistics(raw_ostream &OS) { OS << "===" << std::string(73, '-') << "===\n" << " ... Statistics Collected ...\n" << "===" << std::string(73, '-') << "===\n\n"; - + // Print all of the statistics. for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i) { std::string CountStr = utostr(Stats.Stats[i]->getValue()); @@ -129,7 +129,7 @@ void llvm::PrintStatistics(raw_ostream &OS) { << std::string(MaxNameLen-std::strlen(Stats.Stats[i]->getName()), ' ') << " - " << Stats.Stats[i]->getDesc() << "\n"; } - + OS << '\n'; // Flush the output stream. OS.flush(); diff --git a/lib/Support/StringRef.cpp b/lib/Support/StringRef.cpp index ca0f518..46f26b2 100644 --- a/lib/Support/StringRef.cpp +++ b/lib/Support/StringRef.cpp @@ -9,6 +9,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/APInt.h" +#include using namespace llvm; @@ -30,14 +31,14 @@ static bool ascii_isdigit(char x) { /// compare_lower - Compare strings, ignoring case. int StringRef::compare_lower(StringRef RHS) const { for (size_t I = 0, E = min(Length, RHS.Length); I != E; ++I) { - char LHC = ascii_tolower(Data[I]); - char RHC = ascii_tolower(RHS.Data[I]); + unsigned char LHC = ascii_tolower(Data[I]); + unsigned char RHC = ascii_tolower(RHS.Data[I]); if (LHC != RHC) return LHC < RHC ? -1 : 1; } if (Length == RHS.Length) - return 0; + return 0; return Length < RHS.Length ? -1 : 1; } @@ -58,10 +59,10 @@ int StringRef::compare_numeric(StringRef RHS) const { break; } } - return Data[I] < RHS.Data[I] ? -1 : 1; + return (unsigned char)Data[I] < (unsigned char)RHS.Data[I] ? -1 : 1; } if (Length == RHS.Length) - return 0; + return 0; return Length < RHS.Length ? -1 : 1; } @@ -153,11 +154,15 @@ size_t StringRef::rfind(StringRef Str) const { /// find_first_of - Find the first character in the string that is in \arg /// Chars, or npos if not found. /// -/// Note: O(size() * Chars.size()) +/// Note: O(size() + Chars.size()) StringRef::size_type StringRef::find_first_of(StringRef Chars, size_t From) const { + std::bitset<1 << CHAR_BIT> CharBits; + for (size_type i = 0; i != Chars.size(); ++i) + CharBits.set((unsigned char)Chars[i]); + for (size_type i = min(From, Length), e = Length; i != e; ++i) - if (Chars.find(Data[i]) != npos) + if (CharBits.test((unsigned char)Data[i])) return i; return npos; } @@ -174,11 +179,15 @@ StringRef::size_type StringRef::find_first_not_of(char C, size_t From) const { /// find_first_not_of - Find the first character in the string that is not /// in the string \arg Chars, or npos if not found. /// -/// Note: O(size() * Chars.size()) +/// Note: O(size() + Chars.size()) StringRef::size_type StringRef::find_first_not_of(StringRef Chars, size_t From) const { + std::bitset<1 << CHAR_BIT> CharBits; + for (size_type i = 0; i != Chars.size(); ++i) + CharBits.set((unsigned char)Chars[i]); + for (size_type i = min(From, Length), e = Length; i != e; ++i) - if (Chars.find(Data[i]) == npos) + if (!CharBits.test((unsigned char)Data[i])) return i; return npos; } diff --git a/lib/Support/SystemUtils.cpp b/lib/Support/SystemUtils.cpp index 299032f..c8b260c 100644 --- a/lib/Support/SystemUtils.cpp +++ b/lib/Support/SystemUtils.cpp @@ -49,6 +49,16 @@ sys::Path llvm::FindExecutable(const std::string &ExeName, Result.appendComponent(ExeName); if (Result.canExecute()) return Result; + // If the path is absolute (and it usually is), call FindProgramByName to + // allow it to try platform-specific logic, such as appending a .exe suffix + // on Windows. Don't do this if we somehow have a relative path, because + // we don't want to go searching the PATH and accidentally find an unrelated + // version of the program. + if (Result.isAbsolute()) { + Result = sys::Program::FindProgramByName(Result.str()); + if (!Result.empty()) + return Result; + } } return sys::Path(); diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp index 6a70449..3a95b65 100644 --- a/lib/Support/Triple.cpp +++ b/lib/Support/Triple.cpp @@ -221,121 +221,238 @@ const char *Triple::getArchNameForAssembler() { // -void Triple::Parse() const { - assert(!isInitialized() && "Invalid parse call."); - - StringRef ArchName = getArchName(); - StringRef VendorName = getVendorName(); - StringRef OSName = getOSName(); - +Triple::ArchType Triple::ParseArch(StringRef ArchName) { if (ArchName.size() == 4 && ArchName[0] == 'i' && ArchName[2] == '8' && ArchName[3] == '6' && ArchName[1] - '3' < 6) // i[3-9]86 - Arch = x86; + return x86; else if (ArchName == "amd64" || ArchName == "x86_64") - Arch = x86_64; + return x86_64; else if (ArchName == "bfin") - Arch = bfin; + return bfin; else if (ArchName == "pic16") - Arch = pic16; + return pic16; else if (ArchName == "powerpc") - Arch = ppc; + return ppc; else if ((ArchName == "powerpc64") || (ArchName == "ppu")) - Arch = ppc64; + return ppc64; else if (ArchName == "mblaze") - Arch = mblaze; + return mblaze; else if (ArchName == "arm" || ArchName.startswith("armv") || ArchName == "xscale") - Arch = arm; + return arm; else if (ArchName == "thumb" || ArchName.startswith("thumbv")) - Arch = thumb; + return thumb; else if (ArchName.startswith("alpha")) - Arch = alpha; + return alpha; else if (ArchName == "spu" || ArchName == "cellspu") - Arch = cellspu; + return cellspu; else if (ArchName == "msp430") - Arch = msp430; + return msp430; else if (ArchName == "mips" || ArchName == "mipsallegrex") - Arch = mips; + return mips; else if (ArchName == "mipsel" || ArchName == "mipsallegrexel" || ArchName == "psp") - Arch = mipsel; + return mipsel; else if (ArchName == "sparc") - Arch = sparc; + return sparc; else if (ArchName == "sparcv9") - Arch = sparcv9; + return sparcv9; else if (ArchName == "s390x") - Arch = systemz; + return systemz; else if (ArchName == "tce") - Arch = tce; + return tce; else if (ArchName == "xcore") - Arch = xcore; + return xcore; else - Arch = UnknownArch; - - - // Handle some exceptional cases where the OS / environment components are - // stuck into the vendor field. - if (StringRef(getTriple()).count('-') == 1) { - StringRef VendorName = getVendorName(); - - if (VendorName.startswith("mingw32")) { // 'i386-mingw32', etc. - Vendor = PC; - OS = MinGW32; - return; - } - - // arm-elf is another example, but we don't currently parse anything about - // the environment. - } + return UnknownArch; +} +Triple::VendorType Triple::ParseVendor(StringRef VendorName) { if (VendorName == "apple") - Vendor = Apple; + return Apple; else if (VendorName == "pc") - Vendor = PC; + return PC; else - Vendor = UnknownVendor; + return UnknownVendor; +} +Triple::OSType Triple::ParseOS(StringRef OSName) { if (OSName.startswith("auroraux")) - OS = AuroraUX; + return AuroraUX; else if (OSName.startswith("cygwin")) - OS = Cygwin; + return Cygwin; else if (OSName.startswith("darwin")) - OS = Darwin; + return Darwin; else if (OSName.startswith("dragonfly")) - OS = DragonFly; + return DragonFly; else if (OSName.startswith("freebsd")) - OS = FreeBSD; + return FreeBSD; else if (OSName.startswith("linux")) - OS = Linux; + return Linux; else if (OSName.startswith("lv2")) - OS = Lv2; + return Lv2; else if (OSName.startswith("mingw32")) - OS = MinGW32; + return MinGW32; else if (OSName.startswith("mingw64")) - OS = MinGW64; + return MinGW64; else if (OSName.startswith("netbsd")) - OS = NetBSD; + return NetBSD; else if (OSName.startswith("openbsd")) - OS = OpenBSD; + return OpenBSD; else if (OSName.startswith("psp")) - OS = Psp; + return Psp; else if (OSName.startswith("solaris")) - OS = Solaris; + return Solaris; else if (OSName.startswith("win32")) - OS = Win32; + return Win32; else if (OSName.startswith("haiku")) - OS = Haiku; + return Haiku; else if (OSName.startswith("minix")) - OS = Minix; + return Minix; else - OS = UnknownOS; + return UnknownOS; +} + +void Triple::Parse() const { + assert(!isInitialized() && "Invalid parse call."); + + Arch = ParseArch(getArchName()); + Vendor = ParseVendor(getVendorName()); + OS = ParseOS(getOSName()); assert(isInitialized() && "Failed to initialize!"); } +std::string Triple::normalize(StringRef Str) { + // Parse into components. + SmallVector Components; + for (size_t First = 0, Last = 0; Last != StringRef::npos; First = Last + 1) { + Last = Str.find('-', First); + Components.push_back(Str.slice(First, Last)); + } + + // If the first component corresponds to a known architecture, preferentially + // use it for the architecture. If the second component corresponds to a + // known vendor, preferentially use it for the vendor, etc. This avoids silly + // component movement when a component parses as (eg) both a valid arch and a + // valid os. + ArchType Arch = UnknownArch; + if (Components.size() > 0) + Arch = ParseArch(Components[0]); + VendorType Vendor = UnknownVendor; + if (Components.size() > 1) + Vendor = ParseVendor(Components[1]); + OSType OS = UnknownOS; + if (Components.size() > 2) + OS = ParseOS(Components[2]); + + // Note which components are already in their final position. These will not + // be moved. + bool Found[3]; + Found[0] = Arch != UnknownArch; + Found[1] = Vendor != UnknownVendor; + Found[2] = OS != UnknownOS; + + // If they are not there already, permute the components into their canonical + // positions by seeing if they parse as a valid architecture, and if so moving + // the component to the architecture position etc. + for (unsigned Pos = 0; Pos != 3; ++Pos) { + if (Found[Pos]) + continue; // Already in the canonical position. + + for (unsigned Idx = 0; Idx != Components.size(); ++Idx) { + // Do not reparse any components that already matched. + if (Idx < 3 && Found[Idx]) + continue; + + // Does this component parse as valid for the target position? + bool Valid = false; + StringRef Comp = Components[Idx]; + switch (Pos) { + default: + assert(false && "unexpected component type!"); + case 0: + Arch = ParseArch(Comp); + Valid = Arch != UnknownArch; + break; + case 1: + Vendor = ParseVendor(Comp); + Valid = Vendor != UnknownVendor; + break; + case 2: + OS = ParseOS(Comp); + Valid = OS != UnknownOS; + break; + } + if (!Valid) + continue; // Nope, try the next component. + + // Move the component to the target position, pushing any non-fixed + // components that are in the way to the right. This tends to give + // good results in the common cases of a forgotten vendor component + // or a wrongly positioned environment. + if (Pos < Idx) { + // Insert left, pushing the existing components to the right. For + // example, a-b-i386 -> i386-a-b when moving i386 to the front. + StringRef CurrentComponent(""); // The empty component. + // Replace the component we are moving with an empty component. + std::swap(CurrentComponent, Components[Idx]); + // Insert the component being moved at Pos, displacing any existing + // components to the right. + for (unsigned i = Pos; !CurrentComponent.empty(); ++i) { + // Skip over any fixed components. + while (i < 3 && Found[i]) ++i; + // Place the component at the new position, getting the component + // that was at this position - it will be moved right. + std::swap(CurrentComponent, Components[i]); + } + } else if (Pos > Idx) { + // Push right by inserting empty components until the component at Idx + // reaches the target position Pos. For example, pc-a -> -pc-a when + // moving pc to the second position. + do { + // Insert one empty component at Idx. + StringRef CurrentComponent(""); // The empty component. + for (unsigned i = Idx; i < Components.size(); ++i) { + // Skip over any fixed components. + while (i < 3 && Found[i]) ++i; + // Place the component at the new position, getting the component + // that was at this position - it will be moved right. + std::swap(CurrentComponent, Components[i]); + // If it was placed on top of an empty component then we are done. + if (CurrentComponent.empty()) + break; + } + // The last component was pushed off the end - append it. + if (!CurrentComponent.empty()) + Components.push_back(CurrentComponent); + + // Advance Idx to the component's new position. + while (++Idx < 3 && Found[Idx]) {} + } while (Idx < Pos); // Add more until the final position is reached. + } + assert(Pos < Components.size() && Components[Pos] == Comp && + "Component moved wrong!"); + Found[Pos] = true; + break; + } + } + + // Special case logic goes here. At this point Arch, Vendor and OS have the + // correct values for the computed components. + + // Stick the corrected components back together to form the normalized string. + std::string Normalized; + for (unsigned i = 0, e = Components.size(); i != e; ++i) { + if (i) Normalized += '-'; + Normalized += Components[i]; + } + return Normalized; +} + StringRef Triple::getArchName() const { return StringRef(Data).split('-').first; // Isolate first component } diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp index 8054ae6..dba46df 100644 --- a/lib/Support/raw_ostream.cpp +++ b/lib/Support/raw_ostream.cpp @@ -19,6 +19,7 @@ #include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/System/Signals.h" #include "llvm/ADT/STLExtras.h" #include #include @@ -56,13 +57,6 @@ raw_ostream::~raw_ostream() { if (BufferMode == InternalBuffer) delete [] OutBufStart; - - // If there are any pending errors, report them now. Clients wishing - // to avoid report_fatal_error calls should check for errors with - // has_error() and clear the error flag with clear_error() before - // destructing raw_ostream objects which may have errors. - if (Error) - report_fatal_error("IO failure on output stream."); } // An out of line virtual method to provide a home for the class vtable. @@ -143,9 +137,10 @@ raw_ostream &raw_ostream::operator<<(unsigned long long N) { } raw_ostream &raw_ostream::operator<<(long long N) { - if (N < 0) { + if (N < 0) { *this << '-'; - N = -N; + // Avoid undefined behavior on INT64_MIN with a cast. + N = -(unsigned long long)N; } return this->operator<<(static_cast(N)); @@ -368,7 +363,7 @@ void format_object_base::home() { /// stream should be immediately destroyed; the string will be empty /// if no error occurred. raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo, - unsigned Flags) : pos(0) { + unsigned Flags) : Error(false), pos(0) { assert(Filename != 0 && "Filename is null"); // Verify that we don't have both "append" and "excl". assert((!(Flags & F_Excl) || !(Flags & F_Append)) && @@ -376,14 +371,17 @@ raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo, ErrorInfo.clear(); - // Handle "-" as stdout. + // Handle "-" as stdout. Note that when we do this, we consider ourself + // the owner of stdout. This means that we can do things like close the + // file descriptor when we're done and set the "binary" flag globally. if (Filename[0] == '-' && Filename[1] == 0) { FD = STDOUT_FILENO; // If user requested binary then put stdout into binary mode if // possible. if (Flags & F_Binary) sys::Program::ChangeStdoutToBinary(); - ShouldClose = false; + // Close stdout when we're done, to detect any output errors. + ShouldClose = true; return; } @@ -413,14 +411,22 @@ raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo, } raw_fd_ostream::~raw_fd_ostream() { - if (FD < 0) return; - flush(); - if (ShouldClose) - while (::close(FD) != 0) - if (errno != EINTR) { - error_detected(); - break; - } + if (FD >= 0) { + flush(); + if (ShouldClose) + while (::close(FD) != 0) + if (errno != EINTR) { + error_detected(); + break; + } + } + + // If there are any pending errors, report them now. Clients wishing + // to avoid report_fatal_error calls should check for errors with + // has_error() and clear the error flag with clear_error() before + // destructing raw_ostream objects which may have errors. + if (has_error()) + report_fatal_error("IO failure on output stream."); } @@ -534,30 +540,24 @@ bool raw_fd_ostream::is_displayed() const { } //===----------------------------------------------------------------------===// -// raw_stdout/err_ostream +// outs(), errs(), nulls() //===----------------------------------------------------------------------===// -// Set buffer settings to model stdout and stderr behavior. -// Set standard error to be unbuffered by default. -raw_stdout_ostream::raw_stdout_ostream():raw_fd_ostream(STDOUT_FILENO, false) {} -raw_stderr_ostream::raw_stderr_ostream():raw_fd_ostream(STDERR_FILENO, false, - true) {} - -// An out of line virtual method to provide a home for the class vtable. -void raw_stdout_ostream::handle() {} -void raw_stderr_ostream::handle() {} - /// outs() - This returns a reference to a raw_ostream for standard output. /// Use it like: outs() << "foo" << "bar"; raw_ostream &llvm::outs() { - static raw_stdout_ostream S; + // Set buffer settings to model stdout behavior. + // Delete the file descriptor when the program exists, forcing error + // detection. If you don't want this behavior, don't use outs(). + static raw_fd_ostream S(STDOUT_FILENO, true); return S; } /// errs() - This returns a reference to a raw_ostream for standard error. /// Use it like: errs() << "foo" << "bar"; raw_ostream &llvm::errs() { - static raw_stderr_ostream S; + // Set standard error to be unbuffered by default. + static raw_fd_ostream S(STDERR_FILENO, false, true); return S; } @@ -665,3 +665,34 @@ void raw_null_ostream::write_impl(const char *Ptr, size_t Size) { uint64_t raw_null_ostream::current_pos() const { return 0; } + +//===----------------------------------------------------------------------===// +// tool_output_file +//===----------------------------------------------------------------------===// + +tool_output_file::CleanupInstaller::CleanupInstaller(const char *filename) + : Filename(filename), Keep(false) { + // Arrange for the file to be deleted if the process is killed. + if (Filename != "-") + sys::RemoveFileOnSignal(sys::Path(Filename)); +} + +tool_output_file::CleanupInstaller::~CleanupInstaller() { + // Delete the file if the client hasn't told us not to. + if (!Keep && Filename != "-") + sys::Path(Filename).eraseFromDisk(); + + // Ok, the file is successfully written and closed, or deleted. There's no + // further need to clean it up on signals. + if (Filename != "-") + sys::DontRemoveFileOnSignal(sys::Path(Filename)); +} + +tool_output_file::tool_output_file(const char *filename, std::string &ErrorInfo, + unsigned Flags) + : Installer(filename), + OS(filename, ErrorInfo, Flags) { + // If open fails, no cleanup is needed. + if (!ErrorInfo.empty()) + Installer.Keep = true; +} diff --git a/lib/System/DynamicLibrary.cpp b/lib/System/DynamicLibrary.cpp index 6f6890c..660db49 100644 --- a/lib/System/DynamicLibrary.cpp +++ b/lib/System/DynamicLibrary.cpp @@ -70,6 +70,12 @@ bool DynamicLibrary::LoadLibraryPermanently(const char *Filename, if (ErrMsg) *ErrMsg = dlerror(); return true; } +#ifdef __CYGWIN__ + // Cygwin searches symbols only in the main + // with the handle of dlopen(NULL, RTLD_GLOBAL). + if (Filename == NULL) + H = RTLD_DEFAULT; +#endif if (OpenedHandles == 0) OpenedHandles = new std::vector(); OpenedHandles->push_back(H); diff --git a/lib/System/Path.cpp b/lib/System/Path.cpp index 1235257..4445c66 100644 --- a/lib/System/Path.cpp +++ b/lib/System/Path.cpp @@ -61,7 +61,7 @@ sys::IdentifyFileType(const char *magic, unsigned length) { if (memcmp(magic,"!\n",8) == 0) return Archive_FileType; break; - + case '\177': if (magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') { if (length >= 18 && magic[17] == 0) @@ -76,11 +76,11 @@ sys::IdentifyFileType(const char *magic, unsigned length) { break; case 0xCA: - if (magic[1] == char(0xFE) && magic[2] == char(0xBA) && + if (magic[1] == char(0xFE) && magic[2] == char(0xBA) && magic[3] == char(0xBE)) { - // This is complicated by an overlap with Java class files. + // This is complicated by an overlap with Java class files. // See the Mach-O section in /usr/share/file/magic for details. - if (length >= 8 && magic[7] < 43) + if (length >= 8 && magic[7] < 43) // FIXME: Universal Binary of any type. return Mach_O_DynamicallyLinkedSharedLib_FileType; } @@ -89,18 +89,18 @@ sys::IdentifyFileType(const char *magic, unsigned length) { case 0xFE: case 0xCE: { uint16_t type = 0; - if (magic[0] == char(0xFE) && magic[1] == char(0xED) && + if (magic[0] == char(0xFE) && magic[1] == char(0xED) && magic[2] == char(0xFA) && magic[3] == char(0xCE)) { /* Native endian */ if (length >= 16) type = magic[14] << 8 | magic[15]; - } else if (magic[0] == char(0xCE) && magic[1] == char(0xFA) && + } else if (magic[0] == char(0xCE) && magic[1] == char(0xFA) && magic[2] == char(0xED) && magic[3] == char(0xFE)) { /* Reverse endian */ if (length >= 14) type = magic[13] << 8 | magic[12]; } switch (type) { - default: break; - case 1: return Mach_O_Object_FileType; + default: break; + case 1: return Mach_O_Object_FileType; case 2: return Mach_O_Executable_FileType; case 3: return Mach_O_FixedVirtualMemorySharedLib_FileType; case 4: return Mach_O_Core_FileType; @@ -219,38 +219,38 @@ static StringRef getDirnameCharSep(StringRef path, const char *Sep) { "Sep must be a 1-character string literal."); if (path.empty()) return "."; - + // If the path is all slashes, return a single slash. // Otherwise, remove all trailing slashes. - + signed pos = static_cast(path.size()) - 1; - + while (pos >= 0 && path[pos] == Sep[0]) --pos; - + if (pos < 0) return path[0] == Sep[0] ? Sep : "."; - + // Any slashes left? signed i = 0; - + while (i < pos && path[i] != Sep[0]) ++i; - + if (i == pos) // No slashes? Return "." return "."; - - // There is at least one slash left. Remove all trailing non-slashes. + + // There is at least one slash left. Remove all trailing non-slashes. while (pos >= 0 && path[pos] != Sep[0]) --pos; - + // Remove any trailing slashes. while (pos >= 0 && path[pos] == Sep[0]) --pos; - + if (pos < 0) return path[0] == Sep[0] ? Sep : "."; - + return path.substr(0, pos+1); } diff --git a/lib/System/RWMutex.cpp b/lib/System/RWMutex.cpp index 5faf220..deb0470 100644 --- a/lib/System/RWMutex.cpp +++ b/lib/System/RWMutex.cpp @@ -71,23 +71,9 @@ RWMutexImpl::RWMutexImpl() bzero(rwlock, sizeof(pthread_rwlock_t)); #endif - pthread_rwlockattr_t attr; - - // Initialize the rwlock attributes - int errorcode = pthread_rwlockattr_init(&attr); - assert(errorcode == 0); - -#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) - // Make it a process local rwlock - errorcode = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); -#endif - // Initialize the rwlock - errorcode = pthread_rwlock_init(rwlock, &attr); - assert(errorcode == 0); - - // Destroy the attributes - errorcode = pthread_rwlockattr_destroy(&attr); + int errorcode = pthread_rwlock_init(rwlock, NULL); + (void)errorcode; assert(errorcode == 0); // Assign the data member diff --git a/lib/System/ThreadLocal.cpp b/lib/System/ThreadLocal.cpp index e7054b5..f6a55a1 100644 --- a/lib/System/ThreadLocal.cpp +++ b/lib/System/ThreadLocal.cpp @@ -27,6 +27,7 @@ ThreadLocalImpl::ThreadLocalImpl() { } ThreadLocalImpl::~ThreadLocalImpl() { } void ThreadLocalImpl::setInstance(const void* d) { data = const_cast(d);} const void* ThreadLocalImpl::getInstance() { return data; } +void ThreadLocalImpl::removeInstance() { data = 0; } } #else @@ -67,6 +68,10 @@ const void* ThreadLocalImpl::getInstance() { return pthread_getspecific(*key); } +void ThreadLocalImpl::removeInstance() { + setInstance(0); +} + } #elif defined(LLVM_ON_UNIX) diff --git a/lib/System/Unix/Path.inc b/lib/System/Unix/Path.inc index bc104a3..47e4d1a 100644 --- a/lib/System/Unix/Path.inc +++ b/lib/System/Unix/Path.inc @@ -276,20 +276,20 @@ Path::GetCurrentDirectory() { char pathname[MAXPATHLEN]; if (!getcwd(pathname,MAXPATHLEN)) { assert (false && "Could not query current working directory."); - return Path(""); + return Path(); } return Path(pathname); } -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__minix) static int test_dir(char buf[PATH_MAX], char ret[PATH_MAX], const char *dir, const char *bin) { struct stat sb; - snprintf(buf, PATH_MAX, "%s//%s", dir, bin); + snprintf(buf, PATH_MAX, "%s/%s", dir, bin); if (realpath(buf, ret) == NULL) return (1); if (stat(buf, &sb) != 0) @@ -334,7 +334,7 @@ getprogpath(char ret[PATH_MAX], const char *bin) free(pv); return (NULL); } -#endif // __FreeBSD__ +#endif // __FreeBSD__ || __NetBSD__ /// GetMainExecutable - Return the path to the main executable, given the /// value of argv[0] from program startup. @@ -350,7 +350,7 @@ Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { if (realpath(exe_path, link_path)) return Path(std::string(link_path)); } -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__minix) char exe_path[PATH_MAX]; if (getprogpath(exe_path, argv0) != NULL) @@ -408,7 +408,7 @@ Path::getSuffix() const { std::string::size_type dot = path.rfind('.'); if (dot == std::string::npos || dot < slash) - return StringRef(""); + return StringRef(); else return StringRef(path).substr(dot + 1); } diff --git a/lib/System/Unix/Signals.inc b/lib/System/Unix/Signals.inc index 1e74647..7b7c43e 100644 --- a/lib/System/Unix/Signals.inc +++ b/lib/System/Unix/Signals.inc @@ -182,6 +182,16 @@ bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename, return false; } +// DontRemoveFileOnSignal - The public API +void llvm::sys::DontRemoveFileOnSignal(const sys::Path &Filename) { + SignalsMutex.acquire(); + std::vector::reverse_iterator I = + std::find(FilesToRemove.rbegin(), FilesToRemove.rend(), Filename); + if (I != FilesToRemove.rend()) + FilesToRemove.erase(I.base()-1); + SignalsMutex.release(); +} + /// AddSignalHandler - Add a function to be called when a signal is delivered /// to the process. The handler can have a cookie passed to it to identify /// what instance of the handler it is. @@ -253,3 +263,37 @@ void llvm::sys::PrintStackTraceOnErrorSignal() { AddSignalHandler(PrintStackTrace, 0); } + +/***/ + +// On Darwin, raise sends a signal to the main thread instead of the current +// thread. This has the unfortunate effect that assert() and abort() will end up +// bypassing our crash recovery attempts. We work around this for anything in +// the same linkage unit by just defining our own versions of the assert handler +// and abort. + +#ifdef __APPLE__ + +void __assert_rtn(const char *func, + const char *file, + int line, + const char *expr) { + if (func) + fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", + expr, func, file, line); + else + fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n", + expr, file, line); + abort(); +} + +#include +#include + +void abort() { + pthread_kill(pthread_self(), SIGABRT); + usleep(1000); + __builtin_trap(); +} + +#endif diff --git a/lib/System/Unix/ThreadLocal.inc b/lib/System/Unix/ThreadLocal.inc index 83d554d3..6769520 100644 --- a/lib/System/Unix/ThreadLocal.inc +++ b/lib/System/Unix/ThreadLocal.inc @@ -22,4 +22,5 @@ ThreadLocalImpl::ThreadLocalImpl() { } ThreadLocalImpl::~ThreadLocalImpl() { } void ThreadLocalImpl::setInstance(const void* d) { data = const_cast(d);} const void* ThreadLocalImpl::getInstance() { return data; } +void ThreadLocalImpl::removeInstance() { setInstance(0); } } diff --git a/lib/System/Win32/Path.inc b/lib/System/Win32/Path.inc index 379527d..4a6dbd3 100644 --- a/lib/System/Win32/Path.inc +++ b/lib/System/Win32/Path.inc @@ -400,8 +400,10 @@ PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const { for (unsigned i = 0; i < path.length(); ++i) status.uniqueID += path[i]; - __int64 ft = *reinterpret_cast<__int64*>(&fi.ftLastWriteTime); - status.modTime.fromWin32Time(ft); + ULARGE_INTEGER ui; + ui.LowPart = fi.ftLastWriteTime.dwLowDateTime; + ui.HighPart = fi.ftLastWriteTime.dwHighDateTime; + status.modTime.fromWin32Time(ui.QuadPart); status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; fsIsValid = true; @@ -720,7 +722,7 @@ Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const { bool Path::getMagicNumber(std::string& Magic, unsigned len) const { assert(len < 1024 && "Request for magic string too long"); - char* buf = (char*) alloca(1 + len); + char* buf = reinterpret_cast(alloca(len)); HANDLE h = CreateFile(path.c_str(), GENERIC_READ, @@ -739,8 +741,7 @@ bool Path::getMagicNumber(std::string& Magic, unsigned len) const { if (!ret || nRead != len) return false; - buf[len] = '\0'; - Magic = buf; + Magic = std::string(buf, len); return true; } @@ -777,8 +778,11 @@ Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const { return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: "); } + ULARGE_INTEGER ui; + ui.QuadPart = si.modTime.toWin32Time(); FILETIME ft; - (uint64_t&)ft = si.modTime.toWin32Time(); + ft.dwLowDateTime = ui.LowPart; + ft.dwHighDateTime = ui.HighPart; BOOL ret = SetFileTime(h, NULL, &ft, &ft); DWORD err = GetLastError(); CloseHandle(h); diff --git a/lib/System/Win32/Signals.inc b/lib/System/Win32/Signals.inc index d6db71b..2498a26e 100644 --- a/lib/System/Win32/Signals.inc +++ b/lib/System/Win32/Signals.inc @@ -140,6 +140,20 @@ bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { return false; } +// DontRemoveFileOnSignal - The public API +void sys::DontRemoveFileOnSignal(const sys::Path &Filename) { + if (FilesToRemove == NULL) + return; + + FilesToRemove->push_back(Filename); + std::vector::reverse_iterator I = + std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename); + if (I != FilesToRemove->rend()) + FilesToRemove->erase(I.base()-1); + + LeaveCriticalSection(&CriticalSection); +} + /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or /// SIGSEGV) is delivered to the process, print a stack trace and then exit. void sys::PrintStackTraceOnErrorSignal() { diff --git a/lib/System/Win32/ThreadLocal.inc b/lib/System/Win32/ThreadLocal.inc index c8f7840..b8b933c 100644 --- a/lib/System/Win32/ThreadLocal.inc +++ b/lib/System/Win32/ThreadLocal.inc @@ -46,4 +46,8 @@ void ThreadLocalImpl::setInstance(const void* d){ assert(errorcode != 0); } +void ThreadLocalImpl::removeInstance() { + setInstance(0); +} + } diff --git a/lib/Target/ARM/ARM.h b/lib/Target/ARM/ARM.h index 14825a7..271ca44 100644 --- a/lib/Target/ARM/ARM.h +++ b/lib/Target/ARM/ARM.h @@ -30,22 +30,22 @@ class formatted_raw_ostream; namespace ARMCC { // The CondCodes constants map directly to the 4-bit encoding of the // condition field for predicated instructions. - enum CondCodes { - EQ, - NE, - HS, - LO, - MI, - PL, - VS, - VC, - HI, - LS, - GE, - LT, - GT, - LE, - AL + enum CondCodes { // Meaning (integer) Meaning (floating-point) + EQ, // Equal Equal + NE, // Not equal Not equal, or unordered + HS, // Carry set >, ==, or unordered + LO, // Carry clear Less than + MI, // Minus, negative Less than + PL, // Plus, positive or zero >, ==, or unordered + VS, // Overflow Unordered + VC, // No overflow Not unordered + HI, // Unsigned higher Greater than, or unordered + LS, // Unsigned lower or same Less than or equal + GE, // Greater than or equal Greater than or equal + LT, // Less than Less than, or unordered + GT, // Greater than Greater than + LE, // Less than or equal <, ==, or unordered + AL // Always (unconditional) Always (unconditional) }; inline static CondCodes getOppositeCondition(CondCodes CC) { @@ -90,6 +90,33 @@ inline static const char *ARMCondCodeToString(ARMCC::CondCodes CC) { } } +namespace ARM_MB { + // The Memory Barrier Option constants map directly to the 4-bit encoding of + // the option field for memory barrier operations. + enum MemBOpt { + ST = 14, + ISH = 11, + ISHST = 10, + NSH = 7, + NSHST = 6, + OSH = 3, + OSHST = 2 + }; + + inline static const char *MemBOptToString(unsigned val) { + switch (val) { + default: llvm_unreachable("Unknown memory opetion"); + case ST: return "st"; + case ISH: return "ish"; + case ISHST: return "ishst"; + case NSH: return "nsh"; + case NSHST: return "nshst"; + case OSH: return "osh"; + case OSHST: return "oshst"; + } + } +} // namespace ARM_MB + FunctionPass *createARMISelDag(ARMBaseTargetMachine &TM, CodeGenOpt::Level OptLevel); @@ -98,6 +125,7 @@ FunctionPass *createARMJITCodeEmitterPass(ARMBaseTargetMachine &TM, FunctionPass *createARMLoadStoreOptimizationPass(bool PreAlloc = false); FunctionPass *createARMExpandPseudoPass(); +FunctionPass *createARMGlobalMergePass(const TargetLowering* tli); FunctionPass *createARMConstantIslandPass(); FunctionPass *createNEONPreAllocPass(); FunctionPass *createNEONMoveFixPass(); diff --git a/lib/Target/ARM/ARM.td b/lib/Target/ARM/ARM.td index fa64d6c..d6a8f19 100644 --- a/lib/Target/ARM/ARM.td +++ b/lib/Target/ARM/ARM.td @@ -1,4 +1,4 @@ -//===- ARM.td - Describe the ARM Target Machine -----------------*- C++ -*-===// +//===- ARM.td - Describe the ARM Target Machine ------------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -20,20 +20,6 @@ include "llvm/Target/Target.td" // ARM Subtarget features. // -def ArchV4T : SubtargetFeature<"v4t", "ARMArchVersion", "V4T", - "ARM v4T">; -def ArchV5T : SubtargetFeature<"v5t", "ARMArchVersion", "V5T", - "ARM v5T">; -def ArchV5TE : SubtargetFeature<"v5te", "ARMArchVersion", "V5TE", - "ARM v5TE, v5TEj, v5TExp">; -def ArchV6 : SubtargetFeature<"v6", "ARMArchVersion", "V6", - "ARM v6">; -def ArchV6T2 : SubtargetFeature<"v6t2", "ARMArchVersion", "V6T2", - "ARM v6t2">; -def ArchV7A : SubtargetFeature<"v7a", "ARMArchVersion", "V7A", - "ARM v7A">; -def ArchV7M : SubtargetFeature<"v7m", "ARMArchVersion", "V7M", - "ARM v7M">; def FeatureVFP2 : SubtargetFeature<"vfp2", "ARMFPUType", "VFPv2", "Enable VFP2 instructions">; def FeatureVFP3 : SubtargetFeature<"vfp3", "ARMFPUType", "VFPv3", @@ -42,14 +28,20 @@ def FeatureNEON : SubtargetFeature<"neon", "ARMFPUType", "NEON", "Enable NEON instructions">; def FeatureThumb2 : SubtargetFeature<"thumb2", "ThumbMode", "Thumb2", "Enable Thumb2 instructions">; +def FeatureNoARM : SubtargetFeature<"noarm", "NoARM", "true", + "Does not support ARM mode execution">; def FeatureFP16 : SubtargetFeature<"fp16", "HasFP16", "true", "Enable half-precision floating point">; def FeatureHWDiv : SubtargetFeature<"hwdiv", "HasHardwareDivide", "true", "Enable divide instructions">; -def FeatureT2ExtractPack: SubtargetFeature<"t2xtpk", "HasT2ExtractPack", "true", +def FeatureT2XtPk : SubtargetFeature<"t2xtpk", "HasT2ExtractPack", "true", "Enable Thumb2 extract and pack instructions">; +def FeatureDB : SubtargetFeature<"db", "HasDataBarrier", "true", + "Has data barrier (dmb / dsb) instructions">; def FeatureSlowFPBrcc : SubtargetFeature<"slow-fp-brcc", "SlowFPBrcc", "true", "FP compare + branch is slow">; +def FeatureVFPOnlySP : SubtargetFeature<"fp-only-sp", "FPOnlySP", "true", + "Floating point unit supports single precision only">; // Some processors have multiply-accumulate instructions that don't // play nicely with other VFP instructions, and it's generally better @@ -57,14 +49,41 @@ def FeatureSlowFPBrcc : SubtargetFeature<"slow-fp-brcc", "SlowFPBrcc", "true", // FIXME: Currently, this is only flagged for Cortex-A8. It may be true for // others as well. We should do more benchmarking and confirm one way or // the other. -def FeatureHasSlowVMLx : SubtargetFeature<"vmlx", "SlowVMLx", "true", - "Disable VFP MAC instructions">; +def FeatureHasSlowVMLx : SubtargetFeature<"vmlx", "SlowVMLx", "true", + "Disable VFP MAC instructions">; // Some processors benefit from using NEON instructions for scalar // single-precision FP operations. def FeatureNEONForFP : SubtargetFeature<"neonfp", "UseNEONForSinglePrecisionFP", "true", "Use NEON for single precision FP">; +// Disable 32-bit to 16-bit narrowing for experimentation. +def FeaturePref32BitThumb : SubtargetFeature<"32bit", "Pref32BitThumb", "true", + "Prefer 32-bit Thumb instrs">; + + +// ARM architectures. +def ArchV4T : SubtargetFeature<"v4t", "ARMArchVersion", "V4T", + "ARM v4T">; +def ArchV5T : SubtargetFeature<"v5t", "ARMArchVersion", "V5T", + "ARM v5T">; +def ArchV5TE : SubtargetFeature<"v5te", "ARMArchVersion", "V5TE", + "ARM v5TE, v5TEj, v5TExp">; +def ArchV6 : SubtargetFeature<"v6", "ARMArchVersion", "V6", + "ARM v6">; +def ArchV6M : SubtargetFeature<"v6m", "ARMArchVersion", "V6M", + "ARM v6m", + [FeatureNoARM, FeatureDB]>; +def ArchV6T2 : SubtargetFeature<"v6t2", "ARMArchVersion", "V6T2", + "ARM v6t2", + [FeatureThumb2]>; +def ArchV7A : SubtargetFeature<"v7a", "ARMArchVersion", "V7A", + "ARM v7A", + [FeatureThumb2, FeatureNEON, FeatureDB]>; +def ArchV7M : SubtargetFeature<"v7m", "ARMArchVersion", "V7M", + "ARM v7M", + [FeatureThumb2, FeatureNoARM, FeatureDB, + FeatureHWDiv]>; //===----------------------------------------------------------------------===// // ARM Processors supported. @@ -122,20 +141,23 @@ def : Processor<"arm1176jzf-s", ARMV6Itineraries, [ArchV6, FeatureVFP2]>; def : Processor<"mpcorenovfp", ARMV6Itineraries, [ArchV6]>; def : Processor<"mpcore", ARMV6Itineraries, [ArchV6, FeatureVFP2]>; +// V6M Processors. +def : Processor<"cortex-m0", ARMV6Itineraries, [ArchV6M]>; + // V6T2 Processors. -def : Processor<"arm1156t2-s", ARMV6Itineraries, - [ArchV6T2, FeatureThumb2]>; -def : Processor<"arm1156t2f-s", ARMV6Itineraries, - [ArchV6T2, FeatureThumb2, FeatureVFP2]>; +def : Processor<"arm1156t2-s", ARMV6Itineraries, [ArchV6T2]>; +def : Processor<"arm1156t2f-s", ARMV6Itineraries, [ArchV6T2, FeatureVFP2]>; // V7 Processors. def : Processor<"cortex-a8", CortexA8Itineraries, - [ArchV7A, FeatureThumb2, FeatureNEON, FeatureHasSlowVMLx, - FeatureSlowFPBrcc, FeatureNEONForFP, FeatureT2ExtractPack]>; + [ArchV7A, FeatureHasSlowVMLx, + FeatureSlowFPBrcc, FeatureNEONForFP, FeatureT2XtPk]>; def : Processor<"cortex-a9", CortexA9Itineraries, - [ArchV7A, FeatureThumb2, FeatureNEON, FeatureT2ExtractPack]>; -def : ProcNoItin<"cortex-m3", [ArchV7M, FeatureThumb2, FeatureHWDiv]>; -def : ProcNoItin<"cortex-m4", [ArchV7M, FeatureThumb2, FeatureHWDiv]>; + [ArchV7A, FeatureT2XtPk]>; + +// V7M Processors. +def : ProcNoItin<"cortex-m3", [ArchV7M]>; +def : ProcNoItin<"cortex-m4", [ArchV7M, FeatureVFP2, FeatureVFPOnlySP]>; //===----------------------------------------------------------------------===// // Register File Description diff --git a/lib/Target/ARM/ARMAddressingModes.h b/lib/Target/ARM/ARMAddressingModes.h index 92a13f1..db48100 100644 --- a/lib/Target/ARM/ARMAddressingModes.h +++ b/lib/Target/ARM/ARMAddressingModes.h @@ -458,6 +458,7 @@ namespace ARM_AM { // IB - Increment before // DA - Decrement after // DB - Decrement before + // For VFP instructions, only the IA and DB modes are valid. static inline AMSubMode getAM4SubMode(unsigned Mode) { return (AMSubMode)(Mode & 0x7); @@ -477,14 +478,6 @@ namespace ARM_AM { // // The first operand is always a Reg. The second operand encodes the // operation in bit 8 and the immediate in bits 0-7. - // - // This is also used for FP load/store multiple ops. The second operand - // encodes the number of registers (or 2 times the number of registers - // for DPR ops) in bits 0-7. In addition, bits 8-10 encode one of the - // following two sub-modes: - // - // IA - Increment after - // DB - Decrement before /// getAM5Opc - This function encodes the addrmode5 opc field. static inline unsigned getAM5Opc(AddrOpc Opc, unsigned char Offset) { @@ -498,17 +491,6 @@ namespace ARM_AM { return ((AM5Opc >> 8) & 1) ? sub : add; } - /// getAM5Opc - This function encodes the addrmode5 opc field for VLDM and - /// VSTM instructions. - static inline unsigned getAM5Opc(AMSubMode SubMode, unsigned char Offset) { - assert((SubMode == ia || SubMode == db) && - "Illegal addressing mode 5 sub-mode!"); - return ((int)SubMode << 8) | Offset; - } - static inline AMSubMode getAM5SubMode(unsigned AM5Opc) { - return (AMSubMode)((AM5Opc >> 8) & 0x7); - } - //===--------------------------------------------------------------------===// // Addressing Mode #6 //===--------------------------------------------------------------------===// diff --git a/lib/Target/ARM/ARMAsmPrinter.cpp b/lib/Target/ARM/ARMAsmPrinter.cpp new file mode 100644 index 0000000..6cfd596 --- /dev/null +++ b/lib/Target/ARM/ARMAsmPrinter.cpp @@ -0,0 +1,1491 @@ +//===-- ARMAsmPrinter.cpp - Print machine code to an ARM .s file ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to GAS-format ARM assembly language. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "asm-printer" +#include "ARM.h" +#include "ARMBuildAttrs.h" +#include "ARMAddressingModes.h" +#include "ARMConstantPoolValue.h" +#include "AsmPrinter/ARMInstPrinter.h" +#include "ARMMachineFunctionInfo.h" +#include "ARMMCInstLower.h" +#include "ARMTargetMachine.h" +#include "llvm/Analysis/DebugInfo.h" +#include "llvm/Constants.h" +#include "llvm/Module.h" +#include "llvm/Type.h" +#include "llvm/Assembly/Writer.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include +using namespace llvm; + +static cl::opt +EnableMCInst("enable-arm-mcinst-printer", cl::Hidden, + cl::desc("enable experimental asmprinter gunk in the arm backend")); + +namespace llvm { + namespace ARM { + enum DW_ISA { + DW_ISA_ARM_thumb = 1, + DW_ISA_ARM_arm = 2 + }; + } +} + +namespace { + class ARMAsmPrinter : public AsmPrinter { + + /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can + /// make the right decision when printing asm code for different targets. + const ARMSubtarget *Subtarget; + + /// AFI - Keep a pointer to ARMFunctionInfo for the current + /// MachineFunction. + ARMFunctionInfo *AFI; + + /// MCP - Keep a pointer to constantpool entries of the current + /// MachineFunction. + const MachineConstantPool *MCP; + + public: + explicit ARMAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer), AFI(NULL), MCP(NULL) { + Subtarget = &TM.getSubtarget(); + } + + virtual const char *getPassName() const { + return "ARM Assembly Printer"; + } + + void printInstructionThroughMCStreamer(const MachineInstr *MI); + + + void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O, + const char *Modifier = 0); + void printSOImmOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); + void printSOImm2PartOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printSORegOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrMode2Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrMode2OffsetOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrMode3Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrMode3OffsetOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrMode4Operand(const MachineInstr *MI, int OpNum,raw_ostream &O, + const char *Modifier = 0); + void printAddrMode5Operand(const MachineInstr *MI, int OpNum,raw_ostream &O, + const char *Modifier = 0); + void printAddrMode6Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrMode6OffsetOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrModePCOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, + const char *Modifier = 0); + void printBitfieldInvMaskImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printMemBOption(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printShiftImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + + void printThumbS4ImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printThumbITMask(const MachineInstr *MI, int OpNum, raw_ostream &O); + void printThumbAddrModeRROperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printThumbAddrModeRI5Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O, + unsigned Scale); + void printThumbAddrModeS1Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printThumbAddrModeS2Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printThumbAddrModeS4Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printThumbAddrModeSPOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + + void printT2SOOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); + void printT2AddrModeImm12Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) {} + void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + + void printCPSOptionOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) {} + void printMSRMaskOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) {} + void printNegZeroOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) {} + void printPredicateOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printMandatoryPredicateOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printSBitModifierOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printPCLabel(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printRegisterList(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printCPInstOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, + const char *Modifier); + void printJTBlockOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printJT2BlockOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printTBAddrMode(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printNoHashImmediate(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printVFPf32ImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printVFPf64ImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printNEONModImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + + virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O); + virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, + const char *ExtraCode, raw_ostream &O); + + void printInstruction(const MachineInstr *MI, raw_ostream &O); // autogen + static const char *getRegisterName(unsigned RegNo); + + virtual void EmitInstruction(const MachineInstr *MI); + bool runOnMachineFunction(MachineFunction &F); + + virtual void EmitConstantPool() {} // we emit constant pools customly! + virtual void EmitFunctionEntryLabel(); + void EmitStartOfAsmFile(Module &M); + void EmitEndOfAsmFile(Module &M); + + MachineLocation getDebugValueLocation(const MachineInstr *MI) const { + MachineLocation Location; + assert (MI->getNumOperands() == 4 && "Invalid no. of machine operands!"); + // Frame address. Currently handles register +- offset only. + if (MI->getOperand(0).isReg() && MI->getOperand(1).isImm()) + Location.set(MI->getOperand(0).getReg(), MI->getOperand(1).getImm()); + else { + DEBUG(dbgs() << "DBG_VALUE instruction ignored! " << *MI << "\n"); + } + return Location; + } + + virtual unsigned getISAEncoding() { + // ARM/Darwin adds ISA to the DWARF info for each function. + if (!Subtarget->isTargetDarwin()) + return 0; + return Subtarget->isThumb() ? + llvm::ARM::DW_ISA_ARM_thumb : llvm::ARM::DW_ISA_ARM_arm; + } + + MCSymbol *GetARMSetPICJumpTableLabel2(unsigned uid, unsigned uid2, + const MachineBasicBlock *MBB) const; + MCSymbol *GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const; + + /// EmitMachineConstantPoolValue - Print a machine constantpool value to + /// the .s file. + virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + EmitMachineConstantPoolValue(MCPV, OS); + OutStreamer.EmitRawText(OS.str()); + } + + void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV, + raw_ostream &O) { + switch (TM.getTargetData()->getTypeAllocSize(MCPV->getType())) { + case 1: O << MAI->getData8bitsDirective(0); break; + case 2: O << MAI->getData16bitsDirective(0); break; + case 4: O << MAI->getData32bitsDirective(0); break; + default: assert(0 && "Unknown CPV size"); + } + + ARMConstantPoolValue *ACPV = static_cast(MCPV); + + if (ACPV->isLSDA()) { + O << MAI->getPrivateGlobalPrefix() << "_LSDA_" << getFunctionNumber(); + } else if (ACPV->isBlockAddress()) { + O << *GetBlockAddressSymbol(ACPV->getBlockAddress()); + } else if (ACPV->isGlobalValue()) { + const GlobalValue *GV = ACPV->getGV(); + bool isIndirect = Subtarget->isTargetDarwin() && + Subtarget->GVIsIndirectSymbol(GV, TM.getRelocationModel()); + if (!isIndirect) + O << *Mang->getSymbol(GV); + else { + // FIXME: Remove this when Darwin transition to @GOT like syntax. + MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); + O << *Sym; + + MachineModuleInfoMachO &MMIMachO = + MMI->getObjFileInfo(); + MachineModuleInfoImpl::StubValueTy &StubSym = + GV->hasHiddenVisibility() ? MMIMachO.getHiddenGVStubEntry(Sym) : + MMIMachO.getGVStubEntry(Sym); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); + } + } else { + assert(ACPV->isExtSymbol() && "unrecognized constant pool value"); + O << *GetExternalSymbolSymbol(ACPV->getSymbol()); + } + + if (ACPV->hasModifier()) O << "(" << ACPV->getModifier() << ")"; + if (ACPV->getPCAdjustment() != 0) { + O << "-(" << MAI->getPrivateGlobalPrefix() << "PC" + << getFunctionNumber() << "_" << ACPV->getLabelId() + << "+" << (unsigned)ACPV->getPCAdjustment(); + if (ACPV->mustAddCurrentAddress()) + O << "-."; + O << ')'; + } + } + }; +} // end of anonymous namespace + +#include "ARMGenAsmWriter.inc" + +void ARMAsmPrinter::EmitFunctionEntryLabel() { + if (AFI->isThumbFunction()) { + OutStreamer.EmitRawText(StringRef("\t.code\t16")); + if (!Subtarget->isTargetDarwin()) + OutStreamer.EmitRawText(StringRef("\t.thumb_func")); + else { + // This needs to emit to a temporary string to get properly quoted + // MCSymbols when they have spaces in them. + SmallString<128> Tmp; + raw_svector_ostream OS(Tmp); + OS << "\t.thumb_func\t" << *CurrentFnSym; + OutStreamer.EmitRawText(OS.str()); + } + } + + OutStreamer.EmitLabel(CurrentFnSym); +} + +/// runOnMachineFunction - This uses the printInstruction() +/// method to print assembly for each instruction. +/// +bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) { + AFI = MF.getInfo(); + MCP = MF.getConstantPool(); + + return AsmPrinter::runOnMachineFunction(MF); +} + +void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, const char *Modifier) { + const MachineOperand &MO = MI->getOperand(OpNum); + unsigned TF = MO.getTargetFlags(); + + switch (MO.getType()) { + default: + assert(0 && ""); + case MachineOperand::MO_Register: { + unsigned Reg = MO.getReg(); + assert(TargetRegisterInfo::isPhysicalRegister(Reg)); + if (Modifier && strcmp(Modifier, "dregpair") == 0) { + unsigned DRegLo = TM.getRegisterInfo()->getSubReg(Reg, ARM::dsub_0); + unsigned DRegHi = TM.getRegisterInfo()->getSubReg(Reg, ARM::dsub_1); + O << '{' + << getRegisterName(DRegLo) << ", " << getRegisterName(DRegHi) + << '}'; + } else if (Modifier && strcmp(Modifier, "lane") == 0) { + unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg); + unsigned DReg = + TM.getRegisterInfo()->getMatchingSuperReg(Reg, + RegNum & 1 ? ARM::ssub_1 : ARM::ssub_0, &ARM::DPR_VFP2RegClass); + O << getRegisterName(DReg) << '[' << (RegNum & 1) << ']'; + } else { + assert(!MO.getSubReg() && "Subregs should be eliminated!"); + O << getRegisterName(Reg); + } + break; + } + case MachineOperand::MO_Immediate: { + int64_t Imm = MO.getImm(); + O << '#'; + if ((Modifier && strcmp(Modifier, "lo16") == 0) || + (TF & ARMII::MO_LO16)) + O << ":lower16:"; + else if ((Modifier && strcmp(Modifier, "hi16") == 0) || + (TF & ARMII::MO_HI16)) + O << ":upper16:"; + O << Imm; + break; + } + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + return; + case MachineOperand::MO_GlobalAddress: { + bool isCallOp = Modifier && !strcmp(Modifier, "call"); + const GlobalValue *GV = MO.getGlobal(); + + if ((Modifier && strcmp(Modifier, "lo16") == 0) || + (TF & ARMII::MO_LO16)) + O << ":lower16:"; + else if ((Modifier && strcmp(Modifier, "hi16") == 0) || + (TF & ARMII::MO_HI16)) + O << ":upper16:"; + O << *Mang->getSymbol(GV); + + printOffset(MO.getOffset(), O); + + if (isCallOp && Subtarget->isTargetELF() && + TM.getRelocationModel() == Reloc::PIC_) + O << "(PLT)"; + break; + } + case MachineOperand::MO_ExternalSymbol: { + bool isCallOp = Modifier && !strcmp(Modifier, "call"); + O << *GetExternalSymbolSymbol(MO.getSymbolName()); + + if (isCallOp && Subtarget->isTargetELF() && + TM.getRelocationModel() == Reloc::PIC_) + O << "(PLT)"; + break; + } + case MachineOperand::MO_ConstantPoolIndex: + O << *GetCPISymbol(MO.getIndex()); + break; + case MachineOperand::MO_JumpTableIndex: + O << *GetJTISymbol(MO.getIndex()); + break; + } +} + +static void printSOImm(raw_ostream &O, int64_t V, bool VerboseAsm, + const MCAsmInfo *MAI) { + // Break it up into two parts that make up a shifter immediate. + V = ARM_AM::getSOImmVal(V); + assert(V != -1 && "Not a valid so_imm value!"); + + unsigned Imm = ARM_AM::getSOImmValImm(V); + unsigned Rot = ARM_AM::getSOImmValRot(V); + + // Print low-level immediate formation info, per + // A5.1.3: "Data-processing operands - Immediate". + if (Rot) { + O << "#" << Imm << ", " << Rot; + // Pretty printed version. + if (VerboseAsm) { + O << "\t" << MAI->getCommentString() << ' '; + O << (int)ARM_AM::rotr32(Imm, Rot); + } + } else { + O << "#" << Imm; + } +} + +/// printSOImmOperand - SOImm is 4-bit rotate amount in bits 8-11 with 8-bit +/// immediate in bits 0-7. +void ARMAsmPrinter::printSOImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(OpNum); + assert(MO.isImm() && "Not a valid so_imm value!"); + printSOImm(O, MO.getImm(), isVerbose(), MAI); +} + +/// printSOImm2PartOperand - SOImm is broken into two pieces using a 'mov' +/// followed by an 'orr' to materialize. +void ARMAsmPrinter::printSOImm2PartOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(OpNum); + assert(MO.isImm() && "Not a valid so_imm value!"); + unsigned V1 = ARM_AM::getSOImmTwoPartFirst(MO.getImm()); + unsigned V2 = ARM_AM::getSOImmTwoPartSecond(MO.getImm()); + printSOImm(O, V1, isVerbose(), MAI); + O << "\n\torr"; + printPredicateOperand(MI, 2, O); + O << "\t"; + printOperand(MI, 0, O); + O << ", "; + printOperand(MI, 0, O); + O << ", "; + printSOImm(O, V2, isVerbose(), MAI); +} + +// so_reg is a 4-operand unit corresponding to register forms of the A5.1 +// "Addressing Mode 1 - Data-processing operands" forms. This includes: +// REG 0 0 - e.g. R5 +// REG REG 0,SH_OPC - e.g. R5, ROR R3 +// REG 0 IMM,SH_OPC - e.g. R5, LSL #3 +void ARMAsmPrinter::printSORegOperand(const MachineInstr *MI, int Op, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(Op); + const MachineOperand &MO2 = MI->getOperand(Op+1); + const MachineOperand &MO3 = MI->getOperand(Op+2); + + O << getRegisterName(MO1.getReg()); + + // Print the shift opc. + ARM_AM::ShiftOpc ShOpc = ARM_AM::getSORegShOp(MO3.getImm()); + O << ", " << ARM_AM::getShiftOpcStr(ShOpc); + if (MO2.getReg()) { + O << ' ' << getRegisterName(MO2.getReg()); + assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); + } else if (ShOpc != ARM_AM::rrx) { + O << " #" << ARM_AM::getSORegOffset(MO3.getImm()); + } +} + +void ARMAsmPrinter::printAddrMode2Operand(const MachineInstr *MI, int Op, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(Op); + const MachineOperand &MO2 = MI->getOperand(Op+1); + const MachineOperand &MO3 = MI->getOperand(Op+2); + + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. + printOperand(MI, Op, O); + return; + } + + O << "[" << getRegisterName(MO1.getReg()); + + if (!MO2.getReg()) { + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. + O << ", #" + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) + << ARM_AM::getAM2Offset(MO3.getImm()); + O << "]"; + return; + } + + O << ", " + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) + << getRegisterName(MO2.getReg()); + + if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) + O << ", " + << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO3.getImm())) + << " #" << ShImm; + O << "]"; +} + +void ARMAsmPrinter::printAddrMode2OffsetOperand(const MachineInstr *MI, int Op, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(Op); + const MachineOperand &MO2 = MI->getOperand(Op+1); + + if (!MO1.getReg()) { + unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); + O << "#" + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) + << ImmOffs; + return; + } + + O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) + << getRegisterName(MO1.getReg()); + + if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) + O << ", " + << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO2.getImm())) + << " #" << ShImm; +} + +void ARMAsmPrinter::printAddrMode3Operand(const MachineInstr *MI, int Op, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(Op); + const MachineOperand &MO2 = MI->getOperand(Op+1); + const MachineOperand &MO3 = MI->getOperand(Op+2); + + assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); + O << "[" << getRegisterName(MO1.getReg()); + + if (MO2.getReg()) { + O << ", " + << (char)ARM_AM::getAM3Op(MO3.getImm()) + << getRegisterName(MO2.getReg()) + << "]"; + return; + } + + if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) + O << ", #" + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) + << ImmOffs; + O << "]"; +} + +void ARMAsmPrinter::printAddrMode3OffsetOperand(const MachineInstr *MI, int Op, + raw_ostream &O){ + const MachineOperand &MO1 = MI->getOperand(Op); + const MachineOperand &MO2 = MI->getOperand(Op+1); + + if (MO1.getReg()) { + O << (char)ARM_AM::getAM3Op(MO2.getImm()) + << getRegisterName(MO1.getReg()); + return; + } + + unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); + O << "#" + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) + << ImmOffs; +} + +void ARMAsmPrinter::printAddrMode4Operand(const MachineInstr *MI, int Op, + raw_ostream &O, + const char *Modifier) { + const MachineOperand &MO2 = MI->getOperand(Op+1); + ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); + if (Modifier && strcmp(Modifier, "submode") == 0) { + O << ARM_AM::getAMSubModeStr(Mode); + } else if (Modifier && strcmp(Modifier, "wide") == 0) { + ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); + if (Mode == ARM_AM::ia) + O << ".w"; + } else { + printOperand(MI, Op, O); + } +} + +void ARMAsmPrinter::printAddrMode5Operand(const MachineInstr *MI, int Op, + raw_ostream &O, + const char *Modifier) { + const MachineOperand &MO1 = MI->getOperand(Op); + const MachineOperand &MO2 = MI->getOperand(Op+1); + + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. + printOperand(MI, Op, O); + return; + } + + assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); + + O << "[" << getRegisterName(MO1.getReg()); + + if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { + O << ", #" + << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) + << ImmOffs*4; + } + O << "]"; +} + +void ARMAsmPrinter::printAddrMode6Operand(const MachineInstr *MI, int Op, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(Op); + const MachineOperand &MO2 = MI->getOperand(Op+1); + + O << "[" << getRegisterName(MO1.getReg()); + if (MO2.getImm()) { + // FIXME: Both darwin as and GNU as violate ARM docs here. + O << ", :" << (MO2.getImm() << 3); + } + O << "]"; +} + +void ARMAsmPrinter::printAddrMode6OffsetOperand(const MachineInstr *MI, int Op, + raw_ostream &O){ + const MachineOperand &MO = MI->getOperand(Op); + if (MO.getReg() == 0) + O << "!"; + else + O << ", " << getRegisterName(MO.getReg()); +} + +void ARMAsmPrinter::printAddrModePCOperand(const MachineInstr *MI, int Op, + raw_ostream &O, + const char *Modifier) { + if (Modifier && strcmp(Modifier, "label") == 0) { + printPCLabel(MI, Op+1, O); + return; + } + + const MachineOperand &MO1 = MI->getOperand(Op); + assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); + O << "[pc, " << getRegisterName(MO1.getReg()) << "]"; +} + +void +ARMAsmPrinter::printBitfieldInvMaskImmOperand(const MachineInstr *MI, int Op, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(Op); + uint32_t v = ~MO.getImm(); + int32_t lsb = CountTrailingZeros_32(v); + int32_t width = (32 - CountLeadingZeros_32 (v)) - lsb; + assert(MO.isImm() && "Not a valid bf_inv_mask_imm value!"); + O << "#" << lsb << ", #" << width; +} + +void +ARMAsmPrinter::printMemBOption(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + unsigned val = MI->getOperand(OpNum).getImm(); + O << ARM_MB::MemBOptToString(val); +} + +void ARMAsmPrinter::printShiftImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + unsigned ShiftOp = MI->getOperand(OpNum).getImm(); + ARM_AM::ShiftOpc Opc = ARM_AM::getSORegShOp(ShiftOp); + switch (Opc) { + case ARM_AM::no_shift: + return; + case ARM_AM::lsl: + O << ", lsl #"; + break; + case ARM_AM::asr: + O << ", asr #"; + break; + default: + assert(0 && "unexpected shift opcode for shift immediate operand"); + } + O << ARM_AM::getSORegOffset(ShiftOp); +} + +//===--------------------------------------------------------------------===// + +void ARMAsmPrinter::printThumbS4ImmOperand(const MachineInstr *MI, int Op, + raw_ostream &O) { + O << "#" << MI->getOperand(Op).getImm() * 4; +} + +void +ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op, + raw_ostream &O) { + // (3 - the number of trailing zeros) is the number of then / else. + unsigned Mask = MI->getOperand(Op).getImm(); + unsigned CondBit0 = Mask >> 4 & 1; + unsigned NumTZ = CountTrailingZeros_32(Mask); + assert(NumTZ <= 3 && "Invalid IT mask!"); + for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { + bool T = ((Mask >> Pos) & 1) == CondBit0; + if (T) + O << 't'; + else + O << 'e'; + } +} + +void +ARMAsmPrinter::printThumbAddrModeRROperand(const MachineInstr *MI, int Op, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(Op); + const MachineOperand &MO2 = MI->getOperand(Op+1); + O << "[" << getRegisterName(MO1.getReg()); + O << ", " << getRegisterName(MO2.getReg()) << "]"; +} + +void +ARMAsmPrinter::printThumbAddrModeRI5Operand(const MachineInstr *MI, int Op, + raw_ostream &O, + unsigned Scale) { + const MachineOperand &MO1 = MI->getOperand(Op); + const MachineOperand &MO2 = MI->getOperand(Op+1); + const MachineOperand &MO3 = MI->getOperand(Op+2); + + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. + printOperand(MI, Op, O); + return; + } + + O << "[" << getRegisterName(MO1.getReg()); + if (MO3.getReg()) + O << ", " << getRegisterName(MO3.getReg()); + else if (unsigned ImmOffs = MO2.getImm()) + O << ", #" << ImmOffs * Scale; + O << "]"; +} + +void +ARMAsmPrinter::printThumbAddrModeS1Operand(const MachineInstr *MI, int Op, + raw_ostream &O) { + printThumbAddrModeRI5Operand(MI, Op, O, 1); +} +void +ARMAsmPrinter::printThumbAddrModeS2Operand(const MachineInstr *MI, int Op, + raw_ostream &O) { + printThumbAddrModeRI5Operand(MI, Op, O, 2); +} +void +ARMAsmPrinter::printThumbAddrModeS4Operand(const MachineInstr *MI, int Op, + raw_ostream &O) { + printThumbAddrModeRI5Operand(MI, Op, O, 4); +} + +void ARMAsmPrinter::printThumbAddrModeSPOperand(const MachineInstr *MI,int Op, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(Op); + const MachineOperand &MO2 = MI->getOperand(Op+1); + O << "[" << getRegisterName(MO1.getReg()); + if (unsigned ImmOffs = MO2.getImm()) + O << ", #" << ImmOffs*4; + O << "]"; +} + +//===--------------------------------------------------------------------===// + +// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2 +// register with shift forms. +// REG 0 0 - e.g. R5 +// REG IMM, SH_OPC - e.g. R5, LSL #3 +void ARMAsmPrinter::printT2SOOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); + + unsigned Reg = MO1.getReg(); + assert(TargetRegisterInfo::isPhysicalRegister(Reg)); + O << getRegisterName(Reg); + + // Print the shift opc. + assert(MO2.isImm() && "Not a valid t2_so_reg value!"); + ARM_AM::ShiftOpc ShOpc = ARM_AM::getSORegShOp(MO2.getImm()); + O << ", " << ARM_AM::getShiftOpcStr(ShOpc); + if (ShOpc != ARM_AM::rrx) + O << " #" << ARM_AM::getSORegOffset(MO2.getImm()); +} + +void ARMAsmPrinter::printT2AddrModeImm12Operand(const MachineInstr *MI, + int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); + + O << "[" << getRegisterName(MO1.getReg()); + + unsigned OffImm = MO2.getImm(); + if (OffImm) // Don't print +0. + O << ", #" << OffImm; + O << "]"; +} + +void ARMAsmPrinter::printT2AddrModeImm8Operand(const MachineInstr *MI, + int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); + + O << "[" << getRegisterName(MO1.getReg()); + + int32_t OffImm = (int32_t)MO2.getImm(); + // Don't print +0. + if (OffImm < 0) + O << ", #-" << -OffImm; + else if (OffImm > 0) + O << ", #" << OffImm; + O << "]"; +} + +void ARMAsmPrinter::printT2AddrModeImm8s4Operand(const MachineInstr *MI, + int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); + + O << "[" << getRegisterName(MO1.getReg()); + + int32_t OffImm = (int32_t)MO2.getImm() / 4; + // Don't print +0. + if (OffImm < 0) + O << ", #-" << -OffImm * 4; + else if (OffImm > 0) + O << ", #" << OffImm * 4; + O << "]"; +} + +void ARMAsmPrinter::printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, + int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + int32_t OffImm = (int32_t)MO1.getImm(); + // Don't print +0. + if (OffImm < 0) + O << "#-" << -OffImm; + else if (OffImm > 0) + O << "#" << OffImm; +} + +void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, + int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); + const MachineOperand &MO3 = MI->getOperand(OpNum+2); + + O << "[" << getRegisterName(MO1.getReg()); + + assert(MO2.getReg() && "Invalid so_reg load / store address!"); + O << ", " << getRegisterName(MO2.getReg()); + + unsigned ShAmt = MO3.getImm(); + if (ShAmt) { + assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!"); + O << ", lsl #" << ShAmt; + } + O << "]"; +} + + +//===--------------------------------------------------------------------===// + +void ARMAsmPrinter::printPredicateOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); + if (CC != ARMCC::AL) + O << ARMCondCodeToString(CC); +} + +void ARMAsmPrinter::printMandatoryPredicateOperand(const MachineInstr *MI, + int OpNum, + raw_ostream &O) { + ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); + O << ARMCondCodeToString(CC); +} + +void ARMAsmPrinter::printSBitModifierOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O){ + unsigned Reg = MI->getOperand(OpNum).getReg(); + if (Reg) { + assert(Reg == ARM::CPSR && "Expect ARM CPSR register!"); + O << 's'; + } +} + +void ARMAsmPrinter::printPCLabel(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + int Id = (int)MI->getOperand(OpNum).getImm(); + O << MAI->getPrivateGlobalPrefix() + << "PC" << getFunctionNumber() << "_" << Id; +} + +void ARMAsmPrinter::printRegisterList(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + O << "{"; + for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) { + if (MI->getOperand(i).isImplicit()) + continue; + if ((int)i != OpNum) O << ", "; + printOperand(MI, i, O); + } + O << "}"; +} + +void ARMAsmPrinter::printCPInstOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, const char *Modifier) { + assert(Modifier && "This operand only works with a modifier!"); + // There are two aspects to a CONSTANTPOOL_ENTRY operand, the label and the + // data itself. + if (!strcmp(Modifier, "label")) { + unsigned ID = MI->getOperand(OpNum).getImm(); + OutStreamer.EmitLabel(GetCPISymbol(ID)); + } else { + assert(!strcmp(Modifier, "cpentry") && "Unknown modifier for CPE"); + unsigned CPI = MI->getOperand(OpNum).getIndex(); + + const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPI]; + + if (MCPE.isMachineConstantPoolEntry()) { + EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); + } else { + EmitGlobalConstant(MCPE.Val.ConstVal); + } + } +} + +MCSymbol *ARMAsmPrinter:: +GetARMSetPICJumpTableLabel2(unsigned uid, unsigned uid2, + const MachineBasicBlock *MBB) const { + SmallString<60> Name; + raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() + << getFunctionNumber() << '_' << uid << '_' << uid2 + << "_set_" << MBB->getNumber(); + return OutContext.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *ARMAsmPrinter:: +GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const { + SmallString<60> Name; + raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() << "JTI" + << getFunctionNumber() << '_' << uid << '_' << uid2; + return OutContext.GetOrCreateSymbol(Name.str()); +} + +void ARMAsmPrinter::printJTBlockOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + assert(!Subtarget->isThumb2() && "Thumb2 should use double-jump jumptables!"); + + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id + + unsigned JTI = MO1.getIndex(); + MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); + // Can't use EmitLabel until instprinter happens, label comes out in the wrong + // order. + O << "\n" << *JTISymbol << ":\n"; + + const char *JTEntryDirective = MAI->getData32bitsDirective(); + + const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); + const std::vector &JT = MJTI->getJumpTables(); + const std::vector &JTBBs = JT[JTI].MBBs; + bool UseSet= MAI->hasSetDirective() && TM.getRelocationModel() == Reloc::PIC_; + SmallPtrSet JTSets; + for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { + MachineBasicBlock *MBB = JTBBs[i]; + bool isNew = JTSets.insert(MBB); + + if (UseSet && isNew) { + O << "\t.set\t" + << *GetARMSetPICJumpTableLabel2(JTI, MO2.getImm(), MBB) << ',' + << *MBB->getSymbol() << '-' << *JTISymbol << '\n'; + } + + O << JTEntryDirective << ' '; + if (UseSet) + O << *GetARMSetPICJumpTableLabel2(JTI, MO2.getImm(), MBB); + else if (TM.getRelocationModel() == Reloc::PIC_) + O << *MBB->getSymbol() << '-' << *JTISymbol; + else + O << *MBB->getSymbol(); + + if (i != e-1) + O << '\n'; + } +} + +void ARMAsmPrinter::printJT2BlockOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id + unsigned JTI = MO1.getIndex(); + + MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); + + // Can't use EmitLabel until instprinter happens, label comes out in the wrong + // order. + O << "\n" << *JTISymbol << ":\n"; + + const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); + const std::vector &JT = MJTI->getJumpTables(); + const std::vector &JTBBs = JT[JTI].MBBs; + bool ByteOffset = false, HalfWordOffset = false; + if (MI->getOpcode() == ARM::t2TBB) + ByteOffset = true; + else if (MI->getOpcode() == ARM::t2TBH) + HalfWordOffset = true; + + for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { + MachineBasicBlock *MBB = JTBBs[i]; + if (ByteOffset) + O << MAI->getData8bitsDirective(); + else if (HalfWordOffset) + O << MAI->getData16bitsDirective(); + + if (ByteOffset || HalfWordOffset) + O << '(' << *MBB->getSymbol() << "-" << *JTISymbol << ")/2"; + else + O << "\tb.w " << *MBB->getSymbol(); + + if (i != e-1) + O << '\n'; + } +} + +void ARMAsmPrinter::printTBAddrMode(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + O << "[pc, " << getRegisterName(MI->getOperand(OpNum).getReg()); + if (MI->getOpcode() == ARM::t2TBH) + O << ", lsl #1"; + O << ']'; +} + +void ARMAsmPrinter::printNoHashImmediate(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + O << MI->getOperand(OpNum).getImm(); +} + +void ARMAsmPrinter::printVFPf32ImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const ConstantFP *FP = MI->getOperand(OpNum).getFPImm(); + O << '#' << FP->getValueAPF().convertToFloat(); + if (isVerbose()) { + O << "\t\t" << MAI->getCommentString() << ' '; + WriteAsOperand(O, FP, /*PrintType=*/false); + } +} + +void ARMAsmPrinter::printVFPf64ImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const ConstantFP *FP = MI->getOperand(OpNum).getFPImm(); + O << '#' << FP->getValueAPF().convertToDouble(); + if (isVerbose()) { + O << "\t\t" << MAI->getCommentString() << ' '; + WriteAsOperand(O, FP, /*PrintType=*/false); + } +} + +void ARMAsmPrinter::printNEONModImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + unsigned EncodedImm = MI->getOperand(OpNum).getImm(); + unsigned EltBits; + uint64_t Val = ARM_AM::decodeNEONModImm(EncodedImm, EltBits); + O << "#0x" << utohexstr(Val); +} + +bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O) { + // Does this asm operand have a single letter operand modifier? + if (ExtraCode && ExtraCode[0]) { + if (ExtraCode[1] != 0) return true; // Unknown modifier. + + switch (ExtraCode[0]) { + default: return true; // Unknown modifier. + case 'a': // Print as a memory address. + if (MI->getOperand(OpNum).isReg()) { + O << "[" << getRegisterName(MI->getOperand(OpNum).getReg()) << "]"; + return false; + } + // Fallthrough + case 'c': // Don't print "#" before an immediate operand. + if (!MI->getOperand(OpNum).isImm()) + return true; + printNoHashImmediate(MI, OpNum, O); + return false; + case 'P': // Print a VFP double precision register. + case 'q': // Print a NEON quad precision register. + printOperand(MI, OpNum, O); + return false; + case 'Q': + case 'R': + case 'H': + report_fatal_error("llvm does not support 'Q', 'R', and 'H' modifiers!"); + return true; + } + } + + printOperand(MI, OpNum, O); + return false; +} + +bool ARMAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNum, unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &O) { + if (ExtraCode && ExtraCode[0]) + return true; // Unknown modifier. + + const MachineOperand &MO = MI->getOperand(OpNum); + assert(MO.isReg() && "unexpected inline asm memory operand"); + O << "[" << getRegisterName(MO.getReg()) << "]"; + return false; +} + +void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) { + if (EnableMCInst) { + printInstructionThroughMCStreamer(MI); + return; + } + + if (MI->getOpcode() == ARM::CONSTPOOL_ENTRY) + EmitAlignment(2); + + SmallString<128> Str; + raw_svector_ostream OS(Str); + if (MI->getOpcode() == ARM::DBG_VALUE) { + unsigned NOps = MI->getNumOperands(); + assert(NOps==4); + OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: "; + // cast away const; DIetc do not take const operands for some reason. + DIVariable V(const_cast(MI->getOperand(NOps-1).getMetadata())); + OS << V.getName(); + OS << " <- "; + // Frame address. Currently handles register +- offset only. + assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm()); + OS << '['; printOperand(MI, 0, OS); OS << '+'; printOperand(MI, 1, OS); + OS << ']'; + OS << "+"; + printOperand(MI, NOps-2, OS); + OutStreamer.EmitRawText(OS.str()); + return; + } + + printInstruction(MI, OS); + OutStreamer.EmitRawText(OS.str()); + + // Make sure the instruction that follows TBB is 2-byte aligned. + // FIXME: Constant island pass should insert an "ALIGN" instruction instead. + if (MI->getOpcode() == ARM::t2TBB) + EmitAlignment(1); +} + +void ARMAsmPrinter::EmitStartOfAsmFile(Module &M) { + if (Subtarget->isTargetDarwin()) { + Reloc::Model RelocM = TM.getRelocationModel(); + if (RelocM == Reloc::PIC_ || RelocM == Reloc::DynamicNoPIC) { + // Declare all the text sections up front (before the DWARF sections + // emitted by AsmPrinter::doInitialization) so the assembler will keep + // them together at the beginning of the object file. This helps + // avoid out-of-range branches that are due a fundamental limitation of + // the way symbol offsets are encoded with the current Darwin ARM + // relocations. + const TargetLoweringObjectFileMachO &TLOFMacho = + static_cast( + getObjFileLowering()); + OutStreamer.SwitchSection(TLOFMacho.getTextSection()); + OutStreamer.SwitchSection(TLOFMacho.getTextCoalSection()); + OutStreamer.SwitchSection(TLOFMacho.getConstTextCoalSection()); + if (RelocM == Reloc::DynamicNoPIC) { + const MCSection *sect = + OutContext.getMachOSection("__TEXT", "__symbol_stub4", + MCSectionMachO::S_SYMBOL_STUBS, + 12, SectionKind::getText()); + OutStreamer.SwitchSection(sect); + } else { + const MCSection *sect = + OutContext.getMachOSection("__TEXT", "__picsymbolstub4", + MCSectionMachO::S_SYMBOL_STUBS, + 16, SectionKind::getText()); + OutStreamer.SwitchSection(sect); + } + const MCSection *StaticInitSect = + OutContext.getMachOSection("__TEXT", "__StaticInit", + MCSectionMachO::S_REGULAR | + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + SectionKind::getText()); + OutStreamer.SwitchSection(StaticInitSect); + } + } + + // Use unified assembler syntax. + OutStreamer.EmitRawText(StringRef("\t.syntax unified")); + + // Emit ARM Build Attributes + if (Subtarget->isTargetELF()) { + // CPU Type + std::string CPUString = Subtarget->getCPUString(); + if (CPUString != "generic") + OutStreamer.EmitRawText("\t.cpu " + Twine(CPUString)); + + // FIXME: Emit FPU type + if (Subtarget->hasVFP2()) + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::VFP_arch) + ", 2"); + + // Signal various FP modes. + if (!UnsafeFPMath) { + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_FP_denormal) + ", 1"); + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_FP_exceptions) + ", 1"); + } + + if (NoInfsFPMath && NoNaNsFPMath) + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_FP_number_model)+ ", 1"); + else + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_FP_number_model)+ ", 3"); + + // 8-bytes alignment stuff. + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_align8_needed) + ", 1"); + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_align8_preserved) + ", 1"); + + // Hard float. Use both S and D registers and conform to AAPCS-VFP. + if (Subtarget->isAAPCS_ABI() && FloatABIType == FloatABI::Hard) { + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_HardFP_use) + ", 3"); + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_VFP_args) + ", 1"); + } + // FIXME: Should we signal R9 usage? + } +} + + +void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) { + if (Subtarget->isTargetDarwin()) { + // All darwin targets use mach-o. + const TargetLoweringObjectFileMachO &TLOFMacho = + static_cast(getObjFileLowering()); + MachineModuleInfoMachO &MMIMacho = + MMI->getObjFileInfo(); + + // Output non-lazy-pointers for external and common global variables. + MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetGVStubList(); + + if (!Stubs.empty()) { + // Switch with ".non_lazy_symbol_pointer" directive. + OutStreamer.SwitchSection(TLOFMacho.getNonLazySymbolPointerSection()); + EmitAlignment(2); + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + // L_foo$stub: + OutStreamer.EmitLabel(Stubs[i].first); + // .indirect_symbol _foo + MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second; + OutStreamer.EmitSymbolAttribute(MCSym.getPointer(),MCSA_IndirectSymbol); + + if (MCSym.getInt()) + // External to current translation unit. + OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/); + else + // Internal to current translation unit. + // + // When we place the LSDA into the TEXT section, the type info pointers + // need to be indirect and pc-rel. We accomplish this by using NLPs. + // However, sometimes the types are local to the file. So we need to + // fill in the value for the NLP in those cases. + OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym.getPointer(), + OutContext), + 4/*size*/, 0/*addrspace*/); + } + + Stubs.clear(); + OutStreamer.AddBlankLine(); + } + + Stubs = MMIMacho.GetHiddenGVStubList(); + if (!Stubs.empty()) { + OutStreamer.SwitchSection(getObjFileLowering().getDataSection()); + EmitAlignment(2); + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + // L_foo$stub: + OutStreamer.EmitLabel(Stubs[i].first); + // .long _foo + OutStreamer.EmitValue(MCSymbolRefExpr:: + Create(Stubs[i].second.getPointer(), + OutContext), + 4/*size*/, 0/*addrspace*/); + } + + Stubs.clear(); + OutStreamer.AddBlankLine(); + } + + // Funny Darwin hack: This flag tells the linker that no global symbols + // contain code that falls through to other global symbols (e.g. the obvious + // implementation of multiple entry points). If this doesn't occur, the + // linker can safely perform dead code stripping. Since LLVM never + // generates code that does this, it is always safe to set. + OutStreamer.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols); + } +} + +//===----------------------------------------------------------------------===// + +void ARMAsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) { + ARMMCInstLower MCInstLowering(OutContext, *Mang, *this); + switch (MI->getOpcode()) { + case ARM::t2MOVi32imm: + assert(0 && "Should be lowered by thumb2it pass"); + default: break; + case ARM::PICADD: { // FIXME: Remove asm string from td file. + // This is a pseudo op for a label + instruction sequence, which looks like: + // LPC0: + // add r0, pc, r0 + // This adds the address of LPC0 to r0. + + // Emit the label. + // FIXME: MOVE TO SHARED PLACE. + unsigned Id = (unsigned)MI->getOperand(2).getImm(); + const char *Prefix = MAI->getPrivateGlobalPrefix(); + MCSymbol *Label =OutContext.GetOrCreateSymbol(Twine(Prefix) + + "PC" + Twine(getFunctionNumber()) + "_" + Twine(Id)); + OutStreamer.EmitLabel(Label); + + + // Form and emit tha dd. + MCInst AddInst; + AddInst.setOpcode(ARM::ADDrr); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + AddInst.addOperand(MCOperand::CreateReg(ARM::PC)); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); + OutStreamer.EmitInstruction(AddInst); + return; + } + case ARM::CONSTPOOL_ENTRY: { // FIXME: Remove asm string from td file. + /// CONSTPOOL_ENTRY - This instruction represents a floating constant pool + /// in the function. The first operand is the ID# for this instruction, the + /// second is the index into the MachineConstantPool that this is, the third + /// is the size in bytes of this constant pool entry. + unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); + unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); + + EmitAlignment(2); + OutStreamer.EmitLabel(GetCPISymbol(LabelId)); + + const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; + if (MCPE.isMachineConstantPoolEntry()) + EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); + else + EmitGlobalConstant(MCPE.Val.ConstVal); + + return; + } + case ARM::MOVi2pieces: { // FIXME: Remove asmstring from td file. + // This is a hack that lowers as a two instruction sequence. + unsigned DstReg = MI->getOperand(0).getReg(); + unsigned ImmVal = (unsigned)MI->getOperand(1).getImm(); + + unsigned SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(ImmVal); + unsigned SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(ImmVal); + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVi); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); + TmpInst.addOperand(MCOperand::CreateImm(SOImmValV1)); + + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out + OutStreamer.EmitInstruction(TmpInst); + } + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::ORRri); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // inreg + TmpInst.addOperand(MCOperand::CreateImm(SOImmValV2)); // so_imm + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out + OutStreamer.EmitInstruction(TmpInst); + } + return; + } + case ARM::MOVi32imm: { // FIXME: Remove asmstring from td file. + // This is a hack that lowers as a two instruction sequence. + unsigned DstReg = MI->getOperand(0).getReg(); + const MachineOperand &MO = MI->getOperand(1); + MCOperand V1, V2; + if (MO.isImm()) { + unsigned ImmVal = (unsigned)MI->getOperand(1).getImm(); + V1 = MCOperand::CreateImm(ImmVal & 65535); + V2 = MCOperand::CreateImm(ImmVal >> 16); + } else if (MO.isGlobal()) { + MCSymbol *Symbol = MCInstLowering.GetGlobalAddressSymbol(MO); + const MCSymbolRefExpr *SymRef1 = + MCSymbolRefExpr::Create(Symbol, + MCSymbolRefExpr::VK_ARM_LO16, OutContext); + const MCSymbolRefExpr *SymRef2 = + MCSymbolRefExpr::Create(Symbol, + MCSymbolRefExpr::VK_ARM_HI16, OutContext); + V1 = MCOperand::CreateExpr(SymRef1); + V2 = MCOperand::CreateExpr(SymRef2); + } else { + MI->dump(); + llvm_unreachable("cannot handle this operand"); + } + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVi16); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg + TmpInst.addOperand(V1); // lower16(imm) + + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + OutStreamer.EmitInstruction(TmpInst); + } + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVTi16); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // srcreg + TmpInst.addOperand(V2); // upper16(imm) + + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + OutStreamer.EmitInstruction(TmpInst); + } + + return; + } + } + + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + OutStreamer.EmitInstruction(TmpInst); +} + +//===----------------------------------------------------------------------===// +// Target Registry Stuff +//===----------------------------------------------------------------------===// + +static MCInstPrinter *createARMMCInstPrinter(const Target &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI) { + if (SyntaxVariant == 0) + return new ARMInstPrinter(MAI, false); + return 0; +} + +// Force static initialization. +extern "C" void LLVMInitializeARMAsmPrinter() { + RegisterAsmPrinter X(TheARMTarget); + RegisterAsmPrinter Y(TheThumbTarget); + + TargetRegistry::RegisterMCInstPrinter(TheARMTarget, createARMMCInstPrinter); + TargetRegistry::RegisterMCInstPrinter(TheThumbTarget, createARMMCInstPrinter); +} + diff --git a/lib/Target/ARM/ARMBaseInstrInfo.cpp b/lib/Target/ARM/ARMBaseInstrInfo.cpp index 49c16f3..3a8bebe 100644 --- a/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ b/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -15,9 +15,9 @@ #include "ARM.h" #include "ARMAddressingModes.h" #include "ARMConstantPoolValue.h" -#include "ARMGenInstrInfo.inc" #include "ARMMachineFunctionInfo.h" #include "ARMRegisterInfo.h" +#include "ARMGenInstrInfo.inc" #include "llvm/Constants.h" #include "llvm/Function.h" #include "llvm/GlobalValue.h" @@ -501,7 +501,7 @@ unsigned ARMBaseInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const { llvm_unreachable("Unknown or unset size field for instr!"); case TargetOpcode::IMPLICIT_DEF: case TargetOpcode::KILL: - case TargetOpcode::DBG_LABEL: + case TargetOpcode::PROLOG_LABEL: case TargetOpcode::EH_LABEL: case TargetOpcode::DBG_VALUE: return 0; @@ -573,48 +573,6 @@ unsigned ARMBaseInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const { return 0; // Not reached } -/// Return true if the instruction is a register to register move and -/// leave the source and dest operands in the passed parameters. -/// -bool -ARMBaseInstrInfo::isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned& SrcSubIdx, unsigned& DstSubIdx) const { - switch (MI.getOpcode()) { - default: break; - case ARM::VMOVS: - case ARM::VMOVD: - case ARM::VMOVDneon: - case ARM::VMOVQ: - case ARM::VMOVQQ : { - SrcReg = MI.getOperand(1).getReg(); - DstReg = MI.getOperand(0).getReg(); - SrcSubIdx = MI.getOperand(1).getSubReg(); - DstSubIdx = MI.getOperand(0).getSubReg(); - return true; - } - case ARM::MOVr: - case ARM::MOVr_TC: - case ARM::tMOVr: - case ARM::tMOVgpr2tgpr: - case ARM::tMOVtgpr2gpr: - case ARM::tMOVgpr2gpr: - case ARM::t2MOVr: { - assert(MI.getDesc().getNumOperands() >= 2 && - MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - "Invalid ARM MOV instruction"); - SrcReg = MI.getOperand(1).getReg(); - DstReg = MI.getOperand(0).getReg(); - SrcSubIdx = MI.getOperand(1).getSubReg(); - DstSubIdx = MI.getOperand(0).getSubReg(); - return true; - } - } - - return false; -} - unsigned ARMBaseInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const { @@ -763,8 +721,9 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, Align); // tGPR is used sometimes in ARM instructions that need to avoid using - // certain registers. Just treat it as GPR here. - if (RC == ARM::tGPRRegisterClass || RC == ARM::tcGPRRegisterClass) + // certain registers. Just treat it as GPR here. Likewise, rGPR. + if (RC == ARM::tGPRRegisterClass || RC == ARM::tcGPRRegisterClass + || RC == ARM::rGPRRegisterClass) RC = ARM::GPRRegisterClass; switch (RC->getID()) { @@ -798,7 +757,7 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VSTMQ)) .addReg(SrcReg, getKillRegState(isKill)) .addFrameIndex(FI) - .addImm(ARM_AM::getAM5Opc(ARM_AM::ia, 4)) + .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia)) .addMemOperand(MMO)); } break; @@ -818,7 +777,7 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, MachineInstrBuilder MIB = AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VSTMD)) .addFrameIndex(FI) - .addImm(ARM_AM::getAM5Opc(ARM_AM::ia, 4))) + .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))) .addMemOperand(MMO); MIB = AddDReg(MIB, SrcReg, ARM::dsub_0, getKillRegState(isKill), TRI); MIB = AddDReg(MIB, SrcReg, ARM::dsub_1, 0, TRI); @@ -830,7 +789,7 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, MachineInstrBuilder MIB = AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VSTMD)) .addFrameIndex(FI) - .addImm(ARM_AM::getAM5Opc(ARM_AM::ia, 4))) + .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))) .addMemOperand(MMO); MIB = AddDReg(MIB, SrcReg, ARM::dsub_0, getKillRegState(isKill), TRI); MIB = AddDReg(MIB, SrcReg, ARM::dsub_1, 0, TRI); @@ -865,7 +824,8 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, // tGPR is used sometimes in ARM instructions that need to avoid using // certain registers. Just treat it as GPR here. - if (RC == ARM::tGPRRegisterClass || RC == ARM::tcGPRRegisterClass) + if (RC == ARM::tGPRRegisterClass || RC == ARM::tcGPRRegisterClass + || RC == ARM::rGPRRegisterClass) RC = ARM::GPRRegisterClass; switch (RC->getID()) { @@ -893,7 +853,7 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, } else { AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLDMQ), DestReg) .addFrameIndex(FI) - .addImm(ARM_AM::getAM5Opc(ARM_AM::ia, 4)) + .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia)) .addMemOperand(MMO)); } break; @@ -910,7 +870,7 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, MachineInstrBuilder MIB = AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLDMD)) .addFrameIndex(FI) - .addImm(ARM_AM::getAM5Opc(ARM_AM::ia, 4))) + .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))) .addMemOperand(MMO); MIB = AddDReg(MIB, DestReg, ARM::dsub_0, RegState::Define, TRI); MIB = AddDReg(MIB, DestReg, ARM::dsub_1, RegState::Define, TRI); @@ -922,7 +882,7 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, MachineInstrBuilder MIB = AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLDMD)) .addFrameIndex(FI) - .addImm(ARM_AM::getAM5Opc(ARM_AM::ia, 4))) + .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))) .addMemOperand(MMO); MIB = AddDReg(MIB, DestReg, ARM::dsub_0, RegState::Define, TRI); MIB = AddDReg(MIB, DestReg, ARM::dsub_1, RegState::Define, TRI); @@ -963,6 +923,11 @@ static unsigned duplicateCPV(MachineFunction &MF, unsigned &CPI) { unsigned PCLabelId = AFI->createConstPoolEntryUId(); ARMConstantPoolValue *NewCPV = 0; + // FIXME: The below assumes PIC relocation model and that the function + // is Thumb mode (t1 or t2). PCAdjustment would be 8 for ARM mode PIC, and + // zero for non-PIC in ARM or Thumb. The callers are all of thumb LDR + // instructions, so that's probably OK, but is PIC always correct when + // we get here? if (ACPV->isGlobalValue()) NewCPV = new ARMConstantPoolValue(ACPV->getGV(), PCLabelId, ARMCP::CPValue, 4); @@ -972,6 +937,9 @@ static unsigned duplicateCPV(MachineFunction &MF, unsigned &CPI) { else if (ACPV->isBlockAddress()) NewCPV = new ARMConstantPoolValue(ACPV->getBlockAddress(), PCLabelId, ARMCP::CPBlockAddress, 4); + else if (ACPV->isLSDA()) + NewCPV = new ARMConstantPoolValue(MF.getFunction(), PCLabelId, + ARMCP::CPLSDA, 4); else llvm_unreachable("Unexpected ARM constantpool value type!!"); CPI = MCP->getConstantPoolIndex(NewCPV, MCPE.getAlignment()); @@ -1393,3 +1361,63 @@ bool llvm::rewriteARMFrameIndex(MachineInstr &MI, unsigned FrameRegIdx, Offset = (isSub) ? -Offset : Offset; return Offset == 0; } + +bool ARMBaseInstrInfo:: +AnalyzeCompare(const MachineInstr *MI, unsigned &SrcReg, int &CmpValue) const { + switch (MI->getOpcode()) { + default: break; + case ARM::CMPri: + case ARM::CMPzri: + case ARM::t2CMPri: + case ARM::t2CMPzri: + SrcReg = MI->getOperand(0).getReg(); + CmpValue = MI->getOperand(1).getImm(); + return true; + } + + return false; +} + +/// ConvertToSetZeroFlag - Convert the instruction to set the "zero" flag so +/// that we can remove a "comparison with zero". +bool ARMBaseInstrInfo:: +ConvertToSetZeroFlag(MachineInstr *MI, MachineInstr *CmpInstr) const { + // Conservatively refuse to convert an instruction which isn't in the same BB + // as the comparison. + if (MI->getParent() != CmpInstr->getParent()) + return false; + + // Check that CPSR isn't set between the comparison instruction and the one we + // want to change. + MachineBasicBlock::const_iterator I = CmpInstr, E = MI; + --I; + for (; I != E; --I) { + const MachineInstr &Instr = *I; + + for (unsigned IO = 0, EO = Instr.getNumOperands(); IO != EO; ++IO) { + const MachineOperand &MO = Instr.getOperand(IO); + if (!MO.isReg() || !MO.isDef()) continue; + + // This instruction modifies CPSR before the one we want to change. We + // can't do this transformation. + if (MO.getReg() == ARM::CPSR) + return false; + } + } + + // Set the "zero" bit in CPSR. + switch (MI->getOpcode()) { + default: break; + case ARM::ADDri: + case ARM::SUBri: + case ARM::t2ADDri: + case ARM::t2SUBri: + MI->RemoveOperand(5); + MachineInstrBuilder(MI) + .addReg(ARM::CPSR, RegState::Define | RegState::Implicit); + CmpInstr->eraseFromParent(); + return true; + } + + return false; +} diff --git a/lib/Target/ARM/ARMBaseInstrInfo.h b/lib/Target/ARM/ARMBaseInstrInfo.h index 89a2db7..b4f4a33 100644 --- a/lib/Target/ARM/ARMBaseInstrInfo.h +++ b/lib/Target/ARM/ARMBaseInstrInfo.h @@ -15,11 +15,12 @@ #define ARMBASEINSTRUCTIONINFO_H #include "ARM.h" -#include "ARMRegisterInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/Target/TargetInstrInfo.h" namespace llvm { + class ARMSubtarget; + class ARMBaseRegisterInfo; /// ARMII - This namespace holds all of the target specific flags that /// instruction info tracks. @@ -97,44 +98,45 @@ namespace ARMII { // Miscellaneous arithmetic instructions ArithMiscFrm = 12 << FormShift, + SatFrm = 13 << FormShift, // Extend instructions - ExtFrm = 13 << FormShift, + ExtFrm = 14 << FormShift, // VFP formats - VFPUnaryFrm = 14 << FormShift, - VFPBinaryFrm = 15 << FormShift, - VFPConv1Frm = 16 << FormShift, - VFPConv2Frm = 17 << FormShift, - VFPConv3Frm = 18 << FormShift, - VFPConv4Frm = 19 << FormShift, - VFPConv5Frm = 20 << FormShift, - VFPLdStFrm = 21 << FormShift, - VFPLdStMulFrm = 22 << FormShift, - VFPMiscFrm = 23 << FormShift, + VFPUnaryFrm = 15 << FormShift, + VFPBinaryFrm = 16 << FormShift, + VFPConv1Frm = 17 << FormShift, + VFPConv2Frm = 18 << FormShift, + VFPConv3Frm = 19 << FormShift, + VFPConv4Frm = 20 << FormShift, + VFPConv5Frm = 21 << FormShift, + VFPLdStFrm = 22 << FormShift, + VFPLdStMulFrm = 23 << FormShift, + VFPMiscFrm = 24 << FormShift, // Thumb format - ThumbFrm = 24 << FormShift, + ThumbFrm = 25 << FormShift, // Miscelleaneous format - MiscFrm = 25 << FormShift, + MiscFrm = 26 << FormShift, // NEON formats - NGetLnFrm = 26 << FormShift, - NSetLnFrm = 27 << FormShift, - NDupFrm = 28 << FormShift, - NLdStFrm = 29 << FormShift, - N1RegModImmFrm= 30 << FormShift, - N2RegFrm = 31 << FormShift, - NVCVTFrm = 32 << FormShift, - NVDupLnFrm = 33 << FormShift, - N2RegVShLFrm = 34 << FormShift, - N2RegVShRFrm = 35 << FormShift, - N3RegFrm = 36 << FormShift, - N3RegVShFrm = 37 << FormShift, - NVExtFrm = 38 << FormShift, - NVMulSLFrm = 39 << FormShift, - NVTBLFrm = 40 << FormShift, + NGetLnFrm = 27 << FormShift, + NSetLnFrm = 28 << FormShift, + NDupFrm = 29 << FormShift, + NLdStFrm = 30 << FormShift, + N1RegModImmFrm= 31 << FormShift, + N2RegFrm = 32 << FormShift, + NVCVTFrm = 33 << FormShift, + NVDupLnFrm = 34 << FormShift, + N2RegVShLFrm = 35 << FormShift, + N2RegVShRFrm = 36 << FormShift, + N3RegFrm = 37 << FormShift, + N3RegVShFrm = 38 << FormShift, + NVExtFrm = 39 << FormShift, + NVMulSLFrm = 40 << FormShift, + NVTBLFrm = 41 << FormShift, //===------------------------------------------------------------------===// // Misc flags. @@ -198,7 +200,7 @@ namespace ARMII { } class ARMBaseInstrInfo : public TargetInstrInfoImpl { - const ARMSubtarget& Subtarget; + const ARMSubtarget &Subtarget; protected: // Can be only subclassed. explicit ARMBaseInstrInfo(const ARMSubtarget &STI); @@ -223,7 +225,7 @@ public: virtual bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl &Cond, - bool AllowModify) const; + bool AllowModify = false) const; virtual unsigned RemoveBranch(MachineBasicBlock &MBB) const; virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, @@ -262,12 +264,6 @@ public: /// virtual unsigned GetInstSizeInBytes(const MachineInstr* MI) const; - /// Return true if the instruction is a register to register move and return - /// the source and dest operands and their sub-register indices by reference. - virtual bool isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const; - virtual unsigned isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const; virtual unsigned isStoreToStackSlot(const MachineInstr *MI, @@ -341,6 +337,17 @@ public: unsigned NumInstrs) const { return NumInstrs && NumInstrs == 1; } + + /// AnalyzeCompare - For a comparison instruction, return the source register + /// in SrcReg and the value it compares against in CmpValue. Return true if + /// the comparison instruction can be analyzed. + virtual bool AnalyzeCompare(const MachineInstr *MI, unsigned &SrcReg, + int &CmpValue) const; + + /// ConvertToSetZeroFlag - Convert the instruction to set the zero flag so + /// that we can remove a "comparison with zero". + virtual bool ConvertToSetZeroFlag(MachineInstr *Instr, + MachineInstr *CmpInstr) const; }; static inline diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/lib/Target/ARM/ARMBaseRegisterInfo.cpp index 182bd99..eceafad 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.cpp +++ b/lib/Target/ARM/ARMBaseRegisterInfo.cpp @@ -40,13 +40,20 @@ #include "llvm/Support/CommandLine.h" namespace llvm { -cl::opt -ReuseFrameIndexVals("arm-reuse-frame-index-vals", cl::Hidden, cl::init(true), - cl::desc("Reuse repeated frame index values")); +static cl::opt +ForceAllBaseRegAlloc("arm-force-base-reg-alloc", cl::Hidden, cl::init(false), + cl::desc("Force use of virtual base registers for stack load/store")); +static cl::opt +EnableLocalStackAlloc("enable-local-stack-alloc", cl::init(true), cl::Hidden, + cl::desc("Enable pre-regalloc stack frame index allocation")); } using namespace llvm; +static cl::opt +EnableBasePointer("arm-use-base-pointer", cl::Hidden, cl::init(true), + cl::desc("Enable use of a base pointer for complex stack frames")); + unsigned ARMBaseRegisterInfo::getRegisterNumbering(unsigned RegEnum, bool *isSPVFP) { if (isSPVFP) @@ -143,7 +150,8 @@ ARMBaseRegisterInfo::ARMBaseRegisterInfo(const ARMBaseInstrInfo &tii, const ARMSubtarget &sti) : ARMGenRegisterInfo(ARM::ADJCALLSTACKDOWN, ARM::ADJCALLSTACKUP), TII(tii), STI(sti), - FramePtr((STI.isTargetDarwin() || STI.isThumb()) ? ARM::R7 : ARM::R11) { + FramePtr((STI.isTargetDarwin() || STI.isThumb()) ? ARM::R7 : ARM::R11), + BasePtr(ARM::R6) { } const unsigned* @@ -176,8 +184,11 @@ getReservedRegs(const MachineFunction &MF) const { BitVector Reserved(getNumRegs()); Reserved.set(ARM::SP); Reserved.set(ARM::PC); - if (STI.isTargetDarwin() || hasFP(MF)) + Reserved.set(ARM::FPSCR); + if (hasFP(MF)) Reserved.set(FramePtr); + if (hasBasePointer(MF)) + Reserved.set(BasePtr); // Some targets reserve R9. if (STI.isR9Reserved()) Reserved.set(ARM::R9); @@ -191,9 +202,13 @@ bool ARMBaseRegisterInfo::isReservedReg(const MachineFunction &MF, case ARM::SP: case ARM::PC: return true; + case ARM::R6: + if (hasBasePointer(MF)) + return true; + break; case ARM::R7: case ARM::R11: - if (FramePtr == Reg && (STI.isTargetDarwin() || hasFP(MF))) + if (FramePtr == Reg && hasFP(MF)) return true; break; case ARM::R9: @@ -510,7 +525,7 @@ ARMBaseRegisterInfo::getAllocationOrder(const TargetRegisterClass *RC, return std::make_pair(RC->allocation_order_begin(MF), RC->allocation_order_end(MF)); - if (!STI.isTargetDarwin() && !hasFP(MF)) { + if (!hasFP(MF)) { if (!STI.isR9Reserved()) return std::make_pair(GPREven1, GPREven1 + (sizeof(GPREven1)/sizeof(unsigned))); @@ -539,7 +554,7 @@ ARMBaseRegisterInfo::getAllocationOrder(const TargetRegisterClass *RC, return std::make_pair(RC->allocation_order_begin(MF), RC->allocation_order_end(MF)); - if (!STI.isTargetDarwin() && !hasFP(MF)) { + if (!hasFP(MF)) { if (!STI.isR9Reserved()) return std::make_pair(GPROdd1, GPROdd1 + (sizeof(GPROdd1)/sizeof(unsigned))); @@ -609,30 +624,68 @@ ARMBaseRegisterInfo::UpdateRegAllocHint(unsigned Reg, unsigned NewReg, /// or if frame pointer elimination is disabled. /// bool ARMBaseRegisterInfo::hasFP(const MachineFunction &MF) const { + // Mac OS X requires FP not to be clobbered for backtracing purpose. + if (STI.isTargetDarwin()) + return true; + const MachineFrameInfo *MFI = MF.getFrameInfo(); - return ((DisableFramePointerElim(MF) && MFI->adjustsStack())|| + // Always eliminate non-leaf frame pointers. + return ((DisableFramePointerElim(MF) && MFI->hasCalls()) || needsStackRealignment(MF) || MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken()); } +bool ARMBaseRegisterInfo::hasBasePointer(const MachineFunction &MF) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + const ARMFunctionInfo *AFI = MF.getInfo(); + + if (!EnableBasePointer) + return false; + + if (needsStackRealignment(MF) && MFI->hasVarSizedObjects()) + return true; + + // Thumb has trouble with negative offsets from the FP. Thumb2 has a limited + // negative range for ldr/str (255), and thumb1 is positive offsets only. + // It's going to be better to use the SP or Base Pointer instead. When there + // are variable sized objects, we can't reference off of the SP, so we + // reserve a Base Pointer. + if (AFI->isThumbFunction() && MFI->hasVarSizedObjects()) { + // Conservatively estimate whether the negative offset from the frame + // pointer will be sufficient to reach. If a function has a smallish + // frame, it's less likely to have lots of spills and callee saved + // space, so it's all more likely to be within range of the frame pointer. + // If it's wrong, the scavenger will still enable access to work, it just + // won't be optimal. + if (AFI->isThumb2Function() && MFI->getLocalFrameSize() < 128) + return false; + return true; + } + + return false; +} + bool ARMBaseRegisterInfo::canRealignStack(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); const ARMFunctionInfo *AFI = MF.getInfo(); - return (RealignStack && - !AFI->isThumb1OnlyFunction() && - !MFI->hasVarSizedObjects()); + // We can't realign the stack if: + // 1. Dynamic stack realignment is explicitly disabled, + // 2. This is a Thumb1 function (it's not useful, so we don't bother), or + // 3. There are VLAs in the function and the base pointer is disabled. + return (RealignStack && !AFI->isThumb1OnlyFunction() && + (!MFI->hasVarSizedObjects() || EnableBasePointer)); } bool ARMBaseRegisterInfo:: needsStackRealignment(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); - const ARMFunctionInfo *AFI = MF.getInfo(); + const Function *F = MF.getFunction(); unsigned StackAlign = MF.getTarget().getFrameInfo()->getStackAlignment(); - return (RealignStack && - !AFI->isThumb1OnlyFunction() && - (MFI->getMaxAlignment() > StackAlign) && - !MFI->hasVarSizedObjects()); + bool requiresRealignment = ((MFI->getLocalFrameMaxAlign() > StackAlign) || + F->hasFnAttr(Attribute::StackAlignment)); + + return requiresRealignment && canRealignStack(MF); } bool ARMBaseRegisterInfo:: @@ -668,6 +721,7 @@ static unsigned estimateStackSize(MachineFunction &MF) { /// instructions will require a scratch register during their expansion later. unsigned ARMBaseRegisterInfo::estimateRSStackSizeLimit(MachineFunction &MF) const { + const ARMFunctionInfo *AFI = MF.getInfo(); unsigned Limit = (1 << 12) - 1; for (MachineFunction::iterator BB = MF.begin(),E = MF.end(); BB != E; ++BB) { for (MachineBasicBlock::iterator I = BB->begin(), E = BB->end(); @@ -693,7 +747,10 @@ ARMBaseRegisterInfo::estimateRSStackSizeLimit(MachineFunction &MF) const { Limit = std::min(Limit, ((1U << 8) - 1) * 4); break; case ARMII::AddrModeT2_i12: - if (hasFP(MF)) Limit = std::min(Limit, (1U << 8) - 1); + // i12 supports only positive offset so these will be converted to + // i8 opcodes. See llvm::rewriteT2FrameIndex. + if (hasFP(MF) && AFI->hasStackFrame()) + Limit = std::min(Limit, (1U << 8) - 1); break; case ARMII::AddrMode6: // Addressing mode 6 (load/store) instructions can't encode an @@ -710,6 +767,19 @@ ARMBaseRegisterInfo::estimateRSStackSizeLimit(MachineFunction &MF) const { return Limit; } +static unsigned GetFunctionSizeInBytes(const MachineFunction &MF, + const ARMBaseInstrInfo &TII) { + unsigned FnSize = 0; + for (MachineFunction::const_iterator MBBI = MF.begin(), E = MF.end(); + MBBI != E; ++MBBI) { + const MachineBasicBlock &MBB = *MBBI; + for (MachineBasicBlock::const_iterator I = MBB.begin(),E = MBB.end(); + I != E; ++I) + FnSize += TII.GetInstSizeInBytes(I); + } + return FnSize; +} + void ARMBaseRegisterInfo::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, RegScavenger *RS) const { @@ -737,6 +807,10 @@ ARMBaseRegisterInfo::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, if (AFI->isThumb1OnlyFunction() && AFI->getVarArgsRegSaveSize() > 0) MF.getRegInfo().setPhysRegUsed(ARM::LR); + // Spill the BasePtr if it's used. + if (hasBasePointer(MF)) + MF.getRegInfo().setPhysRegUsed(BasePtr); + // Don't spill FP if the frame can be eliminated. This is determined // by scanning the callee-save registers to see if any is used. const unsigned *CSRegs = getCalleeSavedRegs(); @@ -807,7 +881,7 @@ ARMBaseRegisterInfo::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, bool ForceLRSpill = false; if (!LRSpilled && AFI->isThumb1OnlyFunction()) { - unsigned FnSize = TII.GetFunctionSizeInBytes(MF); + unsigned FnSize = GetFunctionSizeInBytes(MF, TII); // Force LR to be spilled if the Thumb function size is > 2048. This enables // use of BL to implement far jump. If it turns out that it's not needed // then the branch fix up path will undo it. @@ -824,13 +898,19 @@ ARMBaseRegisterInfo::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, // slot of the previous FP. Also, if we have variable sized objects in the // function, stack slot references will often be negative, and some of // our instructions are positive-offset only, so conservatively consider - // that case to want a spill slot (or register) as well. + // that case to want a spill slot (or register) as well. Similarly, if + // the function adjusts the stack pointer during execution and the + // adjustments aren't already part of our stack size estimate, our offset + // calculations may be off, so be conservative. // FIXME: We could add logic to be more precise about negative offsets // and which instructions will need a scratch register for them. Is it // worth the effort and added fragility? bool BigStack = - (RS && (estimateStackSize(MF) + (hasFP(MF) ? 4:0) >= - estimateRSStackSizeLimit(MF))) || MFI->hasVarSizedObjects(); + (RS && + (estimateStackSize(MF) + ((hasFP(MF) && AFI->hasStackFrame()) ? 4:0) >= + estimateRSStackSizeLimit(MF))) + || MFI->hasVarSizedObjects() + || (MFI->adjustsStack() && !canSimplifyCallFramePseudos(MF)); bool ExtraCSSpill = false; if (BigStack || !CanEliminateFrame || cannotEliminateFrame(MF)) { @@ -848,9 +928,7 @@ ARMBaseRegisterInfo::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, ExtraCSSpill = true; } - // Darwin ABI requires FP to point to the stack slot that contains the - // previous FP. - if (STI.isTargetDarwin() || hasFP(MF)) { + if (hasFP(MF)) { MF.getRegInfo().setPhysRegUsed(FramePtr); NumGPRSpills++; } @@ -941,55 +1019,88 @@ unsigned ARMBaseRegisterInfo::getRARegister() const { return ARM::LR; } -unsigned +unsigned ARMBaseRegisterInfo::getFrameRegister(const MachineFunction &MF) const { - if (STI.isTargetDarwin() || hasFP(MF)) + if (hasFP(MF)) return FramePtr; return ARM::SP; } +// Provide a base+offset reference to an FI slot for debug info. It's the +// same as what we use for resolving the code-gen references for now. +// FIXME: This can go wrong when references are SP-relative and simple call +// frames aren't used. int ARMBaseRegisterInfo::getFrameIndexReference(const MachineFunction &MF, int FI, unsigned &FrameReg) const { + return ResolveFrameIndexReference(MF, FI, FrameReg, 0); +} + +int +ARMBaseRegisterInfo::ResolveFrameIndexReference(const MachineFunction &MF, + int FI, + unsigned &FrameReg, + int SPAdj) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); const ARMFunctionInfo *AFI = MF.getInfo(); int Offset = MFI->getObjectOffset(FI) + MFI->getStackSize(); + int FPOffset = Offset - AFI->getFramePtrSpillOffset(); bool isFixed = MFI->isFixedObjectIndex(FI); FrameReg = ARM::SP; + Offset += SPAdj; if (AFI->isGPRCalleeSavedArea1Frame(FI)) - Offset -= AFI->getGPRCalleeSavedArea1Offset(); + return Offset - AFI->getGPRCalleeSavedArea1Offset(); else if (AFI->isGPRCalleeSavedArea2Frame(FI)) - Offset -= AFI->getGPRCalleeSavedArea2Offset(); + return Offset - AFI->getGPRCalleeSavedArea2Offset(); else if (AFI->isDPRCalleeSavedAreaFrame(FI)) - Offset -= AFI->getDPRCalleeSavedAreaOffset(); - else if (needsStackRealignment(MF)) { - // When dynamically realigning the stack, use the frame pointer for - // parameters, and the stack pointer for locals. + return Offset - AFI->getDPRCalleeSavedAreaOffset(); + + // When dynamically realigning the stack, use the frame pointer for + // parameters, and the stack/base pointer for locals. + if (needsStackRealignment(MF)) { assert (hasFP(MF) && "dynamic stack realignment without a FP!"); if (isFixed) { FrameReg = getFrameRegister(MF); - Offset -= AFI->getFramePtrSpillOffset(); + Offset = FPOffset; + } else if (MFI->hasVarSizedObjects()) { + assert(hasBasePointer(MF) && + "VLAs and dynamic stack alignment, but missing base pointer!"); + FrameReg = BasePtr; } - } else if (hasFP(MF) && AFI->hasStackFrame()) { - if (isFixed || MFI->hasVarSizedObjects()) { - // Use frame pointer to reference fixed objects unless this is a - // frameless function. + return Offset; + } + + // If there is a frame pointer, use it when we can. + if (hasFP(MF) && AFI->hasStackFrame()) { + // Use frame pointer to reference fixed objects. Use it for locals if + // there are VLAs (and thus the SP isn't reliable as a base). + if (isFixed || (MFI->hasVarSizedObjects() && !hasBasePointer(MF))) { FrameReg = getFrameRegister(MF); - Offset -= AFI->getFramePtrSpillOffset(); + return FPOffset; + } else if (MFI->hasVarSizedObjects()) { + assert(hasBasePointer(MF) && "missing base pointer!"); + // Use the base register since we have it. + FrameReg = BasePtr; } else if (AFI->isThumb2Function()) { - // In Thumb2 mode, the negative offset is very limited. - int FPOffset = Offset - AFI->getFramePtrSpillOffset(); + // In Thumb2 mode, the negative offset is very limited. Try to avoid + // out of range references. if (FPOffset >= -255 && FPOffset < 0) { FrameReg = getFrameRegister(MF); - Offset = FPOffset; + return FPOffset; } + } else if (Offset > (FPOffset < 0 ? -FPOffset : FPOffset)) { + // Otherwise, use SP or FP, whichever is closer to the stack slot. + FrameReg = getFrameRegister(MF); + return FPOffset; } } + // Use the base pointer if we have one. + if (hasBasePointer(MF)) + FrameReg = BasePtr; return Offset; } - int ARMBaseRegisterInfo::getFrameIndexOffset(const MachineFunction &MF, int FI) const { @@ -1024,7 +1135,8 @@ unsigned ARMBaseRegisterInfo::getRegisterPairEven(unsigned Reg, case ARM::R5: return ARM::R4; case ARM::R7: - return isReservedReg(MF, ARM::R7) ? 0 : ARM::R6; + return (isReservedReg(MF, ARM::R7) || isReservedReg(MF, ARM::R6)) + ? 0 : ARM::R6; case ARM::R9: return isReservedReg(MF, ARM::R9) ? 0 :ARM::R8; case ARM::R11: @@ -1113,7 +1225,8 @@ unsigned ARMBaseRegisterInfo::getRegisterPairOdd(unsigned Reg, case ARM::R4: return ARM::R5; case ARM::R6: - return isReservedReg(MF, ARM::R7) ? 0 : ARM::R7; + return (isReservedReg(MF, ARM::R7) || isReservedReg(MF, ARM::R6)) + ? 0 : ARM::R7; case ARM::R8: return isReservedReg(MF, ARM::R9) ? 0 :ARM::R9; case ARM::R10: @@ -1220,13 +1333,18 @@ requiresFrameIndexScavenging(const MachineFunction &MF) const { return true; } +bool ARMBaseRegisterInfo:: +requiresVirtualBaseRegisters(const MachineFunction &MF) const { + return EnableLocalStackAlloc; +} + // hasReservedCallFrame - Under normal circumstances, when a frame pointer is // not required, we reserve argument space for call sites in the function // immediately on entry to the current function. This eliminates the need for // add/sub sp brackets around call sites. Returns true if the call frame is // included as part of the stack frame. bool ARMBaseRegisterInfo:: -hasReservedCallFrame(MachineFunction &MF) const { +hasReservedCallFrame(const MachineFunction &MF) const { const MachineFrameInfo *FFI = MF.getFrameInfo(); unsigned CFSize = FFI->getMaxCallFrameSize(); // It's not always a good idea to include the call frame as part of the @@ -1244,7 +1362,7 @@ hasReservedCallFrame(MachineFunction &MF) const { // is not sufficient here since we still may reference some objects via SP // even when FP is available in Thumb2 mode. bool ARMBaseRegisterInfo:: -canSimplifyCallFramePseudos(MachineFunction &MF) const { +canSimplifyCallFramePseudos(const MachineFunction &MF) const { return hasReservedCallFrame(MF) || MF.getFrameInfo()->hasVarSizedObjects(); } @@ -1305,10 +1423,258 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MBB.erase(I); } -unsigned +int64_t ARMBaseRegisterInfo:: +getFrameIndexInstrOffset(const MachineInstr *MI, int Idx) const { + const TargetInstrDesc &Desc = MI->getDesc(); + unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask); + int64_t InstrOffs = 0;; + int Scale = 1; + unsigned ImmIdx = 0; + switch (AddrMode) { + case ARMII::AddrModeT2_i8: + case ARMII::AddrModeT2_i12: + // i8 supports only negative, and i12 supports only positive, so + // based on Offset sign, consider the appropriate instruction + InstrOffs = MI->getOperand(Idx+1).getImm(); + Scale = 1; + break; + case ARMII::AddrMode5: { + // VFP address mode. + const MachineOperand &OffOp = MI->getOperand(Idx+1); + InstrOffs = ARM_AM::getAM5Offset(OffOp.getImm()); + if (ARM_AM::getAM5Op(OffOp.getImm()) == ARM_AM::sub) + InstrOffs = -InstrOffs; + Scale = 4; + break; + } + case ARMII::AddrMode2: { + ImmIdx = Idx+2; + InstrOffs = ARM_AM::getAM2Offset(MI->getOperand(ImmIdx).getImm()); + if (ARM_AM::getAM2Op(MI->getOperand(ImmIdx).getImm()) == ARM_AM::sub) + InstrOffs = -InstrOffs; + break; + } + case ARMII::AddrMode3: { + ImmIdx = Idx+2; + InstrOffs = ARM_AM::getAM3Offset(MI->getOperand(ImmIdx).getImm()); + if (ARM_AM::getAM3Op(MI->getOperand(ImmIdx).getImm()) == ARM_AM::sub) + InstrOffs = -InstrOffs; + break; + } + case ARMII::AddrModeT1_s: { + ImmIdx = Idx+1; + InstrOffs = MI->getOperand(ImmIdx).getImm(); + Scale = 4; + break; + } + default: + llvm_unreachable("Unsupported addressing mode!"); + break; + } + + return InstrOffs * Scale; +} + +/// needsFrameBaseReg - Returns true if the instruction's frame index +/// reference would be better served by a base register other than FP +/// or SP. Used by LocalStackFrameAllocation to determine which frame index +/// references it should create new base registers for. +bool ARMBaseRegisterInfo:: +needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const { + for (unsigned i = 0; !MI->getOperand(i).isFI(); ++i) { + assert(i < MI->getNumOperands() &&"Instr doesn't have FrameIndex operand!"); + } + + // It's the load/store FI references that cause issues, as it can be difficult + // to materialize the offset if it won't fit in the literal field. Estimate + // based on the size of the local frame and some conservative assumptions + // about the rest of the stack frame (note, this is pre-regalloc, so + // we don't know everything for certain yet) whether this offset is likely + // to be out of range of the immediate. Return true if so. + + // We only generate virtual base registers for loads and stores, so + // return false for everything else. + unsigned Opc = MI->getOpcode(); + switch (Opc) { + case ARM::LDR: case ARM::LDRH: case ARM::LDRB: + case ARM::STR: case ARM::STRH: case ARM::STRB: + case ARM::t2LDRi12: case ARM::t2LDRi8: + case ARM::t2STRi12: case ARM::t2STRi8: + case ARM::VLDRS: case ARM::VLDRD: + case ARM::VSTRS: case ARM::VSTRD: + case ARM::tSTRspi: case ARM::tLDRspi: + if (ForceAllBaseRegAlloc) + return true; + break; + default: + return false; + } + + // Without a virtual base register, if the function has variable sized + // objects, all fixed-size local references will be via the frame pointer, + // Approximate the offset and see if it's legal for the instruction. + // Note that the incoming offset is based on the SP value at function entry, + // so it'll be negative. + MachineFunction &MF = *MI->getParent()->getParent(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + ARMFunctionInfo *AFI = MF.getInfo(); + + // Estimate an offset from the frame pointer. + // Conservatively assume all callee-saved registers get pushed. R4-R6 + // will be earlier than the FP, so we ignore those. + // R7, LR + int64_t FPOffset = Offset - 8; + // ARM and Thumb2 functions also need to consider R8-R11 and D8-D15 + if (!AFI->isThumbFunction() || !AFI->isThumb1OnlyFunction()) + FPOffset -= 80; + // Estimate an offset from the stack pointer. + // The incoming offset is relating to the SP at the start of the function, + // but when we access the local it'll be relative to the SP after local + // allocation, so adjust our SP-relative offset by that allocation size. + Offset = -Offset; + Offset += MFI->getLocalFrameSize(); + // Assume that we'll have at least some spill slots allocated. + // FIXME: This is a total SWAG number. We should run some statistics + // and pick a real one. + Offset += 128; // 128 bytes of spill slots + + // If there is a frame pointer, try using it. + // The FP is only available if there is no dynamic realignment. We + // don't know for sure yet whether we'll need that, so we guess based + // on whether there are any local variables that would trigger it. + unsigned StackAlign = MF.getTarget().getFrameInfo()->getStackAlignment(); + if (hasFP(MF) && + !((MFI->getLocalFrameMaxAlign() > StackAlign) && canRealignStack(MF))) { + if (isFrameOffsetLegal(MI, FPOffset)) + return false; + } + // If we can reference via the stack pointer, try that. + // FIXME: This (and the code that resolves the references) can be improved + // to only disallow SP relative references in the live range of + // the VLA(s). In practice, it's unclear how much difference that + // would make, but it may be worth doing. + if (!MFI->hasVarSizedObjects() && isFrameOffsetLegal(MI, Offset)) + return false; + + // The offset likely isn't legal, we want to allocate a virtual base register. + return true; +} + +/// materializeFrameBaseRegister - Insert defining instruction(s) for +/// BaseReg to be a pointer to FrameIdx before insertion point I. +void ARMBaseRegisterInfo:: +materializeFrameBaseRegister(MachineBasicBlock::iterator I, unsigned BaseReg, + int FrameIdx, int64_t Offset) const { + ARMFunctionInfo *AFI = + I->getParent()->getParent()->getInfo(); + unsigned ADDriOpc = !AFI->isThumbFunction() ? ARM::ADDri : + (AFI->isThumb1OnlyFunction() ? ARM::tADDrSPi : ARM::t2ADDri); + + MachineInstrBuilder MIB = + BuildMI(*I->getParent(), I, I->getDebugLoc(), TII.get(ADDriOpc), BaseReg) + .addFrameIndex(FrameIdx).addImm(Offset); + if (!AFI->isThumb1OnlyFunction()) + AddDefaultCC(AddDefaultPred(MIB)); +} + +void +ARMBaseRegisterInfo::resolveFrameIndex(MachineBasicBlock::iterator I, + unsigned BaseReg, int64_t Offset) const { + MachineInstr &MI = *I; + MachineBasicBlock &MBB = *MI.getParent(); + MachineFunction &MF = *MBB.getParent(); + ARMFunctionInfo *AFI = MF.getInfo(); + int Off = Offset; // ARM doesn't need the general 64-bit offsets + unsigned i = 0; + + assert(!AFI->isThumb1OnlyFunction() && + "This resolveFrameIndex does not support Thumb1!"); + + while (!MI.getOperand(i).isFI()) { + ++i; + assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); + } + bool Done = false; + if (!AFI->isThumbFunction()) + Done = rewriteARMFrameIndex(MI, i, BaseReg, Off, TII); + else { + assert(AFI->isThumb2Function()); + Done = rewriteT2FrameIndex(MI, i, BaseReg, Off, TII); + } + assert (Done && "Unable to resolve frame index!"); +} + +bool ARMBaseRegisterInfo::isFrameOffsetLegal(const MachineInstr *MI, + int64_t Offset) const { + const TargetInstrDesc &Desc = MI->getDesc(); + unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask); + unsigned i = 0; + + while (!MI->getOperand(i).isFI()) { + ++i; + assert(i < MI->getNumOperands() &&"Instr doesn't have FrameIndex operand!"); + } + + // AddrMode4 and AddrMode6 cannot handle any offset. + if (AddrMode == ARMII::AddrMode4 || AddrMode == ARMII::AddrMode6) + return Offset == 0; + + unsigned NumBits = 0; + unsigned Scale = 1; + bool isSigned = true; + switch (AddrMode) { + case ARMII::AddrModeT2_i8: + case ARMII::AddrModeT2_i12: + // i8 supports only negative, and i12 supports only positive, so + // based on Offset sign, consider the appropriate instruction + Scale = 1; + if (Offset < 0) { + NumBits = 8; + Offset = -Offset; + } else { + NumBits = 12; + } + break; + case ARMII::AddrMode5: + // VFP address mode. + NumBits = 8; + Scale = 4; + break; + case ARMII::AddrMode2: + NumBits = 12; + break; + case ARMII::AddrMode3: + NumBits = 8; + break; + case ARMII::AddrModeT1_s: + NumBits = 5; + Scale = 4; + isSigned = false; + break; + default: + llvm_unreachable("Unsupported addressing mode!"); + break; + } + + Offset += getFrameIndexInstrOffset(MI, i); + // Make sure the offset is encodable for instructions that scale the + // immediate. + if ((Offset & (Scale-1)) != 0) + return false; + + if (isSigned && Offset < 0) + Offset = -Offset; + + unsigned Mask = (1 << NumBits) - 1; + if ((unsigned)Offset <= Mask * Scale) + return true; + + return false; +} + +void ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value, - RegScavenger *RS) const { + int SPAdj, RegScavenger *RS) const { unsigned i = 0; MachineInstr &MI = *II; MachineBasicBlock &MBB = *MI.getParent(); @@ -1325,16 +1691,13 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int FrameIndex = MI.getOperand(i).getIndex(); unsigned FrameReg; - int Offset = getFrameIndexReference(MF, FrameIndex, FrameReg); - if (FrameReg != ARM::SP) - SPAdj = 0; - Offset += SPAdj; + int Offset = ResolveFrameIndexReference(MF, FrameIndex, FrameReg, SPAdj); // Special handling of dbg_value instructions. if (MI.isDebugValue()) { MI.getOperand(i). ChangeToRegister(FrameReg, false /*isDef*/); MI.getOperand(i+1).ChangeToImmediate(Offset); - return 0; + return; } // Modify MI as necessary to handle as much of 'Offset' as possible @@ -1346,7 +1709,7 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, Done = rewriteT2FrameIndex(MI, i, FrameReg, Offset, TII); } if (Done) - return 0; + return; // If we get here, the immediate doesn't fit into the instruction. We folded // as much as possible above, handle the rest, providing a register that is @@ -1366,10 +1729,6 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, MI.getOperand(i).ChangeToRegister(FrameReg, false, false, false); else { ScratchReg = MF.getRegInfo().createVirtualRegister(ARM::GPRRegisterClass); - if (Value) { - Value->first = FrameReg; // use the frame register as a kind indicator - Value->second = Offset; - } if (!AFI->isThumbFunction()) emitARMRegPlusImmediate(MBB, II, MI.getDebugLoc(), ScratchReg, FrameReg, Offset, Pred, PredReg, TII); @@ -1379,10 +1738,7 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, Offset, Pred, PredReg, TII); } MI.getOperand(i).ChangeToRegister(ScratchReg, false, false, true); - if (!ReuseFrameIndexVals) - ScratchReg = 0; } - return ScratchReg; } /// Move iterator past the next bunch of callee save load / store ops for @@ -1494,7 +1850,8 @@ emitPrologue(MachineFunction &MF) const { // Otherwise, if this is not Darwin, all the callee-saved registers go // into spill area 1, including the FP in R11. In either case, it is // now safe to emit this assignment. - if (STI.isTargetDarwin() || hasFP(MF)) { + bool HasFP = hasFP(MF); + if (HasFP) { unsigned ADDriOpc = !AFI->isThumbFunction() ? ARM::ADDri : ARM::t2ADDri; MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(ADDriOpc), FramePtr) @@ -1513,7 +1870,7 @@ emitPrologue(MachineFunction &MF) const { unsigned DPRCSOffset = NumBytes - (GPRCS1Size + GPRCS2Size + DPRCSSize); unsigned GPRCS2Offset = DPRCSOffset + DPRCSSize; unsigned GPRCS1Offset = GPRCS2Offset + GPRCS2Size; - if (STI.isTargetDarwin() || hasFP(MF)) + if (HasFP) AFI->setFramePtrSpillOffset(MFI->getObjectOffset(FramePtrSpillFI) + NumBytes); AFI->setGPRCalleeSavedArea1Offset(GPRCS1Offset); @@ -1525,18 +1882,22 @@ emitPrologue(MachineFunction &MF) const { if (NumBytes) { // Adjust SP after all the callee-save spills. emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes); + if (HasFP) + AFI->setShouldRestoreSPFromFP(true); } if (STI.isTargetELF() && hasFP(MF)) { MFI->setOffsetAdjustment(MFI->getOffsetAdjustment() - AFI->getFramePtrSpillOffset()); + AFI->setShouldRestoreSPFromFP(true); } AFI->setGPRCalleeSavedArea1Size(GPRCS1Size); AFI->setGPRCalleeSavedArea2Size(GPRCS2Size); AFI->setDPRCalleeSavedAreaSize(DPRCSSize); - // If we need dynamic stack realignment, do it here. + // If we need dynamic stack realignment, do it here. Be paranoid and make + // sure if we also have VLAs, we have a base pointer for frame access. if (needsStackRealignment(MF)) { unsigned MaxAlign = MFI->getMaxAlignment(); assert (!AFI->isThumb1OnlyFunction()); @@ -1562,7 +1923,28 @@ emitPrologue(MachineFunction &MF) const { BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVtgpr2gpr), ARM::SP) .addReg(ARM::R4, RegState::Kill); } + + AFI->setShouldRestoreSPFromFP(true); + } + + // If we need a base pointer, set it up here. It's whatever the value + // of the stack pointer is at this point. Any variable size objects + // will be allocated after this, so we can still use the base pointer + // to reference locals. + if (hasBasePointer(MF)) { + if (isARM) + BuildMI(MBB, MBBI, dl, TII.get(ARM::MOVr), BasePtr) + .addReg(ARM::SP) + .addImm((unsigned)ARMCC::AL).addReg(0).addReg(0); + else + BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr), BasePtr) + .addReg(ARM::SP); } + + // If the frame has variable sized objects then the epilogue must restore + // the sp from fp. + if (!AFI->shouldRestoreSPFromFP() && MFI->hasVarSizedObjects()) + AFI->setShouldRestoreSPFromFP(true); } static bool isCalleeSavedRegister(unsigned Reg, const unsigned *CSRegs) { @@ -1617,34 +1999,25 @@ emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { AFI->getGPRCalleeSavedArea2Size() + AFI->getDPRCalleeSavedAreaSize()); - // Darwin ABI requires FP to point to the stack slot that contains the - // previous FP. - bool HasFP = hasFP(MF); - if ((STI.isTargetDarwin() && NumBytes) || HasFP) { + // Reset SP based on frame pointer only if the stack frame extends beyond + // frame pointer stack slot or target is ELF and the function has FP. + if (AFI->shouldRestoreSPFromFP()) { NumBytes = AFI->getFramePtrSpillOffset() - NumBytes; - // Reset SP based on frame pointer only if the stack frame extends beyond - // frame pointer stack slot or target is ELF and the function has FP. - if (HasFP || - AFI->getGPRCalleeSavedArea2Size() || - AFI->getDPRCalleeSavedAreaSize() || - AFI->getDPRCalleeSavedAreaOffset()) { - if (NumBytes) { - if (isARM) - emitARMRegPlusImmediate(MBB, MBBI, dl, ARM::SP, FramePtr, -NumBytes, - ARMCC::AL, 0, TII); - else - emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::SP, FramePtr, -NumBytes, - ARMCC::AL, 0, TII); - } else { - // Thumb2 or ARM. - if (isARM) - BuildMI(MBB, MBBI, dl, TII.get(ARM::MOVr), ARM::SP) - .addReg(FramePtr) - .addImm((unsigned)ARMCC::AL).addReg(0).addReg(0); - else - BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr), ARM::SP) - .addReg(FramePtr); - } + if (NumBytes) { + if (isARM) + emitARMRegPlusImmediate(MBB, MBBI, dl, ARM::SP, FramePtr, -NumBytes, + ARMCC::AL, 0, TII); + else + emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::SP, FramePtr, -NumBytes, + ARMCC::AL, 0, TII); + } else { + // Thumb2 or ARM. + if (isARM) + BuildMI(MBB, MBBI, dl, TII.get(ARM::MOVr), ARM::SP) + .addReg(FramePtr).addImm((unsigned)ARMCC::AL).addReg(0).addReg(0); + else + BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr), ARM::SP) + .addReg(FramePtr); } } else if (NumBytes) emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes); @@ -1670,7 +2043,7 @@ emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { // Jump to label or value in register. if (RetOpcode == ARM::TCRETURNdi) { - BuildMI(MBB, MBBI, dl, + BuildMI(MBB, MBBI, dl, TII.get(STI.isThumb() ? ARM::TAILJMPdt : ARM::TAILJMPd)). addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset(), JumpTarget.getTargetFlags()); @@ -1685,7 +2058,7 @@ emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { } else if (RetOpcode == ARM::TCRETURNriND) { BuildMI(MBB, MBBI, dl, TII.get(ARM::TAILJMPrND)). addReg(JumpTarget.getReg(), RegState::Kill); - } + } MachineInstr *NewMI = prior(MBBI); for (unsigned i = 1, e = MBBI->getNumOperands(); i != e; ++i) diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.h b/lib/Target/ARM/ARMBaseRegisterInfo.h index f7ee0d5..fa2eb6c 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.h +++ b/lib/Target/ARM/ARMBaseRegisterInfo.h @@ -44,7 +44,7 @@ static inline bool isARMLowRegister(unsigned Reg) { } } -struct ARMBaseRegisterInfo : public ARMGenRegisterInfo { +class ARMBaseRegisterInfo : public ARMGenRegisterInfo { protected: const ARMBaseInstrInfo &TII; const ARMSubtarget &STI; @@ -52,6 +52,11 @@ protected: /// FramePtr - ARM physical register used as frame ptr. unsigned FramePtr; + /// BasePtr - ARM physical register used as a base ptr in complex stack + /// frames. I.e., when we need a 3rd base, not just SP and FP, due to + /// variable size stack objects. + unsigned BasePtr; + // Can be only subclassed. explicit ARMBaseRegisterInfo(const ARMBaseInstrInfo &tii, const ARMSubtarget &STI); @@ -102,9 +107,18 @@ public: MachineFunction &MF) const; bool hasFP(const MachineFunction &MF) const; + bool hasBasePointer(const MachineFunction &MF) const; bool canRealignStack(const MachineFunction &MF) const; bool needsStackRealignment(const MachineFunction &MF) const; + int64_t getFrameIndexInstrOffset(const MachineInstr *MI, int Idx) const; + bool needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const; + void materializeFrameBaseRegister(MachineBasicBlock::iterator I, + unsigned BaseReg, int FrameIdx, + int64_t Offset) const; + void resolveFrameIndex(MachineBasicBlock::iterator I, + unsigned BaseReg, int64_t Offset) const; + bool isFrameOffsetLegal(const MachineInstr *MI, int64_t Offset) const; bool cannotEliminateFrame(const MachineFunction &MF) const; @@ -116,6 +130,8 @@ public: unsigned getFrameRegister(const MachineFunction &MF) const; int getFrameIndexReference(const MachineFunction &MF, int FI, unsigned &FrameReg) const; + int ResolveFrameIndexReference(const MachineFunction &MF, int FI, + unsigned &FrameReg, int SPAdj) const; int getFrameIndexOffset(const MachineFunction &MF, int FI) const; // Exception handling queries. @@ -144,16 +160,17 @@ public: virtual bool requiresFrameIndexScavenging(const MachineFunction &MF) const; - virtual bool hasReservedCallFrame(MachineFunction &MF) const; - virtual bool canSimplifyCallFramePseudos(MachineFunction &MF) const; + virtual bool requiresVirtualBaseRegisters(const MachineFunction &MF) const; + + virtual bool hasReservedCallFrame(const MachineFunction &MF) const; + virtual bool canSimplifyCallFramePseudos(const MachineFunction &MF) const; virtual void eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; - virtual unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value = NULL, - RegScavenger *RS = NULL) const; + virtual void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; virtual void emitPrologue(MachineFunction &MF) const; virtual void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; diff --git a/lib/Target/ARM/ARMCallingConv.td b/lib/Target/ARM/ARMCallingConv.td index 8fdb07f..293e32a 100644 --- a/lib/Target/ARM/ARMCallingConv.td +++ b/lib/Target/ARM/ARMCallingConv.td @@ -1,4 +1,4 @@ -//===- ARMCallingConv.td - Calling Conventions for ARM ----------*- C++ -*-===// +//===- ARMCallingConv.td - Calling Conventions for ARM -----*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -68,7 +68,7 @@ def CC_ARM_AAPCS_Common : CallingConv<[ "ArgFlags.getOrigAlign() != 8", CCAssignToReg<[R0, R1, R2, R3]>>>, - CCIfType<[i32], CCIfAlign<"8", CCAssignToStack<4, 8>>>, + CCIfType<[i32], CCIfAlign<"8", CCAssignToStackWithShadow<4, 8, R3>>>, CCIfType<[i32, f32], CCAssignToStack<4, 4>>, CCIfType<[f64], CCAssignToStack<8, 8>>, CCIfType<[v2f64], CCAssignToStack<16, 8>> diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp index 7895cb0..b1a702f 100644 --- a/lib/Target/ARM/ARMCodeEmitter.cpp +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -65,7 +65,7 @@ namespace { static char ID; public: ARMCodeEmitter(TargetMachine &tm, JITCodeEmitter &mce) - : MachineFunctionPass(&ID), JTI(0), + : MachineFunctionPass(ID), JTI(0), II((const ARMInstrInfo *)tm.getInstrInfo()), TD(tm.getTargetData()), TM(tm), MCE(mce), MCPEs(0), MJTEs(0), @@ -124,6 +124,8 @@ namespace { void emitMiscArithInstruction(const MachineInstr &MI); + void emitSaturateInstruction(const MachineInstr &MI); + void emitBranchInstruction(const MachineInstr &MI); void emitInlineJumpTable(unsigned JTIndex); @@ -389,6 +391,9 @@ void ARMCodeEmitter::emitInstruction(const MachineInstr &MI) { case ARMII::ArithMiscFrm: emitMiscArithInstruction(MI); break; + case ARMII::SatFrm: + emitSaturateInstruction(MI); + break; case ARMII::BrFrm: emitBranchInstruction(MI); break; @@ -654,6 +659,19 @@ void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) { switch (Opcode) { default: llvm_unreachable("ARMCodeEmitter::emitPseudoInstruction"); + case ARM::BX: + case ARM::BMOVPCRX: + case ARM::BXr9: + case ARM::BMOVPCRXr9: { + // First emit mov lr, pc + unsigned Binary = 0x01a0e00f; + Binary |= II->getPredicate(&MI) << ARMII::CondShift; + emitWordLE(Binary); + + // and then emit the branch. + emitMiscBranchInstruction(MI); + break; + } case TargetOpcode::INLINEASM: { // We allow inline assembler nodes with empty bodies - they can // implicitly define registers, which is ok for JIT. @@ -662,7 +680,7 @@ void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) { } break; } - case TargetOpcode::DBG_LABEL: + case TargetOpcode::PROLOG_LABEL: case TargetOpcode::EH_LABEL: MCE.emitLabel(MI.getOperand(0).getMCSymbol()); break; @@ -1209,12 +1227,58 @@ void ARMCodeEmitter::emitMiscArithInstruction(const MachineInstr &MI) { // Encode shift_imm. unsigned ShiftAmt = MI.getOperand(OpIdx).getImm(); + if (TID.Opcode == ARM::PKHTB) { + assert(ShiftAmt != 0 && "PKHTB shift_imm is 0!"); + if (ShiftAmt == 32) + ShiftAmt = 0; + } assert(ShiftAmt < 32 && "shift_imm range is 0 to 31!"); Binary |= ShiftAmt << ARMII::ShiftShift; emitWordLE(Binary); } +void ARMCodeEmitter::emitSaturateInstruction(const MachineInstr &MI) { + const TargetInstrDesc &TID = MI.getDesc(); + + // Part of binary is determined by TableGen. + unsigned Binary = getBinaryCodeForInstr(MI); + + // Set the conditional execution predicate + Binary |= II->getPredicate(&MI) << ARMII::CondShift; + + // Encode Rd + Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift; + + // Encode saturate bit position. + unsigned Pos = MI.getOperand(1).getImm(); + if (TID.Opcode == ARM::SSAT || TID.Opcode == ARM::SSAT16) + Pos -= 1; + assert((Pos < 16 || (Pos < 32 && + TID.Opcode != ARM::SSAT16 && + TID.Opcode != ARM::USAT16)) && + "saturate bit position out of range"); + Binary |= Pos << 16; + + // Encode Rm + Binary |= getMachineOpValue(MI, 2); + + // Encode shift_imm. + if (TID.getNumOperands() == 4) { + unsigned ShiftOp = MI.getOperand(3).getImm(); + ARM_AM::ShiftOpc Opc = ARM_AM::getSORegShOp(ShiftOp); + if (Opc == ARM_AM::asr) + Binary |= (1 << 6); + unsigned ShiftAmt = MI.getOperand(3).getImm(); + if (ShiftAmt == 32 && Opc == ARM_AM::asr) + ShiftAmt = 0; + assert(ShiftAmt < 32 && "shift_imm range is 0 to 31!"); + Binary |= ShiftAmt << ARMII::ShiftShift; + } + + emitWordLE(Binary); +} + void ARMCodeEmitter::emitBranchInstruction(const MachineInstr &MI) { const TargetInstrDesc &TID = MI.getDesc(); @@ -1485,7 +1549,7 @@ ARMCodeEmitter::emitVFPLoadStoreMultipleInstruction(const MachineInstr &MI) { // Set addressing mode by modifying bits U(23) and P(24) const MachineOperand &MO = MI.getOperand(OpIdx++); - Binary |= getAddrModeUPBits(ARM_AM::getAM5SubMode(MO.getImm())); + Binary |= getAddrModeUPBits(ARM_AM::getAM4SubMode(MO.getImm())); // Set bit W(21) if (IsUpdating) @@ -1494,7 +1558,7 @@ ARMCodeEmitter::emitVFPLoadStoreMultipleInstruction(const MachineInstr &MI) { // First register is encoded in Dd. Binary |= encodeVFPRd(MI, OpIdx+2); - // Number of registers are encoded in offset field. + // Count the number of registers. unsigned NumRegs = 1; for (unsigned i = OpIdx+3, e = MI.getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI.getOperand(i); diff --git a/lib/Target/ARM/ARMConstantIslandPass.cpp b/lib/Target/ARM/ARMConstantIslandPass.cpp index 65a3da6..60e923b 100644 --- a/lib/Target/ARM/ARMConstantIslandPass.cpp +++ b/lib/Target/ARM/ARMConstantIslandPass.cpp @@ -18,9 +18,9 @@ #include "ARMAddressingModes.h" #include "ARMMachineFunctionInfo.h" #include "ARMInstrInfo.h" +#include "Thumb2InstrInfo.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" @@ -165,7 +165,7 @@ namespace { /// HasInlineAsm - True if the function contains inline assembly. bool HasInlineAsm; - const TargetInstrInfo *TII; + const ARMInstrInfo *TII; const ARMSubtarget *STI; ARMFunctionInfo *AFI; bool isThumb; @@ -173,7 +173,7 @@ namespace { bool isThumb2; public: static char ID; - ARMConstantIslands() : MachineFunctionPass(&ID) {} + ARMConstantIslands() : MachineFunctionPass(ID) {} virtual bool runOnMachineFunction(MachineFunction &MF); @@ -272,7 +272,7 @@ FunctionPass *llvm::createARMConstantIslandPass() { bool ARMConstantIslands::runOnMachineFunction(MachineFunction &MF) { MachineConstantPool &MCP = *MF.getConstantPool(); - TII = MF.getTarget().getInstrInfo(); + TII = (const ARMInstrInfo*)MF.getTarget().getInstrInfo(); AFI = MF.getInfo(); STI = &MF.getTarget().getSubtarget(); @@ -323,6 +323,8 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &MF) { // constant pool users. InitialFunctionScan(MF, CPEMIs); CPEMIs.clear(); + DEBUG(dumpBBs()); + /// Remove dead constant pool entries. RemoveUnusedCPEntries(); @@ -355,7 +357,7 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &MF) { } // Shrink 32-bit Thumb2 branch, load, and store instructions. - if (isThumb2) + if (isThumb2 && !STI->prefers32BitThumb()) MadeChange |= OptimizeThumb2Instructions(MF); // After a while, this might be made debug-only, but it is not expensive. @@ -366,6 +368,8 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &MF) { if (isThumb && !HasFarJump && AFI->isLRSpilledForFarJump()) MadeChange |= UndoLRSpillRestore(); + DEBUG(errs() << '\n'; dumpBBs()); + BBSizes.clear(); BBOffsets.clear(); WaterList.clear(); @@ -509,6 +513,10 @@ void ARMConstantIslands::InitialFunctionScan(MachineFunction &MF, case ARM::tBR_JTr: // A Thumb1 table jump may involve padding; for the offsets to // be right, functions containing these must be 4-byte aligned. + // tBR_JTr expands to a mov pc followed by .align 2 and then the jump + // table entries. So this code checks whether offset of tBR_JTr + 2 + // is aligned. That is held in Offset+MBBSize, which already has + // 2 added in for the size of the mov pc instruction. MF.EnsureAlignment(2U); if ((Offset+MBBSize)%4 != 0 || HasInlineAsm) // FIXME: Add a pseudo ALIGN instruction instead. @@ -768,28 +776,54 @@ MachineBasicBlock *ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) { WaterList.insert(IP, OrigBB); NewWaterList.insert(OrigBB); - // Figure out how large the first NewMBB is. (It cannot - // contain a constpool_entry or tablejump.) - unsigned NewBBSize = 0; - for (MachineBasicBlock::iterator I = NewBB->begin(), E = NewBB->end(); - I != E; ++I) - NewBBSize += TII->GetInstSizeInBytes(I); - unsigned OrigBBI = OrigBB->getNumber(); unsigned NewBBI = NewBB->getNumber(); - // Set the size of NewBB in BBSizes. - BBSizes[NewBBI] = NewBBSize; - // We removed instructions from UserMBB, subtract that off from its size. - // Add 2 or 4 to the block to count the unconditional branch we added to it. int delta = isThumb1 ? 2 : 4; - BBSizes[OrigBBI] -= NewBBSize - delta; + + // Figure out how large the OrigBB is. As the first half of the original + // block, it cannot contain a tablejump. The size includes + // the new jump we added. (It should be possible to do this without + // recounting everything, but it's very confusing, and this is rarely + // executed.) + unsigned OrigBBSize = 0; + for (MachineBasicBlock::iterator I = OrigBB->begin(), E = OrigBB->end(); + I != E; ++I) + OrigBBSize += TII->GetInstSizeInBytes(I); + BBSizes[OrigBBI] = OrigBBSize; // ...and adjust BBOffsets for NewBB accordingly. BBOffsets[NewBBI] = BBOffsets[OrigBBI] + BBSizes[OrigBBI]; + // Figure out how large the NewMBB is. As the second half of the original + // block, it may contain a tablejump. + unsigned NewBBSize = 0; + for (MachineBasicBlock::iterator I = NewBB->begin(), E = NewBB->end(); + I != E; ++I) + NewBBSize += TII->GetInstSizeInBytes(I); + // Set the size of NewBB in BBSizes. It does not include any padding now. + BBSizes[NewBBI] = NewBBSize; + + MachineInstr* ThumbJTMI = prior(NewBB->end()); + if (ThumbJTMI->getOpcode() == ARM::tBR_JTr) { + // We've added another 2-byte instruction before this tablejump, which + // means we will always need padding if we didn't before, and vice versa. + + // The original offset of the jump instruction was: + unsigned OrigOffset = BBOffsets[OrigBBI] + BBSizes[OrigBBI] - delta; + if (OrigOffset%4 == 0) { + // We had padding before and now we don't. No net change in code size. + delta = 0; + } else { + // We didn't have padding before and now we do. + BBSizes[NewBBI] += 2; + delta = 4; + } + } + // All BBOffsets following these blocks must be modified. - AdjustBBOffsetsAfter(NewBB, delta); + if (delta) + AdjustBBOffsetsAfter(NewBB, delta); return NewBB; } @@ -915,6 +949,10 @@ void ARMConstantIslands::AdjustBBOffsetsAfter(MachineBasicBlock *BB, } // Thumb1 jump tables require padding. They should be at the end; // following unconditional branches are removed by AnalyzeBranch. + // tBR_JTr expands to a mov pc followed by .align 2 and then the jump + // table entries. So this code checks whether offset of tBR_JTr + // is aligned; if it is, the offset of the jump table following the + // instruction will not be aligned, and we need padding. MachineInstr *ThumbJTMI = prior(MBB->end()); if (ThumbJTMI->getOpcode() == ARM::tBR_JTr) { unsigned NewMIOffset = GetOffsetOf(ThumbJTMI); @@ -1143,11 +1181,13 @@ void ARMConstantIslands::CreateNewWater(unsigned CPUserIndex, MachineBasicBlock::iterator MI = UserMI; ++MI; unsigned CPUIndex = CPUserIndex+1; + unsigned NumCPUsers = CPUsers.size(); + MachineInstr *LastIT = 0; for (unsigned Offset = UserOffset+TII->GetInstSizeInBytes(UserMI); Offset < BaseInsertOffset; Offset += TII->GetInstSizeInBytes(MI), - MI = llvm::next(MI)) { - if (CPUIndex < CPUsers.size() && CPUsers[CPUIndex].MI == MI) { + MI = llvm::next(MI)) { + if (CPUIndex < NumCPUsers && CPUsers[CPUIndex].MI == MI) { CPUser &U = CPUsers[CPUIndex]; if (!OffsetIsInRange(Offset, EndInsertOffset, U.MaxDisp, U.NegOk, U.IsSoImm)) { @@ -1159,9 +1199,23 @@ void ARMConstantIslands::CreateNewWater(unsigned CPUserIndex, EndInsertOffset += CPUsers[CPUIndex].CPEMI->getOperand(2).getImm(); CPUIndex++; } + + // Remember the last IT instruction. + if (MI->getOpcode() == ARM::t2IT) + LastIT = MI; } + DEBUG(errs() << "Split in middle of big block\n"); - NewMBB = SplitBlockBeforeInstr(prior(MI)); + --MI; + + // Avoid splitting an IT block. + if (LastIT) { + unsigned PredReg = 0; + ARMCC::CondCodes CC = llvm::getITInstrPredicate(MI, PredReg); + if (CC != ARMCC::AL) + MI = LastIT; + } + NewMBB = SplitBlockBeforeInstr(MI); } } diff --git a/lib/Target/ARM/ARMExpandPseudoInsts.cpp b/lib/Target/ARM/ARMExpandPseudoInsts.cpp index 9c62597..fc2e3c3 100644 --- a/lib/Target/ARM/ARMExpandPseudoInsts.cpp +++ b/lib/Target/ARM/ARMExpandPseudoInsts.cpp @@ -19,14 +19,21 @@ #include "ARMBaseInstrInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" - +#include "llvm/Target/TargetRegisterInfo.h" using namespace llvm; namespace { class ARMExpandPseudo : public MachineFunctionPass { + // Constants for register spacing in NEON load/store instructions. + enum NEONRegSpacing { + SingleSpc, + EvenDblSpc, + OddDblSpc + }; + public: static char ID; - ARMExpandPseudo() : MachineFunctionPass(&ID) {} + ARMExpandPseudo() : MachineFunctionPass(ID) {} const TargetInstrInfo *TII; const TargetRegisterInfo *TRI; @@ -41,6 +48,10 @@ namespace { void TransferImpOps(MachineInstr &OldMI, MachineInstrBuilder &UseMI, MachineInstrBuilder &DefMI); bool ExpandMBB(MachineBasicBlock &MBB); + void ExpandVLD(MachineBasicBlock::iterator &MBBI, unsigned Opc, + bool hasWriteBack, NEONRegSpacing RegSpc, unsigned NumRegs); + void ExpandVST(MachineBasicBlock::iterator &MBBI, unsigned Opc, + bool hasWriteBack, NEONRegSpacing RegSpc, unsigned NumRegs); }; char ARMExpandPseudo::ID = 0; } @@ -63,6 +74,129 @@ void ARMExpandPseudo::TransferImpOps(MachineInstr &OldMI, } } +/// ExpandVLD - Translate VLD pseudo instructions with Q, QQ or QQQQ register +/// operands to real VLD instructions with D register operands. +void ARMExpandPseudo::ExpandVLD(MachineBasicBlock::iterator &MBBI, + unsigned Opc, bool hasWriteBack, + NEONRegSpacing RegSpc, unsigned NumRegs) { + MachineInstr &MI = *MBBI; + MachineBasicBlock &MBB = *MI.getParent(); + + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc)); + unsigned OpIdx = 0; + + bool DstIsDead = MI.getOperand(OpIdx).isDead(); + unsigned DstReg = MI.getOperand(OpIdx++).getReg(); + unsigned D0, D1, D2, D3; + if (RegSpc == SingleSpc) { + D0 = TRI->getSubReg(DstReg, ARM::dsub_0); + D1 = TRI->getSubReg(DstReg, ARM::dsub_1); + D2 = TRI->getSubReg(DstReg, ARM::dsub_2); + D3 = TRI->getSubReg(DstReg, ARM::dsub_3); + } else if (RegSpc == EvenDblSpc) { + D0 = TRI->getSubReg(DstReg, ARM::dsub_0); + D1 = TRI->getSubReg(DstReg, ARM::dsub_2); + D2 = TRI->getSubReg(DstReg, ARM::dsub_4); + D3 = TRI->getSubReg(DstReg, ARM::dsub_6); + } else { + assert(RegSpc == OddDblSpc && "unknown register spacing for VLD"); + D0 = TRI->getSubReg(DstReg, ARM::dsub_1); + D1 = TRI->getSubReg(DstReg, ARM::dsub_3); + D2 = TRI->getSubReg(DstReg, ARM::dsub_5); + D3 = TRI->getSubReg(DstReg, ARM::dsub_7); + } + MIB.addReg(D0, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(D1, RegState::Define | getDeadRegState(DstIsDead)); + if (NumRegs > 2) + MIB.addReg(D2, RegState::Define | getDeadRegState(DstIsDead)); + if (NumRegs > 3) + MIB.addReg(D3, RegState::Define | getDeadRegState(DstIsDead)); + + if (hasWriteBack) { + bool WBIsDead = MI.getOperand(OpIdx).isDead(); + unsigned WBReg = MI.getOperand(OpIdx++).getReg(); + MIB.addReg(WBReg, RegState::Define | getDeadRegState(WBIsDead)); + } + // Copy the addrmode6 operands. + bool AddrIsKill = MI.getOperand(OpIdx).isKill(); + MIB.addReg(MI.getOperand(OpIdx++).getReg(), getKillRegState(AddrIsKill)); + MIB.addImm(MI.getOperand(OpIdx++).getImm()); + if (hasWriteBack) { + // Copy the am6offset operand. + bool OffsetIsKill = MI.getOperand(OpIdx).isKill(); + MIB.addReg(MI.getOperand(OpIdx++).getReg(), getKillRegState(OffsetIsKill)); + } + + MIB = AddDefaultPred(MIB); + TransferImpOps(MI, MIB, MIB); + // For an instruction writing the odd subregs, add an implicit use of the + // super-register because the even subregs were loaded separately. + if (RegSpc == OddDblSpc) + MIB.addReg(DstReg, RegState::Implicit); + // Add an implicit def for the super-register. + MIB.addReg(DstReg, RegState::ImplicitDefine | getDeadRegState(DstIsDead)); + MI.eraseFromParent(); +} + +/// ExpandVST - Translate VST pseudo instructions with Q, QQ or QQQQ register +/// operands to real VST instructions with D register operands. +void ARMExpandPseudo::ExpandVST(MachineBasicBlock::iterator &MBBI, + unsigned Opc, bool hasWriteBack, + NEONRegSpacing RegSpc, unsigned NumRegs) { + MachineInstr &MI = *MBBI; + MachineBasicBlock &MBB = *MI.getParent(); + + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc)); + unsigned OpIdx = 0; + if (hasWriteBack) { + bool DstIsDead = MI.getOperand(OpIdx).isDead(); + unsigned DstReg = MI.getOperand(OpIdx++).getReg(); + MIB.addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead)); + } + // Copy the addrmode6 operands. + bool AddrIsKill = MI.getOperand(OpIdx).isKill(); + MIB.addReg(MI.getOperand(OpIdx++).getReg(), getKillRegState(AddrIsKill)); + MIB.addImm(MI.getOperand(OpIdx++).getImm()); + if (hasWriteBack) { + // Copy the am6offset operand. + bool OffsetIsKill = MI.getOperand(OpIdx).isKill(); + MIB.addReg(MI.getOperand(OpIdx++).getReg(), getKillRegState(OffsetIsKill)); + } + + bool SrcIsKill = MI.getOperand(OpIdx).isKill(); + unsigned SrcReg = MI.getOperand(OpIdx).getReg(); + unsigned D0, D1, D2, D3; + if (RegSpc == SingleSpc) { + D0 = TRI->getSubReg(SrcReg, ARM::dsub_0); + D1 = TRI->getSubReg(SrcReg, ARM::dsub_1); + D2 = TRI->getSubReg(SrcReg, ARM::dsub_2); + D3 = TRI->getSubReg(SrcReg, ARM::dsub_3); + } else if (RegSpc == EvenDblSpc) { + D0 = TRI->getSubReg(SrcReg, ARM::dsub_0); + D1 = TRI->getSubReg(SrcReg, ARM::dsub_2); + D2 = TRI->getSubReg(SrcReg, ARM::dsub_4); + D3 = TRI->getSubReg(SrcReg, ARM::dsub_6); + } else { + assert(RegSpc == OddDblSpc && "unknown register spacing for VST"); + D0 = TRI->getSubReg(SrcReg, ARM::dsub_1); + D1 = TRI->getSubReg(SrcReg, ARM::dsub_3); + D2 = TRI->getSubReg(SrcReg, ARM::dsub_5); + D3 = TRI->getSubReg(SrcReg, ARM::dsub_7); + } + + MIB.addReg(D0).addReg(D1); + if (NumRegs > 2) + MIB.addReg(D2); + if (NumRegs > 3) + MIB.addReg(D3); + MIB = AddDefaultPred(MIB); + TransferImpOps(MI, MIB, MIB); + if (SrcIsKill) + // Add an implicit kill for the super-reg. + (*MIB).addRegisterKilled(SrcReg, TRI, true); + MI.eraseFromParent(); +} + bool ARMExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { bool Modified = false; @@ -71,9 +205,13 @@ bool ARMExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { MachineInstr &MI = *MBBI; MachineBasicBlock::iterator NMBBI = llvm::next(MBBI); + bool ModifiedOp = true; unsigned Opcode = MI.getOpcode(); switch (Opcode) { - default: break; + default: + ModifiedOp = false; + break; + case ARM::tLDRpci_pic: case ARM::t2LDRpci_pic: { unsigned NewLdOpc = (Opcode == ARM::tLDRpci_pic) @@ -92,10 +230,10 @@ bool ARMExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { .addOperand(MI.getOperand(2)); TransferImpOps(MI, MIB1, MIB2); MI.eraseFromParent(); - Modified = true; break; } + case ARM::MOVi32imm: case ARM::t2MOVi32imm: { unsigned PredReg = 0; ARMCC::CondCodes Pred = llvm::getInstrPredicate(&MI, PredReg); @@ -104,9 +242,13 @@ bool ARMExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { const MachineOperand &MO = MI.getOperand(1); MachineInstrBuilder LO16, HI16; - LO16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::t2MOVi16), + LO16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), + TII->get(Opcode == ARM::MOVi32imm ? + ARM::MOVi16 : ARM::t2MOVi16), DstReg); - HI16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::t2MOVTi16)) + HI16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), + TII->get(Opcode == ARM::MOVi32imm ? + ARM::MOVTi16 : ARM::t2MOVTi16)) .addReg(DstReg, getDefRegState(true) | getDeadRegState(DstIsDead)) .addReg(DstReg); @@ -128,7 +270,6 @@ bool ARMExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { HI16.addImm(Pred).addReg(PredReg); TransferImpOps(MI, LO16, HI16); MI.eraseFromParent(); - Modified = true; break; } @@ -155,9 +296,211 @@ bool ARMExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { .addReg(OddSrc, getKillRegState(SrcIsKill))); TransferImpOps(MI, Even, Odd); MI.eraseFromParent(); - Modified = true; } + + case ARM::VLD1q8Pseudo: + ExpandVLD(MBBI, ARM::VLD1q8, false, SingleSpc, 2); break; + case ARM::VLD1q16Pseudo: + ExpandVLD(MBBI, ARM::VLD1q16, false, SingleSpc, 2); break; + case ARM::VLD1q32Pseudo: + ExpandVLD(MBBI, ARM::VLD1q32, false, SingleSpc, 2); break; + case ARM::VLD1q64Pseudo: + ExpandVLD(MBBI, ARM::VLD1q64, false, SingleSpc, 2); break; + case ARM::VLD1q8Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD1q8, true, SingleSpc, 2); break; + case ARM::VLD1q16Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD1q16, true, SingleSpc, 2); break; + case ARM::VLD1q32Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD1q32, true, SingleSpc, 2); break; + case ARM::VLD1q64Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD1q64, true, SingleSpc, 2); break; + + case ARM::VLD2d8Pseudo: + ExpandVLD(MBBI, ARM::VLD2d8, false, SingleSpc, 2); break; + case ARM::VLD2d16Pseudo: + ExpandVLD(MBBI, ARM::VLD2d16, false, SingleSpc, 2); break; + case ARM::VLD2d32Pseudo: + ExpandVLD(MBBI, ARM::VLD2d32, false, SingleSpc, 2); break; + case ARM::VLD2q8Pseudo: + ExpandVLD(MBBI, ARM::VLD2q8, false, SingleSpc, 4); break; + case ARM::VLD2q16Pseudo: + ExpandVLD(MBBI, ARM::VLD2q16, false, SingleSpc, 4); break; + case ARM::VLD2q32Pseudo: + ExpandVLD(MBBI, ARM::VLD2q32, false, SingleSpc, 4); break; + case ARM::VLD2d8Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD2d8, true, SingleSpc, 2); break; + case ARM::VLD2d16Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD2d16, true, SingleSpc, 2); break; + case ARM::VLD2d32Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD2d32, true, SingleSpc, 2); break; + case ARM::VLD2q8Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD2q8, true, SingleSpc, 4); break; + case ARM::VLD2q16Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD2q16, true, SingleSpc, 4); break; + case ARM::VLD2q32Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD2q32, true, SingleSpc, 4); break; + + case ARM::VLD3d8Pseudo: + ExpandVLD(MBBI, ARM::VLD3d8, false, SingleSpc, 3); break; + case ARM::VLD3d16Pseudo: + ExpandVLD(MBBI, ARM::VLD3d16, false, SingleSpc, 3); break; + case ARM::VLD3d32Pseudo: + ExpandVLD(MBBI, ARM::VLD3d32, false, SingleSpc, 3); break; + case ARM::VLD1d64TPseudo: + ExpandVLD(MBBI, ARM::VLD1d64T, false, SingleSpc, 3); break; + case ARM::VLD3d8Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD3d8_UPD, true, SingleSpc, 3); break; + case ARM::VLD3d16Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD3d16_UPD, true, SingleSpc, 3); break; + case ARM::VLD3d32Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD3d32_UPD, true, SingleSpc, 3); break; + case ARM::VLD1d64TPseudo_UPD: + ExpandVLD(MBBI, ARM::VLD1d64T_UPD, true, SingleSpc, 3); break; + case ARM::VLD3q8Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD3q8_UPD, true, EvenDblSpc, 3); break; + case ARM::VLD3q16Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD3q16_UPD, true, EvenDblSpc, 3); break; + case ARM::VLD3q32Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD3q32_UPD, true, EvenDblSpc, 3); break; + case ARM::VLD3q8oddPseudo_UPD: + ExpandVLD(MBBI, ARM::VLD3q8_UPD, true, OddDblSpc, 3); break; + case ARM::VLD3q16oddPseudo_UPD: + ExpandVLD(MBBI, ARM::VLD3q16_UPD, true, OddDblSpc, 3); break; + case ARM::VLD3q32oddPseudo_UPD: + ExpandVLD(MBBI, ARM::VLD3q32_UPD, true, OddDblSpc, 3); break; + + case ARM::VLD4d8Pseudo: + ExpandVLD(MBBI, ARM::VLD4d8, false, SingleSpc, 4); break; + case ARM::VLD4d16Pseudo: + ExpandVLD(MBBI, ARM::VLD4d16, false, SingleSpc, 4); break; + case ARM::VLD4d32Pseudo: + ExpandVLD(MBBI, ARM::VLD4d32, false, SingleSpc, 4); break; + case ARM::VLD1d64QPseudo: + ExpandVLD(MBBI, ARM::VLD1d64Q, false, SingleSpc, 4); break; + case ARM::VLD4d8Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD4d8_UPD, true, SingleSpc, 4); break; + case ARM::VLD4d16Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD4d16_UPD, true, SingleSpc, 4); break; + case ARM::VLD4d32Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD4d32_UPD, true, SingleSpc, 4); break; + case ARM::VLD1d64QPseudo_UPD: + ExpandVLD(MBBI, ARM::VLD1d64Q_UPD, true, SingleSpc, 4); break; + case ARM::VLD4q8Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD4q8_UPD, true, EvenDblSpc, 4); break; + case ARM::VLD4q16Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD4q16_UPD, true, EvenDblSpc, 4); break; + case ARM::VLD4q32Pseudo_UPD: + ExpandVLD(MBBI, ARM::VLD4q32_UPD, true, EvenDblSpc, 4); break; + case ARM::VLD4q8oddPseudo_UPD: + ExpandVLD(MBBI, ARM::VLD4q8_UPD, true, OddDblSpc, 4); break; + case ARM::VLD4q16oddPseudo_UPD: + ExpandVLD(MBBI, ARM::VLD4q16_UPD, true, OddDblSpc, 4); break; + case ARM::VLD4q32oddPseudo_UPD: + ExpandVLD(MBBI, ARM::VLD4q32_UPD, true, OddDblSpc, 4); break; + + case ARM::VST1q8Pseudo: + ExpandVST(MBBI, ARM::VST1q8, false, SingleSpc, 2); break; + case ARM::VST1q16Pseudo: + ExpandVST(MBBI, ARM::VST1q16, false, SingleSpc, 2); break; + case ARM::VST1q32Pseudo: + ExpandVST(MBBI, ARM::VST1q32, false, SingleSpc, 2); break; + case ARM::VST1q64Pseudo: + ExpandVST(MBBI, ARM::VST1q64, false, SingleSpc, 2); break; + case ARM::VST1q8Pseudo_UPD: + ExpandVST(MBBI, ARM::VST1q8_UPD, true, SingleSpc, 2); break; + case ARM::VST1q16Pseudo_UPD: + ExpandVST(MBBI, ARM::VST1q16_UPD, true, SingleSpc, 2); break; + case ARM::VST1q32Pseudo_UPD: + ExpandVST(MBBI, ARM::VST1q32_UPD, true, SingleSpc, 2); break; + case ARM::VST1q64Pseudo_UPD: + ExpandVST(MBBI, ARM::VST1q64_UPD, true, SingleSpc, 2); break; + + case ARM::VST2d8Pseudo: + ExpandVST(MBBI, ARM::VST2d8, false, SingleSpc, 2); break; + case ARM::VST2d16Pseudo: + ExpandVST(MBBI, ARM::VST2d16, false, SingleSpc, 2); break; + case ARM::VST2d32Pseudo: + ExpandVST(MBBI, ARM::VST2d32, false, SingleSpc, 2); break; + case ARM::VST2q8Pseudo: + ExpandVST(MBBI, ARM::VST2q8, false, SingleSpc, 4); break; + case ARM::VST2q16Pseudo: + ExpandVST(MBBI, ARM::VST2q16, false, SingleSpc, 4); break; + case ARM::VST2q32Pseudo: + ExpandVST(MBBI, ARM::VST2q32, false, SingleSpc, 4); break; + case ARM::VST2d8Pseudo_UPD: + ExpandVST(MBBI, ARM::VST2d8_UPD, true, SingleSpc, 2); break; + case ARM::VST2d16Pseudo_UPD: + ExpandVST(MBBI, ARM::VST2d16_UPD, true, SingleSpc, 2); break; + case ARM::VST2d32Pseudo_UPD: + ExpandVST(MBBI, ARM::VST2d32_UPD, true, SingleSpc, 2); break; + case ARM::VST2q8Pseudo_UPD: + ExpandVST(MBBI, ARM::VST2q8_UPD, true, SingleSpc, 4); break; + case ARM::VST2q16Pseudo_UPD: + ExpandVST(MBBI, ARM::VST2q16_UPD, true, SingleSpc, 4); break; + case ARM::VST2q32Pseudo_UPD: + ExpandVST(MBBI, ARM::VST2q32_UPD, true, SingleSpc, 4); break; + + case ARM::VST3d8Pseudo: + ExpandVST(MBBI, ARM::VST3d8, false, SingleSpc, 3); break; + case ARM::VST3d16Pseudo: + ExpandVST(MBBI, ARM::VST3d16, false, SingleSpc, 3); break; + case ARM::VST3d32Pseudo: + ExpandVST(MBBI, ARM::VST3d32, false, SingleSpc, 3); break; + case ARM::VST1d64TPseudo: + ExpandVST(MBBI, ARM::VST1d64T, false, SingleSpc, 3); break; + case ARM::VST3d8Pseudo_UPD: + ExpandVST(MBBI, ARM::VST3d8_UPD, true, SingleSpc, 3); break; + case ARM::VST3d16Pseudo_UPD: + ExpandVST(MBBI, ARM::VST3d16_UPD, true, SingleSpc, 3); break; + case ARM::VST3d32Pseudo_UPD: + ExpandVST(MBBI, ARM::VST3d32_UPD, true, SingleSpc, 3); break; + case ARM::VST1d64TPseudo_UPD: + ExpandVST(MBBI, ARM::VST1d64T_UPD, true, SingleSpc, 3); break; + case ARM::VST3q8Pseudo_UPD: + ExpandVST(MBBI, ARM::VST3q8_UPD, true, EvenDblSpc, 3); break; + case ARM::VST3q16Pseudo_UPD: + ExpandVST(MBBI, ARM::VST3q16_UPD, true, EvenDblSpc, 3); break; + case ARM::VST3q32Pseudo_UPD: + ExpandVST(MBBI, ARM::VST3q32_UPD, true, EvenDblSpc, 3); break; + case ARM::VST3q8oddPseudo_UPD: + ExpandVST(MBBI, ARM::VST3q8_UPD, true, OddDblSpc, 3); break; + case ARM::VST3q16oddPseudo_UPD: + ExpandVST(MBBI, ARM::VST3q16_UPD, true, OddDblSpc, 3); break; + case ARM::VST3q32oddPseudo_UPD: + ExpandVST(MBBI, ARM::VST3q32_UPD, true, OddDblSpc, 3); break; + + case ARM::VST4d8Pseudo: + ExpandVST(MBBI, ARM::VST4d8, false, SingleSpc, 4); break; + case ARM::VST4d16Pseudo: + ExpandVST(MBBI, ARM::VST4d16, false, SingleSpc, 4); break; + case ARM::VST4d32Pseudo: + ExpandVST(MBBI, ARM::VST4d32, false, SingleSpc, 4); break; + case ARM::VST1d64QPseudo: + ExpandVST(MBBI, ARM::VST1d64Q, false, SingleSpc, 4); break; + case ARM::VST4d8Pseudo_UPD: + ExpandVST(MBBI, ARM::VST4d8_UPD, true, SingleSpc, 4); break; + case ARM::VST4d16Pseudo_UPD: + ExpandVST(MBBI, ARM::VST4d16_UPD, true, SingleSpc, 4); break; + case ARM::VST4d32Pseudo_UPD: + ExpandVST(MBBI, ARM::VST4d32_UPD, true, SingleSpc, 4); break; + case ARM::VST1d64QPseudo_UPD: + ExpandVST(MBBI, ARM::VST1d64Q_UPD, true, SingleSpc, 4); break; + case ARM::VST4q8Pseudo_UPD: + ExpandVST(MBBI, ARM::VST4q8_UPD, true, EvenDblSpc, 4); break; + case ARM::VST4q16Pseudo_UPD: + ExpandVST(MBBI, ARM::VST4q16_UPD, true, EvenDblSpc, 4); break; + case ARM::VST4q32Pseudo_UPD: + ExpandVST(MBBI, ARM::VST4q32_UPD, true, EvenDblSpc, 4); break; + case ARM::VST4q8oddPseudo_UPD: + ExpandVST(MBBI, ARM::VST4q8_UPD, true, OddDblSpc, 4); break; + case ARM::VST4q16oddPseudo_UPD: + ExpandVST(MBBI, ARM::VST4q16_UPD, true, OddDblSpc, 4); break; + case ARM::VST4q32oddPseudo_UPD: + ExpandVST(MBBI, ARM::VST4q32_UPD, true, OddDblSpc, 4); break; } + + if (ModifiedOp) + Modified = true; MBBI = NMBBI; } diff --git a/lib/Target/ARM/ARMFastISel.cpp b/lib/Target/ARM/ARMFastISel.cpp new file mode 100644 index 0000000..4892eae --- /dev/null +++ b/lib/Target/ARM/ARMFastISel.cpp @@ -0,0 +1,665 @@ +//===-- ARMFastISel.cpp - ARM FastISel implementation ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ARM-specific support for the FastISel class. Some +// of the target-specific code is generated by tablegen in the file +// ARMGenFastISel.inc, which is #included here. +// +//===----------------------------------------------------------------------===// + +#include "ARM.h" +#include "ARMBaseInstrInfo.h" +#include "ARMRegisterInfo.h" +#include "ARMTargetMachine.h" +#include "ARMSubtarget.h" +#include "llvm/CallingConv.h" +#include "llvm/DerivedTypes.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Instructions.h" +#include "llvm/IntrinsicInst.h" +#include "llvm/CodeGen/Analysis.h" +#include "llvm/CodeGen/FastISel.h" +#include "llvm/CodeGen/FunctionLoweringInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Support/CallSite.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/GetElementPtrTypeIterator.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetLowering.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +using namespace llvm; + +static cl::opt +EnableARMFastISel("arm-fast-isel", + cl::desc("Turn on experimental ARM fast-isel support"), + cl::init(false), cl::Hidden); + +namespace { + +class ARMFastISel : public FastISel { + + /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can + /// make the right decision when generating code for different targets. + const ARMSubtarget *Subtarget; + const TargetMachine &TM; + const TargetInstrInfo &TII; + const TargetLowering &TLI; + const ARMFunctionInfo *AFI; + + // Convenience variable to avoid checking all the time. + bool isThumb; + + public: + explicit ARMFastISel(FunctionLoweringInfo &funcInfo) + : FastISel(funcInfo), + TM(funcInfo.MF->getTarget()), + TII(*TM.getInstrInfo()), + TLI(*TM.getTargetLowering()) { + Subtarget = &TM.getSubtarget(); + AFI = funcInfo.MF->getInfo(); + isThumb = AFI->isThumbFunction(); + } + + // Code from FastISel.cpp. + virtual unsigned FastEmitInst_(unsigned MachineInstOpcode, + const TargetRegisterClass *RC); + virtual unsigned FastEmitInst_r(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill); + virtual unsigned FastEmitInst_rr(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, + unsigned Op1, bool Op1IsKill); + virtual unsigned FastEmitInst_ri(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, + uint64_t Imm); + virtual unsigned FastEmitInst_rf(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, + const ConstantFP *FPImm); + virtual unsigned FastEmitInst_i(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + uint64_t Imm); + virtual unsigned FastEmitInst_rri(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, + unsigned Op1, bool Op1IsKill, + uint64_t Imm); + virtual unsigned FastEmitInst_extractsubreg(MVT RetVT, + unsigned Op0, bool Op0IsKill, + uint32_t Idx); + + // Backend specific FastISel code. + virtual bool TargetSelectInstruction(const Instruction *I); + virtual unsigned TargetMaterializeConstant(const Constant *C); + + #include "ARMGenFastISel.inc" + + // Instruction selection routines. + virtual bool ARMSelectLoad(const Instruction *I); + virtual bool ARMSelectStore(const Instruction *I); + virtual bool ARMSelectBranch(const Instruction *I); + + // Utility routines. + private: + bool isTypeLegal(const Type *Ty, EVT &VT); + bool isLoadTypeLegal(const Type *Ty, EVT &VT); + bool ARMEmitLoad(EVT VT, unsigned &ResultReg, unsigned Reg, int Offset); + bool ARMEmitStore(EVT VT, unsigned SrcReg, unsigned Reg, int Offset); + bool ARMLoadAlloca(const Instruction *I); + bool ARMStoreAlloca(const Instruction *I, unsigned SrcReg); + bool ARMComputeRegOffset(const Value *Obj, unsigned &Reg, int &Offset); + bool ARMMaterializeConstant(const ConstantInt *Val, unsigned &Reg); + + bool DefinesOptionalPredicate(MachineInstr *MI, bool *CPSR); + const MachineInstrBuilder &AddOptionalDefs(const MachineInstrBuilder &MIB); +}; + +} // end anonymous namespace + +// #include "ARMGenCallingConv.inc" + +// DefinesOptionalPredicate - This is different from DefinesPredicate in that +// we don't care about implicit defs here, just places we'll need to add a +// default CCReg argument. Sets CPSR if we're setting CPSR instead of CCR. +bool ARMFastISel::DefinesOptionalPredicate(MachineInstr *MI, bool *CPSR) { + const TargetInstrDesc &TID = MI->getDesc(); + if (!TID.hasOptionalDef()) + return false; + + // Look to see if our OptionalDef is defining CPSR or CCR. + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + if (!MO.isReg() || !MO.isDef()) continue; + if (MO.getReg() == ARM::CPSR) + *CPSR = true; + } + return true; +} + +// If the machine is predicable go ahead and add the predicate operands, if +// it needs default CC operands add those. +const MachineInstrBuilder & +ARMFastISel::AddOptionalDefs(const MachineInstrBuilder &MIB) { + MachineInstr *MI = &*MIB; + + // Do we use a predicate? + if (TII.isPredicable(MI)) + AddDefaultPred(MIB); + + // Do we optionally set a predicate? Preds is size > 0 iff the predicate + // defines CPSR. All other OptionalDefines in ARM are the CCR register. + bool CPSR = false; + if (DefinesOptionalPredicate(MI, &CPSR)) { + if (CPSR) + AddDefaultT1CC(MIB); + else + AddDefaultCC(MIB); + } + return MIB; +} + +unsigned ARMFastISel::FastEmitInst_(unsigned MachineInstOpcode, + const TargetRegisterClass* RC) { + unsigned ResultReg = createResultReg(RC); + const TargetInstrDesc &II = TII.get(MachineInstOpcode); + + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg)); + return ResultReg; +} + +unsigned ARMFastISel::FastEmitInst_r(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill) { + unsigned ResultReg = createResultReg(RC); + const TargetInstrDesc &II = TII.get(MachineInstOpcode); + + if (II.getNumDefs() >= 1) + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) + .addReg(Op0, Op0IsKill * RegState::Kill)); + else { + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) + .addReg(Op0, Op0IsKill * RegState::Kill)); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(TargetOpcode::COPY), ResultReg) + .addReg(II.ImplicitDefs[0])); + } + return ResultReg; +} + +unsigned ARMFastISel::FastEmitInst_rr(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, + unsigned Op1, bool Op1IsKill) { + unsigned ResultReg = createResultReg(RC); + const TargetInstrDesc &II = TII.get(MachineInstOpcode); + + if (II.getNumDefs() >= 1) + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) + .addReg(Op0, Op0IsKill * RegState::Kill) + .addReg(Op1, Op1IsKill * RegState::Kill)); + else { + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) + .addReg(Op0, Op0IsKill * RegState::Kill) + .addReg(Op1, Op1IsKill * RegState::Kill)); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(TargetOpcode::COPY), ResultReg) + .addReg(II.ImplicitDefs[0])); + } + return ResultReg; +} + +unsigned ARMFastISel::FastEmitInst_ri(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, + uint64_t Imm) { + unsigned ResultReg = createResultReg(RC); + const TargetInstrDesc &II = TII.get(MachineInstOpcode); + + if (II.getNumDefs() >= 1) + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) + .addReg(Op0, Op0IsKill * RegState::Kill) + .addImm(Imm)); + else { + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) + .addReg(Op0, Op0IsKill * RegState::Kill) + .addImm(Imm)); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(TargetOpcode::COPY), ResultReg) + .addReg(II.ImplicitDefs[0])); + } + return ResultReg; +} + +unsigned ARMFastISel::FastEmitInst_rf(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, + const ConstantFP *FPImm) { + unsigned ResultReg = createResultReg(RC); + const TargetInstrDesc &II = TII.get(MachineInstOpcode); + + if (II.getNumDefs() >= 1) + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) + .addReg(Op0, Op0IsKill * RegState::Kill) + .addFPImm(FPImm)); + else { + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) + .addReg(Op0, Op0IsKill * RegState::Kill) + .addFPImm(FPImm)); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(TargetOpcode::COPY), ResultReg) + .addReg(II.ImplicitDefs[0])); + } + return ResultReg; +} + +unsigned ARMFastISel::FastEmitInst_rri(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + unsigned Op0, bool Op0IsKill, + unsigned Op1, bool Op1IsKill, + uint64_t Imm) { + unsigned ResultReg = createResultReg(RC); + const TargetInstrDesc &II = TII.get(MachineInstOpcode); + + if (II.getNumDefs() >= 1) + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) + .addReg(Op0, Op0IsKill * RegState::Kill) + .addReg(Op1, Op1IsKill * RegState::Kill) + .addImm(Imm)); + else { + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) + .addReg(Op0, Op0IsKill * RegState::Kill) + .addReg(Op1, Op1IsKill * RegState::Kill) + .addImm(Imm)); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(TargetOpcode::COPY), ResultReg) + .addReg(II.ImplicitDefs[0])); + } + return ResultReg; +} + +unsigned ARMFastISel::FastEmitInst_i(unsigned MachineInstOpcode, + const TargetRegisterClass *RC, + uint64_t Imm) { + unsigned ResultReg = createResultReg(RC); + const TargetInstrDesc &II = TII.get(MachineInstOpcode); + + if (II.getNumDefs() >= 1) + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) + .addImm(Imm)); + else { + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) + .addImm(Imm)); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(TargetOpcode::COPY), ResultReg) + .addReg(II.ImplicitDefs[0])); + } + return ResultReg; +} + +unsigned ARMFastISel::FastEmitInst_extractsubreg(MVT RetVT, + unsigned Op0, bool Op0IsKill, + uint32_t Idx) { + unsigned ResultReg = createResultReg(TLI.getRegClassFor(RetVT)); + assert(TargetRegisterInfo::isVirtualRegister(Op0) && + "Cannot yet extract from physregs"); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, + DL, TII.get(TargetOpcode::COPY), ResultReg) + .addReg(Op0, getKillRegState(Op0IsKill), Idx)); + return ResultReg; +} + +unsigned ARMFastISel::TargetMaterializeConstant(const Constant *C) { + EVT VT = TLI.getValueType(C->getType(), true); + + // Only handle simple types. + if (!VT.isSimple()) return 0; + + // TODO: This should be safe for fp because they're just bits from the + // Constant. + // TODO: Theoretically we could materialize fp constants with instructions + // from VFP3. + + // MachineConstantPool wants an explicit alignment. + unsigned Align = TD.getPrefTypeAlignment(C->getType()); + if (Align == 0) { + // TODO: Figure out if this is correct. + Align = TD.getTypeAllocSize(C->getType()); + } + unsigned Idx = MCP.getConstantPoolIndex(C, Align); + + unsigned DestReg = createResultReg(TLI.getRegClassFor(VT)); + // Different addressing modes between ARM/Thumb2 for constant pool loads. + if (isThumb) + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(ARM::t2LDRpci)) + .addReg(DestReg).addConstantPoolIndex(Idx)); + else + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(ARM::LDRcp)) + .addReg(DestReg).addConstantPoolIndex(Idx) + .addReg(0).addImm(0)); + + return DestReg; +} + +bool ARMFastISel::isTypeLegal(const Type *Ty, EVT &VT) { + VT = TLI.getValueType(Ty, true); + + // Only handle simple types. + if (VT == MVT::Other || !VT.isSimple()) return false; + + // Handle all legal types, i.e. a register that will directly hold this + // value. + return TLI.isTypeLegal(VT); +} + +bool ARMFastISel::isLoadTypeLegal(const Type *Ty, EVT &VT) { + if (isTypeLegal(Ty, VT)) return true; + + // If this is a type than can be sign or zero-extended to a basic operation + // go ahead and accept it now. + if (VT == MVT::i8 || VT == MVT::i16) + return true; + + return false; +} + +// Computes the Reg+Offset to get to an object. +bool ARMFastISel::ARMComputeRegOffset(const Value *Obj, unsigned &Reg, + int &Offset) { + // Some boilerplate from the X86 FastISel. + const User *U = NULL; + unsigned Opcode = Instruction::UserOp1; + if (const Instruction *I = dyn_cast(Obj)) { + // Don't walk into other basic blocks; it's possible we haven't + // visited them yet, so the instructions may not yet be assigned + // virtual registers. + if (FuncInfo.MBBMap[I->getParent()] != FuncInfo.MBB) + return false; + + Opcode = I->getOpcode(); + U = I; + } else if (const ConstantExpr *C = dyn_cast(Obj)) { + Opcode = C->getOpcode(); + U = C; + } + + if (const PointerType *Ty = dyn_cast(Obj->getType())) + if (Ty->getAddressSpace() > 255) + // Fast instruction selection doesn't support the special + // address spaces. + return false; + + switch (Opcode) { + default: + //errs() << "Failing Opcode is: " << *Op1 << "\n"; + break; + case Instruction::Alloca: { + assert(false && "Alloca should have been handled earlier!"); + return false; + } + } + + if (const GlobalValue *GV = dyn_cast(Obj)) { + //errs() << "Failing GV is: " << GV << "\n"; + (void)GV; + return false; + } + + // Try to get this in a register if nothing else has worked. + Reg = getRegForValue(Obj); + if (Reg == 0) return false; + + // Since the offset may be too large for the load instruction + // get the reg+offset into a register. + // TODO: Verify the additions work, otherwise we'll need to add the + // offset instead of 0 to the instructions and do all sorts of operand + // munging. + // TODO: Optimize this somewhat. + if (Offset != 0) { + ARMCC::CondCodes Pred = ARMCC::AL; + unsigned PredReg = 0; + + if (!isThumb) + emitARMRegPlusImmediate(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + Reg, Reg, Offset, Pred, PredReg, + static_cast(TII)); + else { + assert(AFI->isThumb2Function()); + emitT2RegPlusImmediate(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + Reg, Reg, Offset, Pred, PredReg, + static_cast(TII)); + } + } + + return true; +} + +bool ARMFastISel::ARMLoadAlloca(const Instruction *I) { + Value *Op0 = I->getOperand(0); + + // Verify it's an alloca. + if (const AllocaInst *AI = dyn_cast(Op0)) { + DenseMap::iterator SI = + FuncInfo.StaticAllocaMap.find(AI); + + if (SI != FuncInfo.StaticAllocaMap.end()) { + TargetRegisterClass* RC = TLI.getRegClassFor(TLI.getPointerTy()); + unsigned ResultReg = createResultReg(RC); + TII.loadRegFromStackSlot(*FuncInfo.MBB, *FuncInfo.InsertPt, + ResultReg, SI->second, RC, + TM.getRegisterInfo()); + UpdateValueMap(I, ResultReg); + return true; + } + } + return false; +} + +bool ARMFastISel::ARMEmitLoad(EVT VT, unsigned &ResultReg, + unsigned Reg, int Offset) { + + assert(VT.isSimple() && "Non-simple types are invalid here!"); + unsigned Opc; + + switch (VT.getSimpleVT().SimpleTy) { + default: + assert(false && "Trying to emit for an unhandled type!"); + return false; + case MVT::i16: + Opc = isThumb ? ARM::tLDRH : ARM::LDRH; + VT = MVT::i32; + break; + case MVT::i8: + Opc = isThumb ? ARM::tLDRB : ARM::LDRB; + VT = MVT::i32; + break; + case MVT::i32: + Opc = isThumb ? ARM::tLDR : ARM::LDR; + break; + } + + ResultReg = createResultReg(TLI.getRegClassFor(VT)); + + // TODO: Fix the Addressing modes so that these can share some code. + // Since this is a Thumb1 load this will work in Thumb1 or 2 mode. + if (isThumb) + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(Opc), ResultReg) + .addReg(Reg).addImm(Offset).addReg(0)); + else + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(Opc), ResultReg) + .addReg(Reg).addReg(0).addImm(Offset)); + + return true; +} + +bool ARMFastISel::ARMStoreAlloca(const Instruction *I, unsigned SrcReg) { + Value *Op1 = I->getOperand(1); + + // Verify it's an alloca. + if (const AllocaInst *AI = dyn_cast(Op1)) { + DenseMap::iterator SI = + FuncInfo.StaticAllocaMap.find(AI); + + if (SI != FuncInfo.StaticAllocaMap.end()) { + TargetRegisterClass* RC = TLI.getRegClassFor(TLI.getPointerTy()); + assert(SrcReg != 0 && "Nothing to store!"); + TII.storeRegToStackSlot(*FuncInfo.MBB, *FuncInfo.InsertPt, + SrcReg, true /*isKill*/, SI->second, RC, + TM.getRegisterInfo()); + return true; + } + } + return false; +} + +bool ARMFastISel::ARMEmitStore(EVT VT, unsigned SrcReg, + unsigned DstReg, int Offset) { + unsigned StrOpc; + switch (VT.getSimpleVT().SimpleTy) { + default: return false; + case MVT::i1: + case MVT::i8: StrOpc = isThumb ? ARM::tSTRB : ARM::STRB; break; + case MVT::i16: StrOpc = isThumb ? ARM::tSTRH : ARM::STRH; break; + case MVT::i32: StrOpc = isThumb ? ARM::tSTR : ARM::STR; break; + case MVT::f32: + if (!Subtarget->hasVFP2()) return false; + StrOpc = ARM::VSTRS; + break; + case MVT::f64: + if (!Subtarget->hasVFP2()) return false; + StrOpc = ARM::VSTRD; + break; + } + + if (isThumb) + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(StrOpc), SrcReg) + .addReg(DstReg).addImm(Offset).addReg(0)); + else + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(StrOpc), SrcReg) + .addReg(DstReg).addReg(0).addImm(Offset)); + + return true; +} + +bool ARMFastISel::ARMSelectStore(const Instruction *I) { + Value *Op0 = I->getOperand(0); + unsigned SrcReg = 0; + + // Yay type legalization + EVT VT; + if (!isLoadTypeLegal(I->getOperand(0)->getType(), VT)) + return false; + + // Get the value to be stored into a register. + SrcReg = getRegForValue(Op0); + if (SrcReg == 0) + return false; + + // If we're an alloca we know we have a frame index and can emit the store + // quickly. + if (ARMStoreAlloca(I, SrcReg)) + return true; + + // Our register and offset with innocuous defaults. + unsigned Reg = 0; + int Offset = 0; + + // See if we can handle this as Reg + Offset + if (!ARMComputeRegOffset(I->getOperand(1), Reg, Offset)) + return false; + + if (!ARMEmitStore(VT, SrcReg, Reg, Offset /* 0 */)) return false; + + return false; + +} + +bool ARMFastISel::ARMSelectLoad(const Instruction *I) { + // If we're an alloca we know we have a frame index and can emit the load + // directly in short order. + if (ARMLoadAlloca(I)) + return true; + + // Verify we have a legal type before going any further. + EVT VT; + if (!isLoadTypeLegal(I->getType(), VT)) + return false; + + // Our register and offset with innocuous defaults. + unsigned Reg = 0; + int Offset = 0; + + // See if we can handle this as Reg + Offset + if (!ARMComputeRegOffset(I->getOperand(0), Reg, Offset)) + return false; + + unsigned ResultReg; + if (!ARMEmitLoad(VT, ResultReg, Reg, Offset /* 0 */)) return false; + + UpdateValueMap(I, ResultReg); + return true; +} + +bool ARMFastISel::ARMSelectBranch(const Instruction *I) { + const BranchInst *BI = cast(I); + MachineBasicBlock *TBB = FuncInfo.MBBMap[BI->getSuccessor(0)]; + MachineBasicBlock *FBB = FuncInfo.MBBMap[BI->getSuccessor(1)]; + + // Simple branch support. + unsigned CondReg = getRegForValue(BI->getCondition()); + if (CondReg == 0) return false; + + unsigned CmpOpc = isThumb ? ARM::t2CMPrr : ARM::CMPrr; + unsigned BrOpc = isThumb ? ARM::t2Bcc : ARM::Bcc; + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CmpOpc)) + .addReg(CondReg).addReg(CondReg)); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(BrOpc)) + .addMBB(TBB).addImm(ARMCC::NE).addReg(ARM::CPSR); + FastEmitBranch(FBB, DL); + FuncInfo.MBB->addSuccessor(TBB); + return true; +} + +// TODO: SoftFP support. +bool ARMFastISel::TargetSelectInstruction(const Instruction *I) { + // No Thumb-1 for now. + if (isThumb && !AFI->isThumb2Function()) return false; + + switch (I->getOpcode()) { + case Instruction::Load: + return ARMSelectLoad(I); + case Instruction::Store: + return ARMSelectStore(I); + case Instruction::Br: + return ARMSelectBranch(I); + default: break; + } + return false; +} + +namespace llvm { + llvm::FastISel *ARM::createFastISel(FunctionLoweringInfo &funcInfo) { + if (EnableARMFastISel) return new ARMFastISel(funcInfo); + return 0; + } +} diff --git a/lib/Target/ARM/ARMGlobalMerge.cpp b/lib/Target/ARM/ARMGlobalMerge.cpp new file mode 100644 index 0000000..85b0c6c --- /dev/null +++ b/lib/Target/ARM/ARMGlobalMerge.cpp @@ -0,0 +1,212 @@ +//===-- ARMGlobalMerge.cpp - Internal globals merging --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This pass merges globals with internal linkage into one. This way all the +// globals which were merged into a biggest one can be addressed using offsets +// from the same base pointer (no need for separate base pointer for each of the +// global). Such a transformation can significantly reduce the register pressure +// when many globals are involved. +// +// For example, consider the code which touches several global variables at once: +// +// static int foo[N], bar[N], baz[N]; +// +// for (i = 0; i < N; ++i) { +// foo[i] = bar[i] * baz[i]; +// } +// +// On ARM the addresses of 3 arrays should be kept in the registers, thus +// this code has quite large register pressure (loop body): +// +// ldr r1, [r5], #4 +// ldr r2, [r6], #4 +// mul r1, r2, r1 +// str r1, [r0], #4 +// +// Pass converts the code to something like: +// +// static struct { +// int foo[N]; +// int bar[N]; +// int baz[N]; +// } merged; +// +// for (i = 0; i < N; ++i) { +// merged.foo[i] = merged.bar[i] * merged.baz[i]; +// } +// +// and in ARM code this becomes: +// +// ldr r0, [r5, #40] +// ldr r1, [r5, #80] +// mul r0, r1, r0 +// str r0, [r5], #4 +// +// note that we saved 2 registers here almostly "for free". +// ===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "arm-global-merge" +#include "ARM.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Attributes.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Function.h" +#include "llvm/GlobalVariable.h" +#include "llvm/Instructions.h" +#include "llvm/Intrinsics.h" +#include "llvm/Module.h" +#include "llvm/Pass.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetLowering.h" +using namespace llvm; + +namespace { + class LLVM_LIBRARY_VISIBILITY ARMGlobalMerge : public FunctionPass { + /// TLI - Keep a pointer of a TargetLowering to consult for determining + /// target type sizes. + const TargetLowering *TLI; + + bool doMerge(SmallVectorImpl &Globals, + Module &M, bool) const; + + public: + static char ID; // Pass identification, replacement for typeid. + explicit ARMGlobalMerge(const TargetLowering *tli) + : FunctionPass(ID), TLI(tli) {} + + virtual bool doInitialization(Module &M); + virtual bool runOnFunction(Function& F); + + const char *getPassName() const { + return "Merge internal globals"; + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); + FunctionPass::getAnalysisUsage(AU); + } + + struct GlobalCmp { + const TargetData *TD; + + GlobalCmp(const TargetData *td): + TD(td) { } + + bool operator() (const GlobalVariable* GV1, + const GlobalVariable* GV2) { + const Type* Ty1 = cast(GV1->getType())->getElementType(); + const Type* Ty2 = cast(GV2->getType())->getElementType(); + + return (TD->getTypeAllocSize(Ty1) < TD->getTypeAllocSize(Ty2)); + } + }; + }; +} // end anonymous namespace + +char ARMGlobalMerge::ID = 0; + +bool ARMGlobalMerge::doMerge(SmallVectorImpl &Globals, + Module &M, bool isConst) const { + const TargetData *TD = TLI->getTargetData(); + + // FIXME: Infer the maximum possible offset depending on the actual users + // (these max offsets are different for the users inside Thumb or ARM + // functions) + unsigned MaxOffset = TLI->getMaximalGlobalOffset(); + + // FIXME: Find better heuristics + std::stable_sort(Globals.begin(), Globals.end(), GlobalCmp(TD)); + + const Type *Int32Ty = Type::getInt32Ty(M.getContext()); + + for (size_t i = 0, e = Globals.size(); i != e; ) { + size_t j = 0; + uint64_t MergedSize = 0; + std::vector Tys; + std::vector Inits; + for (j = i; MergedSize < MaxOffset && j != e; ++j) { + const Type* Ty = Globals[j]->getType()->getElementType(); + Tys.push_back(Ty); + Inits.push_back(Globals[j]->getInitializer()); + MergedSize += TD->getTypeAllocSize(Ty); + } + + StructType* MergedTy = StructType::get(M.getContext(), Tys); + Constant* MergedInit = ConstantStruct::get(MergedTy, Inits); + GlobalVariable* MergedGV = new GlobalVariable(M, MergedTy, isConst, + GlobalValue::InternalLinkage, + MergedInit, "merged"); + for (size_t k = i; k < j; ++k) { + SmallVector Idx; + Idx.push_back(ConstantInt::get(Int32Ty, 0)); + Idx.push_back(ConstantInt::get(Int32Ty, k-i)); + + Constant* GEP = + ConstantExpr::getInBoundsGetElementPtr(MergedGV, + &Idx[0], Idx.size()); + + Globals[k]->replaceAllUsesWith(GEP); + Globals[k]->eraseFromParent(); + } + i = j; + } + + return true; +} + + +bool ARMGlobalMerge::doInitialization(Module& M) { + SmallVector Globals, ConstGlobals; + const TargetData *TD = TLI->getTargetData(); + unsigned MaxOffset = TLI->getMaximalGlobalOffset(); + bool Changed = false; + + // Grab all non-const globals. + for (Module::global_iterator I = M.global_begin(), + E = M.global_end(); I != E; ++I) { + // Merge is safe for "normal" internal globals only + if (!I->hasLocalLinkage() || I->isThreadLocal() || I->hasSection()) + continue; + + // Ignore fancy-aligned globals for now. + if (I->getAlignment() != 0) + continue; + + // Ignore all 'special' globals. + if (I->getName().startswith("llvm.") || + I->getName().startswith(".llvm.")) + continue; + + if (TD->getTypeAllocSize(I->getType()) < MaxOffset) { + if (I->isConstant()) + ConstGlobals.push_back(I); + else + Globals.push_back(I); + } + } + + if (Globals.size() > 1) + Changed |= doMerge(Globals, M, false); + // FIXME: This currently breaks the EH processing due to way how the + // typeinfo detection works. We might want to detect the TIs and ignore + // them in the future. + + // if (ConstGlobals.size() > 1) + // Changed |= doMerge(ConstGlobals, M, true); + + return Changed; +} + +bool ARMGlobalMerge::runOnFunction(Function& F) { + return false; +} + +FunctionPass *llvm::createARMGlobalMergePass(const TargetLowering *tli) { + return new ARMGlobalMerge(tli); +} diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index c84d3ff..51a30c1 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -36,6 +36,11 @@ using namespace llvm; +static cl::opt +DisableShifterOp("disable-shifter-op", cl::Hidden, + cl::desc("Disable isel of shifter-op"), + cl::init(false)); + //===--------------------------------------------------------------------===// /// ARMDAGToDAGISel - ARM specific code to select ARM machine /// instructions for SelectionDAG operations. @@ -113,6 +118,16 @@ public: bool SelectT2AddrModeSoReg(SDNode *Op, SDValue N, SDValue &Base, SDValue &OffReg, SDValue &ShImm); + inline bool Pred_so_imm(SDNode *inN) const { + ConstantSDNode *N = cast(inN); + return ARM_AM::getSOImmVal(N->getZExtValue()) != -1; + } + + inline bool Pred_t2_so_imm(SDNode *inN) const { + ConstantSDNode *N = cast(inN); + return ARM_AM::getT2SOImmVal(N->getZExtValue()) != -1; + } + // Include the pieces autogenerated from the target description. #include "ARMGenDAGISel.inc" @@ -220,6 +235,9 @@ bool ARMDAGToDAGISel::SelectShifterOperandReg(SDNode *Op, SDValue &BaseReg, SDValue &ShReg, SDValue &Opc) { + if (DisableShifterOp) + return false; + ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N); // Don't match base register only case. That is matched to a separate @@ -463,7 +481,7 @@ bool ARMDAGToDAGISel::SelectAddrMode3Offset(SDNode *Op, SDValue N, bool ARMDAGToDAGISel::SelectAddrMode4(SDNode *Op, SDValue N, SDValue &Addr, SDValue &Mode) { Addr = N; - Mode = CurDAG->getTargetConstant(0, MVT::i32); + Mode = CurDAG->getTargetConstant(ARM_AM::getAM4ModeImm(ARM_AM::ia), MVT::i32); return true; } @@ -666,6 +684,9 @@ bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDNode *Op, SDValue N, bool ARMDAGToDAGISel::SelectT2ShifterOperandReg(SDNode *Op, SDValue N, SDValue &BaseReg, SDValue &Opc) { + if (DisableShifterOp) + return false; + ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N); // Don't match base register only case. That is matched to a separate @@ -1090,110 +1111,79 @@ SDNode *ARMDAGToDAGISel::SelectVLD(SDNode *N, unsigned NumVecs, break; } + EVT ResTy; + if (NumVecs == 1) + ResTy = VT; + else { + unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs; + if (!is64BitVector) + ResTyElts *= 2; + ResTy = EVT::getVectorVT(*CurDAG->getContext(), MVT::i64, ResTyElts); + } + SDValue Pred = getAL(CurDAG); SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); + SDValue SuperReg; if (is64BitVector) { unsigned Opc = DOpcodes[OpcodeIndex]; const SDValue Ops[] = { MemAddr, Align, Pred, Reg0, Chain }; - std::vector ResTys(NumVecs, VT); - ResTys.push_back(MVT::Other); - SDNode *VLd = CurDAG->getMachineNode(Opc, dl, ResTys, Ops, 5); - if (NumVecs < 2) + SDNode *VLd = CurDAG->getMachineNode(Opc, dl, ResTy, MVT::Other, Ops, 5); + if (NumVecs == 1) return VLd; - SDValue RegSeq; - SDValue V0 = SDValue(VLd, 0); - SDValue V1 = SDValue(VLd, 1); - - // Form a REG_SEQUENCE to force register allocation. - if (NumVecs == 2) - RegSeq = SDValue(PairDRegs(MVT::v2i64, V0, V1), 0); - else { - SDValue V2 = SDValue(VLd, 2); - // If it's a vld3, form a quad D-register but discard the last part. - SDValue V3 = (NumVecs == 3) - ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,dl,VT), 0) - : SDValue(VLd, 3); - RegSeq = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); - } - + SuperReg = SDValue(VLd, 0); assert(ARM::dsub_7 == ARM::dsub_0+7 && "Unexpected subreg numbering"); for (unsigned Vec = 0; Vec < NumVecs; ++Vec) { SDValue D = CurDAG->getTargetExtractSubreg(ARM::dsub_0+Vec, - dl, VT, RegSeq); + dl, VT, SuperReg); ReplaceUses(SDValue(N, Vec), D); } - ReplaceUses(SDValue(N, NumVecs), SDValue(VLd, NumVecs)); + ReplaceUses(SDValue(N, NumVecs), SDValue(VLd, 1)); return NULL; } - EVT RegVT = GetNEONSubregVT(VT); if (NumVecs <= 2) { // Quad registers are directly supported for VLD1 and VLD2, // loading pairs of D regs. unsigned Opc = QOpcodes0[OpcodeIndex]; const SDValue Ops[] = { MemAddr, Align, Pred, Reg0, Chain }; - std::vector ResTys(2 * NumVecs, RegVT); - ResTys.push_back(MVT::Other); - SDNode *VLd = CurDAG->getMachineNode(Opc, dl, ResTys, Ops, 5); - Chain = SDValue(VLd, 2 * NumVecs); + SDNode *VLd = CurDAG->getMachineNode(Opc, dl, ResTy, MVT::Other, Ops, 5); + if (NumVecs == 1) + return VLd; + + SuperReg = SDValue(VLd, 0); + Chain = SDValue(VLd, 1); - // Combine the even and odd subregs to produce the result. - if (NumVecs == 1) { - SDNode *Q = PairDRegs(VT, SDValue(VLd, 0), SDValue(VLd, 1)); - ReplaceUses(SDValue(N, 0), SDValue(Q, 0)); - } else { - SDValue QQ = SDValue(QuadDRegs(MVT::v4i64, - SDValue(VLd, 0), SDValue(VLd, 1), - SDValue(VLd, 2), SDValue(VLd, 3)), 0); - SDValue Q0 = CurDAG->getTargetExtractSubreg(ARM::qsub_0, dl, VT, QQ); - SDValue Q1 = CurDAG->getTargetExtractSubreg(ARM::qsub_1, dl, VT, QQ); - ReplaceUses(SDValue(N, 0), Q0); - ReplaceUses(SDValue(N, 1), Q1); - } } else { // Otherwise, quad registers are loaded with two separate instructions, // where one loads the even registers and the other loads the odd registers. - - std::vector ResTys(NumVecs, RegVT); - ResTys.push_back(MemAddr.getValueType()); - ResTys.push_back(MVT::Other); + EVT AddrTy = MemAddr.getValueType(); // Load the even subregs. unsigned Opc = QOpcodes0[OpcodeIndex]; - const SDValue OpsA[] = { MemAddr, Align, Reg0, Pred, Reg0, Chain }; - SDNode *VLdA = CurDAG->getMachineNode(Opc, dl, ResTys, OpsA, 6); - Chain = SDValue(VLdA, NumVecs+1); + SDValue ImplDef = + SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, ResTy), 0); + const SDValue OpsA[] = { MemAddr, Align, Reg0, ImplDef, Pred, Reg0, Chain }; + SDNode *VLdA = + CurDAG->getMachineNode(Opc, dl, ResTy, AddrTy, MVT::Other, OpsA, 7); + Chain = SDValue(VLdA, 2); // Load the odd subregs. Opc = QOpcodes1[OpcodeIndex]; - const SDValue OpsB[] = { SDValue(VLdA, NumVecs), - Align, Reg0, Pred, Reg0, Chain }; - SDNode *VLdB = CurDAG->getMachineNode(Opc, dl, ResTys, OpsB, 6); - Chain = SDValue(VLdB, NumVecs+1); - - SDValue V0 = SDValue(VLdA, 0); - SDValue V1 = SDValue(VLdB, 0); - SDValue V2 = SDValue(VLdA, 1); - SDValue V3 = SDValue(VLdB, 1); - SDValue V4 = SDValue(VLdA, 2); - SDValue V5 = SDValue(VLdB, 2); - SDValue V6 = (NumVecs == 3) - ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,dl,RegVT), 0) - : SDValue(VLdA, 3); - SDValue V7 = (NumVecs == 3) - ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,dl,RegVT), 0) - : SDValue(VLdB, 3); - SDValue RegSeq = SDValue(OctoDRegs(MVT::v8i64, V0, V1, V2, V3, - V4, V5, V6, V7), 0); - - // Extract out the 3 / 4 Q registers. - assert(ARM::qsub_3 == ARM::qsub_0+3 && "Unexpected subreg numbering"); - for (unsigned Vec = 0; Vec < NumVecs; ++Vec) { - SDValue Q = CurDAG->getTargetExtractSubreg(ARM::qsub_0+Vec, - dl, VT, RegSeq); - ReplaceUses(SDValue(N, Vec), Q); - } + const SDValue OpsB[] = { SDValue(VLdA, 1), Align, Reg0, SDValue(VLdA, 0), + Pred, Reg0, Chain }; + SDNode *VLdB = + CurDAG->getMachineNode(Opc, dl, ResTy, AddrTy, MVT::Other, OpsB, 7); + SuperReg = SDValue(VLdB, 0); + Chain = SDValue(VLdB, 2); + } + + // Extract out the Q registers. + assert(ARM::qsub_3 == ARM::qsub_0+3 && "Unexpected subreg numbering"); + for (unsigned Vec = 0; Vec < NumVecs; ++Vec) { + SDValue Q = CurDAG->getTargetExtractSubreg(ARM::qsub_0+Vec, + dl, VT, SuperReg); + ReplaceUses(SDValue(N, Vec), Q); } ReplaceUses(SDValue(N, NumVecs), Chain); return NULL; @@ -1235,12 +1225,14 @@ SDNode *ARMDAGToDAGISel::SelectVST(SDNode *N, unsigned NumVecs, SDValue Pred = getAL(CurDAG); SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); - SmallVector Ops; + SmallVector Ops; Ops.push_back(MemAddr); Ops.push_back(Align); if (is64BitVector) { - if (NumVecs >= 2) { + if (NumVecs == 1) { + Ops.push_back(N->getOperand(3)); + } else { SDValue RegSeq; SDValue V0 = N->getOperand(0+3); SDValue V1 = N->getOperand(1+3); @@ -1257,111 +1249,61 @@ SDNode *ARMDAGToDAGISel::SelectVST(SDNode *N, unsigned NumVecs, : N->getOperand(3+3); RegSeq = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); } - - // Now extract the D registers back out. - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_0, dl, VT, - RegSeq)); - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_1, dl, VT, - RegSeq)); - if (NumVecs > 2) - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_2, dl, VT, - RegSeq)); - if (NumVecs > 3) - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_3, dl, VT, - RegSeq)); - } else { - for (unsigned Vec = 0; Vec < NumVecs; ++Vec) - Ops.push_back(N->getOperand(Vec+3)); + Ops.push_back(RegSeq); } Ops.push_back(Pred); Ops.push_back(Reg0); // predicate register Ops.push_back(Chain); unsigned Opc = DOpcodes[OpcodeIndex]; - return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), NumVecs+5); + return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), 6); } - EVT RegVT = GetNEONSubregVT(VT); if (NumVecs <= 2) { - // Quad registers are directly supported for VST1 and VST2, - // storing pairs of D regs. + // Quad registers are directly supported for VST1 and VST2. unsigned Opc = QOpcodes0[OpcodeIndex]; - if (NumVecs == 2) { - // First extract the pair of Q registers. + if (NumVecs == 1) { + Ops.push_back(N->getOperand(3)); + } else { + // Form a QQ register. SDValue Q0 = N->getOperand(3); SDValue Q1 = N->getOperand(4); - - // Form a QQ register. - SDValue QQ = SDValue(PairQRegs(MVT::v4i64, Q0, Q1), 0); - - // Now extract the D registers back out. - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_0, dl, RegVT, - QQ)); - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_1, dl, RegVT, - QQ)); - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_2, dl, RegVT, - QQ)); - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_3, dl, RegVT, - QQ)); - Ops.push_back(Pred); - Ops.push_back(Reg0); // predicate register - Ops.push_back(Chain); - return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), 5 + 4); - } else { - for (unsigned Vec = 0; Vec < NumVecs; ++Vec) { - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_0, dl, RegVT, - N->getOperand(Vec+3))); - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_1, dl, RegVT, - N->getOperand(Vec+3))); - } - Ops.push_back(Pred); - Ops.push_back(Reg0); // predicate register - Ops.push_back(Chain); - return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), - 5 + 2 * NumVecs); + Ops.push_back(SDValue(PairQRegs(MVT::v4i64, Q0, Q1), 0)); } + Ops.push_back(Pred); + Ops.push_back(Reg0); // predicate register + Ops.push_back(Chain); + return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), 6); } // Otherwise, quad registers are stored with two separate instructions, // where one stores the even registers and the other stores the odd registers. // Form the QQQQ REG_SEQUENCE. - SDValue V[8]; - for (unsigned Vec = 0, i = 0; Vec < NumVecs; ++Vec, i+=2) { - V[i] = CurDAG->getTargetExtractSubreg(ARM::dsub_0, dl, RegVT, - N->getOperand(Vec+3)); - V[i+1] = CurDAG->getTargetExtractSubreg(ARM::dsub_1, dl, RegVT, - N->getOperand(Vec+3)); - } - if (NumVecs == 3) - V[6] = V[7] = SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, - dl, RegVT), 0); - - SDValue RegSeq = SDValue(OctoDRegs(MVT::v8i64, V[0], V[1], V[2], V[3], - V[4], V[5], V[6], V[7]), 0); + SDValue V0 = N->getOperand(0+3); + SDValue V1 = N->getOperand(1+3); + SDValue V2 = N->getOperand(2+3); + SDValue V3 = (NumVecs == 3) + ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0) + : N->getOperand(3+3); + SDValue RegSeq = SDValue(QuadQRegs(MVT::v8i64, V0, V1, V2, V3), 0); // Store the even D registers. - assert(ARM::dsub_7 == ARM::dsub_0+7 && "Unexpected subreg numbering"); Ops.push_back(Reg0); // post-access address offset - for (unsigned Vec = 0; Vec < NumVecs; ++Vec) - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_0+Vec*2, dl, - RegVT, RegSeq)); + Ops.push_back(RegSeq); Ops.push_back(Pred); Ops.push_back(Reg0); // predicate register Ops.push_back(Chain); unsigned Opc = QOpcodes0[OpcodeIndex]; SDNode *VStA = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(), - MVT::Other, Ops.data(), NumVecs+6); + MVT::Other, Ops.data(), 7); Chain = SDValue(VStA, 1); // Store the odd D registers. Ops[0] = SDValue(VStA, 0); // MemAddr - for (unsigned Vec = 0; Vec < NumVecs; ++Vec) - Ops[Vec+3] = CurDAG->getTargetExtractSubreg(ARM::dsub_1+Vec*2, dl, - RegVT, RegSeq); - Ops[NumVecs+5] = Chain; + Ops[6] = Chain; Opc = QOpcodes1[OpcodeIndex]; SDNode *VStB = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(), - MVT::Other, Ops.data(), NumVecs+6); + MVT::Other, Ops.data(), 7); Chain = SDValue(VStB, 1); ReplaceUses(SDValue(N, 0), Chain); return NULL; @@ -1675,7 +1617,7 @@ SelectT2CMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, if (!T) return 0; - if (Predicate_t2_so_imm(TrueVal.getNode())) { + if (Pred_t2_so_imm(TrueVal.getNode())) { SDValue True = CurDAG->getTargetConstant(T->getZExtValue(), MVT::i32); SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag }; @@ -1692,7 +1634,7 @@ SelectARMCMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, if (!T) return 0; - if (Predicate_so_imm(TrueVal.getNode())) { + if (Pred_so_imm(TrueVal.getNode())) { SDValue True = CurDAG->getTargetConstant(T->getZExtValue(), MVT::i32); SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag }; @@ -1740,7 +1682,7 @@ SDNode *ARMDAGToDAGISel::SelectCMOVOp(SDNode *N) { } // Pattern: (ARMcmov:i32 GPR:i32:$false, - // (imm:i32)<>:$true, + // (imm:i32)<>:$true, // (imm:i32):$cc) // Emits: (MOVCCi:i32 GPR:i32:$false, // (so_imm:i32 (imm:i32):$true), (imm:i32):$cc) @@ -2013,43 +1955,6 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { ResNode = SelectARMIndexedLoad(N); if (ResNode) return ResNode; - - // VLDMQ must be custom-selected for "v2f64 load" to set the AM5Opc value. - if (Subtarget->hasVFP2() && - N->getValueType(0).getSimpleVT().SimpleTy == MVT::v2f64) { - SDValue Chain = N->getOperand(0); - SDValue AM5Opc = - CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::ia, 4), MVT::i32); - SDValue Pred = getAL(CurDAG); - SDValue PredReg = CurDAG->getRegister(0, MVT::i32); - SDValue Ops[] = { N->getOperand(1), AM5Opc, Pred, PredReg, Chain }; - MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); - MemOp[0] = cast(N)->getMemOperand(); - SDNode *Ret = CurDAG->getMachineNode(ARM::VLDMQ, dl, - MVT::v2f64, MVT::Other, Ops, 5); - cast(Ret)->setMemRefs(MemOp, MemOp + 1); - return Ret; - } - // Other cases are autogenerated. - break; - } - case ISD::STORE: { - // VSTMQ must be custom-selected for "v2f64 store" to set the AM5Opc value. - if (Subtarget->hasVFP2() && - N->getOperand(1).getValueType().getSimpleVT().SimpleTy == MVT::v2f64) { - SDValue Chain = N->getOperand(0); - SDValue AM5Opc = - CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::ia, 4), MVT::i32); - SDValue Pred = getAL(CurDAG); - SDValue PredReg = CurDAG->getRegister(0, MVT::i32); - SDValue Ops[] = { N->getOperand(1), N->getOperand(2), - AM5Opc, Pred, PredReg, Chain }; - MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); - MemOp[0] = cast(N)->getMemOperand(); - SDNode *Ret = CurDAG->getMachineNode(ARM::VSTMQ, dl, MVT::Other, Ops, 6); - cast(Ret)->setMemRefs(MemOp, MemOp + 1); - return Ret; - } // Other cases are autogenerated. break; } @@ -2206,39 +2111,40 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { case Intrinsic::arm_neon_vld1: { unsigned DOpcodes[] = { ARM::VLD1d8, ARM::VLD1d16, ARM::VLD1d32, ARM::VLD1d64 }; - unsigned QOpcodes[] = { ARM::VLD1q8, ARM::VLD1q16, - ARM::VLD1q32, ARM::VLD1q64 }; + unsigned QOpcodes[] = { ARM::VLD1q8Pseudo, ARM::VLD1q16Pseudo, + ARM::VLD1q32Pseudo, ARM::VLD1q64Pseudo }; return SelectVLD(N, 1, DOpcodes, QOpcodes, 0); } case Intrinsic::arm_neon_vld2: { - unsigned DOpcodes[] = { ARM::VLD2d8, ARM::VLD2d16, - ARM::VLD2d32, ARM::VLD1q64 }; - unsigned QOpcodes[] = { ARM::VLD2q8, ARM::VLD2q16, ARM::VLD2q32 }; + unsigned DOpcodes[] = { ARM::VLD2d8Pseudo, ARM::VLD2d16Pseudo, + ARM::VLD2d32Pseudo, ARM::VLD1q64Pseudo }; + unsigned QOpcodes[] = { ARM::VLD2q8Pseudo, ARM::VLD2q16Pseudo, + ARM::VLD2q32Pseudo }; return SelectVLD(N, 2, DOpcodes, QOpcodes, 0); } case Intrinsic::arm_neon_vld3: { - unsigned DOpcodes[] = { ARM::VLD3d8, ARM::VLD3d16, - ARM::VLD3d32, ARM::VLD1d64T }; - unsigned QOpcodes0[] = { ARM::VLD3q8_UPD, - ARM::VLD3q16_UPD, - ARM::VLD3q32_UPD }; - unsigned QOpcodes1[] = { ARM::VLD3q8odd_UPD, - ARM::VLD3q16odd_UPD, - ARM::VLD3q32odd_UPD }; + unsigned DOpcodes[] = { ARM::VLD3d8Pseudo, ARM::VLD3d16Pseudo, + ARM::VLD3d32Pseudo, ARM::VLD1d64TPseudo }; + unsigned QOpcodes0[] = { ARM::VLD3q8Pseudo_UPD, + ARM::VLD3q16Pseudo_UPD, + ARM::VLD3q32Pseudo_UPD }; + unsigned QOpcodes1[] = { ARM::VLD3q8oddPseudo_UPD, + ARM::VLD3q16oddPseudo_UPD, + ARM::VLD3q32oddPseudo_UPD }; return SelectVLD(N, 3, DOpcodes, QOpcodes0, QOpcodes1); } case Intrinsic::arm_neon_vld4: { - unsigned DOpcodes[] = { ARM::VLD4d8, ARM::VLD4d16, - ARM::VLD4d32, ARM::VLD1d64Q }; - unsigned QOpcodes0[] = { ARM::VLD4q8_UPD, - ARM::VLD4q16_UPD, - ARM::VLD4q32_UPD }; - unsigned QOpcodes1[] = { ARM::VLD4q8odd_UPD, - ARM::VLD4q16odd_UPD, - ARM::VLD4q32odd_UPD }; + unsigned DOpcodes[] = { ARM::VLD4d8Pseudo, ARM::VLD4d16Pseudo, + ARM::VLD4d32Pseudo, ARM::VLD1d64QPseudo }; + unsigned QOpcodes0[] = { ARM::VLD4q8Pseudo_UPD, + ARM::VLD4q16Pseudo_UPD, + ARM::VLD4q32Pseudo_UPD }; + unsigned QOpcodes1[] = { ARM::VLD4q8oddPseudo_UPD, + ARM::VLD4q16oddPseudo_UPD, + ARM::VLD4q32oddPseudo_UPD }; return SelectVLD(N, 4, DOpcodes, QOpcodes0, QOpcodes1); } @@ -2266,39 +2172,40 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { case Intrinsic::arm_neon_vst1: { unsigned DOpcodes[] = { ARM::VST1d8, ARM::VST1d16, ARM::VST1d32, ARM::VST1d64 }; - unsigned QOpcodes[] = { ARM::VST1q8, ARM::VST1q16, - ARM::VST1q32, ARM::VST1q64 }; + unsigned QOpcodes[] = { ARM::VST1q8Pseudo, ARM::VST1q16Pseudo, + ARM::VST1q32Pseudo, ARM::VST1q64Pseudo }; return SelectVST(N, 1, DOpcodes, QOpcodes, 0); } case Intrinsic::arm_neon_vst2: { - unsigned DOpcodes[] = { ARM::VST2d8, ARM::VST2d16, - ARM::VST2d32, ARM::VST1q64 }; - unsigned QOpcodes[] = { ARM::VST2q8, ARM::VST2q16, ARM::VST2q32 }; + unsigned DOpcodes[] = { ARM::VST2d8Pseudo, ARM::VST2d16Pseudo, + ARM::VST2d32Pseudo, ARM::VST1q64Pseudo }; + unsigned QOpcodes[] = { ARM::VST2q8Pseudo, ARM::VST2q16Pseudo, + ARM::VST2q32Pseudo }; return SelectVST(N, 2, DOpcodes, QOpcodes, 0); } case Intrinsic::arm_neon_vst3: { - unsigned DOpcodes[] = { ARM::VST3d8, ARM::VST3d16, - ARM::VST3d32, ARM::VST1d64T }; - unsigned QOpcodes0[] = { ARM::VST3q8_UPD, - ARM::VST3q16_UPD, - ARM::VST3q32_UPD }; - unsigned QOpcodes1[] = { ARM::VST3q8odd_UPD, - ARM::VST3q16odd_UPD, - ARM::VST3q32odd_UPD }; + unsigned DOpcodes[] = { ARM::VST3d8Pseudo, ARM::VST3d16Pseudo, + ARM::VST3d32Pseudo, ARM::VST1d64TPseudo }; + unsigned QOpcodes0[] = { ARM::VST3q8Pseudo_UPD, + ARM::VST3q16Pseudo_UPD, + ARM::VST3q32Pseudo_UPD }; + unsigned QOpcodes1[] = { ARM::VST3q8oddPseudo_UPD, + ARM::VST3q16oddPseudo_UPD, + ARM::VST3q32oddPseudo_UPD }; return SelectVST(N, 3, DOpcodes, QOpcodes0, QOpcodes1); } case Intrinsic::arm_neon_vst4: { - unsigned DOpcodes[] = { ARM::VST4d8, ARM::VST4d16, - ARM::VST4d32, ARM::VST1d64Q }; - unsigned QOpcodes0[] = { ARM::VST4q8_UPD, - ARM::VST4q16_UPD, - ARM::VST4q32_UPD }; - unsigned QOpcodes1[] = { ARM::VST4q8odd_UPD, - ARM::VST4q16odd_UPD, - ARM::VST4q32odd_UPD }; + unsigned DOpcodes[] = { ARM::VST4d8Pseudo, ARM::VST4d16Pseudo, + ARM::VST4d32Pseudo, ARM::VST1d64QPseudo }; + unsigned QOpcodes0[] = { ARM::VST4q8Pseudo_UPD, + ARM::VST4q16Pseudo_UPD, + ARM::VST4q32Pseudo_UPD }; + unsigned QOpcodes1[] = { ARM::VST4q8oddPseudo_UPD, + ARM::VST4q16oddPseudo_UPD, + ARM::VST4q32oddPseudo_UPD }; return SelectVST(N, 4, DOpcodes, QOpcodes0, QOpcodes1); } diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 0091df7..ce4a2c9 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -55,7 +55,14 @@ STATISTIC(NumTailCalls, "Number of tail calls"); static cl::opt EnableARMTailCalls("arm-tail-calls", cl::Hidden, cl::desc("Generate tail calls (TEMPORARY OPTION)."), - cl::init(true)); + cl::init(false)); + +// This option should go away when Machine LICM is smart enough to hoist a +// reg-to-reg VDUP. +static cl::opt +EnableARMVDUPsplat("arm-vdup-splat", cl::Hidden, + cl::desc("Generate VDUP for integer constant splats (TEMPORARY OPTION)."), + cl::init(false)); static cl::opt EnableARMLongCalls("arm-long-calls", cl::Hidden, @@ -122,7 +129,10 @@ void ARMTargetLowering::addTypeForNEON(EVT VT, EVT PromotedLdStVT, setOperationAction(ISD::SHL, VT.getSimpleVT(), Custom); setOperationAction(ISD::SRA, VT.getSimpleVT(), Custom); setOperationAction(ISD::SRL, VT.getSimpleVT(), Custom); + setLoadExtAction(ISD::SEXTLOAD, VT.getSimpleVT(), Expand); + setLoadExtAction(ISD::ZEXTLOAD, VT.getSimpleVT(), Expand); } + setLoadExtAction(ISD::EXTLOAD, VT.getSimpleVT(), Expand); // Promote all bit-wise operations. if (VT.isInteger() && VT != PromotedBitwiseVT) { @@ -166,6 +176,7 @@ static TargetLoweringObjectFile *createTLOF(TargetMachine &TM) { ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) : TargetLowering(TM, createTLOF(TM)) { Subtarget = &TM.getSubtarget(); + RegInfo = TM.getRegisterInfo(); if (Subtarget->isTargetDarwin()) { // Uses VFP for Thumb libfuncs if available. @@ -264,7 +275,8 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) addRegisterClass(MVT::i32, ARM::GPRRegisterClass); if (!UseSoftFloat && Subtarget->hasVFP2() && !Subtarget->isThumb1Only()) { addRegisterClass(MVT::f32, ARM::SPRRegisterClass); - addRegisterClass(MVT::f64, ARM::DPRRegisterClass); + if (!Subtarget->isFPOnlySP()) + addRegisterClass(MVT::f64, ARM::DPRRegisterClass); setTruncStoreAction(MVT::f64, MVT::f32, Expand); } @@ -310,9 +322,14 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) setOperationAction(ISD::FNEARBYINT, MVT::v2f64, Expand); setOperationAction(ISD::FFLOOR, MVT::v2f64, Expand); + setTruncStoreAction(MVT::v2f64, MVT::v2f32, Expand); + // Neon does not support some operations on v1i64 and v2i64 types. setOperationAction(ISD::MUL, MVT::v1i64, Expand); - setOperationAction(ISD::MUL, MVT::v2i64, Expand); + // Custom handling for some quad-vector types to detect VMULL. + setOperationAction(ISD::MUL, MVT::v8i16, Custom); + setOperationAction(ISD::MUL, MVT::v4i32, Custom); + setOperationAction(ISD::MUL, MVT::v2i64, Custom); setOperationAction(ISD::VSETCC, MVT::v1i64, Expand); setOperationAction(ISD::VSETCC, MVT::v2i64, Expand); @@ -410,12 +427,10 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) // doesn't yet know how to not do that for SjLj. setExceptionSelectorRegister(ARM::R0); setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); - // Handle atomics directly for ARMv[67] (except for Thumb1), otherwise - // use the default expansion. - bool canHandleAtomics = - (Subtarget->hasV7Ops() || - (Subtarget->hasV6Ops() && !Subtarget->isThumb1Only())); - if (canHandleAtomics) { + // ARMv6 Thumb1 (except for CPUs that support dmb / dsb) and earlier use + // the default expansion. + if (Subtarget->hasDataBarrier() || + (Subtarget->hasV6Ops() && !Subtarget->isThumb1Only())) { // membarrier needs custom lowering; the rest are legal and handled // normally. setOperationAction(ISD::MEMBARRIER, MVT::Other, Custom); @@ -466,10 +481,12 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) } setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); - if (!UseSoftFloat && Subtarget->hasVFP2() && !Subtarget->isThumb1Only()) + if (!UseSoftFloat && Subtarget->hasVFP2() && !Subtarget->isThumb1Only()) { // Turn f64->i64 into VMOVRRD, i64 -> f64 to VMOVDRR // iff target supports vfp2. setOperationAction(ISD::BIT_CONVERT, MVT::i64, Custom); + setOperationAction(ISD::FLT_ROUNDS_, MVT::i32, Custom); + } // We want to custom lower some of our intrinsics. setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); @@ -481,9 +498,9 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) setOperationAction(ISD::SETCC, MVT::i32, Expand); setOperationAction(ISD::SETCC, MVT::f32, Expand); setOperationAction(ISD::SETCC, MVT::f64, Expand); - setOperationAction(ISD::SELECT, MVT::i32, Expand); - setOperationAction(ISD::SELECT, MVT::f32, Expand); - setOperationAction(ISD::SELECT, MVT::f64, Expand); + setOperationAction(ISD::SELECT, MVT::i32, Custom); + setOperationAction(ISD::SELECT, MVT::f32, Custom); + setOperationAction(ISD::SELECT, MVT::f64, Custom); setOperationAction(ISD::SELECT_CC, MVT::i32, Custom); setOperationAction(ISD::SELECT_CC, MVT::f32, Custom); setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); @@ -530,6 +547,9 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) setTargetDAGCombine(ISD::SUB); setTargetDAGCombine(ISD::MUL); + if (Subtarget->hasV6T2Ops()) + setTargetDAGCombine(ISD::OR); + setStackPointerRegisterToSaveRestore(ARM::SP); if (UseSoftFloat || Subtarget->isThumb1Only() || !Subtarget->hasVFP2()) @@ -547,6 +567,37 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) benefitFromCodePlacementOpt = true; } +std::pair +ARMTargetLowering::findRepresentativeClass(EVT VT) const{ + const TargetRegisterClass *RRC = 0; + uint8_t Cost = 1; + switch (VT.getSimpleVT().SimpleTy) { + default: + return TargetLowering::findRepresentativeClass(VT); + // Use DPR as representative register class for all floating point + // and vector types. Since there are 32 SPR registers and 32 DPR registers so + // the cost is 1 for both f32 and f64. + case MVT::f32: case MVT::f64: case MVT::v8i8: case MVT::v4i16: + case MVT::v2i32: case MVT::v1i64: case MVT::v2f32: + RRC = ARM::DPRRegisterClass; + break; + case MVT::v16i8: case MVT::v8i16: case MVT::v4i32: case MVT::v2i64: + case MVT::v4f32: case MVT::v2f64: + RRC = ARM::DPRRegisterClass; + Cost = 2; + break; + case MVT::v4i64: + RRC = ARM::DPRRegisterClass; + Cost = 4; + break; + case MVT::v8i64: + RRC = ARM::DPRRegisterClass; + Cost = 8; + break; + } + return std::make_pair(RRC, Cost); +} + const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { switch (Opcode) { default: return 0; @@ -561,6 +612,7 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { case ARMISD::BR2_JT: return "ARMISD::BR2_JT"; case ARMISD::RET_FLAG: return "ARMISD::RET_FLAG"; case ARMISD::PIC_ADD: return "ARMISD::PIC_ADD"; + case ARMISD::AND: return "ARMISD::AND"; case ARMISD::CMP: return "ARMISD::CMP"; case ARMISD::CMPZ: return "ARMISD::CMPZ"; case ARMISD::CMPFP: return "ARMISD::CMPFP"; @@ -635,9 +687,12 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { case ARMISD::VZIP: return "ARMISD::VZIP"; case ARMISD::VUZP: return "ARMISD::VUZP"; case ARMISD::VTRN: return "ARMISD::VTRN"; + case ARMISD::VMULLs: return "ARMISD::VMULLs"; + case ARMISD::VMULLu: return "ARMISD::VMULLu"; case ARMISD::BUILD_VECTOR: return "ARMISD::BUILD_VECTOR"; case ARMISD::FMAX: return "ARMISD::FMAX"; case ARMISD::FMIN: return "ARMISD::FMIN"; + case ARMISD::BFI: return "ARMISD::BFI"; } } @@ -656,11 +711,23 @@ TargetRegisterClass *ARMTargetLowering::getRegClassFor(EVT VT) const { return TargetLowering::getRegClassFor(VT); } +// Create a fast isel object. +FastISel * +ARMTargetLowering::createFastISel(FunctionLoweringInfo &funcInfo) const { + return ARM::createFastISel(funcInfo); +} + /// getFunctionAlignment - Return the Log2 alignment of this function. unsigned ARMTargetLowering::getFunctionAlignment(const Function *F) const { return getTargetMachine().getSubtarget().isThumb() ? 1 : 2; } +/// getMaximalGlobalOffset - Returns the maximal possible offset which can +/// be used for loads / stores from the global. +unsigned ARMTargetLowering::getMaximalGlobalOffset() const { + return (Subtarget->isThumb1Only() ? 127 : 4095); +} + Sched::Preference ARMTargetLowering::getSchedulingPreference(SDNode *N) const { unsigned NumVals = N->getNumValues(); if (!NumVals) @@ -688,6 +755,24 @@ Sched::Preference ARMTargetLowering::getSchedulingPreference(SDNode *N) const { return Sched::RegPressure; } +unsigned +ARMTargetLowering::getRegPressureLimit(const TargetRegisterClass *RC, + MachineFunction &MF) const { + switch (RC->getID()) { + default: + return 0; + case ARM::tGPRRegClassID: + return RegInfo->hasFP(MF) ? 4 : 5; + case ARM::GPRRegClassID: { + unsigned FP = RegInfo->hasFP(MF) ? 1 : 0; + return 10 - FP - (Subtarget->isR9Reserved() ? 1 : 0); + } + case ARM::SPRRegClassID: // Currently not used as 'rep' register class. + case ARM::DPRRegClassID: + return 32 - 10; + } +} + //===----------------------------------------------------------------------===// // Lowering Code //===----------------------------------------------------------------------===// @@ -793,8 +878,9 @@ static bool f64AssignAAPCS(unsigned &ValNo, EVT &ValVT, EVT &LocVT, CCState &State, bool CanFail) { static const unsigned HiRegList[] = { ARM::R0, ARM::R2 }; static const unsigned LoRegList[] = { ARM::R1, ARM::R3 }; + static const unsigned ShadowRegList[] = { ARM::R0, ARM::R1 }; - unsigned Reg = State.AllocateReg(HiRegList, LoRegList, 2); + unsigned Reg = State.AllocateReg(HiRegList, ShadowRegList, 2); if (Reg == 0) { // For the 2nd half of a v2f64, do not just fail. if (CanFail) @@ -812,6 +898,10 @@ static bool f64AssignAAPCS(unsigned &ValNo, EVT &ValVT, EVT &LocVT, if (HiRegList[i] == Reg) break; + unsigned T = State.AllocateReg(LoRegList[i]); + (void)T; + assert(T == LoRegList[i] && "Could not allocate register"); + State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i], LocVT, LocInfo)); @@ -1624,6 +1714,10 @@ static SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) { return DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Res); } +unsigned ARMTargetLowering::getJumpTableEncoding() const { + return MachineJumpTableInfo::EK_Inline; +} + SDValue ARMTargetLowering::LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); @@ -1917,17 +2011,19 @@ static SDValue LowerMEMBARRIER(SDValue Op, SelectionDAG &DAG, DebugLoc dl = Op.getDebugLoc(); SDValue Op5 = Op.getOperand(5); unsigned isDeviceBarrier = cast(Op5)->getZExtValue(); - // v6 and v7 can both handle barriers directly, but need handled a bit - // differently. Thumb1 and pre-v6 ARM mode use a libcall instead and should + // Some subtargets which have dmb and dsb instructions can handle barriers + // directly. Some ARMv6 cpus can support them with the help of mcr + // instruction. Thumb1 and pre-v6 ARM mode use a libcall instead and should // never get here. unsigned Opc = isDeviceBarrier ? ARMISD::SYNCBARRIER : ARMISD::MEMBARRIER; - if (Subtarget->hasV7Ops()) + if (Subtarget->hasDataBarrier()) return DAG.getNode(Opc, dl, MVT::Other, Op.getOperand(0)); - else if (Subtarget->hasV6Ops() && !Subtarget->isThumb1Only()) + else { + assert(Subtarget->hasV6Ops() && !Subtarget->isThumb1Only() && + "Unexpected ISD::MEMBARRIER encountered. Should be libcall!"); return DAG.getNode(Opc, dl, MVT::Other, Op.getOperand(0), DAG.getConstant(0, MVT::i32)); - assert(0 && "Unexpected ISD::MEMBARRIER encountered. Should be libcall!"); - return SDValue(); + } } static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) { @@ -1945,54 +2041,6 @@ static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) { } SDValue -ARMTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, - SelectionDAG &DAG) const { - SDNode *Node = Op.getNode(); - DebugLoc dl = Node->getDebugLoc(); - EVT VT = Node->getValueType(0); - SDValue Chain = Op.getOperand(0); - SDValue Size = Op.getOperand(1); - SDValue Align = Op.getOperand(2); - - // Chain the dynamic stack allocation so that it doesn't modify the stack - // pointer when other instructions are using the stack. - Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(0, true)); - - unsigned AlignVal = cast(Align)->getZExtValue(); - unsigned StackAlign = getTargetMachine().getFrameInfo()->getStackAlignment(); - if (AlignVal > StackAlign) - // Do this now since selection pass cannot introduce new target - // independent node. - Align = DAG.getConstant(-(uint64_t)AlignVal, VT); - - // In Thumb1 mode, there isn't a "sub r, sp, r" instruction, we will end up - // using a "add r, sp, r" instead. Negate the size now so we don't have to - // do even more horrible hack later. - MachineFunction &MF = DAG.getMachineFunction(); - ARMFunctionInfo *AFI = MF.getInfo(); - if (AFI->isThumb1OnlyFunction()) { - bool Negate = true; - ConstantSDNode *C = dyn_cast(Size); - if (C) { - uint32_t Val = C->getZExtValue(); - if (Val <= 508 && ((Val & 3) == 0)) - Negate = false; - } - if (Negate) - Size = DAG.getNode(ISD::SUB, dl, VT, DAG.getConstant(0, VT), Size); - } - - SDVTList VTList = DAG.getVTList(VT, MVT::Other); - SDValue Ops1[] = { Chain, Size, Align }; - SDValue Res = DAG.getNode(ARMISD::DYN_ALLOC, dl, VTList, Ops1, 3); - Chain = Res.getValue(1); - Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(0, true), - DAG.getIntPtrConstant(0, true), SDValue()); - SDValue Ops2[] = { Res, Chain }; - return DAG.getMergeValues(Ops2, 2, dl); -} - -SDValue ARMTargetLowering::GetF64FormalArgument(CCValAssign &VA, CCValAssign &NextVA, SDValue &Root, SelectionDAG &DAG, DebugLoc dl) const { @@ -2229,28 +2277,28 @@ ARMTargetLowering::getARMCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC, default: break; case ISD::SETLT: case ISD::SETGE: - if (isLegalICmpImmediate(C-1)) { + if (C != 0x80000000 && isLegalICmpImmediate(C-1)) { CC = (CC == ISD::SETLT) ? ISD::SETLE : ISD::SETGT; RHS = DAG.getConstant(C-1, MVT::i32); } break; case ISD::SETULT: case ISD::SETUGE: - if (C > 0 && isLegalICmpImmediate(C-1)) { + if (C != 0 && isLegalICmpImmediate(C-1)) { CC = (CC == ISD::SETULT) ? ISD::SETULE : ISD::SETUGT; RHS = DAG.getConstant(C-1, MVT::i32); } break; case ISD::SETLE: case ISD::SETGT: - if (isLegalICmpImmediate(C+1)) { + if (C != 0x7fffffff && isLegalICmpImmediate(C+1)) { CC = (CC == ISD::SETLE) ? ISD::SETLT : ISD::SETGE; RHS = DAG.getConstant(C+1, MVT::i32); } break; case ISD::SETULE: case ISD::SETUGT: - if (C < 0xffffffff && isLegalICmpImmediate(C+1)) { + if (C != 0xffffffff && isLegalICmpImmediate(C+1)) { CC = (CC == ISD::SETULE) ? ISD::SETULT : ISD::SETUGE; RHS = DAG.getConstant(C+1, MVT::i32); } @@ -2287,6 +2335,52 @@ ARMTargetLowering::getVFPCmp(SDValue LHS, SDValue RHS, SelectionDAG &DAG, return DAG.getNode(ARMISD::FMSTAT, dl, MVT::Flag, Cmp); } +SDValue ARMTargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const { + SDValue Cond = Op.getOperand(0); + SDValue SelectTrue = Op.getOperand(1); + SDValue SelectFalse = Op.getOperand(2); + DebugLoc dl = Op.getDebugLoc(); + + // Convert: + // + // (select (cmov 1, 0, cond), t, f) -> (cmov t, f, cond) + // (select (cmov 0, 1, cond), t, f) -> (cmov f, t, cond) + // + if (Cond.getOpcode() == ARMISD::CMOV && Cond.hasOneUse()) { + const ConstantSDNode *CMOVTrue = + dyn_cast(Cond.getOperand(0)); + const ConstantSDNode *CMOVFalse = + dyn_cast(Cond.getOperand(1)); + + if (CMOVTrue && CMOVFalse) { + unsigned CMOVTrueVal = CMOVTrue->getZExtValue(); + unsigned CMOVFalseVal = CMOVFalse->getZExtValue(); + + SDValue True; + SDValue False; + if (CMOVTrueVal == 1 && CMOVFalseVal == 0) { + True = SelectTrue; + False = SelectFalse; + } else if (CMOVTrueVal == 0 && CMOVFalseVal == 1) { + True = SelectFalse; + False = SelectTrue; + } + + if (True.getNode() && False.getNode()) { + EVT VT = Cond.getValueType(); + SDValue ARMcc = Cond.getOperand(2); + SDValue CCR = Cond.getOperand(3); + SDValue Cmp = Cond.getOperand(4); + return DAG.getNode(ARMISD::CMOV, dl, VT, True, False, ARMcc, CCR, Cmp); + } + } + } + + return DAG.getSelectCC(dl, Cond, + DAG.getConstant(0, Cond.getValueType()), + SelectTrue, SelectFalse, ISD::SETNE); +} + SDValue ARMTargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const { EVT VT = Op.getValueType(); SDValue LHS = Op.getOperand(0); @@ -2403,8 +2497,9 @@ ARMTargetLowering::OptimizeVFPBrcond(SDValue Op, SelectionDAG &DAG) const { bool SeenZero = false; if (canChangeToInt(LHS, SeenZero, Subtarget) && canChangeToInt(RHS, SeenZero, Subtarget) && - // If one of the operand is zero, it's safe to ignore the NaN case. - (FiniteOnlyFPMath() || SeenZero)) { + // If one of the operand is zero, it's safe to ignore the NaN case since + // we only care about equality comparisons. + (SeenZero || (DAG.isKnownNeverNaN(LHS) && DAG.isKnownNeverNaN(RHS)))) { // If unsafe fp math optimization is enabled and there are no othter uses of // the CMP operands, and the condition code is EQ oe NE, we can optimize it // to an integer comparison. @@ -2587,7 +2682,7 @@ SDValue ARMTargetLowering::LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const{ } // Return LR, which contains the return address. Mark it an implicit live-in. - unsigned Reg = MF.addLiveIn(ARM::LR, ARM::GPRRegisterClass); + unsigned Reg = MF.addLiveIn(ARM::LR, getRegClassFor(MVT::i32)); return DAG.getCopyFromReg(DAG.getEntryNode(), dl, Reg, VT); } @@ -2730,6 +2825,24 @@ SDValue ARMTargetLowering::LowerShiftLeftParts(SDValue Op, return DAG.getMergeValues(Ops, 2, dl); } +SDValue ARMTargetLowering::LowerFLT_ROUNDS_(SDValue Op, + SelectionDAG &DAG) const { + // The rounding mode is in bits 23:22 of the FPSCR. + // The ARM rounding mode value to FLT_ROUNDS mapping is 0->1, 1->2, 2->3, 3->0 + // The formula we use to implement this is (((FPSCR + 1 << 22) >> 22) & 3) + // so that the shift + and get folded into a bitfield extract. + DebugLoc dl = Op.getDebugLoc(); + SDValue FPSCR = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::i32, + DAG.getConstant(Intrinsic::arm_get_fpscr, + MVT::i32)); + SDValue FltRounds = DAG.getNode(ISD::ADD, dl, MVT::i32, FPSCR, + DAG.getConstant(1U << 22, MVT::i32)); + SDValue RMODE = DAG.getNode(ISD::SRL, dl, MVT::i32, FltRounds, + DAG.getConstant(22, MVT::i32)); + return DAG.getNode(ISD::AND, dl, MVT::i32, RMODE, + DAG.getConstant(3, MVT::i32)); +} + static SDValue LowerCTTZ(SDNode *N, SelectionDAG &DAG, const ARMSubtarget *ST) { EVT VT = N->getValueType(0); @@ -3046,6 +3159,11 @@ static bool isVEXTMask(const SmallVectorImpl &M, EVT VT, bool &ReverseVEXT, unsigned &Imm) { unsigned NumElts = VT.getVectorNumElements(); ReverseVEXT = false; + + // Assume that the first shuffle index is not UNDEF. Fail if it is. + if (M[0] < 0) + return false; + Imm = M[0]; // If this is a VEXT shuffle, the immediate value is the index of the first @@ -3061,6 +3179,7 @@ static bool isVEXTMask(const SmallVectorImpl &M, EVT VT, ReverseVEXT = true; } + if (M[i] < 0) continue; // ignore UNDEF indices if (ExpectedElt != static_cast(M[i])) return false; } @@ -3086,13 +3205,16 @@ static bool isVREVMask(const SmallVectorImpl &M, EVT VT, unsigned NumElts = VT.getVectorNumElements(); unsigned BlockElts = M[0] + 1; + // If the first shuffle index is UNDEF, be optimistic. + if (M[0] < 0) + BlockElts = BlockSize / EltSz; if (BlockSize <= EltSz || BlockSize != BlockElts * EltSz) return false; for (unsigned i = 0; i < NumElts; ++i) { - if ((unsigned) M[i] != - (i - i%BlockElts) + (BlockElts - 1 - i%BlockElts)) + if (M[i] < 0) continue; // ignore UNDEF indices + if ((unsigned) M[i] != (i - i%BlockElts) + (BlockElts - 1 - i%BlockElts)) return false; } @@ -3108,8 +3230,8 @@ static bool isVTRNMask(const SmallVectorImpl &M, EVT VT, unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); for (unsigned i = 0; i < NumElts; i += 2) { - if ((unsigned) M[i] != i + WhichResult || - (unsigned) M[i+1] != i + NumElts + WhichResult) + if ((M[i] >= 0 && (unsigned) M[i] != i + WhichResult) || + (M[i+1] >= 0 && (unsigned) M[i+1] != i + NumElts + WhichResult)) return false; } return true; @@ -3127,8 +3249,8 @@ static bool isVTRN_v_undef_Mask(const SmallVectorImpl &M, EVT VT, unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); for (unsigned i = 0; i < NumElts; i += 2) { - if ((unsigned) M[i] != i + WhichResult || - (unsigned) M[i+1] != i + WhichResult) + if ((M[i] >= 0 && (unsigned) M[i] != i + WhichResult) || + (M[i+1] >= 0 && (unsigned) M[i+1] != i + WhichResult)) return false; } return true; @@ -3143,6 +3265,7 @@ static bool isVUZPMask(const SmallVectorImpl &M, EVT VT, unsigned NumElts = VT.getVectorNumElements(); WhichResult = (M[0] == 0 ? 0 : 1); for (unsigned i = 0; i != NumElts; ++i) { + if (M[i] < 0) continue; // ignore UNDEF indices if ((unsigned) M[i] != 2 * i + WhichResult) return false; } @@ -3168,7 +3291,8 @@ static bool isVUZP_v_undef_Mask(const SmallVectorImpl &M, EVT VT, for (unsigned j = 0; j != 2; ++j) { unsigned Idx = WhichResult; for (unsigned i = 0; i != Half; ++i) { - if ((unsigned) M[i + j * Half] != Idx) + int MIdx = M[i + j * Half]; + if (MIdx >= 0 && (unsigned) MIdx != Idx) return false; Idx += 2; } @@ -3191,8 +3315,8 @@ static bool isVZIPMask(const SmallVectorImpl &M, EVT VT, WhichResult = (M[0] == 0 ? 0 : 1); unsigned Idx = WhichResult * NumElts / 2; for (unsigned i = 0; i != NumElts; i += 2) { - if ((unsigned) M[i] != Idx || - (unsigned) M[i+1] != Idx + NumElts) + if ((M[i] >= 0 && (unsigned) M[i] != Idx) || + (M[i+1] >= 0 && (unsigned) M[i+1] != Idx + NumElts)) return false; Idx += 1; } @@ -3217,8 +3341,8 @@ static bool isVZIP_v_undef_Mask(const SmallVectorImpl &M, EVT VT, WhichResult = (M[0] == 0 ? 0 : 1); unsigned Idx = WhichResult * NumElts / 2; for (unsigned i = 0; i != NumElts; i += 2) { - if ((unsigned) M[i] != Idx || - (unsigned) M[i+1] != Idx) + if ((M[i] >= 0 && (unsigned) M[i] != Idx) || + (M[i+1] >= 0 && (unsigned) M[i+1] != Idx)) return false; Idx += 1; } @@ -3230,9 +3354,30 @@ static bool isVZIP_v_undef_Mask(const SmallVectorImpl &M, EVT VT, return true; } +// If N is an integer constant that can be moved into a register in one +// instruction, return an SDValue of such a constant (will become a MOV +// instruction). Otherwise return null. +static SDValue IsSingleInstrConstant(SDValue N, SelectionDAG &DAG, + const ARMSubtarget *ST, DebugLoc dl) { + uint64_t Val; + if (!isa(N)) + return SDValue(); + Val = cast(N)->getZExtValue(); + + if (ST->isThumb1Only()) { + if (Val <= 255 || ~Val <= 255) + return DAG.getConstant(Val, MVT::i32); + } else { + if (ARM_AM::getSOImmVal(Val) != -1 || ARM_AM::getSOImmVal(~Val) != -1) + return DAG.getConstant(Val, MVT::i32); + } + return SDValue(); +} + // If this is a case we can't handle, return null and let the default // expansion code take care of it. -static SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) { +static SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, + const ARMSubtarget *ST) { BuildVectorSDNode *BVN = cast(Op.getNode()); DebugLoc dl = Op.getDebugLoc(); EVT VT = Op.getValueType(); @@ -3292,15 +3437,41 @@ static SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) { if (isOnlyLowElement) return DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Value); - // If all elements are constants, fall back to the default expansion, which - // will generate a load from the constant pool. + unsigned EltSize = VT.getVectorElementType().getSizeInBits(); + + if (EnableARMVDUPsplat) { + // Use VDUP for non-constant splats. For f32 constant splats, reduce to + // i32 and try again. + if (usesOnlyOneValue && EltSize <= 32) { + if (!isConstant) + return DAG.getNode(ARMISD::VDUP, dl, VT, Value); + if (VT.getVectorElementType().isFloatingPoint()) { + SmallVector Ops; + for (unsigned i = 0; i < NumElts; ++i) + Ops.push_back(DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, + Op.getOperand(i))); + SDValue Val = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v4i32, &Ops[0], + NumElts); + return DAG.getNode(ISD::BIT_CONVERT, dl, VT, + LowerBUILD_VECTOR(Val, DAG, ST)); + } + SDValue Val = IsSingleInstrConstant(Value, DAG, ST, dl); + if (Val.getNode()) + return DAG.getNode(ARMISD::VDUP, dl, VT, Val); + } + } + + // If all elements are constants and the case above didn't get hit, fall back + // to the default expansion, which will generate a load from the constant + // pool. if (isConstant) return SDValue(); - // Use VDUP for non-constant splats. - unsigned EltSize = VT.getVectorElementType().getSizeInBits(); - if (usesOnlyOneValue && EltSize <= 32) - return DAG.getNode(ARMISD::VDUP, dl, VT, Value); + if (!EnableARMVDUPsplat) { + // Use VDUP for non-constant splats. + if (usesOnlyOneValue && EltSize <= 32) + return DAG.getNode(ARMISD::VDUP, dl, VT, Value); + } // Vectors with 32- or 64-bit elements can be built by directly assigning // the subregisters. Lower it to an ARMISD::BUILD_VECTOR so the operands @@ -3585,6 +3756,51 @@ static SDValue LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) { return DAG.getNode(ISD::BIT_CONVERT, dl, Op.getValueType(), Val); } +/// SkipExtension - For a node that is either a SIGN_EXTEND, ZERO_EXTEND, or +/// an extending load, return the unextended value. +static SDValue SkipExtension(SDNode *N, SelectionDAG &DAG) { + if (N->getOpcode() == ISD::SIGN_EXTEND || N->getOpcode() == ISD::ZERO_EXTEND) + return N->getOperand(0); + LoadSDNode *LD = cast(N); + return DAG.getLoad(LD->getMemoryVT(), N->getDebugLoc(), LD->getChain(), + LD->getBasePtr(), LD->getSrcValue(), + LD->getSrcValueOffset(), LD->isVolatile(), + LD->isNonTemporal(), LD->getAlignment()); +} + +static SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) { + // Multiplications are only custom-lowered for 128-bit vectors so that + // VMULL can be detected. Otherwise v2i64 multiplications are not legal. + EVT VT = Op.getValueType(); + assert(VT.is128BitVector() && "unexpected type for custom-lowering ISD::MUL"); + SDNode *N0 = Op.getOperand(0).getNode(); + SDNode *N1 = Op.getOperand(1).getNode(); + unsigned NewOpc = 0; + if ((N0->getOpcode() == ISD::SIGN_EXTEND || ISD::isSEXTLoad(N0)) && + (N1->getOpcode() == ISD::SIGN_EXTEND || ISD::isSEXTLoad(N1))) { + NewOpc = ARMISD::VMULLs; + } else if ((N0->getOpcode() == ISD::ZERO_EXTEND || ISD::isZEXTLoad(N0)) && + (N1->getOpcode() == ISD::ZERO_EXTEND || ISD::isZEXTLoad(N1))) { + NewOpc = ARMISD::VMULLu; + } else if (VT.getSimpleVT().SimpleTy == MVT::v2i64) { + // Fall through to expand this. It is not legal. + return SDValue(); + } else { + // Other vector multiplications are legal. + return Op; + } + + // Legalize to a VMULL instruction. + DebugLoc DL = Op.getDebugLoc(); + SDValue Op0 = SkipExtension(N0, DAG); + SDValue Op1 = SkipExtension(N1, DAG); + + assert(Op0.getValueType().is64BitVector() && + Op1.getValueType().is64BitVector() && + "unexpected types for extended operands to VMULL"); + return DAG.getNode(NewOpc, DL, VT, Op0, Op1); +} + SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { default: llvm_unreachable("Don't know how to custom lower this!"); @@ -3594,10 +3810,10 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { return Subtarget->isTargetDarwin() ? LowerGlobalAddressDarwin(Op, DAG) : LowerGlobalAddressELF(Op, DAG); case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); + case ISD::SELECT: return LowerSELECT(Op, DAG); case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); case ISD::BR_CC: return LowerBR_CC(Op, DAG); case ISD::BR_JT: return LowerBR_JT(Op, DAG); - case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG); case ISD::VASTART: return LowerVASTART(Op, DAG); case ISD::MEMBARRIER: return LowerMEMBARRIER(Op, DAG, Subtarget); case ISD::SINT_TO_FP: @@ -3621,10 +3837,12 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::SRA_PARTS: return LowerShiftRightParts(Op, DAG); case ISD::CTTZ: return LowerCTTZ(Op.getNode(), DAG, Subtarget); case ISD::VSETCC: return LowerVSETCC(Op, DAG); - case ISD::BUILD_VECTOR: return LowerBUILD_VECTOR(Op, DAG); + case ISD::BUILD_VECTOR: return LowerBUILD_VECTOR(Op, DAG, Subtarget); case ISD::VECTOR_SHUFFLE: return LowerVECTOR_SHUFFLE(Op, DAG); case ISD::EXTRACT_VECTOR_ELT: return LowerEXTRACT_VECTOR_ELT(Op, DAG); case ISD::CONCAT_VECTORS: return LowerCONCAT_VECTORS(Op, DAG); + case ISD::FLT_ROUNDS_: return LowerFLT_ROUNDS_(Op, DAG); + case ISD::MUL: return LowerMUL(Op, DAG); } return SDValue(); } @@ -4002,78 +4220,6 @@ ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, MI->eraseFromParent(); // The pseudo instruction is gone now. return BB; } - - case ARM::tANDsp: - case ARM::tADDspr_: - case ARM::tSUBspi_: - case ARM::t2SUBrSPi_: - case ARM::t2SUBrSPi12_: - case ARM::t2SUBrSPs_: { - MachineFunction *MF = BB->getParent(); - unsigned DstReg = MI->getOperand(0).getReg(); - unsigned SrcReg = MI->getOperand(1).getReg(); - bool DstIsDead = MI->getOperand(0).isDead(); - bool SrcIsKill = MI->getOperand(1).isKill(); - - if (SrcReg != ARM::SP) { - // Copy the source to SP from virtual register. - const TargetRegisterClass *RC = MF->getRegInfo().getRegClass(SrcReg); - unsigned CopyOpc = (RC == ARM::tGPRRegisterClass) - ? ARM::tMOVtgpr2gpr : ARM::tMOVgpr2gpr; - BuildMI(*BB, MI, dl, TII->get(CopyOpc), ARM::SP) - .addReg(SrcReg, getKillRegState(SrcIsKill)); - } - - unsigned OpOpc = 0; - bool NeedPred = false, NeedCC = false, NeedOp3 = false; - switch (MI->getOpcode()) { - default: - llvm_unreachable("Unexpected pseudo instruction!"); - case ARM::tANDsp: - OpOpc = ARM::tAND; - NeedPred = true; - break; - case ARM::tADDspr_: - OpOpc = ARM::tADDspr; - break; - case ARM::tSUBspi_: - OpOpc = ARM::tSUBspi; - break; - case ARM::t2SUBrSPi_: - OpOpc = ARM::t2SUBrSPi; - NeedPred = true; NeedCC = true; - break; - case ARM::t2SUBrSPi12_: - OpOpc = ARM::t2SUBrSPi12; - NeedPred = true; - break; - case ARM::t2SUBrSPs_: - OpOpc = ARM::t2SUBrSPs; - NeedPred = true; NeedCC = true; NeedOp3 = true; - break; - } - MachineInstrBuilder MIB = BuildMI(*BB, MI, dl, TII->get(OpOpc), ARM::SP); - if (OpOpc == ARM::tAND) - AddDefaultT1CC(MIB); - MIB.addReg(ARM::SP); - MIB.addOperand(MI->getOperand(2)); - if (NeedOp3) - MIB.addOperand(MI->getOperand(3)); - if (NeedPred) - AddDefaultPred(MIB); - if (NeedCC) - AddDefaultCC(MIB); - - // Copy the result from SP to virtual register. - const TargetRegisterClass *RC = MF->getRegInfo().getRegClass(DstReg); - unsigned CopyOpc = (RC == ARM::tGPRRegisterClass) - ? ARM::tMOVgpr2tgpr : ARM::tMOVgpr2gpr; - BuildMI(*BB, MI, dl, TII->get(CopyOpc)) - .addReg(DstReg, getDefRegState(true) | getDeadRegState(DstIsDead)) - .addReg(ARM::SP); - MI->eraseFromParent(); // The pseudo instruction is gone now. - return BB; - } } } @@ -4141,30 +4287,42 @@ SDValue combineSelectAndUse(SDNode *N, SDValue Slct, SDValue OtherOp, return SDValue(); } -/// PerformADDCombine - Target-specific dag combine xforms for ISD::ADD. -static SDValue PerformADDCombine(SDNode *N, - TargetLowering::DAGCombinerInfo &DCI) { - // added by evan in r37685 with no testcase. - SDValue N0 = N->getOperand(0), N1 = N->getOperand(1); - +/// PerformADDCombineWithOperands - Try DAG combinations for an ADD with +/// operands N0 and N1. This is a helper for PerformADDCombine that is +/// called with the default operands, and if that fails, with commuted +/// operands. +static SDValue PerformADDCombineWithOperands(SDNode *N, SDValue N0, SDValue N1, + TargetLowering::DAGCombinerInfo &DCI) { // fold (add (select cc, 0, c), x) -> (select cc, x, (add, x, c)) if (N0.getOpcode() == ISD::SELECT && N0.getNode()->hasOneUse()) { SDValue Result = combineSelectAndUse(N, N0, N1, DCI); if (Result.getNode()) return Result; } - if (N1.getOpcode() == ISD::SELECT && N1.getNode()->hasOneUse()) { - SDValue Result = combineSelectAndUse(N, N1, N0, DCI); - if (Result.getNode()) return Result; - } - return SDValue(); } +/// PerformADDCombine - Target-specific dag combine xforms for ISD::ADD. +/// +static SDValue PerformADDCombine(SDNode *N, + TargetLowering::DAGCombinerInfo &DCI) { + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + + // First try with the default operand order. + SDValue Result = PerformADDCombineWithOperands(N, N0, N1, DCI); + if (Result.getNode()) + return Result; + + // If that didn't work, try again with the operands commuted. + return PerformADDCombineWithOperands(N, N1, N0, DCI); +} + /// PerformSUBCombine - Target-specific dag combine xforms for ISD::SUB. +/// static SDValue PerformSUBCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { - // added by evan in r37685 with no testcase. - SDValue N0 = N->getOperand(0), N1 = N->getOperand(1); + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); // fold (sub x, (select cc, 0, c)) -> (select cc, x, (sub, x, c)) if (N1.getOpcode() == ISD::SELECT && N1.getNode()->hasOneUse()) { @@ -4231,6 +4389,105 @@ static SDValue PerformMULCombine(SDNode *N, return SDValue(); } +/// PerformORCombine - Target-specific dag combine xforms for ISD::OR +static SDValue PerformORCombine(SDNode *N, + TargetLowering::DAGCombinerInfo &DCI, + const ARMSubtarget *Subtarget) { + // Try to use the ARM/Thumb2 BFI (bitfield insert) instruction when + // reasonable. + + // BFI is only available on V6T2+ + if (Subtarget->isThumb1Only() || !Subtarget->hasV6T2Ops()) + return SDValue(); + + SelectionDAG &DAG = DCI.DAG; + SDValue N0 = N->getOperand(0), N1 = N->getOperand(1); + DebugLoc DL = N->getDebugLoc(); + // 1) or (and A, mask), val => ARMbfi A, val, mask + // iff (val & mask) == val + // + // 2) or (and A, mask), (and B, mask2) => ARMbfi A, (lsr B, amt), mask + // 2a) iff isBitFieldInvertedMask(mask) && isBitFieldInvertedMask(~mask2) + // && CountPopulation_32(mask) == CountPopulation_32(~mask2) + // 2b) iff isBitFieldInvertedMask(~mask) && isBitFieldInvertedMask(mask2) + // && CountPopulation_32(mask) == CountPopulation_32(~mask2) + // (i.e., copy a bitfield value into another bitfield of the same width) + if (N0.getOpcode() != ISD::AND) + return SDValue(); + + EVT VT = N->getValueType(0); + if (VT != MVT::i32) + return SDValue(); + + + // The value and the mask need to be constants so we can verify this is + // actually a bitfield set. If the mask is 0xffff, we can do better + // via a movt instruction, so don't use BFI in that case. + ConstantSDNode *C = dyn_cast(N0.getOperand(1)); + if (!C) + return SDValue(); + unsigned Mask = C->getZExtValue(); + if (Mask == 0xffff) + return SDValue(); + SDValue Res; + // Case (1): or (and A, mask), val => ARMbfi A, val, mask + if ((C = dyn_cast(N1))) { + unsigned Val = C->getZExtValue(); + if (!ARM::isBitFieldInvertedMask(Mask) || (Val & ~Mask) != Val) + return SDValue(); + Val >>= CountTrailingZeros_32(~Mask); + + Res = DAG.getNode(ARMISD::BFI, DL, VT, N0.getOperand(0), + DAG.getConstant(Val, MVT::i32), + DAG.getConstant(Mask, MVT::i32)); + + // Do not add new nodes to DAG combiner worklist. + DCI.CombineTo(N, Res, false); + } else if (N1.getOpcode() == ISD::AND) { + // case (2) or (and A, mask), (and B, mask2) => ARMbfi A, (lsr B, amt), mask + C = dyn_cast(N1.getOperand(1)); + if (!C) + return SDValue(); + unsigned Mask2 = C->getZExtValue(); + + if (ARM::isBitFieldInvertedMask(Mask) && + ARM::isBitFieldInvertedMask(~Mask2) && + (CountPopulation_32(Mask) == CountPopulation_32(~Mask2))) { + // The pack halfword instruction works better for masks that fit it, + // so use that when it's available. + if (Subtarget->hasT2ExtractPack() && + (Mask == 0xffff || Mask == 0xffff0000)) + return SDValue(); + // 2a + unsigned lsb = CountTrailingZeros_32(Mask2); + Res = DAG.getNode(ISD::SRL, DL, VT, N1.getOperand(0), + DAG.getConstant(lsb, MVT::i32)); + Res = DAG.getNode(ARMISD::BFI, DL, VT, N0.getOperand(0), Res, + DAG.getConstant(Mask, MVT::i32)); + // Do not add new nodes to DAG combiner worklist. + DCI.CombineTo(N, Res, false); + } else if (ARM::isBitFieldInvertedMask(~Mask) && + ARM::isBitFieldInvertedMask(Mask2) && + (CountPopulation_32(~Mask) == CountPopulation_32(Mask2))) { + // The pack halfword instruction works better for masks that fit it, + // so use that when it's available. + if (Subtarget->hasT2ExtractPack() && + (Mask2 == 0xffff || Mask2 == 0xffff0000)) + return SDValue(); + // 2b + unsigned lsb = CountTrailingZeros_32(Mask); + Res = DAG.getNode(ISD::SRL, DL, VT, N0.getOperand(0), + DAG.getConstant(lsb, MVT::i32)); + Res = DAG.getNode(ARMISD::BFI, DL, VT, N1.getOperand(0), Res, + DAG.getConstant(Mask2, MVT::i32)); + // Do not add new nodes to DAG combiner worklist. + DCI.CombineTo(N, Res, false); + } + } + + return SDValue(); +} + /// PerformVMOVRRDCombine - Target-specific dag combine xforms for /// ARMISD::VMOVRRD. static SDValue PerformVMOVRRDCombine(SDNode *N, @@ -4561,7 +4818,7 @@ static SDValue PerformExtendCombine(SDNode *N, SelectionDAG &DAG, static SDValue PerformSELECT_CCCombine(SDNode *N, SelectionDAG &DAG, const ARMSubtarget *ST) { // If the target supports NEON, try to use vmax/vmin instructions for f32 - // selects like "x < y ? x : y". Unless the FiniteOnlyFPMath option is set, + // selects like "x < y ? x : y". Unless the NoNaNsFPMath option is set, // be careful about NaNs: NEON's vmax/vmin return NaN if either operand is // a NaN; only do the transformation when it matches that behavior. @@ -4648,6 +4905,7 @@ SDValue ARMTargetLowering::PerformDAGCombine(SDNode *N, case ISD::ADD: return PerformADDCombine(N, DCI); case ISD::SUB: return PerformSUBCombine(N, DCI); case ISD::MUL: return PerformMULCombine(N, DCI, Subtarget); + case ISD::OR: return PerformORCombine(N, DCI, Subtarget); case ARMISD::VMOVRRD: return PerformVMOVRRDCombine(N, DCI); case ARMISD::VDUPLANE: return PerformVDUPLANECombine(N, DCI); case ISD::INTRINSIC_WO_CHAIN: return PerformIntrinsicCombine(N, DCI.DAG); @@ -5379,6 +5637,21 @@ int ARM::getVFPf64Imm(const APFloat &FPImm) { return ((int)Sign << 7) | (Exp << 4) | Mantissa; } +bool ARM::isBitFieldInvertedMask(unsigned v) { + if (v == 0xffffffff) + return 0; + // there can be 1's on either or both "outsides", all the "inside" + // bits must be 0's + unsigned int lsb = 0, msb = 31; + while (v & (1 << msb)) --msb; + while (v & (1 << lsb)) ++lsb; + for (unsigned int i = lsb; i <= msb; ++i) { + if (v & (1 << i)) + return 0; + } + return 1; +} + /// isFPImmLegal - Returns true if the target can instruction select the /// specified FP immediate natively. If false, the legalizer will /// materialize the FP immediate as a load from a constant pool. diff --git a/lib/Target/ARM/ARMISelLowering.h b/lib/Target/ARM/ARMISelLowering.h index 128b72e..ba9ea7f 100644 --- a/lib/Target/ARM/ARMISelLowering.h +++ b/lib/Target/ARM/ARMISelLowering.h @@ -17,6 +17,8 @@ #include "ARMSubtarget.h" #include "llvm/Target/TargetLowering.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/CodeGen/FastISel.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/CallingConvLower.h" #include @@ -45,6 +47,8 @@ namespace llvm { PIC_ADD, // Add with a PC operand and a PIC label. + AND, // ARM "and" instruction that sets the 's' flag in CPSR. + CMP, // ARM compare instructions. CMPZ, // ARM compare that sets only Z flag. CMPFP, // ARM VFP compare instruction, sets FPSCR. @@ -80,7 +84,7 @@ namespace llvm { MEMBARRIER, // Memory barrier SYNCBARRIER, // Memory sync barrier - + VCEQ, // Vector compare equal. VCGE, // Vector compare greater than or equal. VCGEU, // Vector compare unsigned greater than or equal. @@ -141,6 +145,10 @@ namespace llvm { VUZP, // unzip (deinterleave) VTRN, // transpose + // Vector multiply long: + VMULLs, // ...signed + VMULLu, // ...unsigned + // Operands of the standard BUILD_VECTOR node are not legalized, which // is fine if BUILD_VECTORs are always lowered to shuffles or other // operations, but for ARM some BUILD_VECTORs are legal as-is and their @@ -150,7 +158,10 @@ namespace llvm { // Floating-point max and min: FMAX, - FMIN + FMIN, + + // Bit-field insert + BFI }; } @@ -162,6 +173,7 @@ namespace llvm { /// returns -1. int getVFPf32Imm(const APFloat &FPImm); int getVFPf64Imm(const APFloat &FPImm); + bool isBitFieldInvertedMask(unsigned v); } //===--------------------------------------------------------------------===// @@ -171,6 +183,8 @@ namespace llvm { public: explicit ARMTargetLowering(TargetMachine &TM); + virtual unsigned getJumpTableEncoding(void) const; + virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const; /// ReplaceNodeResults - Replace the results of node with an illegal result @@ -255,8 +269,19 @@ namespace llvm { /// getFunctionAlignment - Return the Log2 alignment of this function. virtual unsigned getFunctionAlignment(const Function *F) const; + /// getMaximalGlobalOffset - Returns the maximal possible offset which can + /// be used for loads / stores from the global. + virtual unsigned getMaximalGlobalOffset() const; + + /// createFastISel - This method returns a target specific FastISel object, + /// or null if the target does not support "fast" ISel. + virtual FastISel *createFastISel(FunctionLoweringInfo &funcInfo) const; + Sched::Preference getSchedulingPreference(SDNode *N) const; + unsigned getRegPressureLimit(const TargetRegisterClass *RC, + MachineFunction &MF) const; + bool isShuffleMaskLegal(const SmallVectorImpl &M, EVT VT) const; bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; @@ -265,11 +290,17 @@ namespace llvm { /// materialize the FP immediate as a load from a constant pool. virtual bool isFPImmLegal(const APFloat &Imm, EVT VT) const; + protected: + std::pair + findRepresentativeClass(EVT VT) const; + private: /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can /// make the right decision when generating code for different targets. const ARMSubtarget *Subtarget; + const TargetRegisterInfo *RegInfo; + /// ARMPCLabelIndex - Keep track of the number of ARM PC labels created. /// unsigned ARMPCLabelIndex; @@ -310,14 +341,15 @@ namespace llvm { SelectionDAG &DAG) const; SDValue LowerGLOBAL_OFFSET_TABLE(SDValue Op, SelectionDAG &DAG) const; SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSELECT(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const; SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; - SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const; SDValue LowerShiftRightParts(SDValue Op, SelectionDAG &DAG) const; SDValue LowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerFLT_ROUNDS_(SDValue Op, SelectionDAG &DAG) const; SDValue LowerCallResult(SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool isVarArg, @@ -377,6 +409,10 @@ namespace llvm { unsigned BinOpcode) const; }; + + namespace ARM { + FastISel *createFastISel(FunctionLoweringInfo &funcInfo); + } } #endif // ARMISELLOWERING_H diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td index ac568e7..113cfff 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -36,37 +36,38 @@ def LdStMulFrm : Format<10>; def LdStExFrm : Format<11>; def ArithMiscFrm : Format<12>; -def ExtFrm : Format<13>; - -def VFPUnaryFrm : Format<14>; -def VFPBinaryFrm : Format<15>; -def VFPConv1Frm : Format<16>; -def VFPConv2Frm : Format<17>; -def VFPConv3Frm : Format<18>; -def VFPConv4Frm : Format<19>; -def VFPConv5Frm : Format<20>; -def VFPLdStFrm : Format<21>; -def VFPLdStMulFrm : Format<22>; -def VFPMiscFrm : Format<23>; - -def ThumbFrm : Format<24>; -def MiscFrm : Format<25>; - -def NGetLnFrm : Format<26>; -def NSetLnFrm : Format<27>; -def NDupFrm : Format<28>; -def NLdStFrm : Format<29>; -def N1RegModImmFrm: Format<30>; -def N2RegFrm : Format<31>; -def NVCVTFrm : Format<32>; -def NVDupLnFrm : Format<33>; -def N2RegVShLFrm : Format<34>; -def N2RegVShRFrm : Format<35>; -def N3RegFrm : Format<36>; -def N3RegVShFrm : Format<37>; -def NVExtFrm : Format<38>; -def NVMulSLFrm : Format<39>; -def NVTBLFrm : Format<40>; +def SatFrm : Format<13>; +def ExtFrm : Format<14>; + +def VFPUnaryFrm : Format<15>; +def VFPBinaryFrm : Format<16>; +def VFPConv1Frm : Format<17>; +def VFPConv2Frm : Format<18>; +def VFPConv3Frm : Format<19>; +def VFPConv4Frm : Format<20>; +def VFPConv5Frm : Format<21>; +def VFPLdStFrm : Format<22>; +def VFPLdStMulFrm : Format<23>; +def VFPMiscFrm : Format<24>; + +def ThumbFrm : Format<25>; +def MiscFrm : Format<26>; + +def NGetLnFrm : Format<27>; +def NSetLnFrm : Format<28>; +def NDupFrm : Format<29>; +def NLdStFrm : Format<30>; +def N1RegModImmFrm: Format<31>; +def N2RegFrm : Format<32>; +def NVCVTFrm : Format<33>; +def NVDupLnFrm : Format<34>; +def N2RegVShLFrm : Format<35>; +def N2RegVShRFrm : Format<36>; +def N3RegFrm : Format<37>; +def N3RegVShFrm : Format<38>; +def NVExtFrm : Format<39>; +def NVMulSLFrm : Format<40>; +def NVTBLFrm : Format<41>; // Misc flags. @@ -87,21 +88,21 @@ class Xform16Bit { bit canXformTo16Bit = 1; } class AddrMode val> { bits<4> Value = val; } -def AddrModeNone : AddrMode<0>; -def AddrMode1 : AddrMode<1>; -def AddrMode2 : AddrMode<2>; -def AddrMode3 : AddrMode<3>; -def AddrMode4 : AddrMode<4>; -def AddrMode5 : AddrMode<5>; -def AddrMode6 : AddrMode<6>; -def AddrModeT1_1 : AddrMode<7>; -def AddrModeT1_2 : AddrMode<8>; -def AddrModeT1_4 : AddrMode<9>; -def AddrModeT1_s : AddrMode<10>; -def AddrModeT2_i12: AddrMode<11>; -def AddrModeT2_i8 : AddrMode<12>; -def AddrModeT2_so : AddrMode<13>; -def AddrModeT2_pc : AddrMode<14>; +def AddrModeNone : AddrMode<0>; +def AddrMode1 : AddrMode<1>; +def AddrMode2 : AddrMode<2>; +def AddrMode3 : AddrMode<3>; +def AddrMode4 : AddrMode<4>; +def AddrMode5 : AddrMode<5>; +def AddrMode6 : AddrMode<6>; +def AddrModeT1_1 : AddrMode<7>; +def AddrModeT1_2 : AddrMode<8>; +def AddrModeT1_4 : AddrMode<9>; +def AddrModeT1_s : AddrMode<10>; +def AddrModeT2_i12 : AddrMode<11>; +def AddrModeT2_i8 : AddrMode<12>; +def AddrModeT2_so : AddrMode<13>; +def AddrModeT2_pc : AddrMode<14>; def AddrModeT2_i8s4 : AddrMode<15>; // Instruction size. @@ -137,11 +138,17 @@ def VFPNeonDomain : Domain<3>; // Instructions in both VFP & Neon domains // ARM special operands. // +def CondCodeOperand : AsmOperandClass { + let Name = "CondCode"; + let SuperClasses = []; +} + // ARM Predicate operand. Default to 14 = always (AL). Second part is CC // register whose default is 0 (no register). def pred : PredicateOperand { let PrintMethod = "printPredicateOperand"; + let ParserMatchClass = CondCodeOperand; } // Conditional code result for instructions whose 's' bit is set, e.g. subs. @@ -240,6 +247,7 @@ class I Predicates = [IsARM]; } + // A few are not predicable class InoP Predicates = [IsARM]; } -// Same as I except it can optionally modify CPSR. Note it's modeled as -// an input operand since by default it's a zero register. It will -// become an implicit def once it's "flipped". +// Same as I except it can optionally modify CPSR. Note it's modeled as an input +// operand since by default it's a zero register. It will become an implicit def +// once it's "flipped". class sI opcod, dag oops, dag iops, InstrItinClass itin, } class ABXIx2 pattern> - : XI; // BR_JT instructions @@ -322,16 +330,14 @@ class JTI; - // Atomic load/store instructions - class AIldrex opcod, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : I { let Inst{27-23} = 0b00011; let Inst{22-21} = opcod; - let Inst{20} = 1; + let Inst{20} = 1; let Inst{11-0} = 0b111110011111; } class AIstrex opcod, dag oops, dag iops, InstrItinClass itin, @@ -340,7 +346,7 @@ class AIstrex opcod, dag oops, dag iops, InstrItinClass itin, opc, asm, "", pattern> { let Inst{27-23} = 0b00011; let Inst{22-21} = opcod; - let Inst{20} = 0; + let Inst{20} = 0; let Inst{11-4} = 0b11111001; } @@ -350,21 +356,21 @@ class AI1 opcod, dag oops, dag iops, Format f, InstrItinClass itin, : I { let Inst{24-21} = opcod; - let Inst{27-26} = {0,0}; + let Inst{27-26} = 0b00; } class AsI1 opcod, dag oops, dag iops, Format f, InstrItinClass itin, string opc, string asm, list pattern> : sI { let Inst{24-21} = opcod; - let Inst{27-26} = {0,0}; + let Inst{27-26} = 0b00; } class AXI1 opcod, dag oops, dag iops, Format f, InstrItinClass itin, string asm, list pattern> : XI { let Inst{24-21} = opcod; - let Inst{27-26} = {0,0}; + let Inst{27-26} = 0b00; } class AI1x2 pattern> @@ -377,7 +383,7 @@ class AI2 pattern> : I { - let Inst{27-26} = {0,1}; + let Inst{27-26} = 0b01; } // loads @@ -389,7 +395,7 @@ class AI2ldw pattern> @@ -399,7 +405,7 @@ class AXI2ldw pattern> @@ -409,7 +415,7 @@ class AI2ldb pattern> @@ -419,7 +425,7 @@ class AXI2ldb pattern> @@ -441,7 +447,7 @@ class AXI2stw pattern> @@ -451,7 +457,7 @@ class AI2stb pattern> @@ -461,7 +467,7 @@ class AXI2stb pattern> @@ -483,7 +489,7 @@ class AI2ldbpr pattern> @@ -505,7 +511,7 @@ class AI2stbpr pattern> @@ -527,7 +533,7 @@ class AI2ldbpo pattern> @@ -549,7 +555,7 @@ class AI2stbpo opcod1, bits<2> opcod2, bit opcod3, Encoding { let Inst{31-27} = opcod1; let Inst{15-14} = opcod2; - let Inst{12} = opcod3; + let Inst{12} = opcod3; } // BR_JT instructions @@ -1099,13 +1105,13 @@ class T1Special opcode> : Encoding16 { // A6.2.4 Load/store single data item encoding. class T1LoadStore opA, bits<3> opB> : Encoding16 { let Inst{15-12} = opA; - let Inst{11-9} = opB; + let Inst{11-9} = opB; } -class T1LdSt opB> : T1LoadStore<0b0101, opB>; +class T1LdSt opB> : T1LoadStore<0b0101, opB>; class T1LdSt4Imm opB> : T1LoadStore<0b0110, opB>; // Immediate, 4 bytes class T1LdSt1Imm opB> : T1LoadStore<0b0111, opB>; // Immediate, 1 byte class T1LdSt2Imm opB> : T1LoadStore<0b1000, opB>; // Immediate, 2 bytes -class T1LdStSP opB> : T1LoadStore<0b1001, opB>; // SP relative +class T1LdStSP opB> : T1LoadStore<0b1001, opB>; // SP relative // A6.2.5 Miscellaneous 16-bit instructions encoding. class T1Misc opcode> : Encoding16 { @@ -1125,9 +1131,10 @@ class Thumb2I Predicates = [IsThumb2]; } -// Same as Thumb2I except it can optionally modify CPSR. Note it's modeled as -// an input operand since by default it's a zero register. It will -// become an implicit def once it's "flipped". +// Same as Thumb2I except it can optionally modify CPSR. Note it's modeled as an +// input operand since by default it's a zero register. It will become an +// implicit def once it's "flipped". +// // FIXME: This uses unified syntax so {s} comes before {p}. We should make it // more consistent. class Thumb2sI { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b00; - let Inst{24} = P; - let Inst{23} = ?; // The U bit. - let Inst{22} = 1; - let Inst{21} = W; - let Inst{20} = load; + let Inst{24} = P; + let Inst{23} = ?; // The U bit. + let Inst{22} = 1; + let Inst{21} = W; + let Inst{20} = load; } class T2sI opcod, bit load, bit pre, list Predicates = [IsThumb2]; let Inst{31-27} = 0b11111; let Inst{26-25} = 0b00; - let Inst{24} = signed; - let Inst{23} = 0; + let Inst{24} = signed; + let Inst{23} = 0; let Inst{22-21} = opcod; - let Inst{20} = load; - let Inst{11} = 1; + let Inst{20} = load; + let Inst{11} = 1; // (P, W) = (1, 1) Pre-indexed or (0, 1) Post-indexed - let Inst{10} = pre; // The P bit. - let Inst{8} = 1; // The W bit. + let Inst{10} = pre; // The P bit. + let Inst{8} = 1; // The W bit. } // Helper class for disassembly only @@ -1243,9 +1250,9 @@ class T2I_mac op22_20, bits<4> op7_4, dag oops, dag iops, : T2I { let Inst{31-27} = 0b11111; let Inst{26-24} = 0b011; - let Inst{23} = long; + let Inst{23} = long; let Inst{22-20} = op22_20; - let Inst{7-4} = op7_4; + let Inst{7-4} = op7_4; } // Tv5Pat - Same as Pat<>, but requires V5T Thumb mode. @@ -1325,9 +1332,9 @@ class ASI5 opcod1, bits<2> opcod2, dag oops, dag iops, } // Load / store multiple -class AXDI5 pattern> - : VFPXI { // TODO: Mark the instructions with the appropriate subtarget info. let Inst{27-25} = 0b110; @@ -1337,9 +1344,9 @@ class AXDI5 pattern> - : VFPXI { // TODO: Mark the instructions with the appropriate subtarget info. let Inst{27-25} = 0b110; @@ -1367,8 +1374,8 @@ class ADbI opcod1, bits<2> opcod2, bit op6, bit op4, dag oops, let Inst{27-23} = opcod1; let Inst{21-20} = opcod2; let Inst{11-8} = 0b1011; - let Inst{6} = op6; - let Inst{4} = op4; + let Inst{6} = op6; + let Inst{4} = op4; } // Double precision, binary, VML[AS] (for additional predicate) @@ -1379,12 +1386,11 @@ class ADbI_vmlX opcod1, bits<2> opcod2, bit op6, bit op4, dag oops, let Inst{27-23} = opcod1; let Inst{21-20} = opcod2; let Inst{11-8} = 0b1011; - let Inst{6} = op6; - let Inst{4} = op4; + let Inst{6} = op6; + let Inst{4} = op4; list Predicates = [HasVFP2, UseVMLx]; } - // Single precision, unary class ASuI opcod1, bits<2> opcod2, bits<4> opcod3, bits<2> opcod4, bit opcod5, dag oops, dag iops, InstrItinClass itin, string opc, @@ -1415,8 +1421,8 @@ class ASbI opcod1, bits<2> opcod2, bit op6, bit op4, dag oops, dag iops, let Inst{27-23} = opcod1; let Inst{21-20} = opcod2; let Inst{11-8} = 0b1010; - let Inst{6} = op6; - let Inst{4} = op4; + let Inst{6} = op6; + let Inst{4} = op4; } // Single precision binary, if no NEON @@ -1521,10 +1527,18 @@ class NLdSt op21_20, bits<4> op11_8, bits<4> op7_4, : NeonI { let Inst{31-24} = 0b11110100; - let Inst{23} = op23; + let Inst{23} = op23; let Inst{21-20} = op21_20; - let Inst{11-8} = op11_8; - let Inst{7-4} = op7_4; + let Inst{11-8} = op11_8; + let Inst{7-4} = op7_4; +} + +class PseudoNLdSt + : InstARM { + let OutOperandList = oops; + let InOperandList = !con(iops, (ins pred:$p)); + list Predicates = [HasNEON]; } class NDataI op21_19, bits<4> op11_8, bit op7, bit op6, string opc, string dt, string asm, string cstr, list pattern> : NDataI { - let Inst{23} = op23; + let Inst{23} = op23; let Inst{21-19} = op21_19; - let Inst{11-8} = op11_8; - let Inst{7} = op7; - let Inst{6} = op6; - let Inst{5} = op5; - let Inst{4} = op4; + let Inst{11-8} = op11_8; + let Inst{7} = op7; + let Inst{6} = op6; + let Inst{5} = op5; + let Inst{4} = op4; } // NEON 2 vector register format. @@ -1567,9 +1581,9 @@ class N2V op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, let Inst{21-20} = op21_20; let Inst{19-18} = op19_18; let Inst{17-16} = op17_16; - let Inst{11-7} = op11_7; - let Inst{6} = op6; - let Inst{4} = op4; + let Inst{11-7} = op11_7; + let Inst{6} = op6; + let Inst{4} = op4; } // Same as N2V except it doesn't have a datatype suffix. @@ -1582,9 +1596,9 @@ class N2VX op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, let Inst{21-20} = op21_20; let Inst{19-18} = op19_18; let Inst{17-16} = op17_16; - let Inst{11-7} = op11_7; - let Inst{6} = op6; - let Inst{4} = op4; + let Inst{11-7} = op11_7; + let Inst{6} = op6; + let Inst{4} = op4; } // NEON 2 vector register with immediate. @@ -1592,12 +1606,12 @@ class N2VImm op11_8, bit op7, bit op6, bit op4, dag oops, dag iops, Format f, InstrItinClass itin, string opc, string dt, string asm, string cstr, list pattern> : NDataI { - let Inst{24} = op24; - let Inst{23} = op23; + let Inst{24} = op24; + let Inst{23} = op23; let Inst{11-8} = op11_8; - let Inst{7} = op7; - let Inst{6} = op6; - let Inst{4} = op4; + let Inst{7} = op7; + let Inst{6} = op6; + let Inst{4} = op4; } // NEON 3 vector register format. @@ -1605,12 +1619,12 @@ class N3V op21_20, bits<4> op11_8, bit op6, bit op4, dag oops, dag iops, Format f, InstrItinClass itin, string opc, string dt, string asm, string cstr, list pattern> : NDataI { - let Inst{24} = op24; - let Inst{23} = op23; + let Inst{24} = op24; + let Inst{23} = op23; let Inst{21-20} = op21_20; - let Inst{11-8} = op11_8; - let Inst{6} = op6; - let Inst{4} = op4; + let Inst{11-8} = op11_8; + let Inst{6} = op6; + let Inst{4} = op4; } // Same as N3V except it doesn't have a data type suffix. @@ -1619,12 +1633,12 @@ class N3VX op21_20, bits<4> op11_8, bit op6, dag oops, dag iops, Format f, InstrItinClass itin, string opc, string asm, string cstr, list pattern> : NDataXI { - let Inst{24} = op24; - let Inst{23} = op23; + let Inst{24} = op24; + let Inst{23} = op23; let Inst{21-20} = op21_20; - let Inst{11-8} = op11_8; - let Inst{6} = op6; - let Inst{4} = op4; + let Inst{11-8} = op11_8; + let Inst{6} = op6; + let Inst{4} = op4; } // NEON VMOVs between scalar and core registers. @@ -1634,9 +1648,9 @@ class NVLaneOp opcod1, bits<4> opcod2, bits<2> opcod3, : InstARM { let Inst{27-20} = opcod1; - let Inst{11-8} = opcod2; - let Inst{6-5} = opcod3; - let Inst{4} = 1; + let Inst{11-8} = opcod2; + let Inst{6-5} = opcod3; + let Inst{4} = 1; let OutOperandList = oops; let InOperandList = !con(iops, (ins pred:$p)); @@ -1670,9 +1684,9 @@ class NVDupLane op19_16, bit op6, dag oops, dag iops, let Inst{24-23} = 0b11; let Inst{21-20} = 0b11; let Inst{19-16} = op19_16; - let Inst{11-7} = 0b11000; - let Inst{6} = op6; - let Inst{4} = 0; + let Inst{11-7} = 0b11000; + let Inst{6} = op6; + let Inst{4} = 0; } // NEONFPPat - Same as Pat<>, but requires that the compiler be using NEON diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 51fc152..e66f9b9 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -44,6 +44,10 @@ def SDT_ARMBCC_i64 : SDTypeProfile<0, 6, SDTCisVT<3, i32>, SDTCisVT<4, i32>, SDTCisVT<5, OtherVT>]>; +def SDT_ARMAnd : SDTypeProfile<1, 2, + [SDTCisVT<0, i32>, SDTCisVT<1, i32>, + SDTCisVT<2, i32>]>; + def SDT_ARMCmp : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>; def SDT_ARMPICAdd : SDTypeProfile<1, 2, [SDTCisSameAs<0, 1>, @@ -54,13 +58,16 @@ def SDT_ARMEH_SJLJ_Setjmp : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisPtrTy<1>, SDTCisInt<2>]>; def SDT_ARMEH_SJLJ_Longjmp: SDTypeProfile<0, 2, [SDTCisPtrTy<0>, SDTCisInt<1>]>; -def SDT_ARMMEMBARRIERV7 : SDTypeProfile<0, 0, []>; -def SDT_ARMSYNCBARRIERV7 : SDTypeProfile<0, 0, []>; -def SDT_ARMMEMBARRIERV6 : SDTypeProfile<0, 1, [SDTCisInt<0>]>; -def SDT_ARMSYNCBARRIERV6 : SDTypeProfile<0, 1, [SDTCisInt<0>]>; +def SDT_ARMMEMBARRIER : SDTypeProfile<0, 0, []>; +def SDT_ARMSYNCBARRIER : SDTypeProfile<0, 0, []>; +def SDT_ARMMEMBARRIERMCR : SDTypeProfile<0, 1, [SDTCisInt<0>]>; +def SDT_ARMSYNCBARRIERMCR : SDTypeProfile<0, 1, [SDTCisInt<0>]>; def SDT_ARMTCRET : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>; +def SDT_ARMBFI : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, SDTCisVT<1, i32>, + SDTCisVT<2, i32>, SDTCisVT<3, i32>]>; + // Node definitions. def ARMWrapper : SDNode<"ARMISD::Wrapper", SDTIntUnaryOp>; def ARMWrapperJT : SDNode<"ARMISD::WrapperJT", SDTIntBinOp>; @@ -99,11 +106,14 @@ def ARMbr2jt : SDNode<"ARMISD::BR2_JT", SDT_ARMBr2JT, def ARMBcci64 : SDNode<"ARMISD::BCC_i64", SDT_ARMBCC_i64, [SDNPHasChain]>; +def ARMand : SDNode<"ARMISD::AND", SDT_ARMAnd, + [SDNPOutFlag]>; + def ARMcmp : SDNode<"ARMISD::CMP", SDT_ARMCmp, [SDNPOutFlag]>; def ARMcmpZ : SDNode<"ARMISD::CMPZ", SDT_ARMCmp, - [SDNPOutFlag,SDNPCommutative]>; + [SDNPOutFlag, SDNPCommutative]>; def ARMpic_add : SDNode<"ARMISD::PIC_ADD", SDT_ARMPICAdd>; @@ -117,51 +127,54 @@ def ARMeh_sjlj_setjmp: SDNode<"ARMISD::EH_SJLJ_SETJMP", def ARMeh_sjlj_longjmp: SDNode<"ARMISD::EH_SJLJ_LONGJMP", SDT_ARMEH_SJLJ_Longjmp, [SDNPHasChain]>; -def ARMMemBarrierV7 : SDNode<"ARMISD::MEMBARRIER", SDT_ARMMEMBARRIERV7, - [SDNPHasChain]>; -def ARMSyncBarrierV7 : SDNode<"ARMISD::SYNCBARRIER", SDT_ARMMEMBARRIERV7, - [SDNPHasChain]>; -def ARMMemBarrierV6 : SDNode<"ARMISD::MEMBARRIER", SDT_ARMMEMBARRIERV6, - [SDNPHasChain]>; -def ARMSyncBarrierV6 : SDNode<"ARMISD::SYNCBARRIER", SDT_ARMMEMBARRIERV6, - [SDNPHasChain]>; +def ARMMemBarrier : SDNode<"ARMISD::MEMBARRIER", SDT_ARMMEMBARRIER, + [SDNPHasChain]>; +def ARMSyncBarrier : SDNode<"ARMISD::SYNCBARRIER", SDT_ARMMEMBARRIER, + [SDNPHasChain]>; +def ARMMemBarrierMCR : SDNode<"ARMISD::MEMBARRIER", SDT_ARMMEMBARRIERMCR, + [SDNPHasChain]>; +def ARMSyncBarrierMCR : SDNode<"ARMISD::SYNCBARRIER", SDT_ARMMEMBARRIERMCR, + [SDNPHasChain]>; def ARMrbit : SDNode<"ARMISD::RBIT", SDTIntUnaryOp>; def ARMtcret : SDNode<"ARMISD::TC_RETURN", SDT_ARMTCRET, [SDNPHasChain, SDNPOptInFlag, SDNPVariadic]>; + +def ARMbfi : SDNode<"ARMISD::BFI", SDT_ARMBFI>; + //===----------------------------------------------------------------------===// // ARM Instruction Predicate Definitions. // -def HasV4T : Predicate<"Subtarget->hasV4TOps()">; -def NoV4T : Predicate<"!Subtarget->hasV4TOps()">; -def HasV5T : Predicate<"Subtarget->hasV5TOps()">; -def HasV5TE : Predicate<"Subtarget->hasV5TEOps()">; -def HasV6 : Predicate<"Subtarget->hasV6Ops()">; -def HasV6T2 : Predicate<"Subtarget->hasV6T2Ops()">; -def NoV6T2 : Predicate<"!Subtarget->hasV6T2Ops()">; -def HasV7 : Predicate<"Subtarget->hasV7Ops()">; -def NoVFP : Predicate<"!Subtarget->hasVFP2()">; -def HasVFP2 : Predicate<"Subtarget->hasVFP2()">; -def HasVFP3 : Predicate<"Subtarget->hasVFP3()">; -def HasNEON : Predicate<"Subtarget->hasNEON()">; -def HasDivide : Predicate<"Subtarget->hasDivide()">; +def HasV4T : Predicate<"Subtarget->hasV4TOps()">; +def NoV4T : Predicate<"!Subtarget->hasV4TOps()">; +def HasV5T : Predicate<"Subtarget->hasV5TOps()">; +def HasV5TE : Predicate<"Subtarget->hasV5TEOps()">; +def HasV6 : Predicate<"Subtarget->hasV6Ops()">; +def HasV6T2 : Predicate<"Subtarget->hasV6T2Ops()">; +def NoV6T2 : Predicate<"!Subtarget->hasV6T2Ops()">; +def HasV7 : Predicate<"Subtarget->hasV7Ops()">; +def NoVFP : Predicate<"!Subtarget->hasVFP2()">; +def HasVFP2 : Predicate<"Subtarget->hasVFP2()">; +def HasVFP3 : Predicate<"Subtarget->hasVFP3()">; +def HasNEON : Predicate<"Subtarget->hasNEON()">; +def HasDivide : Predicate<"Subtarget->hasDivide()">; def HasT2ExtractPack : Predicate<"Subtarget->hasT2ExtractPack()">; -def UseNEONForFP : Predicate<"Subtarget->useNEONForSinglePrecisionFP()">; +def HasDB : Predicate<"Subtarget->hasDataBarrier()">; +def UseNEONForFP : Predicate<"Subtarget->useNEONForSinglePrecisionFP()">; def DontUseNEONForFP : Predicate<"!Subtarget->useNEONForSinglePrecisionFP()">; -def IsThumb : Predicate<"Subtarget->isThumb()">; -def IsThumb1Only : Predicate<"Subtarget->isThumb1Only()">; -def IsThumb2 : Predicate<"Subtarget->isThumb2()">; -def IsARM : Predicate<"!Subtarget->isThumb()">; -def IsDarwin : Predicate<"Subtarget->isTargetDarwin()">; -def IsNotDarwin : Predicate<"!Subtarget->isTargetDarwin()">; +def IsThumb : Predicate<"Subtarget->isThumb()">; +def IsThumb1Only : Predicate<"Subtarget->isThumb1Only()">; +def IsThumb2 : Predicate<"Subtarget->isThumb2()">; +def IsARM : Predicate<"!Subtarget->isThumb()">; +def IsDarwin : Predicate<"Subtarget->isTargetDarwin()">; +def IsNotDarwin : Predicate<"!Subtarget->isTargetDarwin()">; // FIXME: Eventually this will be just "hasV6T2Ops". -def UseMovt : Predicate<"Subtarget->useMovt()">; -def DontUseMovt : Predicate<"!Subtarget->useMovt()">; - -def UseVMLx : Predicate<"Subtarget->useVMLx()">; +def UseMovt : Predicate<"Subtarget->useMovt()">; +def DontUseMovt : Predicate<"!Subtarget->useMovt()">; +def UseVMLx : Predicate<"Subtarget->useVMLx()">; //===----------------------------------------------------------------------===// // ARM Flag Definitions. @@ -221,29 +234,12 @@ def sext_16_node : PatLeaf<(i32 GPR:$a), [{ /// e.g., 0xf000ffff def bf_inv_mask_imm : Operand, PatLeaf<(imm), [{ - uint32_t v = (uint32_t)N->getZExtValue(); - if (v == 0xffffffff) - return 0; - // there can be 1's on either or both "outsides", all the "inside" - // bits must be 0's - unsigned int lsb = 0, msb = 31; - while (v & (1 << msb)) --msb; - while (v & (1 << lsb)) ++lsb; - for (unsigned int i = lsb; i <= msb; ++i) { - if (v & (1 << i)) - return 0; - } - return 1; + return ARM::isBitFieldInvertedMask(N->getZExtValue()); }] > { let PrintMethod = "printBitfieldInvMaskImmOperand"; } /// Split a 32-bit immediate into two 16 bit parts. -def lo16 : SDNodeXFormgetTargetConstant((uint32_t)N->getZExtValue() & 0xffff, - MVT::i32); -}]>; - def hi16 : SDNodeXFormgetTargetConstant((uint32_t)N->getZExtValue() >> 16, MVT::i32); }]>; @@ -306,6 +302,13 @@ def pclabel : Operand { let PrintMethod = "printPCLabel"; } +// shift_imm: An integer that encodes a shift amount and the type of shift +// (currently either asr or lsl) using the same encoding used for the +// immediates in so_reg operands. +def shift_imm : Operand { + let PrintMethod = "printShiftImmOperand"; +} + // shifter_operand operands: so_reg and so_imm. def so_reg : Operand, // reg reg imm ComplexPattern, // reg reg imm // represented in the imm field in the same 12-bit form that they are encoded // into so_imm instructions: the 8-bit immediate is the least significant bits // [bits 0-7], the 4-bit shift amount is the next 4 bits [bits 8-11]. -def so_imm : Operand, - PatLeaf<(imm), [{ - return ARM_AM::getSOImmVal(N->getZExtValue()) != -1; - }]> { +def so_imm : Operand, PatLeaf<(imm), [{ return Pred_so_imm(N); }]> { let PrintMethod = "printSOImmOperand"; } @@ -452,11 +452,15 @@ include "ARMInstrFormats.td" /// binop that produces a value. multiclass AsI1_bin_irs opcod, string opc, PatFrag opnode, bit Commutable = 0> { + // The register-immediate version is re-materializable. This is useful + // in particular for taking the address of a local. + let isReMaterializable = 1 in { def ri : AsI1 { let Inst{25} = 1; } + } def rr : AsI1 { @@ -502,7 +506,7 @@ multiclass AI1_bin_s_irs opcod, string opc, PatFrag opnode, /// AI1_cmp_irs - Defines a set of (op r, {so_imm|r|so_reg}) cmp / test /// patterns. Similar to AsI1_bin_irs except the instruction does not produce /// a explicit result, only implicitly set CPSR. -let Defs = [CPSR] in { +let isCompare = 1, Defs = [CPSR] in { multiclass AI1_cmp_irs opcod, string opc, PatFrag opnode, bit Commutable = 0> { def ri : AI1 { let Inst{11-4} = 0b00000000; let Inst{15-12} = 0b1111; @@ -1127,7 +1131,7 @@ let isBranch = 1, isTerminator = 1 in { } def BR_JTm : JTI<(outs), (ins addrmode2:$target, jtblock_operand:$jt, i32imm:$id), - IIC_Br, "ldr\tpc, $target \n$jt", + IIC_Br, "ldr\tpc, $target$jt", [(ARMbrjt (i32 (load addrmode2:$target)), tjumptable:$jt, imm:$id)]> { let Inst{15-12} = 0b1111; @@ -1139,7 +1143,7 @@ let isBranch = 1, isTerminator = 1 in { } def BR_JTadd : JTI<(outs), (ins GPR:$target, GPR:$idx, jtblock_operand:$jt, i32imm:$id), - IIC_Br, "add\tpc, $target, $idx \n$jt", + IIC_Br, "add\tpc, $target, $idx$jt", [(ARMbrjt (add GPR:$target, GPR:$idx), tjumptable:$jt, imm:$id)]> { let Inst{15-12} = 0b1111; @@ -1573,8 +1577,12 @@ defm UXTH : AI_unary_rrot<0b01101111, defm UXTB16 : AI_unary_rrot<0b01101100, "uxtb16", UnOpFrag<(and node:$Src, 0x00FF00FF)>>; -def : ARMV6Pat<(and (shl GPR:$Src, (i32 8)), 0xFF00FF), - (UXTB16r_rot GPR:$Src, 24)>; +// FIXME: This pattern incorrectly assumes the shl operator is a rotate. +// The transformation should probably be done as a combiner action +// instead so we can include a check for masking back in the upper +// eight bits of the source into the lower eight bits of the result. +//def : ARMV6Pat<(and (shl GPR:$Src, (i32 8)), 0xFF00FF), +// (UXTB16r_rot GPR:$Src, 24)>; def : ARMV6Pat<(and (srl GPR:$Src, (i32 8)), 0xFF00FF), (UXTB16r_rot GPR:$Src, 8)>; @@ -1631,16 +1639,24 @@ defm ADCS : AI1_adde_sube_s_irs<0b0101, "adcs", defm SBCS : AI1_adde_sube_s_irs<0b0110, "sbcs", BinOpFrag<(sube_live_carry node:$LHS, node:$RHS) >>; -// These don't define reg/reg forms, because they are handled above. def RSBri : AsI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPFrm, - IIC_iALUi, "rsb", "\t$dst, $a, $b", - [(set GPR:$dst, (sub so_imm:$b, GPR:$a))]> { + IIC_iALUi, "rsb", "\t$dst, $a, $b", + [(set GPR:$dst, (sub so_imm:$b, GPR:$a))]> { let Inst{25} = 1; } +// The reg/reg form is only defined for the disassembler; for codegen it is +// equivalent to SUBrr. +def RSBrr : AsI1<0b0011, (outs GPR:$dst), (ins GPR:$a, GPR:$b), DPFrm, + IIC_iALUr, "rsb", "\t$dst, $a, $b", + [/* For disassembly only; pattern left blank */]> { + let Inst{25} = 0; + let Inst{11-4} = 0b00000000; +} + def RSBrs : AsI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm, - IIC_iALUsr, "rsb", "\t$dst, $a, $b", - [(set GPR:$dst, (sub so_reg:$b, GPR:$a))]> { + IIC_iALUsr, "rsb", "\t$dst, $a, $b", + [(set GPR:$dst, (sub so_reg:$b, GPR:$a))]> { let Inst{25} = 0; } @@ -1667,6 +1683,14 @@ def RSCri : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), Requires<[IsARM]> { let Inst{25} = 1; } +// The reg/reg form is only defined for the disassembler; for codegen it is +// equivalent to SUBrr. +def RSCrr : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, GPR:$b), + DPFrm, IIC_iALUr, "rsc", "\t$dst, $a, $b", + [/* For disassembly only; pattern left blank */]> { + let Inst{25} = 0; + let Inst{11-4} = 0b00000000; +} def RSCrs : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm, IIC_iALUsr, "rsc", "\t$dst, $a, $b", [(set GPR:$dst, (sube_dead_carry so_reg:$b, GPR:$a))]>, @@ -1716,24 +1740,26 @@ def : ARMPat<(adde GPR:$src, so_imm_not:$imm), // ARM Arithmetic Instruction -- for disassembly only // GPR:$dst = GPR:$a op GPR:$b -class AAI op27_20, bits<4> op7_4, string opc> +class AAI op27_20, bits<4> op7_4, string opc, + list pattern = [/* For disassembly only; pattern left blank */]> : AI<(outs GPR:$dst), (ins GPR:$a, GPR:$b), DPFrm, IIC_iALUr, - opc, "\t$dst, $a, $b", - [/* For disassembly only; pattern left blank */]> { + opc, "\t$dst, $a, $b", pattern> { let Inst{27-20} = op27_20; let Inst{7-4} = op7_4; } // Saturating add/subtract -- for disassembly only -def QADD : AAI<0b00010000, 0b0101, "qadd">; +def QADD : AAI<0b00010000, 0b0101, "qadd", + [(set GPR:$dst, (int_arm_qadd GPR:$a, GPR:$b))]>; def QADD16 : AAI<0b01100010, 0b0001, "qadd16">; def QADD8 : AAI<0b01100010, 0b1001, "qadd8">; def QASX : AAI<0b01100010, 0b0011, "qasx">; def QDADD : AAI<0b00010100, 0b0101, "qdadd">; def QDSUB : AAI<0b00010110, 0b0101, "qdsub">; def QSAX : AAI<0b01100010, 0b0101, "qsax">; -def QSUB : AAI<0b00010010, 0b0101, "qsub">; +def QSUB : AAI<0b00010010, 0b0101, "qsub", + [(set GPR:$dst, (int_arm_qsub GPR:$a, GPR:$b))]>; def QSUB16 : AAI<0b01100010, 0b0111, "qsub16">; def QSUB8 : AAI<0b01100010, 0b1111, "qsub8">; def UQADD16 : AAI<0b01100110, 0b0001, "uqadd16">; @@ -1793,54 +1819,45 @@ def USADA8 : AI<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), // Signed/Unsigned saturate -- for disassembly only -def SSATlsl : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, i32imm:$shamt), - DPFrm, NoItinerary, "ssat", "\t$dst, $bit_pos, $a, lsl $shamt", - [/* For disassembly only; pattern left blank */]> { - let Inst{27-21} = 0b0110101; - let Inst{6-4} = 0b001; -} - -def SSATasr : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, i32imm:$shamt), - DPFrm, NoItinerary, "ssat", "\t$dst, $bit_pos, $a, asr $shamt", - [/* For disassembly only; pattern left blank */]> { +def SSAT : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, shift_imm:$sh), + SatFrm, NoItinerary, "ssat", "\t$dst, $bit_pos, $a$sh", + [/* For disassembly only; pattern left blank */]> { let Inst{27-21} = 0b0110101; - let Inst{6-4} = 0b101; + let Inst{5-4} = 0b01; } -def SSAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), DPFrm, +def SSAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), SatFrm, NoItinerary, "ssat16", "\t$dst, $bit_pos, $a", [/* For disassembly only; pattern left blank */]> { let Inst{27-20} = 0b01101010; let Inst{7-4} = 0b0011; } -def USATlsl : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, i32imm:$shamt), - DPFrm, NoItinerary, "usat", "\t$dst, $bit_pos, $a, lsl $shamt", - [/* For disassembly only; pattern left blank */]> { - let Inst{27-21} = 0b0110111; - let Inst{6-4} = 0b001; -} - -def USATasr : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, i32imm:$shamt), - DPFrm, NoItinerary, "usat", "\t$dst, $bit_pos, $a, asr $shamt", - [/* For disassembly only; pattern left blank */]> { +def USAT : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, shift_imm:$sh), + SatFrm, NoItinerary, "usat", "\t$dst, $bit_pos, $a$sh", + [/* For disassembly only; pattern left blank */]> { let Inst{27-21} = 0b0110111; - let Inst{6-4} = 0b101; + let Inst{5-4} = 0b01; } -def USAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), DPFrm, +def USAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), SatFrm, NoItinerary, "usat16", "\t$dst, $bit_pos, $a", [/* For disassembly only; pattern left blank */]> { let Inst{27-20} = 0b01101110; let Inst{7-4} = 0b0011; } +def : ARMV6Pat<(int_arm_ssat GPR:$a, imm:$pos), (SSAT imm:$pos, GPR:$a, 0)>; +def : ARMV6Pat<(int_arm_usat GPR:$a, imm:$pos), (USAT imm:$pos, GPR:$a, 0)>; + //===----------------------------------------------------------------------===// // Bitwise Instructions. // defm AND : AsI1_bin_irs<0b0000, "and", BinOpFrag<(and node:$LHS, node:$RHS)>, 1>; +defm ANDS : AI1_bin_s_irs<0b0000, "and", + BinOpFrag<(ARMand node:$LHS, node:$RHS)>, 1>; defm ORR : AsI1_bin_irs<0b1100, "orr", BinOpFrag<(or node:$LHS, node:$RHS)>, 1>; defm EOR : AsI1_bin_irs<0b0001, "eor", @@ -1858,11 +1875,11 @@ def BFC : I<(outs GPR:$dst), (ins GPR:$src, bf_inv_mask_imm:$imm), } // A8.6.18 BFI - Bitfield insert (Encoding A1) -// Added for disassembler with the pattern field purposely left blank. -def BFI : I<(outs GPR:$dst), (ins GPR:$src, bf_inv_mask_imm:$imm), +def BFI : I<(outs GPR:$dst), (ins GPR:$src, GPR:$val, bf_inv_mask_imm:$imm), AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi, - "bfi", "\t$dst, $src, $imm", "", - [/* For disassembly only; pattern left blank */]>, + "bfi", "\t$dst, $val, $imm", "$src = $dst", + [(set GPR:$dst, (ARMbfi GPR:$src, GPR:$val, + bf_inv_mask_imm:$imm))]>, Requires<[IsARM, HasV6T2]> { let Inst{27-21} = 0b0111110; let Inst{6-4} = 0b001; // Rn: Inst{3-0} != 15 @@ -2232,11 +2249,20 @@ def REVSH : AMiscA1I<0b01101111, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, let Inst{19-16} = 0b1111; } +def lsl_shift_imm : SDNodeXFormgetZExtValue()); + return CurDAG->getTargetConstant(Sh, MVT::i32); +}]>; + +def lsl_amt : PatLeaf<(i32 imm), [{ + return (N->getZExtValue() < 32); +}], lsl_shift_imm>; + def PKHBT : AMiscA1I<0b01101000, (outs GPR:$dst), - (ins GPR:$src1, GPR:$src2, i32imm:$shamt), - IIC_iALUsi, "pkhbt", "\t$dst, $src1, $src2, lsl $shamt", + (ins GPR:$src1, GPR:$src2, shift_imm:$sh), + IIC_iALUsi, "pkhbt", "\t$dst, $src1, $src2$sh", [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF), - (and (shl GPR:$src2, (i32 imm:$shamt)), + (and (shl GPR:$src2, lsl_amt:$sh), 0xFFFF0000)))]>, Requires<[IsARM, HasV6]> { let Inst{6-4} = 0b001; @@ -2245,26 +2271,37 @@ def PKHBT : AMiscA1I<0b01101000, (outs GPR:$dst), // Alternate cases for PKHBT where identities eliminate some nodes. def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF), (and GPR:$src2, 0xFFFF0000)), (PKHBT GPR:$src1, GPR:$src2, 0)>; -def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF), (shl GPR:$src2, imm16_31:$shamt)), - (PKHBT GPR:$src1, GPR:$src2, imm16_31:$shamt)>; +def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF), (shl GPR:$src2, imm16_31:$sh)), + (PKHBT GPR:$src1, GPR:$src2, (lsl_shift_imm imm16_31:$sh))>; + +def asr_shift_imm : SDNodeXFormgetZExtValue()); + return CurDAG->getTargetConstant(Sh, MVT::i32); +}]>; +def asr_amt : PatLeaf<(i32 imm), [{ + return (N->getZExtValue() <= 32); +}], asr_shift_imm>; +// Note: Shifts of 1-15 bits will be transformed to srl instead of sra and +// will match the pattern below. def PKHTB : AMiscA1I<0b01101000, (outs GPR:$dst), - (ins GPR:$src1, GPR:$src2, i32imm:$shamt), - IIC_iALUsi, "pkhtb", "\t$dst, $src1, $src2, asr $shamt", + (ins GPR:$src1, GPR:$src2, shift_imm:$sh), + IIC_iALUsi, "pkhtb", "\t$dst, $src1, $src2$sh", [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF0000), - (and (sra GPR:$src2, imm16_31:$shamt), - 0xFFFF)))]>, Requires<[IsARM, HasV6]> { + (and (sra GPR:$src2, asr_amt:$sh), + 0xFFFF)))]>, + Requires<[IsARM, HasV6]> { let Inst{6-4} = 0b101; } // Alternate cases for PKHTB where identities eliminate some nodes. Note that // a shift amount of 0 is *not legal* here, it is PKHBT instead. -def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF0000), (srl GPR:$src2, (i32 16))), - (PKHTB GPR:$src1, GPR:$src2, 16)>; +def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF0000), (srl GPR:$src2, imm16_31:$sh)), + (PKHTB GPR:$src1, GPR:$src2, (asr_shift_imm imm16_31:$sh))>; def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF0000), - (and (srl GPR:$src2, imm1_15:$shamt), 0xFFFF)), - (PKHTB GPR:$src1, GPR:$src2, imm1_15:$shamt)>; + (and (srl GPR:$src2, imm1_15:$sh), 0xFFFF)), + (PKHTB GPR:$src1, GPR:$src2, (asr_shift_imm imm1_15:$sh))>; //===----------------------------------------------------------------------===// // Comparison Instructions... @@ -2272,8 +2309,52 @@ def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF0000), defm CMP : AI1_cmp_irs<0b1010, "cmp", BinOpFrag<(ARMcmp node:$LHS, node:$RHS)>>; -//FIXME: Disable CMN, as CCodes are backwards from compare expectations -// Compare-to-zero still works out, just not the relationals + +// FIXME: There seems to be a (potential) hardware bug with the CMN instruction +// and comparison with 0. These two pieces of code should give identical +// results: +// +// rsbs r1, r1, 0 +// cmp r0, r1 +// mov r0, #0 +// it ls +// mov r0, #1 +// +// and: +// +// cmn r0, r1 +// mov r0, #0 +// it ls +// mov r0, #1 +// +// However, the CMN gives the *opposite* result when r1 is 0. This is because +// the carry flag is set in the CMP case but not in the CMN case. In short, the +// CMP instruction doesn't perform a truncate of the (logical) NOT of 0 plus the +// value of r0 and the carry bit (because the "carry bit" parameter to +// AddWithCarry is defined as 1 in this case, the carry flag will always be set +// when r0 >= 0). The CMN instruction doesn't perform a NOT of 0 so there is +// never a "carry" when this AddWithCarry is performed (because the "carry bit" +// parameter to AddWithCarry is defined as 0). +// +// The AddWithCarry in the CMP case seems to be relying upon the identity: +// +// ~x + 1 = -x +// +// However when x is 0 and unsigned, this doesn't hold: +// +// x = 0 +// ~x = 0xFFFF FFFF +// ~x + 1 = 0x1 0000 0000 +// (-x = 0) != (0x1 0000 0000 = ~x + 1) +// +// Therefore, we should disable *all* versions of CMN, especially when comparing +// against zero, until we can limit when the CMN instruction is used (when we +// know that the RHS is not 0) or when we have a hardware fix for this. +// +// (See the ARM docs for the "AddWithCarry" pseudo-code.) +// +// This is related to . +// //defm CMN : AI1_cmp_irs<0b1011, "cmn", // BinOpFrag<(ARMcmp node:$LHS,(ineg node:$RHS))>>; @@ -2298,8 +2379,8 @@ def : ARMPat<(ARMcmpZ GPR:$src, so_imm_neg:$imm), let usesCustomInserter = 1, isBranch = 1, isTerminator = 1, Defs = [CPSR] in { def BCCi64 : PseudoInst<(outs), - (ins i32imm:$cc, GPR:$lhs1, GPR:$lhs2, GPR:$rhs1, GPR:$rhs2, brtarget:$dst), - IIC_Br, + (ins i32imm:$cc, GPR:$lhs1, GPR:$lhs2, GPR:$rhs1, GPR:$rhs2, brtarget:$dst), + IIC_Br, "${:comment} B\t$dst GPR:$lhs1, GPR:$lhs2, GPR:$rhs1, GPR:$rhs2, imm:$cc", [(ARMBcci64 imm:$cc, GPR:$lhs1, GPR:$lhs2, GPR:$rhs1, GPR:$rhs2, bb:$dst)]>; @@ -2346,102 +2427,63 @@ def MOVCCi : AI1<0b1101, (outs GPR:$dst), // memory barriers protect the atomic sequences let hasSideEffects = 1 in { -def Int_MemBarrierV7 : AInoP<(outs), (ins), - Pseudo, NoItinerary, - "dmb", "", - [(ARMMemBarrierV7)]>, - Requires<[IsARM, HasV7]> { +def DMBsy : AInoP<(outs), (ins), MiscFrm, NoItinerary, "dmb", "", + [(ARMMemBarrier)]>, Requires<[IsARM, HasDB]> { let Inst{31-4} = 0xf57ff05; // FIXME: add support for options other than a full system DMB // See DMB disassembly-only variants below. let Inst{3-0} = 0b1111; } -def Int_SyncBarrierV7 : AInoP<(outs), (ins), - Pseudo, NoItinerary, - "dsb", "", - [(ARMSyncBarrierV7)]>, - Requires<[IsARM, HasV7]> { +def DSBsy : AInoP<(outs), (ins), MiscFrm, NoItinerary, "dsb", "", + [(ARMSyncBarrier)]>, Requires<[IsARM, HasDB]> { let Inst{31-4} = 0xf57ff04; // FIXME: add support for options other than a full system DSB // See DSB disassembly-only variants below. let Inst{3-0} = 0b1111; } -def Int_MemBarrierV6 : AInoP<(outs), (ins GPR:$zero), - Pseudo, NoItinerary, +def DMB_MCR : AInoP<(outs), (ins GPR:$zero), MiscFrm, NoItinerary, "mcr", "\tp15, 0, $zero, c7, c10, 5", - [(ARMMemBarrierV6 GPR:$zero)]>, + [(ARMMemBarrierMCR GPR:$zero)]>, Requires<[IsARM, HasV6]> { // FIXME: add support for options other than a full system DMB // FIXME: add encoding } -def Int_SyncBarrierV6 : AInoP<(outs), (ins GPR:$zero), - Pseudo, NoItinerary, +def DSB_MCR : AInoP<(outs), (ins GPR:$zero), MiscFrm, NoItinerary, "mcr", "\tp15, 0, $zero, c7, c10, 4", - [(ARMSyncBarrierV6 GPR:$zero)]>, + [(ARMSyncBarrierMCR GPR:$zero)]>, Requires<[IsARM, HasV6]> { // FIXME: add support for options other than a full system DSB // FIXME: add encoding } } -// Helper class for multiclass MemB -- for disassembly only -class AMBI - : AInoP<(outs), (ins), MiscFrm, NoItinerary, opc, asm, - [/* For disassembly only; pattern left blank */]>, - Requires<[IsARM, HasV7]> { - let Inst{31-20} = 0xf57; -} - -multiclass MemB op7_4, string opc> { - - def st : AMBI { - let Inst{7-4} = op7_4; - let Inst{3-0} = 0b1110; - } - - def ish : AMBI { - let Inst{7-4} = op7_4; - let Inst{3-0} = 0b1011; - } - - def ishst : AMBI { - let Inst{7-4} = op7_4; - let Inst{3-0} = 0b1010; - } - - def nsh : AMBI { - let Inst{7-4} = op7_4; - let Inst{3-0} = 0b0111; - } - - def nshst : AMBI { - let Inst{7-4} = op7_4; - let Inst{3-0} = 0b0110; - } +// Memory Barrier Operations Variants -- for disassembly only - def osh : AMBI { - let Inst{7-4} = op7_4; - let Inst{3-0} = 0b0011; - } +def memb_opt : Operand { + let PrintMethod = "printMemBOption"; +} - def oshst : AMBI { - let Inst{7-4} = op7_4; - let Inst{3-0} = 0b0010; - } +class AMBI op7_4, string opc> + : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary, opc, "\t$opt", + [/* For disassembly only; pattern left blank */]>, + Requires<[IsARM, HasDB]> { + let Inst{31-8} = 0xf57ff0; + let Inst{7-4} = op7_4; } // These DMB variants are for disassembly only. -defm DMB : MemB<0b0101, "dmb">; +def DMBvar : AMBI<0b0101, "dmb">; // These DSB variants are for disassembly only. -defm DSB : MemB<0b0100, "dsb">; +def DSBvar : AMBI<0b0100, "dsb">; // ISB has only full system option -- for disassembly only -def ISBsy : AMBI<"isb", ""> { - let Inst{7-4} = 0b0110; +def ISBsy : AInoP<(outs), (ins), MiscFrm, NoItinerary, "isb", "", []>, + Requires<[IsARM, HasDB]> { + let Inst{31-4} = 0xf57ff06; let Inst{3-0} = 0b1111; } diff --git a/lib/Target/ARM/ARMInstrNEON.td b/lib/Target/ARM/ARMInstrNEON.td index 7f7eb98..4d2f116 100644 --- a/lib/Target/ARM/ARMInstrNEON.td +++ b/lib/Target/ARM/ARMInstrNEON.td @@ -93,6 +93,11 @@ def NEONzip : SDNode<"ARMISD::VZIP", SDTARMVSHUF2>; def NEONuzp : SDNode<"ARMISD::VUZP", SDTARMVSHUF2>; def NEONtrn : SDNode<"ARMISD::VTRN", SDTARMVSHUF2>; +def SDTARMVMULL : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisInt<1>, + SDTCisSameAs<1, 2>]>; +def NEONvmulls : SDNode<"ARMISD::VMULLs", SDTARMVMULL>; +def NEONvmullu : SDNode<"ARMISD::VMULLu", SDTARMVMULL>; + def SDTARMFMAX : SDTypeProfile<1, 2, [SDTCisVT<0, f32>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>]>; def NEONfmax : SDNode<"ARMISD::FMAX", SDTARMFMAX>; @@ -100,14 +105,14 @@ def NEONfmin : SDNode<"ARMISD::FMIN", SDTARMFMAX>; def NEONimmAllZerosV: PatLeaf<(NEONvmovImm (i32 timm)), [{ ConstantSDNode *ConstVal = cast(N->getOperand(0)); - unsigned EltBits; + unsigned EltBits = 0; uint64_t EltVal = ARM_AM::decodeNEONModImm(ConstVal->getZExtValue(), EltBits); return (EltBits == 32 && EltVal == 0); }]>; def NEONimmAllOnesV: PatLeaf<(NEONvmovImm (i32 timm)), [{ ConstantSDNode *ConstVal = cast(N->getOperand(0)); - unsigned EltBits; + unsigned EltBits = 0; uint64_t EltVal = ARM_AM::decodeNEONModImm(ConstVal->getZExtValue(), EltBits); return (EltBits == 8 && EltVal == 0xff); }]>; @@ -124,15 +129,16 @@ def nModImm : Operand { // NEON load / store instructions //===----------------------------------------------------------------------===// -let mayLoad = 1, neverHasSideEffects = 1 in { // Use vldmia to load a Q register as a D register pair. // This is equivalent to VLDMD except that it has a Q register operand // instead of a pair of D registers. def VLDMQ - : AXDI5<(outs QPR:$dst), (ins addrmode5:$addr, pred:$p), + : AXDI4<(outs QPR:$dst), (ins addrmode4:$addr, pred:$p), IndexModeNone, IIC_fpLoadm, - "vldm${addr:submode}${p}\t${addr:base}, ${dst:dregpair}", "", []>; + "vldm${addr:submode}${p}\t$addr, ${dst:dregpair}", "", + [(set QPR:$dst, (v2f64 (load addrmode4:$addr)))]>; +let mayLoad = 1, neverHasSideEffects = 1 in { // Use vld1 to load a Q register as a D register pair. // This alternative to VLDMQ allows an alignment to be specified. // This is equivalent to VLD1q64 except that it has a Q register operand. @@ -141,15 +147,16 @@ def VLD1q IIC_VLD1, "vld1", "64", "${dst:dregpair}, $addr", "", []>; } // mayLoad = 1, neverHasSideEffects = 1 -let mayStore = 1, neverHasSideEffects = 1 in { // Use vstmia to store a Q register as a D register pair. // This is equivalent to VSTMD except that it has a Q register operand // instead of a pair of D registers. def VSTMQ - : AXDI5<(outs), (ins QPR:$src, addrmode5:$addr, pred:$p), + : AXDI4<(outs), (ins QPR:$src, addrmode4:$addr, pred:$p), IndexModeNone, IIC_fpStorem, - "vstm${addr:submode}${p}\t${addr:base}, ${src:dregpair}", "", []>; + "vstm${addr:submode}${p}\t$addr, ${src:dregpair}", "", + [(store (v2f64 QPR:$src), addrmode4:$addr)]>; +let mayStore = 1, neverHasSideEffects = 1 in { // Use vst1 to store a Q register as a D register pair. // This alternative to VSTMQ allows an alignment to be specified. // This is equivalent to VST1q64 except that it has a Q register operand. @@ -160,6 +167,25 @@ def VST1q let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in { +// Classes for VLD* pseudo-instructions with multi-register operands. +// These are expanded to real instructions after register allocation. +class VLDQPseudo + : PseudoNLdSt<(outs QPR:$dst), (ins addrmode6:$addr), IIC_VST, "">; +class VLDQWBPseudo + : PseudoNLdSt<(outs QPR:$dst, GPR:$wb), + (ins addrmode6:$addr, am6offset:$offset), IIC_VST, + "$addr.addr = $wb">; +class VLDQQPseudo + : PseudoNLdSt<(outs QQPR:$dst), (ins addrmode6:$addr), IIC_VST, "">; +class VLDQQWBPseudo + : PseudoNLdSt<(outs QQPR:$dst, GPR:$wb), + (ins addrmode6:$addr, am6offset:$offset), IIC_VST, + "$addr.addr = $wb">; +class VLDQQQQWBPseudo + : PseudoNLdSt<(outs QQQQPR:$dst, GPR:$wb), + (ins addrmode6:$addr, am6offset:$offset, QQQQPR:$src), IIC_VST, + "$addr.addr = $wb, $src = $dst">; + // VLD1 : Vector Load (multiple single elements) class VLD1D op7_4, string Dt> : NLdSt<0,0b10,0b0111,op7_4, (outs DPR:$dst), @@ -180,6 +206,11 @@ def VLD1q16 : VLD1Q<0b0100, "16">; def VLD1q32 : VLD1Q<0b1000, "32">; def VLD1q64 : VLD1Q<0b1100, "64">; +def VLD1q8Pseudo : VLDQPseudo; +def VLD1q16Pseudo : VLDQPseudo; +def VLD1q32Pseudo : VLDQPseudo; +def VLD1q64Pseudo : VLDQPseudo; + // ...with address register writeback: class VLD1DWB op7_4, string Dt> : NLdSt<0,0b10,0b0111,op7_4, (outs DPR:$dst, GPR:$wb), @@ -202,6 +233,11 @@ def VLD1q16_UPD : VLD1QWB<0b0100, "16">; def VLD1q32_UPD : VLD1QWB<0b1000, "32">; def VLD1q64_UPD : VLD1QWB<0b1100, "64">; +def VLD1q8Pseudo_UPD : VLDQWBPseudo; +def VLD1q16Pseudo_UPD : VLDQWBPseudo; +def VLD1q32Pseudo_UPD : VLDQWBPseudo; +def VLD1q64Pseudo_UPD : VLDQWBPseudo; + // ...with 3 registers (some of these are only for the disassembler): class VLD1D3 op7_4, string Dt> : NLdSt<0,0b10,0b0110,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3), @@ -222,6 +258,9 @@ def VLD1d16T_UPD : VLD1D3WB<0b0100, "16">; def VLD1d32T_UPD : VLD1D3WB<0b1000, "32">; def VLD1d64T_UPD : VLD1D3WB<0b1100, "64">; +def VLD1d64TPseudo : VLDQQPseudo; +def VLD1d64TPseudo_UPD : VLDQQWBPseudo; + // ...with 4 registers (some of these are only for the disassembler): class VLD1D4 op7_4, string Dt> : NLdSt<0,0b10,0b0010,op7_4,(outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4), @@ -244,6 +283,9 @@ def VLD1d16Q_UPD : VLD1D4WB<0b0100, "16">; def VLD1d32Q_UPD : VLD1D4WB<0b1000, "32">; def VLD1d64Q_UPD : VLD1D4WB<0b1100, "64">; +def VLD1d64QPseudo : VLDQQPseudo; +def VLD1d64QPseudo_UPD : VLDQQWBPseudo; + // VLD2 : Vector Load (multiple 2-element structures) class VLD2D op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b10, op11_8, op7_4, (outs DPR:$dst1, DPR:$dst2), @@ -263,6 +305,14 @@ def VLD2q8 : VLD2Q<0b0000, "8">; def VLD2q16 : VLD2Q<0b0100, "16">; def VLD2q32 : VLD2Q<0b1000, "32">; +def VLD2d8Pseudo : VLDQPseudo; +def VLD2d16Pseudo : VLDQPseudo; +def VLD2d32Pseudo : VLDQPseudo; + +def VLD2q8Pseudo : VLDQQPseudo; +def VLD2q16Pseudo : VLDQQPseudo; +def VLD2q32Pseudo : VLDQQPseudo; + // ...with address register writeback: class VLD2DWB op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b10, op11_8, op7_4, (outs DPR:$dst1, DPR:$dst2, GPR:$wb), @@ -284,6 +334,14 @@ def VLD2q8_UPD : VLD2QWB<0b0000, "8">; def VLD2q16_UPD : VLD2QWB<0b0100, "16">; def VLD2q32_UPD : VLD2QWB<0b1000, "32">; +def VLD2d8Pseudo_UPD : VLDQWBPseudo; +def VLD2d16Pseudo_UPD : VLDQWBPseudo; +def VLD2d32Pseudo_UPD : VLDQWBPseudo; + +def VLD2q8Pseudo_UPD : VLDQQWBPseudo; +def VLD2q16Pseudo_UPD : VLDQQWBPseudo; +def VLD2q32Pseudo_UPD : VLDQQWBPseudo; + // ...with double-spaced registers (for disassembly only): def VLD2b8 : VLD2D<0b1001, 0b0000, "8">; def VLD2b16 : VLD2D<0b1001, 0b0100, "16">; @@ -302,6 +360,10 @@ def VLD3d8 : VLD3D<0b0100, 0b0000, "8">; def VLD3d16 : VLD3D<0b0100, 0b0100, "16">; def VLD3d32 : VLD3D<0b0100, 0b1000, "32">; +def VLD3d8Pseudo : VLDQQPseudo; +def VLD3d16Pseudo : VLDQQPseudo; +def VLD3d32Pseudo : VLDQQPseudo; + // ...with address register writeback: class VLD3DWB op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b10, op11_8, op7_4, @@ -314,6 +376,10 @@ def VLD3d8_UPD : VLD3DWB<0b0100, 0b0000, "8">; def VLD3d16_UPD : VLD3DWB<0b0100, 0b0100, "16">; def VLD3d32_UPD : VLD3DWB<0b0100, 0b1000, "32">; +def VLD3d8Pseudo_UPD : VLDQQWBPseudo; +def VLD3d16Pseudo_UPD : VLDQQWBPseudo; +def VLD3d32Pseudo_UPD : VLDQQWBPseudo; + // ...with double-spaced registers (non-updating versions for disassembly only): def VLD3q8 : VLD3D<0b0101, 0b0000, "8">; def VLD3q16 : VLD3D<0b0101, 0b0100, "16">; @@ -322,10 +388,14 @@ def VLD3q8_UPD : VLD3DWB<0b0101, 0b0000, "8">; def VLD3q16_UPD : VLD3DWB<0b0101, 0b0100, "16">; def VLD3q32_UPD : VLD3DWB<0b0101, 0b1000, "32">; +def VLD3q8Pseudo_UPD : VLDQQQQWBPseudo; +def VLD3q16Pseudo_UPD : VLDQQQQWBPseudo; +def VLD3q32Pseudo_UPD : VLDQQQQWBPseudo; + // ...alternate versions to be allocated odd register numbers: -def VLD3q8odd_UPD : VLD3DWB<0b0101, 0b0000, "8">; -def VLD3q16odd_UPD : VLD3DWB<0b0101, 0b0100, "16">; -def VLD3q32odd_UPD : VLD3DWB<0b0101, 0b1000, "32">; +def VLD3q8oddPseudo_UPD : VLDQQQQWBPseudo; +def VLD3q16oddPseudo_UPD : VLDQQQQWBPseudo; +def VLD3q32oddPseudo_UPD : VLDQQQQWBPseudo; // VLD4 : Vector Load (multiple 4-element structures) class VLD4D op11_8, bits<4> op7_4, string Dt> @@ -338,6 +408,10 @@ def VLD4d8 : VLD4D<0b0000, 0b0000, "8">; def VLD4d16 : VLD4D<0b0000, 0b0100, "16">; def VLD4d32 : VLD4D<0b0000, 0b1000, "32">; +def VLD4d8Pseudo : VLDQQPseudo; +def VLD4d16Pseudo : VLDQQPseudo; +def VLD4d32Pseudo : VLDQQPseudo; + // ...with address register writeback: class VLD4DWB op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b10, op11_8, op7_4, @@ -350,6 +424,10 @@ def VLD4d8_UPD : VLD4DWB<0b0000, 0b0000, "8">; def VLD4d16_UPD : VLD4DWB<0b0000, 0b0100, "16">; def VLD4d32_UPD : VLD4DWB<0b0000, 0b1000, "32">; +def VLD4d8Pseudo_UPD : VLDQQWBPseudo; +def VLD4d16Pseudo_UPD : VLDQQWBPseudo; +def VLD4d32Pseudo_UPD : VLDQQWBPseudo; + // ...with double-spaced registers (non-updating versions for disassembly only): def VLD4q8 : VLD4D<0b0001, 0b0000, "8">; def VLD4q16 : VLD4D<0b0001, 0b0100, "16">; @@ -358,10 +436,14 @@ def VLD4q8_UPD : VLD4DWB<0b0001, 0b0000, "8">; def VLD4q16_UPD : VLD4DWB<0b0001, 0b0100, "16">; def VLD4q32_UPD : VLD4DWB<0b0001, 0b1000, "32">; +def VLD4q8Pseudo_UPD : VLDQQQQWBPseudo; +def VLD4q16Pseudo_UPD : VLDQQQQWBPseudo; +def VLD4q32Pseudo_UPD : VLDQQQQWBPseudo; + // ...alternate versions to be allocated odd register numbers: -def VLD4q8odd_UPD : VLD4DWB<0b0001, 0b0000, "8">; -def VLD4q16odd_UPD : VLD4DWB<0b0001, 0b0100, "16">; -def VLD4q32odd_UPD : VLD4DWB<0b0001, 0b1000, "32">; +def VLD4q8oddPseudo_UPD : VLDQQQQWBPseudo; +def VLD4q16oddPseudo_UPD : VLDQQQQWBPseudo; +def VLD4q32oddPseudo_UPD : VLDQQQQWBPseudo; // VLD1LN : Vector Load (single element to one lane) // FIXME: Not yet implemented. @@ -486,6 +568,25 @@ def VLD4LNq32_UPD : VLD4LNWB<0b1011, {?,1,?,?}, "32">; let mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 in { +// Classes for VST* pseudo-instructions with multi-register operands. +// These are expanded to real instructions after register allocation. +class VSTQPseudo + : PseudoNLdSt<(outs), (ins addrmode6:$addr, QPR:$src), IIC_VST, "">; +class VSTQWBPseudo + : PseudoNLdSt<(outs GPR:$wb), + (ins addrmode6:$addr, am6offset:$offset, QPR:$src), IIC_VST, + "$addr.addr = $wb">; +class VSTQQPseudo + : PseudoNLdSt<(outs), (ins addrmode6:$addr, QQPR:$src), IIC_VST, "">; +class VSTQQWBPseudo + : PseudoNLdSt<(outs GPR:$wb), + (ins addrmode6:$addr, am6offset:$offset, QQPR:$src), IIC_VST, + "$addr.addr = $wb">; +class VSTQQQQWBPseudo + : PseudoNLdSt<(outs GPR:$wb), + (ins addrmode6:$addr, am6offset:$offset, QQQQPR:$src), IIC_VST, + "$addr.addr = $wb">; + // VST1 : Vector Store (multiple single elements) class VST1D op7_4, string Dt> : NLdSt<0,0b00,0b0111,op7_4, (outs), (ins addrmode6:$addr, DPR:$src), IIC_VST, @@ -505,6 +606,11 @@ def VST1q16 : VST1Q<0b0100, "16">; def VST1q32 : VST1Q<0b1000, "32">; def VST1q64 : VST1Q<0b1100, "64">; +def VST1q8Pseudo : VSTQPseudo; +def VST1q16Pseudo : VSTQPseudo; +def VST1q32Pseudo : VSTQPseudo; +def VST1q64Pseudo : VSTQPseudo; + // ...with address register writeback: class VST1DWB op7_4, string Dt> : NLdSt<0, 0b00, 0b0111, op7_4, (outs GPR:$wb), @@ -525,6 +631,11 @@ def VST1q16_UPD : VST1QWB<0b0100, "16">; def VST1q32_UPD : VST1QWB<0b1000, "32">; def VST1q64_UPD : VST1QWB<0b1100, "64">; +def VST1q8Pseudo_UPD : VSTQWBPseudo; +def VST1q16Pseudo_UPD : VSTQWBPseudo; +def VST1q32Pseudo_UPD : VSTQWBPseudo; +def VST1q64Pseudo_UPD : VSTQWBPseudo; + // ...with 3 registers (some of these are only for the disassembler): class VST1D3 op7_4, string Dt> : NLdSt<0, 0b00, 0b0110, op7_4, (outs), @@ -547,6 +658,9 @@ def VST1d16T_UPD : VST1D3WB<0b0100, "16">; def VST1d32T_UPD : VST1D3WB<0b1000, "32">; def VST1d64T_UPD : VST1D3WB<0b1100, "64">; +def VST1d64TPseudo : VSTQQPseudo; +def VST1d64TPseudo_UPD : VSTQQWBPseudo; + // ...with 4 registers (some of these are only for the disassembler): class VST1D4 op7_4, string Dt> : NLdSt<0, 0b00, 0b0010, op7_4, (outs), @@ -570,6 +684,9 @@ def VST1d16Q_UPD : VST1D4WB<0b0100, "16">; def VST1d32Q_UPD : VST1D4WB<0b1000, "32">; def VST1d64Q_UPD : VST1D4WB<0b1100, "64">; +def VST1d64QPseudo : VSTQQPseudo; +def VST1d64QPseudo_UPD : VSTQQWBPseudo; + // VST2 : Vector Store (multiple 2-element structures) class VST2D op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b00, op11_8, op7_4, (outs), @@ -589,6 +706,14 @@ def VST2q8 : VST2Q<0b0000, "8">; def VST2q16 : VST2Q<0b0100, "16">; def VST2q32 : VST2Q<0b1000, "32">; +def VST2d8Pseudo : VSTQPseudo; +def VST2d16Pseudo : VSTQPseudo; +def VST2d32Pseudo : VSTQPseudo; + +def VST2q8Pseudo : VSTQQPseudo; +def VST2q16Pseudo : VSTQQPseudo; +def VST2q32Pseudo : VSTQQPseudo; + // ...with address register writeback: class VST2DWB op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b00, op11_8, op7_4, (outs GPR:$wb), @@ -610,6 +735,14 @@ def VST2q8_UPD : VST2QWB<0b0000, "8">; def VST2q16_UPD : VST2QWB<0b0100, "16">; def VST2q32_UPD : VST2QWB<0b1000, "32">; +def VST2d8Pseudo_UPD : VSTQWBPseudo; +def VST2d16Pseudo_UPD : VSTQWBPseudo; +def VST2d32Pseudo_UPD : VSTQWBPseudo; + +def VST2q8Pseudo_UPD : VSTQQWBPseudo; +def VST2q16Pseudo_UPD : VSTQQWBPseudo; +def VST2q32Pseudo_UPD : VSTQQWBPseudo; + // ...with double-spaced registers (for disassembly only): def VST2b8 : VST2D<0b1001, 0b0000, "8">; def VST2b16 : VST2D<0b1001, 0b0100, "16">; @@ -628,6 +761,10 @@ def VST3d8 : VST3D<0b0100, 0b0000, "8">; def VST3d16 : VST3D<0b0100, 0b0100, "16">; def VST3d32 : VST3D<0b0100, 0b1000, "32">; +def VST3d8Pseudo : VSTQQPseudo; +def VST3d16Pseudo : VSTQQPseudo; +def VST3d32Pseudo : VSTQQPseudo; + // ...with address register writeback: class VST3DWB op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b00, op11_8, op7_4, (outs GPR:$wb), @@ -640,6 +777,10 @@ def VST3d8_UPD : VST3DWB<0b0100, 0b0000, "8">; def VST3d16_UPD : VST3DWB<0b0100, 0b0100, "16">; def VST3d32_UPD : VST3DWB<0b0100, 0b1000, "32">; +def VST3d8Pseudo_UPD : VSTQQWBPseudo; +def VST3d16Pseudo_UPD : VSTQQWBPseudo; +def VST3d32Pseudo_UPD : VSTQQWBPseudo; + // ...with double-spaced registers (non-updating versions for disassembly only): def VST3q8 : VST3D<0b0101, 0b0000, "8">; def VST3q16 : VST3D<0b0101, 0b0100, "16">; @@ -648,10 +789,14 @@ def VST3q8_UPD : VST3DWB<0b0101, 0b0000, "8">; def VST3q16_UPD : VST3DWB<0b0101, 0b0100, "16">; def VST3q32_UPD : VST3DWB<0b0101, 0b1000, "32">; +def VST3q8Pseudo_UPD : VSTQQQQWBPseudo; +def VST3q16Pseudo_UPD : VSTQQQQWBPseudo; +def VST3q32Pseudo_UPD : VSTQQQQWBPseudo; + // ...alternate versions to be allocated odd register numbers: -def VST3q8odd_UPD : VST3DWB<0b0101, 0b0000, "8">; -def VST3q16odd_UPD : VST3DWB<0b0101, 0b0100, "16">; -def VST3q32odd_UPD : VST3DWB<0b0101, 0b1000, "32">; +def VST3q8oddPseudo_UPD : VSTQQQQWBPseudo; +def VST3q16oddPseudo_UPD : VSTQQQQWBPseudo; +def VST3q32oddPseudo_UPD : VSTQQQQWBPseudo; // VST4 : Vector Store (multiple 4-element structures) class VST4D op11_8, bits<4> op7_4, string Dt> @@ -664,6 +809,10 @@ def VST4d8 : VST4D<0b0000, 0b0000, "8">; def VST4d16 : VST4D<0b0000, 0b0100, "16">; def VST4d32 : VST4D<0b0000, 0b1000, "32">; +def VST4d8Pseudo : VSTQQPseudo; +def VST4d16Pseudo : VSTQQPseudo; +def VST4d32Pseudo : VSTQQPseudo; + // ...with address register writeback: class VST4DWB op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b00, op11_8, op7_4, (outs GPR:$wb), @@ -676,6 +825,10 @@ def VST4d8_UPD : VST4DWB<0b0000, 0b0000, "8">; def VST4d16_UPD : VST4DWB<0b0000, 0b0100, "16">; def VST4d32_UPD : VST4DWB<0b0000, 0b1000, "32">; +def VST4d8Pseudo_UPD : VSTQQWBPseudo; +def VST4d16Pseudo_UPD : VSTQQWBPseudo; +def VST4d32Pseudo_UPD : VSTQQWBPseudo; + // ...with double-spaced registers (non-updating versions for disassembly only): def VST4q8 : VST4D<0b0001, 0b0000, "8">; def VST4q16 : VST4D<0b0001, 0b0100, "16">; @@ -684,10 +837,14 @@ def VST4q8_UPD : VST4DWB<0b0001, 0b0000, "8">; def VST4q16_UPD : VST4DWB<0b0001, 0b0100, "16">; def VST4q32_UPD : VST4DWB<0b0001, 0b1000, "32">; +def VST4q8Pseudo_UPD : VSTQQQQWBPseudo; +def VST4q16Pseudo_UPD : VSTQQQQWBPseudo; +def VST4q32Pseudo_UPD : VSTQQQQWBPseudo; + // ...alternate versions to be allocated odd register numbers: -def VST4q8odd_UPD : VST4DWB<0b0001, 0b0000, "8">; -def VST4q16odd_UPD : VST4DWB<0b0001, 0b0100, "16">; -def VST4q32odd_UPD : VST4DWB<0b0001, 0b1000, "32">; +def VST4q8oddPseudo_UPD : VSTQQQQWBPseudo; +def VST4q16oddPseudo_UPD : VSTQQQQWBPseudo; +def VST4q32oddPseudo_UPD : VSTQQQQWBPseudo; // VST1LN : Vector Store (single element from one lane) // FIXME: Not yet implemented. @@ -879,6 +1036,15 @@ class N2VQInt op24_23, bits<2> op21_20, bits<2> op19_18, (ins QPR:$src), itin, OpcodeStr, Dt, "$dst, $src", "", [(set QPR:$dst, (ResTy (IntOp (OpTy QPR:$src))))]>; +// Narrow 2-register operations. +class N2VN op24_23, bits<2> op21_20, bits<2> op19_18, + bits<2> op17_16, bits<5> op11_7, bit op6, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType TyD, ValueType TyQ, SDNode OpNode> + : N2V; + // Narrow 2-register intrinsics. class N2VNInt op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, bits<5> op11_7, bit op6, bit op4, @@ -888,14 +1054,14 @@ class N2VNInt op24_23, bits<2> op21_20, bits<2> op19_18, (ins QPR:$src), itin, OpcodeStr, Dt, "$dst, $src", "", [(set DPR:$dst, (TyD (IntOp (TyQ QPR:$src))))]>; -// Long 2-register intrinsics (currently only used for VMOVL). -class N2VLInt op24_23, bits<2> op21_20, bits<2> op19_18, - bits<2> op17_16, bits<5> op11_7, bit op6, bit op4, - InstrItinClass itin, string OpcodeStr, string Dt, - ValueType TyQ, ValueType TyD, Intrinsic IntOp> +// Long 2-register operations (currently only used for VMOVL). +class N2VL op24_23, bits<2> op21_20, bits<2> op19_18, + bits<2> op17_16, bits<5> op11_7, bit op6, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType TyQ, ValueType TyD, SDNode OpNode> : N2V; + [(set QPR:$dst, (TyQ (OpNode (TyD DPR:$src))))]>; // 2-register shuffles (VTRN/VZIP/VUZP), both double- and quad-register. class N2VDShuffle op19_18, bits<5> op11_7, string OpcodeStr, string Dt> @@ -1150,6 +1316,24 @@ class N3VQMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, (ResTy (NEONvduplane (OpTy DPR_8:$src3), imm:$lane)))))))]>; +// Neon Intrinsic-Op instructions (VABA): double- and quad-register. +class N3VDIntOp op21_20, bits<4> op11_8, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType Ty, Intrinsic IntOp, SDNode OpNode> + : N3V; +class N3VQIntOp op21_20, bits<4> op11_8, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType Ty, Intrinsic IntOp, SDNode OpNode> + : N3V; + // Neon 3-argument intrinsics, both double- and quad-register. // The destination register is also used as the first source operand register. class N3VDInt3 op21_20, bits<4> op11_8, bit op4, @@ -1169,6 +1353,53 @@ class N3VQInt3 op21_20, bits<4> op11_8, bit op4, [(set QPR:$dst, (ResTy (IntOp (OpTy QPR:$src1), (OpTy QPR:$src2), (OpTy QPR:$src3))))]>; +// Long Multiply-Add/Sub operations. +class N3VLMulOp op21_20, bits<4> op11_8, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType TyQ, ValueType TyD, SDNode MulOp, SDNode OpNode> + : N3V; +class N3VLMulOpSL op21_20, bits<4> op11_8, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType TyQ, ValueType TyD, SDNode MulOp, SDNode OpNode> + : N3V; +class N3VLMulOpSL16 op21_20, bits<4> op11_8, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType TyQ, ValueType TyD, SDNode MulOp, SDNode OpNode> + : N3V; + +// Long Intrinsic-Op vector operations with explicit extend (VABAL). +class N3VLIntExtOp op21_20, bits<4> op11_8, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType TyQ, ValueType TyD, Intrinsic IntOp, SDNode ExtOp, + SDNode OpNode> + : N3V; + // Neon Long 3-argument intrinsic. The destination register is // a quad-register and is also used as the first source operand register. class N3VLInt3 op21_20, bits<4> op11_8, bit op4, @@ -1217,6 +1448,61 @@ class N3VNInt op21_20, bits<4> op11_8, bit op4, let isCommutable = Commutable; } +// Long 3-register operations. +class N3VL op21_20, bits<4> op11_8, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType TyQ, ValueType TyD, SDNode OpNode, bit Commutable> + : N3V { + let isCommutable = Commutable; +} +class N3VLSL op21_20, bits<4> op11_8, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType TyQ, ValueType TyD, SDNode OpNode> + : N3V; +class N3VLSL16 op21_20, bits<4> op11_8, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType TyQ, ValueType TyD, SDNode OpNode> + : N3V; + +// Long 3-register operations with explicitly extended operands. +class N3VLExt op21_20, bits<4> op11_8, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType TyQ, ValueType TyD, SDNode OpNode, SDNode ExtOp, + bit Commutable> + : N3V { + let isCommutable = Commutable; +} + +// Long 3-register intrinsics with explicit extend (VABDL). +class N3VLIntExt op21_20, bits<4> op11_8, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType TyQ, ValueType TyD, Intrinsic IntOp, SDNode ExtOp, + bit Commutable> + : N3V { + let isCommutable = Commutable; +} + // Long 3-register intrinsics. class N3VLInt op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, @@ -1248,14 +1534,15 @@ class N3VLIntSL16 op21_20, bits<4> op11_8, (OpTy (NEONvduplane (OpTy DPR_8:$src2), imm:$lane)))))]>; -// Wide 3-register intrinsics. -class N3VWInt op21_20, bits<4> op11_8, bit op4, - string OpcodeStr, string Dt, ValueType TyQ, ValueType TyD, - Intrinsic IntOp, bit Commutable> +// Wide 3-register operations. +class N3VW op21_20, bits<4> op11_8, bit op4, + string OpcodeStr, string Dt, ValueType TyQ, ValueType TyD, + SDNode OpNode, SDNode ExtOp, bit Commutable> : N3V { + [(set QPR:$dst, (OpNode (TyQ QPR:$src1), + (TyQ (ExtOp (TyD DPR:$src2)))))]> { let isCommutable = Commutable; } @@ -1488,6 +1775,23 @@ multiclass N3V_QHSD op11_8, bit op4, } +// Neon Narrowing 2-register vector operations, +// source operand element sizes of 16, 32 and 64 bits: +multiclass N2VN_HSD op24_23, bits<2> op21_20, bits<2> op17_16, + bits<5> op11_7, bit op6, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + SDNode OpNode> { + def v8i8 : N2VN; + def v4i16 : N2VN; + def v2i32 : N2VN; +} + // Neon Narrowing 2-register vector intrinsics, // source operand element sizes of 16, 32 and 64 bits: multiclass N2VNInt_HSD op24_23, bits<2> op21_20, bits<2> op17_16, @@ -1508,14 +1812,14 @@ multiclass N2VNInt_HSD op24_23, bits<2> op21_20, bits<2> op17_16, // Neon Lengthening 2-register vector intrinsic (currently specific to VMOVL). // source operand element sizes of 16, 32 and 64 bits: -multiclass N2VLInt_QHS op24_23, bits<5> op11_7, bit op6, bit op4, - string OpcodeStr, string Dt, Intrinsic IntOp> { - def v8i16 : N2VLInt; - def v4i32 : N2VLInt; - def v2i64 : N2VLInt; +multiclass N2VL_QHS op24_23, bits<5> op11_7, bit op6, bit op4, + string OpcodeStr, string Dt, SDNode OpNode> { + def v8i16 : N2VL; + def v4i32 : N2VL; + def v2i64 : N2VL; } @@ -1607,6 +1911,47 @@ multiclass N3VNInt_HSD op11_8, bit op4, } +// Neon Long 3-register vector operations. + +multiclass N3VL_QHS op11_8, bit op4, + InstrItinClass itin16, InstrItinClass itin32, + string OpcodeStr, string Dt, + SDNode OpNode, bit Commutable = 0> { + def v8i16 : N3VL; + def v4i32 : N3VL; + def v2i64 : N3VL; +} + +multiclass N3VLSL_HS op11_8, + InstrItinClass itin, string OpcodeStr, string Dt, + SDNode OpNode> { + def v4i16 : N3VLSL16; + def v2i32 : N3VLSL; +} + +multiclass N3VLExt_QHS op11_8, bit op4, + InstrItinClass itin16, InstrItinClass itin32, + string OpcodeStr, string Dt, + SDNode OpNode, SDNode ExtOp, bit Commutable = 0> { + def v8i16 : N3VLExt; + def v4i32 : N3VLExt; + def v2i64 : N3VLExt; +} + // Neon Long 3-register vector intrinsics. // First with only element sizes of 16 and 32 bits: @@ -1643,21 +1988,36 @@ multiclass N3VLInt_QHS op11_8, bit op4, v8i16, v8i8, IntOp, Commutable>; } +// ....with explicit extend (VABDL). +multiclass N3VLIntExt_QHS op11_8, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + Intrinsic IntOp, SDNode ExtOp, bit Commutable = 0> { + def v8i16 : N3VLIntExt; + def v4i32 : N3VLIntExt; + def v2i64 : N3VLIntExt; +} + // Neon Wide 3-register vector intrinsics, // source operand element sizes of 8, 16 and 32 bits: -multiclass N3VWInt_QHS op11_8, bit op4, - string OpcodeStr, string Dt, - Intrinsic IntOp, bit Commutable = 0> { - def v8i16 : N3VWInt; - def v4i32 : N3VWInt; - def v2i64 : N3VWInt; +multiclass N3VW_QHS op11_8, bit op4, + string OpcodeStr, string Dt, + SDNode OpNode, SDNode ExtOp, bit Commutable = 0> { + def v8i16 : N3VW; + def v4i32 : N3VW; + def v2i64 : N3VW; } @@ -1700,6 +2060,29 @@ multiclass N3VMulOpSL_HS op11_8, mul, ShOp>; } +// Neon Intrinsic-Op vector operations, +// element sizes of 8, 16 and 32 bits: +multiclass N3VIntOp_QHS op11_8, bit op4, + InstrItinClass itinD, InstrItinClass itinQ, + string OpcodeStr, string Dt, Intrinsic IntOp, + SDNode OpNode> { + // 64-bit vector types. + def v8i8 : N3VDIntOp; + def v4i16 : N3VDIntOp; + def v2i32 : N3VDIntOp; + + // 128-bit vector types. + def v16i8 : N3VQIntOp; + def v8i16 : N3VQIntOp; + def v4i32 : N3VQIntOp; +} + // Neon 3-argument intrinsics, // element sizes of 8, 16 and 32 bits: multiclass N3VInt3_QHS op11_8, bit op4, @@ -1723,6 +2106,29 @@ multiclass N3VInt3_QHS op11_8, bit op4, } +// Neon Long Multiply-Op vector operations, +// element sizes of 8, 16 and 32 bits: +multiclass N3VLMulOp_QHS op11_8, bit op4, + InstrItinClass itin16, InstrItinClass itin32, + string OpcodeStr, string Dt, SDNode MulOp, + SDNode OpNode> { + def v8i16 : N3VLMulOp; + def v4i32 : N3VLMulOp; + def v2i64 : N3VLMulOp; +} + +multiclass N3VLMulOpSL_HS op11_8, string OpcodeStr, + string Dt, SDNode MulOp, SDNode OpNode> { + def v4i16 : N3VLMulOpSL16; + def v2i32 : N3VLMulOpSL; +} + + // Neon Long 3-argument intrinsics. // First with only element sizes of 16 and 32 bits: @@ -1752,6 +2158,21 @@ multiclass N3VLInt3_QHS op11_8, bit op4, OpcodeStr, !strconcat(Dt, "8"), v8i16, v8i8, IntOp>; } +// ....with explicit extend (VABAL). +multiclass N3VLIntExtOp_QHS op11_8, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + Intrinsic IntOp, SDNode ExtOp, SDNode OpNode> { + def v8i16 : N3VLIntExtOp; + def v4i32 : N3VLIntExtOp; + def v2i64 : N3VLIntExtOp; +} + // Neon 2-register vector intrinsics, // element sizes of 8, 16 and 32 bits: @@ -1996,13 +2417,13 @@ def VADDfd : N3VD<0, 0, 0b00, 0b1101, 0, IIC_VBIND, "vadd", "f32", def VADDfq : N3VQ<0, 0, 0b00, 0b1101, 0, IIC_VBINQ, "vadd", "f32", v4f32, v4f32, fadd, 1>; // VADDL : Vector Add Long (Q = D + D) -defm VADDLs : N3VLInt_QHS<0,1,0b0000,0, IIC_VSHLiD, IIC_VSHLiD, - "vaddl", "s", int_arm_neon_vaddls, 1>; -defm VADDLu : N3VLInt_QHS<1,1,0b0000,0, IIC_VSHLiD, IIC_VSHLiD, - "vaddl", "u", int_arm_neon_vaddlu, 1>; +defm VADDLs : N3VLExt_QHS<0,1,0b0000,0, IIC_VSHLiD, IIC_VSHLiD, + "vaddl", "s", add, sext, 1>; +defm VADDLu : N3VLExt_QHS<1,1,0b0000,0, IIC_VSHLiD, IIC_VSHLiD, + "vaddl", "u", add, zext, 1>; // VADDW : Vector Add Wide (Q = Q + D) -defm VADDWs : N3VWInt_QHS<0,1,0b0001,0, "vaddw", "s", int_arm_neon_vaddws, 0>; -defm VADDWu : N3VWInt_QHS<1,1,0b0001,0, "vaddw", "u", int_arm_neon_vaddwu, 0>; +defm VADDWs : N3VW_QHS<0,1,0b0001,0, "vaddw", "s", add, sext, 0>; +defm VADDWu : N3VW_QHS<1,1,0b0001,0, "vaddw", "u", add, zext, 0>; // VHADD : Vector Halving Add defm VHADDs : N3VInt_QHS<0, 0, 0b0000, 0, N3RegFrm, IIC_VBINi4D, IIC_VBINi4D, IIC_VBINi4Q, IIC_VBINi4Q, @@ -2113,16 +2534,14 @@ def : Pat<(v4i32 (int_arm_neon_vqrdmulh (v4i32 QPR:$src1), (SubReg_i32_lane imm:$lane)))>; // VMULL : Vector Multiply Long (integer and polynomial) (Q = D * D) -defm VMULLs : N3VLInt_QHS<0,1,0b1100,0, IIC_VMULi16D, IIC_VMULi32D, - "vmull", "s", int_arm_neon_vmulls, 1>; -defm VMULLu : N3VLInt_QHS<1,1,0b1100,0, IIC_VMULi16D, IIC_VMULi32D, - "vmull", "u", int_arm_neon_vmullu, 1>; +defm VMULLs : N3VL_QHS<0,1,0b1100,0, IIC_VMULi16D, IIC_VMULi32D, + "vmull", "s", NEONvmulls, 1>; +defm VMULLu : N3VL_QHS<1,1,0b1100,0, IIC_VMULi16D, IIC_VMULi32D, + "vmull", "u", NEONvmullu, 1>; def VMULLp : N3VLInt<0, 1, 0b00, 0b1110, 0, IIC_VMULi16D, "vmull", "p8", v8i16, v8i8, int_arm_neon_vmullp, 1>; -defm VMULLsls : N3VLIntSL_HS<0, 0b1010, IIC_VMULi16D, "vmull", "s", - int_arm_neon_vmulls>; -defm VMULLslu : N3VLIntSL_HS<1, 0b1010, IIC_VMULi16D, "vmull", "u", - int_arm_neon_vmullu>; +defm VMULLsls : N3VLSL_HS<0, 0b1010, IIC_VMULi16D, "vmull", "s", NEONvmulls>; +defm VMULLslu : N3VLSL_HS<1, 0b1010, IIC_VMULi16D, "vmull", "u", NEONvmullu>; // VQDMULL : Vector Saturating Doubling Multiply Long (Q = D * D) defm VQDMULL : N3VLInt_HS<0,1,0b1101,0, IIC_VMULi16D, IIC_VMULi32D, @@ -2172,13 +2591,13 @@ def : Pat<(v4f32 (fadd (v4f32 QPR:$src1), (SubReg_i32_lane imm:$lane)))>; // VMLAL : Vector Multiply Accumulate Long (Q += D * D) -defm VMLALs : N3VLInt3_QHS<0,1,0b1000,0, IIC_VMACi16D, IIC_VMACi32D, - "vmlal", "s", int_arm_neon_vmlals>; -defm VMLALu : N3VLInt3_QHS<1,1,0b1000,0, IIC_VMACi16D, IIC_VMACi32D, - "vmlal", "u", int_arm_neon_vmlalu>; +defm VMLALs : N3VLMulOp_QHS<0,1,0b1000,0, IIC_VMACi16D, IIC_VMACi32D, + "vmlal", "s", NEONvmulls, add>; +defm VMLALu : N3VLMulOp_QHS<1,1,0b1000,0, IIC_VMACi16D, IIC_VMACi32D, + "vmlal", "u", NEONvmullu, add>; -defm VMLALsls : N3VLInt3SL_HS<0, 0b0010, "vmlal", "s", int_arm_neon_vmlals>; -defm VMLALslu : N3VLInt3SL_HS<1, 0b0010, "vmlal", "u", int_arm_neon_vmlalu>; +defm VMLALsls : N3VLMulOpSL_HS<0, 0b0010, "vmlal", "s", NEONvmulls, add>; +defm VMLALslu : N3VLMulOpSL_HS<1, 0b0010, "vmlal", "u", NEONvmullu, add>; // VQDMLAL : Vector Saturating Doubling Multiply Accumulate Long (Q += D * D) defm VQDMLAL : N3VLInt3_HS<0, 1, 0b1001, 0, IIC_VMACi16D, IIC_VMACi32D, @@ -2224,13 +2643,13 @@ def : Pat<(v4f32 (fsub (v4f32 QPR:$src1), (SubReg_i32_lane imm:$lane)))>; // VMLSL : Vector Multiply Subtract Long (Q -= D * D) -defm VMLSLs : N3VLInt3_QHS<0,1,0b1010,0, IIC_VMACi16D, IIC_VMACi32D, - "vmlsl", "s", int_arm_neon_vmlsls>; -defm VMLSLu : N3VLInt3_QHS<1,1,0b1010,0, IIC_VMACi16D, IIC_VMACi32D, - "vmlsl", "u", int_arm_neon_vmlslu>; +defm VMLSLs : N3VLMulOp_QHS<0,1,0b1010,0, IIC_VMACi16D, IIC_VMACi32D, + "vmlsl", "s", NEONvmulls, sub>; +defm VMLSLu : N3VLMulOp_QHS<1,1,0b1010,0, IIC_VMACi16D, IIC_VMACi32D, + "vmlsl", "u", NEONvmullu, sub>; -defm VMLSLsls : N3VLInt3SL_HS<0, 0b0110, "vmlsl", "s", int_arm_neon_vmlsls>; -defm VMLSLslu : N3VLInt3SL_HS<1, 0b0110, "vmlsl", "u", int_arm_neon_vmlslu>; +defm VMLSLsls : N3VLMulOpSL_HS<0, 0b0110, "vmlsl", "s", NEONvmulls, sub>; +defm VMLSLslu : N3VLMulOpSL_HS<1, 0b0110, "vmlsl", "u", NEONvmullu, sub>; // VQDMLSL : Vector Saturating Doubling Multiply Subtract Long (Q -= D * D) defm VQDMLSL : N3VLInt3_HS<0, 1, 0b1011, 0, IIC_VMACi16D, IIC_VMACi32D, @@ -2247,13 +2666,13 @@ def VSUBfd : N3VD<0, 0, 0b10, 0b1101, 0, IIC_VBIND, "vsub", "f32", def VSUBfq : N3VQ<0, 0, 0b10, 0b1101, 0, IIC_VBINQ, "vsub", "f32", v4f32, v4f32, fsub, 0>; // VSUBL : Vector Subtract Long (Q = D - D) -defm VSUBLs : N3VLInt_QHS<0,1,0b0010,0, IIC_VSHLiD, IIC_VSHLiD, - "vsubl", "s", int_arm_neon_vsubls, 1>; -defm VSUBLu : N3VLInt_QHS<1,1,0b0010,0, IIC_VSHLiD, IIC_VSHLiD, - "vsubl", "u", int_arm_neon_vsublu, 1>; +defm VSUBLs : N3VLExt_QHS<0,1,0b0010,0, IIC_VSHLiD, IIC_VSHLiD, + "vsubl", "s", sub, sext, 0>; +defm VSUBLu : N3VLExt_QHS<1,1,0b0010,0, IIC_VSHLiD, IIC_VSHLiD, + "vsubl", "u", sub, zext, 0>; // VSUBW : Vector Subtract Wide (Q = Q - D) -defm VSUBWs : N3VWInt_QHS<0,1,0b0011,0, "vsubw", "s", int_arm_neon_vsubws, 0>; -defm VSUBWu : N3VWInt_QHS<1,1,0b0011,0, "vsubw", "u", int_arm_neon_vsubwu, 0>; +defm VSUBWs : N3VW_QHS<0,1,0b0011,0, "vsubw", "s", sub, sext, 0>; +defm VSUBWu : N3VW_QHS<1,1,0b0011,0, "vsubw", "u", sub, zext, 0>; // VHSUB : Vector Halving Subtract defm VHSUBs : N3VInt_QHS<0, 0, 0b0010, 0, N3RegFrm, IIC_VSUBi4D, IIC_VSUBi4D, IIC_VSUBi4Q, IIC_VSUBi4Q, @@ -2469,32 +2888,32 @@ def VBITq : N3VX<1, 0, 0b10, 0b0001, 1, 1, // VABD : Vector Absolute Difference defm VABDs : N3VInt_QHS<0, 0, 0b0111, 0, N3RegFrm, IIC_VSUBi4D, IIC_VSUBi4D, IIC_VSUBi4Q, IIC_VSUBi4Q, - "vabd", "s", int_arm_neon_vabds, 0>; + "vabd", "s", int_arm_neon_vabds, 1>; defm VABDu : N3VInt_QHS<1, 0, 0b0111, 0, N3RegFrm, IIC_VSUBi4D, IIC_VSUBi4D, IIC_VSUBi4Q, IIC_VSUBi4Q, - "vabd", "u", int_arm_neon_vabdu, 0>; + "vabd", "u", int_arm_neon_vabdu, 1>; def VABDfd : N3VDInt<1, 0, 0b10, 0b1101, 0, N3RegFrm, IIC_VBIND, - "vabd", "f32", v2f32, v2f32, int_arm_neon_vabds, 0>; + "vabd", "f32", v2f32, v2f32, int_arm_neon_vabds, 1>; def VABDfq : N3VQInt<1, 0, 0b10, 0b1101, 0, N3RegFrm, IIC_VBINQ, - "vabd", "f32", v4f32, v4f32, int_arm_neon_vabds, 0>; + "vabd", "f32", v4f32, v4f32, int_arm_neon_vabds, 1>; // VABDL : Vector Absolute Difference Long (Q = | D - D |) -defm VABDLs : N3VLInt_QHS<0,1,0b0111,0, IIC_VSUBi4Q, IIC_VSUBi4Q, - "vabdl", "s", int_arm_neon_vabdls, 0>; -defm VABDLu : N3VLInt_QHS<1,1,0b0111,0, IIC_VSUBi4Q, IIC_VSUBi4Q, - "vabdl", "u", int_arm_neon_vabdlu, 0>; +defm VABDLs : N3VLIntExt_QHS<0,1,0b0111,0, IIC_VSUBi4Q, + "vabdl", "s", int_arm_neon_vabds, zext, 1>; +defm VABDLu : N3VLIntExt_QHS<1,1,0b0111,0, IIC_VSUBi4Q, + "vabdl", "u", int_arm_neon_vabdu, zext, 1>; // VABA : Vector Absolute Difference and Accumulate -defm VABAs : N3VInt3_QHS<0,0,0b0111,1, IIC_VABAD, IIC_VABAQ, - "vaba", "s", int_arm_neon_vabas>; -defm VABAu : N3VInt3_QHS<1,0,0b0111,1, IIC_VABAD, IIC_VABAQ, - "vaba", "u", int_arm_neon_vabau>; +defm VABAs : N3VIntOp_QHS<0,0,0b0111,1, IIC_VABAD, IIC_VABAQ, + "vaba", "s", int_arm_neon_vabds, add>; +defm VABAu : N3VIntOp_QHS<1,0,0b0111,1, IIC_VABAD, IIC_VABAQ, + "vaba", "u", int_arm_neon_vabdu, add>; // VABAL : Vector Absolute Difference and Accumulate Long (Q += | D - D |) -defm VABALs : N3VLInt3_QHS<0,1,0b0101,0, IIC_VABAD, IIC_VABAD, - "vabal", "s", int_arm_neon_vabals>; -defm VABALu : N3VLInt3_QHS<1,1,0b0101,0, IIC_VABAD, IIC_VABAD, - "vabal", "u", int_arm_neon_vabalu>; +defm VABALs : N3VLIntExtOp_QHS<0,1,0b0101,0, IIC_VABAD, + "vabal", "s", int_arm_neon_vabds, zext, add>; +defm VABALu : N3VLIntExtOp_QHS<1,1,0b0101,0, IIC_VABAD, + "vabal", "u", int_arm_neon_vabdu, zext, add>; // Vector Maximum and Minimum. @@ -3113,8 +3532,8 @@ def VDUPfqf : N2V<0b11, 0b11, {?,1}, {0,0}, 0b11000, 1, 0, [(set QPR:$dst, (v4f32 (NEONvdup (f32 SPR:$src))))]>; // VMOVN : Vector Narrowing Move -defm VMOVN : N2VNInt_HSD<0b11,0b11,0b10,0b00100,0,0, IIC_VMOVD, - "vmovn", "i", int_arm_neon_vmovn>; +defm VMOVN : N2VN_HSD<0b11,0b11,0b10,0b00100,0,0, IIC_VMOVD, + "vmovn", "i", trunc>; // VQMOVN : Vector Saturating Narrowing Move defm VQMOVNs : N2VNInt_HSD<0b11,0b11,0b10,0b00101,0,0, IIC_VQUNAiD, "vqmovn", "s", int_arm_neon_vqmovns>; @@ -3123,10 +3542,8 @@ defm VQMOVNu : N2VNInt_HSD<0b11,0b11,0b10,0b00101,1,0, IIC_VQUNAiD, defm VQMOVNsu : N2VNInt_HSD<0b11,0b11,0b10,0b00100,1,0, IIC_VQUNAiD, "vqmovun", "s", int_arm_neon_vqmovnsu>; // VMOVL : Vector Lengthening Move -defm VMOVLs : N2VLInt_QHS<0b01,0b10100,0,1, "vmovl", "s", - int_arm_neon_vmovls>; -defm VMOVLu : N2VLInt_QHS<0b11,0b10100,0,1, "vmovl", "u", - int_arm_neon_vmovlu>; +defm VMOVLs : N2VL_QHS<0b01,0b10100,0,1, "vmovl", "s", sext>; +defm VMOVLu : N2VL_QHS<0b11,0b10100,0,1, "vmovl", "u", zext>; // Vector Conversions. diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td index bc0790d..a13ff12 100644 --- a/lib/Target/ARM/ARMInstrThumb.td +++ b/lib/Target/ARM/ARMInstrThumb.td @@ -221,9 +221,13 @@ def tADDrPCi : T1I<(outs tGPR:$dst), (ins t_imm_s4:$rhs), IIC_iALUi, T1Encoding<{1,0,1,0,0,?}>; // A6.2 & A8.6.10 // ADD rd, sp, #imm8 +// This is rematerializable, which is particularly useful for taking the +// address of locals. +let isReMaterializable = 1 in { def tADDrSPi : T1I<(outs tGPR:$dst), (ins GPR:$sp, t_imm_s4:$rhs), IIC_iALUi, "add\t$dst, $sp, $rhs", []>, T1Encoding<{1,0,1,0,1,?}>; // A6.2 & A8.6.8 +} // ADD sp, sp, #imm7 def tADDspi : TIt<(outs GPR:$dst), (ins GPR:$lhs, t_imm_s4:$rhs), IIC_iALUi, @@ -251,19 +255,6 @@ def tADDspr : TIt<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), IIC_iALUr, let Inst{2-0} = 0b101; } -// Pseudo instruction that will expand into a tSUBspi + a copy. -let usesCustomInserter = 1 in { // Expanded after instruction selection. -def tSUBspi_ : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, t_imm_s4:$rhs), - NoItinerary, "${:comment} sub\t$dst, $rhs", []>; - -def tADDspr_ : PseudoInst<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), - NoItinerary, "${:comment} add\t$dst, $rhs", []>; - -let Defs = [CPSR] in -def tANDsp : PseudoInst<(outs tGPR:$dst), (ins tGPR:$lhs, tGPR:$rhs), - NoItinerary, "${:comment} and\t$dst, $rhs", []>; -} // usesCustomInserter - //===----------------------------------------------------------------------===// // Control Flow Instructions. // @@ -378,7 +369,7 @@ let isBranch = 1, isTerminator = 1 in { def tBR_JTr : T1JTI<(outs), (ins tGPR:$target, jtblock_operand:$jt, i32imm:$id), - IIC_Br, "mov\tpc, $target\n\t.align\t2\n$jt", + IIC_Br, "mov\tpc, $target\n\t.align\t2$jt", [(ARMbrjt tGPR:$target, tjumptable:$jt, imm:$id)]>, Encoding16 { let Inst{15-7} = 0b010001101; diff --git a/lib/Target/ARM/ARMInstrThumb2.td b/lib/Target/ARM/ARMInstrThumb2.td index bbe675e..6ba0a44 100644 --- a/lib/Target/ARM/ARMInstrThumb2.td +++ b/lib/Target/ARM/ARMInstrThumb2.td @@ -32,7 +32,7 @@ def t2_so_reg : Operand, // reg imm ComplexPattern { let PrintMethod = "printT2SOOperand"; - let MIOperandInfo = (ops GPR, i32imm); + let MIOperandInfo = (ops rGPR, i32imm); } // t2_so_imm_not_XFORM - Return the complement of a t2_so_imm value @@ -51,10 +51,7 @@ def t2_so_imm_neg_XFORM : SDNodeXForm, - PatLeaf<(imm), [{ - return ARM_AM::getT2SOImmVal((uint32_t)N->getZExtValue()) != -1; -}]>; +def t2_so_imm : Operand, PatLeaf<(imm), [{ return Pred_t2_so_imm(N); }]>; // t2_so_imm_not - Match an immediate that is a complement // of a t2_so_imm. @@ -162,7 +159,7 @@ def t2am_imm8s4_offset : Operand { def t2addrmode_so_reg : Operand, ComplexPattern { let PrintMethod = "printT2AddrModeSoRegOperand"; - let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm); + let MIOperandInfo = (ops GPR:$base, rGPR:$offsreg, i32imm:$offsimm); } @@ -176,9 +173,9 @@ def t2addrmode_so_reg : Operand, multiclass T2I_un_irs opcod, string opc, PatFrag opnode, bit Cheap = 0, bit ReMat = 0> { // shifted imm - def i : T2sI<(outs GPR:$dst), (ins t2_so_imm:$src), IIC_iMOVi, + def i : T2sI<(outs rGPR:$dst), (ins t2_so_imm:$src), IIC_iMOVi, opc, "\t$dst, $src", - [(set GPR:$dst, (opnode t2_so_imm:$src))]> { + [(set rGPR:$dst, (opnode t2_so_imm:$src))]> { let isAsCheapAsAMove = Cheap; let isReMaterializable = ReMat; let Inst{31-27} = 0b11110; @@ -189,9 +186,9 @@ multiclass T2I_un_irs opcod, string opc, PatFrag opnode, let Inst{15} = 0; } // register - def r : T2sI<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVr, + def r : T2sI<(outs rGPR:$dst), (ins rGPR:$src), IIC_iMOVr, opc, ".w\t$dst, $src", - [(set GPR:$dst, (opnode GPR:$src))]> { + [(set rGPR:$dst, (opnode rGPR:$src))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; @@ -202,9 +199,9 @@ multiclass T2I_un_irs opcod, string opc, PatFrag opnode, let Inst{5-4} = 0b00; // type } // shifted register - def s : T2sI<(outs GPR:$dst), (ins t2_so_reg:$src), IIC_iMOVsi, + def s : T2sI<(outs rGPR:$dst), (ins t2_so_reg:$src), IIC_iMOVsi, opc, ".w\t$dst, $src", - [(set GPR:$dst, (opnode t2_so_reg:$src))]> { + [(set rGPR:$dst, (opnode t2_so_reg:$src))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; @@ -217,11 +214,11 @@ multiclass T2I_un_irs opcod, string opc, PatFrag opnode, /// binary operation that produces a value. These are predicable and can be /// changed to modify CPSR. multiclass T2I_bin_irs opcod, string opc, PatFrag opnode, - bit Commutable = 0, string wide =""> { + bit Commutable = 0, string wide = ""> { // shifted imm - def ri : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs), IIC_iALUi, + def ri : T2sI<(outs rGPR:$dst), (ins rGPR:$lhs, t2_so_imm:$rhs), IIC_iALUi, opc, "\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]> { + [(set rGPR:$dst, (opnode rGPR:$lhs, t2_so_imm:$rhs))]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; @@ -229,9 +226,9 @@ multiclass T2I_bin_irs opcod, string opc, PatFrag opnode, let Inst{15} = 0; } // register - def rr : T2sI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), IIC_iALUr, + def rr : T2sI<(outs rGPR:$dst), (ins rGPR:$lhs, rGPR:$rhs), IIC_iALUr, opc, !strconcat(wide, "\t$dst, $lhs, $rhs"), - [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]> { + [(set rGPR:$dst, (opnode rGPR:$lhs, rGPR:$rhs))]> { let isCommutable = Commutable; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; @@ -242,9 +239,9 @@ multiclass T2I_bin_irs opcod, string opc, PatFrag opnode, let Inst{5-4} = 0b00; // type } // shifted register - def rs : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), IIC_iALUsi, + def rs : T2sI<(outs rGPR:$dst), (ins rGPR:$lhs, t2_so_reg:$rhs), IIC_iALUsi, opc, !strconcat(wide, "\t$dst, $lhs, $rhs"), - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]> { + [(set rGPR:$dst, (opnode rGPR:$lhs, t2_so_reg:$rhs))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; @@ -259,23 +256,35 @@ multiclass T2I_bin_w_irs opcod, string opc, PatFrag opnode, T2I_bin_irs; /// T2I_rbin_is - Same as T2I_bin_irs except the order of operands are -/// reversed. It doesn't define the 'rr' form since it's handled by its -/// T2I_bin_irs counterpart. -multiclass T2I_rbin_is opcod, string opc, PatFrag opnode> { +/// reversed. The 'rr' form is only defined for the disassembler; for codegen +/// it is equivalent to the T2I_bin_irs counterpart. +multiclass T2I_rbin_irs opcod, string opc, PatFrag opnode> { // shifted imm - def ri : T2sI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs), IIC_iALUi, + def ri : T2sI<(outs rGPR:$dst), (ins rGPR:$rhs, t2_so_imm:$lhs), IIC_iALUi, opc, ".w\t$dst, $rhs, $lhs", - [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]> { + [(set rGPR:$dst, (opnode t2_so_imm:$lhs, rGPR:$rhs))]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; let Inst{20} = ?; // The S bit. let Inst{15} = 0; } + // register + def rr : T2sI<(outs rGPR:$dst), (ins rGPR:$rhs, rGPR:$lhs), IIC_iALUr, + opc, "\t$dst, $rhs, $lhs", + [/* For disassembly only; pattern left blank */]> { + let Inst{31-27} = 0b11101; + let Inst{26-25} = 0b01; + let Inst{24-21} = opcod; + let Inst{20} = ?; // The S bit. + let Inst{14-12} = 0b000; // imm3 + let Inst{7-6} = 0b00; // imm2 + let Inst{5-4} = 0b00; // type + } // shifted register - def rs : T2sI<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs), IIC_iALUsi, + def rs : T2sI<(outs rGPR:$dst), (ins rGPR:$rhs, t2_so_reg:$lhs), IIC_iALUsi, opc, "\t$dst, $rhs, $lhs", - [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]> { + [(set rGPR:$dst, (opnode t2_so_reg:$lhs, rGPR:$rhs))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; @@ -289,9 +298,9 @@ let Defs = [CPSR] in { multiclass T2I_bin_s_irs opcod, string opc, PatFrag opnode, bit Commutable = 0> { // shifted imm - def ri : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs), IIC_iALUi, + def ri : T2I<(outs rGPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs), IIC_iALUi, !strconcat(opc, "s"), ".w\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]> { + [(set rGPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; @@ -299,9 +308,9 @@ multiclass T2I_bin_s_irs opcod, string opc, PatFrag opnode, let Inst{15} = 0; } // register - def rr : T2I<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), IIC_iALUr, + def rr : T2I<(outs rGPR:$dst), (ins GPR:$lhs, rGPR:$rhs), IIC_iALUr, !strconcat(opc, "s"), ".w\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]> { + [(set rGPR:$dst, (opnode GPR:$lhs, rGPR:$rhs))]> { let isCommutable = Commutable; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; @@ -312,9 +321,9 @@ multiclass T2I_bin_s_irs opcod, string opc, PatFrag opnode, let Inst{5-4} = 0b00; // type } // shifted register - def rs : T2I<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), IIC_iALUsi, + def rs : T2I<(outs rGPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), IIC_iALUsi, !strconcat(opc, "s"), ".w\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]> { + [(set rGPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; @@ -328,9 +337,12 @@ multiclass T2I_bin_s_irs opcod, string opc, PatFrag opnode, multiclass T2I_bin_ii12rs op23_21, string opc, PatFrag opnode, bit Commutable = 0> { // shifted imm - def ri : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs), IIC_iALUi, + // The register-immediate version is re-materializable. This is useful + // in particular for taking the address of a local. + let isReMaterializable = 1 in { + def ri : T2sI<(outs rGPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs), IIC_iALUi, opc, ".w\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]> { + [(set rGPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24} = 1; @@ -338,10 +350,11 @@ multiclass T2I_bin_ii12rs op23_21, string opc, PatFrag opnode, let Inst{20} = 0; // The S bit. let Inst{15} = 0; } + } // 12-bit imm - def ri12 : T2I<(outs GPR:$dst), (ins GPR:$lhs, imm0_4095:$rhs), IIC_iALUi, + def ri12 : T2I<(outs rGPR:$dst), (ins GPR:$lhs, imm0_4095:$rhs), IIC_iALUi, !strconcat(opc, "w"), "\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, imm0_4095:$rhs))]> { + [(set rGPR:$dst, (opnode GPR:$lhs, imm0_4095:$rhs))]> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24} = 0; @@ -350,9 +363,9 @@ multiclass T2I_bin_ii12rs op23_21, string opc, PatFrag opnode, let Inst{15} = 0; } // register - def rr : T2sI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), IIC_iALUr, + def rr : T2sI<(outs rGPR:$dst), (ins GPR:$lhs, rGPR:$rhs), IIC_iALUr, opc, ".w\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]> { + [(set rGPR:$dst, (opnode GPR:$lhs, rGPR:$rhs))]> { let isCommutable = Commutable; let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; @@ -364,9 +377,9 @@ multiclass T2I_bin_ii12rs op23_21, string opc, PatFrag opnode, let Inst{5-4} = 0b00; // type } // shifted register - def rs : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), IIC_iALUsi, + def rs : T2sI<(outs rGPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), IIC_iALUsi, opc, ".w\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]> { + [(set rGPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24} = 1; @@ -382,9 +395,9 @@ let Uses = [CPSR] in { multiclass T2I_adde_sube_irs opcod, string opc, PatFrag opnode, bit Commutable = 0> { // shifted imm - def ri : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs), IIC_iALUi, + def ri : T2sI<(outs rGPR:$dst), (ins rGPR:$lhs, t2_so_imm:$rhs), IIC_iALUi, opc, "\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>, + [(set rGPR:$dst, (opnode rGPR:$lhs, t2_so_imm:$rhs))]>, Requires<[IsThumb2]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; @@ -393,9 +406,9 @@ multiclass T2I_adde_sube_irs opcod, string opc, PatFrag opnode, let Inst{15} = 0; } // register - def rr : T2sI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), IIC_iALUr, + def rr : T2sI<(outs rGPR:$dst), (ins rGPR:$lhs, rGPR:$rhs), IIC_iALUr, opc, ".w\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>, + [(set rGPR:$dst, (opnode rGPR:$lhs, rGPR:$rhs))]>, Requires<[IsThumb2]> { let isCommutable = Commutable; let Inst{31-27} = 0b11101; @@ -407,9 +420,9 @@ multiclass T2I_adde_sube_irs opcod, string opc, PatFrag opnode, let Inst{5-4} = 0b00; // type } // shifted register - def rs : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), IIC_iALUsi, + def rs : T2sI<(outs rGPR:$dst), (ins rGPR:$lhs, t2_so_reg:$rhs), IIC_iALUsi, opc, ".w\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>, + [(set rGPR:$dst, (opnode rGPR:$lhs, t2_so_reg:$rhs))]>, Requires<[IsThumb2]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; @@ -423,9 +436,9 @@ let Defs = [CPSR] in { multiclass T2I_adde_sube_s_irs opcod, string opc, PatFrag opnode, bit Commutable = 0> { // shifted imm - def ri : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_imm:$rhs), IIC_iALUi, + def ri : T2sI<(outs rGPR:$dst), (ins rGPR:$lhs, t2_so_imm:$rhs), IIC_iALUi, opc, "\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_imm:$rhs))]>, + [(set rGPR:$dst, (opnode rGPR:$lhs, t2_so_imm:$rhs))]>, Requires<[IsThumb2]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; @@ -434,9 +447,9 @@ multiclass T2I_adde_sube_s_irs opcod, string opc, PatFrag opnode, let Inst{15} = 0; } // register - def rr : T2sI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), IIC_iALUr, + def rr : T2sI<(outs rGPR:$dst), (ins rGPR:$lhs, rGPR:$rhs), IIC_iALUr, opc, ".w\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]>, + [(set rGPR:$dst, (opnode rGPR:$lhs, rGPR:$rhs))]>, Requires<[IsThumb2]> { let isCommutable = Commutable; let Inst{31-27} = 0b11101; @@ -448,9 +461,9 @@ multiclass T2I_adde_sube_s_irs opcod, string opc, PatFrag opnode, let Inst{5-4} = 0b00; // type } // shifted register - def rs : T2sI<(outs GPR:$dst), (ins GPR:$lhs, t2_so_reg:$rhs), IIC_iALUsi, + def rs : T2sI<(outs rGPR:$dst), (ins rGPR:$lhs, t2_so_reg:$rhs), IIC_iALUsi, opc, ".w\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, t2_so_reg:$rhs))]>, + [(set rGPR:$dst, (opnode rGPR:$lhs, t2_so_reg:$rhs))]>, Requires<[IsThumb2]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; @@ -461,13 +474,14 @@ multiclass T2I_adde_sube_s_irs opcod, string opc, PatFrag opnode, } } -/// T2I_rbin_s_is - Same as T2I_rbin_is except sets 's' bit. +/// T2I_rbin_s_is - Same as T2I_rbin_irs except sets 's' bit and the register +/// version is not needed since this is only for codegen. let Defs = [CPSR] in { multiclass T2I_rbin_s_is opcod, string opc, PatFrag opnode> { // shifted imm - def ri : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_imm:$lhs), IIC_iALUi, + def ri : T2I<(outs rGPR:$dst), (ins rGPR:$rhs, t2_so_imm:$lhs), IIC_iALUi, !strconcat(opc, "s"), ".w\t$dst, $rhs, $lhs", - [(set GPR:$dst, (opnode t2_so_imm:$lhs, GPR:$rhs))]> { + [(set rGPR:$dst, (opnode t2_so_imm:$lhs, rGPR:$rhs))]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = opcod; @@ -475,9 +489,9 @@ multiclass T2I_rbin_s_is opcod, string opc, PatFrag opnode> { let Inst{15} = 0; } // shifted register - def rs : T2I<(outs GPR:$dst), (ins GPR:$rhs, t2_so_reg:$lhs), IIC_iALUsi, + def rs : T2I<(outs rGPR:$dst), (ins rGPR:$rhs, t2_so_reg:$lhs), IIC_iALUsi, !strconcat(opc, "s"), "\t$dst, $rhs, $lhs", - [(set GPR:$dst, (opnode t2_so_reg:$lhs, GPR:$rhs))]> { + [(set rGPR:$dst, (opnode t2_so_reg:$lhs, rGPR:$rhs))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; @@ -490,18 +504,18 @@ multiclass T2I_rbin_s_is opcod, string opc, PatFrag opnode> { // rotate operation that produces a value. multiclass T2I_sh_ir opcod, string opc, PatFrag opnode> { // 5-bit imm - def ri : T2sI<(outs GPR:$dst), (ins GPR:$lhs, i32imm:$rhs), IIC_iMOVsi, + def ri : T2sI<(outs rGPR:$dst), (ins rGPR:$lhs, i32imm:$rhs), IIC_iMOVsi, opc, ".w\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, imm1_31:$rhs))]> { + [(set rGPR:$dst, (opnode rGPR:$lhs, imm1_31:$rhs))]> { let Inst{31-27} = 0b11101; let Inst{26-21} = 0b010010; let Inst{19-16} = 0b1111; // Rn let Inst{5-4} = opcod; } // register - def rr : T2sI<(outs GPR:$dst), (ins GPR:$lhs, GPR:$rhs), IIC_iMOVsr, + def rr : T2sI<(outs rGPR:$dst), (ins rGPR:$lhs, rGPR:$rhs), IIC_iMOVsr, opc, ".w\t$dst, $lhs, $rhs", - [(set GPR:$dst, (opnode GPR:$lhs, GPR:$rhs))]> { + [(set rGPR:$dst, (opnode rGPR:$lhs, rGPR:$rhs))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-21} = opcod; @@ -513,7 +527,7 @@ multiclass T2I_sh_ir opcod, string opc, PatFrag opnode> { /// T2I_cmp_irs - Defines a set of (op r, {so_imm|r|so_reg}) cmp / test /// patterns. Similar to T2I_bin_irs except the instruction does not produce /// a explicit result, only implicitly set CPSR. -let Defs = [CPSR] in { +let isCompare = 1, Defs = [CPSR] in { multiclass T2I_cmp_irs opcod, string opc, PatFrag opnode> { // shifted imm def ri : T2I<(outs), (ins GPR:$lhs, t2_so_imm:$rhs), IIC_iCMPi, @@ -527,9 +541,9 @@ multiclass T2I_cmp_irs opcod, string opc, PatFrag opnode> { let Inst{11-8} = 0b1111; // Rd } // register - def rr : T2I<(outs), (ins GPR:$lhs, GPR:$rhs), IIC_iCMPr, + def rr : T2I<(outs), (ins GPR:$lhs, rGPR:$rhs), IIC_iCMPr, opc, ".w\t$lhs, $rhs", - [(opnode GPR:$lhs, GPR:$rhs)]> { + [(opnode GPR:$lhs, rGPR:$rhs)]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = opcod; @@ -639,9 +653,9 @@ multiclass T2I_st opcod, string opc, PatFrag opnode> { /// T2I_unary_rrot - A unary operation with two forms: one whose operand is a /// register and one whose operand is a register rotated by 8/16/24. multiclass T2I_unary_rrot opcod, string opc, PatFrag opnode> { - def r : T2I<(outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, + def r : T2I<(outs rGPR:$dst), (ins rGPR:$src), IIC_iUNAr, opc, ".w\t$dst, $src", - [(set GPR:$dst, (opnode GPR:$src))]> { + [(set rGPR:$dst, (opnode rGPR:$src))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-20} = opcod; @@ -650,9 +664,9 @@ multiclass T2I_unary_rrot opcod, string opc, PatFrag opnode> { let Inst{7} = 1; let Inst{5-4} = 0b00; // rotate } - def r_rot : T2I<(outs GPR:$dst), (ins GPR:$src, i32imm:$rot), IIC_iUNAsi, + def r_rot : T2I<(outs rGPR:$dst), (ins rGPR:$src, i32imm:$rot), IIC_iUNAsi, opc, ".w\t$dst, $src, ror $rot", - [(set GPR:$dst, (opnode (rotr GPR:$src, rot_imm:$rot)))]> { + [(set rGPR:$dst, (opnode (rotr rGPR:$src, rot_imm:$rot)))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; let Inst{22-20} = opcod; @@ -665,9 +679,9 @@ multiclass T2I_unary_rrot opcod, string opc, PatFrag opnode> { // UXTB16 - Requres T2ExtractPack, does not need the .w qualifier. multiclass T2I_unary_rrot_uxtb16 opcod, string opc, PatFrag opnode> { - def r : T2I<(outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, + def r : T2I<(outs rGPR:$dst), (ins rGPR:$src), IIC_iUNAr, opc, "\t$dst, $src", - [(set GPR:$dst, (opnode GPR:$src))]>, + [(set rGPR:$dst, (opnode rGPR:$src))]>, Requires<[HasT2ExtractPack]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; @@ -677,9 +691,9 @@ multiclass T2I_unary_rrot_uxtb16 opcod, string opc, PatFrag opnode> { let Inst{7} = 1; let Inst{5-4} = 0b00; // rotate } - def r_rot : T2I<(outs GPR:$dst), (ins GPR:$src, i32imm:$rot), IIC_iUNAsi, + def r_rot : T2I<(outs rGPR:$dst), (ins rGPR:$src, i32imm:$rot), IIC_iUNAsi, opc, "\t$dst, $src, ror $rot", - [(set GPR:$dst, (opnode (rotr GPR:$src, rot_imm:$rot)))]>, + [(set rGPR:$dst, (opnode (rotr rGPR:$src, rot_imm:$rot)))]>, Requires<[HasT2ExtractPack]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; @@ -694,7 +708,7 @@ multiclass T2I_unary_rrot_uxtb16 opcod, string opc, PatFrag opnode> { // SXTB16 - Requres T2ExtractPack, does not need the .w qualifier, no pattern // supported yet. multiclass T2I_unary_rrot_sxtb16 opcod, string opc> { - def r : T2I<(outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, + def r : T2I<(outs rGPR:$dst), (ins rGPR:$src), IIC_iUNAr, opc, "\t$dst, $src", []> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; @@ -704,7 +718,7 @@ multiclass T2I_unary_rrot_sxtb16 opcod, string opc> { let Inst{7} = 1; let Inst{5-4} = 0b00; // rotate } - def r_rot : T2I<(outs GPR:$dst), (ins GPR:$src, i32imm:$rot), IIC_iUNAsi, + def r_rot : T2I<(outs rGPR:$dst), (ins rGPR:$src, i32imm:$rot), IIC_iUNAsi, opc, "\t$dst, $src, ror $rot", []> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; @@ -719,9 +733,9 @@ multiclass T2I_unary_rrot_sxtb16 opcod, string opc> { /// T2I_bin_rrot - A binary operation with two forms: one whose operand is a /// register and one whose operand is a register rotated by 8/16/24. multiclass T2I_bin_rrot opcod, string opc, PatFrag opnode> { - def rr : T2I<(outs GPR:$dst), (ins GPR:$LHS, GPR:$RHS), IIC_iALUr, + def rr : T2I<(outs rGPR:$dst), (ins rGPR:$LHS, rGPR:$RHS), IIC_iALUr, opc, "\t$dst, $LHS, $RHS", - [(set GPR:$dst, (opnode GPR:$LHS, GPR:$RHS))]>, + [(set rGPR:$dst, (opnode rGPR:$LHS, rGPR:$RHS))]>, Requires<[HasT2ExtractPack]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; @@ -730,10 +744,10 @@ multiclass T2I_bin_rrot opcod, string opc, PatFrag opnode> { let Inst{7} = 1; let Inst{5-4} = 0b00; // rotate } - def rr_rot : T2I<(outs GPR:$dst), (ins GPR:$LHS, GPR:$RHS, i32imm:$rot), + def rr_rot : T2I<(outs rGPR:$dst), (ins rGPR:$LHS, rGPR:$RHS, i32imm:$rot), IIC_iALUsr, opc, "\t$dst, $LHS, $RHS, ror $rot", - [(set GPR:$dst, (opnode GPR:$LHS, - (rotr GPR:$RHS, rot_imm:$rot)))]>, + [(set rGPR:$dst, (opnode rGPR:$LHS, + (rotr rGPR:$RHS, rot_imm:$rot)))]>, Requires<[HasT2ExtractPack]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; @@ -747,7 +761,7 @@ multiclass T2I_bin_rrot opcod, string opc, PatFrag opnode> { // DO variant - disassembly only, no pattern multiclass T2I_bin_rrot_DO opcod, string opc> { - def rr : T2I<(outs GPR:$dst), (ins GPR:$LHS, GPR:$RHS), IIC_iALUr, + def rr : T2I<(outs rGPR:$dst), (ins rGPR:$LHS, rGPR:$RHS), IIC_iALUr, opc, "\t$dst, $LHS, $RHS", []> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; @@ -756,7 +770,7 @@ multiclass T2I_bin_rrot_DO opcod, string opc> { let Inst{7} = 1; let Inst{5-4} = 0b00; // rotate } - def rr_rot : T2I<(outs GPR:$dst), (ins GPR:$LHS, GPR:$RHS, i32imm:$rot), + def rr_rot : T2I<(outs rGPR:$dst), (ins rGPR:$LHS, rGPR:$RHS, i32imm:$rot), IIC_iALUsr, opc, "\t$dst, $LHS, $RHS, ror $rot", []> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0100; @@ -779,8 +793,8 @@ multiclass T2I_bin_rrot_DO opcod, string opc> { // assembler. let neverHasSideEffects = 1 in { let isReMaterializable = 1 in -def t2LEApcrel : T2XI<(outs GPR:$dst), (ins i32imm:$label, pred:$p), IIC_iALUi, - "adr$p.w\t$dst, #$label", []> { +def t2LEApcrel : T2XI<(outs rGPR:$dst), (ins i32imm:$label, pred:$p), IIC_iALUi, + "adr${p}.w\t$dst, #$label", []> { let Inst{31-27} = 0b11110; let Inst{25-24} = 0b10; // Inst{23:21} = '11' (add = FALSE) or '00' (add = TRUE) @@ -790,9 +804,9 @@ def t2LEApcrel : T2XI<(outs GPR:$dst), (ins i32imm:$label, pred:$p), IIC_iALUi, let Inst{15} = 0; } } // neverHasSideEffects -def t2LEApcrelJT : T2XI<(outs GPR:$dst), +def t2LEApcrelJT : T2XI<(outs rGPR:$dst), (ins i32imm:$label, nohash_imm:$id, pred:$p), IIC_iALUi, - "adr$p.w\t$dst, #${label}_${id}", []> { + "adr${p}.w\t$dst, #${label}_${id}", []> { let Inst{31-27} = 0b11110; let Inst{25-24} = 0b10; // Inst{23:21} = '11' (add = FALSE) or '00' (add = TRUE) @@ -866,9 +880,9 @@ def t2SUBrSPs : T2sI<(outs GPR:$dst), (ins GPR:$sp, t2_so_reg:$rhs), } // Signed and unsigned division on v7-M -def t2SDIV : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iALUi, +def t2SDIV : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iALUi, "sdiv", "\t$dst, $a, $b", - [(set GPR:$dst, (sdiv GPR:$a, GPR:$b))]>, + [(set rGPR:$dst, (sdiv rGPR:$a, rGPR:$b))]>, Requires<[HasDivide]> { let Inst{31-27} = 0b11111; let Inst{26-21} = 0b011100; @@ -877,9 +891,9 @@ def t2SDIV : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iALUi, let Inst{7-4} = 0b1111; } -def t2UDIV : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iALUi, +def t2UDIV : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iALUi, "udiv", "\t$dst, $a, $b", - [(set GPR:$dst, (udiv GPR:$a, GPR:$b))]>, + [(set rGPR:$dst, (udiv rGPR:$a, rGPR:$b))]>, Requires<[HasDivide]> { let Inst{31-27} = 0b11111; let Inst{26-21} = 0b011101; @@ -888,17 +902,6 @@ def t2UDIV : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iALUi, let Inst{7-4} = 0b1111; } -// Pseudo instruction that will expand into a t2SUBrSPi + a copy. -let usesCustomInserter = 1 in { // Expanded after instruction selection. -def t2SUBrSPi_ : PseudoInst<(outs GPR:$dst), (ins GPR:$sp, t2_so_imm:$imm), - NoItinerary, "${:comment} sub.w\t$dst, $sp, $imm", []>; -def t2SUBrSPi12_ : PseudoInst<(outs GPR:$dst), (ins GPR:$sp, imm0_4095:$imm), - NoItinerary, "${:comment} subw\t$dst, $sp, $imm", []>; -def t2SUBrSPs_ : PseudoInst<(outs GPR:$dst), (ins GPR:$sp, t2_so_reg:$rhs), - NoItinerary, "${:comment} sub\t$dst, $sp, $rhs", []>; -} // usesCustomInserter - - //===----------------------------------------------------------------------===// // Load / store Instructions. // @@ -917,10 +920,10 @@ defm t2LDRSB : T2I_ld<1, 0b00, "ldrsb", UnOpFrag<(sextloadi8 node:$Src)>>; let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in { // Load doubleword -def t2LDRDi8 : T2Ii8s4<1, 0, 1, (outs GPR:$dst1, GPR:$dst2), +def t2LDRDi8 : T2Ii8s4<1, 0, 1, (outs rGPR:$dst1, rGPR:$dst2), (ins t2addrmode_imm8s4:$addr), IIC_iLoadi, "ldrd", "\t$dst1, $addr", []>; -def t2LDRDpci : T2Ii8s4<1, 0, 1, (outs GPR:$dst1, GPR:$dst2), +def t2LDRDpci : T2Ii8s4<1, 0, 1, (outs rGPR:$dst1, rGPR:$dst2), (ins i32imm:$addr), IIC_iLoadi, "ldrd", "\t$dst1, $addr", []> { let Inst{19-16} = 0b1111; // Rn @@ -967,6 +970,11 @@ def : T2Pat<(extloadi16 t2addrmode_so_reg:$addr), def : T2Pat<(extloadi16 (ARMWrapper tconstpool:$addr)), (t2LDRHpci tconstpool:$addr)>; +// FIXME: The destination register of the loads and stores can't be PC, but +// can be SP. We need another regclass (similar to rGPR) to represent +// that. Not a pressing issue since these are selected manually, +// not via pattern. + // Indexed loads let mayLoad = 1, neverHasSideEffects = 1 in { def t2LDR_PRE : T2Iidxldst<0, 0b10, 1, 1, (outs GPR:$dst, GPR:$base_wb), @@ -1286,9 +1294,9 @@ def t2MOVr : T2sI<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVr, // AddedComplexity to ensure isel tries t2MOVi before t2MOVi16. let isReMaterializable = 1, isAsCheapAsAMove = 1, AddedComplexity = 1 in -def t2MOVi : T2sI<(outs GPR:$dst), (ins t2_so_imm:$src), IIC_iMOVi, +def t2MOVi : T2sI<(outs rGPR:$dst), (ins t2_so_imm:$src), IIC_iMOVi, "mov", ".w\t$dst, $src", - [(set GPR:$dst, t2_so_imm:$src)]> { + [(set rGPR:$dst, t2_so_imm:$src)]> { let Inst{31-27} = 0b11110; let Inst{25} = 0; let Inst{24-21} = 0b0010; @@ -1298,9 +1306,9 @@ def t2MOVi : T2sI<(outs GPR:$dst), (ins t2_so_imm:$src), IIC_iMOVi, } let isReMaterializable = 1, isAsCheapAsAMove = 1 in -def t2MOVi16 : T2I<(outs GPR:$dst), (ins i32imm:$src), IIC_iMOVi, +def t2MOVi16 : T2I<(outs rGPR:$dst), (ins i32imm:$src), IIC_iMOVi, "movw", "\t$dst, $src", - [(set GPR:$dst, imm0_65535:$src)]> { + [(set rGPR:$dst, imm0_65535:$src)]> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24-21} = 0b0010; @@ -1309,10 +1317,10 @@ def t2MOVi16 : T2I<(outs GPR:$dst), (ins i32imm:$src), IIC_iMOVi, } let Constraints = "$src = $dst" in -def t2MOVTi16 : T2I<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm), IIC_iMOVi, +def t2MOVTi16 : T2I<(outs rGPR:$dst), (ins rGPR:$src, i32imm:$imm), IIC_iMOVi, "movt", "\t$dst, $imm", - [(set GPR:$dst, - (or (and GPR:$src, 0xffff), lo16AllZero:$imm))]> { + [(set rGPR:$dst, + (or (and rGPR:$src, 0xffff), lo16AllZero:$imm))]> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24-21} = 0b0110; @@ -1320,7 +1328,7 @@ def t2MOVTi16 : T2I<(outs GPR:$dst), (ins GPR:$src, i32imm:$imm), IIC_iMOVi, let Inst{15} = 0; } -def : T2Pat<(or GPR:$src, 0xffff0000), (t2MOVTi16 GPR:$src, 0xffff)>; +def : T2Pat<(or rGPR:$src, 0xffff0000), (t2MOVTi16 rGPR:$src, 0xffff)>; //===----------------------------------------------------------------------===// // Extend Instructions. @@ -1352,10 +1360,14 @@ defm t2UXTH : T2I_unary_rrot<0b001, "uxth", defm t2UXTB16 : T2I_unary_rrot_uxtb16<0b011, "uxtb16", UnOpFrag<(and node:$Src, 0x00FF00FF)>>; -def : T2Pat<(and (shl GPR:$Src, (i32 8)), 0xFF00FF), - (t2UXTB16r_rot GPR:$Src, 24)>, Requires<[HasT2ExtractPack]>; -def : T2Pat<(and (srl GPR:$Src, (i32 8)), 0xFF00FF), - (t2UXTB16r_rot GPR:$Src, 8)>, Requires<[HasT2ExtractPack]>; +// FIXME: This pattern incorrectly assumes the shl operator is a rotate. +// The transformation should probably be done as a combiner action +// instead so we can include a check for masking back in the upper +// eight bits of the source into the lower eight bits of the result. +//def : T2Pat<(and (shl rGPR:$Src, (i32 8)), 0xFF00FF), +// (t2UXTB16r_rot rGPR:$Src, 24)>, Requires<[HasT2ExtractPack]>; +def : T2Pat<(and (srl rGPR:$Src, (i32 8)), 0xFF00FF), + (t2UXTB16r_rot rGPR:$Src, 8)>, Requires<[HasT2ExtractPack]>; defm t2UXTAB : T2I_bin_rrot<0b101, "uxtab", BinOpFrag<(add node:$LHS, (and node:$RHS, 0x00FF))>>; @@ -1389,7 +1401,7 @@ defm t2SBCS : T2I_adde_sube_s_irs<0b1011, "sbc", BinOpFrag<(sube_live_carry node:$LHS, node:$RHS)>>; // RSB -defm t2RSB : T2I_rbin_is <0b1110, "rsb", +defm t2RSB : T2I_rbin_irs <0b1110, "rsb", BinOpFrag<(sub node:$LHS, node:$RHS)>>; defm t2RSBS : T2I_rbin_s_is <0b1110, "rsb", BinOpFrag<(subc node:$LHS, node:$RHS)>>; @@ -1409,18 +1421,18 @@ def : T2Pat<(add GPR:$src, t2_so_imm_neg:$imm), def : T2Pat<(add GPR:$src, imm0_4095_neg:$imm), (t2SUBri12 GPR:$src, imm0_4095_neg:$imm)>; let AddedComplexity = 1 in -def : T2Pat<(addc GPR:$src, imm0_255_neg:$imm), - (t2SUBSri GPR:$src, imm0_255_neg:$imm)>; -def : T2Pat<(addc GPR:$src, t2_so_imm_neg:$imm), - (t2SUBSri GPR:$src, t2_so_imm_neg:$imm)>; +def : T2Pat<(addc rGPR:$src, imm0_255_neg:$imm), + (t2SUBSri rGPR:$src, imm0_255_neg:$imm)>; +def : T2Pat<(addc rGPR:$src, t2_so_imm_neg:$imm), + (t2SUBSri rGPR:$src, t2_so_imm_neg:$imm)>; // The with-carry-in form matches bitwise not instead of the negation. // Effectively, the inverse interpretation of the carry flag already accounts // for part of the negation. let AddedComplexity = 1 in -def : T2Pat<(adde GPR:$src, imm0_255_not:$imm), - (t2SBCSri GPR:$src, imm0_255_not:$imm)>; -def : T2Pat<(adde GPR:$src, t2_so_imm_not:$imm), - (t2SBCSri GPR:$src, t2_so_imm_not:$imm)>; +def : T2Pat<(adde rGPR:$src, imm0_255_not:$imm), + (t2SBCSri rGPR:$src, imm0_255_not:$imm)>; +def : T2Pat<(adde rGPR:$src, t2_so_imm_not:$imm), + (t2SBCSri rGPR:$src, t2_so_imm_not:$imm)>; // Select Bytes -- for disassembly only @@ -1437,9 +1449,10 @@ def t2SEL : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), NoItinerary, "sel", // A6.3.13, A6.3.14, A6.3.15 Parallel addition and subtraction (signed/unsigned) // And Miscellaneous operations -- for disassembly only -class T2I_pam op22_20, bits<4> op7_4, string opc> - : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), NoItinerary, opc, - "\t$dst, $a, $b", [/* For disassembly only; pattern left blank */]> { +class T2I_pam op22_20, bits<4> op7_4, string opc, + list pat = [/* For disassembly only; pattern left blank */]> + : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), NoItinerary, opc, + "\t$dst, $a, $b", pat> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0101; let Inst{22-20} = op22_20; @@ -1449,14 +1462,16 @@ class T2I_pam op22_20, bits<4> op7_4, string opc> // Saturating add/subtract -- for disassembly only -def t2QADD : T2I_pam<0b000, 0b1000, "qadd">; +def t2QADD : T2I_pam<0b000, 0b1000, "qadd", + [(set rGPR:$dst, (int_arm_qadd rGPR:$a, rGPR:$b))]>; def t2QADD16 : T2I_pam<0b001, 0b0001, "qadd16">; def t2QADD8 : T2I_pam<0b000, 0b0001, "qadd8">; def t2QASX : T2I_pam<0b010, 0b0001, "qasx">; def t2QDADD : T2I_pam<0b000, 0b1001, "qdadd">; def t2QDSUB : T2I_pam<0b000, 0b1011, "qdsub">; def t2QSAX : T2I_pam<0b110, 0b0001, "qsax">; -def t2QSUB : T2I_pam<0b000, 0b1010, "qsub">; +def t2QSUB : T2I_pam<0b000, 0b1010, "qsub", + [(set rGPR:$dst, (int_arm_qsub rGPR:$a, rGPR:$b))]>; def t2QSUB16 : T2I_pam<0b101, 0b0001, "qsub16">; def t2QSUB8 : T2I_pam<0b100, 0b0001, "qsub8">; def t2UQADD16 : T2I_pam<0b001, 0b0101, "uqadd16">; @@ -1498,37 +1513,27 @@ def t2UHSUB8 : T2I_pam<0b100, 0b0110, "uhsub8">; // Unsigned Sum of Absolute Differences [and Accumulate] -- for disassembly only -def t2USAD8 : T2I_mac<0, 0b111, 0b0000, (outs GPR:$dst), (ins GPR:$a, GPR:$b), +def t2USAD8 : T2I_mac<0, 0b111, 0b0000, (outs rGPR:$dst), + (ins rGPR:$a, rGPR:$b), NoItinerary, "usad8", "\t$dst, $a, $b", []> { let Inst{15-12} = 0b1111; } -def t2USADA8 : T2I_mac<0, 0b111, 0b0000, (outs GPR:$dst), - (ins GPR:$a, GPR:$b, GPR:$acc), NoItinerary, "usada8", +def t2USADA8 : T2I_mac<0, 0b111, 0b0000, (outs rGPR:$dst), + (ins rGPR:$a, rGPR:$b, rGPR:$acc), NoItinerary, "usada8", "\t$dst, $a, $b, $acc", []>; // Signed/Unsigned saturate -- for disassembly only -def t2SSATlsl : T2I<(outs GPR:$dst), (ins i32imm:$bit_pos,GPR:$a,i32imm:$shamt), - NoItinerary, "ssat", "\t$dst, $bit_pos, $a, lsl $shamt", - [/* For disassembly only; pattern left blank */]> { - let Inst{31-27} = 0b11110; - let Inst{25-22} = 0b1100; - let Inst{20} = 0; - let Inst{15} = 0; - let Inst{21} = 0; // sh = '0' -} - -def t2SSATasr : T2I<(outs GPR:$dst), (ins i32imm:$bit_pos,GPR:$a,i32imm:$shamt), - NoItinerary, "ssat", "\t$dst, $bit_pos, $a, asr $shamt", - [/* For disassembly only; pattern left blank */]> { +def t2SSAT: T2I<(outs rGPR:$dst), (ins i32imm:$bit_pos, rGPR:$a, shift_imm:$sh), + NoItinerary, "ssat", "\t$dst, $bit_pos, $a$sh", + [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11110; let Inst{25-22} = 0b1100; let Inst{20} = 0; let Inst{15} = 0; - let Inst{21} = 1; // sh = '1' } -def t2SSAT16 : T2I<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), NoItinerary, +def t2SSAT16: T2I<(outs rGPR:$dst), (ins i32imm:$bit_pos, rGPR:$a), NoItinerary, "ssat16", "\t$dst, $bit_pos, $a", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11110; @@ -1540,27 +1545,16 @@ def t2SSAT16 : T2I<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), NoItinerary, let Inst{7-6} = 0b00; // imm2 = '00' } -def t2USATlsl : T2I<(outs GPR:$dst), (ins i32imm:$bit_pos,GPR:$a,i32imm:$shamt), - NoItinerary, "usat", "\t$dst, $bit_pos, $a, lsl $shamt", - [/* For disassembly only; pattern left blank */]> { - let Inst{31-27} = 0b11110; - let Inst{25-22} = 0b1110; - let Inst{20} = 0; - let Inst{15} = 0; - let Inst{21} = 0; // sh = '0' -} - -def t2USATasr : T2I<(outs GPR:$dst), (ins i32imm:$bit_pos,GPR:$a,i32imm:$shamt), - NoItinerary, "usat", "\t$dst, $bit_pos, $a, asr $shamt", - [/* For disassembly only; pattern left blank */]> { +def t2USAT: T2I<(outs rGPR:$dst), (ins i32imm:$bit_pos, rGPR:$a, shift_imm:$sh), + NoItinerary, "usat", "\t$dst, $bit_pos, $a$sh", + [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11110; let Inst{25-22} = 0b1110; let Inst{20} = 0; let Inst{15} = 0; - let Inst{21} = 1; // sh = '1' } -def t2USAT16 : T2I<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), NoItinerary, +def t2USAT16: T2I<(outs rGPR:$dst), (ins i32imm:$bit_pos, rGPR:$a), NoItinerary, "usat16", "\t$dst, $bit_pos, $a", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11110; @@ -1572,6 +1566,9 @@ def t2USAT16 : T2I<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), NoItinerary, let Inst{7-6} = 0b00; // imm2 = '00' } +def : T2Pat<(int_arm_ssat GPR:$a, imm:$pos), (t2SSAT imm:$pos, GPR:$a, 0)>; +def : T2Pat<(int_arm_usat GPR:$a, imm:$pos), (t2USAT imm:$pos, GPR:$a, 0)>; + //===----------------------------------------------------------------------===// // Shift and rotate Instructions. // @@ -1582,9 +1579,9 @@ defm t2ASR : T2I_sh_ir<0b10, "asr", BinOpFrag<(sra node:$LHS, node:$RHS)>>; defm t2ROR : T2I_sh_ir<0b11, "ror", BinOpFrag<(rotr node:$LHS, node:$RHS)>>; let Uses = [CPSR] in { -def t2MOVrx : T2sI<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVsi, +def t2MOVrx : T2sI<(outs rGPR:$dst), (ins rGPR:$src), IIC_iMOVsi, "rrx", "\t$dst, $src", - [(set GPR:$dst, (ARMrrx GPR:$src))]> { + [(set rGPR:$dst, (ARMrrx rGPR:$src))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b0010; @@ -1596,9 +1593,9 @@ def t2MOVrx : T2sI<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVsi, } let Defs = [CPSR] in { -def t2MOVsrl_flag : T2I<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVsi, +def t2MOVsrl_flag : T2I<(outs rGPR:$dst), (ins rGPR:$src), IIC_iMOVsi, "lsrs", ".w\t$dst, $src, #1", - [(set GPR:$dst, (ARMsrl_flag GPR:$src))]> { + [(set rGPR:$dst, (ARMsrl_flag rGPR:$src))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b0010; @@ -1609,9 +1606,9 @@ def t2MOVsrl_flag : T2I<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVsi, let Inst{14-12} = 0b000; let Inst{7-6} = 0b01; } -def t2MOVsra_flag : T2I<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVsi, +def t2MOVsra_flag : T2I<(outs rGPR:$dst), (ins rGPR:$src), IIC_iMOVsi, "asrs", ".w\t$dst, $src, #1", - [(set GPR:$dst, (ARMsra_flag GPR:$src))]> { + [(set rGPR:$dst, (ARMsra_flag rGPR:$src))]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; let Inst{24-21} = 0b0010; @@ -1638,10 +1635,13 @@ defm t2EOR : T2I_bin_w_irs<0b0100, "eor", defm t2BIC : T2I_bin_w_irs<0b0001, "bic", BinOpFrag<(and node:$LHS, (not node:$RHS))>>; +defm t2ANDS : T2I_bin_s_irs<0b0000, "and", + BinOpFrag<(ARMand node:$LHS, node:$RHS)>, 1>; + let Constraints = "$src = $dst" in -def t2BFC : T2I<(outs GPR:$dst), (ins GPR:$src, bf_inv_mask_imm:$imm), +def t2BFC : T2I<(outs rGPR:$dst), (ins rGPR:$src, bf_inv_mask_imm:$imm), IIC_iUNAsi, "bfc", "\t$dst, $imm", - [(set GPR:$dst, (and GPR:$src, bf_inv_mask_imm:$imm))]> { + [(set rGPR:$dst, (and rGPR:$src, bf_inv_mask_imm:$imm))]> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24-20} = 0b10110; @@ -1649,7 +1649,7 @@ def t2BFC : T2I<(outs GPR:$dst), (ins GPR:$src, bf_inv_mask_imm:$imm), let Inst{15} = 0; } -def t2SBFX : T2I<(outs GPR:$dst), (ins GPR:$src, imm0_31:$lsb, imm0_31:$width), +def t2SBFX: T2I<(outs rGPR:$dst), (ins rGPR:$src, imm0_31:$lsb, imm0_31:$width), IIC_iALUi, "sbfx", "\t$dst, $src, $lsb, $width", []> { let Inst{31-27} = 0b11110; let Inst{25} = 1; @@ -1657,7 +1657,7 @@ def t2SBFX : T2I<(outs GPR:$dst), (ins GPR:$src, imm0_31:$lsb, imm0_31:$width), let Inst{15} = 0; } -def t2UBFX : T2I<(outs GPR:$dst), (ins GPR:$src, imm0_31:$lsb, imm0_31:$width), +def t2UBFX: T2I<(outs rGPR:$dst), (ins rGPR:$src, imm0_31:$lsb, imm0_31:$width), IIC_iALUi, "ubfx", "\t$dst, $src, $lsb, $width", []> { let Inst{31-27} = 0b11110; let Inst{25} = 1; @@ -1666,10 +1666,12 @@ def t2UBFX : T2I<(outs GPR:$dst), (ins GPR:$src, imm0_31:$lsb, imm0_31:$width), } // A8.6.18 BFI - Bitfield insert (Encoding T1) -// Added for disassembler with the pattern field purposely left blank. -// FIXME: Utilize this instruction in codgen. -def t2BFI : T2I<(outs GPR:$dst), (ins GPR:$src, imm0_31:$lsb, imm0_31:$width), - IIC_iALUi, "bfi", "\t$dst, $src, $lsb, $width", []> { +let Constraints = "$src = $dst" in +def t2BFI : T2I<(outs rGPR:$dst), + (ins rGPR:$src, rGPR:$val, bf_inv_mask_imm:$imm), + IIC_iALUi, "bfi", "\t$dst, $val, $imm", + [(set rGPR:$dst, (ARMbfi rGPR:$src, rGPR:$val, + bf_inv_mask_imm:$imm))]> { let Inst{31-27} = 0b11110; let Inst{25} = 1; let Inst{24-20} = 0b10110; @@ -1677,19 +1679,20 @@ def t2BFI : T2I<(outs GPR:$dst), (ins GPR:$src, imm0_31:$lsb, imm0_31:$width), } defm t2ORN : T2I_bin_irs<0b0011, "orn", BinOpFrag<(or node:$LHS, - (not node:$RHS))>>; + (not node:$RHS))>, 0, "">; // Prefer over of t2EORri ra, rb, -1 because mvn has 16-bit version let AddedComplexity = 1 in defm t2MVN : T2I_un_irs <0b0011, "mvn", UnOpFrag<(not node:$Src)>, 1, 1>; -def : T2Pat<(and GPR:$src, t2_so_imm_not:$imm), - (t2BICri GPR:$src, t2_so_imm_not:$imm)>; +let AddedComplexity = 1 in +def : T2Pat<(and rGPR:$src, t2_so_imm_not:$imm), + (t2BICri rGPR:$src, t2_so_imm_not:$imm)>; // FIXME: Disable this pattern on Darwin to workaround an assembler bug. -def : T2Pat<(or GPR:$src, t2_so_imm_not:$imm), - (t2ORNri GPR:$src, t2_so_imm_not:$imm)>, +def : T2Pat<(or rGPR:$src, t2_so_imm_not:$imm), + (t2ORNri rGPR:$src, t2_so_imm_not:$imm)>, Requires<[IsThumb2]>; def : T2Pat<(t2_so_imm_not:$src), @@ -1699,9 +1702,9 @@ def : T2Pat<(t2_so_imm_not:$src), // Multiply Instructions. // let isCommutable = 1 in -def t2MUL: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iMUL32, +def t2MUL: T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL32, "mul", "\t$dst, $a, $b", - [(set GPR:$dst, (mul GPR:$a, GPR:$b))]> { + [(set rGPR:$dst, (mul rGPR:$a, rGPR:$b))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b000; @@ -1709,9 +1712,9 @@ def t2MUL: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iMUL32, let Inst{7-4} = 0b0000; // Multiply } -def t2MLA: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), IIC_iMAC32, +def t2MLA: T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$c), IIC_iMAC32, "mla", "\t$dst, $a, $b, $c", - [(set GPR:$dst, (add (mul GPR:$a, GPR:$b), GPR:$c))]> { + [(set rGPR:$dst, (add (mul rGPR:$a, rGPR:$b), rGPR:$c))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b000; @@ -1719,9 +1722,9 @@ def t2MLA: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), IIC_iMAC32, let Inst{7-4} = 0b0000; // Multiply } -def t2MLS: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), IIC_iMAC32, +def t2MLS: T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$c), IIC_iMAC32, "mls", "\t$dst, $a, $b, $c", - [(set GPR:$dst, (sub GPR:$c, (mul GPR:$a, GPR:$b)))]> { + [(set rGPR:$dst, (sub rGPR:$c, (mul rGPR:$a, rGPR:$b)))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b000; @@ -1732,7 +1735,8 @@ def t2MLS: T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), IIC_iMAC32, // Extra precision multiplies with low / high results let neverHasSideEffects = 1 in { let isCommutable = 1 in { -def t2SMULL : T2I<(outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b), IIC_iMUL64, +def t2SMULL : T2I<(outs rGPR:$ldst, rGPR:$hdst), + (ins rGPR:$a, rGPR:$b), IIC_iMUL64, "smull", "\t$ldst, $hdst, $a, $b", []> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0111; @@ -1740,7 +1744,8 @@ def t2SMULL : T2I<(outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b), IIC_iMUL64, let Inst{7-4} = 0b0000; } -def t2UMULL : T2I<(outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b), IIC_iMUL64, +def t2UMULL : T2I<(outs rGPR:$ldst, rGPR:$hdst), + (ins rGPR:$a, rGPR:$b), IIC_iMUL64, "umull", "\t$ldst, $hdst, $a, $b", []> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0111; @@ -1750,7 +1755,8 @@ def t2UMULL : T2I<(outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b), IIC_iMUL64, } // isCommutable // Multiply + accumulate -def t2SMLAL : T2I<(outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b), IIC_iMAC64, +def t2SMLAL : T2I<(outs rGPR:$ldst, rGPR:$hdst), + (ins rGPR:$a, rGPR:$b), IIC_iMAC64, "smlal", "\t$ldst, $hdst, $a, $b", []>{ let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0111; @@ -1758,7 +1764,8 @@ def t2SMLAL : T2I<(outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b), IIC_iMAC64, let Inst{7-4} = 0b0000; } -def t2UMLAL : T2I<(outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b), IIC_iMAC64, +def t2UMLAL : T2I<(outs rGPR:$ldst, rGPR:$hdst), + (ins rGPR:$a, rGPR:$b), IIC_iMAC64, "umlal", "\t$ldst, $hdst, $a, $b", []>{ let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0111; @@ -1766,7 +1773,8 @@ def t2UMLAL : T2I<(outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b), IIC_iMAC64, let Inst{7-4} = 0b0000; } -def t2UMAAL : T2I<(outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b), IIC_iMAC64, +def t2UMAAL : T2I<(outs rGPR:$ldst, rGPR:$hdst), + (ins rGPR:$a, rGPR:$b), IIC_iMAC64, "umaal", "\t$ldst, $hdst, $a, $b", []>{ let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0111; @@ -1778,9 +1786,9 @@ def t2UMAAL : T2I<(outs GPR:$ldst, GPR:$hdst), (ins GPR:$a, GPR:$b), IIC_iMAC64, // Rounding variants of the below included for disassembly only // Most significant word multiply -def t2SMMUL : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iMUL32, +def t2SMMUL : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL32, "smmul", "\t$dst, $a, $b", - [(set GPR:$dst, (mulhs GPR:$a, GPR:$b))]> { + [(set rGPR:$dst, (mulhs rGPR:$a, rGPR:$b))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b101; @@ -1788,7 +1796,7 @@ def t2SMMUL : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iMUL32, let Inst{7-4} = 0b0000; // No Rounding (Inst{4} = 0) } -def t2SMMULR : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iMUL32, +def t2SMMULR : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL32, "smmulr", "\t$dst, $a, $b", []> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; @@ -1797,9 +1805,9 @@ def t2SMMULR : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iMUL32, let Inst{7-4} = 0b0001; // Rounding (Inst{4} = 1) } -def t2SMMLA : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), IIC_iMAC32, +def t2SMMLA : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$c), IIC_iMAC32, "smmla", "\t$dst, $a, $b, $c", - [(set GPR:$dst, (add (mulhs GPR:$a, GPR:$b), GPR:$c))]> { + [(set rGPR:$dst, (add (mulhs rGPR:$a, rGPR:$b), rGPR:$c))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b101; @@ -1807,7 +1815,7 @@ def t2SMMLA : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), IIC_iMAC32, let Inst{7-4} = 0b0000; // No Rounding (Inst{4} = 0) } -def t2SMMLAR : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), IIC_iMAC32, +def t2SMMLAR: T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$c), IIC_iMAC32, "smmlar", "\t$dst, $a, $b, $c", []> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; @@ -1816,9 +1824,9 @@ def t2SMMLAR : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), IIC_iMAC32, let Inst{7-4} = 0b0001; // Rounding (Inst{4} = 1) } -def t2SMMLS : T2I <(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), IIC_iMAC32, +def t2SMMLS: T2I <(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$c), IIC_iMAC32, "smmls", "\t$dst, $a, $b, $c", - [(set GPR:$dst, (sub GPR:$c, (mulhs GPR:$a, GPR:$b)))]> { + [(set rGPR:$dst, (sub rGPR:$c, (mulhs rGPR:$a, rGPR:$b)))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b110; @@ -1826,7 +1834,7 @@ def t2SMMLS : T2I <(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), IIC_iMAC32, let Inst{7-4} = 0b0000; // No Rounding (Inst{4} = 0) } -def t2SMMLSR : T2I <(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), IIC_iMAC32, +def t2SMMLSR:T2I <(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$c), IIC_iMAC32, "smmlsr", "\t$dst, $a, $b, $c", []> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; @@ -1836,10 +1844,10 @@ def t2SMMLSR : T2I <(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), IIC_iMAC32, } multiclass T2I_smul { - def BB : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iMUL32, + def BB : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL32, !strconcat(opc, "bb"), "\t$dst, $a, $b", - [(set GPR:$dst, (opnode (sext_inreg GPR:$a, i16), - (sext_inreg GPR:$b, i16)))]> { + [(set rGPR:$dst, (opnode (sext_inreg rGPR:$a, i16), + (sext_inreg rGPR:$b, i16)))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; @@ -1848,10 +1856,10 @@ multiclass T2I_smul { let Inst{5-4} = 0b00; } - def BT : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iMUL32, + def BT : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL32, !strconcat(opc, "bt"), "\t$dst, $a, $b", - [(set GPR:$dst, (opnode (sext_inreg GPR:$a, i16), - (sra GPR:$b, (i32 16))))]> { + [(set rGPR:$dst, (opnode (sext_inreg rGPR:$a, i16), + (sra rGPR:$b, (i32 16))))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; @@ -1860,10 +1868,10 @@ multiclass T2I_smul { let Inst{5-4} = 0b01; } - def TB : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iMUL32, + def TB : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL32, !strconcat(opc, "tb"), "\t$dst, $a, $b", - [(set GPR:$dst, (opnode (sra GPR:$a, (i32 16)), - (sext_inreg GPR:$b, i16)))]> { + [(set rGPR:$dst, (opnode (sra rGPR:$a, (i32 16)), + (sext_inreg rGPR:$b, i16)))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; @@ -1872,10 +1880,10 @@ multiclass T2I_smul { let Inst{5-4} = 0b10; } - def TT : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iMUL32, + def TT : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL32, !strconcat(opc, "tt"), "\t$dst, $a, $b", - [(set GPR:$dst, (opnode (sra GPR:$a, (i32 16)), - (sra GPR:$b, (i32 16))))]> { + [(set rGPR:$dst, (opnode (sra rGPR:$a, (i32 16)), + (sra rGPR:$b, (i32 16))))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; @@ -1884,10 +1892,10 @@ multiclass T2I_smul { let Inst{5-4} = 0b11; } - def WB : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iMUL16, + def WB : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL16, !strconcat(opc, "wb"), "\t$dst, $a, $b", - [(set GPR:$dst, (sra (opnode GPR:$a, - (sext_inreg GPR:$b, i16)), (i32 16)))]> { + [(set rGPR:$dst, (sra (opnode rGPR:$a, + (sext_inreg rGPR:$b, i16)), (i32 16)))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b011; @@ -1896,10 +1904,10 @@ multiclass T2I_smul { let Inst{5-4} = 0b00; } - def WT : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b), IIC_iMUL16, + def WT : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), IIC_iMUL16, !strconcat(opc, "wt"), "\t$dst, $a, $b", - [(set GPR:$dst, (sra (opnode GPR:$a, - (sra GPR:$b, (i32 16))), (i32 16)))]> { + [(set rGPR:$dst, (sra (opnode rGPR:$a, + (sra rGPR:$b, (i32 16))), (i32 16)))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b011; @@ -1911,11 +1919,11 @@ multiclass T2I_smul { multiclass T2I_smla { - def BB : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC16, + def BB : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC16, !strconcat(opc, "bb"), "\t$dst, $a, $b, $acc", - [(set GPR:$dst, (add GPR:$acc, - (opnode (sext_inreg GPR:$a, i16), - (sext_inreg GPR:$b, i16))))]> { + [(set rGPR:$dst, (add rGPR:$acc, + (opnode (sext_inreg rGPR:$a, i16), + (sext_inreg rGPR:$b, i16))))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; @@ -1924,10 +1932,10 @@ multiclass T2I_smla { let Inst{5-4} = 0b00; } - def BT : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC16, + def BT : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC16, !strconcat(opc, "bt"), "\t$dst, $a, $b, $acc", - [(set GPR:$dst, (add GPR:$acc, (opnode (sext_inreg GPR:$a, i16), - (sra GPR:$b, (i32 16)))))]> { + [(set rGPR:$dst, (add rGPR:$acc, (opnode (sext_inreg rGPR:$a, i16), + (sra rGPR:$b, (i32 16)))))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; @@ -1936,10 +1944,10 @@ multiclass T2I_smla { let Inst{5-4} = 0b01; } - def TB : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC16, + def TB : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC16, !strconcat(opc, "tb"), "\t$dst, $a, $b, $acc", - [(set GPR:$dst, (add GPR:$acc, (opnode (sra GPR:$a, (i32 16)), - (sext_inreg GPR:$b, i16))))]> { + [(set rGPR:$dst, (add rGPR:$acc, (opnode (sra rGPR:$a, (i32 16)), + (sext_inreg rGPR:$b, i16))))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; @@ -1948,10 +1956,10 @@ multiclass T2I_smla { let Inst{5-4} = 0b10; } - def TT : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC16, + def TT : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC16, !strconcat(opc, "tt"), "\t$dst, $a, $b, $acc", - [(set GPR:$dst, (add GPR:$acc, (opnode (sra GPR:$a, (i32 16)), - (sra GPR:$b, (i32 16)))))]> { + [(set rGPR:$dst, (add rGPR:$acc, (opnode (sra rGPR:$a, (i32 16)), + (sra rGPR:$b, (i32 16)))))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b001; @@ -1960,10 +1968,10 @@ multiclass T2I_smla { let Inst{5-4} = 0b11; } - def WB : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC16, + def WB : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC16, !strconcat(opc, "wb"), "\t$dst, $a, $b, $acc", - [(set GPR:$dst, (add GPR:$acc, (sra (opnode GPR:$a, - (sext_inreg GPR:$b, i16)), (i32 16))))]> { + [(set rGPR:$dst, (add rGPR:$acc, (sra (opnode rGPR:$a, + (sext_inreg rGPR:$b, i16)), (i32 16))))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b011; @@ -1972,10 +1980,10 @@ multiclass T2I_smla { let Inst{5-4} = 0b00; } - def WT : T2I<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC16, + def WT : T2I<(outs rGPR:$dst), (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC16, !strconcat(opc, "wt"), "\t$dst, $a, $b, $acc", - [(set GPR:$dst, (add GPR:$acc, (sra (opnode GPR:$a, - (sra GPR:$b, (i32 16))), (i32 16))))]> { + [(set rGPR:$dst, (add rGPR:$acc, (sra (opnode rGPR:$a, + (sra rGPR:$b, (i32 16))), (i32 16))))]> { let Inst{31-27} = 0b11111; let Inst{26-23} = 0b0110; let Inst{22-20} = 0b011; @@ -1989,61 +1997,61 @@ defm t2SMUL : T2I_smul<"smul", BinOpFrag<(mul node:$LHS, node:$RHS)>>; defm t2SMLA : T2I_smla<"smla", BinOpFrag<(mul node:$LHS, node:$RHS)>>; // Halfword multiple accumulate long: SMLAL -- for disassembly only -def t2SMLALBB : T2I_mac<1, 0b100, 0b1000, (outs GPR:$ldst,GPR:$hdst), - (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlalbb", "\t$ldst, $hdst, $a, $b", +def t2SMLALBB : T2I_mac<1, 0b100, 0b1000, (outs rGPR:$ldst,rGPR:$hdst), + (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlalbb", "\t$ldst, $hdst, $a, $b", [/* For disassembly only; pattern left blank */]>; -def t2SMLALBT : T2I_mac<1, 0b100, 0b1001, (outs GPR:$ldst,GPR:$hdst), - (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlalbt", "\t$ldst, $hdst, $a, $b", +def t2SMLALBT : T2I_mac<1, 0b100, 0b1001, (outs rGPR:$ldst,rGPR:$hdst), + (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlalbt", "\t$ldst, $hdst, $a, $b", [/* For disassembly only; pattern left blank */]>; -def t2SMLALTB : T2I_mac<1, 0b100, 0b1010, (outs GPR:$ldst,GPR:$hdst), - (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlaltb", "\t$ldst, $hdst, $a, $b", +def t2SMLALTB : T2I_mac<1, 0b100, 0b1010, (outs rGPR:$ldst,rGPR:$hdst), + (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlaltb", "\t$ldst, $hdst, $a, $b", [/* For disassembly only; pattern left blank */]>; -def t2SMLALTT : T2I_mac<1, 0b100, 0b1011, (outs GPR:$ldst,GPR:$hdst), - (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlaltt", "\t$ldst, $hdst, $a, $b", +def t2SMLALTT : T2I_mac<1, 0b100, 0b1011, (outs rGPR:$ldst,rGPR:$hdst), + (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlaltt", "\t$ldst, $hdst, $a, $b", [/* For disassembly only; pattern left blank */]>; // Dual halfword multiple: SMUAD, SMUSD, SMLAD, SMLSD, SMLALD, SMLSLD // These are for disassembly only. -def t2SMUAD : T2I_mac<0, 0b010, 0b0000, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - IIC_iMAC32, "smuad", "\t$dst, $a, $b", []> { +def t2SMUAD: T2I_mac<0, 0b010, 0b0000, (outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), + IIC_iMAC32, "smuad", "\t$dst, $a, $b", []> { let Inst{15-12} = 0b1111; } -def t2SMUADX : T2I_mac<0, 0b010, 0b0001, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - IIC_iMAC32, "smuadx", "\t$dst, $a, $b", []> { +def t2SMUADX:T2I_mac<0, 0b010, 0b0001, (outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), + IIC_iMAC32, "smuadx", "\t$dst, $a, $b", []> { let Inst{15-12} = 0b1111; } -def t2SMUSD : T2I_mac<0, 0b100, 0b0000, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - IIC_iMAC32, "smusd", "\t$dst, $a, $b", []> { +def t2SMUSD: T2I_mac<0, 0b100, 0b0000, (outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), + IIC_iMAC32, "smusd", "\t$dst, $a, $b", []> { let Inst{15-12} = 0b1111; } -def t2SMUSDX : T2I_mac<0, 0b100, 0b0001, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - IIC_iMAC32, "smusdx", "\t$dst, $a, $b", []> { +def t2SMUSDX:T2I_mac<0, 0b100, 0b0001, (outs rGPR:$dst), (ins rGPR:$a, rGPR:$b), + IIC_iMAC32, "smusdx", "\t$dst, $a, $b", []> { let Inst{15-12} = 0b1111; } -def t2SMLAD : T2I_mac<0, 0b010, 0b0000, (outs GPR:$dst), - (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC32, "smlad", +def t2SMLAD : T2I_mac<0, 0b010, 0b0000, (outs rGPR:$dst), + (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC32, "smlad", "\t$dst, $a, $b, $acc", []>; -def t2SMLADX : T2I_mac<0, 0b010, 0b0001, (outs GPR:$dst), - (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC32, "smladx", +def t2SMLADX : T2I_mac<0, 0b010, 0b0001, (outs rGPR:$dst), + (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC32, "smladx", "\t$dst, $a, $b, $acc", []>; -def t2SMLSD : T2I_mac<0, 0b100, 0b0000, (outs GPR:$dst), - (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC32, "smlsd", +def t2SMLSD : T2I_mac<0, 0b100, 0b0000, (outs rGPR:$dst), + (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC32, "smlsd", "\t$dst, $a, $b, $acc", []>; -def t2SMLSDX : T2I_mac<0, 0b100, 0b0001, (outs GPR:$dst), - (ins GPR:$a, GPR:$b, GPR:$acc), IIC_iMAC32, "smlsdx", +def t2SMLSDX : T2I_mac<0, 0b100, 0b0001, (outs rGPR:$dst), + (ins rGPR:$a, rGPR:$b, rGPR:$acc), IIC_iMAC32, "smlsdx", "\t$dst, $a, $b, $acc", []>; -def t2SMLALD : T2I_mac<1, 0b100, 0b1100, (outs GPR:$ldst,GPR:$hdst), - (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlald", +def t2SMLALD : T2I_mac<1, 0b100, 0b1100, (outs rGPR:$ldst,rGPR:$hdst), + (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlald", "\t$ldst, $hdst, $a, $b", []>; -def t2SMLALDX : T2I_mac<1, 0b100, 0b1101, (outs GPR:$ldst,GPR:$hdst), - (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlaldx", +def t2SMLALDX : T2I_mac<1, 0b100, 0b1101, (outs rGPR:$ldst,rGPR:$hdst), + (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlaldx", "\t$ldst, $hdst, $a, $b", []>; -def t2SMLSLD : T2I_mac<1, 0b101, 0b1100, (outs GPR:$ldst,GPR:$hdst), - (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlsld", +def t2SMLSLD : T2I_mac<1, 0b101, 0b1100, (outs rGPR:$ldst,rGPR:$hdst), + (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlsld", "\t$ldst, $hdst, $a, $b", []>; -def t2SMLSLDX : T2I_mac<1, 0b101, 0b1101, (outs GPR:$ldst,GPR:$hdst), - (ins GPR:$a,GPR:$b), IIC_iMAC64, "smlsldx", +def t2SMLSLDX : T2I_mac<1, 0b101, 0b1101, (outs rGPR:$ldst,rGPR:$hdst), + (ins rGPR:$a,rGPR:$b), IIC_iMAC64, "smlsldx", "\t$ldst, $hdst, $a, $b", []>; //===----------------------------------------------------------------------===// @@ -2061,35 +2069,35 @@ class T2I_misc op1, bits<2> op2, dag oops, dag iops, let Inst{5-4} = op2; } -def t2CLZ : T2I_misc<0b11, 0b00, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, - "clz", "\t$dst, $src", [(set GPR:$dst, (ctlz GPR:$src))]>; +def t2CLZ : T2I_misc<0b11, 0b00, (outs rGPR:$dst), (ins rGPR:$src), IIC_iUNAr, + "clz", "\t$dst, $src", [(set rGPR:$dst, (ctlz rGPR:$src))]>; -def t2RBIT : T2I_misc<0b01, 0b10, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, +def t2RBIT : T2I_misc<0b01, 0b10, (outs rGPR:$dst), (ins rGPR:$src), IIC_iUNAr, "rbit", "\t$dst, $src", - [(set GPR:$dst, (ARMrbit GPR:$src))]>; + [(set rGPR:$dst, (ARMrbit rGPR:$src))]>; -def t2REV : T2I_misc<0b01, 0b00, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, - "rev", ".w\t$dst, $src", [(set GPR:$dst, (bswap GPR:$src))]>; +def t2REV : T2I_misc<0b01, 0b00, (outs rGPR:$dst), (ins rGPR:$src), IIC_iUNAr, + "rev", ".w\t$dst, $src", [(set rGPR:$dst, (bswap rGPR:$src))]>; -def t2REV16 : T2I_misc<0b01, 0b01, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, +def t2REV16 : T2I_misc<0b01, 0b01, (outs rGPR:$dst), (ins rGPR:$src), IIC_iUNAr, "rev16", ".w\t$dst, $src", - [(set GPR:$dst, - (or (and (srl GPR:$src, (i32 8)), 0xFF), - (or (and (shl GPR:$src, (i32 8)), 0xFF00), - (or (and (srl GPR:$src, (i32 8)), 0xFF0000), - (and (shl GPR:$src, (i32 8)), 0xFF000000)))))]>; + [(set rGPR:$dst, + (or (and (srl rGPR:$src, (i32 8)), 0xFF), + (or (and (shl rGPR:$src, (i32 8)), 0xFF00), + (or (and (srl rGPR:$src, (i32 8)), 0xFF0000), + (and (shl rGPR:$src, (i32 8)), 0xFF000000)))))]>; -def t2REVSH : T2I_misc<0b01, 0b11, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, +def t2REVSH : T2I_misc<0b01, 0b11, (outs rGPR:$dst), (ins rGPR:$src), IIC_iUNAr, "revsh", ".w\t$dst, $src", - [(set GPR:$dst, + [(set rGPR:$dst, (sext_inreg - (or (srl (and GPR:$src, 0xFF00), (i32 8)), - (shl GPR:$src, (i32 8))), i16))]>; + (or (srl (and rGPR:$src, 0xFF00), (i32 8)), + (shl rGPR:$src, (i32 8))), i16))]>; -def t2PKHBT : T2I<(outs GPR:$dst), (ins GPR:$src1, GPR:$src2, i32imm:$shamt), - IIC_iALUsi, "pkhbt", "\t$dst, $src1, $src2, lsl $shamt", - [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF), - (and (shl GPR:$src2, (i32 imm:$shamt)), +def t2PKHBT : T2I<(outs rGPR:$dst), (ins rGPR:$src1, rGPR:$src2, shift_imm:$sh), + IIC_iALUsi, "pkhbt", "\t$dst, $src1, $src2$sh", + [(set rGPR:$dst, (or (and rGPR:$src1, 0xFFFF), + (and (shl rGPR:$src2, lsl_amt:$sh), 0xFFFF0000)))]>, Requires<[HasT2ExtractPack]> { let Inst{31-27} = 0b11101; @@ -2100,18 +2108,20 @@ def t2PKHBT : T2I<(outs GPR:$dst), (ins GPR:$src1, GPR:$src2, i32imm:$shamt), } // Alternate cases for PKHBT where identities eliminate some nodes. -def : T2Pat<(or (and GPR:$src1, 0xFFFF), (and GPR:$src2, 0xFFFF0000)), - (t2PKHBT GPR:$src1, GPR:$src2, 0)>, +def : T2Pat<(or (and rGPR:$src1, 0xFFFF), (and rGPR:$src2, 0xFFFF0000)), + (t2PKHBT rGPR:$src1, rGPR:$src2, 0)>, Requires<[HasT2ExtractPack]>; -def : T2Pat<(or (and GPR:$src1, 0xFFFF), (shl GPR:$src2, imm16_31:$shamt)), - (t2PKHBT GPR:$src1, GPR:$src2, imm16_31:$shamt)>, +def : T2Pat<(or (and rGPR:$src1, 0xFFFF), (shl rGPR:$src2, imm16_31:$sh)), + (t2PKHBT rGPR:$src1, rGPR:$src2, (lsl_shift_imm imm16_31:$sh))>, Requires<[HasT2ExtractPack]>; -def t2PKHTB : T2I<(outs GPR:$dst), (ins GPR:$src1, GPR:$src2, i32imm:$shamt), - IIC_iALUsi, "pkhtb", "\t$dst, $src1, $src2, asr $shamt", - [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF0000), - (and (sra GPR:$src2, imm16_31:$shamt), - 0xFFFF)))]>, +// Note: Shifts of 1-15 bits will be transformed to srl instead of sra and +// will match the pattern below. +def t2PKHTB : T2I<(outs rGPR:$dst), (ins rGPR:$src1, rGPR:$src2, shift_imm:$sh), + IIC_iALUsi, "pkhtb", "\t$dst, $src1, $src2$sh", + [(set rGPR:$dst, (or (and rGPR:$src1, 0xFFFF0000), + (and (sra rGPR:$src2, asr_amt:$sh), + 0xFFFF)))]>, Requires<[HasT2ExtractPack]> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; @@ -2122,18 +2132,17 @@ def t2PKHTB : T2I<(outs GPR:$dst), (ins GPR:$src1, GPR:$src2, i32imm:$shamt), // Alternate cases for PKHTB where identities eliminate some nodes. Note that // a shift amount of 0 is *not legal* here, it is PKHBT instead. -def : T2Pat<(or (and GPR:$src1, 0xFFFF0000), (srl GPR:$src2, (i32 16))), - (t2PKHTB GPR:$src1, GPR:$src2, 16)>, +def : T2Pat<(or (and rGPR:$src1, 0xFFFF0000), (srl rGPR:$src2, imm16_31:$sh)), + (t2PKHTB rGPR:$src1, rGPR:$src2, (asr_shift_imm imm16_31:$sh))>, Requires<[HasT2ExtractPack]>; -def : T2Pat<(or (and GPR:$src1, 0xFFFF0000), - (and (srl GPR:$src2, imm1_15:$shamt), 0xFFFF)), - (t2PKHTB GPR:$src1, GPR:$src2, imm1_15:$shamt)>, +def : T2Pat<(or (and rGPR:$src1, 0xFFFF0000), + (and (srl rGPR:$src2, imm1_15:$sh), 0xFFFF)), + (t2PKHTB rGPR:$src1, rGPR:$src2, (asr_shift_imm imm1_15:$sh))>, Requires<[HasT2ExtractPack]>; //===----------------------------------------------------------------------===// // Comparison Instructions... // - defm t2CMP : T2I_cmp_irs<0b1101, "cmp", BinOpFrag<(ARMcmp node:$LHS, node:$RHS)>>; defm t2CMPz : T2I_cmp_irs<0b1101, "cmp", @@ -2157,18 +2166,13 @@ defm t2TST : T2I_cmp_irs<0b0000, "tst", defm t2TEQ : T2I_cmp_irs<0b0100, "teq", BinOpFrag<(ARMcmpZ (xor node:$LHS, node:$RHS), 0)>>; -// A8.6.27 CBNZ, CBZ - Compare and branch on (non)zero. -// Short range conditional branch. Looks awesome for loops. Need to figure -// out how to use this one. - - // Conditional moves // FIXME: should be able to write a pattern for ARMcmov, but can't use // a two-value operand where a dag node expects two operands. :( let neverHasSideEffects = 1 in { -def t2MOVCCr : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true), IIC_iCMOVr, +def t2MOVCCr : T2I<(outs rGPR:$dst), (ins rGPR:$false, rGPR:$true), IIC_iCMOVr, "mov", ".w\t$dst, $true", - [/*(set GPR:$dst, (ARMcmov GPR:$false, GPR:$true, imm:$cc, CCR:$ccr))*/]>, + [/*(set rGPR:$dst, (ARMcmov rGPR:$false, rGPR:$true, imm:$cc, CCR:$ccr))*/]>, RegConstraint<"$false = $dst"> { let Inst{31-27} = 0b11101; let Inst{26-25} = 0b01; @@ -2179,9 +2183,9 @@ def t2MOVCCr : T2I<(outs GPR:$dst), (ins GPR:$false, GPR:$true), IIC_iCMOVr, let Inst{7-4} = 0b0000; } -def t2MOVCCi : T2I<(outs GPR:$dst), (ins GPR:$false, t2_so_imm:$true), +def t2MOVCCi : T2I<(outs rGPR:$dst), (ins rGPR:$false, t2_so_imm:$true), IIC_iCMOVi, "mov", ".w\t$dst, $true", -[/*(set GPR:$dst, (ARMcmov GPR:$false, t2_so_imm:$true, imm:$cc, CCR:$ccr))*/]>, +[/*(set rGPR:$dst,(ARMcmov rGPR:$false,t2_so_imm:$true, imm:$cc, CCR:$ccr))*/]>, RegConstraint<"$false = $dst"> { let Inst{31-27} = 0b11110; let Inst{25} = 0; @@ -2201,20 +2205,20 @@ class T2I_movcc_sh opcod, dag oops, dag iops, InstrItinClass itin, let Inst{19-16} = 0b1111; // Rn let Inst{5-4} = opcod; // Shift type. } -def t2MOVCClsl : T2I_movcc_sh<0b00, (outs GPR:$dst), - (ins GPR:$false, GPR:$true, i32imm:$rhs), +def t2MOVCClsl : T2I_movcc_sh<0b00, (outs rGPR:$dst), + (ins rGPR:$false, rGPR:$true, i32imm:$rhs), IIC_iCMOVsi, "lsl", ".w\t$dst, $true, $rhs", []>, RegConstraint<"$false = $dst">; -def t2MOVCClsr : T2I_movcc_sh<0b01, (outs GPR:$dst), - (ins GPR:$false, GPR:$true, i32imm:$rhs), +def t2MOVCClsr : T2I_movcc_sh<0b01, (outs rGPR:$dst), + (ins rGPR:$false, rGPR:$true, i32imm:$rhs), IIC_iCMOVsi, "lsr", ".w\t$dst, $true, $rhs", []>, RegConstraint<"$false = $dst">; -def t2MOVCCasr : T2I_movcc_sh<0b10, (outs GPR:$dst), - (ins GPR:$false, GPR:$true, i32imm:$rhs), +def t2MOVCCasr : T2I_movcc_sh<0b10, (outs rGPR:$dst), + (ins rGPR:$false, rGPR:$true, i32imm:$rhs), IIC_iCMOVsi, "asr", ".w\t$dst, $true, $rhs", []>, RegConstraint<"$false = $dst">; -def t2MOVCCror : T2I_movcc_sh<0b11, (outs GPR:$dst), - (ins GPR:$false, GPR:$true, i32imm:$rhs), +def t2MOVCCror : T2I_movcc_sh<0b11, (outs rGPR:$dst), + (ins rGPR:$false, rGPR:$true, i32imm:$rhs), IIC_iCMOVsi, "ror", ".w\t$dst, $true, $rhs", []>, RegConstraint<"$false = $dst">; } // neverHasSideEffects @@ -2225,21 +2229,15 @@ def t2MOVCCror : T2I_movcc_sh<0b11, (outs GPR:$dst), // memory barriers protect the atomic sequences let hasSideEffects = 1 in { -def t2Int_MemBarrierV7 : AInoP<(outs), (ins), - ThumbFrm, NoItinerary, - "dmb", "", - [(ARMMemBarrierV7)]>, - Requires<[IsThumb2]> { +def t2DMBsy : AInoP<(outs), (ins), ThumbFrm, NoItinerary, "dmb", "", + [(ARMMemBarrier)]>, Requires<[IsThumb, HasDB]> { let Inst{31-4} = 0xF3BF8F5; // FIXME: add support for options other than a full system DMB let Inst{3-0} = 0b1111; } -def t2Int_SyncBarrierV7 : AInoP<(outs), (ins), - ThumbFrm, NoItinerary, - "dsb", "", - [(ARMSyncBarrierV7)]>, - Requires<[IsThumb2]> { +def t2DSBsy : AInoP<(outs), (ins), ThumbFrm, NoItinerary, "dsb", "", + [(ARMSyncBarrier)]>, Requires<[IsThumb, HasDB]> { let Inst{31-4} = 0xF3BF8F4; // FIXME: add support for options other than a full system DSB let Inst{3-0} = 0b1111; @@ -2329,13 +2327,13 @@ class T2I_strex opcod, dag oops, dag iops, AddrMode am, SizeFlagVal sz, } let mayLoad = 1 in { -def t2LDREXB : T2I_ldrex<0b00, (outs GPR:$dest), (ins GPR:$ptr), AddrModeNone, +def t2LDREXB : T2I_ldrex<0b00, (outs rGPR:$dest), (ins rGPR:$ptr), AddrModeNone, Size4Bytes, NoItinerary, "ldrexb", "\t$dest, [$ptr]", "", []>; -def t2LDREXH : T2I_ldrex<0b01, (outs GPR:$dest), (ins GPR:$ptr), AddrModeNone, +def t2LDREXH : T2I_ldrex<0b01, (outs rGPR:$dest), (ins rGPR:$ptr), AddrModeNone, Size4Bytes, NoItinerary, "ldrexh", "\t$dest, [$ptr]", "", []>; -def t2LDREX : Thumb2I<(outs GPR:$dest), (ins GPR:$ptr), AddrModeNone, +def t2LDREX : Thumb2I<(outs rGPR:$dest), (ins rGPR:$ptr), AddrModeNone, Size4Bytes, NoItinerary, "ldrex", "\t$dest, [$ptr]", "", []> { @@ -2344,20 +2342,20 @@ def t2LDREX : Thumb2I<(outs GPR:$dest), (ins GPR:$ptr), AddrModeNone, let Inst{11-8} = 0b1111; let Inst{7-0} = 0b00000000; // imm8 = 0 } -def t2LDREXD : T2I_ldrex<0b11, (outs GPR:$dest, GPR:$dest2), (ins GPR:$ptr), +def t2LDREXD : T2I_ldrex<0b11, (outs rGPR:$dest, rGPR:$dest2), (ins rGPR:$ptr), AddrModeNone, Size4Bytes, NoItinerary, "ldrexd", "\t$dest, $dest2, [$ptr]", "", [], {?, ?, ?, ?}>; } let mayStore = 1, Constraints = "@earlyclobber $success" in { -def t2STREXB : T2I_strex<0b00, (outs GPR:$success), (ins GPR:$src, GPR:$ptr), +def t2STREXB : T2I_strex<0b00, (outs rGPR:$success), (ins rGPR:$src, rGPR:$ptr), AddrModeNone, Size4Bytes, NoItinerary, "strexb", "\t$success, $src, [$ptr]", "", []>; -def t2STREXH : T2I_strex<0b01, (outs GPR:$success), (ins GPR:$src, GPR:$ptr), +def t2STREXH : T2I_strex<0b01, (outs rGPR:$success), (ins rGPR:$src, rGPR:$ptr), AddrModeNone, Size4Bytes, NoItinerary, "strexh", "\t$success, $src, [$ptr]", "", []>; -def t2STREX : Thumb2I<(outs GPR:$success), (ins GPR:$src, GPR:$ptr), +def t2STREX : Thumb2I<(outs rGPR:$success), (ins rGPR:$src, rGPR:$ptr), AddrModeNone, Size4Bytes, NoItinerary, "strex", "\t$success, $src, [$ptr]", "", []> { @@ -2365,8 +2363,8 @@ def t2STREX : Thumb2I<(outs GPR:$success), (ins GPR:$src, GPR:$ptr), let Inst{26-20} = 0b0000100; let Inst{7-0} = 0b00000000; // imm8 = 0 } -def t2STREXD : T2I_strex<0b11, (outs GPR:$success), - (ins GPR:$src, GPR:$src2, GPR:$ptr), +def t2STREXD : T2I_strex<0b11, (outs rGPR:$success), + (ins rGPR:$src, rGPR:$src2, rGPR:$ptr), AddrModeNone, Size4Bytes, NoItinerary, "strexd", "\t$success, $src, $src2, [$ptr]", "", [], {?, ?, ?, ?}>; @@ -2416,7 +2414,7 @@ let Defs = D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31 ], hasSideEffects = 1, isBarrier = 1 in { - def t2Int_eh_sjlj_setjmp : Thumb2XI<(outs), (ins GPR:$src, tGPR:$val), + def t2Int_eh_sjlj_setjmp : Thumb2XI<(outs), (ins tGPR:$src, tGPR:$val), AddrModeNone, SizeSpecial, NoItinerary, "mov\t$val, pc\t${:comment} begin eh.setjmp\n\t" "adds\t$val, #7\n\t" @@ -2425,14 +2423,14 @@ let Defs = "b\t1f\n\t" "movs\tr0, #1\t${:comment} end eh.setjmp\n\t" "1:", "", - [(set R0, (ARMeh_sjlj_setjmp GPR:$src, tGPR:$val))]>, + [(set R0, (ARMeh_sjlj_setjmp tGPR:$src, tGPR:$val))]>, Requires<[IsThumb2, HasVFP2]>; } let Defs = [ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR ], hasSideEffects = 1, isBarrier = 1 in { - def t2Int_eh_sjlj_setjmp_nofp : Thumb2XI<(outs), (ins GPR:$src, tGPR:$val), + def t2Int_eh_sjlj_setjmp_nofp : Thumb2XI<(outs), (ins tGPR:$src, tGPR:$val), AddrModeNone, SizeSpecial, NoItinerary, "mov\t$val, pc\t${:comment} begin eh.setjmp\n\t" "adds\t$val, #7\n\t" @@ -2441,7 +2439,7 @@ let Defs = "b\t1f\n\t" "movs\tr0, #1\t${:comment} end eh.setjmp\n\t" "1:", "", - [(set R0, (ARMeh_sjlj_setjmp GPR:$src, tGPR:$val))]>, + [(set R0, (ARMeh_sjlj_setjmp tGPR:$src, tGPR:$val))]>, Requires<[IsThumb2, NoVFP]>; } @@ -2482,7 +2480,7 @@ let isNotDuplicable = 1, isIndirectBranch = 1 in { def t2BR_JT : T2JTI<(outs), (ins GPR:$target, GPR:$index, jt2block_operand:$jt, i32imm:$id), - IIC_Br, "mov\tpc, $target\n$jt", + IIC_Br, "mov\tpc, $target$jt", [(ARMbr2jt GPR:$target, GPR:$index, tjumptable:$jt, imm:$id)]> { let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0100100; @@ -2496,7 +2494,7 @@ def t2BR_JT : def t2TBB : T2JTI<(outs), (ins tb_addrmode:$index, jt2block_operand:$jt, i32imm:$id), - IIC_Br, "tbb\t$index\n$jt", []> { + IIC_Br, "tbb\t$index$jt", []> { let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0001101; let Inst{19-16} = 0b1111; // Rn = pc (table follows this instruction) @@ -2507,7 +2505,7 @@ def t2TBB : def t2TBH : T2JTI<(outs), (ins tb_addrmode:$index, jt2block_operand:$jt, i32imm:$id), - IIC_Br, "tbh\t$index\n$jt", []> { + IIC_Br, "tbh\t$index$jt", []> { let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0001101; let Inst{19-16} = 0b1111; // Rn = pc (table follows this instruction) @@ -2560,7 +2558,7 @@ def t2IT : Thumb2XI<(outs), (ins it_pred:$cc, it_mask:$mask), // Branch and Exchange Jazelle -- for disassembly only // Rm = Inst{19-16} -def t2BXJ : T2I<(outs), (ins GPR:$func), NoItinerary, "bxj", "\t$func", +def t2BXJ : T2I<(outs), (ins rGPR:$func), NoItinerary, "bxj", "\t$func", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11110; let Inst{26} = 0; @@ -2647,25 +2645,25 @@ def t2SRSIA : T2I<(outs), (ins i32imm:$mode),NoItinerary,"srsia","\tsp, $mode", } // Return From Exception is a system instruction -- for disassembly only -def t2RFEDBW : T2I<(outs), (ins GPR:$base), NoItinerary, "rfedb", "\t$base!", +def t2RFEDBW : T2I<(outs), (ins rGPR:$base), NoItinerary, "rfedb", "\t$base!", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0000011; // W = 1 } -def t2RFEDB : T2I<(outs), (ins GPR:$base), NoItinerary, "rfeab", "\t$base", +def t2RFEDB : T2I<(outs), (ins rGPR:$base), NoItinerary, "rfeab", "\t$base", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0000001; // W = 0 } -def t2RFEIAW : T2I<(outs), (ins GPR:$base), NoItinerary, "rfeia", "\t$base!", +def t2RFEIAW : T2I<(outs), (ins rGPR:$base), NoItinerary, "rfeia", "\t$base!", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0011011; // W = 1 } -def t2RFEIA : T2I<(outs), (ins GPR:$base), NoItinerary, "rfeia", "\t$base", +def t2RFEIA : T2I<(outs), (ins rGPR:$base), NoItinerary, "rfeia", "\t$base", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11101; let Inst{26-20} = 0b0011001; // W = 0 @@ -2676,26 +2674,26 @@ def t2RFEIA : T2I<(outs), (ins GPR:$base), NoItinerary, "rfeia", "\t$base", // // Two piece so_imms. -def : T2Pat<(or GPR:$LHS, t2_so_imm2part:$RHS), - (t2ORRri (t2ORRri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), +def : T2Pat<(or rGPR:$LHS, t2_so_imm2part:$RHS), + (t2ORRri (t2ORRri rGPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), (t2_so_imm2part_2 imm:$RHS))>; -def : T2Pat<(xor GPR:$LHS, t2_so_imm2part:$RHS), - (t2EORri (t2EORri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), +def : T2Pat<(xor rGPR:$LHS, t2_so_imm2part:$RHS), + (t2EORri (t2EORri rGPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), (t2_so_imm2part_2 imm:$RHS))>; -def : T2Pat<(add GPR:$LHS, t2_so_imm2part:$RHS), - (t2ADDri (t2ADDri GPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), +def : T2Pat<(add rGPR:$LHS, t2_so_imm2part:$RHS), + (t2ADDri (t2ADDri rGPR:$LHS, (t2_so_imm2part_1 imm:$RHS)), (t2_so_imm2part_2 imm:$RHS))>; -def : T2Pat<(add GPR:$LHS, t2_so_neg_imm2part:$RHS), - (t2SUBri (t2SUBri GPR:$LHS, (t2_so_neg_imm2part_1 imm:$RHS)), +def : T2Pat<(add rGPR:$LHS, t2_so_neg_imm2part:$RHS), + (t2SUBri (t2SUBri rGPR:$LHS, (t2_so_neg_imm2part_1 imm:$RHS)), (t2_so_neg_imm2part_2 imm:$RHS))>; // 32-bit immediate using movw + movt. // This is a single pseudo instruction to make it re-materializable. Remove // when we can do generalized remat. let isReMaterializable = 1 in -def t2MOVi32imm : T2Ix2<(outs GPR:$dst), (ins i32imm:$src), IIC_iMOVi, +def t2MOVi32imm : T2Ix2<(outs rGPR:$dst), (ins i32imm:$src), IIC_iMOVi, "movw", "\t$dst, ${src:lo16}\n\tmovt${p}\t$dst, ${src:hi16}", - [(set GPR:$dst, (i32 imm:$src))]>; + [(set rGPR:$dst, (i32 imm:$src))]>; // ConstantPool, GlobalAddress, and JumpTable def : T2Pat<(ARMWrapper tglobaladdr :$dst), (t2LEApcrel tglobaladdr :$dst)>, @@ -2723,7 +2721,7 @@ def t2LDRpci_pic : PseudoInst<(outs GPR:$dst), (ins i32imm:$addr, pclabel:$cp), // // Rd = Instr{11-8} -def t2MRS : T2I<(outs GPR:$dst), (ins), NoItinerary, "mrs", "\t$dst, cpsr", +def t2MRS : T2I<(outs rGPR:$dst), (ins), NoItinerary, "mrs", "\t$dst, cpsr", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11110; let Inst{26} = 0; @@ -2734,7 +2732,7 @@ def t2MRS : T2I<(outs GPR:$dst), (ins), NoItinerary, "mrs", "\t$dst, cpsr", } // Rd = Instr{11-8} -def t2MRSsys : T2I<(outs GPR:$dst), (ins), NoItinerary, "mrs", "\t$dst, spsr", +def t2MRSsys : T2I<(outs rGPR:$dst), (ins), NoItinerary, "mrs", "\t$dst, spsr", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11110; let Inst{26} = 0; @@ -2745,7 +2743,7 @@ def t2MRSsys : T2I<(outs GPR:$dst), (ins), NoItinerary, "mrs", "\t$dst, spsr", } // Rn = Inst{19-16} -def t2MSR : T2I<(outs), (ins GPR:$src, msr_mask:$mask), NoItinerary, "msr", +def t2MSR : T2I<(outs), (ins rGPR:$src, msr_mask:$mask), NoItinerary, "msr", "\tcpsr$mask, $src", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11110; @@ -2757,7 +2755,7 @@ def t2MSR : T2I<(outs), (ins GPR:$src, msr_mask:$mask), NoItinerary, "msr", } // Rn = Inst{19-16} -def t2MSRsys : T2I<(outs), (ins GPR:$src, msr_mask:$mask), NoItinerary, "msr", +def t2MSRsys : T2I<(outs), (ins rGPR:$src, msr_mask:$mask), NoItinerary, "msr", "\tspsr$mask, $src", [/* For disassembly only; pattern left blank */]> { let Inst{31-27} = 0b11110; diff --git a/lib/Target/ARM/ARMInstrVFP.td b/lib/Target/ARM/ARMInstrVFP.td index 84c23e1..c29e096 100644 --- a/lib/Target/ARM/ARMInstrVFP.td +++ b/lib/Target/ARM/ARMInstrVFP.td @@ -77,61 +77,61 @@ def VSTRS : ASI5<0b1101, 0b00, (outs), (ins SPR:$src, addrmode5:$addr), // let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in { -def VLDMD : AXDI5<(outs), (ins addrmode5:$addr, pred:$p, reglist:$dsts, +def VLDMD : AXDI4<(outs), (ins addrmode4:$addr, pred:$p, reglist:$dsts, variable_ops), IndexModeNone, IIC_fpLoadm, - "vldm${addr:submode}${p}\t${addr:base}, $dsts", "", []> { + "vldm${addr:submode}${p}\t$addr, $dsts", "", []> { let Inst{20} = 1; } -def VLDMS : AXSI5<(outs), (ins addrmode5:$addr, pred:$p, reglist:$dsts, +def VLDMS : AXSI4<(outs), (ins addrmode4:$addr, pred:$p, reglist:$dsts, variable_ops), IndexModeNone, IIC_fpLoadm, - "vldm${addr:submode}${p}\t${addr:base}, $dsts", "", []> { + "vldm${addr:submode}${p}\t$addr, $dsts", "", []> { let Inst{20} = 1; } -def VLDMD_UPD : AXDI5<(outs GPR:$wb), (ins addrmode5:$addr, pred:$p, +def VLDMD_UPD : AXDI4<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, reglist:$dsts, variable_ops), IndexModeUpd, IIC_fpLoadm, - "vldm${addr:submode}${p}\t${addr:base}!, $dsts", - "$addr.base = $wb", []> { + "vldm${addr:submode}${p}\t$addr!, $dsts", + "$addr.addr = $wb", []> { let Inst{20} = 1; } -def VLDMS_UPD : AXSI5<(outs GPR:$wb), (ins addrmode5:$addr, pred:$p, +def VLDMS_UPD : AXSI4<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, reglist:$dsts, variable_ops), IndexModeUpd, IIC_fpLoadm, - "vldm${addr:submode}${p}\t${addr:base}!, $dsts", - "$addr.base = $wb", []> { + "vldm${addr:submode}${p}\t$addr!, $dsts", + "$addr.addr = $wb", []> { let Inst{20} = 1; } } // mayLoad, neverHasSideEffects, hasExtraDefRegAllocReq let mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 in { -def VSTMD : AXDI5<(outs), (ins addrmode5:$addr, pred:$p, reglist:$srcs, +def VSTMD : AXDI4<(outs), (ins addrmode4:$addr, pred:$p, reglist:$srcs, variable_ops), IndexModeNone, IIC_fpStorem, - "vstm${addr:submode}${p}\t${addr:base}, $srcs", "", []> { + "vstm${addr:submode}${p}\t$addr, $srcs", "", []> { let Inst{20} = 0; } -def VSTMS : AXSI5<(outs), (ins addrmode5:$addr, pred:$p, reglist:$srcs, +def VSTMS : AXSI4<(outs), (ins addrmode4:$addr, pred:$p, reglist:$srcs, variable_ops), IndexModeNone, IIC_fpStorem, - "vstm${addr:submode}${p}\t${addr:base}, $srcs", "", []> { + "vstm${addr:submode}${p}\t$addr, $srcs", "", []> { let Inst{20} = 0; } -def VSTMD_UPD : AXDI5<(outs GPR:$wb), (ins addrmode5:$addr, pred:$p, +def VSTMD_UPD : AXDI4<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, reglist:$srcs, variable_ops), IndexModeUpd, IIC_fpStorem, - "vstm${addr:submode}${p}\t${addr:base}!, $srcs", - "$addr.base = $wb", []> { + "vstm${addr:submode}${p}\t$addr!, $srcs", + "$addr.addr = $wb", []> { let Inst{20} = 0; } -def VSTMS_UPD : AXSI5<(outs GPR:$wb), (ins addrmode5:$addr, pred:$p, +def VSTMS_UPD : AXSI4<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, reglist:$srcs, variable_ops), IndexModeUpd, IIC_fpStorem, - "vstm${addr:submode}${p}\t${addr:base}!, $srcs", - "$addr.base = $wb", []> { + "vstm${addr:submode}${p}\t$addr!, $srcs", + "$addr.addr = $wb", []> { let Inst{20} = 0; } } // mayStore, neverHasSideEffects, hasExtraSrcRegAllocReq @@ -420,34 +420,35 @@ def VTOUIZS : AVConv1In<0b11101, 0b11, 0b1100, 0b1010, // And the Z bit '0' variants, i.e. use the rounding mode specified by FPSCR. // For disassembly only. - +let Uses = [FPSCR] in { def VTOSIRD : AVConv1I<0b11101, 0b11, 0b1101, 0b1011, (outs SPR:$dst), (ins DPR:$a), IIC_fpCVTDI, "vcvtr", ".s32.f64\t$dst, $a", - [/* For disassembly only; pattern left blank */]> { + [(set SPR:$dst, (int_arm_vcvtr (f64 DPR:$a)))]> { let Inst{7} = 0; // Z bit } def VTOSIRS : AVConv1In<0b11101, 0b11, 0b1101, 0b1010, (outs SPR:$dst), (ins SPR:$a), IIC_fpCVTSI, "vcvtr", ".s32.f32\t$dst, $a", - [/* For disassembly only; pattern left blank */]> { + [(set SPR:$dst, (int_arm_vcvtr SPR:$a))]> { let Inst{7} = 0; // Z bit } def VTOUIRD : AVConv1I<0b11101, 0b11, 0b1100, 0b1011, (outs SPR:$dst), (ins DPR:$a), IIC_fpCVTDI, "vcvtr", ".u32.f64\t$dst, $a", - [/* For disassembly only; pattern left blank */]> { + [(set SPR:$dst, (int_arm_vcvtru (f64 DPR:$a)))]> { let Inst{7} = 0; // Z bit } def VTOUIRS : AVConv1In<0b11101, 0b11, 0b1100, 0b1010, (outs SPR:$dst), (ins SPR:$a), IIC_fpCVTSI, "vcvtr", ".u32.f32\t$dst, $a", - [/* For disassembly only; pattern left blank */]> { + [(set SPR:$dst, (int_arm_vcvtru SPR:$a))]> { let Inst{7} = 0; // Z bit } +} // Convert between floating-point and fixed-point // Data type for fixed-point naming convention: @@ -460,6 +461,7 @@ let Constraints = "$a = $dst" in { // FP to Fixed-Point: +let isCodeGenOnly = 1 in { def VTOSHS : AVConv1XI<0b11101, 0b11, 0b1110, 0b1010, 0, (outs SPR:$dst), (ins SPR:$a, i32imm:$fbits), IIC_fpCVTSI, "vcvt", ".s16.f32\t$dst, $a, $fbits", @@ -499,9 +501,11 @@ def VTOULD : AVConv1XI<0b11101, 0b11, 0b1111, 0b1011, 1, (outs DPR:$dst), (ins DPR:$a, i32imm:$fbits), IIC_fpCVTDI, "vcvt", ".u32.f64\t$dst, $a, $fbits", [/* For disassembly only; pattern left blank */]>; +} // Fixed-Point to FP: +let isCodeGenOnly = 1 in { def VSHTOS : AVConv1XI<0b11101, 0b11, 0b1010, 0b1010, 0, (outs SPR:$dst), (ins SPR:$a, i32imm:$fbits), IIC_fpCVTIS, "vcvt", ".f32.s16\t$dst, $a, $fbits", @@ -541,6 +545,7 @@ def VULTOD : AVConv1XI<0b11101, 0b11, 0b1011, 0b1011, 1, (outs DPR:$dst), (ins DPR:$a, i32imm:$fbits), IIC_fpCVTID, "vcvt", ".f64.u32\t$dst, $a, $fbits", [/* For disassembly only; pattern left blank */]>; +} } // End of 'let Constraints = "$src = $dst" in' @@ -654,32 +659,27 @@ def FMSTAT : VFPAI<(outs), (ins), VFPMiscFrm, IIC_fpSTAT, "vmrs", } // FPSCR <-> GPR (for disassembly only) - -let neverHasSideEffects = 1 in { -let Uses = [FPSCR] in { -def VMRS : VFPAI<(outs GPR:$dst), (ins), VFPMiscFrm, IIC_fpSTAT, "vmrs", - "\t$dst, fpscr", - [/* For disassembly only; pattern left blank */]> { +let hasSideEffects = 1, Uses = [FPSCR] in +def VMRS : VFPAI<(outs GPR:$dst), (ins), VFPMiscFrm, IIC_fpSTAT, + "vmrs", "\t$dst, fpscr", + [(set GPR:$dst, (int_arm_get_fpscr))]> { let Inst{27-20} = 0b11101111; let Inst{19-16} = 0b0001; let Inst{11-8} = 0b1010; let Inst{7} = 0; let Inst{4} = 1; } -} -let Defs = [FPSCR] in { -def VMSR : VFPAI<(outs), (ins GPR:$src), VFPMiscFrm, IIC_fpSTAT, "vmsr", - "\tfpscr, $src", - [/* For disassembly only; pattern left blank */]> { +let Defs = [FPSCR] in +def VMSR : VFPAI<(outs), (ins GPR:$src), VFPMiscFrm, IIC_fpSTAT, + "vmsr", "\tfpscr, $src", + [(int_arm_set_fpscr GPR:$src)]> { let Inst{27-20} = 0b11101110; let Inst{19-16} = 0b0001; let Inst{11-8} = 0b1010; let Inst{7} = 0; let Inst{4} = 1; } -} -} // neverHasSideEffects // Materialize FP immediates. VFP3 only. let isReMaterializable = 1 in { diff --git a/lib/Target/ARM/ARMLoadStoreOptimizer.cpp b/lib/Target/ARM/ARMLoadStoreOptimizer.cpp index f80e316..2b7645a 100644 --- a/lib/Target/ARM/ARMLoadStoreOptimizer.cpp +++ b/lib/Target/ARM/ARMLoadStoreOptimizer.cpp @@ -57,7 +57,7 @@ STATISTIC(NumSTRD2STR, "Number of strd instructions turned back into str's"); namespace { struct ARMLoadStoreOpt : public MachineFunctionPass { static char ID; - ARMLoadStoreOpt() : MachineFunctionPass(&ID) {} + ARMLoadStoreOpt() : MachineFunctionPass(ID) {} const TargetInstrInfo *TII; const TargetRegisterInfo *TRI; @@ -193,20 +193,17 @@ ARMLoadStoreOpt::MergeOps(MachineBasicBlock &MBB, return false; ARM_AM::AMSubMode Mode = ARM_AM::ia; - bool isAM4 = isi32Load(Opcode) || isi32Store(Opcode); - if (isAM4 && Offset == 4) { - if (isThumb2) - // Thumb2 does not support ldmib / stmib. - return false; + // VFP and Thumb2 do not support IB or DA modes. + bool isNotVFP = isi32Load(Opcode) || isi32Store(Opcode); + bool haveIBAndDA = isNotVFP && !isThumb2; + if (Offset == 4 && haveIBAndDA) Mode = ARM_AM::ib; - } else if (isAM4 && Offset == -4 * (int)NumRegs + 4) { - if (isThumb2) - // Thumb2 does not support ldmda / stmda. - return false; + else if (Offset == -4 * (int)NumRegs + 4 && haveIBAndDA) Mode = ARM_AM::da; - } else if (isAM4 && Offset == -4 * (int)NumRegs) { + else if (Offset == -4 * (int)NumRegs && isNotVFP) + // VLDM/VSTM do not support DB mode without also updating the base reg. Mode = ARM_AM::db; - } else if (Offset != 0) { + else if (Offset != 0) { // If starting offset isn't zero, insert a MI to materialize a new base. // But only do so if it is cost effective, i.e. merging more than two // loads / stores. @@ -246,18 +243,12 @@ ARMLoadStoreOpt::MergeOps(MachineBasicBlock &MBB, BaseKill = true; // New base is always killed right its use. } - bool isDPR = (Opcode == ARM::VLDRD || Opcode == ARM::VSTRD); bool isDef = (isi32Load(Opcode) || Opcode == ARM::VLDRS || Opcode == ARM::VLDRD); Opcode = getLoadStoreMultipleOpcode(Opcode); - MachineInstrBuilder MIB = (isAM4) - ? BuildMI(MBB, MBBI, dl, TII->get(Opcode)) - .addReg(Base, getKillRegState(BaseKill)) - .addImm(ARM_AM::getAM4ModeImm(Mode)).addImm(Pred).addReg(PredReg) - : BuildMI(MBB, MBBI, dl, TII->get(Opcode)) - .addReg(Base, getKillRegState(BaseKill)) - .addImm(ARM_AM::getAM5Opc(Mode, isDPR ? NumRegs<<1 : NumRegs)) - .addImm(Pred).addReg(PredReg); + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII->get(Opcode)) + .addReg(Base, getKillRegState(BaseKill)) + .addImm(ARM_AM::getAM4ModeImm(Mode)).addImm(Pred).addReg(PredReg); for (unsigned i = 0; i != NumRegs; ++i) MIB = MIB.addReg(Regs[i].first, getDefRegState(isDef) | getKillRegState(Regs[i].second)); @@ -333,6 +324,7 @@ void ARMLoadStoreOpt::MergeOpsUpdate(MachineBasicBlock &MBB, if (KilledRegs.count(Reg)) { unsigned j = Killer[Reg]; memOps[j].MBBI->getOperand(0).setIsKill(false); + memOps[j].isKill = false; } } MBB.erase(memOps[i].MBBI); @@ -348,7 +340,7 @@ ARMLoadStoreOpt::MergeLDR_STR(MachineBasicBlock &MBB, unsigned SIndex, ARMCC::CondCodes Pred, unsigned PredReg, unsigned Scratch, MemOpQueue &MemOps, SmallVector &Merges) { - bool isAM4 = isi32Load(Opcode) || isi32Store(Opcode); + bool isNotVFP = isi32Load(Opcode) || isi32Store(Opcode); int Offset = MemOps[SIndex].Offset; int SOffset = Offset; unsigned insertAfter = SIndex; @@ -366,12 +358,12 @@ ARMLoadStoreOpt::MergeLDR_STR(MachineBasicBlock &MBB, unsigned SIndex, unsigned Reg = MO.getReg(); unsigned RegNum = MO.isUndef() ? UINT_MAX : ARMRegisterInfo::getRegisterNumbering(Reg); - // AM4 - register numbers in ascending order. - // AM5 - consecutive register numbers in ascending order. - // Can only do up to 16 double-word registers per insn. + // Register numbers must be in ascending order. For VFP, the registers + // must also be consecutive and there is a limit of 16 double-word + // registers per instruction. if (Reg != ARM::SP && NewOffset == Offset + (int)Size && - ((isAM4 && RegNum > PRegNum) + ((isNotVFP && RegNum > PRegNum) || ((Size < 8 || Count < 16) && RegNum == PRegNum+1))) { Offset += Size; PRegNum = RegNum; @@ -409,7 +401,7 @@ static inline bool isMatchingDecrement(MachineInstr *MI, unsigned Base, return false; // Make sure the offset fits in 8 bits. - if (Bytes <= 0 || (Limit && Bytes >= Limit)) + if (Bytes == 0 || (Limit && Bytes >= Limit)) return false; unsigned Scale = (MI->getOpcode() == ARM::tSUBspi) ? 4 : 1; // FIXME @@ -433,7 +425,7 @@ static inline bool isMatchingIncrement(MachineInstr *MI, unsigned Base, MI->getOpcode() != ARM::ADDri) return false; - if (Bytes <= 0 || (Limit && Bytes >= Limit)) + if (Bytes == 0 || (Limit && Bytes >= Limit)) // Make sure the offset fits in 8 bits. return false; @@ -464,12 +456,12 @@ static inline unsigned getLSMultipleTransferSize(MachineInstr *MI) { case ARM::STM: case ARM::t2LDM: case ARM::t2STM: - return (MI->getNumOperands() - 4) * 4; case ARM::VLDMS: case ARM::VSTMS: + return (MI->getNumOperands() - 4) * 4; case ARM::VLDMD: case ARM::VSTMD: - return ARM_AM::getAM5Offset(MI->getOperand(1).getImm()) * 4; + return (MI->getNumOperands() - 4) * 8; } } @@ -512,26 +504,17 @@ bool ARMLoadStoreOpt::MergeBaseUpdateLSMultiple(MachineBasicBlock &MBB, ARMCC::CondCodes Pred = llvm::getInstrPredicate(MI, PredReg); int Opcode = MI->getOpcode(); DebugLoc dl = MI->getDebugLoc(); - bool isAM4 = (Opcode == ARM::LDM || Opcode == ARM::t2LDM || - Opcode == ARM::STM || Opcode == ARM::t2STM); bool DoMerge = false; ARM_AM::AMSubMode Mode = ARM_AM::ia; - unsigned Offset = 0; - if (isAM4) { - // Can't use an updating ld/st if the base register is also a dest - // register. e.g. ldmdb r0!, {r0, r1, r2}. The behavior is undefined. - for (unsigned i = 3, e = MI->getNumOperands(); i != e; ++i) { - if (MI->getOperand(i).getReg() == Base) - return false; - } - Mode = ARM_AM::getAM4SubMode(MI->getOperand(1).getImm()); - } else { - // VLDM{D|S}, VSTM{D|S} addressing mode 5 ops. - Mode = ARM_AM::getAM5SubMode(MI->getOperand(1).getImm()); - Offset = ARM_AM::getAM5Offset(MI->getOperand(1).getImm()); + // Can't use an updating ld/st if the base register is also a dest + // register. e.g. ldmdb r0!, {r0, r1, r2}. The behavior is undefined. + for (unsigned i = 3, e = MI->getNumOperands(); i != e; ++i) { + if (MI->getOperand(i).getReg() == Base) + return false; } + Mode = ARM_AM::getAM4SubMode(MI->getOperand(1).getImm()); // Try merging with the previous instruction. MachineBasicBlock::iterator BeginMBBI = MBB.begin(); @@ -539,22 +522,14 @@ bool ARMLoadStoreOpt::MergeBaseUpdateLSMultiple(MachineBasicBlock &MBB, MachineBasicBlock::iterator PrevMBBI = prior(MBBI); while (PrevMBBI != BeginMBBI && PrevMBBI->isDebugValue()) --PrevMBBI; - if (isAM4) { - if (Mode == ARM_AM::ia && - isMatchingDecrement(PrevMBBI, Base, Bytes, 0, Pred, PredReg)) { - DoMerge = true; - Mode = ARM_AM::db; - } else if (isAM4 && Mode == ARM_AM::ib && - isMatchingDecrement(PrevMBBI, Base, Bytes, 0, Pred, PredReg)) { - DoMerge = true; - Mode = ARM_AM::da; - } - } else { - if (Mode == ARM_AM::ia && - isMatchingDecrement(PrevMBBI, Base, Bytes, 0, Pred, PredReg)) { - Mode = ARM_AM::db; - DoMerge = true; - } + if (Mode == ARM_AM::ia && + isMatchingDecrement(PrevMBBI, Base, Bytes, 0, Pred, PredReg)) { + Mode = ARM_AM::db; + DoMerge = true; + } else if (Mode == ARM_AM::ib && + isMatchingDecrement(PrevMBBI, Base, Bytes, 0, Pred, PredReg)) { + Mode = ARM_AM::da; + DoMerge = true; } if (DoMerge) MBB.erase(PrevMBBI); @@ -566,19 +541,12 @@ bool ARMLoadStoreOpt::MergeBaseUpdateLSMultiple(MachineBasicBlock &MBB, MachineBasicBlock::iterator NextMBBI = llvm::next(MBBI); while (NextMBBI != EndMBBI && NextMBBI->isDebugValue()) ++NextMBBI; - if (isAM4) { - if ((Mode == ARM_AM::ia || Mode == ARM_AM::ib) && - isMatchingIncrement(NextMBBI, Base, Bytes, 0, Pred, PredReg)) { - DoMerge = true; - } else if ((Mode == ARM_AM::da || Mode == ARM_AM::db) && - isMatchingDecrement(NextMBBI, Base, Bytes, 0, Pred, PredReg)) { - DoMerge = true; - } - } else { - if (Mode == ARM_AM::ia && - isMatchingIncrement(NextMBBI, Base, Bytes, 0, Pred, PredReg)) { - DoMerge = true; - } + if ((Mode == ARM_AM::ia || Mode == ARM_AM::ib) && + isMatchingIncrement(NextMBBI, Base, Bytes, 0, Pred, PredReg)) { + DoMerge = true; + } else if ((Mode == ARM_AM::da || Mode == ARM_AM::db) && + isMatchingDecrement(NextMBBI, Base, Bytes, 0, Pred, PredReg)) { + DoMerge = true; } if (DoMerge) { if (NextMBBI == I) { @@ -595,16 +563,9 @@ bool ARMLoadStoreOpt::MergeBaseUpdateLSMultiple(MachineBasicBlock &MBB, unsigned NewOpc = getUpdatingLSMultipleOpcode(Opcode); MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII->get(NewOpc)) .addReg(Base, getDefRegState(true)) // WB base register - .addReg(Base, getKillRegState(BaseKill)); - if (isAM4) { - // [t2]LDM_UPD, [t2]STM_UPD - MIB.addImm(ARM_AM::getAM4ModeImm(Mode)) - .addImm(Pred).addReg(PredReg); - } else { - // VLDM[SD}_UPD, VSTM[SD]_UPD - MIB.addImm(ARM_AM::getAM5Opc(Mode, Offset)) - .addImm(Pred).addReg(PredReg); - } + .addReg(Base, getKillRegState(BaseKill)) + .addImm(ARM_AM::getAM4ModeImm(Mode)) + .addImm(Pred).addReg(PredReg); // Transfer the rest of operands. for (unsigned OpNum = 4, e = MI->getNumOperands(); OpNum != e; ++OpNum) MIB.addOperand(MI->getOperand(OpNum)); @@ -736,11 +697,10 @@ bool ARMLoadStoreOpt::MergeBaseUpdateLoadStore(MachineBasicBlock &MBB, if (!DoMerge) return false; - bool isDPR = NewOpc == ARM::VLDMD || NewOpc == ARM::VSTMD; unsigned Offset = 0; if (isAM5) - Offset = ARM_AM::getAM5Opc(AddSub == ARM_AM::sub ? ARM_AM::db : ARM_AM::ia, - (isDPR ? 2 : 1)); + Offset = ARM_AM::getAM4ModeImm(AddSub == ARM_AM::sub ? + ARM_AM::db : ARM_AM::ia); else if (isAM2) Offset = ARM_AM::getAM2Opc(AddSub, Bytes, ARM_AM::no_shift); else @@ -748,6 +708,9 @@ bool ARMLoadStoreOpt::MergeBaseUpdateLoadStore(MachineBasicBlock &MBB, if (isAM5) { // VLDM[SD}_UPD, VSTM[SD]_UPD + // (There are no base-updating versions of VLDR/VSTR instructions, but the + // updating load/store-multiple instructions can be used with only one + // register.) MachineOperand &MO = MI->getOperand(0); BuildMI(MBB, MBBI, dl, TII->get(NewOpc)) .addReg(Base, getDefRegState(true)) // WB base register @@ -1268,7 +1231,7 @@ bool ARMLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) { namespace { struct ARMPreAllocLoadStoreOpt : public MachineFunctionPass{ static char ID; - ARMPreAllocLoadStoreOpt() : MachineFunctionPass(&ID) {} + ARMPreAllocLoadStoreOpt() : MachineFunctionPass(ID) {} const TargetData *TD; const TargetInstrInfo *TII; diff --git a/lib/Target/ARM/ARMMCInstLower.cpp b/lib/Target/ARM/ARMMCInstLower.cpp new file mode 100644 index 0000000..ab2b06b --- /dev/null +++ b/lib/Target/ARM/ARMMCInstLower.cpp @@ -0,0 +1,162 @@ +//===-- ARMMCInstLower.cpp - Convert ARM MachineInstr to an MCInst --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower ARM MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "ARMMCInstLower.h" +//#include "llvm/CodeGen/MachineModuleInfoImpls.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +//#include "llvm/MC/MCStreamer.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/SmallString.h" +using namespace llvm; + + +#if 0 +const ARMSubtarget &ARMMCInstLower::getSubtarget() const { + return AsmPrinter.getSubtarget(); +} + +MachineModuleInfoMachO &ARMMCInstLower::getMachOMMI() const { + assert(getSubtarget().isTargetDarwin() &&"Can only get MachO info on darwin"); + return AsmPrinter.MMI->getObjFileInfo(); +} +#endif + +MCSymbol *ARMMCInstLower:: +GetGlobalAddressSymbol(const MachineOperand &MO) const { + // FIXME: HANDLE PLT references how?? + switch (MO.getTargetFlags()) { + default: assert(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Printer.Mang->getSymbol(MO.getGlobal()); +} + +MCSymbol *ARMMCInstLower:: +GetExternalSymbolSymbol(const MachineOperand &MO) const { + // FIXME: HANDLE PLT references how?? + switch (MO.getTargetFlags()) { + default: assert(0 && "Unknown target flag on GV operand"); + case 0: break; + } + + return Printer.GetExternalSymbolSymbol(MO.getSymbolName()); +} + + + +MCSymbol *ARMMCInstLower:: +GetJumpTableSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "JTI" + << Printer.getFunctionNumber() << '_' << MO.getIndex(); + +#if 0 + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + } +#endif + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *ARMMCInstLower:: +GetConstantPoolIndexSymbol(const MachineOperand &MO) const { + SmallString<256> Name; + raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "CPI" + << Printer.getFunctionNumber() << '_' << MO.getIndex(); + +#if 0 + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + } +#endif + + // Create a symbol for the name. + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCOperand ARMMCInstLower:: +LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const { + // FIXME: We would like an efficient form for this, so we don't have to do a + // lot of extra uniquing. + const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); + +#if 0 + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + } +#endif + + if (!MO.isJTI() && MO.getOffset()) + Expr = MCBinaryExpr::CreateAdd(Expr, + MCConstantExpr::Create(MO.getOffset(), Ctx), + Ctx); + return MCOperand::CreateExpr(Expr); +} + + +void ARMMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + + MCOperand MCOp; + switch (MO.getType()) { + default: + MI->dump(); + assert(0 && "unknown operand type"); + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) continue; + assert(!MO.getSubReg() && "Subregs should be eliminated!"); + MCOp = MCOperand::CreateReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::CreateImm(MO.getImm()); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( + MO.getMBB()->getSymbol(), Ctx)); + break; + case MachineOperand::MO_GlobalAddress: + MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); + break; + case MachineOperand::MO_ExternalSymbol: + MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); + break; + case MachineOperand::MO_JumpTableIndex: + MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO)); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO)); + break; + case MachineOperand::MO_BlockAddress: + MCOp = LowerSymbolOperand(MO, Printer.GetBlockAddressSymbol( + MO.getBlockAddress())); + break; + } + + OutMI.addOperand(MCOp); + } + +} diff --git a/lib/Target/ARM/ARMMCInstLower.h b/lib/Target/ARM/ARMMCInstLower.h new file mode 100644 index 0000000..b81a306 --- /dev/null +++ b/lib/Target/ARM/ARMMCInstLower.h @@ -0,0 +1,56 @@ +//===-- ARMMCInstLower.h - Lower MachineInstr to MCInst -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef ARM_MCINSTLOWER_H +#define ARM_MCINSTLOWER_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { + class AsmPrinter; + class MCAsmInfo; + class MCContext; + class MCInst; + class MCOperand; + class MCSymbol; + class MachineInstr; + class MachineModuleInfoMachO; + class MachineOperand; + class Mangler; + //class ARMSubtarget; + +/// ARMMCInstLower - This class is used to lower an MachineInstr into an MCInst. +class LLVM_LIBRARY_VISIBILITY ARMMCInstLower { + MCContext &Ctx; + Mangler &Mang; + AsmPrinter &Printer; + + //const ARMSubtarget &getSubtarget() const; +public: + ARMMCInstLower(MCContext &ctx, Mangler &mang, AsmPrinter &printer) + : Ctx(ctx), Mang(mang), Printer(printer) {} + + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + + //MCSymbol *GetPICBaseSymbol() const; + MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; + MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; + MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const; + MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; + MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; + +/* +private: + MachineModuleInfoMachO &getMachOMMI() const; + */ +}; + +} + +#endif diff --git a/lib/Target/ARM/ARMMachineFunctionInfo.h b/lib/Target/ARM/ARMMachineFunctionInfo.h index 7e57a1c..514c26b 100644 --- a/lib/Target/ARM/ARMMachineFunctionInfo.h +++ b/lib/Target/ARM/ARMMachineFunctionInfo.h @@ -43,6 +43,10 @@ class ARMFunctionInfo : public MachineFunctionInfo { /// processFunctionBeforeCalleeSavedScan(). bool HasStackFrame; + /// RestoreSPFromFP - True if epilogue should restore SP from FP. Set by + /// emitPrologue. + bool RestoreSPFromFP; + /// LRSpilledForFarJump - True if the LR register has been for spilled to /// enable far jump. bool LRSpilledForFarJump; @@ -95,7 +99,7 @@ public: ARMFunctionInfo() : isThumb(false), hasThumb2(false), - VarArgsRegSaveSize(0), HasStackFrame(false), + VarArgsRegSaveSize(0), HasStackFrame(false), RestoreSPFromFP(false), LRSpilledForFarJump(false), FramePtrSpillOffset(0), GPRCS1Offset(0), GPRCS2Offset(0), DPRCSOffset(0), GPRCS1Size(0), GPRCS2Size(0), DPRCSSize(0), @@ -106,7 +110,7 @@ public: explicit ARMFunctionInfo(MachineFunction &MF) : isThumb(MF.getTarget().getSubtarget().isThumb()), hasThumb2(MF.getTarget().getSubtarget().hasThumb2()), - VarArgsRegSaveSize(0), HasStackFrame(false), + VarArgsRegSaveSize(0), HasStackFrame(false), RestoreSPFromFP(false), LRSpilledForFarJump(false), FramePtrSpillOffset(0), GPRCS1Offset(0), GPRCS2Offset(0), DPRCSOffset(0), GPRCS1Size(0), GPRCS2Size(0), DPRCSSize(0), @@ -125,6 +129,9 @@ public: bool hasStackFrame() const { return HasStackFrame; } void setHasStackFrame(bool s) { HasStackFrame = s; } + bool shouldRestoreSPFromFP() const { return RestoreSPFromFP; } + void setShouldRestoreSPFromFP(bool s) { RestoreSPFromFP = s; } + bool isLRSpilledForFarJump() const { return LRSpilledForFarJump; } void setLRIsSpilledForFarJump(bool s) { LRSpilledForFarJump = s; } diff --git a/lib/Target/ARM/ARMRegisterInfo.td b/lib/Target/ARM/ARMRegisterInfo.td index d020f3c..305b232 100644 --- a/lib/Target/ARM/ARMRegisterInfo.td +++ b/lib/Target/ARM/ARMRegisterInfo.td @@ -1,4 +1,4 @@ -//===- ARMRegisterInfo.td - ARM Register defs -------------------*- C++ -*-===// +//===- ARMRegisterInfo.td - ARM Register defs --------------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -220,41 +220,11 @@ def GPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6, iterator allocation_order_end(const MachineFunction &MF) const; }]; let MethodBodies = [{ - // FP is R11, R9 is available. - static const unsigned ARM_GPR_AO_1[] = { + static const unsigned ARM_GPR_AO[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3, ARM::R12,ARM::LR, ARM::R4, ARM::R5, ARM::R6, ARM::R7, - ARM::R8, ARM::R9, ARM::R10, - ARM::R11 }; - // FP is R11, R9 is not available. - static const unsigned ARM_GPR_AO_2[] = { - ARM::R0, ARM::R1, ARM::R2, ARM::R3, - ARM::R12,ARM::LR, - ARM::R4, ARM::R5, ARM::R6, ARM::R7, - ARM::R8, ARM::R10, - ARM::R11 }; - // FP is R7, R9 is available as non-callee-saved register. - // This is used by Darwin. - static const unsigned ARM_GPR_AO_3[] = { - ARM::R0, ARM::R1, ARM::R2, ARM::R3, - ARM::R9, ARM::R12,ARM::LR, - ARM::R4, ARM::R5, ARM::R6, - ARM::R8, ARM::R10,ARM::R11,ARM::R7 }; - // FP is R7, R9 is not available. - static const unsigned ARM_GPR_AO_4[] = { - ARM::R0, ARM::R1, ARM::R2, ARM::R3, - ARM::R12,ARM::LR, - ARM::R4, ARM::R5, ARM::R6, - ARM::R8, ARM::R10,ARM::R11, - ARM::R7 }; - // FP is R7, R9 is available as callee-saved register. - // This is used by non-Darwin platform in Thumb mode. - static const unsigned ARM_GPR_AO_5[] = { - ARM::R0, ARM::R1, ARM::R2, ARM::R3, - ARM::R12,ARM::LR, - ARM::R4, ARM::R5, ARM::R6, - ARM::R8, ARM::R9, ARM::R10,ARM::R11,ARM::R7 }; + ARM::R8, ARM::R9, ARM::R10, ARM::R11 }; // For Thumb1 mode, we don't want to allocate hi regs at all, as we // don't know how to spill them. If we make our prologue/epilogue code @@ -270,85 +240,71 @@ def GPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6, const ARMSubtarget &Subtarget = TM.getSubtarget(); if (Subtarget.isThumb1Only()) return THUMB_GPR_AO; - if (Subtarget.isTargetDarwin()) { - if (Subtarget.isR9Reserved()) - return ARM_GPR_AO_4; - else - return ARM_GPR_AO_3; - } else { - if (Subtarget.isR9Reserved()) - return ARM_GPR_AO_2; - else if (Subtarget.isThumb()) - return ARM_GPR_AO_5; - else - return ARM_GPR_AO_1; - } + return ARM_GPR_AO; } GPRClass::iterator GPRClass::allocation_order_end(const MachineFunction &MF) const { const TargetMachine &TM = MF.getTarget(); - const TargetRegisterInfo *RI = TM.getRegisterInfo(); const ARMSubtarget &Subtarget = TM.getSubtarget(); - GPRClass::iterator I; - - if (Subtarget.isThumb1Only()) { - I = THUMB_GPR_AO + (sizeof(THUMB_GPR_AO)/sizeof(unsigned)); - // Mac OS X requires FP not to be clobbered for backtracing purpose. - return (Subtarget.isTargetDarwin() || RI->hasFP(MF)) ? I-1 : I; - } - - if (Subtarget.isTargetDarwin()) { - if (Subtarget.isR9Reserved()) - I = ARM_GPR_AO_4 + (sizeof(ARM_GPR_AO_4)/sizeof(unsigned)); - else - I = ARM_GPR_AO_3 + (sizeof(ARM_GPR_AO_3)/sizeof(unsigned)); - } else { - if (Subtarget.isR9Reserved()) - I = ARM_GPR_AO_2 + (sizeof(ARM_GPR_AO_2)/sizeof(unsigned)); - else if (Subtarget.isThumb()) - I = ARM_GPR_AO_5 + (sizeof(ARM_GPR_AO_5)/sizeof(unsigned)); - else - I = ARM_GPR_AO_1 + (sizeof(ARM_GPR_AO_1)/sizeof(unsigned)); - } - - // Mac OS X requires FP not to be clobbered for backtracing purpose. - return (Subtarget.isTargetDarwin() || RI->hasFP(MF)) ? I-1 : I; + if (Subtarget.isThumb1Only()) + return THUMB_GPR_AO + (sizeof(THUMB_GPR_AO)/sizeof(unsigned)); + return ARM_GPR_AO + (sizeof(ARM_GPR_AO)/sizeof(unsigned)); } }]; } -// Thumb registers are R0-R7 normally. Some instructions can still use -// the general GPR register class above (MOV, e.g.) -def tGPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6, R7]> { +// restricted GPR register class. Many Thumb2 instructions allow the full +// register range for operands, but have undefined behaviours when PC +// or SP (R13 or R15) are used. The ARM ARM refers to these operands +// via the BadReg() pseudo-code description. +def rGPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6, + R7, R8, R9, R10, R11, R12, LR]> { let MethodProtos = [{ iterator allocation_order_begin(const MachineFunction &MF) const; iterator allocation_order_end(const MachineFunction &MF) const; }]; let MethodBodies = [{ - static const unsigned THUMB_tGPR_AO[] = { + static const unsigned ARM_rGPR_AO[] = { + ARM::R0, ARM::R1, ARM::R2, ARM::R3, + ARM::R12,ARM::LR, + ARM::R4, ARM::R5, ARM::R6, ARM::R7, + ARM::R8, ARM::R9, ARM::R10, + ARM::R11 }; + + // For Thumb1 mode, we don't want to allocate hi regs at all, as we + // don't know how to spill them. If we make our prologue/epilogue code + // smarter at some point, we can go back to using the above allocation + // orders for the Thumb1 instructions that know how to use hi regs. + static const unsigned THUMB_rGPR_AO[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3, ARM::R4, ARM::R5, ARM::R6, ARM::R7 }; - // FP is R7, only low registers available. - tGPRClass::iterator - tGPRClass::allocation_order_begin(const MachineFunction &MF) const { - return THUMB_tGPR_AO; + rGPRClass::iterator + rGPRClass::allocation_order_begin(const MachineFunction &MF) const { + const TargetMachine &TM = MF.getTarget(); + const ARMSubtarget &Subtarget = TM.getSubtarget(); + if (Subtarget.isThumb1Only()) + return THUMB_rGPR_AO; + return ARM_rGPR_AO; } - tGPRClass::iterator - tGPRClass::allocation_order_end(const MachineFunction &MF) const { + rGPRClass::iterator + rGPRClass::allocation_order_end(const MachineFunction &MF) const { const TargetMachine &TM = MF.getTarget(); - const TargetRegisterInfo *RI = TM.getRegisterInfo(); const ARMSubtarget &Subtarget = TM.getSubtarget(); - tGPRClass::iterator I = - THUMB_tGPR_AO + (sizeof(THUMB_tGPR_AO)/sizeof(unsigned)); - // Mac OS X requires FP not to be clobbered for backtracing purpose. - return (Subtarget.isTargetDarwin() || RI->hasFP(MF)) ? I-1 : I; + + if (Subtarget.isThumb1Only()) + return THUMB_rGPR_AO + (sizeof(THUMB_rGPR_AO)/sizeof(unsigned)); + return ARM_rGPR_AO + (sizeof(ARM_rGPR_AO)/sizeof(unsigned)); } }]; } +// Thumb registers are R0-R7 normally. Some instructions can still use +// the general GPR register class above (MOV, e.g.) +def tGPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R4, R5, R6, R7]> {} + // For tail calls, we can't use callee-saved registers, as they are restored // to the saved value before the tail call, which would clobber a call address. // Note, getMinimalPhysRegClass(R0) returns tGPR because of the names of @@ -381,36 +337,20 @@ def tcGPR : RegisterClass<"ARM", [i32], 32, [R0, R1, R2, R3, R9, R12]> { const ARMSubtarget &Subtarget = TM.getSubtarget(); if (Subtarget.isThumb1Only()) return THUMB_GPR_AO_TC; - if (Subtarget.isTargetDarwin()) { - if (Subtarget.isR9Reserved()) - return ARM_GPR_NOR9_TC; - else - return ARM_GPR_R9_TC; - } else - // R9 is either callee-saved or reserved; can't use it. - return ARM_GPR_NOR9_TC; + return Subtarget.isTargetDarwin() ? ARM_GPR_R9_TC : ARM_GPR_NOR9_TC; } tcGPRClass::iterator tcGPRClass::allocation_order_end(const MachineFunction &MF) const { const TargetMachine &TM = MF.getTarget(); const ARMSubtarget &Subtarget = TM.getSubtarget(); - GPRClass::iterator I; - - if (Subtarget.isThumb1Only()) { - I = THUMB_GPR_AO_TC + (sizeof(THUMB_GPR_AO_TC)/sizeof(unsigned)); - return I; - } - - if (Subtarget.isTargetDarwin()) { - if (Subtarget.isR9Reserved()) - I = ARM_GPR_NOR9_TC + (sizeof(ARM_GPR_NOR9_TC)/sizeof(unsigned)); - else - I = ARM_GPR_R9_TC + (sizeof(ARM_GPR_R9_TC)/sizeof(unsigned)); - } else - // R9 is either callee-saved or reserved; can't use it. - I = ARM_GPR_NOR9_TC + (sizeof(ARM_GPR_NOR9_TC)/sizeof(unsigned)); - return I; + + if (Subtarget.isThumb1Only()) + return THUMB_GPR_AO_TC + (sizeof(THUMB_GPR_AO_TC)/sizeof(unsigned)); + + return Subtarget.isTargetDarwin() ? + ARM_GPR_R9_TC + (sizeof(ARM_GPR_R9_TC)/sizeof(unsigned)) : + ARM_GPR_NOR9_TC + (sizeof(ARM_GPR_NOR9_TC)/sizeof(unsigned)); } }]; } diff --git a/lib/Target/ARM/ARMSubtarget.cpp b/lib/Target/ARM/ARMSubtarget.cpp index 10fd257..cb539f4 100644 --- a/lib/Target/ARM/ARMSubtarget.cpp +++ b/lib/Target/ARM/ARMSubtarget.cpp @@ -33,14 +33,19 @@ ARMSubtarget::ARMSubtarget(const std::string &TT, const std::string &FS, , ARMFPUType(None) , UseNEONForSinglePrecisionFP(false) , SlowVMLx(false) + , SlowFPBrcc(false) , IsThumb(isT) , ThumbMode(Thumb1) + , NoARM(false) , PostRAScheduler(false) , IsR9Reserved(ReserveR9) , UseMovt(UseMOVT) , HasFP16(false) , HasHardwareDivide(false) , HasT2ExtractPack(false) + , HasDataBarrier(false) + , Pref32BitThumb(false) + , FPOnlySP(false) , stackAlignment(4) , CPUString("generic") , TargetType(isELF) // Default to ELF unless otherwise specified. diff --git a/lib/Target/ARM/ARMSubtarget.h b/lib/Target/ARM/ARMSubtarget.h index e7d92ed..67e5803 100644 --- a/lib/Target/ARM/ARMSubtarget.h +++ b/lib/Target/ARM/ARMSubtarget.h @@ -26,7 +26,7 @@ class GlobalValue; class ARMSubtarget : public TargetSubtarget { protected: enum ARMArchEnum { - V4, V4T, V5T, V5TE, V6, V6T2, V7A, V7M + V4, V4T, V5T, V5TE, V6, V6M, V6T2, V7A, V7M }; enum ARMFPEnum { @@ -63,6 +63,9 @@ protected: /// ThumbMode - Indicates supported Thumb version. ThumbTypeEnum ThumbMode; + /// NoARM - True if subtarget does not support ARM mode execution. + bool NoARM; + /// PostRAScheduler - True if using post-register-allocation scheduler. bool PostRAScheduler; @@ -84,6 +87,18 @@ protected: /// instructions. bool HasT2ExtractPack; + /// HasDataBarrier - True if the subtarget supports DMB / DSB data barrier + /// instructions. + bool HasDataBarrier; + + /// Pref32BitThumb - If true, codegen would prefer 32-bit Thumb instructions + /// over 16-bit ones. + bool Pref32BitThumb; + + /// FPOnlySP - If true, the floating point unit only supports single + /// precision. + bool FPOnlySP; + /// stackAlignment - The minimum alignment known to hold of the stack frame on /// entry to the function and which must be maintained by every function. unsigned stackAlignment; @@ -128,6 +143,8 @@ protected: bool hasV6T2Ops() const { return ARMArchVersion >= V6T2; } bool hasV7Ops() const { return ARMArchVersion >= V7A; } + bool hasARMOps() const { return !NoARM; } + bool hasVFP2() const { return ARMFPUType >= VFPv2; } bool hasVFP3() const { return ARMFPUType >= VFPv3; } bool hasNEON() const { return ARMFPUType >= NEON; } @@ -135,8 +152,11 @@ protected: return hasNEON() && UseNEONForSinglePrecisionFP; } bool hasDivide() const { return HasHardwareDivide; } bool hasT2ExtractPack() const { return HasT2ExtractPack; } + bool hasDataBarrier() const { return HasDataBarrier; } bool useVMLx() const {return hasVFP2() && !SlowVMLx; } bool isFPBrccSlow() const { return SlowFPBrcc; } + bool isFPOnlySP() const { return FPOnlySP; } + bool prefers32BitThumb() const { return Pref32BitThumb; } bool hasFP16() const { return HasFP16; } diff --git a/lib/Target/ARM/ARMTargetMachine.cpp b/lib/Target/ARM/ARMTargetMachine.cpp index 09203f9..30ff827 100644 --- a/lib/Target/ARM/ARMTargetMachine.cpp +++ b/lib/Target/ARM/ARMTargetMachine.cpp @@ -31,7 +31,6 @@ static MCAsmInfo *createMCAsmInfo(const Target &T, StringRef TT) { } } - extern "C" void LLVMInitializeARMTarget() { // Register the target. RegisterTargetMachine X(TheARMTarget); @@ -66,6 +65,9 @@ ARMTargetMachine::ARMTargetMachine(const Target &T, const std::string &TT, "v128:64:128-v64:64:64-n32")), TLInfo(*this), TSInfo(*this) { + if (!Subtarget.hasARMOps()) + report_fatal_error("CPU: '" + Subtarget.getCPUString() + "' does not " + "support ARM mode execution!"); } ThumbTargetMachine::ThumbTargetMachine(const Target &T, const std::string &TT, @@ -85,9 +87,15 @@ ThumbTargetMachine::ThumbTargetMachine(const Target &T, const std::string &TT, TSInfo(*this) { } +// Pass Pipeline Configuration +bool ARMBaseTargetMachine::addPreISel(PassManagerBase &PM, + CodeGenOpt::Level OptLevel) { + if (OptLevel != CodeGenOpt::None) + PM.add(createARMGlobalMergePass(getTargetLowering())); + return false; +} -// Pass Pipeline Configuration bool ARMBaseTargetMachine::addInstSelector(PassManagerBase &PM, CodeGenOpt::Level OptLevel) { PM.add(createARMISelDag(*this, OptLevel)); @@ -132,7 +140,7 @@ bool ARMBaseTargetMachine::addPreSched2(PassManagerBase &PM, bool ARMBaseTargetMachine::addPreEmitPass(PassManagerBase &PM, CodeGenOpt::Level OptLevel) { - if (Subtarget.isThumb2()) + if (Subtarget.isThumb2() && !Subtarget.prefers32BitThumb()) PM.add(createThumb2SizeReductionPass()); PM.add(createARMConstantIslandPass()); diff --git a/lib/Target/ARM/ARMTargetMachine.h b/lib/Target/ARM/ARMTargetMachine.h index a222e57..17e5425 100644 --- a/lib/Target/ARM/ARMTargetMachine.h +++ b/lib/Target/ARM/ARMTargetMachine.h @@ -50,6 +50,7 @@ public: } // Pass Pipeline Configuration + virtual bool addPreISel(PassManagerBase &PM, CodeGenOpt::Level OptLevel); virtual bool addInstSelector(PassManagerBase &PM, CodeGenOpt::Level OptLevel); virtual bool addPreRegAlloc(PassManagerBase &PM, CodeGenOpt::Level OptLevel); virtual bool addPreSched2(PassManagerBase &PM, CodeGenOpt::Level OptLevel); diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 4b08324..75e2a73 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "ARM.h" +#include "ARMSubtarget.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" @@ -18,8 +19,10 @@ #include "llvm/Target/TargetAsmParser.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" using namespace llvm; @@ -37,6 +40,7 @@ enum ShiftType { class ARMAsmParser : public TargetAsmParser { MCAsmParser &Parser; + TargetMachine &TM; private: MCAsmParser &getParser() const { return Parser; } @@ -76,26 +80,33 @@ private: bool ParseDirectiveSyntax(SMLoc L); - // TODO - For now hacked versions of the next two are in here in this file to - // allow some parser testing until the table gen versions are implemented. + bool MatchInstruction(SMLoc IDLoc, + const SmallVectorImpl &Operands, + MCInst &Inst) { + if (!MatchInstructionImpl(Operands, Inst)) + return false; + + // FIXME: We should give nicer diagnostics about the exact failure. + Error(IDLoc, "unrecognized instruction"); + + return true; + } /// @name Auto-generated Match Functions /// { - bool MatchInstruction(const SmallVectorImpl &Operands, - MCInst &Inst); - /// MatchRegisterName - Match the given string to a register name and return - /// its register number, or -1 if there is no match. To allow return values - /// to be used directly in register lists, arm registers have values between - /// 0 and 15. - int MatchRegisterName(StringRef Name); + unsigned ComputeAvailableFeatures(const ARMSubtarget *Subtarget) const; + + bool MatchInstructionImpl(const SmallVectorImpl + &Operands, + MCInst &Inst); /// } public: - ARMAsmParser(const Target &T, MCAsmParser &_Parser) - : TargetAsmParser(T), Parser(_Parser) {} + ARMAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &_TM) + : TargetAsmParser(T), Parser(_Parser), TM(_TM) {} virtual bool ParseInstruction(StringRef Name, SMLoc NameLoc, SmallVectorImpl &Operands); @@ -110,16 +121,21 @@ private: ARMOperand() {} public: enum KindTy { - Token, - Register, + CondCode, Immediate, - Memory + Memory, + Register, + Token } Kind; SMLoc StartLoc, EndLoc; union { struct { + ARMCC::CondCodes Val; + } CC; + + struct { const char *Data; unsigned Length; } Tok; @@ -151,16 +167,19 @@ public: }; - ARMOperand(KindTy K, SMLoc S, SMLoc E) - : Kind(K), StartLoc(S), EndLoc(E) {} + //ARMOperand(KindTy K, SMLoc S, SMLoc E) + // : Kind(K), StartLoc(S), EndLoc(E) {} ARMOperand(const ARMOperand &o) : MCParsedAsmOperand() { Kind = o.Kind; StartLoc = o.StartLoc; EndLoc = o.EndLoc; switch (Kind) { + case CondCode: + CC = o.CC; + break; case Token: - Tok = o.Tok; + Tok = o.Tok; break; case Register: Reg = o.Reg; @@ -179,6 +198,11 @@ public: /// getEndLoc - Get the location of the last token of this operand. SMLoc getEndLoc() const { return EndLoc; } + ARMCC::CondCodes getCondCode() const { + assert(Kind == CondCode && "Invalid access!"); + return CC.Val; + } + StringRef getToken() const { assert(Kind == Token && "Invalid access!"); return StringRef(Tok.Data, Tok.Length); @@ -194,15 +218,50 @@ public: return Imm.Val; } - bool isToken() const {return Kind == Token; } + bool isCondCode() const { return Kind == CondCode; } + + bool isImm() const { return Kind == Immediate; } bool isReg() const { return Kind == Register; } + bool isToken() const {return Kind == Token; } + + void addExpr(MCInst &Inst, const MCExpr *Expr) const { + // Add as immediates when possible. + if (const MCConstantExpr *CE = dyn_cast(Expr)) + Inst.addOperand(MCOperand::CreateImm(CE->getValue())); + else + Inst.addOperand(MCOperand::CreateExpr(Expr)); + } + + void addCondCodeOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::CreateImm(unsigned(getCondCode()))); + // FIXME: What belongs here? + Inst.addOperand(MCOperand::CreateReg(0)); + } + void addRegOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::CreateReg(getReg())); } + void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + addExpr(Inst, getImm()); + } + + virtual void dump(raw_ostream &OS) const; + + static void CreateCondCode(OwningPtr &Op, ARMCC::CondCodes CC, + SMLoc S) { + Op.reset(new ARMOperand); + Op->Kind = CondCode; + Op->CC.Val = CC; + Op->StartLoc = S; + Op->EndLoc = S; + } + static void CreateToken(OwningPtr &Op, StringRef Str, SMLoc S) { Op.reset(new ARMOperand); @@ -262,6 +321,33 @@ public: } // end anonymous namespace. +void ARMOperand::dump(raw_ostream &OS) const { + switch (Kind) { + case CondCode: + OS << ARMCondCodeToString(getCondCode()); + break; + case Immediate: + getImm()->print(OS); + break; + case Memory: + OS << ""; + break; + case Register: + OS << ""; + break; + case Token: + OS << "'" << getToken() << "'"; + break; + } +} + +/// @name Auto-generated Match Functions +/// { + +static unsigned MatchRegisterName(StringRef Name); + +/// } + /// Try to parse a register name. The token must be an Identifier when called, /// and if it is a register name a Reg operand is created, the token is eaten /// and false is returned. Else true is returned and no token is eaten. @@ -548,77 +634,6 @@ bool ARMAsmParser::ParseShift(ShiftType &St, return false; } -/// A hack to allow some testing, to be replaced by a real table gen version. -int ARMAsmParser::MatchRegisterName(StringRef Name) { - if (Name == "r0" || Name == "R0") - return 0; - else if (Name == "r1" || Name == "R1") - return 1; - else if (Name == "r2" || Name == "R2") - return 2; - else if (Name == "r3" || Name == "R3") - return 3; - else if (Name == "r3" || Name == "R3") - return 3; - else if (Name == "r4" || Name == "R4") - return 4; - else if (Name == "r5" || Name == "R5") - return 5; - else if (Name == "r6" || Name == "R6") - return 6; - else if (Name == "r7" || Name == "R7") - return 7; - else if (Name == "r8" || Name == "R8") - return 8; - else if (Name == "r9" || Name == "R9") - return 9; - else if (Name == "r10" || Name == "R10") - return 10; - else if (Name == "r11" || Name == "R11" || Name == "fp") - return 11; - else if (Name == "r12" || Name == "R12" || Name == "ip") - return 12; - else if (Name == "r13" || Name == "R13" || Name == "sp") - return 13; - else if (Name == "r14" || Name == "R14" || Name == "lr") - return 14; - else if (Name == "r15" || Name == "R15" || Name == "pc") - return 15; - return -1; -} - -/// A hack to allow some testing, to be replaced by a real table gen version. -bool ARMAsmParser:: -MatchInstruction(const SmallVectorImpl &Operands, - MCInst &Inst) { - ARMOperand &Op0 = *(ARMOperand*)Operands[0]; - assert(Op0.Kind == ARMOperand::Token && "First operand not a Token"); - StringRef Mnemonic = Op0.getToken(); - if (Mnemonic == "add" || - Mnemonic == "stmfd" || - Mnemonic == "str" || - Mnemonic == "ldmfd" || - Mnemonic == "ldr" || - Mnemonic == "mov" || - Mnemonic == "sub" || - Mnemonic == "bl" || - Mnemonic == "push" || - Mnemonic == "blx" || - Mnemonic == "pop") { - // Hard-coded to a valid instruction, till we have a real matcher. - Inst = MCInst(); - Inst.setOpcode(ARM::MOVr); - Inst.addOperand(MCOperand::CreateReg(2)); - Inst.addOperand(MCOperand::CreateReg(2)); - Inst.addOperand(MCOperand::CreateImm(0)); - Inst.addOperand(MCOperand::CreateImm(0)); - Inst.addOperand(MCOperand::CreateReg(0)); - return false; - } - - return true; -} - /// Parse a arm instruction operand. For now this parses the operand regardless /// of the mnemonic. bool ARMAsmParser::ParseOperand(OwningPtr &Op) { @@ -661,12 +676,56 @@ bool ARMAsmParser::ParseOperand(OwningPtr &Op) { bool ARMAsmParser::ParseInstruction(StringRef Name, SMLoc NameLoc, SmallVectorImpl &Operands) { OwningPtr Op; - ARMOperand::CreateToken(Op, Name, NameLoc); - + + // Create the leading tokens for the mnemonic, split by '.' characters. + size_t Start = 0, Next = Name.find('.'); + StringRef Head = Name.slice(Start, Next); + + // Determine the predicate, if any. + // + // FIXME: We need a way to check whether a prefix supports predication, + // otherwise we will end up with an ambiguity for instructions that happen to + // end with a predicate name. + unsigned CC = StringSwitch(Head.substr(Head.size()-2)) + .Case("eq", ARMCC::EQ) + .Case("ne", ARMCC::NE) + .Case("hs", ARMCC::HS) + .Case("lo", ARMCC::LO) + .Case("mi", ARMCC::MI) + .Case("pl", ARMCC::PL) + .Case("vs", ARMCC::VS) + .Case("vc", ARMCC::VC) + .Case("hi", ARMCC::HI) + .Case("ls", ARMCC::LS) + .Case("ge", ARMCC::GE) + .Case("lt", ARMCC::LT) + .Case("gt", ARMCC::GT) + .Case("le", ARMCC::LE) + .Case("al", ARMCC::AL) + .Default(~0U); + if (CC != ~0U) { + Head = Head.slice(0, Head.size() - 2); + } else + CC = ARMCC::AL; + + ARMOperand::CreateToken(Op, Head, NameLoc); Operands.push_back(Op.take()); - if (getLexer().isNot(AsmToken::EndOfStatement)) { + ARMOperand::CreateCondCode(Op, ARMCC::CondCodes(CC), NameLoc); + Operands.push_back(Op.take()); + + // Add the remaining tokens in the mnemonic. + while (Next != StringRef::npos) { + Start = Next; + Next = Name.find('.', Start + 1); + Head = Name.slice(Start, Next); + ARMOperand::CreateToken(Op, Head, NameLoc); + Operands.push_back(Op.take()); + } + + // Read the remaining operands. + if (getLexer().isNot(AsmToken::EndOfStatement)) { // Read the first operand. OwningPtr Op; if (ParseOperand(Op)) return true; @@ -809,3 +868,5 @@ extern "C" void LLVMInitializeARMAsmParser() { RegisterAsmParser Y(TheThumbTarget); LLVMInitializeARMAsmLexer(); } + +#include "ARMGenAsmMatcher.inc" diff --git a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp deleted file mode 100644 index 946f474..0000000 --- a/lib/Target/ARM/AsmPrinter/ARMAsmPrinter.cpp +++ /dev/null @@ -1,1438 +0,0 @@ -//===-- ARMAsmPrinter.cpp - Print machine code to an ARM .s file ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains a printer that converts from our internal representation -// of machine-dependent LLVM code to GAS-format ARM assembly language. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "asm-printer" -#include "ARM.h" -#include "ARMBuildAttrs.h" -#include "ARMAddressingModes.h" -#include "ARMConstantPoolValue.h" -#include "ARMInstPrinter.h" -#include "ARMMachineFunctionInfo.h" -#include "ARMMCInstLower.h" -#include "ARMTargetMachine.h" -#include "llvm/Analysis/DebugInfo.h" -#include "llvm/Constants.h" -#include "llvm/Module.h" -#include "llvm/Type.h" -#include "llvm/Assembly/Writer.h" -#include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/CodeGen/MachineModuleInfoImpls.h" -#include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineJumpTableInfo.h" -#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCSectionMachO.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/Target/Mangler.h" -#include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetOptions.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" -#include -using namespace llvm; - -static cl::opt -EnableMCInst("enable-arm-mcinst-printer", cl::Hidden, - cl::desc("enable experimental asmprinter gunk in the arm backend")); - -namespace { - class ARMAsmPrinter : public AsmPrinter { - - /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can - /// make the right decision when printing asm code for different targets. - const ARMSubtarget *Subtarget; - - /// AFI - Keep a pointer to ARMFunctionInfo for the current - /// MachineFunction. - ARMFunctionInfo *AFI; - - /// MCP - Keep a pointer to constantpool entries of the current - /// MachineFunction. - const MachineConstantPool *MCP; - - public: - explicit ARMAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) - : AsmPrinter(TM, Streamer), AFI(NULL), MCP(NULL) { - Subtarget = &TM.getSubtarget(); - } - - virtual const char *getPassName() const { - return "ARM Assembly Printer"; - } - - void printInstructionThroughMCStreamer(const MachineInstr *MI); - - - void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O, - const char *Modifier = 0); - void printSOImmOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); - void printSOImm2PartOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printSORegOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrMode2Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrMode2OffsetOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrMode3Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrMode3OffsetOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrMode4Operand(const MachineInstr *MI, int OpNum,raw_ostream &O, - const char *Modifier = 0); - void printAddrMode5Operand(const MachineInstr *MI, int OpNum,raw_ostream &O, - const char *Modifier = 0); - void printAddrMode6Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrMode6OffsetOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrModePCOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O, - const char *Modifier = 0); - void printBitfieldInvMaskImmOperand (const MachineInstr *MI, int OpNum, - raw_ostream &O); - - void printThumbS4ImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printThumbITMask(const MachineInstr *MI, int OpNum, raw_ostream &O); - void printThumbAddrModeRROperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printThumbAddrModeRI5Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O, - unsigned Scale); - void printThumbAddrModeS1Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printThumbAddrModeS2Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printThumbAddrModeS4Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printThumbAddrModeSPOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - - void printT2SOOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); - void printT2AddrModeImm12Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) {} - void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - - void printCPSOptionOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) {} - void printMSRMaskOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) {} - void printNegZeroOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) {} - void printPredicateOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printMandatoryPredicateOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printSBitModifierOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printPCLabel(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printRegisterList(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printCPInstOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O, - const char *Modifier); - void printJTBlockOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printJT2BlockOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printTBAddrMode(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printNoHashImmediate(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printVFPf32ImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printVFPf64ImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printNEONModImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - - virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, - unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O); - virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, - unsigned AsmVariant, - const char *ExtraCode, raw_ostream &O); - - void printInstruction(const MachineInstr *MI, raw_ostream &O); // autogen - static const char *getRegisterName(unsigned RegNo); - - virtual void EmitInstruction(const MachineInstr *MI); - bool runOnMachineFunction(MachineFunction &F); - - virtual void EmitConstantPool() {} // we emit constant pools customly! - virtual void EmitFunctionEntryLabel(); - void EmitStartOfAsmFile(Module &M); - void EmitEndOfAsmFile(Module &M); - - MCSymbol *GetARMSetPICJumpTableLabel2(unsigned uid, unsigned uid2, - const MachineBasicBlock *MBB) const; - MCSymbol *GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const; - - /// EmitMachineConstantPoolValue - Print a machine constantpool value to - /// the .s file. - virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) { - SmallString<128> Str; - raw_svector_ostream OS(Str); - EmitMachineConstantPoolValue(MCPV, OS); - OutStreamer.EmitRawText(OS.str()); - } - - void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV, - raw_ostream &O) { - switch (TM.getTargetData()->getTypeAllocSize(MCPV->getType())) { - case 1: O << MAI->getData8bitsDirective(0); break; - case 2: O << MAI->getData16bitsDirective(0); break; - case 4: O << MAI->getData32bitsDirective(0); break; - default: assert(0 && "Unknown CPV size"); - } - - ARMConstantPoolValue *ACPV = static_cast(MCPV); - - if (ACPV->isLSDA()) { - O << MAI->getPrivateGlobalPrefix() << "_LSDA_" << getFunctionNumber(); - } else if (ACPV->isBlockAddress()) { - O << *GetBlockAddressSymbol(ACPV->getBlockAddress()); - } else if (ACPV->isGlobalValue()) { - const GlobalValue *GV = ACPV->getGV(); - bool isIndirect = Subtarget->isTargetDarwin() && - Subtarget->GVIsIndirectSymbol(GV, TM.getRelocationModel()); - if (!isIndirect) - O << *Mang->getSymbol(GV); - else { - // FIXME: Remove this when Darwin transition to @GOT like syntax. - MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); - O << *Sym; - - MachineModuleInfoMachO &MMIMachO = - MMI->getObjFileInfo(); - MachineModuleInfoImpl::StubValueTy &StubSym = - GV->hasHiddenVisibility() ? MMIMachO.getHiddenGVStubEntry(Sym) : - MMIMachO.getGVStubEntry(Sym); - if (StubSym.getPointer() == 0) - StubSym = MachineModuleInfoImpl:: - StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); - } - } else { - assert(ACPV->isExtSymbol() && "unrecognized constant pool value"); - O << *GetExternalSymbolSymbol(ACPV->getSymbol()); - } - - if (ACPV->hasModifier()) O << "(" << ACPV->getModifier() << ")"; - if (ACPV->getPCAdjustment() != 0) { - O << "-(" << MAI->getPrivateGlobalPrefix() << "PC" - << getFunctionNumber() << "_" << ACPV->getLabelId() - << "+" << (unsigned)ACPV->getPCAdjustment(); - if (ACPV->mustAddCurrentAddress()) - O << "-."; - O << ')'; - } - } - }; -} // end of anonymous namespace - -#include "ARMGenAsmWriter.inc" - -void ARMAsmPrinter::EmitFunctionEntryLabel() { - if (AFI->isThumbFunction()) { - OutStreamer.EmitRawText(StringRef("\t.code\t16")); - if (!Subtarget->isTargetDarwin()) - OutStreamer.EmitRawText(StringRef("\t.thumb_func")); - else { - // This needs to emit to a temporary string to get properly quoted - // MCSymbols when they have spaces in them. - SmallString<128> Tmp; - raw_svector_ostream OS(Tmp); - OS << "\t.thumb_func\t" << *CurrentFnSym; - OutStreamer.EmitRawText(OS.str()); - } - } - - OutStreamer.EmitLabel(CurrentFnSym); -} - -/// runOnMachineFunction - This uses the printInstruction() -/// method to print assembly for each instruction. -/// -bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) { - AFI = MF.getInfo(); - MCP = MF.getConstantPool(); - - return AsmPrinter::runOnMachineFunction(MF); -} - -void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O, const char *Modifier) { - const MachineOperand &MO = MI->getOperand(OpNum); - unsigned TF = MO.getTargetFlags(); - - switch (MO.getType()) { - default: - assert(0 && ""); - case MachineOperand::MO_Register: { - unsigned Reg = MO.getReg(); - assert(TargetRegisterInfo::isPhysicalRegister(Reg)); - if (Modifier && strcmp(Modifier, "dregpair") == 0) { - unsigned DRegLo = TM.getRegisterInfo()->getSubReg(Reg, ARM::dsub_0); - unsigned DRegHi = TM.getRegisterInfo()->getSubReg(Reg, ARM::dsub_1); - O << '{' - << getRegisterName(DRegLo) << ", " << getRegisterName(DRegHi) - << '}'; - } else if (Modifier && strcmp(Modifier, "lane") == 0) { - unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg); - unsigned DReg = - TM.getRegisterInfo()->getMatchingSuperReg(Reg, - RegNum & 1 ? ARM::ssub_1 : ARM::ssub_0, &ARM::DPR_VFP2RegClass); - O << getRegisterName(DReg) << '[' << (RegNum & 1) << ']'; - } else { - assert(!MO.getSubReg() && "Subregs should be eliminated!"); - O << getRegisterName(Reg); - } - break; - } - case MachineOperand::MO_Immediate: { - int64_t Imm = MO.getImm(); - O << '#'; - if ((Modifier && strcmp(Modifier, "lo16") == 0) || - (TF & ARMII::MO_LO16)) - O << ":lower16:"; - else if ((Modifier && strcmp(Modifier, "hi16") == 0) || - (TF & ARMII::MO_HI16)) - O << ":upper16:"; - O << Imm; - break; - } - case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(); - return; - case MachineOperand::MO_GlobalAddress: { - bool isCallOp = Modifier && !strcmp(Modifier, "call"); - const GlobalValue *GV = MO.getGlobal(); - - if ((Modifier && strcmp(Modifier, "lo16") == 0) || - (TF & ARMII::MO_LO16)) - O << ":lower16:"; - else if ((Modifier && strcmp(Modifier, "hi16") == 0) || - (TF & ARMII::MO_HI16)) - O << ":upper16:"; - O << *Mang->getSymbol(GV); - - printOffset(MO.getOffset(), O); - - if (isCallOp && Subtarget->isTargetELF() && - TM.getRelocationModel() == Reloc::PIC_) - O << "(PLT)"; - break; - } - case MachineOperand::MO_ExternalSymbol: { - bool isCallOp = Modifier && !strcmp(Modifier, "call"); - O << *GetExternalSymbolSymbol(MO.getSymbolName()); - - if (isCallOp && Subtarget->isTargetELF() && - TM.getRelocationModel() == Reloc::PIC_) - O << "(PLT)"; - break; - } - case MachineOperand::MO_ConstantPoolIndex: - O << *GetCPISymbol(MO.getIndex()); - break; - case MachineOperand::MO_JumpTableIndex: - O << *GetJTISymbol(MO.getIndex()); - break; - } -} - -static void printSOImm(raw_ostream &O, int64_t V, bool VerboseAsm, - const MCAsmInfo *MAI) { - // Break it up into two parts that make up a shifter immediate. - V = ARM_AM::getSOImmVal(V); - assert(V != -1 && "Not a valid so_imm value!"); - - unsigned Imm = ARM_AM::getSOImmValImm(V); - unsigned Rot = ARM_AM::getSOImmValRot(V); - - // Print low-level immediate formation info, per - // A5.1.3: "Data-processing operands - Immediate". - if (Rot) { - O << "#" << Imm << ", " << Rot; - // Pretty printed version. - if (VerboseAsm) { - O << "\t" << MAI->getCommentString() << ' '; - O << (int)ARM_AM::rotr32(Imm, Rot); - } - } else { - O << "#" << Imm; - } -} - -/// printSOImmOperand - SOImm is 4-bit rotate amount in bits 8-11 with 8-bit -/// immediate in bits 0-7. -void ARMAsmPrinter::printSOImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - const MachineOperand &MO = MI->getOperand(OpNum); - assert(MO.isImm() && "Not a valid so_imm value!"); - printSOImm(O, MO.getImm(), isVerbose(), MAI); -} - -/// printSOImm2PartOperand - SOImm is broken into two pieces using a 'mov' -/// followed by an 'orr' to materialize. -void ARMAsmPrinter::printSOImm2PartOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - const MachineOperand &MO = MI->getOperand(OpNum); - assert(MO.isImm() && "Not a valid so_imm value!"); - unsigned V1 = ARM_AM::getSOImmTwoPartFirst(MO.getImm()); - unsigned V2 = ARM_AM::getSOImmTwoPartSecond(MO.getImm()); - printSOImm(O, V1, isVerbose(), MAI); - O << "\n\torr"; - printPredicateOperand(MI, 2, O); - O << "\t"; - printOperand(MI, 0, O); - O << ", "; - printOperand(MI, 0, O); - O << ", "; - printSOImm(O, V2, isVerbose(), MAI); -} - -// so_reg is a 4-operand unit corresponding to register forms of the A5.1 -// "Addressing Mode 1 - Data-processing operands" forms. This includes: -// REG 0 0 - e.g. R5 -// REG REG 0,SH_OPC - e.g. R5, ROR R3 -// REG 0 IMM,SH_OPC - e.g. R5, LSL #3 -void ARMAsmPrinter::printSORegOperand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - const MachineOperand &MO3 = MI->getOperand(Op+2); - - O << getRegisterName(MO1.getReg()); - - // Print the shift opc. - O << ", " - << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm())) - << " "; - - if (MO2.getReg()) { - O << getRegisterName(MO2.getReg()); - assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); - } else { - O << "#" << ARM_AM::getSORegOffset(MO3.getImm()); - } -} - -void ARMAsmPrinter::printAddrMode2Operand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - const MachineOperand &MO3 = MI->getOperand(Op+2); - - if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. - printOperand(MI, Op, O); - return; - } - - O << "[" << getRegisterName(MO1.getReg()); - - if (!MO2.getReg()) { - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. - O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) - << ARM_AM::getAM2Offset(MO3.getImm()); - O << "]"; - return; - } - - O << ", " - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) - << getRegisterName(MO2.getReg()); - - if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) - O << ", " - << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO3.getImm())) - << " #" << ShImm; - O << "]"; -} - -void ARMAsmPrinter::printAddrMode2OffsetOperand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - - if (!MO1.getReg()) { - unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); - O << "#" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) - << ImmOffs; - return; - } - - O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) - << getRegisterName(MO1.getReg()); - - if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) - O << ", " - << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO2.getImm())) - << " #" << ShImm; -} - -void ARMAsmPrinter::printAddrMode3Operand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - const MachineOperand &MO3 = MI->getOperand(Op+2); - - assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); - O << "[" << getRegisterName(MO1.getReg()); - - if (MO2.getReg()) { - O << ", " - << (char)ARM_AM::getAM3Op(MO3.getImm()) - << getRegisterName(MO2.getReg()) - << "]"; - return; - } - - if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) - O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) - << ImmOffs; - O << "]"; -} - -void ARMAsmPrinter::printAddrMode3OffsetOperand(const MachineInstr *MI, int Op, - raw_ostream &O){ - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - - if (MO1.getReg()) { - O << (char)ARM_AM::getAM3Op(MO2.getImm()) - << getRegisterName(MO1.getReg()); - return; - } - - unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); - O << "#" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) - << ImmOffs; -} - -void ARMAsmPrinter::printAddrMode4Operand(const MachineInstr *MI, int Op, - raw_ostream &O, - const char *Modifier) { - const MachineOperand &MO2 = MI->getOperand(Op+1); - ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); - if (Modifier && strcmp(Modifier, "submode") == 0) { - O << ARM_AM::getAMSubModeStr(Mode); - } else if (Modifier && strcmp(Modifier, "wide") == 0) { - ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); - if (Mode == ARM_AM::ia) - O << ".w"; - } else { - printOperand(MI, Op, O); - } -} - -void ARMAsmPrinter::printAddrMode5Operand(const MachineInstr *MI, int Op, - raw_ostream &O, - const char *Modifier) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - - if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. - printOperand(MI, Op, O); - return; - } - - assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); - - if (Modifier && strcmp(Modifier, "submode") == 0) { - ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MO2.getImm()); - O << ARM_AM::getAMSubModeStr(Mode); - return; - } else if (Modifier && strcmp(Modifier, "base") == 0) { - // Used for FSTM{D|S} and LSTM{D|S} operations. - O << getRegisterName(MO1.getReg()); - return; - } - - O << "[" << getRegisterName(MO1.getReg()); - - if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { - O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) - << ImmOffs*4; - } - O << "]"; -} - -void ARMAsmPrinter::printAddrMode6Operand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - - O << "[" << getRegisterName(MO1.getReg()); - if (MO2.getImm()) { - // FIXME: Both darwin as and GNU as violate ARM docs here. - O << ", :" << (MO2.getImm() << 3); - } - O << "]"; -} - -void ARMAsmPrinter::printAddrMode6OffsetOperand(const MachineInstr *MI, int Op, - raw_ostream &O){ - const MachineOperand &MO = MI->getOperand(Op); - if (MO.getReg() == 0) - O << "!"; - else - O << ", " << getRegisterName(MO.getReg()); -} - -void ARMAsmPrinter::printAddrModePCOperand(const MachineInstr *MI, int Op, - raw_ostream &O, - const char *Modifier) { - if (Modifier && strcmp(Modifier, "label") == 0) { - printPCLabel(MI, Op+1, O); - return; - } - - const MachineOperand &MO1 = MI->getOperand(Op); - assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); - O << "[pc, " << getRegisterName(MO1.getReg()) << "]"; -} - -void -ARMAsmPrinter::printBitfieldInvMaskImmOperand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO = MI->getOperand(Op); - uint32_t v = ~MO.getImm(); - int32_t lsb = CountTrailingZeros_32(v); - int32_t width = (32 - CountLeadingZeros_32 (v)) - lsb; - assert(MO.isImm() && "Not a valid bf_inv_mask_imm value!"); - O << "#" << lsb << ", #" << width; -} - -//===--------------------------------------------------------------------===// - -void ARMAsmPrinter::printThumbS4ImmOperand(const MachineInstr *MI, int Op, - raw_ostream &O) { - O << "#" << MI->getOperand(Op).getImm() * 4; -} - -void -ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op, - raw_ostream &O) { - // (3 - the number of trailing zeros) is the number of then / else. - unsigned Mask = MI->getOperand(Op).getImm(); - unsigned CondBit0 = Mask >> 4 & 1; - unsigned NumTZ = CountTrailingZeros_32(Mask); - assert(NumTZ <= 3 && "Invalid IT mask!"); - for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { - bool T = ((Mask >> Pos) & 1) == CondBit0; - if (T) - O << 't'; - else - O << 'e'; - } -} - -void -ARMAsmPrinter::printThumbAddrModeRROperand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - O << "[" << getRegisterName(MO1.getReg()); - O << ", " << getRegisterName(MO2.getReg()) << "]"; -} - -void -ARMAsmPrinter::printThumbAddrModeRI5Operand(const MachineInstr *MI, int Op, - raw_ostream &O, - unsigned Scale) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - const MachineOperand &MO3 = MI->getOperand(Op+2); - - if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. - printOperand(MI, Op, O); - return; - } - - O << "[" << getRegisterName(MO1.getReg()); - if (MO3.getReg()) - O << ", " << getRegisterName(MO3.getReg()); - else if (unsigned ImmOffs = MO2.getImm()) - O << ", #" << ImmOffs * Scale; - O << "]"; -} - -void -ARMAsmPrinter::printThumbAddrModeS1Operand(const MachineInstr *MI, int Op, - raw_ostream &O) { - printThumbAddrModeRI5Operand(MI, Op, O, 1); -} -void -ARMAsmPrinter::printThumbAddrModeS2Operand(const MachineInstr *MI, int Op, - raw_ostream &O) { - printThumbAddrModeRI5Operand(MI, Op, O, 2); -} -void -ARMAsmPrinter::printThumbAddrModeS4Operand(const MachineInstr *MI, int Op, - raw_ostream &O) { - printThumbAddrModeRI5Operand(MI, Op, O, 4); -} - -void ARMAsmPrinter::printThumbAddrModeSPOperand(const MachineInstr *MI,int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - O << "[" << getRegisterName(MO1.getReg()); - if (unsigned ImmOffs = MO2.getImm()) - O << ", #" << ImmOffs*4; - O << "]"; -} - -//===--------------------------------------------------------------------===// - -// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2 -// register with shift forms. -// REG 0 0 - e.g. R5 -// REG IMM, SH_OPC - e.g. R5, LSL #3 -void ARMAsmPrinter::printT2SOOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); - - unsigned Reg = MO1.getReg(); - assert(TargetRegisterInfo::isPhysicalRegister(Reg)); - O << getRegisterName(Reg); - - // Print the shift opc. - O << ", " - << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO2.getImm())) - << " "; - - assert(MO2.isImm() && "Not a valid t2_so_reg value!"); - O << "#" << ARM_AM::getSORegOffset(MO2.getImm()); -} - -void ARMAsmPrinter::printT2AddrModeImm12Operand(const MachineInstr *MI, - int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); - - O << "[" << getRegisterName(MO1.getReg()); - - unsigned OffImm = MO2.getImm(); - if (OffImm) // Don't print +0. - O << ", #" << OffImm; - O << "]"; -} - -void ARMAsmPrinter::printT2AddrModeImm8Operand(const MachineInstr *MI, - int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); - - O << "[" << getRegisterName(MO1.getReg()); - - int32_t OffImm = (int32_t)MO2.getImm(); - // Don't print +0. - if (OffImm < 0) - O << ", #-" << -OffImm; - else if (OffImm > 0) - O << ", #" << OffImm; - O << "]"; -} - -void ARMAsmPrinter::printT2AddrModeImm8s4Operand(const MachineInstr *MI, - int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); - - O << "[" << getRegisterName(MO1.getReg()); - - int32_t OffImm = (int32_t)MO2.getImm() / 4; - // Don't print +0. - if (OffImm < 0) - O << ", #-" << -OffImm * 4; - else if (OffImm > 0) - O << ", #" << OffImm * 4; - O << "]"; -} - -void ARMAsmPrinter::printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, - int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - int32_t OffImm = (int32_t)MO1.getImm(); - // Don't print +0. - if (OffImm < 0) - O << "#-" << -OffImm; - else if (OffImm > 0) - O << "#" << OffImm; -} - -void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, - int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); - const MachineOperand &MO3 = MI->getOperand(OpNum+2); - - O << "[" << getRegisterName(MO1.getReg()); - - assert(MO2.getReg() && "Invalid so_reg load / store address!"); - O << ", " << getRegisterName(MO2.getReg()); - - unsigned ShAmt = MO3.getImm(); - if (ShAmt) { - assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!"); - O << ", lsl #" << ShAmt; - } - O << "]"; -} - - -//===--------------------------------------------------------------------===// - -void ARMAsmPrinter::printPredicateOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); - if (CC != ARMCC::AL) - O << ARMCondCodeToString(CC); -} - -void ARMAsmPrinter::printMandatoryPredicateOperand(const MachineInstr *MI, - int OpNum, - raw_ostream &O) { - ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); - O << ARMCondCodeToString(CC); -} - -void ARMAsmPrinter::printSBitModifierOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O){ - unsigned Reg = MI->getOperand(OpNum).getReg(); - if (Reg) { - assert(Reg == ARM::CPSR && "Expect ARM CPSR register!"); - O << 's'; - } -} - -void ARMAsmPrinter::printPCLabel(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - int Id = (int)MI->getOperand(OpNum).getImm(); - O << MAI->getPrivateGlobalPrefix() - << "PC" << getFunctionNumber() << "_" << Id; -} - -void ARMAsmPrinter::printRegisterList(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - O << "{"; - for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) { - if (MI->getOperand(i).isImplicit()) - continue; - if ((int)i != OpNum) O << ", "; - printOperand(MI, i, O); - } - O << "}"; -} - -void ARMAsmPrinter::printCPInstOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O, const char *Modifier) { - assert(Modifier && "This operand only works with a modifier!"); - // There are two aspects to a CONSTANTPOOL_ENTRY operand, the label and the - // data itself. - if (!strcmp(Modifier, "label")) { - unsigned ID = MI->getOperand(OpNum).getImm(); - OutStreamer.EmitLabel(GetCPISymbol(ID)); - } else { - assert(!strcmp(Modifier, "cpentry") && "Unknown modifier for CPE"); - unsigned CPI = MI->getOperand(OpNum).getIndex(); - - const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPI]; - - if (MCPE.isMachineConstantPoolEntry()) { - EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); - } else { - EmitGlobalConstant(MCPE.Val.ConstVal); - } - } -} - -MCSymbol *ARMAsmPrinter:: -GetARMSetPICJumpTableLabel2(unsigned uid, unsigned uid2, - const MachineBasicBlock *MBB) const { - SmallString<60> Name; - raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() - << getFunctionNumber() << '_' << uid << '_' << uid2 - << "_set_" << MBB->getNumber(); - return OutContext.GetOrCreateSymbol(Name.str()); -} - -MCSymbol *ARMAsmPrinter:: -GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const { - SmallString<60> Name; - raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() << "JTI" - << getFunctionNumber() << '_' << uid << '_' << uid2; - return OutContext.GetOrCreateSymbol(Name.str()); -} - -void ARMAsmPrinter::printJTBlockOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - assert(!Subtarget->isThumb2() && "Thumb2 should use double-jump jumptables!"); - - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id - - unsigned JTI = MO1.getIndex(); - MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); - // Can't use EmitLabel until instprinter happens, label comes out in the wrong - // order. - O << *JTISymbol << ":\n"; - - const char *JTEntryDirective = MAI->getData32bitsDirective(); - - const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); - const std::vector &JT = MJTI->getJumpTables(); - const std::vector &JTBBs = JT[JTI].MBBs; - bool UseSet= MAI->hasSetDirective() && TM.getRelocationModel() == Reloc::PIC_; - SmallPtrSet JTSets; - for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { - MachineBasicBlock *MBB = JTBBs[i]; - bool isNew = JTSets.insert(MBB); - - if (UseSet && isNew) { - O << "\t.set\t" - << *GetARMSetPICJumpTableLabel2(JTI, MO2.getImm(), MBB) << ',' - << *MBB->getSymbol() << '-' << *JTISymbol << '\n'; - } - - O << JTEntryDirective << ' '; - if (UseSet) - O << *GetARMSetPICJumpTableLabel2(JTI, MO2.getImm(), MBB); - else if (TM.getRelocationModel() == Reloc::PIC_) - O << *MBB->getSymbol() << '-' << *JTISymbol; - else - O << *MBB->getSymbol(); - - if (i != e-1) - O << '\n'; - } -} - -void ARMAsmPrinter::printJT2BlockOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id - unsigned JTI = MO1.getIndex(); - - MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); - - // Can't use EmitLabel until instprinter happens, label comes out in the wrong - // order. - O << *JTISymbol << ":\n"; - - const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); - const std::vector &JT = MJTI->getJumpTables(); - const std::vector &JTBBs = JT[JTI].MBBs; - bool ByteOffset = false, HalfWordOffset = false; - if (MI->getOpcode() == ARM::t2TBB) - ByteOffset = true; - else if (MI->getOpcode() == ARM::t2TBH) - HalfWordOffset = true; - - for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { - MachineBasicBlock *MBB = JTBBs[i]; - if (ByteOffset) - O << MAI->getData8bitsDirective(); - else if (HalfWordOffset) - O << MAI->getData16bitsDirective(); - - if (ByteOffset || HalfWordOffset) - O << '(' << *MBB->getSymbol() << "-" << *JTISymbol << ")/2"; - else - O << "\tb.w " << *MBB->getSymbol(); - - if (i != e-1) - O << '\n'; - } -} - -void ARMAsmPrinter::printTBAddrMode(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - O << "[pc, " << getRegisterName(MI->getOperand(OpNum).getReg()); - if (MI->getOpcode() == ARM::t2TBH) - O << ", lsl #1"; - O << ']'; -} - -void ARMAsmPrinter::printNoHashImmediate(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - O << MI->getOperand(OpNum).getImm(); -} - -void ARMAsmPrinter::printVFPf32ImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - const ConstantFP *FP = MI->getOperand(OpNum).getFPImm(); - O << '#' << FP->getValueAPF().convertToFloat(); - if (isVerbose()) { - O << "\t\t" << MAI->getCommentString() << ' '; - WriteAsOperand(O, FP, /*PrintType=*/false); - } -} - -void ARMAsmPrinter::printVFPf64ImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - const ConstantFP *FP = MI->getOperand(OpNum).getFPImm(); - O << '#' << FP->getValueAPF().convertToDouble(); - if (isVerbose()) { - O << "\t\t" << MAI->getCommentString() << ' '; - WriteAsOperand(O, FP, /*PrintType=*/false); - } -} - -void ARMAsmPrinter::printNEONModImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - unsigned EncodedImm = MI->getOperand(OpNum).getImm(); - unsigned EltBits; - uint64_t Val = ARM_AM::decodeNEONModImm(EncodedImm, EltBits); - O << "#0x" << utohexstr(Val); -} - -bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, - unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O) { - // Does this asm operand have a single letter operand modifier? - if (ExtraCode && ExtraCode[0]) { - if (ExtraCode[1] != 0) return true; // Unknown modifier. - - switch (ExtraCode[0]) { - default: return true; // Unknown modifier. - case 'a': // Print as a memory address. - if (MI->getOperand(OpNum).isReg()) { - O << "[" << getRegisterName(MI->getOperand(OpNum).getReg()) << "]"; - return false; - } - // Fallthrough - case 'c': // Don't print "#" before an immediate operand. - if (!MI->getOperand(OpNum).isImm()) - return true; - printNoHashImmediate(MI, OpNum, O); - return false; - case 'P': // Print a VFP double precision register. - case 'q': // Print a NEON quad precision register. - printOperand(MI, OpNum, O); - return false; - case 'Q': - case 'R': - case 'H': - report_fatal_error("llvm does not support 'Q', 'R', and 'H' modifiers!"); - return true; - } - } - - printOperand(MI, OpNum, O); - return false; -} - -bool ARMAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, - unsigned OpNum, unsigned AsmVariant, - const char *ExtraCode, - raw_ostream &O) { - if (ExtraCode && ExtraCode[0]) - return true; // Unknown modifier. - - const MachineOperand &MO = MI->getOperand(OpNum); - assert(MO.isReg() && "unexpected inline asm memory operand"); - O << "[" << getRegisterName(MO.getReg()) << "]"; - return false; -} - -void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) { - if (EnableMCInst) { - printInstructionThroughMCStreamer(MI); - return; - } - - if (MI->getOpcode() == ARM::CONSTPOOL_ENTRY) - EmitAlignment(2); - - SmallString<128> Str; - raw_svector_ostream OS(Str); - if (MI->getOpcode() == ARM::DBG_VALUE) { - unsigned NOps = MI->getNumOperands(); - assert(NOps==4); - OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: "; - // cast away const; DIetc do not take const operands for some reason. - DIVariable V(const_cast(MI->getOperand(NOps-1).getMetadata())); - OS << V.getName(); - OS << " <- "; - // Frame address. Currently handles register +- offset only. - assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm()); - OS << '['; printOperand(MI, 0, OS); OS << '+'; printOperand(MI, 1, OS); - OS << ']'; - OS << "+"; - printOperand(MI, NOps-2, OS); - OutStreamer.EmitRawText(OS.str()); - return; - } - - printInstruction(MI, OS); - OutStreamer.EmitRawText(OS.str()); - - // Make sure the instruction that follows TBB is 2-byte aligned. - // FIXME: Constant island pass should insert an "ALIGN" instruction instead. - if (MI->getOpcode() == ARM::t2TBB) - EmitAlignment(1); -} - -void ARMAsmPrinter::EmitStartOfAsmFile(Module &M) { - if (Subtarget->isTargetDarwin()) { - Reloc::Model RelocM = TM.getRelocationModel(); - if (RelocM == Reloc::PIC_ || RelocM == Reloc::DynamicNoPIC) { - // Declare all the text sections up front (before the DWARF sections - // emitted by AsmPrinter::doInitialization) so the assembler will keep - // them together at the beginning of the object file. This helps - // avoid out-of-range branches that are due a fundamental limitation of - // the way symbol offsets are encoded with the current Darwin ARM - // relocations. - const TargetLoweringObjectFileMachO &TLOFMacho = - static_cast( - getObjFileLowering()); - OutStreamer.SwitchSection(TLOFMacho.getTextSection()); - OutStreamer.SwitchSection(TLOFMacho.getTextCoalSection()); - OutStreamer.SwitchSection(TLOFMacho.getConstTextCoalSection()); - if (RelocM == Reloc::DynamicNoPIC) { - const MCSection *sect = - OutContext.getMachOSection("__TEXT", "__symbol_stub4", - MCSectionMachO::S_SYMBOL_STUBS, - 12, SectionKind::getText()); - OutStreamer.SwitchSection(sect); - } else { - const MCSection *sect = - OutContext.getMachOSection("__TEXT", "__picsymbolstub4", - MCSectionMachO::S_SYMBOL_STUBS, - 16, SectionKind::getText()); - OutStreamer.SwitchSection(sect); - } - } - } - - // Use unified assembler syntax. - OutStreamer.EmitRawText(StringRef("\t.syntax unified")); - - // Emit ARM Build Attributes - if (Subtarget->isTargetELF()) { - // CPU Type - std::string CPUString = Subtarget->getCPUString(); - if (CPUString != "generic") - OutStreamer.EmitRawText("\t.cpu " + Twine(CPUString)); - - // FIXME: Emit FPU type - if (Subtarget->hasVFP2()) - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::VFP_arch) + ", 2"); - - // Signal various FP modes. - if (!UnsafeFPMath) { - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_FP_denormal) + ", 1"); - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_FP_exceptions) + ", 1"); - } - - if (FiniteOnlyFPMath()) - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_FP_number_model)+ ", 1"); - else - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_FP_number_model)+ ", 3"); - - // 8-bytes alignment stuff. - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_align8_needed) + ", 1"); - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_align8_preserved) + ", 1"); - - // Hard float. Use both S and D registers and conform to AAPCS-VFP. - if (Subtarget->isAAPCS_ABI() && FloatABIType == FloatABI::Hard) { - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_HardFP_use) + ", 3"); - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_VFP_args) + ", 1"); - } - // FIXME: Should we signal R9 usage? - } -} - - -void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) { - if (Subtarget->isTargetDarwin()) { - // All darwin targets use mach-o. - const TargetLoweringObjectFileMachO &TLOFMacho = - static_cast(getObjFileLowering()); - MachineModuleInfoMachO &MMIMacho = - MMI->getObjFileInfo(); - - // Output non-lazy-pointers for external and common global variables. - MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetGVStubList(); - - if (!Stubs.empty()) { - // Switch with ".non_lazy_symbol_pointer" directive. - OutStreamer.SwitchSection(TLOFMacho.getNonLazySymbolPointerSection()); - EmitAlignment(2); - for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { - // L_foo$stub: - OutStreamer.EmitLabel(Stubs[i].first); - // .indirect_symbol _foo - MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second; - OutStreamer.EmitSymbolAttribute(MCSym.getPointer(),MCSA_IndirectSymbol); - - if (MCSym.getInt()) - // External to current translation unit. - OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/); - else - // Internal to current translation unit. - // - // When we place the LSDA into the TEXT section, the type info pointers - // need to be indirect and pc-rel. We accomplish this by using NLPs. - // However, sometimes the types are local to the file. So we need to - // fill in the value for the NLP in those cases. - OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym.getPointer(), - OutContext), - 4/*size*/, 0/*addrspace*/); - } - - Stubs.clear(); - OutStreamer.AddBlankLine(); - } - - Stubs = MMIMacho.GetHiddenGVStubList(); - if (!Stubs.empty()) { - OutStreamer.SwitchSection(getObjFileLowering().getDataSection()); - EmitAlignment(2); - for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { - // L_foo$stub: - OutStreamer.EmitLabel(Stubs[i].first); - // .long _foo - OutStreamer.EmitValue(MCSymbolRefExpr:: - Create(Stubs[i].second.getPointer(), - OutContext), - 4/*size*/, 0/*addrspace*/); - } - - Stubs.clear(); - OutStreamer.AddBlankLine(); - } - - // Funny Darwin hack: This flag tells the linker that no global symbols - // contain code that falls through to other global symbols (e.g. the obvious - // implementation of multiple entry points). If this doesn't occur, the - // linker can safely perform dead code stripping. Since LLVM never - // generates code that does this, it is always safe to set. - OutStreamer.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols); - } -} - -//===----------------------------------------------------------------------===// - -void ARMAsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) { - ARMMCInstLower MCInstLowering(OutContext, *Mang, *this); - switch (MI->getOpcode()) { - case ARM::t2MOVi32imm: - assert(0 && "Should be lowered by thumb2it pass"); - default: break; - case ARM::PICADD: { // FIXME: Remove asm string from td file. - // This is a pseudo op for a label + instruction sequence, which looks like: - // LPC0: - // add r0, pc, r0 - // This adds the address of LPC0 to r0. - - // Emit the label. - // FIXME: MOVE TO SHARED PLACE. - unsigned Id = (unsigned)MI->getOperand(2).getImm(); - const char *Prefix = MAI->getPrivateGlobalPrefix(); - MCSymbol *Label =OutContext.GetOrCreateSymbol(Twine(Prefix) - + "PC" + Twine(getFunctionNumber()) + "_" + Twine(Id)); - OutStreamer.EmitLabel(Label); - - - // Form and emit tha dd. - MCInst AddInst; - AddInst.setOpcode(ARM::ADDrr); - AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); - AddInst.addOperand(MCOperand::CreateReg(ARM::PC)); - AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); - OutStreamer.EmitInstruction(AddInst); - return; - } - case ARM::CONSTPOOL_ENTRY: { // FIXME: Remove asm string from td file. - /// CONSTPOOL_ENTRY - This instruction represents a floating constant pool - /// in the function. The first operand is the ID# for this instruction, the - /// second is the index into the MachineConstantPool that this is, the third - /// is the size in bytes of this constant pool entry. - unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); - unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); - - EmitAlignment(2); - OutStreamer.EmitLabel(GetCPISymbol(LabelId)); - - const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; - if (MCPE.isMachineConstantPoolEntry()) - EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); - else - EmitGlobalConstant(MCPE.Val.ConstVal); - - return; - } - case ARM::MOVi2pieces: { // FIXME: Remove asmstring from td file. - // This is a hack that lowers as a two instruction sequence. - unsigned DstReg = MI->getOperand(0).getReg(); - unsigned ImmVal = (unsigned)MI->getOperand(1).getImm(); - - unsigned SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(ImmVal); - unsigned SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(ImmVal); - - { - MCInst TmpInst; - TmpInst.setOpcode(ARM::MOVi); - TmpInst.addOperand(MCOperand::CreateReg(DstReg)); - TmpInst.addOperand(MCOperand::CreateImm(SOImmValV1)); - - // Predicate. - TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); - TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); - - TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out - OutStreamer.EmitInstruction(TmpInst); - } - - { - MCInst TmpInst; - TmpInst.setOpcode(ARM::ORRri); - TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg - TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // inreg - TmpInst.addOperand(MCOperand::CreateImm(SOImmValV2)); // so_imm - // Predicate. - TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); - TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); - - TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out - OutStreamer.EmitInstruction(TmpInst); - } - return; - } - case ARM::MOVi32imm: { // FIXME: Remove asmstring from td file. - // This is a hack that lowers as a two instruction sequence. - unsigned DstReg = MI->getOperand(0).getReg(); - const MachineOperand &MO = MI->getOperand(1); - MCOperand V1, V2; - if (MO.isImm()) { - unsigned ImmVal = (unsigned)MI->getOperand(1).getImm(); - V1 = MCOperand::CreateImm(ImmVal & 65535); - V2 = MCOperand::CreateImm(ImmVal >> 16); - } else if (MO.isGlobal()) { - MCSymbol *Symbol = MCInstLowering.GetGlobalAddressSymbol(MO); - const MCSymbolRefExpr *SymRef1 = - MCSymbolRefExpr::Create(Symbol, - MCSymbolRefExpr::VK_ARM_LO16, OutContext); - const MCSymbolRefExpr *SymRef2 = - MCSymbolRefExpr::Create(Symbol, - MCSymbolRefExpr::VK_ARM_HI16, OutContext); - V1 = MCOperand::CreateExpr(SymRef1); - V2 = MCOperand::CreateExpr(SymRef2); - } else { - MI->dump(); - llvm_unreachable("cannot handle this operand"); - } - - { - MCInst TmpInst; - TmpInst.setOpcode(ARM::MOVi16); - TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg - TmpInst.addOperand(V1); // lower16(imm) - - // Predicate. - TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); - TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); - - OutStreamer.EmitInstruction(TmpInst); - } - - { - MCInst TmpInst; - TmpInst.setOpcode(ARM::MOVTi16); - TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg - TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // srcreg - TmpInst.addOperand(V2); // upper16(imm) - - // Predicate. - TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); - TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); - - OutStreamer.EmitInstruction(TmpInst); - } - - return; - } - } - - MCInst TmpInst; - MCInstLowering.Lower(MI, TmpInst); - OutStreamer.EmitInstruction(TmpInst); -} - -//===----------------------------------------------------------------------===// -// Target Registry Stuff -//===----------------------------------------------------------------------===// - -static MCInstPrinter *createARMMCInstPrinter(const Target &T, - unsigned SyntaxVariant, - const MCAsmInfo &MAI) { - if (SyntaxVariant == 0) - return new ARMInstPrinter(MAI, false); - return 0; -} - -// Force static initialization. -extern "C" void LLVMInitializeARMAsmPrinter() { - RegisterAsmPrinter X(TheARMTarget); - RegisterAsmPrinter Y(TheThumbTarget); - - TargetRegistry::RegisterMCInstPrinter(TheARMTarget, createARMMCInstPrinter); - TargetRegistry::RegisterMCInstPrinter(TheThumbTarget, createARMMCInstPrinter); -} - diff --git a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp index edc9345..8026e77 100644 --- a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp +++ b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp @@ -158,7 +158,7 @@ void ARMInstPrinter::printInst(const MCInst *MI, raw_ostream &O) { if ((MI->getOpcode() == ARM::VSTMS_UPD || MI->getOpcode() ==ARM::VSTMD_UPD) && MI->getOperand(0).getReg() == ARM::SP) { const MCOperand &MO1 = MI->getOperand(2); - if (ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::db) { + if (ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::db) { O << '\t' << "vpush"; printPredicateOperand(MI, 3, O); O << '\t'; @@ -171,7 +171,7 @@ void ARMInstPrinter::printInst(const MCInst *MI, raw_ostream &O) { if ((MI->getOpcode() == ARM::VLDMS_UPD || MI->getOpcode() ==ARM::VLDMD_UPD) && MI->getOperand(0).getReg() == ARM::SP) { const MCOperand &MO1 = MI->getOperand(2); - if (ARM_AM::getAM5SubMode(MO1.getImm()) == ARM_AM::ia) { + if (ARM_AM::getAM4SubMode(MO1.getImm()) == ARM_AM::ia) { O << '\t' << "vpop"; printPredicateOperand(MI, 3, O); O << '\t'; @@ -278,15 +278,13 @@ void ARMInstPrinter::printSORegOperand(const MCInst *MI, unsigned OpNum, O << getRegisterName(MO1.getReg()); // Print the shift opc. - O << ", " - << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm())) - << ' '; - + ARM_AM::ShiftOpc ShOpc = ARM_AM::getSORegShOp(MO3.getImm()); + O << ", " << ARM_AM::getShiftOpcStr(ShOpc); if (MO2.getReg()) { - O << getRegisterName(MO2.getReg()); + O << ' ' << getRegisterName(MO2.getReg()); assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); - } else { - O << "#" << ARM_AM::getSORegOffset(MO3.getImm()); + } else if (ShOpc != ARM_AM::rrx) { + O << " #" << ARM_AM::getSORegOffset(MO3.getImm()); } } @@ -414,16 +412,6 @@ void ARMInstPrinter::printAddrMode5Operand(const MCInst *MI, unsigned OpNum, return; } - if (Modifier && strcmp(Modifier, "submode") == 0) { - ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MO2.getImm()); - O << ARM_AM::getAMSubModeStr(Mode); - return; - } else if (Modifier && strcmp(Modifier, "base") == 0) { - // Used for FSTM{D|S} and LSTM{D|S} operations. - O << getRegisterName(MO1.getReg()); - return; - } - O << "[" << getRegisterName(MO1.getReg()); if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { @@ -463,9 +451,9 @@ void ARMInstPrinter::printAddrModePCOperand(const MCInst *MI, unsigned OpNum, assert(0 && "FIXME: Implement printAddrModePCOperand"); } -void ARMInstPrinter::printBitfieldInvMaskImmOperand (const MCInst *MI, - unsigned OpNum, - raw_ostream &O) { +void ARMInstPrinter::printBitfieldInvMaskImmOperand(const MCInst *MI, + unsigned OpNum, + raw_ostream &O) { const MCOperand &MO = MI->getOperand(OpNum); uint32_t v = ~MO.getImm(); int32_t lsb = CountTrailingZeros_32(v); @@ -474,6 +462,31 @@ void ARMInstPrinter::printBitfieldInvMaskImmOperand (const MCInst *MI, O << '#' << lsb << ", #" << width; } +void ARMInstPrinter::printMemBOption(const MCInst *MI, unsigned OpNum, + raw_ostream &O) { + unsigned val = MI->getOperand(OpNum).getImm(); + O << ARM_MB::MemBOptToString(val); +} + +void ARMInstPrinter::printShiftImmOperand(const MCInst *MI, unsigned OpNum, + raw_ostream &O) { + unsigned ShiftOp = MI->getOperand(OpNum).getImm(); + ARM_AM::ShiftOpc Opc = ARM_AM::getSORegShOp(ShiftOp); + switch (Opc) { + case ARM_AM::no_shift: + return; + case ARM_AM::lsl: + O << ", lsl #"; + break; + case ARM_AM::asr: + O << ", asr #"; + break; + default: + assert(0 && "unexpected shift opcode for shift immediate operand"); + } + O << ARM_AM::getSORegOffset(ShiftOp); +} + void ARMInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum, raw_ostream &O) { O << "{"; @@ -669,12 +682,11 @@ void ARMInstPrinter::printT2SOOperand(const MCInst *MI, unsigned OpNum, O << getRegisterName(Reg); // Print the shift opc. - O << ", " - << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO2.getImm())) - << " "; - assert(MO2.isImm() && "Not a valid t2_so_reg value!"); - O << "#" << ARM_AM::getSORegOffset(MO2.getImm()); + ARM_AM::ShiftOpc ShOpc = ARM_AM::getSORegShOp(MO2.getImm()); + O << ", " << ARM_AM::getShiftOpcStr(ShOpc); + if (ShOpc != ARM_AM::rrx) + O << " #" << ARM_AM::getSORegOffset(MO2.getImm()); } void ARMInstPrinter::printT2AddrModeImm12Operand(const MCInst *MI, diff --git a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h index ddf5047..e5ad0d0 100644 --- a/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h +++ b/lib/Target/ARM/AsmPrinter/ARMInstPrinter.h @@ -57,6 +57,8 @@ public: void printBitfieldInvMaskImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); + void printMemBOption(const MCInst *MI, unsigned OpNum, raw_ostream &O); + void printShiftImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printThumbS4ImmOperand(const MCInst *MI, unsigned OpNum, raw_ostream &O); void printThumbITMask(const MCInst *MI, unsigned OpNum, raw_ostream &O); diff --git a/lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp b/lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp deleted file mode 100644 index ab2b06b..0000000 --- a/lib/Target/ARM/AsmPrinter/ARMMCInstLower.cpp +++ /dev/null @@ -1,162 +0,0 @@ -//===-- ARMMCInstLower.cpp - Convert ARM MachineInstr to an MCInst --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains code to lower ARM MachineInstrs to their corresponding -// MCInst records. -// -//===----------------------------------------------------------------------===// - -#include "ARMMCInstLower.h" -//#include "llvm/CodeGen/MachineModuleInfoImpls.h" -#include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/CodeGen/MachineBasicBlock.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCInst.h" -//#include "llvm/MC/MCStreamer.h" -#include "llvm/Target/Mangler.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/ADT/SmallString.h" -using namespace llvm; - - -#if 0 -const ARMSubtarget &ARMMCInstLower::getSubtarget() const { - return AsmPrinter.getSubtarget(); -} - -MachineModuleInfoMachO &ARMMCInstLower::getMachOMMI() const { - assert(getSubtarget().isTargetDarwin() &&"Can only get MachO info on darwin"); - return AsmPrinter.MMI->getObjFileInfo(); -} -#endif - -MCSymbol *ARMMCInstLower:: -GetGlobalAddressSymbol(const MachineOperand &MO) const { - // FIXME: HANDLE PLT references how?? - switch (MO.getTargetFlags()) { - default: assert(0 && "Unknown target flag on GV operand"); - case 0: break; - } - - return Printer.Mang->getSymbol(MO.getGlobal()); -} - -MCSymbol *ARMMCInstLower:: -GetExternalSymbolSymbol(const MachineOperand &MO) const { - // FIXME: HANDLE PLT references how?? - switch (MO.getTargetFlags()) { - default: assert(0 && "Unknown target flag on GV operand"); - case 0: break; - } - - return Printer.GetExternalSymbolSymbol(MO.getSymbolName()); -} - - - -MCSymbol *ARMMCInstLower:: -GetJumpTableSymbol(const MachineOperand &MO) const { - SmallString<256> Name; - raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "JTI" - << Printer.getFunctionNumber() << '_' << MO.getIndex(); - -#if 0 - switch (MO.getTargetFlags()) { - default: llvm_unreachable("Unknown target flag on GV operand"); - } -#endif - - // Create a symbol for the name. - return Ctx.GetOrCreateSymbol(Name.str()); -} - -MCSymbol *ARMMCInstLower:: -GetConstantPoolIndexSymbol(const MachineOperand &MO) const { - SmallString<256> Name; - raw_svector_ostream(Name) << Printer.MAI->getPrivateGlobalPrefix() << "CPI" - << Printer.getFunctionNumber() << '_' << MO.getIndex(); - -#if 0 - switch (MO.getTargetFlags()) { - default: llvm_unreachable("Unknown target flag on GV operand"); - } -#endif - - // Create a symbol for the name. - return Ctx.GetOrCreateSymbol(Name.str()); -} - -MCOperand ARMMCInstLower:: -LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const { - // FIXME: We would like an efficient form for this, so we don't have to do a - // lot of extra uniquing. - const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); - -#if 0 - switch (MO.getTargetFlags()) { - default: llvm_unreachable("Unknown target flag on GV operand"); - } -#endif - - if (!MO.isJTI() && MO.getOffset()) - Expr = MCBinaryExpr::CreateAdd(Expr, - MCConstantExpr::Create(MO.getOffset(), Ctx), - Ctx); - return MCOperand::CreateExpr(Expr); -} - - -void ARMMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { - OutMI.setOpcode(MI->getOpcode()); - - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { - const MachineOperand &MO = MI->getOperand(i); - - MCOperand MCOp; - switch (MO.getType()) { - default: - MI->dump(); - assert(0 && "unknown operand type"); - case MachineOperand::MO_Register: - // Ignore all implicit register operands. - if (MO.isImplicit()) continue; - assert(!MO.getSubReg() && "Subregs should be eliminated!"); - MCOp = MCOperand::CreateReg(MO.getReg()); - break; - case MachineOperand::MO_Immediate: - MCOp = MCOperand::CreateImm(MO.getImm()); - break; - case MachineOperand::MO_MachineBasicBlock: - MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( - MO.getMBB()->getSymbol(), Ctx)); - break; - case MachineOperand::MO_GlobalAddress: - MCOp = LowerSymbolOperand(MO, GetGlobalAddressSymbol(MO)); - break; - case MachineOperand::MO_ExternalSymbol: - MCOp = LowerSymbolOperand(MO, GetExternalSymbolSymbol(MO)); - break; - case MachineOperand::MO_JumpTableIndex: - MCOp = LowerSymbolOperand(MO, GetJumpTableSymbol(MO)); - break; - case MachineOperand::MO_ConstantPoolIndex: - MCOp = LowerSymbolOperand(MO, GetConstantPoolIndexSymbol(MO)); - break; - case MachineOperand::MO_BlockAddress: - MCOp = LowerSymbolOperand(MO, Printer.GetBlockAddressSymbol( - MO.getBlockAddress())); - break; - } - - OutMI.addOperand(MCOp); - } - -} diff --git a/lib/Target/ARM/AsmPrinter/ARMMCInstLower.h b/lib/Target/ARM/AsmPrinter/ARMMCInstLower.h deleted file mode 100644 index b81a306..0000000 --- a/lib/Target/ARM/AsmPrinter/ARMMCInstLower.h +++ /dev/null @@ -1,56 +0,0 @@ -//===-- ARMMCInstLower.h - Lower MachineInstr to MCInst -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef ARM_MCINSTLOWER_H -#define ARM_MCINSTLOWER_H - -#include "llvm/Support/Compiler.h" - -namespace llvm { - class AsmPrinter; - class MCAsmInfo; - class MCContext; - class MCInst; - class MCOperand; - class MCSymbol; - class MachineInstr; - class MachineModuleInfoMachO; - class MachineOperand; - class Mangler; - //class ARMSubtarget; - -/// ARMMCInstLower - This class is used to lower an MachineInstr into an MCInst. -class LLVM_LIBRARY_VISIBILITY ARMMCInstLower { - MCContext &Ctx; - Mangler &Mang; - AsmPrinter &Printer; - - //const ARMSubtarget &getSubtarget() const; -public: - ARMMCInstLower(MCContext &ctx, Mangler &mang, AsmPrinter &printer) - : Ctx(ctx), Mang(mang), Printer(printer) {} - - void Lower(const MachineInstr *MI, MCInst &OutMI) const; - - //MCSymbol *GetPICBaseSymbol() const; - MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const; - MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const; - MCSymbol *GetJumpTableSymbol(const MachineOperand &MO) const; - MCSymbol *GetConstantPoolIndexSymbol(const MachineOperand &MO) const; - MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; - -/* -private: - MachineModuleInfoMachO &getMachOMMI() const; - */ -}; - -} - -#endif diff --git a/lib/Target/ARM/AsmPrinter/CMakeLists.txt b/lib/Target/ARM/AsmPrinter/CMakeLists.txt index 4e299f8..18645c0 100644 --- a/lib/Target/ARM/AsmPrinter/CMakeLists.txt +++ b/lib/Target/ARM/AsmPrinter/CMakeLists.txt @@ -1,8 +1,6 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) add_llvm_library(LLVMARMAsmPrinter - ARMAsmPrinter.cpp ARMInstPrinter.cpp - ARMMCInstLower.cpp ) add_dependencies(LLVMARMAsmPrinter ARMCodeGenTable_gen) diff --git a/lib/Target/ARM/CMakeLists.txt b/lib/Target/ARM/CMakeLists.txt index 0df3466..6b4dee5 100644 --- a/lib/Target/ARM/CMakeLists.txt +++ b/lib/Target/ARM/CMakeLists.txt @@ -7,25 +7,32 @@ tablegen(ARMGenInstrNames.inc -gen-instr-enums) tablegen(ARMGenInstrInfo.inc -gen-instr-desc) tablegen(ARMGenCodeEmitter.inc -gen-emitter) tablegen(ARMGenAsmWriter.inc -gen-asm-writer) +tablegen(ARMGenAsmMatcher.inc -gen-asm-matcher) tablegen(ARMGenDAGISel.inc -gen-dag-isel) +tablegen(ARMGenFastISel.inc -gen-fast-isel) tablegen(ARMGenCallingConv.inc -gen-callingconv) tablegen(ARMGenSubtarget.inc -gen-subtarget) tablegen(ARMGenEDInfo.inc -gen-enhanced-disassembly-info) add_llvm_target(ARMCodeGen + ARMAsmPrinter.cpp ARMBaseInstrInfo.cpp ARMBaseRegisterInfo.cpp ARMCodeEmitter.cpp ARMConstantIslandPass.cpp ARMConstantPoolValue.cpp ARMExpandPseudoInsts.cpp + ARMFastISel.cpp + ARMGlobalMerge.cpp ARMISelDAGToDAG.cpp ARMISelLowering.cpp ARMInstrInfo.cpp ARMJITInfo.cpp ARMLoadStoreOptimizer.cpp ARMMCAsmInfo.cpp + ARMMCInstLower.cpp ARMRegisterInfo.cpp + ARMSelectionDAGInfo.cpp ARMSubtarget.cpp ARMTargetMachine.cpp ARMTargetObjectFile.cpp @@ -38,7 +45,6 @@ add_llvm_target(ARMCodeGen Thumb2InstrInfo.cpp Thumb2RegisterInfo.cpp Thumb2SizeReduction.cpp - ARMSelectionDAGInfo.cpp ) -target_link_libraries (LLVMARMCodeGen LLVMSelectionDAG) +target_link_libraries (LLVMARMCodeGen LLVMARMAsmPrinter LLVMSelectionDAG) diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index 4de697e..e220289 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -26,6 +26,8 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +//#define DEBUG(X) do { X; } while (0) + /// ARMGenDecoderTables.inc - ARMDecoderTables.inc is tblgen'ed from /// ARMDecoderEmitter.cpp TableGen backend. It contains: /// @@ -87,6 +89,11 @@ static unsigned decodeARMInstruction(uint32_t &insn) { return ARM::BFI; } + // Ditto for STRBT, which is a super-instruction for A8.6.199 Encoding A1 & A2. + // As a result, the decoder fails to deocode USAT properly. + if (slice(insn, 27, 21) == 0x37 && slice(insn, 5, 4) == 1) + return ARM::USAT; + // Ditto for ADDSrs, which is a super-instruction for A8.6.7 & A8.6.8. // As a result, the decoder fails to decode UMULL properly. if (slice(insn, 27, 21) == 0x04 && slice(insn, 7, 4) == 9) { @@ -106,7 +113,7 @@ static unsigned decodeARMInstruction(uint32_t &insn) { // Ditto for STRT, which is a super-instruction for A8.6.210 Encoding A1 & A2. // As a result, the decoder fails to deocode SSAT properly. if (slice(insn, 27, 21) == 0x35 && slice(insn, 5, 4) == 1) - return slice(insn, 6, 6) == 0 ? ARM::SSATlsl : ARM::SSATasr; + return ARM::SSAT; // Ditto for RSCrs, which is a super-instruction for A8.6.146 & A8.6.147. // As a result, the decoder fails to decode STRHT/LDRHT/LDRSHT/LDRSBT. @@ -291,7 +298,7 @@ static unsigned T2Morph2LoadLiteral(unsigned Opcode) { /// decodeInstruction(insn) is invoked on the original insn. /// /// Otherwise, decodeThumbInstruction is called with the original insn. -static unsigned decodeThumbSideEffect(bool IsThumb2, uint32_t &insn) { +static unsigned decodeThumbSideEffect(bool IsThumb2, unsigned &insn) { if (IsThumb2) { uint16_t op1 = slice(insn, 28, 27); uint16_t op2 = slice(insn, 26, 20); @@ -429,7 +436,7 @@ bool ThumbDisassembler::getInstruction(MCInst &MI, // passed to decodeThumbInstruction(). For 16-bit Thumb instruction, the top // halfword of insn is 0x00 0x00; otherwise, the first halfword is moved to // the top half followed by the second halfword. - uint32_t insn = 0; + unsigned insn = 0; // Possible second halfword. uint16_t insn1 = 0; diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp index a07ff28..9f493b9 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp @@ -20,6 +20,8 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +//#define DEBUG(X) do { X; } while (0) + /// ARMGenInstrInfo.inc - ARMGenInstrInfo.inc contains the static const /// TargetInstrDesc ARMInsts[] definition and the TargetOperandInfo[]'s /// describing the operand info for each ARMInsts[i]. @@ -93,6 +95,9 @@ static unsigned getRegisterEnum(BO B, unsigned RegClassID, unsigned RawRegister, RegClassID = ARM::DPRRegClassID; } + // For this purpose, we can treat rGPR as if it were GPR. + if (RegClassID == ARM::rGPRRegClassID) RegClassID = ARM::GPRRegClassID; + // See also decodeNEONRd(), decodeNEONRn(), decodeNEONRm(). unsigned RegNum = RegClassID == ARM::QPRRegClassID ? RawRegister >> 1 : RawRegister; @@ -451,12 +456,23 @@ static inline ARM_AM::ShiftOpc getShiftOpcForBits(unsigned bits) { // // A8-11: DecodeImmShift() static inline void getImmShiftSE(ARM_AM::ShiftOpc &ShOp, unsigned &ShImm) { - // If type == 0b11 and imm5 == 0, we have an rrx, instead. - if (ShOp == ARM_AM::ror && ShImm == 0) - ShOp = ARM_AM::rrx; - // If (lsr or asr) and imm5 == 0, shift amount is 32. - if ((ShOp == ARM_AM::lsr || ShOp == ARM_AM::asr) && ShImm == 0) + if (ShImm != 0) + return; + switch (ShOp) { + case ARM_AM::no_shift: + case ARM_AM::rrx: + break; + case ARM_AM::lsl: + ShOp = ARM_AM::no_shift; + break; + case ARM_AM::lsr: + case ARM_AM::asr: ShImm = 32; + break; + case ARM_AM::ror: + ShOp = ARM_AM::rrx; + break; + } } // getAMSubModeForBits - getAMSubModeForBits translates from the ARM encoding @@ -490,9 +506,6 @@ static inline ARM_AM::AMSubMode getAMSubModeForBits(unsigned bits) { static bool DisassemblePseudo(MCInst &MI, unsigned Opcode, uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO) { - if (Opcode == ARM::Int_MemBarrierV7 || Opcode == ARM::Int_SyncBarrierV7) - return true; - assert(0 && "Unexpected pseudo instruction!"); return false; } @@ -887,7 +900,6 @@ static bool DisassembleBrMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, return true; } - assert(0 && "Unexpected BrMiscFrm Opcode"); return false; } @@ -906,34 +918,6 @@ static inline bool getBFCInvMask(uint32_t insn, uint32_t &mask) { return true; } -static inline bool SaturateOpcode(unsigned Opcode) { - switch (Opcode) { - case ARM::SSATlsl: case ARM::SSATasr: case ARM::SSAT16: - case ARM::USATlsl: case ARM::USATasr: case ARM::USAT16: - return true; - default: - return false; - } -} - -static inline unsigned decodeSaturatePos(unsigned Opcode, uint32_t insn) { - switch (Opcode) { - case ARM::SSATlsl: - case ARM::SSATasr: - return slice(insn, 20, 16) + 1; - case ARM::SSAT16: - return slice(insn, 19, 16) + 1; - case ARM::USATlsl: - case ARM::USATasr: - return slice(insn, 20, 16); - case ARM::USAT16: - return slice(insn, 19, 16); - default: - assert(0 && "Invalid opcode passed in"); - return 0; - } -} - // A major complication is the fact that some of the saturating add/subtract // operations have Rd Rm Rn, instead of the "normal" Rd Rn Rm. // They are QADD, QDADD, QDSUB, and QSUB. @@ -959,40 +943,14 @@ static bool DisassembleDPFrm(MCInst &MI, unsigned Opcode, uint32_t insn, if (OpIdx >= NumOps) return false; - // SSAT/SSAT16/USAT/USAT16 has imm operand after Rd. - if (SaturateOpcode(Opcode)) { - MI.addOperand(MCOperand::CreateImm(decodeSaturatePos(Opcode, insn))); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, - decodeRm(insn)))); - - if (Opcode == ARM::SSAT16 || Opcode == ARM::USAT16) { - OpIdx += 2; - return true; - } - - // For SSAT operand reg (Rm) has been disassembled above. - // Now disassemble the shift amount. - - // Inst{11-7} encodes the imm5 shift amount. - unsigned ShAmt = slice(insn, 11, 7); - - // A8.6.183. Possible ASR shift amount of 32... - if (Opcode == ARM::SSATasr && ShAmt == 0) - ShAmt = 32; - - MI.addOperand(MCOperand::CreateImm(ShAmt)); - - OpIdx += 3; - return true; - } - // Special-case handling of BFC/BFI/SBFX/UBFX. if (Opcode == ARM::BFC || Opcode == ARM::BFI) { - // TIED_TO operand skipped for BFC and Inst{3-0} (Reg) for BFI. - MI.addOperand(MCOperand::CreateReg(Opcode == ARM::BFC ? 0 - : getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(0)); + if (Opcode == ARM::BFI) { + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, decodeRm(insn)))); + ++OpIdx; + } uint32_t mask = 0; if (!getBFCInvMask(insn, mask)) return false; @@ -1498,13 +1456,55 @@ static bool DisassembleArithMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef()) { // Extract the 5-bit immediate field Inst{11-7}. unsigned ShiftAmt = (insn >> ARMII::ShiftShift) & 0x1F; - MI.addOperand(MCOperand::CreateImm(ShiftAmt)); + ARM_AM::ShiftOpc Opc = ARM_AM::no_shift; + if (Opcode == ARM::PKHBT) + Opc = ARM_AM::lsl; + else if (Opcode == ARM::PKHBT) + Opc = ARM_AM::asr; + getImmShiftSE(Opc, ShiftAmt); + MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(Opc, ShiftAmt))); ++OpIdx; } return true; } +/// DisassembleSatFrm - Disassemble saturate instructions: +/// SSAT, SSAT16, USAT, and USAT16. +static bool DisassembleSatFrm(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned short NumOps, unsigned &NumOpsAdded, BO B) { + + const TargetInstrDesc &TID = ARMInsts[Opcode]; + NumOpsAdded = TID.getNumOperands() - 2; // ignore predicate operands + + // Disassemble register def. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + decodeRd(insn)))); + + unsigned Pos = slice(insn, 20, 16); + if (Opcode == ARM::SSAT || Opcode == ARM::SSAT16) + Pos += 1; + MI.addOperand(MCOperand::CreateImm(Pos)); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + decodeRm(insn)))); + + if (NumOpsAdded == 4) { + ARM_AM::ShiftOpc Opc = (slice(insn, 6, 6) != 0 ? ARM_AM::asr : ARM_AM::lsl); + // Inst{11-7} encodes the imm5 shift amount. + unsigned ShAmt = slice(insn, 11, 7); + if (ShAmt == 0) { + // A8.6.183. Possible ASR shift amount of 32... + if (Opc == ARM_AM::asr) + ShAmt = 32; + else + Opc = ARM_AM::no_shift; + } + MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(Opc, ShAmt))); + } + return true; +} + // Extend instructions. // SXT* and UXT*: Rd [Rn] Rm [rot_imm]. // The 2nd operand register is Rn and the 3rd operand regsiter is Rm for the @@ -1863,7 +1863,7 @@ static bool DisassembleVFPLdStFrm(MCInst &MI, unsigned Opcode, uint32_t insn, assert(NumOps >= 3 && "VFPLdStFrm expects NumOps >= 3"); - bool isSPVFP = (Opcode == ARM::VLDRS || Opcode == ARM::VSTRS) ? true : false; + bool isSPVFP = (Opcode == ARM::VLDRS || Opcode == ARM::VSTRS); unsigned RegClassID = isSPVFP ? ARM::SPRRegClassID : ARM::DPRRegClassID; // Extract Dd/Sd for operand 0. @@ -1886,7 +1886,7 @@ static bool DisassembleVFPLdStFrm(MCInst &MI, unsigned Opcode, uint32_t insn, // VFP Load/Store Multiple Instructions. // This is similar to the algorithm for LDM/STM in that operand 0 (the base) and -// operand 1 (the AM5 mode imm) is followed by two predicate operands. It is +// operand 1 (the AM4 mode imm) is followed by two predicate operands. It is // followed by a reglist of either DPR(s) or SPR(s). // // VLDMD[_UPD], VLDMS[_UPD], VSTMD[_UPD], VSTMS[_UPD] @@ -1910,16 +1910,14 @@ static bool DisassembleVFPLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, MI.addOperand(MCOperand::CreateReg(Base)); - // Next comes the AM5 Opcode. + // Next comes the AM4 Opcode. ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); // Must be either "ia" or "db" submode. if (SubMode != ARM_AM::ia && SubMode != ARM_AM::db) { - DEBUG(errs() << "Illegal addressing mode 5 sub-mode!\n"); + DEBUG(errs() << "Illegal addressing mode 4 sub-mode!\n"); return false; } - - unsigned char Imm8 = insn & 0xFF; - MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM5Opc(SubMode, Imm8))); + MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode))); // Handling the two predicate operands before the reglist. int64_t CondVal = insn >> ARMII::CondShift; @@ -1929,13 +1927,14 @@ static bool DisassembleVFPLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, OpIdx += 4; bool isSPVFP = (Opcode == ARM::VLDMS || Opcode == ARM::VLDMS_UPD || - Opcode == ARM::VSTMS || Opcode == ARM::VSTMS_UPD) ? true : false; + Opcode == ARM::VSTMS || Opcode == ARM::VSTMS_UPD); unsigned RegClassID = isSPVFP ? ARM::SPRRegClassID : ARM::DPRRegClassID; // Extract Dd/Sd. unsigned RegD = decodeVFPRd(insn, isSPVFP); // Fill the variadic part of reglist. + unsigned char Imm8 = insn & 0xFF; unsigned Regs = isSPVFP ? Imm8 : Imm8/2; for (unsigned i = 0; i < Regs; ++i) { MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RegClassID, @@ -2244,9 +2243,10 @@ static bool DisassembleNLdSt0(MCInst &MI, unsigned Opcode, uint32_t insn, // We have homogeneous NEON registers for Load/Store. unsigned RegClass = 0; + bool DRegPair = UseDRegPair(Opcode); // Double-spaced registers have increments of 2. - unsigned Inc = DblSpaced ? 2 : 1; + unsigned Inc = (DblSpaced || DRegPair) ? 2 : 1; unsigned Rn = decodeRn(insn); unsigned Rm = decodeRm(insn); @@ -2292,8 +2292,7 @@ static bool DisassembleNLdSt0(MCInst &MI, unsigned Opcode, uint32_t insn, RegClass = OpInfo[OpIdx].RegClass; while (OpIdx < NumOps && (unsigned)OpInfo[OpIdx].RegClass == RegClass) { MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(B, RegClass, Rd, - UseDRegPair(Opcode)))); + getRegisterEnum(B, RegClass, Rd, DRegPair))); Rd += Inc; ++OpIdx; } @@ -2312,8 +2311,7 @@ static bool DisassembleNLdSt0(MCInst &MI, unsigned Opcode, uint32_t insn, while (OpIdx < NumOps && (unsigned)OpInfo[OpIdx].RegClass == RegClass) { MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(B, RegClass, Rd, - UseDRegPair(Opcode)))); + getRegisterEnum(B, RegClass, Rd, DRegPair))); Rd += Inc; ++OpIdx; } @@ -2351,6 +2349,11 @@ static bool DisassembleNLdSt0(MCInst &MI, unsigned Opcode, uint32_t insn, } } + // Accessing registers past the end of the NEON register file is not + // defined. + if (Rd > 32) + return false; + return true; } @@ -2423,10 +2426,14 @@ static bool DisassembleN1RegModImmFrm(MCInst &MI, unsigned Opcode, break; case ARM::VMOVv4i16: case ARM::VMOVv8i16: + case ARM::VMVNv4i16: + case ARM::VMVNv8i16: esize = ESize16; break; case ARM::VMOVv2i32: case ARM::VMOVv4i32: + case ARM::VMVNv2i32: + case ARM::VMVNv4i32: esize = ESize32; break; case ARM::VMOVv1i64: @@ -2944,7 +2951,7 @@ static bool DisassembleNDupFrm(MCInst &MI, unsigned Opcode, uint32_t insn, // A8.6.49 ISB static inline bool MemBarrierInstr(uint32_t insn) { unsigned op7_4 = slice(insn, 7, 4); - if (slice(insn, 31, 20) == 0xf57 && (op7_4 >= 4 && op7_4 <= 6)) + if (slice(insn, 31, 8) == 0xf57ff0 && (op7_4 >= 4 && op7_4 <= 6)) return true; return false; @@ -3001,8 +3008,15 @@ static bool DisassemblePreLoadFrm(MCInst &MI, unsigned Opcode, uint32_t insn, static bool DisassembleMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) { - if (MemBarrierInstr(insn)) + if (MemBarrierInstr(insn)) { + // DMBsy, DSBsy, and ISBsy instructions have zero operand and are taken care + // of within the generic ARMBasicMCBuilder::BuildIt() method. + // + // Inst{3-0} encodes the memory barrier option for the variants. + MI.addOperand(MCOperand::CreateImm(slice(insn, 3, 0))); + NumOpsAdded = 1; return true; + } switch (Opcode) { case ARM::CLREX: @@ -3073,6 +3087,7 @@ static const DisassembleFP FuncPtrs[] = { &DisassembleLdStMulFrm, &DisassembleLdStExFrm, &DisassembleArithMiscFrm, + &DisassembleSatFrm, &DisassembleExtFrm, &DisassembleVFPUnaryFrm, &DisassembleVFPBinaryFrm, diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h index 7d21256..9c30d33 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h +++ b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h @@ -23,7 +23,8 @@ #include "llvm/MC/MCInst.h" #include "llvm/Target/TargetInstrInfo.h" -#include "ARMInstrInfo.h" +#include "ARMBaseInstrInfo.h" +#include "ARMRegisterInfo.h" #include "ARMDisassembler.h" namespace llvm { @@ -53,36 +54,35 @@ public: ENTRY(ARM_FORMAT_LDSTMULFRM, 10) \ ENTRY(ARM_FORMAT_LDSTEXFRM, 11) \ ENTRY(ARM_FORMAT_ARITHMISCFRM, 12) \ - ENTRY(ARM_FORMAT_EXTFRM, 13) \ - ENTRY(ARM_FORMAT_VFPUNARYFRM, 14) \ - ENTRY(ARM_FORMAT_VFPBINARYFRM, 15) \ - ENTRY(ARM_FORMAT_VFPCONV1FRM, 16) \ - ENTRY(ARM_FORMAT_VFPCONV2FRM, 17) \ - ENTRY(ARM_FORMAT_VFPCONV3FRM, 18) \ - ENTRY(ARM_FORMAT_VFPCONV4FRM, 19) \ - ENTRY(ARM_FORMAT_VFPCONV5FRM, 20) \ - ENTRY(ARM_FORMAT_VFPLDSTFRM, 21) \ - ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 22) \ - ENTRY(ARM_FORMAT_VFPMISCFRM, 23) \ - ENTRY(ARM_FORMAT_THUMBFRM, 24) \ - ENTRY(ARM_FORMAT_NEONFRM, 25) \ - ENTRY(ARM_FORMAT_NEONGETLNFRM, 26) \ - ENTRY(ARM_FORMAT_NEONSETLNFRM, 27) \ - ENTRY(ARM_FORMAT_NEONDUPFRM, 28) \ - ENTRY(ARM_FORMAT_MISCFRM, 29) \ - ENTRY(ARM_FORMAT_THUMBMISCFRM, 30) \ - ENTRY(ARM_FORMAT_NLdSt, 31) \ - ENTRY(ARM_FORMAT_N1RegModImm, 32) \ - ENTRY(ARM_FORMAT_N2Reg, 33) \ - ENTRY(ARM_FORMAT_NVCVT, 34) \ - ENTRY(ARM_FORMAT_NVecDupLn, 35) \ - ENTRY(ARM_FORMAT_N2RegVecShL, 36) \ - ENTRY(ARM_FORMAT_N2RegVecShR, 37) \ - ENTRY(ARM_FORMAT_N3Reg, 38) \ - ENTRY(ARM_FORMAT_N3RegVecSh, 39) \ - ENTRY(ARM_FORMAT_NVecExtract, 40) \ - ENTRY(ARM_FORMAT_NVecMulScalar, 41) \ - ENTRY(ARM_FORMAT_NVTBL, 42) + ENTRY(ARM_FORMAT_SATFRM, 13) \ + ENTRY(ARM_FORMAT_EXTFRM, 14) \ + ENTRY(ARM_FORMAT_VFPUNARYFRM, 15) \ + ENTRY(ARM_FORMAT_VFPBINARYFRM, 16) \ + ENTRY(ARM_FORMAT_VFPCONV1FRM, 17) \ + ENTRY(ARM_FORMAT_VFPCONV2FRM, 18) \ + ENTRY(ARM_FORMAT_VFPCONV3FRM, 19) \ + ENTRY(ARM_FORMAT_VFPCONV4FRM, 20) \ + ENTRY(ARM_FORMAT_VFPCONV5FRM, 21) \ + ENTRY(ARM_FORMAT_VFPLDSTFRM, 22) \ + ENTRY(ARM_FORMAT_VFPLDSTMULFRM, 23) \ + ENTRY(ARM_FORMAT_VFPMISCFRM, 24) \ + ENTRY(ARM_FORMAT_THUMBFRM, 25) \ + ENTRY(ARM_FORMAT_MISCFRM, 26) \ + ENTRY(ARM_FORMAT_NEONGETLNFRM, 27) \ + ENTRY(ARM_FORMAT_NEONSETLNFRM, 28) \ + ENTRY(ARM_FORMAT_NEONDUPFRM, 29) \ + ENTRY(ARM_FORMAT_NLdSt, 30) \ + ENTRY(ARM_FORMAT_N1RegModImm, 31) \ + ENTRY(ARM_FORMAT_N2Reg, 32) \ + ENTRY(ARM_FORMAT_NVCVT, 33) \ + ENTRY(ARM_FORMAT_NVecDupLn, 34) \ + ENTRY(ARM_FORMAT_N2RegVecShL, 35) \ + ENTRY(ARM_FORMAT_N2RegVecShR, 36) \ + ENTRY(ARM_FORMAT_N3Reg, 37) \ + ENTRY(ARM_FORMAT_N3RegVecSh, 38) \ + ENTRY(ARM_FORMAT_NVecExtract, 39) \ + ENTRY(ARM_FORMAT_NVecMulScalar, 40) \ + ENTRY(ARM_FORMAT_NVTBL, 41) // ARM instruction format specifies the encoding used by the instruction. #define ENTRY(n, v) n = v, @@ -126,8 +126,8 @@ static inline unsigned slice(uint32_t Bits, unsigned From, unsigned To) { } /// Utility function for setting [From, To] bits to Val for a uint32_t. -static inline void setSlice(uint32_t &Bits, unsigned From, unsigned To, - uint32_t Val) { +static inline void setSlice(unsigned &Bits, unsigned From, unsigned To, + unsigned Val) { assert(From < 32 && To < 32 && From >= To); uint32_t Mask = ((1 << (From - To + 1)) - 1); Bits &= ~(Mask << To); diff --git a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h index 4b7a0bf..112817b 100644 --- a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h +++ b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h @@ -103,7 +103,7 @@ static inline unsigned getT1Cond(uint32_t insn) { } static inline bool IsGPR(unsigned RegClass) { - return RegClass == ARM::GPRRegClassID; + return RegClass == ARM::GPRRegClassID || RegClass == ARM::rGPRRegClassID; } // Utilities for 32-bit Thumb instructions. @@ -220,7 +220,7 @@ static inline unsigned decodeImmShift(unsigned bits2, unsigned imm5, switch (bits2) { default: assert(0 && "No such value"); case 0: - ShOp = ARM_AM::lsl; + ShOp = (imm5 == 0 ? ARM_AM::no_shift : ARM_AM::lsl); return imm5; case 1: ShOp = ARM_AM::lsr; @@ -1324,7 +1324,7 @@ static bool DisassembleThumb2DPSoReg(MCInst &MI, unsigned Opcode, uint32_t insn, && OpInfo[1].RegClass == ARM::GPRRegClassID && OpInfo[2].RegClass < 0 && OpInfo[3].RegClass < 0 - && "Exactlt 4 operands expect and first two as reg operands"); + && "Exactly 4 operands expect and first two as reg operands"); // Only need to populate the src reg operand. MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, decodeRm(insn)))); @@ -1338,17 +1338,20 @@ static bool DisassembleThumb2DPSoReg(MCInst &MI, unsigned Opcode, uint32_t insn, OpIdx = 0; assert(NumOps >= 2 - && OpInfo[0].RegClass == ARM::GPRRegClassID - && OpInfo[1].RegClass == ARM::GPRRegClassID + && (OpInfo[0].RegClass == ARM::GPRRegClassID || + OpInfo[0].RegClass == ARM::rGPRRegClassID) + && (OpInfo[1].RegClass == ARM::GPRRegClassID || + OpInfo[1].RegClass == ARM::rGPRRegClassID) && "Expect >= 2 operands and first two as reg operands"); - bool ThreeReg = (NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID); + bool ThreeReg = (NumOps > 2 && (OpInfo[2].RegClass == ARM::GPRRegClassID || + OpInfo[2].RegClass == ARM::rGPRRegClassID)); bool NoDstReg = (decodeRs(insn) == 0xF); // Build the register operands, followed by the constant shift specifier. MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(B, ARM::GPRRegClassID, + getRegisterEnum(B, OpInfo[0].RegClass, NoDstReg ? decodeRn(insn) : decodeRs(insn)))); ++OpIdx; @@ -1359,7 +1362,7 @@ static bool DisassembleThumb2DPSoReg(MCInst &MI, unsigned Opcode, uint32_t insn, MI.addOperand(MI.getOperand(Idx)); ++OpIdx; } else if (!NoDstReg) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[1].RegClass, decodeRn(insn)))); ++OpIdx; } else { @@ -1368,7 +1371,7 @@ static bool DisassembleThumb2DPSoReg(MCInst &MI, unsigned Opcode, uint32_t insn, } } - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, OpInfo[OpIdx].RegClass, decodeRm(insn)))); ++OpIdx; @@ -1386,14 +1389,7 @@ static bool DisassembleThumb2DPSoReg(MCInst &MI, unsigned Opcode, uint32_t insn, unsigned imm5 = getShiftAmtBits(insn); ARM_AM::ShiftOpc ShOp = ARM_AM::no_shift; unsigned ShAmt = decodeImmShift(bits2, imm5, ShOp); - - // PKHBT/PKHTB are special in that we need the decodeImmShift() call to - // decode the shift amount from raw imm5 and bits2, but we DO NOT need - // to encode the ShOp, as it's in the asm string already. - if (Opcode == ARM::t2PKHBT || Opcode == ARM::t2PKHTB) - MI.addOperand(MCOperand::CreateImm(ShAmt)); - else - MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, ShAmt))); + MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(ShOp, ShAmt))); } ++OpIdx; } @@ -1416,16 +1412,20 @@ static bool DisassembleThumb2DPModImm(MCInst &MI, unsigned Opcode, OpIdx = 0; - assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::GPRRegClassID + unsigned RdRegClassID = OpInfo[0].RegClass; + assert(NumOps >= 2 && (RdRegClassID == ARM::GPRRegClassID || + RdRegClassID == ARM::rGPRRegClassID) && "Expect >= 2 operands and first one as reg operand"); - bool TwoReg = (OpInfo[1].RegClass == ARM::GPRRegClassID); + unsigned RnRegClassID = OpInfo[1].RegClass; + bool TwoReg = (RnRegClassID == ARM::GPRRegClassID + || RnRegClassID == ARM::rGPRRegClassID); bool NoDstReg = (decodeRs(insn) == 0xF); // Build the register operands, followed by the modified immediate. MI.addOperand(MCOperand::CreateReg( - getRegisterEnum(B, ARM::GPRRegClassID, + getRegisterEnum(B, RdRegClassID, NoDstReg ? decodeRn(insn) : decodeRs(insn)))); ++OpIdx; @@ -1434,7 +1434,7 @@ static bool DisassembleThumb2DPModImm(MCInst &MI, unsigned Opcode, DEBUG(errs()<<"Thumb2 encoding error: d==15 for DPModImm 2-reg instr.\n"); return false; } - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RnRegClassID, decodeRn(insn)))); ++OpIdx; } @@ -1455,30 +1455,48 @@ static bool DisassembleThumb2DPModImm(MCInst &MI, unsigned Opcode, static inline bool Thumb2SaturateOpcode(unsigned Opcode) { switch (Opcode) { - case ARM::t2SSATlsl: case ARM::t2SSATasr: case ARM::t2SSAT16: - case ARM::t2USATlsl: case ARM::t2USATasr: case ARM::t2USAT16: + case ARM::t2SSAT: case ARM::t2SSAT16: + case ARM::t2USAT: case ARM::t2USAT16: return true; default: return false; } } -static inline unsigned decodeThumb2SaturatePos(unsigned Opcode, uint32_t insn) { - switch (Opcode) { - case ARM::t2SSATlsl: - case ARM::t2SSATasr: - return slice(insn, 4, 0) + 1; - case ARM::t2SSAT16: - return slice(insn, 3, 0) + 1; - case ARM::t2USATlsl: - case ARM::t2USATasr: - return slice(insn, 4, 0); - case ARM::t2USAT16: - return slice(insn, 3, 0); - default: - assert(0 && "Unexpected opcode"); - return 0; +/// DisassembleThumb2Sat - Disassemble Thumb2 saturate instructions: +/// o t2SSAT, t2USAT: Rs sat_pos Rn shamt +/// o t2SSAT16, t2USAT16: Rs sat_pos Rn +static bool DisassembleThumb2Sat(MCInst &MI, unsigned Opcode, uint32_t insn, + unsigned &NumOpsAdded, BO B) { + const TargetInstrDesc &TID = ARMInsts[Opcode]; + NumOpsAdded = TID.getNumOperands() - 2; // ignore predicate operands + + // Disassemble the register def. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID, + decodeRs(insn)))); + + unsigned Pos = slice(insn, 4, 0); + if (Opcode == ARM::t2SSAT || Opcode == ARM::t2SSAT16) + Pos += 1; + MI.addOperand(MCOperand::CreateImm(Pos)); + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID, + decodeRn(insn)))); + + if (NumOpsAdded == 4) { + ARM_AM::ShiftOpc Opc = (slice(insn, 21, 21) != 0 ? + ARM_AM::asr : ARM_AM::lsl); + // Inst{14-12:7-6} encodes the imm5 shift amount. + unsigned ShAmt = slice(insn, 14, 12) << 2 | slice(insn, 7, 6); + if (ShAmt == 0) { + if (Opc == ARM_AM::asr) + ShAmt = 32; + else + Opc = ARM_AM::no_shift; + } + MI.addOperand(MCOperand::CreateImm(ARM_AM::getSORegOpc(Opc, ShAmt))); } + return true; } // A6.3.3 Data-processing (plain binary immediate) @@ -1492,11 +1510,6 @@ static inline unsigned decodeThumb2SaturatePos(unsigned Opcode, uint32_t insn) { // o t2SBFX (SBFX): Rs Rn lsb width // o t2UBFX (UBFX): Rs Rn lsb width // o t2BFI (BFI): Rs Rn lsb width -// -// [Signed|Unsigned] Saturate [16] -// -// o t2SSAT[lsl|asr], t2USAT[lsl|asr]: Rs sat_pos Rn shamt -// o t2SSAT16, t2USAT16: Rs sat_pos Rn static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode, uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) { @@ -1506,41 +1519,21 @@ static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode, OpIdx = 0; - assert(NumOps >= 2 && OpInfo[0].RegClass == ARM::GPRRegClassID + unsigned RdRegClassID = OpInfo[0].RegClass; + assert(NumOps >= 2 && (RdRegClassID == ARM::GPRRegClassID || + RdRegClassID == ARM::rGPRRegClassID) && "Expect >= 2 operands and first one as reg operand"); - bool TwoReg = (OpInfo[1].RegClass == ARM::GPRRegClassID); + unsigned RnRegClassID = OpInfo[1].RegClass; + bool TwoReg = (RnRegClassID == ARM::GPRRegClassID + || RnRegClassID == ARM::rGPRRegClassID); // Build the register operand(s), followed by the immediate(s). - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RdRegClassID, decodeRs(insn)))); ++OpIdx; - // t2SSAT/t2SSAT16/t2USAT/t2USAT16 has imm operand after Rd. - if (Thumb2SaturateOpcode(Opcode)) { - MI.addOperand(MCOperand::CreateImm(decodeThumb2SaturatePos(Opcode, insn))); - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, - decodeRn(insn)))); - - if (Opcode == ARM::t2SSAT16 || Opcode == ARM::t2USAT16) { - OpIdx += 2; - return true; - } - - // For SSAT operand reg (Rn) has been disassembled above. - // Now disassemble the shift amount. - - // Inst{14-12:7-6} encodes the imm5 shift amount. - unsigned ShAmt = slice(insn, 14, 12) << 2 | slice(insn, 7, 6); - - MI.addOperand(MCOperand::CreateImm(ShAmt)); - - OpIdx += 3; - return true; - } - if (TwoReg) { assert(NumOps >= 3 && "Expect >= 3 operands"); int Idx; @@ -1549,12 +1542,19 @@ static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode, MI.addOperand(MI.getOperand(Idx)); } else { // Add src reg operand. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RnRegClassID, decodeRn(insn)))); } ++OpIdx; } + if (Opcode == ARM::t2BFI) { + // Add val reg operand. + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, RnRegClassID, + decodeRn(insn)))); + ++OpIdx; + } + assert(OpInfo[OpIdx].RegClass < 0 && !OpInfo[OpIdx].isPredicate() && !OpInfo[OpIdx].isOptionalDef() && "Pure imm operand expected"); @@ -1567,7 +1567,7 @@ static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode, MI.addOperand(MCOperand::CreateImm(getIImm3Imm8(insn))); else if (Opcode == ARM::t2MOVi16 || Opcode == ARM::t2MOVTi16) MI.addOperand(MCOperand::CreateImm(getImm16(insn))); - else if (Opcode == ARM::t2BFC) { + else if (Opcode == ARM::t2BFC || Opcode == ARM::t2BFI) { uint32_t mask = 0; if (getBitfieldInvMask(insn, mask)) MI.addOperand(MCOperand::CreateImm(mask)); @@ -1575,17 +1575,10 @@ static bool DisassembleThumb2DPBinImm(MCInst &MI, unsigned Opcode, return false; } else { // Handle the case of: lsb width - assert((Opcode == ARM::t2SBFX || Opcode == ARM::t2UBFX || - Opcode == ARM::t2BFI) && "Unexpected opcode"); + assert((Opcode == ARM::t2SBFX || Opcode == ARM::t2UBFX) + && "Unexpected opcode"); MI.addOperand(MCOperand::CreateImm(getLsb(insn))); - if (Opcode == ARM::t2BFI) { - if (getMsb(insn) < getLsb(insn)) { - DEBUG(errs() << "Encoding error: msb < lsb\n"); - return false; - } - MI.addOperand(MCOperand::CreateImm(getMsb(insn) - getLsb(insn) + 1)); - } else - MI.addOperand(MCOperand::CreateImm(getWidthMinus1(insn) + 1)); + MI.addOperand(MCOperand::CreateImm(getWidthMinus1(insn) + 1)); ++OpIdx; } @@ -1618,8 +1611,8 @@ static inline bool t2MiscCtrlInstr(uint32_t insn) { // A8.6.26 // t2BXJ -> Rn // -// Miscellaneous control: t2Int_MemBarrierV7 (and its t2DMB variants), -// t2Int_SyncBarrierV7 (and its t2DSB varianst), t2ISBsy, t2CLREX +// Miscellaneous control: t2DMBsy (and its t2DMB variants), +// t2DSBsy (and its t2DSB varianst), t2ISBsy, t2CLREX // -> no operand (except pred-imm pred-ccr for CLREX, memory barrier variants) // // Hint: t2NOP, t2YIELD, t2WFE, t2WFI, t2SEV @@ -1959,25 +1952,25 @@ static bool DisassembleThumb2DPReg(MCInst &MI, unsigned Opcode, uint32_t insn, OpIdx = 0; assert(NumOps >= 2 && - OpInfo[0].RegClass == ARM::GPRRegClassID && - OpInfo[1].RegClass == ARM::GPRRegClassID && + OpInfo[0].RegClass == ARM::rGPRRegClassID && + OpInfo[1].RegClass == ARM::rGPRRegClassID && "Expect >= 2 operands and first two as reg operands"); // Build the register operands, followed by the optional rotation amount. - bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::GPRRegClassID; + bool ThreeReg = NumOps > 2 && OpInfo[2].RegClass == ARM::rGPRRegClassID; - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID, decodeRs(insn)))); ++OpIdx; if (ThreeReg) { - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID, decodeRn(insn)))); ++OpIdx; } - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID, decodeRm(insn)))); ++OpIdx; @@ -2009,26 +2002,26 @@ static bool DisassembleThumb2Mul(MCInst &MI, unsigned Opcode, uint32_t insn, const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; assert(NumOps >= 3 && - OpInfo[0].RegClass == ARM::GPRRegClassID && - OpInfo[1].RegClass == ARM::GPRRegClassID && - OpInfo[2].RegClass == ARM::GPRRegClassID && + OpInfo[0].RegClass == ARM::rGPRRegClassID && + OpInfo[1].RegClass == ARM::rGPRRegClassID && + OpInfo[2].RegClass == ARM::rGPRRegClassID && "Expect >= 3 operands and first three as reg operands"); // Build the register operands. - bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::GPRRegClassID; + bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::rGPRRegClassID; - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID, decodeRs(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID, decodeRn(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID, decodeRm(insn)))); if (FourReg) - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID, decodeRd(insn)))); NumOpsAdded = FourReg ? 4 : 3; @@ -2054,26 +2047,26 @@ static bool DisassembleThumb2LongMul(MCInst &MI, unsigned Opcode, uint32_t insn, const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; assert(NumOps >= 3 && - OpInfo[0].RegClass == ARM::GPRRegClassID && - OpInfo[1].RegClass == ARM::GPRRegClassID && - OpInfo[2].RegClass == ARM::GPRRegClassID && + OpInfo[0].RegClass == ARM::rGPRRegClassID && + OpInfo[1].RegClass == ARM::rGPRRegClassID && + OpInfo[2].RegClass == ARM::rGPRRegClassID && "Expect >= 3 operands and first three as reg operands"); - bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::GPRRegClassID; + bool FourReg = NumOps > 3 && OpInfo[3].RegClass == ARM::rGPRRegClassID; // Build the register operands. if (FourReg) - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID, decodeRd(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID, decodeRs(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID, decodeRn(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::rGPRRegClassID, decodeRm(insn)))); if (FourReg) @@ -2152,22 +2145,20 @@ static bool DisassembleThumb2(uint16_t op1, uint16_t op2, uint16_t op, break; case 2: if (op == 0) { - if (slice(op2, 5, 5) == 0) { + if (slice(op2, 5, 5) == 0) // Data-processing (modified immediate) return DisassembleThumb2DPModImm(MI, Opcode, insn, NumOps, NumOpsAdded, B); - } else { - // Data-processing (plain binary immediate) - return DisassembleThumb2DPBinImm(MI, Opcode, insn, NumOps, NumOpsAdded, - B); - } - } else { - // Branches and miscellaneous control on page A6-20. - return DisassembleThumb2BrMiscCtrl(MI, Opcode, insn, NumOps, NumOpsAdded, - B); - } + if (Thumb2SaturateOpcode(Opcode)) + return DisassembleThumb2Sat(MI, Opcode, insn, NumOpsAdded, B); - break; + // Data-processing (plain binary immediate) + return DisassembleThumb2DPBinImm(MI, Opcode, insn, NumOps, NumOpsAdded, + B); + } + // Branches and miscellaneous control on page A6-20. + return DisassembleThumb2BrMiscCtrl(MI, Opcode, insn, NumOps, NumOpsAdded, + B); case 3: switch (slice(op2, 6, 5)) { case 0: diff --git a/lib/Target/ARM/Makefile b/lib/Target/ARM/Makefile index 9e3ff29..b3fcfaf6 100644 --- a/lib/Target/ARM/Makefile +++ b/lib/Target/ARM/Makefile @@ -14,10 +14,11 @@ TARGET = ARM # Make sure that tblgen is run, first thing. BUILT_SOURCES = ARMGenRegisterInfo.h.inc ARMGenRegisterNames.inc \ ARMGenRegisterInfo.inc ARMGenInstrNames.inc \ - ARMGenInstrInfo.inc ARMGenAsmWriter.inc \ + ARMGenInstrInfo.inc ARMGenAsmWriter.inc ARMGenAsmMatcher.inc \ ARMGenDAGISel.inc ARMGenSubtarget.inc \ ARMGenCodeEmitter.inc ARMGenCallingConv.inc \ - ARMGenDecoderTables.inc ARMGenEDInfo.inc + ARMGenDecoderTables.inc ARMGenEDInfo.inc \ + ARMGenFastISel.inc DIRS = AsmPrinter AsmParser Disassembler TargetInfo diff --git a/lib/Target/ARM/NEONMoveFix.cpp b/lib/Target/ARM/NEONMoveFix.cpp index bbdd3c7..97e54bf 100644 --- a/lib/Target/ARM/NEONMoveFix.cpp +++ b/lib/Target/ARM/NEONMoveFix.cpp @@ -24,7 +24,7 @@ STATISTIC(NumVMovs, "Number of reg-reg moves converted"); namespace { struct NEONMoveFixPass : public MachineFunctionPass { static char ID; - NEONMoveFixPass() : MachineFunctionPass(&ID) {} + NEONMoveFixPass() : MachineFunctionPass(ID) {} virtual bool runOnMachineFunction(MachineFunction &Fn); diff --git a/lib/Target/ARM/NEONPreAllocPass.cpp b/lib/Target/ARM/NEONPreAllocPass.cpp index f67717c..3407ac6 100644 --- a/lib/Target/ARM/NEONPreAllocPass.cpp +++ b/lib/Target/ARM/NEONPreAllocPass.cpp @@ -23,7 +23,7 @@ namespace { public: static char ID; - NEONPreAllocPass() : MachineFunctionPass(&ID) {} + NEONPreAllocPass() : MachineFunctionPass(ID) {} virtual bool runOnMachineFunction(MachineFunction &MF); @@ -51,13 +51,6 @@ static bool isNEONMultiRegOp(int Opcode, unsigned &FirstOpnd, unsigned &NumRegs, default: break; - case ARM::VLD1q8: - case ARM::VLD1q16: - case ARM::VLD1q32: - case ARM::VLD1q64: - case ARM::VLD2d8: - case ARM::VLD2d16: - case ARM::VLD2d32: case ARM::VLD2LNd8: case ARM::VLD2LNd16: case ARM::VLD2LNd32: @@ -65,13 +58,6 @@ static bool isNEONMultiRegOp(int Opcode, unsigned &FirstOpnd, unsigned &NumRegs, NumRegs = 2; return true; - case ARM::VLD2q8: - case ARM::VLD2q16: - case ARM::VLD2q32: - FirstOpnd = 0; - NumRegs = 4; - return true; - case ARM::VLD2LNq16: case ARM::VLD2LNq32: FirstOpnd = 0; @@ -88,10 +74,6 @@ static bool isNEONMultiRegOp(int Opcode, unsigned &FirstOpnd, unsigned &NumRegs, Stride = 2; return true; - case ARM::VLD3d8: - case ARM::VLD3d16: - case ARM::VLD3d32: - case ARM::VLD1d64T: case ARM::VLD3LNd8: case ARM::VLD3LNd16: case ARM::VLD3LNd32: @@ -99,24 +81,6 @@ static bool isNEONMultiRegOp(int Opcode, unsigned &FirstOpnd, unsigned &NumRegs, NumRegs = 3; return true; - case ARM::VLD3q8_UPD: - case ARM::VLD3q16_UPD: - case ARM::VLD3q32_UPD: - FirstOpnd = 0; - NumRegs = 3; - Offset = 0; - Stride = 2; - return true; - - case ARM::VLD3q8odd_UPD: - case ARM::VLD3q16odd_UPD: - case ARM::VLD3q32odd_UPD: - FirstOpnd = 0; - NumRegs = 3; - Offset = 1; - Stride = 2; - return true; - case ARM::VLD3LNq16: case ARM::VLD3LNq32: FirstOpnd = 0; @@ -133,10 +97,6 @@ static bool isNEONMultiRegOp(int Opcode, unsigned &FirstOpnd, unsigned &NumRegs, Stride = 2; return true; - case ARM::VLD4d8: - case ARM::VLD4d16: - case ARM::VLD4d32: - case ARM::VLD1d64Q: case ARM::VLD4LNd8: case ARM::VLD4LNd16: case ARM::VLD4LNd32: @@ -144,24 +104,6 @@ static bool isNEONMultiRegOp(int Opcode, unsigned &FirstOpnd, unsigned &NumRegs, NumRegs = 4; return true; - case ARM::VLD4q8_UPD: - case ARM::VLD4q16_UPD: - case ARM::VLD4q32_UPD: - FirstOpnd = 0; - NumRegs = 4; - Offset = 0; - Stride = 2; - return true; - - case ARM::VLD4q8odd_UPD: - case ARM::VLD4q16odd_UPD: - case ARM::VLD4q32odd_UPD: - FirstOpnd = 0; - NumRegs = 4; - Offset = 1; - Stride = 2; - return true; - case ARM::VLD4LNq16: case ARM::VLD4LNq32: FirstOpnd = 0; @@ -178,13 +120,6 @@ static bool isNEONMultiRegOp(int Opcode, unsigned &FirstOpnd, unsigned &NumRegs, Stride = 2; return true; - case ARM::VST1q8: - case ARM::VST1q16: - case ARM::VST1q32: - case ARM::VST1q64: - case ARM::VST2d8: - case ARM::VST2d16: - case ARM::VST2d32: case ARM::VST2LNd8: case ARM::VST2LNd16: case ARM::VST2LNd32: @@ -192,13 +127,6 @@ static bool isNEONMultiRegOp(int Opcode, unsigned &FirstOpnd, unsigned &NumRegs, NumRegs = 2; return true; - case ARM::VST2q8: - case ARM::VST2q16: - case ARM::VST2q32: - FirstOpnd = 2; - NumRegs = 4; - return true; - case ARM::VST2LNq16: case ARM::VST2LNq32: FirstOpnd = 2; @@ -215,10 +143,6 @@ static bool isNEONMultiRegOp(int Opcode, unsigned &FirstOpnd, unsigned &NumRegs, Stride = 2; return true; - case ARM::VST3d8: - case ARM::VST3d16: - case ARM::VST3d32: - case ARM::VST1d64T: case ARM::VST3LNd8: case ARM::VST3LNd16: case ARM::VST3LNd32: @@ -226,24 +150,6 @@ static bool isNEONMultiRegOp(int Opcode, unsigned &FirstOpnd, unsigned &NumRegs, NumRegs = 3; return true; - case ARM::VST3q8_UPD: - case ARM::VST3q16_UPD: - case ARM::VST3q32_UPD: - FirstOpnd = 4; - NumRegs = 3; - Offset = 0; - Stride = 2; - return true; - - case ARM::VST3q8odd_UPD: - case ARM::VST3q16odd_UPD: - case ARM::VST3q32odd_UPD: - FirstOpnd = 4; - NumRegs = 3; - Offset = 1; - Stride = 2; - return true; - case ARM::VST3LNq16: case ARM::VST3LNq32: FirstOpnd = 2; @@ -260,10 +166,6 @@ static bool isNEONMultiRegOp(int Opcode, unsigned &FirstOpnd, unsigned &NumRegs, Stride = 2; return true; - case ARM::VST4d8: - case ARM::VST4d16: - case ARM::VST4d32: - case ARM::VST1d64Q: case ARM::VST4LNd8: case ARM::VST4LNd16: case ARM::VST4LNd32: @@ -271,24 +173,6 @@ static bool isNEONMultiRegOp(int Opcode, unsigned &FirstOpnd, unsigned &NumRegs, NumRegs = 4; return true; - case ARM::VST4q8_UPD: - case ARM::VST4q16_UPD: - case ARM::VST4q32_UPD: - FirstOpnd = 4; - NumRegs = 4; - Offset = 0; - Stride = 2; - return true; - - case ARM::VST4q8odd_UPD: - case ARM::VST4q16odd_UPD: - case ARM::VST4q32odd_UPD: - FirstOpnd = 4; - NumRegs = 4; - Offset = 1; - Stride = 2; - return true; - case ARM::VST4LNq16: case ARM::VST4LNq32: FirstOpnd = 2; @@ -468,7 +352,34 @@ bool NEONPreAllocPass::PreAllocNEONRegisters(MachineBasicBlock &MBB) { continue; if (FormsRegSequence(MI, FirstOpnd, NumRegs, Offset, Stride)) continue; - llvm_unreachable("expected a REG_SEQUENCE"); + + MachineBasicBlock::iterator NextI = llvm::next(MBBI); + for (unsigned R = 0; R < NumRegs; ++R) { + MachineOperand &MO = MI->getOperand(FirstOpnd + R); + assert(MO.isReg() && MO.getSubReg() == 0 && "unexpected operand"); + unsigned VirtReg = MO.getReg(); + assert(TargetRegisterInfo::isVirtualRegister(VirtReg) && + "expected a virtual register"); + + // For now, just assign a fixed set of adjacent registers. + // This leaves plenty of room for future improvements. + static const unsigned NEONDRegs[] = { + ARM::D0, ARM::D1, ARM::D2, ARM::D3, + ARM::D4, ARM::D5, ARM::D6, ARM::D7 + }; + MO.setReg(NEONDRegs[Offset + R * Stride]); + + if (MO.isUse()) { + // Insert a copy from VirtReg. + BuildMI(MBB, MBBI, DebugLoc(), TII->get(TargetOpcode::COPY),MO.getReg()) + .addReg(VirtReg, getKillRegState(MO.isKill())); + MO.setIsKill(); + } else if (MO.isDef() && !MO.isDead()) { + // Add a copy to VirtReg. + BuildMI(MBB, NextI, DebugLoc(), TII->get(TargetOpcode::COPY), VirtReg) + .addReg(MO.getReg()); + } + } } return Modified; diff --git a/lib/Target/ARM/README.txt b/lib/Target/ARM/README.txt index 0cb8ff0..9fc3fb9 100644 --- a/lib/Target/ARM/README.txt +++ b/lib/Target/ARM/README.txt @@ -611,27 +611,6 @@ constant which was already loaded). Not sure what's necessary to do that. //===---------------------------------------------------------------------===// -Given the following on ARMv7: -int test1(int A, int B) { - return (A&-8388481)|(B&8388480); -} - -We currently generate: - bfc r0, #7, #16 - movw r2, #:lower16:8388480 - movt r2, #:upper16:8388480 - and r1, r1, r2 - orr r0, r1, r0 - bx lr - -The following is much shorter: - lsr r1, r1, #7 - bfi r0, r1, #7, #16 - bx lr - - -//===---------------------------------------------------------------------===// - The code generated for bswap on armv4/5 (CPUs without rev) is less than ideal: int a(int x) { return __builtin_bswap32(x); } @@ -657,3 +636,24 @@ A custom Thumb version would also be a slight improvement over the generic version. //===---------------------------------------------------------------------===// + +Consider the following simple C code: + +void foo(unsigned char *a, unsigned char *b, int *c) { + if ((*a | *b) == 0) *c = 0; +} + +currently llvm-gcc generates something like this (nice branchless code I'd say): + + ldrb r0, [r0] + ldrb r1, [r1] + orr r0, r1, r0 + tst r0, #255 + moveq r0, #0 + streq r0, [r2] + bx lr + +Note that both "tst" and "moveq" are redundant. + +//===---------------------------------------------------------------------===// + diff --git a/lib/Target/ARM/Thumb1RegisterInfo.cpp b/lib/Target/ARM/Thumb1RegisterInfo.cpp index 39b70b4..a21a3da 100644 --- a/lib/Target/ARM/Thumb1RegisterInfo.cpp +++ b/lib/Target/ARM/Thumb1RegisterInfo.cpp @@ -68,7 +68,7 @@ void Thumb1RegisterInfo::emitLoadConstPool(MachineBasicBlock &MBB, .addConstantPoolIndex(Idx).addImm(Pred).addReg(PredReg); } -bool Thumb1RegisterInfo::hasReservedCallFrame(MachineFunction &MF) const { +bool Thumb1RegisterInfo::hasReservedCallFrame(const MachineFunction &MF) const { const MachineFrameInfo *FFI = MF.getFrameInfo(); unsigned CFSize = FFI->getMaxCallFrameSize(); // It's not always a good idea to include the call frame as part of the @@ -363,107 +363,19 @@ static void removeOperands(MachineInstr &MI, unsigned i) { MI.RemoveOperand(Op); } -int Thumb1RegisterInfo:: -rewriteFrameIndex(MachineInstr &MI, unsigned FrameRegIdx, - unsigned FrameReg, int Offset, - unsigned MOVOpc, unsigned ADDriOpc, unsigned SUBriOpc) const -{ - // if/when eliminateFrameIndex() conforms with ARMBaseRegisterInfo - // version then can pull out Thumb1 specific parts here - return 0; -} - -/// saveScavengerRegister - Spill the register so it can be used by the -/// register scavenger. Return true. -bool -Thumb1RegisterInfo::saveScavengerRegister(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, - MachineBasicBlock::iterator &UseMI, - const TargetRegisterClass *RC, - unsigned Reg) const { - // Thumb1 can't use the emergency spill slot on the stack because - // ldr/str immediate offsets must be positive, and if we're referencing - // off the frame pointer (if, for example, there are alloca() calls in - // the function, the offset will be negative. Use R12 instead since that's - // a call clobbered register that we know won't be used in Thumb1 mode. - DebugLoc DL; - BuildMI(MBB, I, DL, TII.get(ARM::tMOVtgpr2gpr)). - addReg(ARM::R12, RegState::Define).addReg(Reg, RegState::Kill); - - // The UseMI is where we would like to restore the register. If there's - // interference with R12 before then, however, we'll need to restore it - // before that instead and adjust the UseMI. - bool done = false; - for (MachineBasicBlock::iterator II = I; !done && II != UseMI ; ++II) { - if (II->isDebugValue()) - continue; - // If this instruction affects R12, adjust our restore point. - for (unsigned i = 0, e = II->getNumOperands(); i != e; ++i) { - const MachineOperand &MO = II->getOperand(i); - if (!MO.isReg() || MO.isUndef() || !MO.getReg() || - TargetRegisterInfo::isVirtualRegister(MO.getReg())) - continue; - if (MO.getReg() == ARM::R12) { - UseMI = II; - done = true; - break; - } - } - } - // Restore the register from R12 - BuildMI(MBB, UseMI, DL, TII.get(ARM::tMOVgpr2tgpr)). - addReg(Reg, RegState::Define).addReg(ARM::R12, RegState::Kill); - - return true; -} - -unsigned -Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value, - RegScavenger *RS) const{ - unsigned VReg = 0; - unsigned i = 0; +bool Thumb1RegisterInfo:: +rewriteFrameIndex(MachineBasicBlock::iterator II, unsigned FrameRegIdx, + unsigned FrameReg, int &Offset, + const ARMBaseInstrInfo &TII) const { MachineInstr &MI = *II; MachineBasicBlock &MBB = *MI.getParent(); - MachineFunction &MF = *MBB.getParent(); - ARMFunctionInfo *AFI = MF.getInfo(); DebugLoc dl = MI.getDebugLoc(); - - while (!MI.getOperand(i).isFI()) { - ++i; - assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); - } - - unsigned FrameReg = ARM::SP; - int FrameIndex = MI.getOperand(i).getIndex(); - int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) + - MF.getFrameInfo()->getStackSize() + SPAdj; - - if (AFI->isGPRCalleeSavedArea1Frame(FrameIndex)) - Offset -= AFI->getGPRCalleeSavedArea1Offset(); - else if (AFI->isGPRCalleeSavedArea2Frame(FrameIndex)) - Offset -= AFI->getGPRCalleeSavedArea2Offset(); - else if (MF.getFrameInfo()->hasVarSizedObjects()) { - assert(SPAdj == 0 && hasFP(MF) && "Unexpected"); - // There are alloca()'s in this function, must reference off the frame - // pointer instead. - FrameReg = getFrameRegister(MF); - Offset -= AFI->getFramePtrSpillOffset(); - } - - // Special handling of dbg_value instructions. - if (MI.isDebugValue()) { - MI.getOperand(i). ChangeToRegister(FrameReg, false /*isDef*/); - MI.getOperand(i+1).ChangeToImmediate(Offset); - return 0; - } - unsigned Opcode = MI.getOpcode(); const TargetInstrDesc &Desc = MI.getDesc(); unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask); if (Opcode == ARM::tADDrSPi) { - Offset += MI.getOperand(i+1).getImm(); + Offset += MI.getOperand(FrameRegIdx+1).getImm(); // Can't use tADDrSPi if it's based off the frame pointer. unsigned NumBits = 0; @@ -483,12 +395,13 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, if (Offset == 0 && getInstrPredicate(&MI, PredReg) == ARMCC::AL) { // Turn it into a move. MI.setDesc(TII.get(ARM::tMOVgpr2tgpr)); - MI.getOperand(i).ChangeToRegister(FrameReg, false); + MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false); // Remove offset and remaining explicit predicate operands. - do MI.RemoveOperand(i+1); - while (MI.getNumOperands() > i+1 && - (!MI.getOperand(i+1).isReg() || !MI.getOperand(i+1).isImm())); - return 0; + do MI.RemoveOperand(FrameRegIdx+1); + while (MI.getNumOperands() > FrameRegIdx+1 && + (!MI.getOperand(FrameRegIdx+1).isReg() || + !MI.getOperand(FrameRegIdx+1).isImm())); + return true; } // Common case: small offset, fits into instruction. @@ -496,15 +409,15 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, if (((Offset / Scale) & ~Mask) == 0) { // Replace the FrameIndex with sp / fp if (Opcode == ARM::tADDi3) { - removeOperands(MI, i); + removeOperands(MI, FrameRegIdx); MachineInstrBuilder MIB(&MI); AddDefaultPred(AddDefaultT1CC(MIB).addReg(FrameReg) .addImm(Offset / Scale)); } else { - MI.getOperand(i).ChangeToRegister(FrameReg, false); - MI.getOperand(i+1).ChangeToImmediate(Offset / Scale); + MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false); + MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset / Scale); } - return 0; + return true; } unsigned DestReg = MI.getOperand(0).getReg(); @@ -516,7 +429,7 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, emitThumbRegPlusImmediate(MBB, II, DestReg, FrameReg, Offset, TII, *this, dl); MBB.erase(II); - return 0; + return true; } if (Offset > 0) { @@ -524,12 +437,12 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, // r0 = add sp, 255*4 // r0 = add r0, (imm - 255*4) if (Opcode == ARM::tADDi3) { - removeOperands(MI, i); + removeOperands(MI, FrameRegIdx); MachineInstrBuilder MIB(&MI); AddDefaultPred(AddDefaultT1CC(MIB).addReg(FrameReg).addImm(Mask)); } else { - MI.getOperand(i).ChangeToRegister(FrameReg, false); - MI.getOperand(i+1).ChangeToImmediate(Mask); + MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false); + MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Mask); } Offset = (Offset - Mask * Scale); MachineBasicBlock::iterator NII = llvm::next(II); @@ -542,14 +455,14 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, emitThumbConstant(MBB, II, DestReg, Offset, TII, *this, dl); MI.setDesc(TII.get(ARM::tADDhirr)); - MI.getOperand(i).ChangeToRegister(DestReg, false, false, true); - MI.getOperand(i+1).ChangeToRegister(FrameReg, false); + MI.getOperand(FrameRegIdx).ChangeToRegister(DestReg, false, false, true); + MI.getOperand(FrameRegIdx+1).ChangeToRegister(FrameReg, false); if (Opcode == ARM::tADDi3) { MachineInstrBuilder MIB(&MI); AddDefaultPred(MIB); } } - return 0; + return true; } else { unsigned ImmIdx = 0; int InstrOffs = 0; @@ -557,7 +470,7 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, unsigned Scale = 1; switch (AddrMode) { case ARMII::AddrModeT1_s: { - ImmIdx = i+1; + ImmIdx = FrameRegIdx+1; InstrOffs = MI.getOperand(ImmIdx).getImm(); NumBits = (FrameReg == ARM::SP) ? 8 : 5; Scale = 4; @@ -577,9 +490,9 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, unsigned Mask = (1 << NumBits) - 1; if ((unsigned)Offset <= Mask * Scale) { // Replace the FrameIndex with sp - MI.getOperand(i).ChangeToRegister(FrameReg, false); + MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false); ImmOp.ChangeToImmediate(ImmedOffset); - return 0; + return true; } bool isThumSpillRestore = Opcode == ARM::tRestore || Opcode == ARM::tSpill; @@ -600,12 +513,126 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, Offset &= ~(Mask*Scale); } } + return Offset == 0; +} + +void +Thumb1RegisterInfo::resolveFrameIndex(MachineBasicBlock::iterator I, + unsigned BaseReg, int64_t Offset) const { + MachineInstr &MI = *I; + int Off = Offset; // ARM doesn't need the general 64-bit offsets + unsigned i = 0; + + while (!MI.getOperand(i).isFI()) { + ++i; + assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); + } + bool Done = false; + Done = rewriteFrameIndex(MI, i, BaseReg, Off, TII); + assert (Done && "Unable to resolve frame index!"); +} + +/// saveScavengerRegister - Spill the register so it can be used by the +/// register scavenger. Return true. +bool +Thumb1RegisterInfo::saveScavengerRegister(MachineBasicBlock &MBB, + MachineBasicBlock::iterator I, + MachineBasicBlock::iterator &UseMI, + const TargetRegisterClass *RC, + unsigned Reg) const { + // Thumb1 can't use the emergency spill slot on the stack because + // ldr/str immediate offsets must be positive, and if we're referencing + // off the frame pointer (if, for example, there are alloca() calls in + // the function, the offset will be negative. Use R12 instead since that's + // a call clobbered register that we know won't be used in Thumb1 mode. + DebugLoc DL; + BuildMI(MBB, I, DL, TII.get(ARM::tMOVtgpr2gpr)). + addReg(ARM::R12, RegState::Define).addReg(Reg, RegState::Kill); + + // The UseMI is where we would like to restore the register. If there's + // interference with R12 before then, however, we'll need to restore it + // before that instead and adjust the UseMI. + bool done = false; + for (MachineBasicBlock::iterator II = I; !done && II != UseMI ; ++II) { + if (II->isDebugValue()) + continue; + // If this instruction affects R12, adjust our restore point. + for (unsigned i = 0, e = II->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = II->getOperand(i); + if (!MO.isReg() || MO.isUndef() || !MO.getReg() || + TargetRegisterInfo::isVirtualRegister(MO.getReg())) + continue; + if (MO.getReg() == ARM::R12) { + UseMI = II; + done = true; + break; + } + } + } + // Restore the register from R12 + BuildMI(MBB, UseMI, DL, TII.get(ARM::tMOVgpr2tgpr)). + addReg(Reg, RegState::Define).addReg(ARM::R12, RegState::Kill); + + return true; +} + +void +Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS) const { + unsigned VReg = 0; + unsigned i = 0; + MachineInstr &MI = *II; + MachineBasicBlock &MBB = *MI.getParent(); + MachineFunction &MF = *MBB.getParent(); + ARMFunctionInfo *AFI = MF.getInfo(); + DebugLoc dl = MI.getDebugLoc(); + + while (!MI.getOperand(i).isFI()) { + ++i; + assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!"); + } + + unsigned FrameReg = ARM::SP; + int FrameIndex = MI.getOperand(i).getIndex(); + int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) + + MF.getFrameInfo()->getStackSize() + SPAdj; + + if (AFI->isGPRCalleeSavedArea1Frame(FrameIndex)) + Offset -= AFI->getGPRCalleeSavedArea1Offset(); + else if (AFI->isGPRCalleeSavedArea2Frame(FrameIndex)) + Offset -= AFI->getGPRCalleeSavedArea2Offset(); + else if (MF.getFrameInfo()->hasVarSizedObjects()) { + assert(SPAdj == 0 && hasFP(MF) && "Unexpected"); + // There are alloca()'s in this function, must reference off the frame + // pointer or base pointer instead. + if (!hasBasePointer(MF)) { + FrameReg = getFrameRegister(MF); + Offset -= AFI->getFramePtrSpillOffset(); + } else + FrameReg = BasePtr; + } + + // Special handling of dbg_value instructions. + if (MI.isDebugValue()) { + MI.getOperand(i). ChangeToRegister(FrameReg, false /*isDef*/); + MI.getOperand(i+1).ChangeToImmediate(Offset); + return; + } + + // Modify MI as necessary to handle as much of 'Offset' as possible + assert(AFI->isThumbFunction() && + "This eliminateFrameIndex only supports Thumb1!"); + if (rewriteFrameIndex(MI, i, FrameReg, Offset, TII)) + return; // If we get here, the immediate doesn't fit into the instruction. We folded // as much as possible above, handle the rest, providing a register that is // SP+LargeImm. assert(Offset && "This code isn't needed if offset already handled!"); + unsigned Opcode = MI.getOpcode(); + const TargetInstrDesc &Desc = MI.getDesc(); + // Remove predicate first. int PIdx = MI.findFirstPredOperandIdx(); if (PIdx != -1) @@ -637,11 +664,7 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, MI.addOperand(MachineOperand::CreateReg(0, false)); } else if (Desc.mayStore()) { VReg = MF.getRegInfo().createVirtualRegister(ARM::tGPRRegisterClass); - assert (Value && "Frame index virtual allocated, but Value arg is NULL!"); bool UseRR = false; - bool TrackVReg = true; - Value->first = FrameReg; // use the frame register as a kind indicator - Value->second = Offset; if (Opcode == ARM::tSpill) { if (FrameReg == ARM::SP) @@ -650,7 +673,6 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, else { emitLoadConstPool(MBB, II, dl, VReg, 0, Offset); UseRR = true; - TrackVReg = false; } } else emitThumbRegPlusImmediate(MBB, II, VReg, FrameReg, Offset, TII, @@ -661,8 +683,6 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, MI.addOperand(MachineOperand::CreateReg(FrameReg, false)); else // tSTR has an extra register operand. MI.addOperand(MachineOperand::CreateReg(0, false)); - if (!ReuseFrameIndexVals || !TrackVReg) - VReg = 0; } else assert(false && "Unexpected opcode!"); @@ -671,7 +691,6 @@ Thumb1RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, MachineInstrBuilder MIB(&MI); AddDefaultPred(MIB); } - return VReg; } void Thumb1RegisterInfo::emitPrologue(MachineFunction &MF) const { @@ -742,11 +761,11 @@ void Thumb1RegisterInfo::emitPrologue(MachineFunction &MF) const { dl = MBBI->getDebugLoc(); } - // Darwin ABI requires FP to point to the stack slot that contains the - // previous FP. - if (STI.isTargetDarwin() || hasFP(MF)) { + // Adjust FP so it point to the stack slot that contains the previous FP. + if (hasFP(MF)) { BuildMI(MBB, MBBI, dl, TII.get(ARM::tADDrSPi), FramePtr) .addFrameIndex(FramePtrSpillFI).addImm(0); + AFI->setShouldRestoreSPFromFP(true); } // Determine starting offsets of spill areas. @@ -764,14 +783,20 @@ void Thumb1RegisterInfo::emitPrologue(MachineFunction &MF) const { emitSPUpdate(MBB, MBBI, TII, dl, *this, -NumBytes); } - if (STI.isTargetELF() && hasFP(MF)) { + if (STI.isTargetELF() && hasFP(MF)) MFI->setOffsetAdjustment(MFI->getOffsetAdjustment() - AFI->getFramePtrSpillOffset()); - } AFI->setGPRCalleeSavedArea1Size(GPRCS1Size); AFI->setGPRCalleeSavedArea2Size(GPRCS2Size); AFI->setDPRCalleeSavedAreaSize(DPRCSSize); + + // If we need a base pointer, set it up here. It's whatever the value + // of the stack pointer is at this point. Any variable size objects + // will be allocated after this, so we can still use the base pointer + // to reference locals. + if (hasBasePointer(MF)) + BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr), BasePtr).addReg(ARM::SP); } static bool isCalleeSavedRegister(unsigned Reg, const unsigned *CSRegs) { @@ -828,7 +853,7 @@ void Thumb1RegisterInfo::emitEpilogue(MachineFunction &MF, AFI->getGPRCalleeSavedArea2Size() + AFI->getDPRCalleeSavedAreaSize()); - if (hasFP(MF)) { + if (AFI->shouldRestoreSPFromFP()) { NumBytes = AFI->getFramePtrSpillOffset() - NumBytes; // Reset SP based on frame pointer only if the stack frame extends beyond // frame pointer stack slot or target is ELF and the function has FP. diff --git a/lib/Target/ARM/Thumb1RegisterInfo.h b/lib/Target/ARM/Thumb1RegisterInfo.h index 9a0308af..c578054 100644 --- a/lib/Target/ARM/Thumb1RegisterInfo.h +++ b/lib/Target/ARM/Thumb1RegisterInfo.h @@ -38,27 +38,27 @@ public: unsigned PredReg = 0) const; /// Code Generation virtual methods... - bool hasReservedCallFrame(MachineFunction &MF) const; + bool hasReservedCallFrame(const MachineFunction &MF) const; void eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; - // rewrite MI to access 'Offset' bytes from the FP. Return the offset that - // could not be handled directly in MI. - int rewriteFrameIndex(MachineInstr &MI, unsigned FrameRegIdx, - unsigned FrameReg, int Offset, - unsigned MOVOpc, unsigned ADDriOpc, - unsigned SUBriOpc) const; - + // rewrite MI to access 'Offset' bytes from the FP. Update Offset to be + // however much remains to be handled. Return 'true' if no further + // work is required. + bool rewriteFrameIndex(MachineBasicBlock::iterator II, unsigned FrameRegIdx, + unsigned FrameReg, int &Offset, + const ARMBaseInstrInfo &TII) const; + void resolveFrameIndex(MachineBasicBlock::iterator I, + unsigned BaseReg, int64_t Offset) const; bool saveScavengerRegister(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, MachineBasicBlock::iterator &UseMI, const TargetRegisterClass *RC, unsigned Reg) const; - unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value = NULL, - RegScavenger *RS = NULL) const; + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; void emitPrologue(MachineFunction &MF) const; void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; diff --git a/lib/Target/ARM/Thumb2ITBlockPass.cpp b/lib/Target/ARM/Thumb2ITBlockPass.cpp index cd15bbe..45e6937 100644 --- a/lib/Target/ARM/Thumb2ITBlockPass.cpp +++ b/lib/Target/ARM/Thumb2ITBlockPass.cpp @@ -27,7 +27,7 @@ namespace { public: static char ID; - Thumb2ITBlockPass() : MachineFunctionPass(&ID) {} + Thumb2ITBlockPass() : MachineFunctionPass(ID) {} const Thumb2InstrInfo *TII; const TargetRegisterInfo *TRI; @@ -91,35 +91,53 @@ static void TrackDefUses(MachineInstr *MI, } } +static bool isCopy(MachineInstr *MI) { + switch (MI->getOpcode()) { + default: + return false; + case ARM::MOVr: + case ARM::MOVr_TC: + case ARM::tMOVr: + case ARM::tMOVgpr2tgpr: + case ARM::tMOVtgpr2gpr: + case ARM::tMOVgpr2gpr: + case ARM::t2MOVr: + return true; + } +} + bool Thumb2ITBlockPass::MoveCopyOutOfITBlock(MachineInstr *MI, ARMCC::CondCodes CC, ARMCC::CondCodes OCC, SmallSet &Defs, SmallSet &Uses) { - unsigned SrcReg, DstReg, SrcSubIdx, DstSubIdx; - if (TII->isMoveInstr(*MI, SrcReg, DstReg, SrcSubIdx, DstSubIdx)) { - assert(SrcSubIdx == 0 && DstSubIdx == 0 && - "Sub-register indices still around?"); - // llvm models select's as two-address instructions. That means a copy - // is inserted before a t2MOVccr, etc. If the copy is scheduled in - // between selects we would end up creating multiple IT blocks. - - // First check if it's safe to move it. - if (Uses.count(DstReg) || Defs.count(SrcReg)) - return false; - - // Then peek at the next instruction to see if it's predicated on CC or OCC. - // If not, then there is nothing to be gained by moving the copy. - MachineBasicBlock::iterator I = MI; ++I; - MachineBasicBlock::iterator E = MI->getParent()->end(); - while (I != E && I->isDebugValue()) - ++I; - if (I != E) { - unsigned NPredReg = 0; - ARMCC::CondCodes NCC = llvm::getITInstrPredicate(I, NPredReg); - if (NCC == CC || NCC == OCC) - return true; - } + if (!isCopy(MI)) + return false; + // llvm models select's as two-address instructions. That means a copy + // is inserted before a t2MOVccr, etc. If the copy is scheduled in + // between selects we would end up creating multiple IT blocks. + assert(MI->getOperand(0).getSubReg() == 0 && + MI->getOperand(1).getSubReg() == 0 && + "Sub-register indices still around?"); + + unsigned DstReg = MI->getOperand(0).getReg(); + unsigned SrcReg = MI->getOperand(1).getReg(); + + // First check if it's safe to move it. + if (Uses.count(DstReg) || Defs.count(SrcReg)) + return false; + + // Then peek at the next instruction to see if it's predicated on CC or OCC. + // If not, then there is nothing to be gained by moving the copy. + MachineBasicBlock::iterator I = MI; ++I; + MachineBasicBlock::iterator E = MI->getParent()->end(); + while (I != E && I->isDebugValue()) + ++I; + if (I != E) { + unsigned NPredReg = 0; + ARMCC::CondCodes NCC = llvm::getITInstrPredicate(I, NPredReg); + if (NCC == CC || NCC == OCC) + return true; } return false; } diff --git a/lib/Target/ARM/Thumb2InstrInfo.cpp b/lib/Target/ARM/Thumb2InstrInfo.cpp index ee51727..442f41d 100644 --- a/lib/Target/ARM/Thumb2InstrInfo.cpp +++ b/lib/Target/ARM/Thumb2InstrInfo.cpp @@ -147,8 +147,8 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, unsigned SrcReg, bool isKill, int FI, const TargetRegisterClass *RC, const TargetRegisterInfo *TRI) const { - if (RC == ARM::GPRRegisterClass || RC == ARM::tGPRRegisterClass || - RC == ARM::tcGPRRegisterClass) { + if (RC == ARM::GPRRegisterClass || RC == ARM::tGPRRegisterClass || + RC == ARM::tcGPRRegisterClass || RC == ARM::rGPRRegisterClass) { DebugLoc DL; if (I != MBB.end()) DL = I->getDebugLoc(); @@ -173,8 +173,8 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, unsigned DestReg, int FI, const TargetRegisterClass *RC, const TargetRegisterInfo *TRI) const { - if (RC == ARM::GPRRegisterClass || RC == ARM::tGPRRegisterClass || - RC == ARM::tcGPRRegisterClass) { + if (RC == ARM::GPRRegisterClass || RC == ARM::tGPRRegisterClass || + RC == ARM::tcGPRRegisterClass || RC == ARM::rGPRRegisterClass) { DebugLoc DL; if (I != MBB.end()) DL = I->getDebugLoc(); diff --git a/lib/Target/ARM/Thumb2SizeReduction.cpp b/lib/Target/ARM/Thumb2SizeReduction.cpp index ba392f3..0c3962d 100644 --- a/lib/Target/ARM/Thumb2SizeReduction.cpp +++ b/lib/Target/ARM/Thumb2SizeReduction.cpp @@ -173,7 +173,7 @@ namespace { char Thumb2SizeReduce::ID = 0; } -Thumb2SizeReduce::Thumb2SizeReduce() : MachineFunctionPass(&ID) { +Thumb2SizeReduce::Thumb2SizeReduce() : MachineFunctionPass(ID) { for (unsigned i = 0, e = array_lengthof(ReduceTable); i != e; ++i) { unsigned FromOpc = ReduceTable[i].WideOpc; if (!ReduceOpcodeMap.insert(std::make_pair(FromOpc, i)).second) @@ -315,6 +315,18 @@ Thumb2SizeReduce::ReduceLoadStore(MachineBasicBlock &MBB, MachineInstr *MI, ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MI->getOperand(1).getImm()); if (!isARMLowRegister(BaseReg) || Mode != ARM_AM::ia) return false; + // For the non-writeback version (this one), the base register must be + // one of the registers being loaded. + bool isOK = false; + for (unsigned i = 4; i < MI->getNumOperands(); ++i) { + if (MI->getOperand(i).getReg() == BaseReg) { + isOK = true; + break; + } + } + if (!isOK) + return false; + OpNum = 0; isLdStMul = true; break; diff --git a/lib/Target/Alpha/AlphaBranchSelector.cpp b/lib/Target/Alpha/AlphaBranchSelector.cpp index 001656e..3768117 100644 --- a/lib/Target/Alpha/AlphaBranchSelector.cpp +++ b/lib/Target/Alpha/AlphaBranchSelector.cpp @@ -22,7 +22,7 @@ using namespace llvm; namespace { struct AlphaBSel : public MachineFunctionPass { static char ID; - AlphaBSel() : MachineFunctionPass(&ID) {} + AlphaBSel() : MachineFunctionPass(ID) {} virtual bool runOnMachineFunction(MachineFunction &Fn); diff --git a/lib/Target/Alpha/AlphaCodeEmitter.cpp b/lib/Target/Alpha/AlphaCodeEmitter.cpp index a6c6f52..3aec070 100644 --- a/lib/Target/Alpha/AlphaCodeEmitter.cpp +++ b/lib/Target/Alpha/AlphaCodeEmitter.cpp @@ -34,7 +34,7 @@ namespace { public: static char ID; - AlphaCodeEmitter(JITCodeEmitter &mce) : MachineFunctionPass(&ID), + AlphaCodeEmitter(JITCodeEmitter &mce) : MachineFunctionPass(ID), MCE(mce) {} /// getBinaryCodeForInstr - This function, generated by the diff --git a/lib/Target/Alpha/AlphaISelDAGToDAG.cpp b/lib/Target/Alpha/AlphaISelDAGToDAG.cpp index d526dc0..d197bd1 100644 --- a/lib/Target/Alpha/AlphaISelDAGToDAG.cpp +++ b/lib/Target/Alpha/AlphaISelDAGToDAG.cpp @@ -113,8 +113,8 @@ namespace { static uint64_t getNearPower2(uint64_t x) { if (!x) return 0; unsigned at = CountLeadingZeros_64(x); - uint64_t complow = 1 << (63 - at); - uint64_t comphigh = 1 << (64 - at); + uint64_t complow = 1ULL << (63 - at); + uint64_t comphigh = 1ULL << (64 - at); //cerr << x << ":" << complow << ":" << comphigh << "\n"; if (abs64(complow - x) <= abs64(comphigh - x)) return complow; diff --git a/lib/Target/Alpha/AlphaInstrInfo.cpp b/lib/Target/Alpha/AlphaInstrInfo.cpp index ad625a2..5a2f561 100644 --- a/lib/Target/Alpha/AlphaInstrInfo.cpp +++ b/lib/Target/Alpha/AlphaInstrInfo.cpp @@ -27,32 +27,6 @@ AlphaInstrInfo::AlphaInstrInfo() RI(*this) { } -bool AlphaInstrInfo::isMoveInstr(const MachineInstr& MI, - unsigned& sourceReg, unsigned& destReg, - unsigned& SrcSR, unsigned& DstSR) const { - unsigned oc = MI.getOpcode(); - if (oc == Alpha::BISr || - oc == Alpha::CPYSS || - oc == Alpha::CPYST || - oc == Alpha::CPYSSt || - oc == Alpha::CPYSTs) { - // or r1, r2, r2 - // cpys(s|t) r1 r2 r2 - assert(MI.getNumOperands() >= 3 && - MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - MI.getOperand(2).isReg() && - "invalid Alpha BIS instruction!"); - if (MI.getOperand(1).getReg() == MI.getOperand(2).getReg()) { - sourceReg = MI.getOperand(1).getReg(); - destReg = MI.getOperand(0).getReg(); - SrcSR = DstSR = 0; - return true; - } - } - return false; -} - unsigned AlphaInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const { diff --git a/lib/Target/Alpha/AlphaInstrInfo.h b/lib/Target/Alpha/AlphaInstrInfo.h index e20e832..ee6077a 100644 --- a/lib/Target/Alpha/AlphaInstrInfo.h +++ b/lib/Target/Alpha/AlphaInstrInfo.h @@ -30,12 +30,6 @@ public: /// virtual const AlphaRegisterInfo &getRegisterInfo() const { return RI; } - /// Return true if the instruction is a register to register move and return - /// the source and dest operands and their sub-register indices by reference. - virtual bool isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const; - virtual unsigned isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const; virtual unsigned isStoreToStackSlot(const MachineInstr *MI, diff --git a/lib/Target/Alpha/AlphaLLRP.cpp b/lib/Target/Alpha/AlphaLLRP.cpp index 34be470..85fbfd1 100644 --- a/lib/Target/Alpha/AlphaLLRP.cpp +++ b/lib/Target/Alpha/AlphaLLRP.cpp @@ -39,7 +39,7 @@ namespace { static char ID; AlphaLLRPPass(AlphaTargetMachine &tm) - : MachineFunctionPass(&ID), TM(tm) { } + : MachineFunctionPass(ID), TM(tm) { } virtual const char *getPassName() const { return "Alpha NOP inserter"; diff --git a/lib/Target/Alpha/AlphaRegisterInfo.cpp b/lib/Target/Alpha/AlphaRegisterInfo.cpp index dc9d935..327ddb4 100644 --- a/lib/Target/Alpha/AlphaRegisterInfo.cpp +++ b/lib/Target/Alpha/AlphaRegisterInfo.cpp @@ -137,10 +137,9 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, //variable locals //<- SP -unsigned +void AlphaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value, - RegScavenger *RS) const { + int SPAdj, RegScavenger *RS) const { assert(SPAdj == 0 && "Unexpected"); unsigned i = 0; @@ -185,7 +184,6 @@ AlphaRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, } else { MI.getOperand(i).ChangeToImmediate(Offset); } - return 0; } diff --git a/lib/Target/Alpha/AlphaRegisterInfo.h b/lib/Target/Alpha/AlphaRegisterInfo.h index f9fd87a..b164979 100644 --- a/lib/Target/Alpha/AlphaRegisterInfo.h +++ b/lib/Target/Alpha/AlphaRegisterInfo.h @@ -38,9 +38,8 @@ struct AlphaRegisterInfo : public AlphaGenRegisterInfo { MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; - unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value = NULL, - RegScavenger *RS = NULL) const; + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; //void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; diff --git a/lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp b/lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp index 9f4aff6..5428cb9 100644 --- a/lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp +++ b/lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp @@ -53,8 +53,6 @@ namespace { void printOp(const MachineOperand &MO, raw_ostream &O); void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); - void printBaseOffsetPair(const MachineInstr *MI, int i, raw_ostream &O, - bool brackets=true); virtual void EmitFunctionBodyStart(); virtual void EmitFunctionBodyEnd(); void EmitStartOfAsmFile(Module &M); diff --git a/lib/Target/Blackfin/BlackfinInstrInfo.cpp b/lib/Target/Blackfin/BlackfinInstrInfo.cpp index a74d42d..e50d57a 100644 --- a/lib/Target/Blackfin/BlackfinInstrInfo.cpp +++ b/lib/Target/Blackfin/BlackfinInstrInfo.cpp @@ -28,34 +28,6 @@ BlackfinInstrInfo::BlackfinInstrInfo(BlackfinSubtarget &ST) RI(ST, *this), Subtarget(ST) {} -/// Return true if the instruction is a register to register move and -/// leave the source and dest operands in the passed parameters. -bool BlackfinInstrInfo::isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, - unsigned &DstReg, - unsigned &SrcSR, - unsigned &DstSR) const { - SrcSR = DstSR = 0; // No sub-registers. - switch (MI.getOpcode()) { - case BF::MOVE: - case BF::MOVE_ncccc: - case BF::MOVE_ccncc: - case BF::MOVECC_zext: - case BF::MOVECC_nz: - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(1).getReg(); - return true; - case BF::SLL16i: - if (MI.getOperand(2).getImm()!=0) - return false; - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(1).getReg(); - return true; - default: - return false; - } -} - /// isLoadFromStackSlot - If the specified machine instruction is a direct /// load from a stack slot, return the virtual or physical register number of /// the destination along with the FrameIndex of the loaded stack slot. If diff --git a/lib/Target/Blackfin/BlackfinInstrInfo.h b/lib/Target/Blackfin/BlackfinInstrInfo.h index 6c35917..fdc1029 100644 --- a/lib/Target/Blackfin/BlackfinInstrInfo.h +++ b/lib/Target/Blackfin/BlackfinInstrInfo.h @@ -30,10 +30,6 @@ namespace llvm { /// always be able to get register info as well (through this method). virtual const BlackfinRegisterInfo &getRegisterInfo() const { return RI; } - virtual bool isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const; - virtual unsigned isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const; diff --git a/lib/Target/Blackfin/BlackfinRegisterInfo.cpp b/lib/Target/Blackfin/BlackfinRegisterInfo.cpp index 06e95de..a518312 100644 --- a/lib/Target/Blackfin/BlackfinRegisterInfo.cpp +++ b/lib/Target/Blackfin/BlackfinRegisterInfo.cpp @@ -190,10 +190,9 @@ static unsigned findScratchRegister(MachineBasicBlock::iterator II, return Reg; } -unsigned +void BlackfinRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value, - RegScavenger *RS) const { + int SPAdj, RegScavenger *RS) const { MachineInstr &MI = *II; MachineBasicBlock &MBB = *MI.getParent(); MachineFunction &MF = *MBB.getParent(); @@ -230,20 +229,20 @@ BlackfinRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, MI.setDesc(TII.get(isStore ? BF::STORE32p_uimm6m4 : BF::LOAD32p_uimm6m4)); - return 0; + return; } if (BaseReg == BF::FP && isUInt<7>(-Offset)) { MI.setDesc(TII.get(isStore ? BF::STORE32fp_nimm7m4 : BF::LOAD32fp_nimm7m4)); MI.getOperand(FIPos+1).setImm(-Offset); - return 0; + return; } if (isInt<18>(Offset)) { MI.setDesc(TII.get(isStore ? BF::STORE32p_imm18m4 : BF::LOAD32p_imm18m4)); - return 0; + return; } // Use RegScavenger to calculate proper offset... MI.dump(); @@ -328,7 +327,6 @@ BlackfinRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, llvm_unreachable("Cannot eliminate frame index"); break; } - return 0; } void BlackfinRegisterInfo:: @@ -344,10 +342,6 @@ processFunctionBeforeCalleeSavedScan(MachineFunction &MF, } } -void BlackfinRegisterInfo:: -processFunctionBeforeFrameFinalized(MachineFunction &MF) const { -} - // Emit a prologue that sets up a stack frame. // On function entry, R0-R2 and P0 may hold arguments. // R3, P1, and P2 may be used as scratch registers diff --git a/lib/Target/Blackfin/BlackfinRegisterInfo.h b/lib/Target/Blackfin/BlackfinRegisterInfo.h index ead0b4a..bb83c34 100644 --- a/lib/Target/Blackfin/BlackfinRegisterInfo.h +++ b/lib/Target/Blackfin/BlackfinRegisterInfo.h @@ -51,15 +51,12 @@ namespace llvm { MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; - unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value = NULL, - RegScavenger *RS = NULL) const; + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, RegScavenger *RS) const; - void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; - void emitPrologue(MachineFunction &MF) const; void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; diff --git a/lib/Target/CBackend/CBackend.cpp b/lib/Target/CBackend/CBackend.cpp index e8d8474..270fff6 100644 --- a/lib/Target/CBackend/CBackend.cpp +++ b/lib/Target/CBackend/CBackend.cpp @@ -73,7 +73,7 @@ namespace { public: static char ID; CBackendNameAllUsedStructsAndMergeFunctions() - : ModulePass(&ID) {} + : ModulePass(ID) {} void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); } @@ -110,7 +110,7 @@ namespace { public: static char ID; explicit CWriter(formatted_raw_ostream &o) - : FunctionPass(&ID), Out(o), IL(0), Mang(0), LI(0), + : FunctionPass(ID), Out(o), IL(0), Mang(0), LI(0), TheModule(0), TAsm(0), TCtx(0), TD(0), OpaqueCounter(0), NextAnonValueNumber(0) { FPCounter = 0; @@ -199,7 +199,6 @@ namespace { void lowerIntrinsics(Function &F); - void printModule(Module *M); void printModuleTypes(const TypeSymbolTable &ST); void printContainedStructs(const Type *Ty, std::set &); void printFloatingPointConstants(Function &F); @@ -1300,6 +1299,13 @@ void CWriter::printConstantWithCast(Constant* CPV, unsigned Opcode) { } std::string CWriter::GetValueName(const Value *Operand) { + + // Resolve potential alias. + if (const GlobalAlias *GA = dyn_cast(Operand)) { + if (const Value *V = GA->resolveAliasedGlobal(false)) + Operand = V; + } + // Mangle globals with the standard mangler interface for LLC compatibility. if (const GlobalValue *GV = dyn_cast(Operand)) { SmallString<128> Str; diff --git a/lib/Target/CellSPU/SPUCallingConv.td b/lib/Target/CellSPU/SPUCallingConv.td index ec2f663..04fa2ae 100644 --- a/lib/Target/CellSPU/SPUCallingConv.td +++ b/lib/Target/CellSPU/SPUCallingConv.td @@ -1,4 +1,4 @@ -//===- SPUCallingConv.td - Calling Conventions for CellSPU ------*- C++ -*-===// +//===- SPUCallingConv.td - Calling Conventions for CellSPU -*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -19,16 +19,17 @@ class CCIfSubtarget // Return Value Calling Convention //===----------------------------------------------------------------------===// -// Return-value convention for Cell SPU: Everything can be passed back via $3: +// Return-value convention for Cell SPU: return value to be passed in reg 3-74 def RetCC_SPU : CallingConv<[ - CCIfType<[i8], CCAssignToReg<[R3]>>, - CCIfType<[i16], CCAssignToReg<[R3]>>, - CCIfType<[i32], CCAssignToReg<[R3]>>, - CCIfType<[i64], CCAssignToReg<[R3]>>, - CCIfType<[i128], CCAssignToReg<[R3]>>, - CCIfType<[f32, f64], CCAssignToReg<[R3]>>, - CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], CCAssignToReg<[R3]>>, - CCIfType<[v2i32], CCAssignToReg<[R3]>> + CCIfType<[i8,i16,i32,i64,i128,f32,f64,v16i8,v8i16,v4i32,v2i64,v4f32,v2f64], + CCAssignToReg<[R3, R4, R5, R6, R7, R8, R9, R10, R11, + R12, R13, R14, R15, R16, R17, R18, R19, R20, + R21, R22, R23, R24, R25, R26, R27, R28, R29, + R30, R31, R32, R33, R34, R35, R36, R37, R38, + R39, R40, R41, R42, R43, R44, R45, R46, R47, + R48, R49, R50, R51, R52, R53, R54, R55, R56, + R57, R58, R59, R60, R61, R62, R63, R64, R65, + R66, R67, R68, R69, R70, R71, R72, R73, R74]>> ]>; @@ -45,8 +46,7 @@ def CCC_SPU : CallingConv<[ R39, R40, R41, R42, R43, R44, R45, R46, R47, R48, R49, R50, R51, R52, R53, R54, R55, R56, R57, R58, R59, R60, R61, R62, R63, R64, R65, - R66, R67, R68, R69, R70, R71, R72, R73, R74, - R75, R76, R77, R78, R79]>>, + R66, R67, R68, R69, R70, R71, R72, R73, R74]>>, // Integer/FP values get stored in stack slots that are 8 bytes in size and // 8-byte aligned if there are no more registers to hold them. CCIfType<[i32, i64, f32, f64], CCAssignToStack<8, 8>>, diff --git a/lib/Target/CellSPU/SPUISelDAGToDAG.cpp b/lib/Target/CellSPU/SPUISelDAGToDAG.cpp index 9b8c2dd..2f15984 100644 --- a/lib/Target/CellSPU/SPUISelDAGToDAG.cpp +++ b/lib/Target/CellSPU/SPUISelDAGToDAG.cpp @@ -41,13 +41,6 @@ using namespace llvm; namespace { //! ConstantSDNode predicate for i32 sign-extended, 10-bit immediates bool - isI64IntS10Immediate(ConstantSDNode *CN) - { - return isInt<10>(CN->getSExtValue()); - } - - //! ConstantSDNode predicate for i32 sign-extended, 10-bit immediates - bool isI32IntS10Immediate(ConstantSDNode *CN) { return isInt<10>(CN->getSExtValue()); @@ -67,14 +60,6 @@ namespace { return isInt<10>(CN->getSExtValue()); } - //! SDNode predicate for i16 sign-extended, 10-bit immediate values - bool - isI16IntS10Immediate(SDNode *N) - { - ConstantSDNode *CN = dyn_cast(N); - return (CN != 0 && isI16IntS10Immediate(CN)); - } - //! ConstantSDNode predicate for i16 unsigned 10-bit immediate values bool isI16IntU10Immediate(ConstantSDNode *CN) @@ -82,14 +67,6 @@ namespace { return isUInt<10>((short) CN->getZExtValue()); } - //! SDNode predicate for i16 sign-extended, 10-bit immediate values - bool - isI16IntU10Immediate(SDNode *N) - { - return (N->getOpcode() == ISD::Constant - && isI16IntU10Immediate(cast(N))); - } - //! ConstantSDNode predicate for signed 16-bit values /*! \arg CN The constant SelectionDAG node holding the value @@ -119,14 +96,6 @@ namespace { return false; } - //! SDNode predicate for signed 16-bit values. - bool - isIntS16Immediate(SDNode *N, short &Imm) - { - return (N->getOpcode() == ISD::Constant - && isIntS16Immediate(cast(N), Imm)); - } - //! ConstantFPSDNode predicate for representing floats as 16-bit sign ext. static bool isFPS16Immediate(ConstantFPSDNode *FPN, short &Imm) @@ -142,16 +111,6 @@ namespace { return false; } - bool - isHighLow(const SDValue &Op) - { - return (Op.getOpcode() == SPUISD::IndirectAddr - && ((Op.getOperand(0).getOpcode() == SPUISD::Hi - && Op.getOperand(1).getOpcode() == SPUISD::Lo) - || (Op.getOperand(0).getOpcode() == SPUISD::Lo - && Op.getOperand(1).getOpcode() == SPUISD::Hi))); - } - //===------------------------------------------------------------------===// //! EVT to "useful stuff" mapping structure: @@ -607,7 +566,8 @@ SPUDAGToDAGISel::DFormAddressPredicate(SDNode *Op, SDValue N, SDValue &Base, return true; } else if (Opc == ISD::Register ||Opc == ISD::CopyFromReg - ||Opc == ISD::UNDEF) { + ||Opc == ISD::UNDEF + ||Opc == ISD::Constant) { unsigned OpOpc = Op->getOpcode(); if (OpOpc == ISD::STORE || OpOpc == ISD::LOAD) { diff --git a/lib/Target/CellSPU/SPUISelLowering.cpp b/lib/Target/CellSPU/SPUISelLowering.cpp index ece19b9..46f3189 100644 --- a/lib/Target/CellSPU/SPUISelLowering.cpp +++ b/lib/Target/CellSPU/SPUISelLowering.cpp @@ -426,9 +426,6 @@ SPUTargetLowering::SPUTargetLowering(SPUTargetMachine &TM) addRegisterClass(MVT::v4f32, SPU::VECREGRegisterClass); addRegisterClass(MVT::v2f64, SPU::VECREGRegisterClass); - // "Odd size" vector classes that we're willing to support: - addRegisterClass(MVT::v2i32, SPU::VECREGRegisterClass); - for (unsigned i = (unsigned)MVT::FIRST_VECTOR_VALUETYPE; i <= (unsigned)MVT::LAST_VECTOR_VALUETYPE; ++i) { MVT::SimpleValueType VT = (MVT::SimpleValueType)i; @@ -751,7 +748,6 @@ LowerSTORE(SDValue Op, SelectionDAG &DAG, const SPUSubtarget *ST) { if (alignment == 16) { ConstantSDNode *CN; - // Special cases for a known aligned load to simplify the base pointer // and insertion byte: if (basePtr.getOpcode() == ISD::ADD @@ -775,6 +771,9 @@ LowerSTORE(SDValue Op, SelectionDAG &DAG, const SPUSubtarget *ST) { insertEltOffs = DAG.getNode(SPUISD::IndirectAddr, dl, PtrVT, basePtr, DAG.getConstant(0, PtrVT)); + basePtr = DAG.getNode(SPUISD::IndirectAddr, dl, PtrVT, + basePtr, + DAG.getConstant(0, PtrVT)); } } else { // Unaligned load: must be more pessimistic about addressing modes: @@ -811,8 +810,8 @@ LowerSTORE(SDValue Op, SelectionDAG &DAG, const SPUSubtarget *ST) { DAG.getConstant(0, PtrVT)); } - // Re-emit as a v16i8 vector load - alignLoadVec = DAG.getLoad(MVT::v16i8, dl, the_chain, basePtr, + // Load the memory to which to store. + alignLoadVec = DAG.getLoad(vecVT, dl, the_chain, basePtr, SN->getSrcValue(), SN->getSrcValueOffset(), SN->isVolatile(), SN->isNonTemporal(), 16); @@ -843,10 +842,10 @@ LowerSTORE(SDValue Op, SelectionDAG &DAG, const SPUSubtarget *ST) { } #endif - SDValue insertEltOp = - DAG.getNode(SPUISD::SHUFFLE_MASK, dl, vecVT, insertEltOffs); - SDValue vectorizeOp = - DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, vecVT, theValue); + SDValue insertEltOp = DAG.getNode(SPUISD::SHUFFLE_MASK, dl, vecVT, + insertEltOffs); + SDValue vectorizeOp = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, vecVT, + theValue); result = DAG.getNode(SPUISD::SHUFB, dl, vecVT, vectorizeOp, alignLoadVec, @@ -1325,41 +1324,23 @@ SPUTargetLowering::LowerCall(SDValue Chain, SDValue Callee, if (Ins.empty()) return Chain; + // Now handle the return value(s) + SmallVector RVLocs; + CCState CCRetInfo(CallConv, isVarArg, getTargetMachine(), + RVLocs, *DAG.getContext()); + CCRetInfo.AnalyzeCallResult(Ins, CCC_SPU); + + // If the call has results, copy the values out of the ret val registers. - switch (Ins[0].VT.getSimpleVT().SimpleTy) { - default: llvm_unreachable("Unexpected ret value!"); - case MVT::Other: break; - case MVT::i32: - if (Ins.size() > 1 && Ins[1].VT == MVT::i32) { - Chain = DAG.getCopyFromReg(Chain, dl, SPU::R4, - MVT::i32, InFlag).getValue(1); - InVals.push_back(Chain.getValue(0)); - Chain = DAG.getCopyFromReg(Chain, dl, SPU::R3, MVT::i32, - Chain.getValue(2)).getValue(1); - InVals.push_back(Chain.getValue(0)); - } else { - Chain = DAG.getCopyFromReg(Chain, dl, SPU::R3, MVT::i32, - InFlag).getValue(1); - InVals.push_back(Chain.getValue(0)); - } - break; - case MVT::i8: - case MVT::i16: - case MVT::i64: - case MVT::i128: - case MVT::f32: - case MVT::f64: - case MVT::v2f64: - case MVT::v2i64: - case MVT::v4f32: - case MVT::v4i32: - case MVT::v8i16: - case MVT::v16i8: - Chain = DAG.getCopyFromReg(Chain, dl, SPU::R3, Ins[0].VT, - InFlag).getValue(1); - InVals.push_back(Chain.getValue(0)); - break; - } + for (unsigned i = 0; i != RVLocs.size(); ++i) { + CCValAssign VA = RVLocs[i]; + + SDValue Val = DAG.getCopyFromReg(Chain, dl, VA.getLocReg(), VA.getLocVT(), + InFlag); + Chain = Val.getValue(1); + InFlag = Val.getValue(2); + InVals.push_back(Val); + } return Chain; } @@ -1621,10 +1602,6 @@ LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) { SDValue T = DAG.getConstant(unsigned(SplatBits), VT.getVectorElementType()); return DAG.getNode(ISD::BUILD_VECTOR, dl, VT, T, T, T, T); } - case MVT::v2i32: { - SDValue T = DAG.getConstant(unsigned(SplatBits), VT.getVectorElementType()); - return DAG.getNode(ISD::BUILD_VECTOR, dl, VT, T, T); - } case MVT::v2i64: { return SPU::LowerV2I64Splat(VT, DAG, SplatBits, dl); } @@ -1748,11 +1725,12 @@ static SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) { // If we have a single element being moved from V1 to V2, this can be handled // using the C*[DX] compute mask instructions, but the vector elements have - // to be monotonically increasing with one exception element. + // to be monotonically increasing with one exception element, and the source + // slot of the element to move must be the same as the destination. EVT VecVT = V1.getValueType(); EVT EltVT = VecVT.getVectorElementType(); unsigned EltsFromV2 = 0; - unsigned V2Elt = 0; + unsigned V2EltOffset = 0; unsigned V2EltIdx0 = 0; unsigned CurrElt = 0; unsigned MaxElts = VecVT.getVectorNumElements(); @@ -1785,9 +1763,13 @@ static SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) { if (monotonic) { if (SrcElt >= V2EltIdx0) { - if (1 >= (++EltsFromV2)) { - V2Elt = (V2EltIdx0 - SrcElt) << 2; - } + // TODO: optimize for the monotonic case when several consecutive + // elements are taken form V2. Do we ever get such a case? + if (EltsFromV2 == 0 && CurrElt == (SrcElt - V2EltIdx0)) + V2EltOffset = (SrcElt - V2EltIdx0) * (EltVT.getSizeInBits()/8); + else + monotonic = false; + ++EltsFromV2; } else if (CurrElt != SrcElt) { monotonic = false; } @@ -1823,7 +1805,7 @@ static SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) { // R1 ($sp) is used here only as it is guaranteed to have last bits zero SDValue Pointer = DAG.getNode(SPUISD::IndirectAddr, dl, PtrVT, DAG.getRegister(SPU::R1, PtrVT), - DAG.getConstant(V2Elt, MVT::i32)); + DAG.getConstant(V2EltOffset, MVT::i32)); SDValue ShufMaskOp = DAG.getNode(SPUISD::SHUFFLE_MASK, dl, maskVT, Pointer); @@ -1847,7 +1829,6 @@ static SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) { for (unsigned j = 0; j < BytesPerElement; ++j) ResultMask.push_back(DAG.getConstant(SrcElt*BytesPerElement+j,MVT::i8)); } - SDValue VPermMask = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v16i8, &ResultMask[0], ResultMask.size()); return DAG.getNode(SPUISD::SHUFB, dl, V1.getValueType(), V1, V2, VPermMask); @@ -1997,7 +1978,7 @@ static SDValue LowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) { // Variable index: Rotate the requested element into slot 0, then replicate // slot 0 across the vector EVT VecVT = N.getValueType(); - if (!VecVT.isSimple() || !VecVT.isVector() || !VecVT.is128BitVector()) { + if (!VecVT.isSimple() || !VecVT.isVector()) { report_fatal_error("LowerEXTRACT_VECTOR_ELT: Must have a simple, 128-bit" "vector type!"); } @@ -2072,21 +2053,25 @@ static SDValue LowerINSERT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) { SDValue IdxOp = Op.getOperand(2); DebugLoc dl = Op.getDebugLoc(); EVT VT = Op.getValueType(); + EVT eltVT = ValOp.getValueType(); // use 0 when the lane to insert to is 'undef' - int64_t Idx=0; + int64_t Offset=0; if (IdxOp.getOpcode() != ISD::UNDEF) { ConstantSDNode *CN = cast(IdxOp); assert(CN != 0 && "LowerINSERT_VECTOR_ELT: Index is not constant!"); - Idx = (CN->getSExtValue()); + Offset = (CN->getSExtValue()) * eltVT.getSizeInBits()/8; } EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(); // Use $sp ($1) because it's always 16-byte aligned and it's available: SDValue Pointer = DAG.getNode(SPUISD::IndirectAddr, dl, PtrVT, DAG.getRegister(SPU::R1, PtrVT), - DAG.getConstant(Idx, PtrVT)); - SDValue ShufMask = DAG.getNode(SPUISD::SHUFFLE_MASK, dl, VT, Pointer); + DAG.getConstant(Offset, PtrVT)); + // widen the mask when dealing with half vectors + EVT maskVT = EVT::getVectorVT(*(DAG.getContext()), VT.getVectorElementType(), + 128/ VT.getVectorElementType().getSizeInBits()); + SDValue ShufMask = DAG.getNode(SPUISD::SHUFFLE_MASK, dl, maskVT, Pointer); SDValue result = DAG.getNode(SPUISD::SHUFB, dl, VT, diff --git a/lib/Target/CellSPU/SPUInstrInfo.cpp b/lib/Target/CellSPU/SPUInstrInfo.cpp index 69aa088..26d6b4f 100644 --- a/lib/Target/CellSPU/SPUInstrInfo.cpp +++ b/lib/Target/CellSPU/SPUInstrInfo.cpp @@ -54,148 +54,6 @@ SPUInstrInfo::SPUInstrInfo(SPUTargetMachine &tm) RI(*TM.getSubtargetImpl(), *this) { /* NOP */ } -bool -SPUInstrInfo::isMoveInstr(const MachineInstr& MI, - unsigned& sourceReg, - unsigned& destReg, - unsigned& SrcSR, unsigned& DstSR) const { - SrcSR = DstSR = 0; // No sub-registers. - - switch (MI.getOpcode()) { - default: - break; - case SPU::ORIv4i32: - case SPU::ORIr32: - case SPU::ORHIv8i16: - case SPU::ORHIr16: - case SPU::ORHIi8i16: - case SPU::ORBIv16i8: - case SPU::ORBIr8: - case SPU::ORIi16i32: - case SPU::ORIi8i32: - case SPU::AHIvec: - case SPU::AHIr16: - case SPU::AIv4i32: - assert(MI.getNumOperands() == 3 && - MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - MI.getOperand(2).isImm() && - "invalid SPU ORI/ORHI/ORBI/AHI/AI/SFI/SFHI instruction!"); - if (MI.getOperand(2).getImm() == 0) { - sourceReg = MI.getOperand(1).getReg(); - destReg = MI.getOperand(0).getReg(); - return true; - } - break; - case SPU::AIr32: - assert(MI.getNumOperands() == 3 && - "wrong number of operands to AIr32"); - if (MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - (MI.getOperand(2).isImm() && - MI.getOperand(2).getImm() == 0)) { - sourceReg = MI.getOperand(1).getReg(); - destReg = MI.getOperand(0).getReg(); - return true; - } - break; - case SPU::LRr8: - case SPU::LRr16: - case SPU::LRr32: - case SPU::LRf32: - case SPU::LRr64: - case SPU::LRf64: - case SPU::LRr128: - case SPU::LRv16i8: - case SPU::LRv8i16: - case SPU::LRv4i32: - case SPU::LRv4f32: - case SPU::LRv2i64: - case SPU::LRv2f64: - case SPU::ORv16i8_i8: - case SPU::ORv8i16_i16: - case SPU::ORv4i32_i32: - case SPU::ORv2i64_i64: - case SPU::ORv4f32_f32: - case SPU::ORv2f64_f64: - case SPU::ORi8_v16i8: - case SPU::ORi16_v8i16: - case SPU::ORi32_v4i32: - case SPU::ORi64_v2i64: - case SPU::ORf32_v4f32: - case SPU::ORf64_v2f64: -/* - case SPU::ORi128_r64: - case SPU::ORi128_f64: - case SPU::ORi128_r32: - case SPU::ORi128_f32: - case SPU::ORi128_r16: - case SPU::ORi128_r8: -*/ - case SPU::ORi128_vec: -/* - case SPU::ORr64_i128: - case SPU::ORf64_i128: - case SPU::ORr32_i128: - case SPU::ORf32_i128: - case SPU::ORr16_i128: - case SPU::ORr8_i128: -*/ - case SPU::ORvec_i128: -/* - case SPU::ORr16_r32: - case SPU::ORr8_r32: - case SPU::ORf32_r32: - case SPU::ORr32_f32: - case SPU::ORr32_r16: - case SPU::ORr32_r8: - case SPU::ORr16_r64: - case SPU::ORr8_r64: - case SPU::ORr64_r16: - case SPU::ORr64_r8: -*/ - case SPU::ORr64_r32: - case SPU::ORr32_r64: - case SPU::ORf32_r32: - case SPU::ORr32_f32: - case SPU::ORf64_r64: - case SPU::ORr64_f64: { - assert(MI.getNumOperands() == 2 && - MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - "invalid SPU OR_ or LR instruction!"); - sourceReg = MI.getOperand(1).getReg(); - destReg = MI.getOperand(0).getReg(); - return true; - break; - } - case SPU::ORv16i8: - case SPU::ORv8i16: - case SPU::ORv4i32: - case SPU::ORv2i64: - case SPU::ORr8: - case SPU::ORr16: - case SPU::ORr32: - case SPU::ORr64: - case SPU::ORr128: - case SPU::ORf32: - case SPU::ORf64: - assert(MI.getNumOperands() == 3 && - MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - MI.getOperand(2).isReg() && - "invalid SPU OR(vec|r32|r64|gprc) instruction!"); - if (MI.getOperand(1).getReg() == MI.getOperand(2).getReg()) { - sourceReg = MI.getOperand(1).getReg(); - destReg = MI.getOperand(0).getReg(); - return true; - } - break; - } - - return false; -} - unsigned SPUInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const { diff --git a/lib/Target/CellSPU/SPUInstrInfo.h b/lib/Target/CellSPU/SPUInstrInfo.h index fbb1733..191e55d 100644 --- a/lib/Target/CellSPU/SPUInstrInfo.h +++ b/lib/Target/CellSPU/SPUInstrInfo.h @@ -32,12 +32,6 @@ namespace llvm { /// virtual const SPURegisterInfo &getRegisterInfo() const { return RI; } - /// Return true if the instruction is a register to register move and return - /// the source and dest operands and their sub-register indices by reference. - virtual bool isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const; - unsigned isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const; unsigned isStoreToStackSlot(const MachineInstr *MI, diff --git a/lib/Target/CellSPU/SPUInstrInfo.td b/lib/Target/CellSPU/SPUInstrInfo.td index a7fb14c..ca0fe00 100644 --- a/lib/Target/CellSPU/SPUInstrInfo.td +++ b/lib/Target/CellSPU/SPUInstrInfo.td @@ -62,8 +62,6 @@ let canFoldAsLoad = 1 in { def v4f32: LoadDFormVec; def v2f64: LoadDFormVec; - def v2i32: LoadDFormVec; - def r128: LoadDForm; def r64: LoadDForm; def r32: LoadDForm; @@ -96,8 +94,6 @@ let canFoldAsLoad = 1 in { def v4f32: LoadAFormVec; def v2f64: LoadAFormVec; - def v2i32: LoadAFormVec; - def r128: LoadAForm; def r64: LoadAForm; def r32: LoadAForm; @@ -130,8 +126,6 @@ let canFoldAsLoad = 1 in { def v4f32: LoadXFormVec; def v2f64: LoadXFormVec; - def v2i32: LoadXFormVec; - def r128: LoadXForm; def r64: LoadXForm; def r32: LoadXForm; @@ -180,8 +174,6 @@ multiclass StoreDForms def v4f32: StoreDFormVec; def v2f64: StoreDFormVec; - def v2i32: StoreDFormVec; - def r128: StoreDForm; def r64: StoreDForm; def r32: StoreDForm; @@ -212,8 +204,6 @@ multiclass StoreAForms def v4f32: StoreAFormVec; def v2f64: StoreAFormVec; - def v2i32: StoreAFormVec; - def r128: StoreAForm; def r64: StoreAForm; def r32: StoreAForm; @@ -246,8 +236,6 @@ multiclass StoreXForms def v4f32: StoreXFormVec; def v2f64: StoreXFormVec; - def v2i32: StoreXFormVec; - def r128: StoreXForm; def r64: StoreXForm; def r32: StoreXForm; @@ -607,7 +595,6 @@ class ARegInst: multiclass AddInstruction { def v4i32: AVecInst; def v16i8: AVecInst; - def r32: ARegInst; } @@ -672,6 +659,7 @@ def SFvec : RRForm<0b00000010000, (outs VECREG:$rT), "sf\t$rT, $rA, $rB", IntegerOp, [(set (v4i32 VECREG:$rT), (sub (v4i32 VECREG:$rB), (v4i32 VECREG:$rA)))]>; + def SFr32 : RRForm<0b00000010000, (outs R32C:$rT), (ins R32C:$rA, R32C:$rB), "sf\t$rT, $rA, $rB", IntegerOp, [(set R32C:$rT, (sub R32C:$rB, R32C:$rA))]>; @@ -1448,6 +1436,9 @@ class ORCvtGPRCVec: class ORCvtVecGPRC: ORCvtForm<(outs GPRC:$rT), (ins VECREG:$rA)>; +class ORCvtVecVec: + ORCvtForm<(outs VECREG:$rT), (ins VECREG:$rA)>; + multiclass BitwiseOr { def v16i8: ORVecInst; @@ -3894,6 +3885,79 @@ multiclass SFPSub defm FS : SFPSub; +class FMInst pattern>: + RRForm<0b01100011010, OOL, IOL, + "fm\t$rT, $rA, $rB", SPrecFP, + pattern>; + +class FMVecInst: + FMInst<(outs VECREG:$rT), (ins VECREG:$rA, VECREG:$rB), + [(set (type VECREG:$rT), + (fmul (type VECREG:$rA), (type VECREG:$rB)))]>; + +multiclass SFPMul +{ + def v4f32: FMVecInst; + def f32: FMInst<(outs R32FP:$rT), (ins R32FP:$rA, R32FP:$rB), + [(set R32FP:$rT, (fmul R32FP:$rA, R32FP:$rB))]>; +} + +defm FM : SFPMul; + +// Floating point multiply and add +// e.g. d = c + (a * b) +def FMAv4f32: + RRRForm<0b0111, (outs VECREG:$rT), (ins VECREG:$rA, VECREG:$rB, VECREG:$rC), + "fma\t$rT, $rA, $rB, $rC", SPrecFP, + [(set (v4f32 VECREG:$rT), + (fadd (v4f32 VECREG:$rC), + (fmul (v4f32 VECREG:$rA), (v4f32 VECREG:$rB))))]>; + +def FMAf32: + RRRForm<0b0111, (outs R32FP:$rT), (ins R32FP:$rA, R32FP:$rB, R32FP:$rC), + "fma\t$rT, $rA, $rB, $rC", SPrecFP, + [(set R32FP:$rT, (fadd R32FP:$rC, (fmul R32FP:$rA, R32FP:$rB)))]>; + +// FP multiply and subtract +// Subtracts value in rC from product +// res = a * b - c +def FMSv4f32 : + RRRForm<0b0111, (outs VECREG:$rT), (ins VECREG:$rA, VECREG:$rB, VECREG:$rC), + "fms\t$rT, $rA, $rB, $rC", SPrecFP, + [(set (v4f32 VECREG:$rT), + (fsub (fmul (v4f32 VECREG:$rA), (v4f32 VECREG:$rB)), + (v4f32 VECREG:$rC)))]>; + +def FMSf32 : + RRRForm<0b0111, (outs R32FP:$rT), (ins R32FP:$rA, R32FP:$rB, R32FP:$rC), + "fms\t$rT, $rA, $rB, $rC", SPrecFP, + [(set R32FP:$rT, + (fsub (fmul R32FP:$rA, R32FP:$rB), R32FP:$rC))]>; + +// Floating Negative Mulitply and Subtract +// Subtracts product from value in rC +// res = fneg(fms a b c) +// = - (a * b - c) +// = c - a * b +// NOTE: subtraction order +// fsub a b = a - b +// fs a b = b - a? +def FNMSf32 : + RRRForm<0b1101, (outs R32FP:$rT), (ins R32FP:$rA, R32FP:$rB, R32FP:$rC), + "fnms\t$rT, $rA, $rB, $rC", SPrecFP, + [(set R32FP:$rT, (fsub R32FP:$rC, (fmul R32FP:$rA, R32FP:$rB)))]>; + +def FNMSv4f32 : + RRRForm<0b1101, (outs VECREG:$rT), (ins VECREG:$rA, VECREG:$rB, VECREG:$rC), + "fnms\t$rT, $rA, $rB, $rC", SPrecFP, + [(set (v4f32 VECREG:$rT), + (fsub (v4f32 VECREG:$rC), + (fmul (v4f32 VECREG:$rA), + (v4f32 VECREG:$rB))))]>; + + + + // Floating point reciprocal estimate class FRESTInst: @@ -4019,72 +4083,6 @@ def FSCRRf32 : // status and control register read //-------------------------------------- -// Floating point multiply instructions -//-------------------------------------- - -def FMv4f32: - RRForm<0b00100011010, (outs VECREG:$rT), (ins VECREG:$rA, VECREG:$rB), - "fm\t$rT, $rA, $rB", SPrecFP, - [(set (v4f32 VECREG:$rT), (fmul (v4f32 VECREG:$rA), - (v4f32 VECREG:$rB)))]>; - -def FMf32 : - RRForm<0b01100011010, (outs R32FP:$rT), (ins R32FP:$rA, R32FP:$rB), - "fm\t$rT, $rA, $rB", SPrecFP, - [(set R32FP:$rT, (fmul R32FP:$rA, R32FP:$rB))]>; - -// Floating point multiply and add -// e.g. d = c + (a * b) -def FMAv4f32: - RRRForm<0b0111, (outs VECREG:$rT), (ins VECREG:$rA, VECREG:$rB, VECREG:$rC), - "fma\t$rT, $rA, $rB, $rC", SPrecFP, - [(set (v4f32 VECREG:$rT), - (fadd (v4f32 VECREG:$rC), - (fmul (v4f32 VECREG:$rA), (v4f32 VECREG:$rB))))]>; - -def FMAf32: - RRRForm<0b0111, (outs R32FP:$rT), (ins R32FP:$rA, R32FP:$rB, R32FP:$rC), - "fma\t$rT, $rA, $rB, $rC", SPrecFP, - [(set R32FP:$rT, (fadd R32FP:$rC, (fmul R32FP:$rA, R32FP:$rB)))]>; - -// FP multiply and subtract -// Subtracts value in rC from product -// res = a * b - c -def FMSv4f32 : - RRRForm<0b0111, (outs VECREG:$rT), (ins VECREG:$rA, VECREG:$rB, VECREG:$rC), - "fms\t$rT, $rA, $rB, $rC", SPrecFP, - [(set (v4f32 VECREG:$rT), - (fsub (fmul (v4f32 VECREG:$rA), (v4f32 VECREG:$rB)), - (v4f32 VECREG:$rC)))]>; - -def FMSf32 : - RRRForm<0b0111, (outs R32FP:$rT), (ins R32FP:$rA, R32FP:$rB, R32FP:$rC), - "fms\t$rT, $rA, $rB, $rC", SPrecFP, - [(set R32FP:$rT, - (fsub (fmul R32FP:$rA, R32FP:$rB), R32FP:$rC))]>; - -// Floating Negative Mulitply and Subtract -// Subtracts product from value in rC -// res = fneg(fms a b c) -// = - (a * b - c) -// = c - a * b -// NOTE: subtraction order -// fsub a b = a - b -// fs a b = b - a? -def FNMSf32 : - RRRForm<0b1101, (outs R32FP:$rT), (ins R32FP:$rA, R32FP:$rB, R32FP:$rC), - "fnms\t$rT, $rA, $rB, $rC", SPrecFP, - [(set R32FP:$rT, (fsub R32FP:$rC, (fmul R32FP:$rA, R32FP:$rB)))]>; - -def FNMSv4f32 : - RRRForm<0b1101, (outs VECREG:$rT), (ins VECREG:$rA, VECREG:$rB, VECREG:$rC), - "fnms\t$rT, $rA, $rB, $rC", SPrecFP, - [(set (v4f32 VECREG:$rT), - (fsub (v4f32 VECREG:$rC), - (fmul (v4f32 VECREG:$rA), - (v4f32 VECREG:$rB))))]>; - -//-------------------------------------- // Floating Point Conversions // Signed conversions: def CSiFv4f32: diff --git a/lib/Target/CellSPU/SPUOperands.td b/lib/Target/CellSPU/SPUOperands.td index 6216651..e1a0358 100644 --- a/lib/Target/CellSPU/SPUOperands.td +++ b/lib/Target/CellSPU/SPUOperands.td @@ -98,12 +98,6 @@ def immU8 : PatLeaf<(imm), [{ return (N->getZExtValue() <= 0xff); }]>; -// i64ImmSExt10 predicate - True if the i64 immediate fits in a 10-bit sign -// extended field. Used by RI10Form instructions like 'ldq'. -def i64ImmSExt10 : PatLeaf<(imm), [{ - return isI64IntS10Immediate(N); -}]>; - // i32ImmSExt10 predicate - True if the i32 immediate fits in a 10-bit sign // extended field. Used by RI10Form instructions like 'ldq'. def i32ImmSExt10 : PatLeaf<(imm), [{ diff --git a/lib/Target/CellSPU/SPURegisterInfo.cpp b/lib/Target/CellSPU/SPURegisterInfo.cpp index f7cfa42..cf71891 100644 --- a/lib/Target/CellSPU/SPURegisterInfo.cpp +++ b/lib/Target/CellSPU/SPURegisterInfo.cpp @@ -270,9 +270,8 @@ SPURegisterInfo::eliminateCallFramePseudoInstr(MachineFunction &MF, MBB.erase(I); } -unsigned +void SPURegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, - FrameIndexValue *Value, RegScavenger *RS) const { unsigned i = 0; @@ -328,7 +327,6 @@ SPURegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, } else { MO.ChangeToImmediate(Offset); } - return 0; } /// determineFrameLayout - Determine the size of the frame and maximum call @@ -417,7 +415,7 @@ void SPURegisterInfo::emitPrologue(MachineFunction &MF) const if (hasDebugInfo) { // Mark effective beginning of when frame pointer becomes valid. FrameLabel = MMI.getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, dl, TII.get(SPU::DBG_LABEL)).addSym(FrameLabel); + BuildMI(MBB, MBBI, dl, TII.get(SPU::PROLOG_LABEL)).addSym(FrameLabel); } // Adjust stack pointer, spilling $lr -> 16($sp) and $sp -> -FrameSize($sp) @@ -476,7 +474,7 @@ void SPURegisterInfo::emitPrologue(MachineFunction &MF) const // Mark effective beginning of when frame pointer is ready. MCSymbol *ReadyLabel = MMI.getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, dl, TII.get(SPU::DBG_LABEL)).addSym(ReadyLabel); + BuildMI(MBB, MBBI, dl, TII.get(SPU::PROLOG_LABEL)).addSym(ReadyLabel); MachineLocation FPDst(SPU::R1); MachineLocation FPSrc(MachineLocation::VirtualFP); @@ -491,7 +489,7 @@ void SPURegisterInfo::emitPrologue(MachineFunction &MF) const dl = MBBI->getDebugLoc(); // Insert terminator label - BuildMI(MBB, MBBI, dl, TII.get(SPU::DBG_LABEL)) + BuildMI(MBB, MBBI, dl, TII.get(SPU::PROLOG_LABEL)) .addSym(MMI.getContext().CreateTempSymbol()); } } @@ -587,6 +585,7 @@ SPURegisterInfo::convertDFormToXForm(int dFormOpcode) const case SPU::LQDr32: return SPU::LQXr32; case SPU::LQDr128: return SPU::LQXr128; case SPU::LQDv16i8: return SPU::LQXv16i8; + case SPU::LQDv4i32: return SPU::LQXv4i32; case SPU::LQDv4f32: return SPU::LQXv4f32; case SPU::STQDr32: return SPU::STQXr32; case SPU::STQDr128: return SPU::STQXr128; diff --git a/lib/Target/CellSPU/SPURegisterInfo.h b/lib/Target/CellSPU/SPURegisterInfo.h index 7a6ae6d..aedb769 100644 --- a/lib/Target/CellSPU/SPURegisterInfo.h +++ b/lib/Target/CellSPU/SPURegisterInfo.h @@ -63,9 +63,8 @@ namespace llvm { MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; //! Convert frame indicies into machine operands - unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, - FrameIndexValue *Value = NULL, - RegScavenger *RS = NULL) const; + void eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, + RegScavenger *RS = NULL) const; //! Determine the frame's layour void determineFrameLayout(MachineFunction &MF) const; diff --git a/lib/Target/CellSPU/SPURegisterInfo.td b/lib/Target/CellSPU/SPURegisterInfo.td index bb88f2b..3e8f097 100644 --- a/lib/Target/CellSPU/SPURegisterInfo.td +++ b/lib/Target/CellSPU/SPURegisterInfo.td @@ -394,7 +394,7 @@ def R8C : RegisterClass<"SPU", [i8], 128, // The SPU's registers as vector registers: def VECREG : RegisterClass<"SPU", - [v16i8,v8i16,v2i32,v4i32,v4f32,v2i64,v2f64], + [v16i8,v8i16,v4i32,v4f32,v2i64,v2f64], 128, [ /* volatile register */ diff --git a/lib/Target/CppBackend/CPPBackend.cpp b/lib/Target/CppBackend/CPPBackend.cpp index 145568a..f08559f 100644 --- a/lib/Target/CppBackend/CPPBackend.cpp +++ b/lib/Target/CppBackend/CPPBackend.cpp @@ -104,7 +104,7 @@ namespace { public: static char ID; explicit CppWriter(formatted_raw_ostream &o) : - ModulePass(&ID), Out(o), uniqueNum(0), is_inline(false), indent_level(0){} + ModulePass(ID), Out(o), uniqueNum(0), is_inline(false), indent_level(0){} virtual const char *getPassName() const { return "C++ backend"; } @@ -288,6 +288,8 @@ void CppWriter::printLinkageType(GlobalValue::LinkageTypes LT) { Out << "GlobalValue::LinkerPrivateLinkage"; break; case GlobalValue::LinkerPrivateWeakLinkage: Out << "GlobalValue::LinkerPrivateWeakLinkage"; break; + case GlobalValue::LinkerPrivateWeakDefAutoLinkage: + Out << "GlobalValue::LinkerPrivateWeakDefAutoLinkage"; break; case GlobalValue::AvailableExternallyLinkage: Out << "GlobalValue::AvailableExternallyLinkage "; break; case GlobalValue::LinkOnceAnyLinkage: @@ -471,14 +473,22 @@ void CppWriter::printAttributes(const AttrListPtr &PAL, HANDLE_ATTR(Nest); HANDLE_ATTR(ReadNone); HANDLE_ATTR(ReadOnly); - HANDLE_ATTR(InlineHint); HANDLE_ATTR(NoInline); HANDLE_ATTR(AlwaysInline); HANDLE_ATTR(OptimizeForSize); HANDLE_ATTR(StackProtect); HANDLE_ATTR(StackProtectReq); HANDLE_ATTR(NoCapture); + HANDLE_ATTR(NoRedZone); + HANDLE_ATTR(NoImplicitFloat); + HANDLE_ATTR(Naked); + HANDLE_ATTR(InlineHint); #undef HANDLE_ATTR + if (attrs & Attribute::StackAlignment) + Out << " | Attribute::constructStackAlignmentFromInt(" + << Attribute::getStackAlignmentFromAttrs(attrs) + << ")"; + attrs &= ~Attribute::StackAlignment; assert(attrs == 0 && "Unhandled attribute!"); Out << ";"; nl(Out); @@ -1404,7 +1414,8 @@ void CppWriter::printInstruction(const Instruction *I, nl(Out); } Out << "CallInst* " << iName << " = CallInst::Create(" - << opNames[call->getNumArgOperands()] << ", " << iName << "_params.begin(), " + << opNames[call->getNumArgOperands()] << ", " + << iName << "_params.begin(), " << iName << "_params.end(), \""; } else if (call->getNumArgOperands() == 1) { Out << "CallInst* " << iName << " = CallInst::Create(" diff --git a/lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp b/lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp index b6e4d65..f4b30ad 100644 --- a/lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp +++ b/lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp @@ -65,11 +65,8 @@ namespace { void printFSLImm(const MachineInstr *MI, int opNum, raw_ostream &O); void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O, const char *Modifier = 0); - void printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, - const char *Modifier = 0); void printSavedRegsBitmask(raw_ostream &OS); - const char *emitCurrentABIString(); void emitFrameDirective(); void printInstruction(const MachineInstr *MI, raw_ostream &O); @@ -292,13 +289,6 @@ printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O, printOperand(MI, opNum, O); } -void MBlazeAsmPrinter:: -printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, - const char *Modifier) { - const MachineOperand& MO = MI->getOperand(opNum); - O << MBlaze::MBlazeFCCToString((MBlaze::CondCode)MO.getImm()); -} - // Force static initialization. extern "C" void LLVMInitializeMBlazeAsmPrinter() { RegisterAsmPrinter X(TheMBlazeTarget); diff --git a/lib/Target/MBlaze/MBlaze.td b/lib/Target/MBlaze/MBlaze.td index 482ddd3..3815b6d 100644 --- a/lib/Target/MBlaze/MBlaze.td +++ b/lib/Target/MBlaze/MBlaze.td @@ -1,4 +1,4 @@ -//===- MBlaze.td - Describe the MBlaze Target Machine -----------*- C++ -*-===// +//===- MBlaze.td - Describe the MBlaze Target Machine ------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/MBlaze/MBlazeCallingConv.td b/lib/Target/MBlaze/MBlazeCallingConv.td index ddd4998..8622e0d 100644 --- a/lib/Target/MBlaze/MBlazeCallingConv.td +++ b/lib/Target/MBlaze/MBlazeCallingConv.td @@ -1,4 +1,4 @@ -//===- MBlazeCallingConv.td - Calling Conventions for MBlaze ----*- C++ -*-===// +//===- MBlazeCallingConv.td - Calling Conventions for MBlaze -*- tablegen -*-=// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp b/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp index 42fea25..b551b79 100644 --- a/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp +++ b/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp @@ -32,7 +32,7 @@ namespace { static char ID; Filler(TargetMachine &tm) - : MachineFunctionPass(&ID), TM(tm), TII(tm.getInstrInfo()) { } + : MachineFunctionPass(ID), TM(tm), TII(tm.getInstrInfo()) { } virtual const char *getPassName() const { return "MBlaze Delay Slot Filler"; diff --git a/lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp b/lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp index c7cd5f4..e64dd0e 100644 --- a/lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp +++ b/lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp @@ -219,7 +219,7 @@ SelectAddr(SDNode *Op, SDValue Addr, SDValue &Offset, SDValue &Base) { // Operand is a result from an ADD. if (Addr.getOpcode() == ISD::ADD) { if (ConstantSDNode *CN = dyn_cast(Addr.getOperand(1))) { - if (Predicate_immSExt16(CN)) { + if (isUInt<16>(CN->getZExtValue())) { // If the first operand is a FI, get the TargetFI Node if (FrameIndexSDNode *FIN = dyn_cast diff --git a/lib/Target/MBlaze/MBlazeInstrFPU.td b/lib/Target/MBlaze/MBlazeInstrFPU.td index a48a8c9..657b1d4 100644 --- a/lib/Target/MBlaze/MBlazeInstrFPU.td +++ b/lib/Target/MBlaze/MBlazeInstrFPU.td @@ -1,4 +1,4 @@ -//===- MBlazeInstrFPU.td - MBlaze FPU Instruction defs ----------*- C++ -*-===// +//===- MBlazeInstrFPU.td - MBlaze FPU Instruction defs -----*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/MBlaze/MBlazeInstrFSL.td b/lib/Target/MBlaze/MBlazeInstrFSL.td index b59999e..5158411 100644 --- a/lib/Target/MBlaze/MBlazeInstrFSL.td +++ b/lib/Target/MBlaze/MBlazeInstrFSL.td @@ -1,4 +1,4 @@ -//===- MBlazeInstrFSL.td - MBlaze FSL Instruction defs ----------*- C++ -*-===// +//===- MBlazeInstrFSL.td - MBlaze FSL Instruction defs -----*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/MBlaze/MBlazeInstrFormats.td b/lib/Target/MBlaze/MBlazeInstrFormats.td index 7d65543..28e8e44 100644 --- a/lib/Target/MBlaze/MBlazeInstrFormats.td +++ b/lib/Target/MBlaze/MBlazeInstrFormats.td @@ -1,4 +1,4 @@ -//===- MBlazeInstrFormats.td - MB Instruction defs --------------*- C++ -*-===// +//===- MBlazeInstrFormats.td - MB Instruction defs ---------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/MBlaze/MBlazeInstrInfo.cpp b/lib/Target/MBlaze/MBlazeInstrInfo.cpp index 6ff5825..b590c09 100644 --- a/lib/Target/MBlaze/MBlazeInstrInfo.cpp +++ b/lib/Target/MBlaze/MBlazeInstrInfo.cpp @@ -30,41 +30,6 @@ static bool isZeroImm(const MachineOperand &op) { return op.isImm() && op.getImm() == 0; } -/// Return true if the instruction is a register to register move and -/// leave the source and dest operands in the passed parameters. -bool MBlazeInstrInfo:: -isMoveInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const { - SrcSubIdx = DstSubIdx = 0; // No sub-registers. - - // add $dst, $src, $zero || addu $dst, $zero, $src - // or $dst, $src, $zero || or $dst, $zero, $src - if ((MI.getOpcode() == MBlaze::ADD) || (MI.getOpcode() == MBlaze::OR)) { - if (MI.getOperand(1).isReg() && MI.getOperand(1).getReg() == MBlaze::R0) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(2).getReg(); - return true; - } else if (MI.getOperand(2).isReg() && - MI.getOperand(2).getReg() == MBlaze::R0) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(1).getReg(); - return true; - } - } - - // addi $dst, $src, 0 - // ori $dst, $src, 0 - if ((MI.getOpcode() == MBlaze::ADDI) || (MI.getOpcode() == MBlaze::ORI)) { - if ((MI.getOperand(1).isReg()) && (isZeroImm(MI.getOperand(2)))) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(1).getReg(); - return true; - } - } - - return false; -} - /// isLoadFromStackSlot - If the specified machine instruction is a direct /// load from a stack slot, return the virtual or physical register number of /// the destination along with the FrameIndex of the loaded stack slot. If diff --git a/lib/Target/MBlaze/MBlazeInstrInfo.h b/lib/Target/MBlaze/MBlazeInstrInfo.h index f074370..b3dba0e 100644 --- a/lib/Target/MBlaze/MBlazeInstrInfo.h +++ b/lib/Target/MBlaze/MBlazeInstrInfo.h @@ -173,12 +173,6 @@ public: /// virtual const MBlazeRegisterInfo &getRegisterInfo() const { return RI; } - /// Return true if the instruction is a register to register move and return - /// the source and dest operands and their sub-register indices by reference. - virtual bool isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const; - /// isLoadFromStackSlot - If the specified machine instruction is a direct /// load from a stack slot, return the virtual or physical register number of /// the destination along with the FrameIndex of the loaded stack slot. If diff --git a/lib/Target/MBlaze/MBlazeInstrInfo.td b/lib/Target/MBlaze/MBlazeInstrInfo.td index 3c406dd..e5d1534 100644 --- a/lib/Target/MBlaze/MBlazeInstrInfo.td +++ b/lib/Target/MBlaze/MBlazeInstrInfo.td @@ -1,4 +1,4 @@ -//===- MBlazeInstrInfo.td - MBlaze Instruction defs -------------*- C++ -*-===// +//===- MBlazeInstrInfo.td - MBlaze Instruction defs --------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/MBlaze/MBlazeIntrinsics.td b/lib/Target/MBlaze/MBlazeIntrinsics.td index 82552fa..a27cb5b 100644 --- a/lib/Target/MBlaze/MBlazeIntrinsics.td +++ b/lib/Target/MBlaze/MBlazeIntrinsics.td @@ -17,17 +17,11 @@ // MBlaze intrinsic classes. let TargetPrefix = "mblaze", isTarget = 1 in { - class MBFSL_Get_Intrinsic : Intrinsic<[llvm_i32_ty], - [llvm_i32_ty], - [IntrWriteMem]>; + class MBFSL_Get_Intrinsic : Intrinsic<[llvm_i32_ty], [llvm_i32_ty], []>; - class MBFSL_Put_Intrinsic : Intrinsic<[], - [llvm_i32_ty, llvm_i32_ty], - [IntrWriteMem]>; + class MBFSL_Put_Intrinsic : Intrinsic<[], [llvm_i32_ty, llvm_i32_ty], []>; - class MBFSL_PutT_Intrinsic : Intrinsic<[], - [llvm_i32_ty], - [IntrWriteMem]>; + class MBFSL_PutT_Intrinsic : Intrinsic<[], [llvm_i32_ty], []>; } //===----------------------------------------------------------------------===// diff --git a/lib/Target/MBlaze/MBlazeRegisterInfo.cpp b/lib/Target/MBlaze/MBlazeRegisterInfo.cpp index 8cafa8c..22b6a30 100644 --- a/lib/Target/MBlaze/MBlazeRegisterInfo.cpp +++ b/lib/Target/MBlaze/MBlazeRegisterInfo.cpp @@ -242,9 +242,9 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, // FrameIndex represent objects inside a abstract stack. // We must replace FrameIndex with an stack/frame pointer // direct reference. -unsigned MBlazeRegisterInfo:: +void MBlazeRegisterInfo:: eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, - FrameIndexValue *Value, RegScavenger *RS) const { + RegScavenger *RS) const { MachineInstr &MI = *II; MachineFunction &MF = *MI.getParent()->getParent(); @@ -277,7 +277,6 @@ eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, MI.getOperand(oi).ChangeToImmediate(Offset); MI.getOperand(i).ChangeToRegister(getFrameRegister(MF), false); - return 0; } void MBlazeRegisterInfo:: diff --git a/lib/Target/MBlaze/MBlazeRegisterInfo.h b/lib/Target/MBlaze/MBlazeRegisterInfo.h index af97b0e..1e1fde1 100644 --- a/lib/Target/MBlaze/MBlazeRegisterInfo.h +++ b/lib/Target/MBlaze/MBlazeRegisterInfo.h @@ -63,9 +63,8 @@ struct MBlazeRegisterInfo : public MBlazeGenRegisterInfo { MachineBasicBlock::iterator I) const; /// Stack Frame Processing Methods - unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value = NULL, - RegScavenger *RS = NULL) const; + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; diff --git a/lib/Target/MBlaze/MBlazeRegisterInfo.td b/lib/Target/MBlaze/MBlazeRegisterInfo.td index d0a1e75..5e93510 100644 --- a/lib/Target/MBlaze/MBlazeRegisterInfo.td +++ b/lib/Target/MBlaze/MBlazeRegisterInfo.td @@ -1,4 +1,4 @@ -//===- MBlazeRegisterInfo.td - MBlaze Register defs -------------*- C++ -*-===// +//===- MBlazeRegisterInfo.td - MBlaze Register defs --------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/MBlaze/MBlazeSchedule.td b/lib/Target/MBlaze/MBlazeSchedule.td index 1fec9e6..4a65542 100644 --- a/lib/Target/MBlaze/MBlazeSchedule.td +++ b/lib/Target/MBlaze/MBlazeSchedule.td @@ -1,4 +1,4 @@ -//===- MBlazeSchedule.td - MBlaze Scheduling Definitions --------*- C++ -*-===// +//===- MBlazeSchedule.td - MBlaze Scheduling Definitions ---*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/MSIL/CMakeLists.txt b/lib/Target/MSIL/CMakeLists.txt deleted file mode 100644 index b1d47ef..0000000 --- a/lib/Target/MSIL/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_llvm_target(MSIL - MSILWriter.cpp - ) diff --git a/lib/Target/MSIL/MSILWriter.cpp b/lib/Target/MSIL/MSILWriter.cpp deleted file mode 100644 index cc350e8..0000000 --- a/lib/Target/MSIL/MSILWriter.cpp +++ /dev/null @@ -1,1706 +0,0 @@ -//===-- MSILWriter.cpp - Library for converting LLVM code to MSIL ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This library converts LLVM code to MSIL code. -// -//===----------------------------------------------------------------------===// - -#include "MSILWriter.h" -#include "llvm/CallingConv.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Intrinsics.h" -#include "llvm/IntrinsicInst.h" -#include "llvm/TypeSymbolTable.h" -#include "llvm/Analysis/ConstantsScanner.h" -#include "llvm/Support/CallSite.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/InstVisitor.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/CodeGen/Passes.h" -using namespace llvm; - -namespace llvm { - // TargetMachine for the MSIL - struct MSILTarget : public TargetMachine { - MSILTarget(const Target &T, const std::string &TT, const std::string &FS) - : TargetMachine(T) {} - - virtual bool addPassesToEmitFile(PassManagerBase &PM, - formatted_raw_ostream &Out, - CodeGenFileType FileType, - CodeGenOpt::Level OptLevel, - bool DisableVerify); - - virtual const TargetData *getTargetData() const { return 0; } - }; -} - -extern "C" void LLVMInitializeMSILTarget() { - // Register the target. - RegisterTargetMachine X(TheMSILTarget); -} - -bool MSILModule::runOnModule(Module &M) { - ModulePtr = &M; - TD = &getAnalysis(); - bool Changed = false; - // Find named types. - TypeSymbolTable& Table = M.getTypeSymbolTable(); - std::set Types = getAnalysis().getTypes(); - for (TypeSymbolTable::iterator I = Table.begin(), E = Table.end(); I!=E; ) { - if (!I->second->isStructTy() && !I->second->isOpaqueTy()) - Table.remove(I++); - else { - std::set::iterator T = Types.find(I->second); - if (T==Types.end()) - Table.remove(I++); - else { - Types.erase(T); - ++I; - } - } - } - // Find unnamed types. - unsigned RenameCounter = 0; - for (std::set::const_iterator I = Types.begin(), - E = Types.end(); I!=E; ++I) - if (const StructType *STy = dyn_cast(*I)) { - while (ModulePtr->addTypeName("unnamed$"+utostr(RenameCounter), STy)) - ++RenameCounter; - Changed = true; - } - // Pointer for FunctionPass. - UsedTypes = &getAnalysis().getTypes(); - return Changed; -} - -char MSILModule::ID = 0; -char MSILWriter::ID = 0; - -bool MSILWriter::runOnFunction(Function &F) { - if (F.isDeclaration()) return false; - - // Do not codegen any 'available_externally' functions at all, they have - // definitions outside the translation unit. - if (F.hasAvailableExternallyLinkage()) - return false; - - LInfo = &getAnalysis(); - printFunction(F); - return false; -} - - -bool MSILWriter::doInitialization(Module &M) { - ModulePtr = &M; - Out << ".assembly extern mscorlib {}\n"; - Out << ".assembly MSIL {}\n\n"; - Out << "// External\n"; - printExternals(); - Out << "// Declarations\n"; - printDeclarations(M.getTypeSymbolTable()); - Out << "// Definitions\n"; - printGlobalVariables(); - Out << "// Startup code\n"; - printModuleStartup(); - return false; -} - - -bool MSILWriter::doFinalization(Module &M) { - return false; -} - - -void MSILWriter::printModuleStartup() { - Out << - ".method static public int32 $MSIL_Startup() {\n" - "\t.entrypoint\n" - "\t.locals (native int i)\n" - "\t.locals (native int argc)\n" - "\t.locals (native int ptr)\n" - "\t.locals (void* argv)\n" - "\t.locals (string[] args)\n" - "\tcall\tstring[] [mscorlib]System.Environment::GetCommandLineArgs()\n" - "\tdup\n" - "\tstloc\targs\n" - "\tldlen\n" - "\tconv.i4\n" - "\tdup\n" - "\tstloc\targc\n"; - printPtrLoad(TD->getPointerSize()); - Out << - "\tmul\n" - "\tlocalloc\n" - "\tstloc\targv\n" - "\tldc.i4.0\n" - "\tstloc\ti\n" - "L_01:\n" - "\tldloc\ti\n" - "\tldloc\targc\n" - "\tceq\n" - "\tbrtrue\tL_02\n" - "\tldloc\targs\n" - "\tldloc\ti\n" - "\tldelem.ref\n" - "\tcall\tnative int [mscorlib]System.Runtime.InteropServices.Marshal::" - "StringToHGlobalAnsi(string)\n" - "\tstloc\tptr\n" - "\tldloc\targv\n" - "\tldloc\ti\n"; - printPtrLoad(TD->getPointerSize()); - Out << - "\tmul\n" - "\tadd\n" - "\tldloc\tptr\n" - "\tstind.i\n" - "\tldloc\ti\n" - "\tldc.i4.1\n" - "\tadd\n" - "\tstloc\ti\n" - "\tbr\tL_01\n" - "L_02:\n" - "\tcall void $MSIL_Init()\n"; - - // Call user 'main' function. - const Function* F = ModulePtr->getFunction("main"); - if (!F || F->isDeclaration()) { - Out << "\tldc.i4.0\n\tret\n}\n"; - return; - } - bool BadSig = true; - std::string Args(""); - Function::const_arg_iterator Arg1,Arg2; - - switch (F->arg_size()) { - case 0: - BadSig = false; - break; - case 1: - Arg1 = F->arg_begin(); - if (Arg1->getType()->isIntegerTy()) { - Out << "\tldloc\targc\n"; - Args = getTypeName(Arg1->getType()); - BadSig = false; - } - break; - case 2: - Arg1 = Arg2 = F->arg_begin(); ++Arg2; - if (Arg1->getType()->isIntegerTy() && - Arg2->getType()->getTypeID() == Type::PointerTyID) { - Out << "\tldloc\targc\n\tldloc\targv\n"; - Args = getTypeName(Arg1->getType())+","+getTypeName(Arg2->getType()); - BadSig = false; - } - break; - default: - BadSig = true; - } - - bool RetVoid = (F->getReturnType()->getTypeID() == Type::VoidTyID); - if (BadSig || (!F->getReturnType()->isIntegerTy() && !RetVoid)) { - Out << "\tldc.i4.0\n"; - } else { - Out << "\tcall\t" << getTypeName(F->getReturnType()) << - getConvModopt(F->getCallingConv()) << "main(" << Args << ")\n"; - if (RetVoid) - Out << "\tldc.i4.0\n"; - else - Out << "\tconv.i4\n"; - } - Out << "\tret\n}\n"; -} - -bool MSILWriter::isZeroValue(const Value* V) { - if (const Constant *C = dyn_cast(V)) - return C->isNullValue(); - return false; -} - - -std::string MSILWriter::getValueName(const Value* V) { - std::string Name; - if (const GlobalValue *GV = dyn_cast(V)) - Name = GV->getName(); - else { - unsigned &No = AnonValueNumbers[V]; - if (No == 0) No = ++NextAnonValueNumber; - Name = "tmp" + utostr(No); - } - - // Name into the quotes allow control and space characters. - return "'"+Name+"'"; -} - - -std::string MSILWriter::getLabelName(const std::string& Name) { - if (Name.find('.')!=std::string::npos) { - std::string Tmp(Name); - // Replace unaccepable characters in the label name. - for (std::string::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) - if (*I=='.') *I = '@'; - return Tmp; - } - return Name; -} - - -std::string MSILWriter::getLabelName(const Value* V) { - std::string Name; - if (const GlobalValue *GV = dyn_cast(V)) - Name = GV->getName(); - else { - unsigned &No = AnonValueNumbers[V]; - if (No == 0) No = ++NextAnonValueNumber; - Name = "tmp" + utostr(No); - } - - return getLabelName(Name); -} - - -std::string MSILWriter::getConvModopt(CallingConv::ID CallingConvID) { - switch (CallingConvID) { - case CallingConv::C: - case CallingConv::Cold: - case CallingConv::Fast: - return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) "; - case CallingConv::X86_FastCall: - return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvFastcall) "; - case CallingConv::X86_StdCall: - return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvStdcall) "; - case CallingConv::X86_ThisCall: - return "modopt([mscorlib]System.Runtime.CompilerServices.CallConvThiscall) "; - default: - errs() << "CallingConvID = " << CallingConvID << '\n'; - llvm_unreachable("Unsupported calling convention"); - } - return ""; // Not reached -} - - -std::string MSILWriter::getArrayTypeName(Type::TypeID TyID, const Type* Ty) { - std::string Tmp = ""; - const Type* ElemTy = Ty; - assert(Ty->getTypeID()==TyID && "Invalid type passed"); - // Walk trought array element types. - for (;;) { - // Multidimensional array. - if (ElemTy->getTypeID()==TyID) { - if (const ArrayType* ATy = dyn_cast(ElemTy)) - Tmp += utostr(ATy->getNumElements()); - else if (const VectorType* VTy = dyn_cast(ElemTy)) - Tmp += utostr(VTy->getNumElements()); - ElemTy = cast(ElemTy)->getElementType(); - } - // Base element type found. - if (ElemTy->getTypeID()!=TyID) break; - Tmp += ","; - } - return getTypeName(ElemTy, false, true)+"["+Tmp+"]"; -} - - -std::string MSILWriter::getPrimitiveTypeName(const Type* Ty, bool isSigned) { - unsigned NumBits = 0; - switch (Ty->getTypeID()) { - case Type::VoidTyID: - return "void "; - case Type::IntegerTyID: - NumBits = getBitWidth(Ty); - if(NumBits==1) - return "bool "; - if (!isSigned) - return "unsigned int"+utostr(NumBits)+" "; - return "int"+utostr(NumBits)+" "; - case Type::FloatTyID: - return "float32 "; - case Type::DoubleTyID: - return "float64 "; - default: - errs() << "Type = " << *Ty << '\n'; - llvm_unreachable("Invalid primitive type"); - } - return ""; // Not reached -} - - -std::string MSILWriter::getTypeName(const Type* Ty, bool isSigned, - bool isNested) { - if (Ty->isPrimitiveType() || Ty->isIntegerTy()) - return getPrimitiveTypeName(Ty,isSigned); - // FIXME: "OpaqueType" support - switch (Ty->getTypeID()) { - case Type::PointerTyID: - return "void* "; - case Type::StructTyID: - if (isNested) - return ModulePtr->getTypeName(Ty); - return "valuetype '"+ModulePtr->getTypeName(Ty)+"' "; - case Type::ArrayTyID: - if (isNested) - return getArrayTypeName(Ty->getTypeID(),Ty); - return "valuetype '"+getArrayTypeName(Ty->getTypeID(),Ty)+"' "; - case Type::VectorTyID: - if (isNested) - return getArrayTypeName(Ty->getTypeID(),Ty); - return "valuetype '"+getArrayTypeName(Ty->getTypeID(),Ty)+"' "; - default: - errs() << "Type = " << *Ty << '\n'; - llvm_unreachable("Invalid type in getTypeName()"); - } - return ""; // Not reached -} - - -MSILWriter::ValueType MSILWriter::getValueLocation(const Value* V) { - // Function argument - if (isa(V)) - return ArgumentVT; - // Function - else if (const Function* F = dyn_cast(V)) - return F->hasLocalLinkage() ? InternalVT : GlobalVT; - // Variable - else if (const GlobalVariable* G = dyn_cast(V)) - return G->hasLocalLinkage() ? InternalVT : GlobalVT; - // Constant - else if (isa(V)) - return isa(V) ? ConstExprVT : ConstVT; - // Local variable - return LocalVT; -} - - -std::string MSILWriter::getTypePostfix(const Type* Ty, bool Expand, - bool isSigned) { - unsigned NumBits = 0; - switch (Ty->getTypeID()) { - // Integer constant, expanding for stack operations. - case Type::IntegerTyID: - NumBits = getBitWidth(Ty); - // Expand integer value to "int32" or "int64". - if (Expand) return (NumBits<=32 ? "i4" : "i8"); - if (NumBits==1) return "i1"; - return (isSigned ? "i" : "u")+utostr(NumBits/8); - // Float constant. - case Type::FloatTyID: - return "r4"; - case Type::DoubleTyID: - return "r8"; - case Type::PointerTyID: - return "i"+utostr(TD->getTypeAllocSize(Ty)); - default: - errs() << "TypeID = " << Ty->getTypeID() << '\n'; - llvm_unreachable("Invalid type in TypeToPostfix()"); - } - return ""; // Not reached -} - - -void MSILWriter::printConvToPtr() { - switch (ModulePtr->getPointerSize()) { - case Module::Pointer32: - printSimpleInstruction("conv.u4"); - break; - case Module::Pointer64: - printSimpleInstruction("conv.u8"); - break; - default: - llvm_unreachable("Module use not supporting pointer size"); - } -} - - -void MSILWriter::printPtrLoad(uint64_t N) { - switch (ModulePtr->getPointerSize()) { - case Module::Pointer32: - printSimpleInstruction("ldc.i4",utostr(N).c_str()); - // FIXME: Need overflow test? - if (!isUInt<32>(N)) { - errs() << "Value = " << utostr(N) << '\n'; - llvm_unreachable("32-bit pointer overflowed"); - } - break; - case Module::Pointer64: - printSimpleInstruction("ldc.i8",utostr(N).c_str()); - break; - default: - llvm_unreachable("Module use not supporting pointer size"); - } -} - - -void MSILWriter::printValuePtrLoad(const Value* V) { - printValueLoad(V); - printConvToPtr(); -} - - -void MSILWriter::printConstLoad(const Constant* C) { - if (const ConstantInt* CInt = dyn_cast(C)) { - // Integer constant - Out << "\tldc." << getTypePostfix(C->getType(),true) << '\t'; - if (CInt->isMinValue(true)) - Out << CInt->getSExtValue(); - else - Out << CInt->getZExtValue(); - } else if (const ConstantFP* FP = dyn_cast(C)) { - // Float constant - uint64_t X; - unsigned Size; - if (FP->getType()->getTypeID()==Type::FloatTyID) { - X = (uint32_t)FP->getValueAPF().bitcastToAPInt().getZExtValue(); - Size = 4; - } else { - X = FP->getValueAPF().bitcastToAPInt().getZExtValue(); - Size = 8; - } - Out << "\tldc.r" << Size << "\t( " << utohexstr(X) << ')'; - } else if (isa(C)) { - // Undefined constant value = NULL. - printPtrLoad(0); - } else { - errs() << "Constant = " << *C << '\n'; - llvm_unreachable("Invalid constant value"); - } - Out << '\n'; -} - - -void MSILWriter::printValueLoad(const Value* V) { - MSILWriter::ValueType Location = getValueLocation(V); - switch (Location) { - // Global variable or function address. - case GlobalVT: - case InternalVT: - if (const Function* F = dyn_cast(V)) { - std::string Name = getConvModopt(F->getCallingConv())+getValueName(F); - printSimpleInstruction("ldftn", - getCallSignature(F->getFunctionType(),NULL,Name).c_str()); - } else { - std::string Tmp; - const Type* ElemTy = cast(V->getType())->getElementType(); - if (Location==GlobalVT && cast(V)->hasDLLImportLinkage()) { - Tmp = "void* "+getValueName(V); - printSimpleInstruction("ldsfld",Tmp.c_str()); - } else { - Tmp = getTypeName(ElemTy)+getValueName(V); - printSimpleInstruction("ldsflda",Tmp.c_str()); - } - } - break; - // Function argument. - case ArgumentVT: - printSimpleInstruction("ldarg",getValueName(V).c_str()); - break; - // Local function variable. - case LocalVT: - printSimpleInstruction("ldloc",getValueName(V).c_str()); - break; - // Constant value. - case ConstVT: - if (isa(V)) - printPtrLoad(0); - else - printConstLoad(cast(V)); - break; - // Constant expression. - case ConstExprVT: - printConstantExpr(cast(V)); - break; - default: - errs() << "Value = " << *V << '\n'; - llvm_unreachable("Invalid value location"); - } -} - - -void MSILWriter::printValueSave(const Value* V) { - switch (getValueLocation(V)) { - case ArgumentVT: - printSimpleInstruction("starg",getValueName(V).c_str()); - break; - case LocalVT: - printSimpleInstruction("stloc",getValueName(V).c_str()); - break; - default: - errs() << "Value = " << *V << '\n'; - llvm_unreachable("Invalid value location"); - } -} - - -void MSILWriter::printBinaryInstruction(const char* Name, const Value* Left, - const Value* Right) { - printValueLoad(Left); - printValueLoad(Right); - Out << '\t' << Name << '\n'; -} - - -void MSILWriter::printSimpleInstruction(const char* Inst, const char* Operand) { - if(Operand) - Out << '\t' << Inst << '\t' << Operand << '\n'; - else - Out << '\t' << Inst << '\n'; -} - - -void MSILWriter::printPHICopy(const BasicBlock* Src, const BasicBlock* Dst) { - for (BasicBlock::const_iterator I = Dst->begin(); isa(I); ++I) { - const PHINode* Phi = cast(I); - const Value* Val = Phi->getIncomingValueForBlock(Src); - if (isa(Val)) continue; - printValueLoad(Val); - printValueSave(Phi); - } -} - - -void MSILWriter::printBranchToBlock(const BasicBlock* CurrBB, - const BasicBlock* TrueBB, - const BasicBlock* FalseBB) { - if (TrueBB==FalseBB) { - // "TrueBB" and "FalseBB" destination equals - printPHICopy(CurrBB,TrueBB); - printSimpleInstruction("pop"); - printSimpleInstruction("br",getLabelName(TrueBB).c_str()); - } else if (FalseBB==NULL) { - // If "FalseBB" not used the jump have condition - printPHICopy(CurrBB,TrueBB); - printSimpleInstruction("brtrue",getLabelName(TrueBB).c_str()); - } else if (TrueBB==NULL) { - // If "TrueBB" not used the jump is unconditional - printPHICopy(CurrBB,FalseBB); - printSimpleInstruction("br",getLabelName(FalseBB).c_str()); - } else { - // Copy PHI instructions for each block - std::string TmpLabel; - // Print PHI instructions for "TrueBB" - if (isa(TrueBB->begin())) { - TmpLabel = getLabelName(TrueBB)+"$phi_"+utostr(getUniqID()); - printSimpleInstruction("brtrue",TmpLabel.c_str()); - } else { - printSimpleInstruction("brtrue",getLabelName(TrueBB).c_str()); - } - // Print PHI instructions for "FalseBB" - if (isa(FalseBB->begin())) { - printPHICopy(CurrBB,FalseBB); - printSimpleInstruction("br",getLabelName(FalseBB).c_str()); - } else { - printSimpleInstruction("br",getLabelName(FalseBB).c_str()); - } - if (isa(TrueBB->begin())) { - // Handle "TrueBB" PHI Copy - Out << TmpLabel << ":\n"; - printPHICopy(CurrBB,TrueBB); - printSimpleInstruction("br",getLabelName(TrueBB).c_str()); - } - } -} - - -void MSILWriter::printBranchInstruction(const BranchInst* Inst) { - if (Inst->isUnconditional()) { - printBranchToBlock(Inst->getParent(),NULL,Inst->getSuccessor(0)); - } else { - printValueLoad(Inst->getCondition()); - printBranchToBlock(Inst->getParent(),Inst->getSuccessor(0), - Inst->getSuccessor(1)); - } -} - - -void MSILWriter::printSelectInstruction(const Value* Cond, const Value* VTrue, - const Value* VFalse) { - std::string TmpLabel = std::string("select$true_")+utostr(getUniqID()); - printValueLoad(VTrue); - printValueLoad(Cond); - printSimpleInstruction("brtrue",TmpLabel.c_str()); - printSimpleInstruction("pop"); - printValueLoad(VFalse); - Out << TmpLabel << ":\n"; -} - - -void MSILWriter::printIndirectLoad(const Value* V) { - const Type* Ty = V->getType(); - printValueLoad(V); - if (const PointerType* P = dyn_cast(Ty)) - Ty = P->getElementType(); - std::string Tmp = "ldind."+getTypePostfix(Ty, false); - printSimpleInstruction(Tmp.c_str()); -} - - -void MSILWriter::printIndirectSave(const Value* Ptr, const Value* Val) { - printValueLoad(Ptr); - printValueLoad(Val); - printIndirectSave(Val->getType()); -} - - -void MSILWriter::printIndirectSave(const Type* Ty) { - // Instruction need signed postfix for any type. - std::string postfix = getTypePostfix(Ty, false); - if (*postfix.begin()=='u') *postfix.begin() = 'i'; - postfix = "stind."+postfix; - printSimpleInstruction(postfix.c_str()); -} - - -void MSILWriter::printCastInstruction(unsigned int Op, const Value* V, - const Type* Ty, const Type* SrcTy) { - std::string Tmp(""); - printValueLoad(V); - switch (Op) { - // Signed - case Instruction::SExt: - // If sign extending int, convert first from unsigned to signed - // with the same bit size - because otherwise we will loose the sign. - if (SrcTy) { - Tmp = "conv."+getTypePostfix(SrcTy,false,true); - printSimpleInstruction(Tmp.c_str()); - } - // FALLTHROUGH - case Instruction::SIToFP: - case Instruction::FPToSI: - Tmp = "conv."+getTypePostfix(Ty,false,true); - printSimpleInstruction(Tmp.c_str()); - break; - // Unsigned - case Instruction::FPTrunc: - case Instruction::FPExt: - case Instruction::UIToFP: - case Instruction::Trunc: - case Instruction::ZExt: - case Instruction::FPToUI: - case Instruction::PtrToInt: - case Instruction::IntToPtr: - Tmp = "conv."+getTypePostfix(Ty,false); - printSimpleInstruction(Tmp.c_str()); - break; - // Do nothing - case Instruction::BitCast: - // FIXME: meaning that ld*/st* instruction do not change data format. - break; - default: - errs() << "Opcode = " << Op << '\n'; - llvm_unreachable("Invalid conversion instruction"); - } -} - - -void MSILWriter::printGepInstruction(const Value* V, gep_type_iterator I, - gep_type_iterator E) { - unsigned Size; - // Load address - printValuePtrLoad(V); - // Calculate element offset. - for (; I!=E; ++I){ - Size = 0; - const Value* IndexValue = I.getOperand(); - if (const StructType* StrucTy = dyn_cast(*I)) { - uint64_t FieldIndex = cast(IndexValue)->getZExtValue(); - // Offset is the sum of all previous structure fields. - for (uint64_t F = 0; FgetTypeAllocSize(StrucTy->getContainedType((unsigned)F)); - printPtrLoad(Size); - printSimpleInstruction("add"); - continue; - } else if (const SequentialType* SeqTy = dyn_cast(*I)) { - Size = TD->getTypeAllocSize(SeqTy->getElementType()); - } else { - Size = TD->getTypeAllocSize(*I); - } - // Add offset of current element to stack top. - if (!isZeroValue(IndexValue)) { - // Constant optimization. - if (const ConstantInt* C = dyn_cast(IndexValue)) { - if (C->getValue().isNegative()) { - printPtrLoad(C->getValue().abs().getZExtValue()*Size); - printSimpleInstruction("sub"); - continue; - } else - printPtrLoad(C->getZExtValue()*Size); - } else { - printPtrLoad(Size); - printValuePtrLoad(IndexValue); - printSimpleInstruction("mul"); - } - printSimpleInstruction("add"); - } - } -} - - -std::string MSILWriter::getCallSignature(const FunctionType* Ty, - const Instruction* Inst, - std::string Name) { - std::string Tmp(""); - if (Ty->isVarArg()) Tmp += "vararg "; - // Name and return type. - Tmp += getTypeName(Ty->getReturnType())+Name+"("; - // Function argument type list. - unsigned NumParams = Ty->getNumParams(); - for (unsigned I = 0; I!=NumParams; ++I) { - if (I!=0) Tmp += ","; - Tmp += getTypeName(Ty->getParamType(I)); - } - // CLR needs to know the exact amount of parameters received by vararg - // function, because caller cleans the stack. - if (Ty->isVarArg() && Inst) { - // Origin to function arguments in "CallInst" or "InvokeInst". - unsigned Org = isa(Inst) ? 3 : 1; - // Print variable argument types. - unsigned NumOperands = Inst->getNumOperands()-Org; - if (NumParamsgetOperand(J+Org)->getType()); - } - } - } - return Tmp+")"; -} - - -void MSILWriter::printFunctionCall(const Value* FnVal, - const Instruction* Inst) { - // Get function calling convention. - std::string Name = ""; - if (const CallInst* Call = dyn_cast(Inst)) - Name = getConvModopt(Call->getCallingConv()); - else if (const InvokeInst* Invoke = dyn_cast(Inst)) - Name = getConvModopt(Invoke->getCallingConv()); - else { - errs() << "Instruction = " << Inst->getName() << '\n'; - llvm_unreachable("Need \"Invoke\" or \"Call\" instruction only"); - } - if (const Function* F = dyn_cast(FnVal)) { - // Direct call. - Name += getValueName(F); - printSimpleInstruction("call", - getCallSignature(F->getFunctionType(),Inst,Name).c_str()); - } else { - // Indirect function call. - const PointerType* PTy = cast(FnVal->getType()); - const FunctionType* FTy = cast(PTy->getElementType()); - // Load function address. - printValueLoad(FnVal); - printSimpleInstruction("calli",getCallSignature(FTy,Inst,Name).c_str()); - } -} - - -void MSILWriter::printIntrinsicCall(const IntrinsicInst* Inst) { - std::string Name; - switch (Inst->getIntrinsicID()) { - case Intrinsic::vastart: - Name = getValueName(Inst->getArgOperand(0)); - Name.insert(Name.length()-1,"$valist"); - // Obtain the argument handle. - printSimpleInstruction("ldloca",Name.c_str()); - printSimpleInstruction("arglist"); - printSimpleInstruction("call", - "instance void [mscorlib]System.ArgIterator::.ctor" - "(valuetype [mscorlib]System.RuntimeArgumentHandle)"); - // Save as pointer type "void*" - printValueLoad(Inst->getArgOperand(0)); - printSimpleInstruction("ldloca",Name.c_str()); - printIndirectSave(PointerType::getUnqual( - IntegerType::get(Inst->getContext(), 8))); - break; - case Intrinsic::vaend: - // Close argument list handle. - printIndirectLoad(Inst->getArgOperand(0)); - printSimpleInstruction("call","instance void [mscorlib]System.ArgIterator::End()"); - break; - case Intrinsic::vacopy: - // Copy "ArgIterator" valuetype. - printIndirectLoad(Inst->getArgOperand(0)); - printIndirectLoad(Inst->getArgOperand(1)); - printSimpleInstruction("cpobj","[mscorlib]System.ArgIterator"); - break; - default: - errs() << "Intrinsic ID = " << Inst->getIntrinsicID() << '\n'; - llvm_unreachable("Invalid intrinsic function"); - } -} - - -void MSILWriter::printCallInstruction(const Instruction* Inst) { - if (isa(Inst)) { - // Handle intrinsic function. - printIntrinsicCall(cast(Inst)); - } else { - const CallInst *CI = cast(Inst); - // Load arguments to stack and call function. - for (int I = 0, E = CI->getNumArgOperands(); I!=E; ++I) - printValueLoad(CI->getArgOperand(I)); - printFunctionCall(CI->getCalledFunction(), Inst); - } -} - - -void MSILWriter::printICmpInstruction(unsigned Predicate, const Value* Left, - const Value* Right) { - switch (Predicate) { - case ICmpInst::ICMP_EQ: - printBinaryInstruction("ceq",Left,Right); - break; - case ICmpInst::ICMP_NE: - // Emulate = not neg (Op1 eq Op2) - printBinaryInstruction("ceq",Left,Right); - printSimpleInstruction("neg"); - printSimpleInstruction("not"); - break; - case ICmpInst::ICMP_ULE: - case ICmpInst::ICMP_SLE: - // Emulate = (Op1 eq Op2) or (Op1 lt Op2) - printBinaryInstruction("ceq",Left,Right); - if (Predicate==ICmpInst::ICMP_ULE) - printBinaryInstruction("clt.un",Left,Right); - else - printBinaryInstruction("clt",Left,Right); - printSimpleInstruction("or"); - break; - case ICmpInst::ICMP_UGE: - case ICmpInst::ICMP_SGE: - // Emulate = (Op1 eq Op2) or (Op1 gt Op2) - printBinaryInstruction("ceq",Left,Right); - if (Predicate==ICmpInst::ICMP_UGE) - printBinaryInstruction("cgt.un",Left,Right); - else - printBinaryInstruction("cgt",Left,Right); - printSimpleInstruction("or"); - break; - case ICmpInst::ICMP_ULT: - printBinaryInstruction("clt.un",Left,Right); - break; - case ICmpInst::ICMP_SLT: - printBinaryInstruction("clt",Left,Right); - break; - case ICmpInst::ICMP_UGT: - printBinaryInstruction("cgt.un",Left,Right); - break; - case ICmpInst::ICMP_SGT: - printBinaryInstruction("cgt",Left,Right); - break; - default: - errs() << "Predicate = " << Predicate << '\n'; - llvm_unreachable("Invalid icmp predicate"); - } -} - - -void MSILWriter::printFCmpInstruction(unsigned Predicate, const Value* Left, - const Value* Right) { - // FIXME: Correct comparison - std::string NanFunc = "bool [mscorlib]System.Double::IsNaN(float64)"; - switch (Predicate) { - case FCmpInst::FCMP_UGT: - // X > Y || llvm_fcmp_uno(X, Y) - printBinaryInstruction("cgt",Left,Right); - printFCmpInstruction(FCmpInst::FCMP_UNO,Left,Right); - printSimpleInstruction("or"); - break; - case FCmpInst::FCMP_OGT: - // X > Y - printBinaryInstruction("cgt",Left,Right); - break; - case FCmpInst::FCMP_UGE: - // X >= Y || llvm_fcmp_uno(X, Y) - printBinaryInstruction("ceq",Left,Right); - printBinaryInstruction("cgt",Left,Right); - printSimpleInstruction("or"); - printFCmpInstruction(FCmpInst::FCMP_UNO,Left,Right); - printSimpleInstruction("or"); - break; - case FCmpInst::FCMP_OGE: - // X >= Y - printBinaryInstruction("ceq",Left,Right); - printBinaryInstruction("cgt",Left,Right); - printSimpleInstruction("or"); - break; - case FCmpInst::FCMP_ULT: - // X < Y || llvm_fcmp_uno(X, Y) - printBinaryInstruction("clt",Left,Right); - printFCmpInstruction(FCmpInst::FCMP_UNO,Left,Right); - printSimpleInstruction("or"); - break; - case FCmpInst::FCMP_OLT: - // X < Y - printBinaryInstruction("clt",Left,Right); - break; - case FCmpInst::FCMP_ULE: - // X <= Y || llvm_fcmp_uno(X, Y) - printBinaryInstruction("ceq",Left,Right); - printBinaryInstruction("clt",Left,Right); - printSimpleInstruction("or"); - printFCmpInstruction(FCmpInst::FCMP_UNO,Left,Right); - printSimpleInstruction("or"); - break; - case FCmpInst::FCMP_OLE: - // X <= Y - printBinaryInstruction("ceq",Left,Right); - printBinaryInstruction("clt",Left,Right); - printSimpleInstruction("or"); - break; - case FCmpInst::FCMP_UEQ: - // X == Y || llvm_fcmp_uno(X, Y) - printBinaryInstruction("ceq",Left,Right); - printFCmpInstruction(FCmpInst::FCMP_UNO,Left,Right); - printSimpleInstruction("or"); - break; - case FCmpInst::FCMP_OEQ: - // X == Y - printBinaryInstruction("ceq",Left,Right); - break; - case FCmpInst::FCMP_UNE: - // X != Y - printBinaryInstruction("ceq",Left,Right); - printSimpleInstruction("neg"); - printSimpleInstruction("not"); - break; - case FCmpInst::FCMP_ONE: - // X != Y && llvm_fcmp_ord(X, Y) - printBinaryInstruction("ceq",Left,Right); - printSimpleInstruction("not"); - break; - case FCmpInst::FCMP_ORD: - // return X == X && Y == Y - printBinaryInstruction("ceq",Left,Left); - printBinaryInstruction("ceq",Right,Right); - printSimpleInstruction("or"); - break; - case FCmpInst::FCMP_UNO: - // X != X || Y != Y - printBinaryInstruction("ceq",Left,Left); - printSimpleInstruction("not"); - printBinaryInstruction("ceq",Right,Right); - printSimpleInstruction("not"); - printSimpleInstruction("or"); - break; - default: - llvm_unreachable("Illegal FCmp predicate"); - } -} - - -void MSILWriter::printInvokeInstruction(const InvokeInst* Inst) { - std::string Label = "leave$normal_"+utostr(getUniqID()); - Out << ".try {\n"; - // Load arguments - for (int I = 0, E = Inst->getNumArgOperands(); I!=E; ++I) - printValueLoad(Inst->getArgOperand(I)); - // Print call instruction - printFunctionCall(Inst->getOperand(0),Inst); - // Save function result and leave "try" block - printValueSave(Inst); - printSimpleInstruction("leave",Label.c_str()); - Out << "}\n"; - Out << "catch [mscorlib]System.Exception {\n"; - // Redirect to unwind block - printSimpleInstruction("pop"); - printBranchToBlock(Inst->getParent(),NULL,Inst->getUnwindDest()); - Out << "}\n" << Label << ":\n"; - // Redirect to continue block - printBranchToBlock(Inst->getParent(),NULL,Inst->getNormalDest()); -} - - -void MSILWriter::printSwitchInstruction(const SwitchInst* Inst) { - // FIXME: Emulate with IL "switch" instruction - // Emulate = if () else if () else if () else ... - for (unsigned int I = 1, E = Inst->getNumCases(); I!=E; ++I) { - printValueLoad(Inst->getCondition()); - printValueLoad(Inst->getCaseValue(I)); - printSimpleInstruction("ceq"); - // Condition jump to successor block - printBranchToBlock(Inst->getParent(),Inst->getSuccessor(I),NULL); - } - // Jump to default block - printBranchToBlock(Inst->getParent(),NULL,Inst->getDefaultDest()); -} - - -void MSILWriter::printVAArgInstruction(const VAArgInst* Inst) { - printIndirectLoad(Inst->getOperand(0)); - printSimpleInstruction("call", - "instance typedref [mscorlib]System.ArgIterator::GetNextArg()"); - printSimpleInstruction("refanyval","void*"); - std::string Name = - "ldind."+getTypePostfix(PointerType::getUnqual( - IntegerType::get(Inst->getContext(), 8)),false); - printSimpleInstruction(Name.c_str()); -} - - -void MSILWriter::printAllocaInstruction(const AllocaInst* Inst) { - uint64_t Size = TD->getTypeAllocSize(Inst->getAllocatedType()); - // Constant optimization. - if (const ConstantInt* CInt = dyn_cast(Inst->getOperand(0))) { - printPtrLoad(CInt->getZExtValue()*Size); - } else { - printPtrLoad(Size); - printValueLoad(Inst->getOperand(0)); - printSimpleInstruction("mul"); - } - printSimpleInstruction("localloc"); -} - - -void MSILWriter::printInstruction(const Instruction* Inst) { - const Value *Left = 0, *Right = 0; - if (Inst->getNumOperands()>=1) Left = Inst->getOperand(0); - if (Inst->getNumOperands()>=2) Right = Inst->getOperand(1); - // Print instruction - // FIXME: "ShuffleVector","ExtractElement","InsertElement" support. - switch (Inst->getOpcode()) { - // Terminator - case Instruction::Ret: - if (Inst->getNumOperands()) { - printValueLoad(Left); - printSimpleInstruction("ret"); - } else - printSimpleInstruction("ret"); - break; - case Instruction::Br: - printBranchInstruction(cast(Inst)); - break; - // Binary - case Instruction::Add: - case Instruction::FAdd: - printBinaryInstruction("add",Left,Right); - break; - case Instruction::Sub: - case Instruction::FSub: - printBinaryInstruction("sub",Left,Right); - break; - case Instruction::Mul: - case Instruction::FMul: - printBinaryInstruction("mul",Left,Right); - break; - case Instruction::UDiv: - printBinaryInstruction("div.un",Left,Right); - break; - case Instruction::SDiv: - case Instruction::FDiv: - printBinaryInstruction("div",Left,Right); - break; - case Instruction::URem: - printBinaryInstruction("rem.un",Left,Right); - break; - case Instruction::SRem: - case Instruction::FRem: - printBinaryInstruction("rem",Left,Right); - break; - // Binary Condition - case Instruction::ICmp: - printICmpInstruction(cast(Inst)->getPredicate(),Left,Right); - break; - case Instruction::FCmp: - printFCmpInstruction(cast(Inst)->getPredicate(),Left,Right); - break; - // Bitwise Binary - case Instruction::And: - printBinaryInstruction("and",Left,Right); - break; - case Instruction::Or: - printBinaryInstruction("or",Left,Right); - break; - case Instruction::Xor: - printBinaryInstruction("xor",Left,Right); - break; - case Instruction::Shl: - printValueLoad(Left); - printValueLoad(Right); - printSimpleInstruction("conv.i4"); - printSimpleInstruction("shl"); - break; - case Instruction::LShr: - printValueLoad(Left); - printValueLoad(Right); - printSimpleInstruction("conv.i4"); - printSimpleInstruction("shr.un"); - break; - case Instruction::AShr: - printValueLoad(Left); - printValueLoad(Right); - printSimpleInstruction("conv.i4"); - printSimpleInstruction("shr"); - break; - case Instruction::Select: - printSelectInstruction(Inst->getOperand(0),Inst->getOperand(1),Inst->getOperand(2)); - break; - case Instruction::Load: - printIndirectLoad(Inst->getOperand(0)); - break; - case Instruction::Store: - printIndirectSave(Inst->getOperand(1), Inst->getOperand(0)); - break; - case Instruction::SExt: - printCastInstruction(Inst->getOpcode(),Left, - cast(Inst)->getDestTy(), - cast(Inst)->getSrcTy()); - break; - case Instruction::Trunc: - case Instruction::ZExt: - case Instruction::FPTrunc: - case Instruction::FPExt: - case Instruction::UIToFP: - case Instruction::SIToFP: - case Instruction::FPToUI: - case Instruction::FPToSI: - case Instruction::PtrToInt: - case Instruction::IntToPtr: - case Instruction::BitCast: - printCastInstruction(Inst->getOpcode(),Left, - cast(Inst)->getDestTy()); - break; - case Instruction::GetElementPtr: - printGepInstruction(Inst->getOperand(0),gep_type_begin(Inst), - gep_type_end(Inst)); - break; - case Instruction::Call: - printCallInstruction(cast(Inst)); - break; - case Instruction::Invoke: - printInvokeInstruction(cast(Inst)); - break; - case Instruction::Unwind: - printSimpleInstruction("newobj", - "instance void [mscorlib]System.Exception::.ctor()"); - printSimpleInstruction("throw"); - break; - case Instruction::Switch: - printSwitchInstruction(cast(Inst)); - break; - case Instruction::Alloca: - printAllocaInstruction(cast(Inst)); - break; - case Instruction::Unreachable: - printSimpleInstruction("ldstr", "\"Unreachable instruction\""); - printSimpleInstruction("newobj", - "instance void [mscorlib]System.Exception::.ctor(string)"); - printSimpleInstruction("throw"); - break; - case Instruction::VAArg: - printVAArgInstruction(cast(Inst)); - break; - default: - errs() << "Instruction = " << Inst->getName() << '\n'; - llvm_unreachable("Unsupported instruction"); - } -} - - -void MSILWriter::printLoop(const Loop* L) { - Out << getLabelName(L->getHeader()->getName()) << ":\n"; - const std::vector& blocks = L->getBlocks(); - for (unsigned I = 0, E = blocks.size(); I!=E; I++) { - BasicBlock* BB = blocks[I]; - Loop* BBLoop = LInfo->getLoopFor(BB); - if (BBLoop == L) - printBasicBlock(BB); - else if (BB==BBLoop->getHeader() && BBLoop->getParentLoop()==L) - printLoop(BBLoop); - } - printSimpleInstruction("br",getLabelName(L->getHeader()->getName()).c_str()); -} - - -void MSILWriter::printBasicBlock(const BasicBlock* BB) { - Out << getLabelName(BB) << ":\n"; - for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I!=E; ++I) { - const Instruction* Inst = I; - // Comment llvm original instruction - // Out << "\n//" << *Inst << "\n"; - // Do not handle PHI instruction in current block - if (Inst->getOpcode()==Instruction::PHI) continue; - // Print instruction - printInstruction(Inst); - // Save result - if (Inst->getType()!=Type::getVoidTy(BB->getContext())) { - // Do not save value after invoke, it done in "try" block - if (Inst->getOpcode()==Instruction::Invoke) continue; - printValueSave(Inst); - } - } -} - - -void MSILWriter::printLocalVariables(const Function& F) { - std::string Name; - const Type* Ty = NULL; - std::set Printed; - const Value* VaList = NULL; - unsigned StackDepth = 8; - // Find local variables - for (const_inst_iterator I = inst_begin(&F), E = inst_end(&F); I!=E; ++I) { - if (I->getOpcode()==Instruction::Call || - I->getOpcode()==Instruction::Invoke) { - // Test stack depth. - if (StackDepthgetNumOperands()) - StackDepth = I->getNumOperands(); - } - const AllocaInst* AI = dyn_cast(&*I); - if (AI && !isa(AI)) { - // Local variable allocation. - Ty = PointerType::getUnqual(AI->getAllocatedType()); - Name = getValueName(AI); - Out << "\t.locals (" << getTypeName(Ty) << Name << ")\n"; - } else if (I->getType()!=Type::getVoidTy(F.getContext())) { - // Operation result. - Ty = I->getType(); - Name = getValueName(&*I); - Out << "\t.locals (" << getTypeName(Ty) << Name << ")\n"; - } - // Test on 'va_list' variable - bool isVaList = false; - if (const VAArgInst* VaInst = dyn_cast(&*I)) { - // "va_list" as "va_arg" instruction operand. - isVaList = true; - VaList = VaInst->getOperand(0); - } else if (const IntrinsicInst* Inst = dyn_cast(&*I)) { - // "va_list" as intrinsic function operand. - switch (Inst->getIntrinsicID()) { - case Intrinsic::vastart: - case Intrinsic::vaend: - case Intrinsic::vacopy: - isVaList = true; - VaList = Inst->getArgOperand(0); - break; - default: - isVaList = false; - } - } - // Print "va_list" variable. - if (isVaList && Printed.insert(VaList).second) { - Name = getValueName(VaList); - Name.insert(Name.length()-1,"$valist"); - Out << "\t.locals (valuetype [mscorlib]System.ArgIterator " - << Name << ")\n"; - } - } - printSimpleInstruction(".maxstack",utostr(StackDepth*2).c_str()); -} - - -void MSILWriter::printFunctionBody(const Function& F) { - // Print body - for (Function::const_iterator I = F.begin(), E = F.end(); I!=E; ++I) { - if (Loop *L = LInfo->getLoopFor(I)) { - if (L->getHeader()==I && L->getParentLoop()==0) - printLoop(L); - } else { - printBasicBlock(I); - } - } -} - - -void MSILWriter::printConstantExpr(const ConstantExpr* CE) { - const Value *left = 0, *right = 0; - if (CE->getNumOperands()>=1) left = CE->getOperand(0); - if (CE->getNumOperands()>=2) right = CE->getOperand(1); - // Print instruction - switch (CE->getOpcode()) { - case Instruction::Trunc: - case Instruction::ZExt: - case Instruction::SExt: - case Instruction::FPTrunc: - case Instruction::FPExt: - case Instruction::UIToFP: - case Instruction::SIToFP: - case Instruction::FPToUI: - case Instruction::FPToSI: - case Instruction::PtrToInt: - case Instruction::IntToPtr: - case Instruction::BitCast: - printCastInstruction(CE->getOpcode(),left,CE->getType()); - break; - case Instruction::GetElementPtr: - printGepInstruction(CE->getOperand(0),gep_type_begin(CE),gep_type_end(CE)); - break; - case Instruction::ICmp: - printICmpInstruction(CE->getPredicate(),left,right); - break; - case Instruction::FCmp: - printFCmpInstruction(CE->getPredicate(),left,right); - break; - case Instruction::Select: - printSelectInstruction(CE->getOperand(0),CE->getOperand(1),CE->getOperand(2)); - break; - case Instruction::Add: - case Instruction::FAdd: - printBinaryInstruction("add",left,right); - break; - case Instruction::Sub: - case Instruction::FSub: - printBinaryInstruction("sub",left,right); - break; - case Instruction::Mul: - case Instruction::FMul: - printBinaryInstruction("mul",left,right); - break; - case Instruction::UDiv: - printBinaryInstruction("div.un",left,right); - break; - case Instruction::SDiv: - case Instruction::FDiv: - printBinaryInstruction("div",left,right); - break; - case Instruction::URem: - printBinaryInstruction("rem.un",left,right); - break; - case Instruction::SRem: - case Instruction::FRem: - printBinaryInstruction("rem",left,right); - break; - case Instruction::And: - printBinaryInstruction("and",left,right); - break; - case Instruction::Or: - printBinaryInstruction("or",left,right); - break; - case Instruction::Xor: - printBinaryInstruction("xor",left,right); - break; - case Instruction::Shl: - printBinaryInstruction("shl",left,right); - break; - case Instruction::LShr: - printBinaryInstruction("shr.un",left,right); - break; - case Instruction::AShr: - printBinaryInstruction("shr",left,right); - break; - default: - errs() << "Expression = " << *CE << "\n"; - llvm_unreachable("Invalid constant expression"); - } -} - - -void MSILWriter::printStaticInitializerList() { - // List of global variables with uninitialized fields. - for (std::map >::iterator - VarI = StaticInitList.begin(), VarE = StaticInitList.end(); VarI!=VarE; - ++VarI) { - const std::vector& InitList = VarI->second; - if (InitList.empty()) continue; - // For each uninitialized field. - for (std::vector::const_iterator I = InitList.begin(), - E = InitList.end(); I!=E; ++I) { - if (const ConstantExpr *CE = dyn_cast(I->constant)) { - // Out << "\n// Init " << getValueName(VarI->first) << ", offset " << - // utostr(I->offset) << ", type "<< *I->constant->getType() << "\n\n"; - // Load variable address - printValueLoad(VarI->first); - // Add offset - if (I->offset!=0) { - printPtrLoad(I->offset); - printSimpleInstruction("add"); - } - // Load value - printConstantExpr(CE); - // Save result at offset - std::string postfix = getTypePostfix(CE->getType(),true); - if (*postfix.begin()=='u') *postfix.begin() = 'i'; - postfix = "stind."+postfix; - printSimpleInstruction(postfix.c_str()); - } else { - errs() << "Constant = " << *I->constant << '\n'; - llvm_unreachable("Invalid static initializer"); - } - } - } -} - - -void MSILWriter::printFunction(const Function& F) { - bool isSigned = F.paramHasAttr(0, Attribute::SExt); - Out << "\n.method static "; - Out << (F.hasLocalLinkage() ? "private " : "public "); - if (F.isVarArg()) Out << "vararg "; - Out << getTypeName(F.getReturnType(),isSigned) << - getConvModopt(F.getCallingConv()) << getValueName(&F) << '\n'; - // Arguments - Out << "\t("; - unsigned ArgIdx = 1; - for (Function::const_arg_iterator I = F.arg_begin(), E = F.arg_end(); I!=E; - ++I, ++ArgIdx) { - isSigned = F.paramHasAttr(ArgIdx, Attribute::SExt); - if (I!=F.arg_begin()) Out << ", "; - Out << getTypeName(I->getType(),isSigned) << getValueName(I); - } - Out << ") cil managed\n"; - // Body - Out << "{\n"; - printLocalVariables(F); - printFunctionBody(F); - Out << "}\n"; -} - - -void MSILWriter::printDeclarations(const TypeSymbolTable& ST) { - std::string Name; - std::set Printed; - for (std::set::const_iterator - UI = UsedTypes->begin(), UE = UsedTypes->end(); UI!=UE; ++UI) { - const Type* Ty = *UI; - if (Ty->isArrayTy() || Ty->isVectorTy() || Ty->isStructTy()) - Name = getTypeName(Ty, false, true); - // Type with no need to declare. - else continue; - // Print not duplicated type - if (Printed.insert(Ty).second) { - Out << ".class value explicit ansi sealed '" << Name << "'"; - Out << " { .pack " << 1 << " .size " << TD->getTypeAllocSize(Ty); - Out << " }\n\n"; - } - } -} - - -unsigned int MSILWriter::getBitWidth(const Type* Ty) { - unsigned int N = Ty->getPrimitiveSizeInBits(); - assert(N!=0 && "Invalid type in getBitWidth()"); - switch (N) { - case 1: - case 8: - case 16: - case 32: - case 64: - return N; - default: - errs() << "Bits = " << N << '\n'; - llvm_unreachable("Unsupported integer width"); - } - return 0; // Not reached -} - - -void MSILWriter::printStaticConstant(const Constant* C, uint64_t& Offset) { - uint64_t TySize = 0; - const Type* Ty = C->getType(); - // Print zero initialized constant. - if (isa(C) || C->isNullValue()) { - TySize = TD->getTypeAllocSize(C->getType()); - Offset += TySize; - Out << "int8 (0) [" << TySize << "]"; - return; - } - // Print constant initializer - switch (Ty->getTypeID()) { - case Type::IntegerTyID: { - TySize = TD->getTypeAllocSize(Ty); - const ConstantInt* Int = cast(C); - Out << getPrimitiveTypeName(Ty,true) << "(" << Int->getSExtValue() << ")"; - break; - } - case Type::FloatTyID: - case Type::DoubleTyID: { - TySize = TD->getTypeAllocSize(Ty); - const ConstantFP* FP = cast(C); - if (Ty->getTypeID() == Type::FloatTyID) - Out << "int32 (" << - (uint32_t)FP->getValueAPF().bitcastToAPInt().getZExtValue() << ')'; - else - Out << "int64 (" << - FP->getValueAPF().bitcastToAPInt().getZExtValue() << ')'; - break; - } - case Type::ArrayTyID: - case Type::VectorTyID: - case Type::StructTyID: - for (unsigned I = 0, E = C->getNumOperands(); I(C->getOperand(I)), Offset); - } - break; - case Type::PointerTyID: - TySize = TD->getTypeAllocSize(C->getType()); - // Initialize with global variable address - if (const GlobalVariable *G = dyn_cast(C)) { - std::string name = getValueName(G); - Out << "&(" << name.insert(name.length()-1,"$data") << ")"; - } else { - // Dynamic initialization - if (!isa(C) && !C->isNullValue()) - InitListPtr->push_back(StaticInitializer(C,Offset)); - // Null pointer initialization - if (TySize==4) Out << "int32 (0)"; - else if (TySize==8) Out << "int64 (0)"; - else llvm_unreachable("Invalid pointer size"); - } - break; - default: - errs() << "TypeID = " << Ty->getTypeID() << '\n'; - llvm_unreachable("Invalid type in printStaticConstant()"); - } - // Increase offset. - Offset += TySize; -} - - -void MSILWriter::printStaticInitializer(const Constant* C, - const std::string& Name) { - switch (C->getType()->getTypeID()) { - case Type::IntegerTyID: - case Type::FloatTyID: - case Type::DoubleTyID: - Out << getPrimitiveTypeName(C->getType(), false); - break; - case Type::ArrayTyID: - case Type::VectorTyID: - case Type::StructTyID: - case Type::PointerTyID: - Out << getTypeName(C->getType()); - break; - default: - errs() << "Type = " << *C << "\n"; - llvm_unreachable("Invalid constant type"); - } - // Print initializer - std::string label = Name; - label.insert(label.length()-1,"$data"); - Out << Name << " at " << label << '\n'; - Out << ".data " << label << " = {\n"; - uint64_t offset = 0; - printStaticConstant(C,offset); - Out << "\n}\n\n"; -} - - -void MSILWriter::printVariableDefinition(const GlobalVariable* G) { - const Constant* C = G->getInitializer(); - if (C->isNullValue() || isa(C) || isa(C)) - InitListPtr = 0; - else - InitListPtr = &StaticInitList[G]; - printStaticInitializer(C,getValueName(G)); -} - - -void MSILWriter::printGlobalVariables() { - if (ModulePtr->global_empty()) return; - Module::global_iterator I,E; - for (I = ModulePtr->global_begin(), E = ModulePtr->global_end(); I!=E; ++I) { - // Variable definition - Out << ".field static " << (I->isDeclaration() ? "public " : - "private "); - if (I->isDeclaration()) { - Out << getTypeName(I->getType()) << getValueName(&*I) << "\n\n"; - } else - printVariableDefinition(&*I); - } -} - - -const char* MSILWriter::getLibraryName(const Function* F) { - return getLibraryForSymbol(F->getName(), true, F->getCallingConv()); -} - - -const char* MSILWriter::getLibraryName(const GlobalVariable* GV) { - return getLibraryForSymbol(GV->getName(), false, CallingConv::C); -} - - -const char* MSILWriter::getLibraryForSymbol(StringRef Name, bool isFunction, - CallingConv::ID CallingConv) { - // TODO: Read *.def file with function and libraries definitions. - return "MSVCRT.DLL"; -} - - -void MSILWriter::printExternals() { - Module::const_iterator I,E; - // Functions. - for (I=ModulePtr->begin(),E=ModulePtr->end(); I!=E; ++I) { - // Skip intrisics - if (I->isIntrinsic()) continue; - if (I->isDeclaration()) { - const Function* F = I; - std::string Name = getConvModopt(F->getCallingConv())+getValueName(F); - std::string Sig = - getCallSignature(cast(F->getFunctionType()), NULL, Name); - Out << ".method static hidebysig pinvokeimpl(\"" - << getLibraryName(F) << "\")\n\t" << Sig << " preservesig {}\n\n"; - } - } - // External variables and static initialization. - Out << - ".method public hidebysig static pinvokeimpl(\"KERNEL32.DLL\" ansi winapi)" - " native int LoadLibrary(string) preservesig {}\n" - ".method public hidebysig static pinvokeimpl(\"KERNEL32.DLL\" ansi winapi)" - " native int GetProcAddress(native int, string) preservesig {}\n"; - Out << - ".method private static void* $MSIL_Import(string lib,string sym)\n" - " managed cil\n{\n" - "\tldarg\tlib\n" - "\tcall\tnative int LoadLibrary(string)\n" - "\tldarg\tsym\n" - "\tcall\tnative int GetProcAddress(native int,string)\n" - "\tdup\n" - "\tbrtrue\tL_01\n" - "\tldstr\t\"Can no import variable\"\n" - "\tnewobj\tinstance void [mscorlib]System.Exception::.ctor(string)\n" - "\tthrow\n" - "L_01:\n" - "\tret\n" - "}\n\n" - ".method static private void $MSIL_Init() managed cil\n{\n"; - printStaticInitializerList(); - // Foreach global variable. - for (Module::global_iterator I = ModulePtr->global_begin(), - E = ModulePtr->global_end(); I!=E; ++I) { - if (!I->isDeclaration() || !I->hasDLLImportLinkage()) continue; - // Use "LoadLibrary"/"GetProcAddress" to recive variable address. - std::string Tmp = getTypeName(I->getType())+getValueName(&*I); - printSimpleInstruction("ldsflda",Tmp.c_str()); - Out << "\tldstr\t\"" << getLibraryName(&*I) << "\"\n"; - Out << "\tldstr\t\"" << I->getName() << "\"\n"; - printSimpleInstruction("call","void* $MSIL_Import(string,string)"); - printIndirectSave(I->getType()); - } - printSimpleInstruction("ret"); - Out << "}\n\n"; -} - - -//===----------------------------------------------------------------------===// -// External Interface declaration -//===----------------------------------------------------------------------===// - -bool MSILTarget::addPassesToEmitFile(PassManagerBase &PM, - formatted_raw_ostream &o, - CodeGenFileType FileType, - CodeGenOpt::Level OptLevel, - bool DisableVerify) -{ - if (FileType != TargetMachine::CGFT_AssemblyFile) return true; - MSILWriter* Writer = new MSILWriter(o); - PM.add(createGCLoweringPass()); - // FIXME: Handle switch through native IL instruction "switch" - PM.add(createLowerSwitchPass()); - PM.add(createCFGSimplificationPass()); - PM.add(new MSILModule(Writer->UsedTypes,Writer->TD)); - PM.add(Writer); - PM.add(createGCInfoDeleter()); - return false; -} diff --git a/lib/Target/MSIL/MSILWriter.h b/lib/Target/MSIL/MSILWriter.h deleted file mode 100644 index 92a3abe..0000000 --- a/lib/Target/MSIL/MSILWriter.h +++ /dev/null @@ -1,258 +0,0 @@ -//===-- MSILWriter.h - TargetMachine for the MSIL ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the MSILWriter that is used by the MSIL. -// -//===----------------------------------------------------------------------===// -#ifndef MSILWRITER_H -#define MSILWRITER_H - -#include "llvm/CallingConv.h" -#include "llvm/Constants.h" -#include "llvm/Module.h" -#include "llvm/Instructions.h" -#include "llvm/IntrinsicInst.h" -#include "llvm/Pass.h" -#include "llvm/PassManager.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Analysis/FindUsedTypes.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/Support/GetElementPtrTypeIterator.h" -#include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetMachine.h" - -namespace llvm { - extern Target TheMSILTarget; - - class MSILModule : public ModulePass { - Module *ModulePtr; - const std::set*& UsedTypes; - const TargetData*& TD; - - public: - static char ID; - MSILModule(const std::set*& _UsedTypes, - const TargetData*& _TD) - : ModulePass(&ID), UsedTypes(_UsedTypes), TD(_TD) {} - - void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - AU.addRequired(); - } - - virtual const char *getPassName() const { - return "MSIL backend definitions"; - } - - virtual bool runOnModule(Module &M); - - }; - - class MSILWriter : public FunctionPass { - struct StaticInitializer { - const Constant* constant; - uint64_t offset; - - StaticInitializer() - : constant(0), offset(0) {} - - StaticInitializer(const Constant* _constant, uint64_t _offset) - : constant(_constant), offset(_offset) {} - }; - - uint64_t UniqID; - - uint64_t getUniqID() { - return ++UniqID; - } - - public: - formatted_raw_ostream &Out; - Module* ModulePtr; - const TargetData* TD; - LoopInfo *LInfo; - std::vector* InitListPtr; - std::map > - StaticInitList; - const std::set* UsedTypes; - static char ID; - DenseMap AnonValueNumbers; - unsigned NextAnonValueNumber; - - MSILWriter(formatted_raw_ostream &o) : FunctionPass(&ID), Out(o), - NextAnonValueNumber(0) { - UniqID = 0; - } - - enum ValueType { - UndefVT, - GlobalVT, - InternalVT, - ArgumentVT, - LocalVT, - ConstVT, - ConstExprVT - }; - - bool isVariable(ValueType V) { - return V==GlobalVT || V==InternalVT || V==ArgumentVT || V==LocalVT; - } - - bool isConstValue(ValueType V) { - return V==ConstVT || V==ConstExprVT; - } - - virtual const char *getPassName() const { return "MSIL backend"; } - - void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - AU.setPreservesAll(); - } - - bool runOnFunction(Function &F); - - virtual bool doInitialization(Module &M); - - virtual bool doFinalization(Module &M); - - void printModuleStartup(); - - bool isZeroValue(const Value* V); - - std::string getValueName(const Value* V); - - std::string getLabelName(const Value* V); - - std::string getLabelName(const std::string& Name); - - std::string getConvModopt(CallingConv::ID CallingConvID); - - std::string getArrayTypeName(Type::TypeID TyID, const Type* Ty); - - std::string getPrimitiveTypeName(const Type* Ty, bool isSigned); - - std::string getFunctionTypeName(const Type* Ty); - - std::string getPointerTypeName(const Type* Ty); - - std::string getTypeName(const Type* Ty, bool isSigned = false, - bool isNested = false); - - ValueType getValueLocation(const Value* V); - - std::string getTypePostfix(const Type* Ty, bool Expand, - bool isSigned = false); - - void printConvToPtr(); - - void printPtrLoad(uint64_t N); - - void printValuePtrLoad(const Value* V); - - void printConstLoad(const Constant* C); - - void printValueLoad(const Value* V); - - void printValueSave(const Value* V); - - void printBinaryInstruction(const char* Name, const Value* Left, - const Value* Right); - - void printSimpleInstruction(const char* Inst, const char* Operand = NULL); - - void printPHICopy(const BasicBlock* Src, const BasicBlock* Dst); - - void printBranchToBlock(const BasicBlock* CurrBB, - const BasicBlock* TrueBB, - const BasicBlock* FalseBB); - - void printBranchInstruction(const BranchInst* Inst); - - void printSelectInstruction(const Value* Cond, const Value* VTrue, - const Value* VFalse); - - void printIndirectLoad(const Value* V); - - void printIndirectSave(const Value* Ptr, const Value* Val); - - void printIndirectSave(const Type* Ty); - - void printCastInstruction(unsigned int Op, const Value* V, - const Type* Ty, const Type* SrcTy=0); - - void printGepInstruction(const Value* V, gep_type_iterator I, - gep_type_iterator E); - - std::string getCallSignature(const FunctionType* Ty, - const Instruction* Inst, - std::string Name); - - void printFunctionCall(const Value* FnVal, const Instruction* Inst); - - void printIntrinsicCall(const IntrinsicInst* Inst); - - void printCallInstruction(const Instruction* Inst); - - void printICmpInstruction(unsigned Predicate, const Value* Left, - const Value* Right); - - void printFCmpInstruction(unsigned Predicate, const Value* Left, - const Value* Right); - - void printInvokeInstruction(const InvokeInst* Inst); - - void printSwitchInstruction(const SwitchInst* Inst); - - void printVAArgInstruction(const VAArgInst* Inst); - - void printAllocaInstruction(const AllocaInst* Inst); - - void printInstruction(const Instruction* Inst); - - void printLoop(const Loop* L); - - void printBasicBlock(const BasicBlock* BB); - - void printLocalVariables(const Function& F); - - void printFunctionBody(const Function& F); - - void printConstantExpr(const ConstantExpr* CE); - - void printStaticInitializerList(); - - void printFunction(const Function& F); - - void printDeclarations(const TypeSymbolTable& ST); - - unsigned int getBitWidth(const Type* Ty); - - void printStaticConstant(const Constant* C, uint64_t& Offset); - - void printStaticInitializer(const Constant* C, const std::string& Name); - - void printVariableDefinition(const GlobalVariable* G); - - void printGlobalVariables(); - - const char* getLibraryName(const Function* F); - - const char* getLibraryName(const GlobalVariable* GV); - - const char* getLibraryForSymbol(StringRef Name, bool isFunction, - CallingConv::ID CallingConv); - - void printExternals(); - }; - -} - -#endif - diff --git a/lib/Target/MSIL/Makefile b/lib/Target/MSIL/Makefile deleted file mode 100644 index 70eadb3..0000000 --- a/lib/Target/MSIL/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -##===- lib/Target/MSIL/Makefile ----------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. -LIBRARYNAME = LLVMMSIL -DIRS = TargetInfo - -include $(LEVEL)/Makefile.common - -CompileCommonOpts := $(CompileCommonOpts) -Wno-format diff --git a/lib/Target/MSIL/README.TXT b/lib/Target/MSIL/README.TXT deleted file mode 100644 index d797c71..0000000 --- a/lib/Target/MSIL/README.TXT +++ /dev/null @@ -1,26 +0,0 @@ -//===---------------------------------------------------------------------===// - -Vector instructions support. - -ShuffleVector -ExtractElement -InsertElement - -//===---------------------------------------------------------------------===// - -Add "OpaqueType" type. - -//===---------------------------------------------------------------------===// - -"switch" instruction emulation with CLI "switch" instruction. - -//===---------------------------------------------------------------------===// - -Write linker for external function, because function export need to know -dynamic library where function located. - -.method static hidebysig pinvokeimpl("msvcrt.dll" cdecl) - void free(void*) preservesig {} - - - diff --git a/lib/Target/MSIL/TargetInfo/CMakeLists.txt b/lib/Target/MSIL/TargetInfo/CMakeLists.txt deleted file mode 100644 index 9f0c3a0..0000000 --- a/lib/Target/MSIL/TargetInfo/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. ) - -add_llvm_library(LLVMMSILInfo - MSILTargetInfo.cpp - ) - diff --git a/lib/Target/MSIL/TargetInfo/MSILTargetInfo.cpp b/lib/Target/MSIL/TargetInfo/MSILTargetInfo.cpp deleted file mode 100644 index dfd4281..0000000 --- a/lib/Target/MSIL/TargetInfo/MSILTargetInfo.cpp +++ /dev/null @@ -1,26 +0,0 @@ -//===-- MSILTargetInfo.cpp - MSIL Target Implementation -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "MSILWriter.h" -#include "llvm/Module.h" -#include "llvm/Target/TargetRegistry.h" -using namespace llvm; - -Target llvm::TheMSILTarget; - -static unsigned MSIL_TripleMatchQuality(const std::string &TT) { - // This class always works, but shouldn't be the default in most cases. - return 1; -} - -extern "C" void LLVMInitializeMSILTargetInfo() { - TargetRegistry::RegisterTarget(TheMSILTarget, "msil", - "MSIL backend", - &MSIL_TripleMatchQuality); -} diff --git a/lib/Target/MSIL/TargetInfo/Makefile b/lib/Target/MSIL/TargetInfo/Makefile deleted file mode 100644 index 30b0950..0000000 --- a/lib/Target/MSIL/TargetInfo/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -##===- lib/Target/MSIL/TargetInfo/Makefile -----------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -LEVEL = ../../../.. -LIBRARYNAME = LLVMMSILInfo - -# Hack: we need to include 'main' target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. - -include $(LEVEL)/Makefile.common diff --git a/lib/Target/MSP430/MSP430BranchSelector.cpp b/lib/Target/MSP430/MSP430BranchSelector.cpp index 68cb342..bd64443 100644 --- a/lib/Target/MSP430/MSP430BranchSelector.cpp +++ b/lib/Target/MSP430/MSP430BranchSelector.cpp @@ -10,7 +10,7 @@ // This file contains a pass that scans a machine function to determine which // conditional branches need more than 10 bits of displacement to reach their // target basic block. It does this in two passes; a calculation of basic block -// positions pass, and a branch psuedo op to machine branch opcode pass. This +// positions pass, and a branch pseudo op to machine branch opcode pass. This // pass should be run last, just before the assembly printer. // //===----------------------------------------------------------------------===// @@ -30,7 +30,7 @@ STATISTIC(NumExpanded, "Number of branches expanded to long format"); namespace { struct MSP430BSel : public MachineFunctionPass { static char ID; - MSP430BSel() : MachineFunctionPass(&ID) {} + MSP430BSel() : MachineFunctionPass(ID) {} /// BlockSizes - The sizes of the basic blocks in the function. std::vector BlockSizes; @@ -52,7 +52,8 @@ FunctionPass *llvm::createMSP430BranchSelectionPass() { } bool MSP430BSel::runOnMachineFunction(MachineFunction &Fn) { - const TargetInstrInfo *TII = Fn.getTarget().getInstrInfo(); + const MSP430InstrInfo *TII = + static_cast(Fn.getTarget().getInstrInfo()); // Give the blocks of the function a dense, in-order, numbering. Fn.RenumberBlocks(); BlockSizes.resize(Fn.getNumBlockIDs()); diff --git a/lib/Target/MSP430/MSP430InstrInfo.cpp b/lib/Target/MSP430/MSP430InstrInfo.cpp index df28d07..bfab844 100644 --- a/lib/Target/MSP430/MSP430InstrInfo.cpp +++ b/lib/Target/MSP430/MSP430InstrInfo.cpp @@ -100,27 +100,6 @@ void MSP430InstrInfo::copyPhysReg(MachineBasicBlock &MBB, } bool -MSP430InstrInfo::isMoveInstr(const MachineInstr& MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const { - SrcSubIdx = DstSubIdx = 0; // No sub-registers yet. - - switch (MI.getOpcode()) { - default: - return false; - case MSP430::MOV8rr: - case MSP430::MOV16rr: - assert(MI.getNumOperands() >= 2 && - MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - "invalid register-register move instruction"); - SrcReg = MI.getOperand(1).getReg(); - DstReg = MI.getOperand(0).getReg(); - return true; - } -} - -bool MSP430InstrInfo::spillCalleeSavedRegisters(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const std::vector &CSI, @@ -361,7 +340,7 @@ unsigned MSP430InstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const { switch (Desc.getOpcode()) { default: assert(0 && "Unknown instruction size!"); - case TargetOpcode::DBG_LABEL: + case TargetOpcode::PROLOG_LABEL: case TargetOpcode::EH_LABEL: case TargetOpcode::IMPLICIT_DEF: case TargetOpcode::KILL: diff --git a/lib/Target/MSP430/MSP430InstrInfo.h b/lib/Target/MSP430/MSP430InstrInfo.h index ebbda1a..49ccc03 100644 --- a/lib/Target/MSP430/MSP430InstrInfo.h +++ b/lib/Target/MSP430/MSP430InstrInfo.h @@ -54,10 +54,6 @@ public: unsigned DestReg, unsigned SrcReg, bool KillSrc) const; - bool isMoveInstr(const MachineInstr& MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const; - virtual void storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, unsigned SrcReg, bool isKill, diff --git a/lib/Target/MSP430/MSP430RegisterInfo.cpp b/lib/Target/MSP430/MSP430RegisterInfo.cpp index 608ca49..3c3fa73 100644 --- a/lib/Target/MSP430/MSP430RegisterInfo.cpp +++ b/lib/Target/MSP430/MSP430RegisterInfo.cpp @@ -101,7 +101,7 @@ bool MSP430RegisterInfo::hasFP(const MachineFunction &MF) const { MFI->isFrameAddressTaken()); } -bool MSP430RegisterInfo::hasReservedCallFrame(MachineFunction &MF) const { +bool MSP430RegisterInfo::hasReservedCallFrame(const MachineFunction &MF) const { return !MF.getFrameInfo()->hasVarSizedObjects(); } @@ -163,10 +163,9 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MBB.erase(I); } -unsigned +void MSP430RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value, - RegScavenger *RS) const { + int SPAdj, RegScavenger *RS) const { assert(SPAdj == 0 && "Unexpected"); unsigned i = 0; @@ -204,7 +203,7 @@ MSP430RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, MI.getOperand(i).ChangeToRegister(BasePtr, false); if (Offset == 0) - return 0; + return; // We need to materialize the offset via add instruction. unsigned DstReg = MI.getOperand(0).getReg(); @@ -215,12 +214,11 @@ MSP430RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, BuildMI(MBB, llvm::next(II), dl, TII.get(MSP430::ADD16ri), DstReg) .addReg(DstReg).addImm(Offset); - return 0; + return; } MI.getOperand(i).ChangeToRegister(BasePtr, false); MI.getOperand(i+1).ChangeToImmediate(Offset); - return 0; } void diff --git a/lib/Target/MSP430/MSP430RegisterInfo.h b/lib/Target/MSP430/MSP430RegisterInfo.h index 6e58d31..4d2795b 100644 --- a/lib/Target/MSP430/MSP430RegisterInfo.h +++ b/lib/Target/MSP430/MSP430RegisterInfo.h @@ -40,15 +40,14 @@ public: const TargetRegisterClass* getPointerRegClass(unsigned Kind = 0) const; bool hasFP(const MachineFunction &MF) const; - bool hasReservedCallFrame(MachineFunction &MF) const; + bool hasReservedCallFrame(const MachineFunction &MF) const; void eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; - unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value = NULL, - RegScavenger *RS = NULL) const; + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; void emitPrologue(MachineFunction &MF) const; void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; diff --git a/lib/Target/Mangler.cpp b/lib/Target/Mangler.cpp index 2037a91..49efe75 100644 --- a/lib/Target/Mangler.cpp +++ b/lib/Target/Mangler.cpp @@ -180,7 +180,8 @@ void Mangler::getNameWithPrefix(SmallVectorImpl &OutName, ManglerPrefixTy PrefixTy = Mangler::Default; if (GV->hasPrivateLinkage() || isImplicitlyPrivate) PrefixTy = Mangler::Private; - else if (GV->hasLinkerPrivateLinkage() || GV->hasLinkerPrivateWeakLinkage()) + else if (GV->hasLinkerPrivateLinkage() || GV->hasLinkerPrivateWeakLinkage() || + GV->hasLinkerPrivateWeakDefAutoLinkage()) PrefixTy = Mangler::LinkerPrivate; // If this global has a name, handle it simply. diff --git a/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp b/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp index 8ae05b7..6660f6b 100644 --- a/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp @@ -18,6 +18,8 @@ #include "MipsInstrInfo.h" #include "MipsTargetMachine.h" #include "MipsMachineFunction.h" +#include "llvm/BasicBlock.h" +#include "llvm/Instructions.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineConstantPool.h" @@ -75,6 +77,7 @@ namespace { } virtual void EmitFunctionBodyStart(); virtual void EmitFunctionBodyEnd(); + virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const; static const char *getRegisterName(unsigned RegNo); virtual void EmitFunctionEntryLabel(); @@ -227,6 +230,23 @@ void MipsAsmPrinter::EmitFunctionBodyEnd() { } +/// isBlockOnlyReachableByFallthough - Return true if the basic block has +/// exactly one predecessor and the control transfer mechanism between +/// the predecessor and this block is a fall-through. +bool MipsAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) + const { + // The predecessor has to be immediately before this block. + const MachineBasicBlock *Pred = *MBB->pred_begin(); + + // If the predecessor is a switch statement, assume a jump table + // implementation, so it is not a fall through. + if (const BasicBlock *bb = Pred->getBasicBlock()) + if (isa(bb->getTerminator())) + return false; + + return AsmPrinter::isBlockOnlyReachableByFallthrough(MBB); +} + // Print out an operand for an inline asm expression. bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, unsigned AsmVariant,const char *ExtraCode, diff --git a/lib/Target/Mips/Mips.td b/lib/Target/Mips/Mips.td index aa036ae..a51c377 100644 --- a/lib/Target/Mips/Mips.td +++ b/lib/Target/Mips/Mips.td @@ -1,4 +1,4 @@ -//===- Mips.td - Describe the Mips Target Machine ---------------*- C++ -*-===// +//===- Mips.td - Describe the Mips Target Machine ----------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/Mips/MipsCallingConv.td b/lib/Target/Mips/MipsCallingConv.td index c2bfb8f..8f313ef 100644 --- a/lib/Target/Mips/MipsCallingConv.td +++ b/lib/Target/Mips/MipsCallingConv.td @@ -1,4 +1,4 @@ -//===- MipsCallingConv.td - Calling Conventions for Mips --------*- C++ -*-===// +//===- MipsCallingConv.td - Calling Conventions for Mips ---*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/Mips/MipsDelaySlotFiller.cpp b/lib/Target/Mips/MipsDelaySlotFiller.cpp index a2b615d..597ea0d 100644 --- a/lib/Target/Mips/MipsDelaySlotFiller.cpp +++ b/lib/Target/Mips/MipsDelaySlotFiller.cpp @@ -32,7 +32,7 @@ namespace { static char ID; Filler(TargetMachine &tm) - : MachineFunctionPass(&ID), TM(tm), TII(tm.getInstrInfo()) { } + : MachineFunctionPass(ID), TM(tm), TII(tm.getInstrInfo()) { } virtual const char *getPassName() const { return "Mips Delay Slot Filler"; diff --git a/lib/Target/Mips/MipsISelDAGToDAG.cpp b/lib/Target/Mips/MipsISelDAGToDAG.cpp index 3888bbf..a47cf7b 100644 --- a/lib/Target/Mips/MipsISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -137,7 +137,7 @@ SelectAddr(SDNode *Op, SDValue Addr, SDValue &Offset, SDValue &Base) // Operand is a result from an ADD. if (Addr.getOpcode() == ISD::ADD) { if (ConstantSDNode *CN = dyn_cast(Addr.getOperand(1))) { - if (Predicate_immSExt16(CN)) { + if (isInt<16>(CN->getSExtValue())) { // If the first operand is a FI, get the TargetFI Node if (FrameIndexSDNode *FIN = dyn_cast @@ -184,8 +184,9 @@ SDNode *MipsDAGToDAGISel::SelectLoadFp64(SDNode *N) { if (!Subtarget.isMips1() || NVT != MVT::f64) return NULL; - if (!Predicate_unindexedload(N) || - !Predicate_load(N)) + LoadSDNode *LN = cast(N); + if (LN->getExtensionType() != ISD::NON_EXTLOAD || + LN->getAddressingMode() != ISD::UNINDEXED) return NULL; SDValue Chain = N->getOperand(0); @@ -248,8 +249,8 @@ SDNode *MipsDAGToDAGISel::SelectStoreFp64(SDNode *N) { SDValue Chain = N->getOperand(0); - if (!Predicate_unindexedstore(N) || - !Predicate_store(N)) + StoreSDNode *SN = cast(N); + if (SN->isTruncatingStore() || SN->getAddressingMode() != ISD::UNINDEXED) return NULL; SDValue N1 = N->getOperand(1); diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index b6ff2c3..b0b99ba 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -317,13 +317,13 @@ MipsTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, BB->addSuccessor(sinkMBB); // sinkMBB: - // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] + // %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ] // ... BB = sinkMBB; BuildMI(*BB, BB->begin(), dl, TII->get(Mips::PHI), MI->getOperand(0).getReg()) - .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB) - .addReg(MI->getOperand(3).getReg()).addMBB(thisMBB); + .addReg(MI->getOperand(2).getReg()).addMBB(thisMBB) + .addReg(MI->getOperand(3).getReg()).addMBB(copy0MBB); MI->eraseFromParent(); // The pseudo instruction is gone now. return BB; @@ -542,7 +542,7 @@ LowerJumpTable(SDValue Op, SelectionDAG &DAG) const SDValue JTI = DAG.getTargetJumpTable(JT->getIndex(), PtrVT, OpFlag); - if (IsPIC) { + if (!IsPIC) { SDValue Ops[] = { JTI }; HiPart = DAG.getNode(MipsISD::Hi, dl, DAG.getVTList(MVT::i32), Ops, 1); } else // Emit Load from Global Pointer diff --git a/lib/Target/Mips/MipsInstrFPU.td b/lib/Target/Mips/MipsInstrFPU.td index e948917..cff79966d 100644 --- a/lib/Target/Mips/MipsInstrFPU.td +++ b/lib/Target/Mips/MipsInstrFPU.td @@ -1,4 +1,4 @@ -//===- MipsInstrFPU.td - Mips FPU Instruction Information -------*- C++ -*-===// +//===- MipsInstrFPU.td - Mips FPU Instruction Information --*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/Mips/MipsInstrFormats.td b/lib/Target/Mips/MipsInstrFormats.td index 0853272..98ae2fa 100644 --- a/lib/Target/Mips/MipsInstrFormats.td +++ b/lib/Target/Mips/MipsInstrFormats.td @@ -1,4 +1,4 @@ -//===- MipsRegisterInfo.td - Mips Register defs -----------------*- C++ -*-===// +//===- MipsRegisterInfo.td - Mips Register defs ------------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/Mips/MipsInstrInfo.cpp b/lib/Target/Mips/MipsInstrInfo.cpp index 6c09a3e..aaf307b 100644 --- a/lib/Target/Mips/MipsInstrInfo.cpp +++ b/lib/Target/Mips/MipsInstrInfo.cpp @@ -30,53 +30,6 @@ static bool isZeroImm(const MachineOperand &op) { return op.isImm() && op.getImm() == 0; } -/// Return true if the instruction is a register to register move and -/// leave the source and dest operands in the passed parameters. -bool MipsInstrInfo:: -isMoveInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const -{ - SrcSubIdx = DstSubIdx = 0; // No sub-registers. - - // addu $dst, $src, $zero || addu $dst, $zero, $src - // or $dst, $src, $zero || or $dst, $zero, $src - if ((MI.getOpcode() == Mips::ADDu) || (MI.getOpcode() == Mips::OR)) { - if (MI.getOperand(1).getReg() == Mips::ZERO) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(2).getReg(); - return true; - } else if (MI.getOperand(2).getReg() == Mips::ZERO) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(1).getReg(); - return true; - } - } - - // mov $fpDst, $fpSrc - // mfc $gpDst, $fpSrc - // mtc $fpDst, $gpSrc - if (MI.getOpcode() == Mips::FMOV_S32 || - MI.getOpcode() == Mips::FMOV_D32 || - MI.getOpcode() == Mips::MFC1 || - MI.getOpcode() == Mips::MTC1 || - MI.getOpcode() == Mips::MOVCCRToCCR) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(1).getReg(); - return true; - } - - // addiu $dst, $src, 0 - if (MI.getOpcode() == Mips::ADDiu) { - if ((MI.getOperand(1).isReg()) && (isZeroImm(MI.getOperand(2)))) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(1).getReg(); - return true; - } - } - - return false; -} - /// isLoadFromStackSlot - If the specified machine instruction is a direct /// load from a stack slot, return the virtual or physical register number of /// the destination along with the FrameIndex of the loaded stack slot. If diff --git a/lib/Target/Mips/MipsInstrInfo.h b/lib/Target/Mips/MipsInstrInfo.h index d6f87f9..52a3d39 100644 --- a/lib/Target/Mips/MipsInstrInfo.h +++ b/lib/Target/Mips/MipsInstrInfo.h @@ -174,12 +174,6 @@ public: /// virtual const MipsRegisterInfo &getRegisterInfo() const { return RI; } - /// Return true if the instruction is a register to register move and return - /// the source and dest operands and their sub-register indices by reference. - virtual bool isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const; - /// isLoadFromStackSlot - If the specified machine instruction is a direct /// load from a stack slot, return the virtual or physical register number of /// the destination along with the FrameIndex of the loaded stack slot. If diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td index 5337c9f..320c5b8 100644 --- a/lib/Target/Mips/MipsInstrInfo.td +++ b/lib/Target/Mips/MipsInstrInfo.td @@ -1,4 +1,4 @@ -//===- MipsInstrInfo.td - Mips Register defs --------------------*- C++ -*-===// +//===- MipsInstrInfo.td - Mips Register defs ---------------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -96,12 +96,7 @@ def HI16 : SDNodeXFormgetValueType(0) == MVT::i32) - return (int32_t)N->getZExtValue() == (short)N->getZExtValue(); - else - return (int64_t)N->getZExtValue() == (short)N->getZExtValue(); -}]>; +def immSExt16 : PatLeaf<(imm), [{ return isInt<16>(N->getSExtValue()); }]>; // Node immediate fits as 16-bit zero extended on target immediate. // The LO16 param means that only the lower 16 bits of the node diff --git a/lib/Target/Mips/MipsRegisterInfo.cpp b/lib/Target/Mips/MipsRegisterInfo.cpp index e15f0a5..69436d2 100644 --- a/lib/Target/Mips/MipsRegisterInfo.cpp +++ b/lib/Target/Mips/MipsRegisterInfo.cpp @@ -327,10 +327,9 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, // FrameIndex represent objects inside a abstract stack. // We must replace FrameIndex with an stack/frame pointer // direct reference. -unsigned MipsRegisterInfo:: +void MipsRegisterInfo:: eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, - FrameIndexValue *Value, RegScavenger *RS) const -{ + RegScavenger *RS) const { MachineInstr &MI = *II; MachineFunction &MF = *MI.getParent()->getParent(); @@ -361,7 +360,6 @@ eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, MI.getOperand(i-1).ChangeToImmediate(Offset); MI.getOperand(i).ChangeToRegister(getFrameRegister(MF), false); - return 0; } void MipsRegisterInfo:: diff --git a/lib/Target/Mips/MipsRegisterInfo.h b/lib/Target/Mips/MipsRegisterInfo.h index b500a65..89282f8 100644 --- a/lib/Target/Mips/MipsRegisterInfo.h +++ b/lib/Target/Mips/MipsRegisterInfo.h @@ -51,9 +51,8 @@ struct MipsRegisterInfo : public MipsGenRegisterInfo { MachineBasicBlock::iterator I) const; /// Stack Frame Processing Methods - unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value = NULL, - RegScavenger *RS = NULL) const; + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; diff --git a/lib/Target/Mips/MipsRegisterInfo.td b/lib/Target/Mips/MipsRegisterInfo.td index be78a22..60efe31 100644 --- a/lib/Target/Mips/MipsRegisterInfo.td +++ b/lib/Target/Mips/MipsRegisterInfo.td @@ -1,4 +1,4 @@ -//===- MipsRegisterInfo.td - Mips Register defs -----------------*- C++ -*-===// +//===- MipsRegisterInfo.td - Mips Register defs ------------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/Mips/MipsSchedule.td b/lib/Target/Mips/MipsSchedule.td index 616a79b..055ff32 100644 --- a/lib/Target/Mips/MipsSchedule.td +++ b/lib/Target/Mips/MipsSchedule.td @@ -1,4 +1,4 @@ -//===- MipsSchedule.td - Mips Scheduling Definitions ------------*- C++ -*-===// +//===- MipsSchedule.td - Mips Scheduling Definitions -------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/PIC16/CMakeLists.txt b/lib/Target/PIC16/CMakeLists.txt index cd4afe8..2b6cb9e 100644 --- a/lib/Target/PIC16/CMakeLists.txt +++ b/lib/Target/PIC16/CMakeLists.txt @@ -10,7 +10,7 @@ tablegen(PIC16GenDAGISel.inc -gen-dag-isel) tablegen(PIC16GenCallingConv.inc -gen-callingconv) tablegen(PIC16GenSubtarget.inc -gen-subtarget) -add_llvm_target(PIC16 +add_llvm_target(PIC16CodeGen PIC16DebugInfo.cpp PIC16InstrInfo.cpp PIC16ISelDAGToDAG.cpp diff --git a/lib/Target/PIC16/PIC16.h b/lib/Target/PIC16/PIC16.h index cee55f4..08bb3e6 100644 --- a/lib/Target/PIC16/PIC16.h +++ b/lib/Target/PIC16/PIC16.h @@ -58,13 +58,10 @@ namespace PIC16CC { ESNames() {} public: ~ESNames() { - std::vector::iterator it = stk.end(); - it--; - while(stk.end() != stk.begin()) + while (!stk.empty()) { - char* p = *it; + char* p = stk.back(); delete [] p; - it--; stk.pop_back(); } } diff --git a/lib/Target/PIC16/PIC16ISelLowering.cpp b/lib/Target/PIC16/PIC16ISelLowering.cpp index 54a6a28..527b31d 100644 --- a/lib/Target/PIC16/PIC16ISelLowering.cpp +++ b/lib/Target/PIC16/PIC16ISelLowering.cpp @@ -312,6 +312,16 @@ PIC16TargetLowering::PIC16TargetLowering(PIC16TargetMachine &TM) computeRegisterProperties(); } +std::pair +PIC16TargetLowering::findRepresentativeClass(EVT VT) const { + switch (VT.getSimpleVT().SimpleTy) { + default: + return TargetLowering::findRepresentativeClass(VT); + case MVT::i16: + return std::make_pair(PIC16::FSR16RegisterClass, 1); + } +} + // getOutFlag - Extract the flag result if the Op has it. static SDValue getOutFlag(SDValue &Op) { // Flag is the last value of the node. diff --git a/lib/Target/PIC16/PIC16ISelLowering.h b/lib/Target/PIC16/PIC16ISelLowering.h index 0a7506c..d942af4 100644 --- a/lib/Target/PIC16/PIC16ISelLowering.h +++ b/lib/Target/PIC16/PIC16ISelLowering.h @@ -50,7 +50,7 @@ namespace llvm { CALL, // PIC16 Call instruction CALLW, // PIC16 CALLW instruction SUBCC, // Compare for equality or inequality. - SELECT_ICC, // Psuedo to be caught in schedular and expanded to brcond. + SELECT_ICC, // Pseudo to be caught in scheduler and expanded to brcond. BRCOND, // Conditional branch. RET, // Return. Dummy @@ -181,6 +181,9 @@ namespace llvm { // FIXME: The function never seems to be aligned. return 1; } + protected: + std::pair + findRepresentativeClass(EVT VT) const; private: // If the Node is a BUILD_PAIR representing a direct Address, // then this function will return true. diff --git a/lib/Target/PIC16/PIC16InstrInfo.cpp b/lib/Target/PIC16/PIC16InstrInfo.cpp index e784f74..81257f3 100644 --- a/lib/Target/PIC16/PIC16InstrInfo.cpp +++ b/lib/Target/PIC16/PIC16InstrInfo.cpp @@ -167,21 +167,6 @@ void PIC16InstrInfo::copyPhysReg(MachineBasicBlock &MBB, .addReg(SrcReg, getKillRegState(KillSrc)); } -bool PIC16InstrInfo::isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DestReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const { - SrcSubIdx = DstSubIdx = 0; // No sub-registers. - - if (MI.getOpcode() == PIC16::copy_fsr - || MI.getOpcode() == PIC16::copy_w) { - DestReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(1).getReg(); - return true; - } - - return false; -} - /// InsertBranch - Insert a branch into the end of the specified /// MachineBasicBlock. This operands to this method are the same as those /// returned by AnalyzeBranch. This is invoked in cases where AnalyzeBranch diff --git a/lib/Target/PIC16/PIC16InstrInfo.h b/lib/Target/PIC16/PIC16InstrInfo.h index a3a77f1..661b335 100644 --- a/lib/Target/PIC16/PIC16InstrInfo.h +++ b/lib/Target/PIC16/PIC16InstrInfo.h @@ -61,10 +61,6 @@ public: MachineBasicBlock::iterator I, DebugLoc DL, unsigned DestReg, unsigned SrcReg, bool KillSrc) const; - virtual bool isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const; - virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, diff --git a/lib/Target/PIC16/PIC16MemSelOpt.cpp b/lib/Target/PIC16/PIC16MemSelOpt.cpp index 241170b..b6aa38f 100644 --- a/lib/Target/PIC16/PIC16MemSelOpt.cpp +++ b/lib/Target/PIC16/PIC16MemSelOpt.cpp @@ -38,7 +38,7 @@ using namespace llvm; namespace { struct MemSelOpt : public MachineFunctionPass { static char ID; - MemSelOpt() : MachineFunctionPass(&ID) {} + MemSelOpt() : MachineFunctionPass(ID) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.addPreservedID(MachineLoopInfoID); diff --git a/lib/Target/PIC16/PIC16Passes/PIC16Cloner.cpp b/lib/Target/PIC16/PIC16Passes/PIC16Cloner.cpp index 27f1cf5..56f0211 100644 --- a/lib/Target/PIC16/PIC16Passes/PIC16Cloner.cpp +++ b/lib/Target/PIC16/PIC16Passes/PIC16Cloner.cpp @@ -256,7 +256,7 @@ PIC16Cloner::cloneFunction(Function *OrgF) { CloneAutos(OrgF); // Now create the clone. - ClonedF = CloneFunction(OrgF, VMap); + ClonedF = CloneFunction(OrgF, VMap, /*ModuleLevelChanges=*/false); // The new function should be for interrupt line. Therefore should have // the name suffixed with IL and section attribute marked with IL. diff --git a/lib/Target/PIC16/PIC16Passes/PIC16Cloner.h b/lib/Target/PIC16/PIC16Passes/PIC16Cloner.h index e8b5aa4..e7d67ce 100644 --- a/lib/Target/PIC16/PIC16Passes/PIC16Cloner.h +++ b/lib/Target/PIC16/PIC16Passes/PIC16Cloner.h @@ -35,7 +35,7 @@ namespace llvm { class PIC16Cloner : public ModulePass { public: static char ID; // Class identification - PIC16Cloner() : ModulePass(&ID) {} + PIC16Cloner() : ModulePass(ID) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); diff --git a/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp b/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp index 5ecb6aa..0f8928a 100644 --- a/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp +++ b/lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp @@ -171,8 +171,9 @@ void PIC16Overlay::MarkIndirectlyCalledFunctions(Module &M) { for (Module::iterator MI = M.begin(), E = M.end(); MI != E; ++MI) { for (Value::use_iterator I = MI->use_begin(), E = MI->use_end(); I != E; ++I) { - if ((!isa(I) && !isa(I)) - || !CallSite(cast(I)).isCallee(I)) { + User *U = *I; + if ((!isa(U) && !isa(U)) + || !CallSite(cast(U)).isCallee(I)) { setColor(MI, ++IndirectCallColor); break; } diff --git a/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h b/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h index 5a2551f..2f611e6 100644 --- a/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h +++ b/lib/Target/PIC16/PIC16Passes/PIC16Overlay.h @@ -39,7 +39,7 @@ namespace llvm { unsigned IndirectCallColor; public: static char ID; // Class identification - PIC16Overlay() : ModulePass(&ID) { + PIC16Overlay() : ModulePass(ID) { OverlayStr = "Overlay="; InterruptDepth = PIC16OVERLAY::StartInterruptColor; IndirectCallColor = PIC16OVERLAY::StartIndirectCallColor; diff --git a/lib/Target/PIC16/PIC16RegisterInfo.cpp b/lib/Target/PIC16/PIC16RegisterInfo.cpp index dff98d1..76de47f 100644 --- a/lib/Target/PIC16/PIC16RegisterInfo.cpp +++ b/lib/Target/PIC16/PIC16RegisterInfo.cpp @@ -44,13 +44,10 @@ bool PIC16RegisterInfo::hasFP(const MachineFunction &MF) const { return false; } -unsigned PIC16RegisterInfo:: +void PIC16RegisterInfo:: eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, - FrameIndexValue *Value, RegScavenger *RS) const -{ - /* NOT YET IMPLEMENTED */ - return 0; -} + RegScavenger *RS) const +{ /* NOT YET IMPLEMENTED */ } void PIC16RegisterInfo::emitPrologue(MachineFunction &MF) const { /* NOT YET IMPLEMENTED */ } diff --git a/lib/Target/PIC16/PIC16RegisterInfo.h b/lib/Target/PIC16/PIC16RegisterInfo.h index 5536a61..20052b0 100644 --- a/lib/Target/PIC16/PIC16RegisterInfo.h +++ b/lib/Target/PIC16/PIC16RegisterInfo.h @@ -44,9 +44,8 @@ class PIC16RegisterInfo : public PIC16GenRegisterInfo { virtual BitVector getReservedRegs(const MachineFunction &MF) const; virtual bool hasFP(const MachineFunction &MF) const; - virtual unsigned eliminateFrameIndex(MachineBasicBlock::iterator MI, - int SPAdj, FrameIndexValue *Value = NULL, - RegScavenger *RS=NULL) const; + virtual void eliminateFrameIndex(MachineBasicBlock::iterator MI, + int SPAdj, RegScavenger *RS=NULL) const; void eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, diff --git a/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp b/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp index e35dc57..c1a5663 100644 --- a/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp +++ b/lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp @@ -43,6 +43,7 @@ #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegistry.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -327,6 +328,19 @@ namespace { void printPredicateOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O, const char *Modifier); + + MachineLocation getDebugValueLocation(const MachineInstr *MI) const { + + MachineLocation Location; + assert (MI->getNumOperands() == 4 && "Invalid no. of machine operands!"); + // Frame address. Currently handles register +- offset only. + if (MI->getOperand(0).isReg() && MI->getOperand(2).isImm()) + Location.set(MI->getOperand(0).getReg(), MI->getOperand(2).getImm()); + else { + DEBUG(dbgs() << "DBG_VALUE instruction ignored! " << *MI << "\n"); + } + return Location; + } }; /// PPCLinuxAsmPrinter - PowerPC assembly printer, customized for Linux diff --git a/lib/Target/PowerPC/PPCBranchSelector.cpp b/lib/Target/PowerPC/PPCBranchSelector.cpp index 52948c8..e161d23 100644 --- a/lib/Target/PowerPC/PPCBranchSelector.cpp +++ b/lib/Target/PowerPC/PPCBranchSelector.cpp @@ -10,7 +10,7 @@ // This file contains a pass that scans a machine function to determine which // conditional branches need more than 16 bits of displacement to reach their // target basic block. It does this in two passes; a calculation of basic block -// positions pass, and a branch psuedo op to machine branch opcode pass. This +// positions pass, and a branch pseudo op to machine branch opcode pass. This // pass should be run last, just before the assembly printer. // //===----------------------------------------------------------------------===// @@ -31,7 +31,7 @@ STATISTIC(NumExpanded, "Number of branches expanded to long format"); namespace { struct PPCBSel : public MachineFunctionPass { static char ID; - PPCBSel() : MachineFunctionPass(&ID) {} + PPCBSel() : MachineFunctionPass(ID) {} /// BlockSizes - The sizes of the basic blocks in the function. std::vector BlockSizes; @@ -53,7 +53,8 @@ FunctionPass *llvm::createPPCBranchSelectionPass() { } bool PPCBSel::runOnMachineFunction(MachineFunction &Fn) { - const TargetInstrInfo *TII = Fn.getTarget().getInstrInfo(); + const PPCInstrInfo *TII = + static_cast(Fn.getTarget().getInstrInfo()); // Give the blocks of the function a dense, in-order, numbering. Fn.RenumberBlocks(); BlockSizes.resize(Fn.getNumBlockIDs()); diff --git a/lib/Target/PowerPC/PPCCallingConv.td b/lib/Target/PowerPC/PPCCallingConv.td index 155fba2..441db94 100644 --- a/lib/Target/PowerPC/PPCCallingConv.td +++ b/lib/Target/PowerPC/PPCCallingConv.td @@ -1,4 +1,4 @@ -//===- PPCCallingConv.td - Calling Conventions for PowerPC ------*- C++ -*-===// +//===- PPCCallingConv.td - Calling Conventions for PowerPC -*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/PowerPC/PPCCodeEmitter.cpp b/lib/Target/PowerPC/PPCCodeEmitter.cpp index 361fa70..df9ab52 100644 --- a/lib/Target/PowerPC/PPCCodeEmitter.cpp +++ b/lib/Target/PowerPC/PPCCodeEmitter.cpp @@ -45,7 +45,7 @@ namespace { public: PPCCodeEmitter(TargetMachine &tm, JITCodeEmitter &mce) - : MachineFunctionPass(&ID), TM(tm), MCE(mce) {} + : MachineFunctionPass(ID), TM(tm), MCE(mce) {} /// getBinaryCodeForInstr - This function, generated by the /// CodeEmitterGenerator using TableGen, produces the binary encoding for @@ -110,7 +110,7 @@ void PPCCodeEmitter::emitBasicBlock(MachineBasicBlock &MBB) { default: MCE.emitWordBE(getBinaryCodeForInstr(MI)); break; - case TargetOpcode::DBG_LABEL: + case TargetOpcode::PROLOG_LABEL: case TargetOpcode::EH_LABEL: MCE.emitLabel(MI.getOperand(0).getMCSymbol()); break; diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index d47d989..14d1b15 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -2467,18 +2467,31 @@ unsigned PrepareCall(SelectionDAG &DAG, SDValue &Callee, SDValue &InFlag, unsigned CallOpc = isSVR4ABI ? PPCISD::CALL_SVR4 : PPCISD::CALL_Darwin; - // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every - // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol - // node so that legalize doesn't hack it. - if (GlobalAddressSDNode *G = dyn_cast(Callee)) - Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, - Callee.getValueType()); - else if (ExternalSymbolSDNode *S = dyn_cast(Callee)) - Callee = DAG.getTargetExternalSymbol(S->getSymbol(), Callee.getValueType()); - else if (SDNode *Dest = isBLACompatibleAddress(Callee, DAG)) + bool needIndirectCall = true; + if (SDNode *Dest = isBLACompatibleAddress(Callee, DAG)) { // If this is an absolute destination address, use the munged value. Callee = SDValue(Dest, 0); - else { + needIndirectCall = false; + } + // XXX Work around for http://llvm.org/bugs/show_bug.cgi?id=5201 + // Use indirect calls for ALL functions calls in JIT mode, since the + // far-call stubs may be outside relocation limits for a BL instruction. + if (!DAG.getTarget().getSubtarget().isJITCodeModel()) { + // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every + // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol + // node so that legalize doesn't hack it. + if (GlobalAddressSDNode *G = dyn_cast(Callee)) { + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, + Callee.getValueType()); + needIndirectCall = false; + } + } + if (ExternalSymbolSDNode *S = dyn_cast(Callee)) { + Callee = DAG.getTargetExternalSymbol(S->getSymbol(), + Callee.getValueType()); + needIndirectCall = false; + } + if (needIndirectCall) { // Otherwise, this is an indirect call. We have to use a MTCTR/BCTRL pair // to do the call, we can't use PPCISD::CALL. SDValue MTCTROps[] = {Chain, Callee, InFlag}; @@ -3942,17 +3955,17 @@ SDValue PPCTargetLowering::LowerBUILD_VECTOR(SDValue Op, } // t = vsplti c, result = vsldoi t, t, 1 - if (SextVal == ((i << 8) | (i >> (TypeShiftAmt-8)))) { + if (SextVal == ((i << 8) | (i < 0 ? 0xFF : 0))) { SDValue T = BuildSplatI(i, SplatSize, MVT::v16i8, DAG, dl); return BuildVSLDOI(T, T, 1, Op.getValueType(), DAG, dl); } // t = vsplti c, result = vsldoi t, t, 2 - if (SextVal == ((i << 16) | (i >> (TypeShiftAmt-16)))) { + if (SextVal == ((i << 16) | (i < 0 ? 0xFFFF : 0))) { SDValue T = BuildSplatI(i, SplatSize, MVT::v16i8, DAG, dl); return BuildVSLDOI(T, T, 2, Op.getValueType(), DAG, dl); } // t = vsplti c, result = vsldoi t, t, 3 - if (SextVal == ((i << 24) | (i >> (TypeShiftAmt-24)))) { + if (SextVal == ((i << 24) | (i < 0 ? 0xFFFFFF : 0))) { SDValue T = BuildSplatI(i, SplatSize, MVT::v16i8, DAG, dl); return BuildVSLDOI(T, T, 3, Op.getValueType(), DAG, dl); } diff --git a/lib/Target/PowerPC/PPCInstrInfo.cpp b/lib/Target/PowerPC/PPCInstrInfo.cpp index 1574aa3..c17108f 100644 --- a/lib/Target/PowerPC/PPCInstrInfo.cpp +++ b/lib/Target/PowerPC/PPCInstrInfo.cpp @@ -18,8 +18,11 @@ #include "PPCGenInstrInfo.inc" #include "PPCTargetMachine.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -36,67 +39,6 @@ PPCInstrInfo::PPCInstrInfo(PPCTargetMachine &tm) : TargetInstrInfoImpl(PPCInsts, array_lengthof(PPCInsts)), TM(tm), RI(*TM.getSubtargetImpl(), *this) {} -bool PPCInstrInfo::isMoveInstr(const MachineInstr& MI, - unsigned& sourceReg, - unsigned& destReg, - unsigned& sourceSubIdx, - unsigned& destSubIdx) const { - sourceSubIdx = destSubIdx = 0; // No sub-registers. - - unsigned oc = MI.getOpcode(); - if (oc == PPC::OR || oc == PPC::OR8 || oc == PPC::VOR || - oc == PPC::OR4To8 || oc == PPC::OR8To4) { // or r1, r2, r2 - assert(MI.getNumOperands() >= 3 && - MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - MI.getOperand(2).isReg() && - "invalid PPC OR instruction!"); - if (MI.getOperand(1).getReg() == MI.getOperand(2).getReg()) { - sourceReg = MI.getOperand(1).getReg(); - destReg = MI.getOperand(0).getReg(); - return true; - } - } else if (oc == PPC::ADDI) { // addi r1, r2, 0 - assert(MI.getNumOperands() >= 3 && - MI.getOperand(0).isReg() && - MI.getOperand(2).isImm() && - "invalid PPC ADDI instruction!"); - if (MI.getOperand(1).isReg() && MI.getOperand(2).getImm() == 0) { - sourceReg = MI.getOperand(1).getReg(); - destReg = MI.getOperand(0).getReg(); - return true; - } - } else if (oc == PPC::ORI) { // ori r1, r2, 0 - assert(MI.getNumOperands() >= 3 && - MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - MI.getOperand(2).isImm() && - "invalid PPC ORI instruction!"); - if (MI.getOperand(2).getImm() == 0) { - sourceReg = MI.getOperand(1).getReg(); - destReg = MI.getOperand(0).getReg(); - return true; - } - } else if (oc == PPC::FMR || oc == PPC::FMRSD) { // fmr r1, r2 - assert(MI.getNumOperands() >= 2 && - MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - "invalid PPC FMR instruction"); - sourceReg = MI.getOperand(1).getReg(); - destReg = MI.getOperand(0).getReg(); - return true; - } else if (oc == PPC::MCRF) { // mcrf cr1, cr2 - assert(MI.getNumOperands() >= 2 && - MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - "invalid PPC MCRF instruction"); - sourceReg = MI.getOperand(1).getReg(); - destReg = MI.getOperand(0).getReg(); - return true; - } - return false; -} - unsigned PPCInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const { switch (MI->getOpcode()) { @@ -524,6 +466,14 @@ PPCInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, for (unsigned i = 0, e = NewMIs.size(); i != e; ++i) MBB.insert(MI, NewMIs[i]); + + const MachineFrameInfo &MFI = *MF.getFrameInfo(); + MachineMemOperand *MMO = + MF.getMachineMemOperand(PseudoSourceValue::getFixedStack(FrameIdx), + MachineMemOperand::MOStore, /*Offset=*/0, + MFI.getObjectSize(FrameIdx), + MFI.getObjectAlignment(FrameIdx)); + NewMIs.back()->addMemOperand(MF, MMO); } void @@ -637,6 +587,14 @@ PPCInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, LoadRegFromStackSlot(MF, DL, DestReg, FrameIdx, RC, NewMIs); for (unsigned i = 0, e = NewMIs.size(); i != e; ++i) MBB.insert(MI, NewMIs[i]); + + const MachineFrameInfo &MFI = *MF.getFrameInfo(); + MachineMemOperand *MMO = + MF.getMachineMemOperand(PseudoSourceValue::getFixedStack(FrameIdx), + MachineMemOperand::MOLoad, /*Offset=*/0, + MFI.getObjectSize(FrameIdx), + MFI.getObjectAlignment(FrameIdx)); + NewMIs.back()->addMemOperand(MF, MMO); } MachineInstr* @@ -667,7 +625,7 @@ unsigned PPCInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const { const char *AsmStr = MI->getOperand(0).getSymbolName(); return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo()); } - case PPC::DBG_LABEL: + case PPC::PROLOG_LABEL: case PPC::EH_LABEL: case PPC::GC_LABEL: case PPC::DBG_VALUE: diff --git a/lib/Target/PowerPC/PPCInstrInfo.h b/lib/Target/PowerPC/PPCInstrInfo.h index eadb21e..fc7b7b3 100644 --- a/lib/Target/PowerPC/PPCInstrInfo.h +++ b/lib/Target/PowerPC/PPCInstrInfo.h @@ -82,12 +82,6 @@ public: /// virtual const PPCRegisterInfo &getRegisterInfo() const { return RI; } - /// Return true if the instruction is a register to register move and return - /// the source and dest operands and their sub-register indices by reference. - virtual bool isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const; - unsigned isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const; unsigned isStoreToStackSlot(const MachineInstr *MI, diff --git a/lib/Target/PowerPC/PPCInstrInfo.td b/lib/Target/PowerPC/PPCInstrInfo.td index 63b4581..eb100ec 100644 --- a/lib/Target/PowerPC/PPCInstrInfo.td +++ b/lib/Target/PowerPC/PPCInstrInfo.td @@ -1022,9 +1022,7 @@ let Uses = [RM] in { } } -/// FMR is split into 2 versions, one for 4/8 byte FP, and one for extending. -/// -/// Note that these are defined as pseudo-ops on the PPC970 because they are +/// Note that FMR is defined as pseudo-ops on the PPC970 because they are /// often coalesced away and we don't want the dispatch group builder to think /// that they will fill slots (which could cause the load of a LSU reject to /// sneak into a d-group with a store). @@ -1032,10 +1030,6 @@ def FMR : XForm_26<63, 72, (outs F4RC:$frD), (ins F4RC:$frB), "fmr $frD, $frB", FPGeneral, []>, // (set F4RC:$frD, F4RC:$frB) PPC970_Unit_Pseudo; -def FMRSD : XForm_26<63, 72, (outs F8RC:$frD), (ins F4RC:$frB), - "fmr $frD, $frB", FPGeneral, - [(set F8RC:$frD, (fextend F4RC:$frB))]>, - PPC970_Unit_Pseudo; let PPC970_Unit = 3 in { // FPU Operations. // These are artificially split into two different forms, for 4/8 byte FP. @@ -1476,10 +1470,13 @@ def : Pat<(extloadi16 iaddr:$src), (LHZ iaddr:$src)>; def : Pat<(extloadi16 xaddr:$src), (LHZX xaddr:$src)>; -def : Pat<(extloadf32 iaddr:$src), - (FMRSD (LFS iaddr:$src))>; -def : Pat<(extloadf32 xaddr:$src), - (FMRSD (LFSX xaddr:$src))>; +def : Pat<(f64 (extloadf32 iaddr:$src)), + (COPY_TO_REGCLASS (LFS iaddr:$src), F8RC)>; +def : Pat<(f64 (extloadf32 xaddr:$src)), + (COPY_TO_REGCLASS (LFSX xaddr:$src), F8RC)>; + +def : Pat<(f64 (fextend F4RC:$src)), + (COPY_TO_REGCLASS F4RC:$src, F8RC)>; // Memory barriers def : Pat<(membarrier (i32 imm /*ll*/), diff --git a/lib/Target/PowerPC/PPCRegisterInfo.cpp b/lib/Target/PowerPC/PPCRegisterInfo.cpp index 4d6132a9..653e143 100644 --- a/lib/Target/PowerPC/PPCRegisterInfo.cpp +++ b/lib/Target/PowerPC/PPCRegisterInfo.cpp @@ -449,8 +449,8 @@ void PPCRegisterInfo::lowerDynamicAlloc(MachineBasicBlock::iterator II, // Get stack alignments. unsigned TargetAlign = MF.getTarget().getFrameInfo()->getStackAlignment(); unsigned MaxAlign = MFI->getMaxAlignment(); - assert(MaxAlign <= TargetAlign && - "Dynamic alloca with large aligns not supported"); + if (MaxAlign > TargetAlign) + report_fatal_error("Dynamic alloca with large aligns not supported"); // Determine the previous frame's address. If FrameSize can't be // represented as 16 bits or we need special alignment, then we load the @@ -580,10 +580,9 @@ void PPCRegisterInfo::lowerCRSpilling(MachineBasicBlock::iterator II, MBB.erase(II); } -unsigned +void PPCRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value, - RegScavenger *RS) const { + int SPAdj, RegScavenger *RS) const { assert(SPAdj == 0 && "Unexpected"); // Get the instruction. @@ -622,14 +621,14 @@ PPCRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, if (FPSI && FrameIndex == FPSI && (OpC == PPC::DYNALLOC || OpC == PPC::DYNALLOC8)) { lowerDynamicAlloc(II, SPAdj, RS); - return 0; + return; } // Special case for pseudo-op SPILL_CR. if (EnableRegisterScavenging) // FIXME (64-bit): Enable by default. if (OpC == PPC::SPILL_CR) { lowerCRSpilling(II, FrameIndex, SPAdj, RS); - return 0; + return; } // Replace the FrameIndex with base register with GPR1 (SP) or GPR31 (FP). @@ -674,7 +673,7 @@ PPCRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, if (isIXAddr) Offset >>= 2; // The actual encoded value has the low two bits zero. MI.getOperand(OffsetOperandNo).ChangeToImmediate(Offset); - return 0; + return; } // The offset doesn't fit into a single register, scavenge one to build the @@ -710,11 +709,10 @@ PPCRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, } else { OperandBase = OffsetOperandNo; } - + unsigned StackReg = MI.getOperand(FIOperandNo).getReg(); MI.getOperand(OperandBase).ChangeToRegister(StackReg, false); MI.getOperand(OperandBase + 1).ChangeToRegister(SReg, false); - return 0; } /// VRRegNo - Map from a numbered VR register to its enum value. @@ -1318,7 +1316,7 @@ PPCRegisterInfo::emitPrologue(MachineFunction &MF) const { if (needsFrameMoves) { // Mark effective beginning of when frame pointer becomes valid. FrameLabel = MMI.getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, dl, TII.get(PPC::DBG_LABEL)).addSym(FrameLabel); + BuildMI(MBB, MBBI, dl, TII.get(PPC::PROLOG_LABEL)).addSym(FrameLabel); // Show update of SP. if (NegFrameSize) { @@ -1361,7 +1359,7 @@ PPCRegisterInfo::emitPrologue(MachineFunction &MF) const { ReadyLabel = MMI.getContext().CreateTempSymbol(); // Mark effective beginning of when frame pointer is ready. - BuildMI(MBB, MBBI, dl, TII.get(PPC::DBG_LABEL)).addSym(ReadyLabel); + BuildMI(MBB, MBBI, dl, TII.get(PPC::PROLOG_LABEL)).addSym(ReadyLabel); MachineLocation FPDst(HasFP ? (isPPC64 ? PPC::X31 : PPC::R31) : (isPPC64 ? PPC::X1 : PPC::R1)); diff --git a/lib/Target/PowerPC/PPCRegisterInfo.h b/lib/Target/PowerPC/PPCRegisterInfo.h index f026847..890b24b 100644 --- a/lib/Target/PowerPC/PPCRegisterInfo.h +++ b/lib/Target/PowerPC/PPCRegisterInfo.h @@ -63,9 +63,8 @@ public: int SPAdj, RegScavenger *RS) const; void lowerCRSpilling(MachineBasicBlock::iterator II, unsigned FrameIndex, int SPAdj, RegScavenger *RS) const; - unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value = NULL, - RegScavenger *RS = NULL) const; + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; /// determineFrameLayout - Determine the size of the frame and maximum call /// frame size. diff --git a/lib/Target/PowerPC/PPCSubtarget.cpp b/lib/Target/PowerPC/PPCSubtarget.cpp index 40914ba..5d46065 100644 --- a/lib/Target/PowerPC/PPCSubtarget.cpp +++ b/lib/Target/PowerPC/PPCSubtarget.cpp @@ -69,6 +69,7 @@ PPCSubtarget::PPCSubtarget(const std::string &TT, const std::string &FS, , HasFSQRT(false) , HasSTFIWX(false) , HasLazyResolverStubs(false) + , IsJITCodeModel(false) , DarwinVers(0) { // Determine default and user specified characteristics @@ -117,6 +118,9 @@ void PPCSubtarget::SetJITMode() { // everything is. This matters for PPC64, which codegens in PIC mode without // stubs. HasLazyResolverStubs = false; + + // Calls to external functions need to use indirect calls + IsJITCodeModel = true; } diff --git a/lib/Target/PowerPC/PPCSubtarget.h b/lib/Target/PowerPC/PPCSubtarget.h index 75fcf62..00ec747 100644 --- a/lib/Target/PowerPC/PPCSubtarget.h +++ b/lib/Target/PowerPC/PPCSubtarget.h @@ -63,6 +63,7 @@ protected: bool HasFSQRT; bool HasSTFIWX; bool HasLazyResolverStubs; + bool IsJITCodeModel; /// DarwinVers - Nonzero if this is a darwin platform. Otherwise, the numeric /// version of the platform, e.g. 8 = 10.4 (Tiger), 9 = 10.5 (Leopard), etc. @@ -124,6 +125,9 @@ public: bool hasLazyResolverStub(const GlobalValue *GV, const TargetMachine &TM) const; + // isJITCodeModel - True if we're generating code for the JIT + bool isJITCodeModel() const { return IsJITCodeModel; } + // Specific obvious features. bool hasFSQRT() const { return HasFSQRT; } bool hasSTFIWX() const { return HasSTFIWX; } diff --git a/lib/Target/README.txt b/lib/Target/README.txt index 4d7ee08..4faf8bc 100644 --- a/lib/Target/README.txt +++ b/lib/Target/README.txt @@ -1919,5 +1919,21 @@ something like the following, which eliminates a branch: ret .LBB0_2: jmp foo # TAILCALL +//===---------------------------------------------------------------------===// +Given a branch where the two target blocks are identical ("ret i32 %b" in +both), simplifycfg will simplify them away. But not so for a switch statement: + +define i32 @f(i32 %a, i32 %b) nounwind readnone { +entry: + switch i32 %a, label %bb3 [ + i32 4, label %bb + i32 6, label %bb + ] +bb: ; preds = %entry, %entry + ret i32 %b + +bb3: ; preds = %entry + ret i32 %b +} //===---------------------------------------------------------------------===// diff --git a/lib/Target/Sparc/DelaySlotFiller.cpp b/lib/Target/Sparc/DelaySlotFiller.cpp index 9e148ad..aae5da8 100644 --- a/lib/Target/Sparc/DelaySlotFiller.cpp +++ b/lib/Target/Sparc/DelaySlotFiller.cpp @@ -32,7 +32,7 @@ namespace { static char ID; Filler(TargetMachine &tm) - : MachineFunctionPass(&ID), TM(tm), TII(tm.getInstrInfo()) { } + : MachineFunctionPass(ID), TM(tm), TII(tm.getInstrInfo()) { } virtual const char *getPassName() const { return "SPARC Delay Slot Filler"; diff --git a/lib/Target/Sparc/FPMover.cpp b/lib/Target/Sparc/FPMover.cpp index 88b0927..1423b1e 100644 --- a/lib/Target/Sparc/FPMover.cpp +++ b/lib/Target/Sparc/FPMover.cpp @@ -36,7 +36,7 @@ namespace { static char ID; explicit FPMover(TargetMachine &tm) - : MachineFunctionPass(&ID), TM(tm) { } + : MachineFunctionPass(ID), TM(tm) { } virtual const char *getPassName() const { return "Sparc Double-FP Move Fixer"; diff --git a/lib/Target/Sparc/Sparc.td b/lib/Target/Sparc/Sparc.td index 925d782..7643366 100644 --- a/lib/Target/Sparc/Sparc.td +++ b/lib/Target/Sparc/Sparc.td @@ -1,4 +1,4 @@ -//===- Sparc.td - Describe the Sparc Target Machine -------------*- C++ -*-===// +//===- Sparc.td - Describe the Sparc Target Machine --------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Target/Sparc/SparcISelDAGToDAG.cpp b/lib/Target/Sparc/SparcISelDAGToDAG.cpp index 698923e..4ea94c4 100644 --- a/lib/Target/Sparc/SparcISelDAGToDAG.cpp +++ b/lib/Target/Sparc/SparcISelDAGToDAG.cpp @@ -84,7 +84,7 @@ bool SparcDAGToDAGISel::SelectADDRri(SDNode *Op, SDValue Addr, if (Addr.getOpcode() == ISD::ADD) { if (ConstantSDNode *CN = dyn_cast(Addr.getOperand(1))) { - if (Predicate_simm13(CN)) { + if (isInt<13>(CN->getSExtValue())) { if (FrameIndexSDNode *FIN = dyn_cast(Addr.getOperand(0))) { // Constant offset from frame ref. @@ -120,9 +120,9 @@ bool SparcDAGToDAGISel::SelectADDRrr(SDNode *Op, SDValue Addr, return false; // direct calls. if (Addr.getOpcode() == ISD::ADD) { - if (isa(Addr.getOperand(1)) && - Predicate_simm13(Addr.getOperand(1).getNode())) - return false; // Let the reg+imm pattern catch this! + if (ConstantSDNode *CN = dyn_cast(Addr.getOperand(1))) + if (isInt<13>(CN->getSExtValue())) + return false; // Let the reg+imm pattern catch this! if (Addr.getOperand(0).getOpcode() == SPISD::Lo || Addr.getOperand(1).getOpcode() == SPISD::Lo) return false; // Let the reg+imm pattern catch this! diff --git a/lib/Target/Sparc/SparcInstrInfo.cpp b/lib/Target/Sparc/SparcInstrInfo.cpp index 3a4c80a..7ede8e7 100644 --- a/lib/Target/Sparc/SparcInstrInfo.cpp +++ b/lib/Target/Sparc/SparcInstrInfo.cpp @@ -28,46 +28,6 @@ SparcInstrInfo::SparcInstrInfo(SparcSubtarget &ST) RI(ST, *this), Subtarget(ST) { } -static bool isZeroImm(const MachineOperand &op) { - return op.isImm() && op.getImm() == 0; -} - -/// Return true if the instruction is a register to register move and -/// leave the source and dest operands in the passed parameters. -/// -bool SparcInstrInfo::isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSR, unsigned &DstSR) const { - SrcSR = DstSR = 0; // No sub-registers. - - // We look for 3 kinds of patterns here: - // or with G0 or 0 - // add with G0 or 0 - // fmovs or FpMOVD (pseudo double move). - if (MI.getOpcode() == SP::ORrr || MI.getOpcode() == SP::ADDrr) { - if (MI.getOperand(1).getReg() == SP::G0) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(2).getReg(); - return true; - } else if (MI.getOperand(2).getReg() == SP::G0) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(1).getReg(); - return true; - } - } else if ((MI.getOpcode() == SP::ORri || MI.getOpcode() == SP::ADDri) && - isZeroImm(MI.getOperand(2)) && MI.getOperand(1).isReg()) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(1).getReg(); - return true; - } else if (MI.getOpcode() == SP::FMOVS || MI.getOpcode() == SP::FpMOVD || - MI.getOpcode() == SP::FMOVD) { - SrcReg = MI.getOperand(1).getReg(); - DstReg = MI.getOperand(0).getReg(); - return true; - } - return false; -} - /// isLoadFromStackSlot - If the specified machine instruction is a direct /// load from a stack slot, return the virtual or physical register number of /// the destination along with the FrameIndex of the loaded stack slot. If diff --git a/lib/Target/Sparc/SparcInstrInfo.h b/lib/Target/Sparc/SparcInstrInfo.h index 1334718..c00bd21 100644 --- a/lib/Target/Sparc/SparcInstrInfo.h +++ b/lib/Target/Sparc/SparcInstrInfo.h @@ -43,12 +43,6 @@ public: /// virtual const SparcRegisterInfo &getRegisterInfo() const { return RI; } - /// Return true if the instruction is a register to register move and return - /// the source and dest operands and their sub-register indices by reference. - virtual bool isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const; - /// isLoadFromStackSlot - If the specified machine instruction is a direct /// load from a stack slot, return the virtual or physical register number of /// the destination along with the FrameIndex of the loaded stack slot. If diff --git a/lib/Target/Sparc/SparcInstrInfo.td b/lib/Target/Sparc/SparcInstrInfo.td index ddadd51..467ed48 100644 --- a/lib/Target/Sparc/SparcInstrInfo.td +++ b/lib/Target/Sparc/SparcInstrInfo.td @@ -43,17 +43,9 @@ def UseDeprecatedInsts : Predicate<"Subtarget.useDeprecatedV8Instructions()">; // Instruction Pattern Stuff //===----------------------------------------------------------------------===// -def simm11 : PatLeaf<(imm), [{ - // simm11 predicate - True if the imm fits in a 11-bit sign extended field. - return (((int)N->getZExtValue() << (32-11)) >> (32-11)) == - (int)N->getZExtValue(); -}]>; +def simm11 : PatLeaf<(imm), [{ return isInt<11>(N->getSExtValue()); }]>; -def simm13 : PatLeaf<(imm), [{ - // simm13 predicate - True if the imm fits in a 13-bit sign extended field. - return (((int)N->getZExtValue() << (32-13)) >> (32-13)) == - (int)N->getZExtValue(); -}]>; +def simm13 : PatLeaf<(imm), [{ return isInt<13>(N->getSExtValue()); }]>; def LO10 : SDNodeXFormgetTargetConstant((unsigned)N->getZExtValue() & 1023, diff --git a/lib/Target/Sparc/SparcRegisterInfo.cpp b/lib/Target/Sparc/SparcRegisterInfo.cpp index 427cc7f..c85db20 100644 --- a/lib/Target/Sparc/SparcRegisterInfo.cpp +++ b/lib/Target/Sparc/SparcRegisterInfo.cpp @@ -69,10 +69,9 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MBB.erase(I); } -unsigned +void SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value, - RegScavenger *RS) const { + int SPAdj, RegScavenger *RS) const { assert(SPAdj == 0 && "Unexpected"); unsigned i = 0; @@ -108,7 +107,6 @@ SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, MI.getOperand(i).ChangeToRegister(SP::G1, false); MI.getOperand(i+1).ChangeToImmediate(Offset & ((1 << 10)-1)); } - return 0; } void SparcRegisterInfo:: diff --git a/lib/Target/Sparc/SparcRegisterInfo.h b/lib/Target/Sparc/SparcRegisterInfo.h index 9f0cda7..020ce56 100644 --- a/lib/Target/Sparc/SparcRegisterInfo.h +++ b/lib/Target/Sparc/SparcRegisterInfo.h @@ -40,9 +40,8 @@ struct SparcRegisterInfo : public SparcGenRegisterInfo { MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; - unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value = NULL, - RegScavenger *RS = NULL) const; + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; void processFunctionBeforeFrameFinalized(MachineFunction &MF) const; diff --git a/lib/Target/SystemZ/SystemZInstrInfo.cpp b/lib/Target/SystemZ/SystemZInstrInfo.cpp index c03864f..367bed3 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.cpp +++ b/lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -141,31 +141,6 @@ void SystemZInstrInfo::copyPhysReg(MachineBasicBlock &MBB, .addReg(SrcReg, getKillRegState(KillSrc)); } -bool -SystemZInstrInfo::isMoveInstr(const MachineInstr& MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const { - switch (MI.getOpcode()) { - default: - return false; - case SystemZ::MOV32rr: - case SystemZ::MOV64rr: - case SystemZ::MOV64rrP: - case SystemZ::MOV128rr: - case SystemZ::FMOV32rr: - case SystemZ::FMOV64rr: - assert(MI.getNumOperands() >= 2 && - MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - "invalid register-register move instruction"); - SrcReg = MI.getOperand(1).getReg(); - DstReg = MI.getOperand(0).getReg(); - SrcSubIdx = MI.getOperand(1).getSubReg(); - DstSubIdx = MI.getOperand(0).getSubReg(); - return true; - } -} - unsigned SystemZInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const { switch (MI->getOpcode()) { diff --git a/lib/Target/SystemZ/SystemZInstrInfo.h b/lib/Target/SystemZ/SystemZInstrInfo.h index 0559619..c248f24 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.h +++ b/lib/Target/SystemZ/SystemZInstrInfo.h @@ -65,9 +65,6 @@ public: unsigned DestReg, unsigned SrcReg, bool KillSrc) const; - bool isMoveInstr(const MachineInstr& MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const; unsigned isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const; unsigned isStoreToStackSlot(const MachineInstr *MI, int &FrameIndex) const; diff --git a/lib/Target/SystemZ/SystemZRegisterInfo.cpp b/lib/Target/SystemZ/SystemZRegisterInfo.cpp index ae96b0b..f8d3e6a 100644 --- a/lib/Target/SystemZ/SystemZRegisterInfo.cpp +++ b/lib/Target/SystemZ/SystemZRegisterInfo.cpp @@ -92,10 +92,9 @@ int SystemZRegisterInfo::getFrameIndexOffset(const MachineFunction &MF, return Offset; } -unsigned +void SystemZRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value, - RegScavenger *RS) const { + int SPAdj, RegScavenger *RS) const { assert(SPAdj == 0 && "Unxpected"); unsigned i = 0; @@ -117,13 +116,13 @@ SystemZRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, // Offset is a either 12-bit unsigned or 20-bit signed integer. // FIXME: handle "too long" displacements. - int Offset = getFrameIndexOffset(MF, FrameIndex) + MI.getOperand(i+1).getImm(); + int Offset = + getFrameIndexOffset(MF, FrameIndex) + MI.getOperand(i+1).getImm(); // Check whether displacement is too long to fit into 12 bit zext field. MI.setDesc(TII.getMemoryInstr(MI.getOpcode(), Offset)); MI.getOperand(i+1).ChangeToImmediate(Offset); - return 0; } void diff --git a/lib/Target/SystemZ/SystemZRegisterInfo.h b/lib/Target/SystemZ/SystemZRegisterInfo.h index 670025f..5dae865 100644 --- a/lib/Target/SystemZ/SystemZRegisterInfo.h +++ b/lib/Target/SystemZ/SystemZRegisterInfo.h @@ -34,7 +34,7 @@ struct SystemZRegisterInfo : public SystemZGenRegisterInfo { BitVector getReservedRegs(const MachineFunction &MF) const; - bool hasReservedCallFrame(MachineFunction &MF) const { return true; } + bool hasReservedCallFrame(const MachineFunction &MF) const { return true; } bool hasFP(const MachineFunction &MF) const; int getFrameIndexOffset(const MachineFunction &MF, int FI) const; @@ -43,9 +43,8 @@ struct SystemZRegisterInfo : public SystemZGenRegisterInfo { MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; - unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value = NULL, - RegScavenger *RS = NULL) const; + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, diff --git a/lib/Target/TargetData.cpp b/lib/Target/TargetData.cpp index 5870d8a..f35c96d 100644 --- a/lib/Target/TargetData.cpp +++ b/lib/Target/TargetData.cpp @@ -34,8 +34,7 @@ using namespace llvm; // Handle the Pass registration stuff necessary to use TargetData's. // Register the default SparcV9 implementation... -static RegisterPass X("targetdata", "Target Data Layout", false, - true); +INITIALIZE_PASS(TargetData, "targetdata", "Target Data Layout", false, true); char TargetData::ID = 0; //===----------------------------------------------------------------------===// @@ -98,8 +97,8 @@ unsigned StructLayout::getElementContainingOffset(uint64_t Offset) const { //===----------------------------------------------------------------------===// TargetAlignElem -TargetAlignElem::get(AlignTypeEnum align_type, unsigned char abi_align, - unsigned char pref_align, uint32_t bit_width) { +TargetAlignElem::get(AlignTypeEnum align_type, unsigned abi_align, + unsigned pref_align, uint32_t bit_width) { assert(abi_align <= pref_align && "Preferred alignment worse than ABI!"); TargetAlignElem retval; retval.AlignType = align_type; @@ -197,10 +196,10 @@ void TargetData::init(StringRef Desc) { } unsigned Size = getInt(Specifier.substr(1)); Split = Token.split(':'); - unsigned char ABIAlign = getInt(Split.first) / 8; + unsigned ABIAlign = getInt(Split.first) / 8; Split = Split.second.split(':'); - unsigned char PrefAlign = getInt(Split.first) / 8; + unsigned PrefAlign = getInt(Split.first) / 8; if (PrefAlign == 0) PrefAlign = ABIAlign; setAlignment(AlignType, ABIAlign, PrefAlign, Size); @@ -227,19 +226,19 @@ void TargetData::init(StringRef Desc) { /// /// @note This has to exist, because this is a pass, but it should never be /// used. -TargetData::TargetData() : ImmutablePass(&ID) { +TargetData::TargetData() : ImmutablePass(ID) { report_fatal_error("Bad TargetData ctor used. " "Tool did not specify a TargetData to use?"); } TargetData::TargetData(const Module *M) - : ImmutablePass(&ID) { + : ImmutablePass(ID) { init(M->getDataLayout()); } void -TargetData::setAlignment(AlignTypeEnum align_type, unsigned char abi_align, - unsigned char pref_align, uint32_t bit_width) { +TargetData::setAlignment(AlignTypeEnum align_type, unsigned abi_align, + unsigned pref_align, uint32_t bit_width) { assert(abi_align <= pref_align && "Preferred alignment worse than ABI!"); for (unsigned i = 0, e = Alignments.size(); i != e; ++i) { if (Alignments[i].AlignType == align_type && @@ -455,15 +454,6 @@ uint64_t TargetData::getTypeSizeInBits(const Type *Ty) const { case Type::StructTyID: // Get the layout annotation... which is lazily created on demand. return getStructLayout(cast(Ty))->getSizeInBits(); - case Type::UnionTyID: { - const UnionType *UnTy = cast(Ty); - uint64_t Size = 0; - for (UnionType::element_iterator i = UnTy->element_begin(), - e = UnTy->element_end(); i != e; ++i) { - Size = std::max(Size, getTypeSizeInBits(*i)); - } - return Size; - } case Type::IntegerTyID: return cast(Ty)->getBitWidth(); case Type::VoidTyID: @@ -496,7 +486,7 @@ uint64_t TargetData::getTypeSizeInBits(const Type *Ty) const { Get the ABI (\a abi_or_pref == true) or preferred alignment (\a abi_or_pref == false) for the requested type \a Ty. */ -unsigned char TargetData::getAlignment(const Type *Ty, bool abi_or_pref) const { +unsigned TargetData::getAlignment(const Type *Ty, bool abi_or_pref) const { int AlignType = -1; assert(Ty->isSized() && "Cannot getTypeInfo() on a type that is unsized!"); @@ -518,18 +508,7 @@ unsigned char TargetData::getAlignment(const Type *Ty, bool abi_or_pref) const { // Get the layout annotation... which is lazily created on demand. const StructLayout *Layout = getStructLayout(cast(Ty)); unsigned Align = getAlignmentInfo(AGGREGATE_ALIGN, 0, abi_or_pref, Ty); - return std::max(Align, (unsigned)Layout->getAlignment()); - } - case Type::UnionTyID: { - const UnionType *UnTy = cast(Ty); - unsigned Align = 1; - - // Unions need the maximum alignment of all their entries - for (UnionType::element_iterator i = UnTy->element_begin(), - e = UnTy->element_end(); i != e; ++i) { - Align = std::max(Align, (unsigned)getAlignment(*i, abi_or_pref)); - } - return Align; + return std::max(Align, Layout->getAlignment()); } case Type::IntegerTyID: case Type::VoidTyID: @@ -556,18 +535,18 @@ unsigned char TargetData::getAlignment(const Type *Ty, bool abi_or_pref) const { abi_or_pref, Ty); } -unsigned char TargetData::getABITypeAlignment(const Type *Ty) const { +unsigned TargetData::getABITypeAlignment(const Type *Ty) const { return getAlignment(Ty, true); } /// getABIIntegerTypeAlignment - Return the minimum ABI-required alignment for /// an integer type of the specified bitwidth. -unsigned char TargetData::getABIIntegerTypeAlignment(unsigned BitWidth) const { +unsigned TargetData::getABIIntegerTypeAlignment(unsigned BitWidth) const { return getAlignmentInfo(INTEGER_ALIGN, BitWidth, true, 0); } -unsigned char TargetData::getCallFrameTypeAlignment(const Type *Ty) const { +unsigned TargetData::getCallFrameTypeAlignment(const Type *Ty) const { for (unsigned i = 0, e = Alignments.size(); i != e; ++i) if (Alignments[i].AlignType == STACK_ALIGN) return Alignments[i].ABIAlign; @@ -575,12 +554,12 @@ unsigned char TargetData::getCallFrameTypeAlignment(const Type *Ty) const { return getABITypeAlignment(Ty); } -unsigned char TargetData::getPrefTypeAlignment(const Type *Ty) const { +unsigned TargetData::getPrefTypeAlignment(const Type *Ty) const { return getAlignment(Ty, false); } -unsigned char TargetData::getPreferredTypeAlignmentShift(const Type *Ty) const { - unsigned Align = (unsigned) getPrefTypeAlignment(Ty); +unsigned TargetData::getPreferredTypeAlignmentShift(const Type *Ty) const { + unsigned Align = getPrefTypeAlignment(Ty); assert(!(Align & (Align-1)) && "Alignment is not a power of two!"); return Log2_32(Align); } @@ -615,18 +594,13 @@ uint64_t TargetData::getIndexedOffset(const Type *ptrTy, Value* const* Indices, // Update Ty to refer to current element Ty = STy->getElementType(FieldNo); - } else if (const UnionType *UnTy = dyn_cast(*TI)) { - unsigned FieldNo = cast(Indices[CurIDX])->getZExtValue(); - - // Offset into union is canonically 0, but type changes - Ty = UnTy->getElementType(FieldNo); } else { // Update Ty to refer to current element Ty = cast(Ty)->getElementType(); // Get the array index and the size of each array element. if (int64_t arrayIdx = cast(Indices[CurIDX])->getSExtValue()) - Result += arrayIdx * (int64_t)getTypeAllocSize(Ty); + Result += (uint64_t)arrayIdx * getTypeAllocSize(Ty); } } diff --git a/lib/Target/TargetMachine.cpp b/lib/Target/TargetMachine.cpp index 47c91df..705b1c0 100644 --- a/lib/Target/TargetMachine.cpp +++ b/lib/Target/TargetMachine.cpp @@ -30,7 +30,8 @@ namespace llvm { bool NoFramePointerElimNonLeaf; bool NoExcessFPPrecision; bool UnsafeFPMath; - bool FiniteOnlyFPMathOption; + bool NoInfsFPMath; + bool NoNaNsFPMath; bool HonorSignDependentRoundingFPMathOption; bool UseSoftFloat; FloatABI::ABIType FloatABIType; @@ -80,9 +81,14 @@ EnableUnsafeFPMath("enable-unsafe-fp-math", cl::location(UnsafeFPMath), cl::init(false)); static cl::opt -EnableFiniteOnlyFPMath("enable-finite-only-fp-math", - cl::desc("Enable optimizations that assumes non- NaNs / +-Infs"), - cl::location(FiniteOnlyFPMathOption), +EnableNoInfsFPMath("enable-no-infs-fp-math", + cl::desc("Enable FP math optimizations that assume no +-Infs"), + cl::location(NoInfsFPMath), + cl::init(false)); +static cl::opt +EnableNoNaNsFPMath("enable-no-nans-fp-math", + cl::desc("Enable FP math optimizations that assume no NaNs"), + cl::location(NoNaNsFPMath), cl::init(false)); static cl::opt EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math", @@ -290,12 +296,6 @@ namespace llvm { /// result is "less precise" than doing those operations individually. bool LessPreciseFPMAD() { return UnsafeFPMath || LessPreciseFPMADOption; } - /// FiniteOnlyFPMath - This returns true when the -enable-finite-only-fp-math - /// option is specified on the command line. If this returns false (default), - /// the code generator is not allowed to assume that FP arithmetic arguments - /// and results are never NaNs or +-Infs. - bool FiniteOnlyFPMath() { return FiniteOnlyFPMathOption; } - /// HonorSignDependentRoundingFPMath - Return true if the codegen must assume /// that the rounding mode of the FPU can change from its default. bool HonorSignDependentRoundingFPMath() { diff --git a/lib/Target/TargetRegisterInfo.cpp b/lib/Target/TargetRegisterInfo.cpp index 49bfad5..55f222c 100644 --- a/lib/Target/TargetRegisterInfo.cpp +++ b/lib/Target/TargetRegisterInfo.cpp @@ -63,7 +63,7 @@ TargetRegisterInfo::getMinimalPhysRegClass(unsigned reg, EVT VT) const { /// getAllocatableSetForRC - Toggle the bits that represent allocatable /// registers for the specific register class. static void getAllocatableSetForRC(const MachineFunction &MF, - const TargetRegisterClass *RC, BitVector &R){ + const TargetRegisterClass *RC, BitVector &R){ for (TargetRegisterClass::iterator I = RC->allocation_order_begin(MF), E = RC->allocation_order_end(MF); I != E; ++I) R.set(*I); @@ -74,12 +74,16 @@ BitVector TargetRegisterInfo::getAllocatableSet(const MachineFunction &MF, BitVector Allocatable(NumRegs); if (RC) { getAllocatableSetForRC(MF, RC, Allocatable); - return Allocatable; + } else { + for (TargetRegisterInfo::regclass_iterator I = regclass_begin(), + E = regclass_end(); I != E; ++I) + getAllocatableSetForRC(MF, *I, Allocatable); } - for (TargetRegisterInfo::regclass_iterator I = regclass_begin(), - E = regclass_end(); I != E; ++I) - getAllocatableSetForRC(MF, *I, Allocatable); + // Mask out the reserved registers + BitVector Reserved = getReservedRegs(MF); + Allocatable ^= Reserved & Allocatable; + return Allocatable; } diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp index f1e66ab..f8588d8 100644 --- a/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -9,6 +9,8 @@ #include "llvm/Target/TargetAsmParser.h" #include "X86.h" +#include "X86Subtarget.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" @@ -19,6 +21,7 @@ #include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetAsmParser.h" using namespace llvm; @@ -28,6 +31,7 @@ struct X86Operand; class X86ATTAsmParser : public TargetAsmParser { MCAsmParser &Parser; + TargetMachine &TM; protected: unsigned Is64Bit : 1; @@ -37,8 +41,6 @@ private: MCAsmLexer &getLexer() const { return Parser.getLexer(); } - void Warning(SMLoc L, const Twine &Msg) { Parser.Warning(L, Msg); } - bool Error(SMLoc L, const Twine &Msg) { return Parser.Error(L, Msg); } bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc); @@ -48,13 +50,14 @@ private: bool ParseDirectiveWord(unsigned Size, SMLoc L); - void InstructionCleanup(MCInst &Inst); + bool MatchInstruction(SMLoc IDLoc, + const SmallVectorImpl &Operands, + MCInst &Inst); - /// @name Auto-generated Match Functions + /// @name Auto-generated Matcher Functions /// { - bool MatchInstruction(const SmallVectorImpl &Operands, - MCInst &Inst); + unsigned ComputeAvailableFeatures(const X86Subtarget *Subtarget) const; bool MatchInstructionImpl( const SmallVectorImpl &Operands, MCInst &Inst); @@ -62,27 +65,32 @@ private: /// } public: - X86ATTAsmParser(const Target &T, MCAsmParser &_Parser) - : TargetAsmParser(T), Parser(_Parser) {} + X86ATTAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &TM) + : TargetAsmParser(T), Parser(_Parser), TM(TM) { + + // Initialize the set of available features. + setAvailableFeatures(ComputeAvailableFeatures( + &TM.getSubtarget())); + } virtual bool ParseInstruction(StringRef Name, SMLoc NameLoc, SmallVectorImpl &Operands); virtual bool ParseDirective(AsmToken DirectiveID); }; - + class X86_32ATTAsmParser : public X86ATTAsmParser { public: - X86_32ATTAsmParser(const Target &T, MCAsmParser &_Parser) - : X86ATTAsmParser(T, _Parser) { + X86_32ATTAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &TM) + : X86ATTAsmParser(T, _Parser, TM) { Is64Bit = false; } }; class X86_64ATTAsmParser : public X86ATTAsmParser { public: - X86_64ATTAsmParser(const Target &T, MCAsmParser &_Parser) - : X86ATTAsmParser(T, _Parser) { + X86_64ATTAsmParser(const Target &T, MCAsmParser &_Parser, TargetMachine &TM) + : X86ATTAsmParser(T, _Parser, TM) { Is64Bit = true; } }; @@ -90,7 +98,7 @@ public: } // end anonymous namespace /// @name Auto-generated Match Functions -/// { +/// { static unsigned MatchRegisterName(StringRef Name); @@ -109,7 +117,7 @@ struct X86Operand : public MCParsedAsmOperand { } Kind; SMLoc StartLoc, EndLoc; - + union { struct { const char *Data; @@ -141,6 +149,8 @@ struct X86Operand : public MCParsedAsmOperand { /// getEndLoc - Get the location of the last token of this operand. SMLoc getEndLoc() const { return EndLoc; } + virtual void dump(raw_ostream &OS) const {} + StringRef getToken() const { assert(Kind == Token && "Invalid access!"); return StringRef(Tok.Data, Tok.Length); @@ -185,7 +195,7 @@ struct X86Operand : public MCParsedAsmOperand { bool isToken() const {return Kind == Token; } bool isImm() const { return Kind == Immediate; } - + bool isImmSExti16i8() const { if (!isImm()) return false; @@ -260,10 +270,6 @@ struct X86Operand : public MCParsedAsmOperand { !getMemIndexReg() && getMemScale() == 1; } - bool isNoSegMem() const { - return Kind == Memory && !getMemSegReg(); - } - bool isReg() const { return Kind == Register; } void addExpr(MCInst &Inst, const MCExpr *Expr) const { @@ -298,14 +304,6 @@ struct X86Operand : public MCParsedAsmOperand { Inst.addOperand(MCOperand::CreateExpr(getMemDisp())); } - void addNoSegMemOperands(MCInst &Inst, unsigned N) const { - assert((N == 4) && "Invalid number of operands!"); - Inst.addOperand(MCOperand::CreateReg(getMemBaseReg())); - Inst.addOperand(MCOperand::CreateImm(getMemScale())); - Inst.addOperand(MCOperand::CreateReg(getMemIndexReg())); - addExpr(Inst, getMemDisp()); - } - static X86Operand *CreateToken(StringRef Str, SMLoc Loc) { X86Operand *Res = new X86Operand(Token, Loc, Loc); Res->Tok.Data = Str.data(); @@ -376,13 +374,19 @@ bool X86ATTAsmParser::ParseRegister(unsigned &RegNo, // FIXME: Validate register for the current architecture; we have to do // validation later, so maybe there is no need for this here. RegNo = MatchRegisterName(Tok.getString()); - + + // FIXME: This should be done using Requires and + // Requires so "eiz" usage in 64-bit instructions + // can be also checked. + if (RegNo == X86::RIZ && !Is64Bit) + return Error(Tok.getLoc(), "riz register in 64-bit mode only"); + // Parse %st(1) and "%st" as "%st(0)" if (RegNo == 0 && Tok.getString() == "st") { RegNo = X86::ST0; EndLoc = Tok.getLoc(); Parser.Lex(); // Eat 'st' - + // Check to see if we have '(4)' after %st. if (getLexer().isNot(AsmToken::LParen)) return false; @@ -403,15 +407,15 @@ bool X86ATTAsmParser::ParseRegister(unsigned &RegNo, case 7: RegNo = X86::ST7; break; default: return Error(IntTok.getLoc(), "invalid stack index"); } - + if (getParser().Lex().isNot(AsmToken::RParen)) return Error(Parser.getTok().getLoc(), "expected ')'"); - + EndLoc = Tok.getLoc(); Parser.Lex(); // Eat ')' return false; } - + // If this is "db[0-7]", match it as an alias // for dr[0-7]. if (RegNo == 0 && Tok.getString().size() == 3 && @@ -426,14 +430,14 @@ bool X86ATTAsmParser::ParseRegister(unsigned &RegNo, case '6': RegNo = X86::DR6; break; case '7': RegNo = X86::DR7; break; } - + if (RegNo != 0) { EndLoc = Tok.getLoc(); Parser.Lex(); // Eat it. return false; } } - + if (RegNo == 0) return Error(Tok.getLoc(), "invalid register name"); @@ -452,13 +456,17 @@ X86Operand *X86ATTAsmParser::ParseOperand() { unsigned RegNo; SMLoc Start, End; if (ParseRegister(RegNo, Start, End)) return 0; - + if (RegNo == X86::EIZ || RegNo == X86::RIZ) { + Error(Start, "eiz and riz can only be used as index registers"); + return 0; + } + // If this is a segment register followed by a ':', then this is the start // of a memory reference, otherwise this is a normal register reference. if (getLexer().isNot(AsmToken::Colon)) return X86Operand::CreateReg(RegNo, Start, End); - - + + getParser().Lex(); // Eat the colon. return ParseMemOperand(RegNo, Start); } @@ -477,7 +485,7 @@ X86Operand *X86ATTAsmParser::ParseOperand() { /// ParseMemOperand: segment: disp(basereg, indexreg, scale). The '%ds:' prefix /// has already been parsed if present. X86Operand *X86ATTAsmParser::ParseMemOperand(unsigned SegReg, SMLoc MemStart) { - + // We have to disambiguate a parenthesized expression "(4+5)" from the start // of a memory operand with a missing displacement "(%ebx)" or "(,%eax)". The // only way to do this without lookahead is to eat the '(' and see what is @@ -486,7 +494,7 @@ X86Operand *X86ATTAsmParser::ParseMemOperand(unsigned SegReg, SMLoc MemStart) { if (getLexer().isNot(AsmToken::LParen)) { SMLoc ExprEnd; if (getParser().ParseExpression(Disp, ExprEnd)) return 0; - + // After parsing the base expression we could either have a parenthesized // memory address or not. If not, return now. If so, eat the (. if (getLexer().isNot(AsmToken::LParen)) { @@ -495,7 +503,7 @@ X86Operand *X86ATTAsmParser::ParseMemOperand(unsigned SegReg, SMLoc MemStart) { return X86Operand::CreateMem(Disp, MemStart, ExprEnd); return X86Operand::CreateMem(SegReg, Disp, 0, 0, 1, MemStart, ExprEnd); } - + // Eat the '('. Parser.Lex(); } else { @@ -503,17 +511,17 @@ X86Operand *X86ATTAsmParser::ParseMemOperand(unsigned SegReg, SMLoc MemStart) { // so we have to eat the ( to see beyond it. SMLoc LParenLoc = Parser.getTok().getLoc(); Parser.Lex(); // Eat the '('. - + if (getLexer().is(AsmToken::Percent) || getLexer().is(AsmToken::Comma)) { // Nothing to do here, fall into the code below with the '(' part of the // memory operand consumed. } else { SMLoc ExprEnd; - + // It must be an parenthesized expression, parse it now. if (getParser().ParseParenExpression(Disp, ExprEnd)) return 0; - + // After parsing the base expression we could either have a parenthesized // memory address or not. If not, return now. If so, eat the (. if (getLexer().isNot(AsmToken::LParen)) { @@ -522,21 +530,25 @@ X86Operand *X86ATTAsmParser::ParseMemOperand(unsigned SegReg, SMLoc MemStart) { return X86Operand::CreateMem(Disp, LParenLoc, ExprEnd); return X86Operand::CreateMem(SegReg, Disp, 0, 0, 1, MemStart, ExprEnd); } - + // Eat the '('. Parser.Lex(); } } - + // If we reached here, then we just ate the ( of the memory operand. Process // the rest of the memory operand. unsigned BaseReg = 0, IndexReg = 0, Scale = 1; - + if (getLexer().is(AsmToken::Percent)) { SMLoc L; if (ParseRegister(BaseReg, L, L)) return 0; + if (BaseReg == X86::EIZ || BaseReg == X86::RIZ) { + Error(L, "eiz and riz can only be used as index registers"); + return 0; + } } - + if (getLexer().is(AsmToken::Comma)) { Parser.Lex(); // Eat the comma. @@ -545,11 +557,11 @@ X86Operand *X86ATTAsmParser::ParseMemOperand(unsigned SegReg, SMLoc MemStart) { // correctly. // // Not that even though it would be completely consistent to support syntax - // like "1(%eax,,1)", the assembler doesn't. + // like "1(%eax,,1)", the assembler doesn't. Use "eiz" or "riz" for this. if (getLexer().is(AsmToken::Percent)) { SMLoc L; if (ParseRegister(IndexReg, L, L)) return 0; - + if (getLexer().isNot(AsmToken::RParen)) { // Parse the scale amount: // ::= ',' [scale-expression] @@ -566,7 +578,7 @@ X86Operand *X86ATTAsmParser::ParseMemOperand(unsigned SegReg, SMLoc MemStart) { int64_t ScaleVal; if (getParser().ParseAbsoluteExpression(ScaleVal)) return 0; - + // Validate the scale amount. if (ScaleVal != 1 && ScaleVal != 2 && ScaleVal != 4 && ScaleVal != 8){ Error(Loc, "scale factor in address must be 1, 2, 4 or 8"); @@ -576,19 +588,20 @@ X86Operand *X86ATTAsmParser::ParseMemOperand(unsigned SegReg, SMLoc MemStart) { } } } else if (getLexer().isNot(AsmToken::RParen)) { - // Otherwise we have the unsupported form of a scale amount without an + // A scale amount without an index is ignored. // index. SMLoc Loc = Parser.getTok().getLoc(); int64_t Value; if (getParser().ParseAbsoluteExpression(Value)) return 0; - - Error(Loc, "cannot have scale factor without index register"); - return 0; + + if (Value != 1) + Warning(Loc, "scale factor without index register is ignored"); + Scale = 1; } } - + // Ok, we've eaten the memory operand, verify we have a ')' and eat it too. if (getLexer().isNot(AsmToken::RParen)) { Error(Parser.getTok().getLoc(), "unexpected token in memory operand"); @@ -596,7 +609,7 @@ X86Operand *X86ATTAsmParser::ParseMemOperand(unsigned SegReg, SMLoc MemStart) { } SMLoc MemEnd = Parser.getTok().getLoc(); Parser.Lex(); // Eat the ')'. - + return X86Operand::CreateMem(SegReg, Disp, BaseReg, IndexReg, Scale, MemStart, MemEnd); } @@ -743,6 +756,23 @@ ParseInstruction(StringRef Name, SMLoc NameLoc, } } } + + // FIXME: Hack to recognize vpclmuldq + if (PatchedName.startswith("vpclmul")) { + unsigned CLMULQuadWordSelect = StringSwitch( + PatchedName.slice(7, PatchedName.size() - 2)) + .Case("lqlq", 0x00) // src1[63:0], src2[63:0] + .Case("hqlq", 0x01) // src1[127:64], src2[63:0] + .Case("lqhq", 0x10) // src1[63:0], src2[127:64] + .Case("hqhq", 0x11) // src1[127:64], src2[127:64] + .Default(~0U); + if (CLMULQuadWordSelect != ~0U) { + ExtraImmOp = MCConstantExpr::Create(CLMULQuadWordSelect, + getParser().getContext()); + assert(PatchedName.endswith("dq") && "Unexpected mnemonic!"); + PatchedName = "vpclmulqdq"; + } + } Operands.push_back(X86Operand::CreateToken(PatchedName, NameLoc)); if (ExtraImmOp) @@ -785,6 +815,20 @@ ParseInstruction(StringRef Name, SMLoc NameLoc, Operands.erase(Operands.begin() + 1); } + // FIXME: Hack to handle "out[bwl]? %al, (%dx)" -> "outb %al, %dx". + if ((Name == "outb" || Name == "outw" || Name == "outl" || Name == "out") && + Operands.size() == 3) { + X86Operand &Op = *(X86Operand*)Operands.back(); + if (Op.isMem() && Op.Mem.SegReg == 0 && + isa(Op.Mem.Disp) && + cast(Op.Mem.Disp)->getValue() == 0 && + Op.Mem.BaseReg == MatchRegisterName("dx") && Op.Mem.IndexReg == 0) { + SMLoc Loc = Op.getEndLoc(); + Operands.back() = X86Operand::CreateReg(Op.Mem.BaseReg, Loc, Loc); + delete &Op; + } + } + // FIXME: Hack to handle "f{mul*,add*,sub*,div*} $op, st(0)" the same as // "f{mul*,add*,sub*,div*} $op" if ((Name.startswith("fmul") || Name.startswith("fadd") || @@ -796,6 +840,16 @@ ParseInstruction(StringRef Name, SMLoc NameLoc, Operands.erase(Operands.begin() + 2); } + // FIXME: Hack to handle "imul , B" which is an alias for "imul , B, + // B". + if (Name.startswith("imul") && Operands.size() == 3 && + static_cast(Operands[1])->isImm() && + static_cast(Operands.back())->isReg()) { + X86Operand *Op = static_cast(Operands.back()); + Operands.push_back(X86Operand::CreateReg(Op->getReg(), Op->getStartLoc(), + Op->getEndLoc())); + } + return false; } @@ -819,7 +873,7 @@ bool X86ATTAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) { if (getLexer().is(AsmToken::EndOfStatement)) break; - + // FIXME: Improve diagnostic. if (getLexer().isNot(AsmToken::Comma)) return Error(L, "unexpected token in directive"); @@ -831,82 +885,32 @@ bool X86ATTAsmParser::ParseDirectiveWord(unsigned Size, SMLoc L) { return false; } -/// LowerMOffset - Lower an 'moffset' form of an instruction, which just has a -/// imm operand, to having "rm" or "mr" operands with the offset in the disp -/// field. -static void LowerMOffset(MCInst &Inst, unsigned Opc, unsigned RegNo, - bool isMR) { - MCOperand Disp = Inst.getOperand(0); - - // Start over with an empty instruction. - Inst = MCInst(); - Inst.setOpcode(Opc); - - if (!isMR) - Inst.addOperand(MCOperand::CreateReg(RegNo)); - - // Add the mem operand. - Inst.addOperand(MCOperand::CreateReg(0)); // Segment - Inst.addOperand(MCOperand::CreateImm(1)); // Scale - Inst.addOperand(MCOperand::CreateReg(0)); // IndexReg - Inst.addOperand(Disp); // Displacement - Inst.addOperand(MCOperand::CreateReg(0)); // BaseReg - - if (isMR) - Inst.addOperand(MCOperand::CreateReg(RegNo)); -} - -// FIXME: Custom X86 cleanup function to implement a temporary hack to handle -// matching INCL/DECL correctly for x86_64. This needs to be replaced by a -// proper mechanism for supporting (ambiguous) feature dependent instructions. -void X86ATTAsmParser::InstructionCleanup(MCInst &Inst) { - if (!Is64Bit) return; - - switch (Inst.getOpcode()) { - case X86::DEC16r: Inst.setOpcode(X86::DEC64_16r); break; - case X86::DEC16m: Inst.setOpcode(X86::DEC64_16m); break; - case X86::DEC32r: Inst.setOpcode(X86::DEC64_32r); break; - case X86::DEC32m: Inst.setOpcode(X86::DEC64_32m); break; - case X86::INC16r: Inst.setOpcode(X86::INC64_16r); break; - case X86::INC16m: Inst.setOpcode(X86::INC64_16m); break; - case X86::INC32r: Inst.setOpcode(X86::INC64_32r); break; - case X86::INC32m: Inst.setOpcode(X86::INC64_32m); break; - - // moffset instructions are x86-32 only. - case X86::MOV8o8a: LowerMOffset(Inst, X86::MOV8rm , X86::AL , false); break; - case X86::MOV16o16a: LowerMOffset(Inst, X86::MOV16rm, X86::AX , false); break; - case X86::MOV32o32a: LowerMOffset(Inst, X86::MOV32rm, X86::EAX, false); break; - case X86::MOV8ao8: LowerMOffset(Inst, X86::MOV8mr , X86::AL , true); break; - case X86::MOV16ao16: LowerMOffset(Inst, X86::MOV16mr, X86::AX , true); break; - case X86::MOV32ao32: LowerMOffset(Inst, X86::MOV32mr, X86::EAX, true); break; - } -} bool -X86ATTAsmParser::MatchInstruction(const SmallVectorImpl +X86ATTAsmParser::MatchInstruction(SMLoc IDLoc, + const SmallVectorImpl &Operands, MCInst &Inst) { + assert(!Operands.empty() && "Unexpect empty operand list!"); + + X86Operand *Op = static_cast(Operands[0]); + assert(Op->isToken() && "Leading operand should always be a mnemonic!"); + // First, try a direct match. if (!MatchInstructionImpl(Operands, Inst)) return false; - // Ignore anything which is obviously not a suffix match. - if (Operands.size() == 0) - return true; - X86Operand *Op = static_cast(Operands[0]); - if (!Op->isToken() || Op->getToken().size() > 15) - return true; - // FIXME: Ideally, we would only attempt suffix matches for things which are // valid prefixes, and we could just infer the right unambiguous // type. However, that requires substantially more matcher support than the // following hack. // Change the operand to point to a temporary token. - char Tmp[16]; StringRef Base = Op->getToken(); - memcpy(Tmp, Base.data(), Base.size()); - Op->setTokenValue(StringRef(Tmp, Base.size() + 1)); + SmallString<16> Tmp; + Tmp += Base; + Tmp += ' '; + Op->setTokenValue(Tmp.str()); // Check for the various suffix matches. Tmp[Base.size()] = 'b'; @@ -928,6 +932,38 @@ X86ATTAsmParser::MatchInstruction(const SmallVectorImpl return false; // Otherwise, the match failed. + + // If we had multiple suffix matches, then identify this as an ambiguous + // match. + if (MatchB + MatchW + MatchL + MatchQ != 4) { + char MatchChars[4]; + unsigned NumMatches = 0; + if (!MatchB) + MatchChars[NumMatches++] = 'b'; + if (!MatchW) + MatchChars[NumMatches++] = 'w'; + if (!MatchL) + MatchChars[NumMatches++] = 'l'; + if (!MatchQ) + MatchChars[NumMatches++] = 'q'; + + SmallString<126> Msg; + raw_svector_ostream OS(Msg); + OS << "ambiguous instructions require an explicit suffix (could be "; + for (unsigned i = 0; i != NumMatches; ++i) { + if (i != 0) + OS << ", "; + if (i + 1 == NumMatches) + OS << "or "; + OS << "'" << Base << MatchChars[i] << "'"; + } + OS << ")"; + Error(IDLoc, OS.str()); + } else { + // FIXME: We should give nicer diagnostics about the exact failure. + Error(IDLoc, "unrecognized instruction"); + } + return true; } diff --git a/lib/Target/X86/AsmPrinter/CMakeLists.txt b/lib/Target/X86/AsmPrinter/CMakeLists.txt index b70a587..033973e 100644 --- a/lib/Target/X86/AsmPrinter/CMakeLists.txt +++ b/lib/Target/X86/AsmPrinter/CMakeLists.txt @@ -2,8 +2,7 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/ add_llvm_library(LLVMX86AsmPrinter X86ATTInstPrinter.cpp - X86AsmPrinter.cpp X86IntelInstPrinter.cpp - X86MCInstLower.cpp + X86InstComments.cpp ) add_dependencies(LLVMX86AsmPrinter X86CodeGenTable_gen) diff --git a/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp b/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp index f2cdb5b..554b96c 100644 --- a/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp +++ b/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp @@ -14,6 +14,7 @@ #define DEBUG_TYPE "asm-printer" #include "X86ATTInstPrinter.h" +#include "X86InstComments.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCExpr.h" @@ -31,6 +32,10 @@ using namespace llvm; void X86ATTInstPrinter::printInst(const MCInst *MI, raw_ostream &OS) { printInstruction(MI, OS); + + // If verbose assembly is enabled, we can print some informative comments. + if (CommentStream) + EmitAnyX86InstComments(MI, *CommentStream, getRegisterName); } StringRef X86ATTInstPrinter::getOpcodeName(unsigned Opcode) const { return getInstructionName(Opcode); diff --git a/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h b/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h index 3be4bae..eb98664 100644 --- a/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h +++ b/lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h @@ -56,6 +56,9 @@ public: void printi128mem(const MCInst *MI, unsigned OpNo, raw_ostream &O) { printMemReference(MI, OpNo, O); } + void printi256mem(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + printMemReference(MI, OpNo, O); + } void printf32mem(const MCInst *MI, unsigned OpNo, raw_ostream &O) { printMemReference(MI, OpNo, O); } diff --git a/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp b/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp deleted file mode 100644 index 08e6486..0000000 --- a/lib/Target/X86/AsmPrinter/X86AsmPrinter.cpp +++ /dev/null @@ -1,680 +0,0 @@ -//===-- X86AsmPrinter.cpp - Convert X86 LLVM code to AT&T assembly --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains a printer that converts from our internal representation -// of machine-dependent LLVM code to X86 machine code. -// -//===----------------------------------------------------------------------===// - -#include "X86AsmPrinter.h" -#include "X86ATTInstPrinter.h" -#include "X86IntelInstPrinter.h" -#include "X86MCInstLower.h" -#include "X86.h" -#include "X86COFFMachineModuleInfo.h" -#include "X86MachineFunctionInfo.h" -#include "X86TargetMachine.h" -#include "llvm/CallingConv.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Module.h" -#include "llvm/Type.h" -#include "llvm/Assembly/Writer.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCSectionMachO.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/CodeGen/MachineJumpTableInfo.h" -#include "llvm/CodeGen/MachineModuleInfoImpls.h" -#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" -#include "llvm/Support/COFF.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Target/Mangler.h" -#include "llvm/Target/TargetOptions.h" -#include "llvm/Target/TargetRegistry.h" -#include "llvm/ADT/SmallString.h" -using namespace llvm; - -//===----------------------------------------------------------------------===// -// Primitive Helper Functions. -//===----------------------------------------------------------------------===// - -void X86AsmPrinter::PrintPICBaseSymbol(raw_ostream &O) const { - const TargetLowering *TLI = TM.getTargetLowering(); - O << *static_cast(TLI)->getPICBaseSymbol(MF, - OutContext); -} - -/// runOnMachineFunction - Emit the function body. -/// -bool X86AsmPrinter::runOnMachineFunction(MachineFunction &MF) { - SetupMachineFunction(MF); - - if (Subtarget->isTargetCOFF()) { - bool Intrn = MF.getFunction()->hasInternalLinkage(); - OutStreamer.BeginCOFFSymbolDef(CurrentFnSym); - OutStreamer.EmitCOFFSymbolStorageClass(Intrn ? COFF::IMAGE_SYM_CLASS_STATIC - : COFF::IMAGE_SYM_CLASS_EXTERNAL); - OutStreamer.EmitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION - << COFF::SCT_COMPLEX_TYPE_SHIFT); - OutStreamer.EndCOFFSymbolDef(); - } - - // Have common code print out the function header with linkage info etc. - EmitFunctionHeader(); - - // Emit the rest of the function body. - EmitFunctionBody(); - - // We didn't modify anything. - return false; -} - -/// printSymbolOperand - Print a raw symbol reference operand. This handles -/// jump tables, constant pools, global address and external symbols, all of -/// which print to a label with various suffixes for relocation types etc. -void X86AsmPrinter::printSymbolOperand(const MachineOperand &MO, - raw_ostream &O) { - switch (MO.getType()) { - default: llvm_unreachable("unknown symbol type!"); - case MachineOperand::MO_JumpTableIndex: - O << *GetJTISymbol(MO.getIndex()); - break; - case MachineOperand::MO_ConstantPoolIndex: - O << *GetCPISymbol(MO.getIndex()); - printOffset(MO.getOffset(), O); - break; - case MachineOperand::MO_GlobalAddress: { - const GlobalValue *GV = MO.getGlobal(); - - MCSymbol *GVSym; - if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB) - GVSym = GetSymbolWithGlobalValueBase(GV, "$stub"); - else if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY || - MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE || - MO.getTargetFlags() == X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE) - GVSym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); - else - GVSym = Mang->getSymbol(GV); - - // Handle dllimport linkage. - if (MO.getTargetFlags() == X86II::MO_DLLIMPORT) - GVSym = OutContext.GetOrCreateSymbol(Twine("__imp_") + GVSym->getName()); - - if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY || - MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE) { - MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); - MachineModuleInfoImpl::StubValueTy &StubSym = - MMI->getObjFileInfo().getGVStubEntry(Sym); - if (StubSym.getPointer() == 0) - StubSym = MachineModuleInfoImpl:: - StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); - } else if (MO.getTargetFlags() == X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE){ - MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); - MachineModuleInfoImpl::StubValueTy &StubSym = - MMI->getObjFileInfo().getHiddenGVStubEntry(Sym); - if (StubSym.getPointer() == 0) - StubSym = MachineModuleInfoImpl:: - StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); - } else if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB) { - MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$stub"); - MachineModuleInfoImpl::StubValueTy &StubSym = - MMI->getObjFileInfo().getFnStubEntry(Sym); - if (StubSym.getPointer() == 0) - StubSym = MachineModuleInfoImpl:: - StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); - } - - // If the name begins with a dollar-sign, enclose it in parens. We do this - // to avoid having it look like an integer immediate to the assembler. - if (GVSym->getName()[0] != '$') - O << *GVSym; - else - O << '(' << *GVSym << ')'; - printOffset(MO.getOffset(), O); - break; - } - case MachineOperand::MO_ExternalSymbol: { - const MCSymbol *SymToPrint; - if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB) { - SmallString<128> TempNameStr; - TempNameStr += StringRef(MO.getSymbolName()); - TempNameStr += StringRef("$stub"); - - MCSymbol *Sym = GetExternalSymbolSymbol(TempNameStr.str()); - MachineModuleInfoImpl::StubValueTy &StubSym = - MMI->getObjFileInfo().getFnStubEntry(Sym); - if (StubSym.getPointer() == 0) { - TempNameStr.erase(TempNameStr.end()-5, TempNameStr.end()); - StubSym = MachineModuleInfoImpl:: - StubValueTy(OutContext.GetOrCreateSymbol(TempNameStr.str()), - true); - } - SymToPrint = StubSym.getPointer(); - } else { - SymToPrint = GetExternalSymbolSymbol(MO.getSymbolName()); - } - - // If the name begins with a dollar-sign, enclose it in parens. We do this - // to avoid having it look like an integer immediate to the assembler. - if (SymToPrint->getName()[0] != '$') - O << *SymToPrint; - else - O << '(' << *SymToPrint << '('; - break; - } - } - - switch (MO.getTargetFlags()) { - default: - llvm_unreachable("Unknown target flag on GV operand"); - case X86II::MO_NO_FLAG: // No flag. - break; - case X86II::MO_DARWIN_NONLAZY: - case X86II::MO_DLLIMPORT: - case X86II::MO_DARWIN_STUB: - // These affect the name of the symbol, not any suffix. - break; - case X86II::MO_GOT_ABSOLUTE_ADDRESS: - O << " + [.-"; - PrintPICBaseSymbol(O); - O << ']'; - break; - case X86II::MO_PIC_BASE_OFFSET: - case X86II::MO_DARWIN_NONLAZY_PIC_BASE: - case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE: - O << '-'; - PrintPICBaseSymbol(O); - break; - case X86II::MO_TLSGD: O << "@TLSGD"; break; - case X86II::MO_GOTTPOFF: O << "@GOTTPOFF"; break; - case X86II::MO_INDNTPOFF: O << "@INDNTPOFF"; break; - case X86II::MO_TPOFF: O << "@TPOFF"; break; - case X86II::MO_NTPOFF: O << "@NTPOFF"; break; - case X86II::MO_GOTPCREL: O << "@GOTPCREL"; break; - case X86II::MO_GOT: O << "@GOT"; break; - case X86II::MO_GOTOFF: O << "@GOTOFF"; break; - case X86II::MO_PLT: O << "@PLT"; break; - case X86II::MO_TLVP: O << "@TLVP"; break; - case X86II::MO_TLVP_PIC_BASE: - O << "@TLVP" << '-'; - PrintPICBaseSymbol(O); - break; - } -} - -/// print_pcrel_imm - This is used to print an immediate value that ends up -/// being encoded as a pc-relative value. These print slightly differently, for -/// example, a $ is not emitted. -void X86AsmPrinter::print_pcrel_imm(const MachineInstr *MI, unsigned OpNo, - raw_ostream &O) { - const MachineOperand &MO = MI->getOperand(OpNo); - switch (MO.getType()) { - default: llvm_unreachable("Unknown pcrel immediate operand"); - case MachineOperand::MO_Immediate: - O << MO.getImm(); - return; - case MachineOperand::MO_MachineBasicBlock: - O << *MO.getMBB()->getSymbol(); - return; - case MachineOperand::MO_GlobalAddress: - case MachineOperand::MO_ExternalSymbol: - printSymbolOperand(MO, O); - return; - } -} - - -void X86AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, - raw_ostream &O, const char *Modifier) { - const MachineOperand &MO = MI->getOperand(OpNo); - switch (MO.getType()) { - default: llvm_unreachable("unknown operand type!"); - case MachineOperand::MO_Register: { - O << '%'; - unsigned Reg = MO.getReg(); - if (Modifier && strncmp(Modifier, "subreg", strlen("subreg")) == 0) { - EVT VT = (strcmp(Modifier+6,"64") == 0) ? - MVT::i64 : ((strcmp(Modifier+6, "32") == 0) ? MVT::i32 : - ((strcmp(Modifier+6,"16") == 0) ? MVT::i16 : MVT::i8)); - Reg = getX86SubSuperRegister(Reg, VT); - } - O << X86ATTInstPrinter::getRegisterName(Reg); - return; - } - - case MachineOperand::MO_Immediate: - O << '$' << MO.getImm(); - return; - - case MachineOperand::MO_JumpTableIndex: - case MachineOperand::MO_ConstantPoolIndex: - case MachineOperand::MO_GlobalAddress: - case MachineOperand::MO_ExternalSymbol: { - O << '$'; - printSymbolOperand(MO, O); - break; - } - } -} - -void X86AsmPrinter::printSSECC(const MachineInstr *MI, unsigned Op, - raw_ostream &O) { - unsigned char value = MI->getOperand(Op).getImm(); - assert(value <= 7 && "Invalid ssecc argument!"); - switch (value) { - case 0: O << "eq"; break; - case 1: O << "lt"; break; - case 2: O << "le"; break; - case 3: O << "unord"; break; - case 4: O << "neq"; break; - case 5: O << "nlt"; break; - case 6: O << "nle"; break; - case 7: O << "ord"; break; - } -} - -void X86AsmPrinter::printLeaMemReference(const MachineInstr *MI, unsigned Op, - raw_ostream &O, const char *Modifier) { - const MachineOperand &BaseReg = MI->getOperand(Op); - const MachineOperand &IndexReg = MI->getOperand(Op+2); - const MachineOperand &DispSpec = MI->getOperand(Op+3); - - // If we really don't want to print out (rip), don't. - bool HasBaseReg = BaseReg.getReg() != 0; - if (HasBaseReg && Modifier && !strcmp(Modifier, "no-rip") && - BaseReg.getReg() == X86::RIP) - HasBaseReg = false; - - // HasParenPart - True if we will print out the () part of the mem ref. - bool HasParenPart = IndexReg.getReg() || HasBaseReg; - - if (DispSpec.isImm()) { - int DispVal = DispSpec.getImm(); - if (DispVal || !HasParenPart) - O << DispVal; - } else { - assert(DispSpec.isGlobal() || DispSpec.isCPI() || - DispSpec.isJTI() || DispSpec.isSymbol()); - printSymbolOperand(MI->getOperand(Op+3), O); - } - - if (HasParenPart) { - assert(IndexReg.getReg() != X86::ESP && - "X86 doesn't allow scaling by ESP"); - - O << '('; - if (HasBaseReg) - printOperand(MI, Op, O, Modifier); - - if (IndexReg.getReg()) { - O << ','; - printOperand(MI, Op+2, O, Modifier); - unsigned ScaleVal = MI->getOperand(Op+1).getImm(); - if (ScaleVal != 1) - O << ',' << ScaleVal; - } - O << ')'; - } -} - -void X86AsmPrinter::printMemReference(const MachineInstr *MI, unsigned Op, - raw_ostream &O, const char *Modifier) { - assert(isMem(MI, Op) && "Invalid memory reference!"); - const MachineOperand &Segment = MI->getOperand(Op+4); - if (Segment.getReg()) { - printOperand(MI, Op+4, O, Modifier); - O << ':'; - } - printLeaMemReference(MI, Op, O, Modifier); -} - -void X86AsmPrinter::printPICLabel(const MachineInstr *MI, unsigned Op, - raw_ostream &O) { - PrintPICBaseSymbol(O); - O << '\n'; - PrintPICBaseSymbol(O); - O << ':'; -} - -bool X86AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode, - raw_ostream &O) { - unsigned Reg = MO.getReg(); - switch (Mode) { - default: return true; // Unknown mode. - case 'b': // Print QImode register - Reg = getX86SubSuperRegister(Reg, MVT::i8); - break; - case 'h': // Print QImode high register - Reg = getX86SubSuperRegister(Reg, MVT::i8, true); - break; - case 'w': // Print HImode register - Reg = getX86SubSuperRegister(Reg, MVT::i16); - break; - case 'k': // Print SImode register - Reg = getX86SubSuperRegister(Reg, MVT::i32); - break; - case 'q': // Print DImode register - Reg = getX86SubSuperRegister(Reg, MVT::i64); - break; - } - - O << '%' << X86ATTInstPrinter::getRegisterName(Reg); - return false; -} - -/// PrintAsmOperand - Print out an operand for an inline asm expression. -/// -bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, - unsigned AsmVariant, - const char *ExtraCode, raw_ostream &O) { - // Does this asm operand have a single letter operand modifier? - if (ExtraCode && ExtraCode[0]) { - if (ExtraCode[1] != 0) return true; // Unknown modifier. - - const MachineOperand &MO = MI->getOperand(OpNo); - - switch (ExtraCode[0]) { - default: return true; // Unknown modifier. - case 'a': // This is an address. Currently only 'i' and 'r' are expected. - if (MO.isImm()) { - O << MO.getImm(); - return false; - } - if (MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isSymbol()) { - printSymbolOperand(MO, O); - if (Subtarget->isPICStyleRIPRel()) - O << "(%rip)"; - return false; - } - if (MO.isReg()) { - O << '('; - printOperand(MI, OpNo, O); - O << ')'; - return false; - } - return true; - - case 'c': // Don't print "$" before a global var name or constant. - if (MO.isImm()) - O << MO.getImm(); - else if (MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isSymbol()) - printSymbolOperand(MO, O); - else - printOperand(MI, OpNo, O); - return false; - - case 'A': // Print '*' before a register (it must be a register) - if (MO.isReg()) { - O << '*'; - printOperand(MI, OpNo, O); - return false; - } - return true; - - case 'b': // Print QImode register - case 'h': // Print QImode high register - case 'w': // Print HImode register - case 'k': // Print SImode register - case 'q': // Print DImode register - if (MO.isReg()) - return printAsmMRegister(MO, ExtraCode[0], O); - printOperand(MI, OpNo, O); - return false; - - case 'P': // This is the operand of a call, treat specially. - print_pcrel_imm(MI, OpNo, O); - return false; - - case 'n': // Negate the immediate or print a '-' before the operand. - // Note: this is a temporary solution. It should be handled target - // independently as part of the 'MC' work. - if (MO.isImm()) { - O << -MO.getImm(); - return false; - } - O << '-'; - } - } - - printOperand(MI, OpNo, O); - return false; -} - -bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, - unsigned OpNo, unsigned AsmVariant, - const char *ExtraCode, - raw_ostream &O) { - if (ExtraCode && ExtraCode[0]) { - if (ExtraCode[1] != 0) return true; // Unknown modifier. - - switch (ExtraCode[0]) { - default: return true; // Unknown modifier. - case 'b': // Print QImode register - case 'h': // Print QImode high register - case 'w': // Print HImode register - case 'k': // Print SImode register - case 'q': // Print SImode register - // These only apply to registers, ignore on mem. - break; - case 'P': // Don't print @PLT, but do print as memory. - printMemReference(MI, OpNo, O, "no-rip"); - return false; - } - } - printMemReference(MI, OpNo, O); - return false; -} - -void X86AsmPrinter::EmitStartOfAsmFile(Module &M) { - if (Subtarget->isTargetDarwin()) - OutStreamer.SwitchSection(getObjFileLowering().getTextSection()); -} - - -void X86AsmPrinter::EmitEndOfAsmFile(Module &M) { - if (Subtarget->isTargetDarwin()) { - // All darwin targets use mach-o. - MachineModuleInfoMachO &MMIMacho = - MMI->getObjFileInfo(); - - // Output stubs for dynamically-linked functions. - MachineModuleInfoMachO::SymbolListTy Stubs; - - Stubs = MMIMacho.GetFnStubList(); - if (!Stubs.empty()) { - const MCSection *TheSection = - OutContext.getMachOSection("__IMPORT", "__jump_table", - MCSectionMachO::S_SYMBOL_STUBS | - MCSectionMachO::S_ATTR_SELF_MODIFYING_CODE | - MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, - 5, SectionKind::getMetadata()); - OutStreamer.SwitchSection(TheSection); - - for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { - // L_foo$stub: - OutStreamer.EmitLabel(Stubs[i].first); - // .indirect_symbol _foo - OutStreamer.EmitSymbolAttribute(Stubs[i].second.getPointer(), - MCSA_IndirectSymbol); - // hlt; hlt; hlt; hlt; hlt hlt = 0xf4 = -12. - const char HltInsts[] = { -12, -12, -12, -12, -12 }; - OutStreamer.EmitBytes(StringRef(HltInsts, 5), 0/*addrspace*/); - } - - Stubs.clear(); - OutStreamer.AddBlankLine(); - } - - // Output stubs for external and common global variables. - Stubs = MMIMacho.GetGVStubList(); - if (!Stubs.empty()) { - const MCSection *TheSection = - OutContext.getMachOSection("__IMPORT", "__pointers", - MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS, - SectionKind::getMetadata()); - OutStreamer.SwitchSection(TheSection); - - for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { - // L_foo$non_lazy_ptr: - OutStreamer.EmitLabel(Stubs[i].first); - // .indirect_symbol _foo - MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second; - OutStreamer.EmitSymbolAttribute(MCSym.getPointer(), - MCSA_IndirectSymbol); - // .long 0 - if (MCSym.getInt()) - // External to current translation unit. - OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/); - else - // Internal to current translation unit. - // - // When we place the LSDA into the TEXT section, the type info - // pointers need to be indirect and pc-rel. We accomplish this by - // using NLPs. However, sometimes the types are local to the file. So - // we need to fill in the value for the NLP in those cases. - OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym.getPointer(), - OutContext), - 4/*size*/, 0/*addrspace*/); - } - Stubs.clear(); - OutStreamer.AddBlankLine(); - } - - Stubs = MMIMacho.GetHiddenGVStubList(); - if (!Stubs.empty()) { - OutStreamer.SwitchSection(getObjFileLowering().getDataSection()); - EmitAlignment(2); - - for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { - // L_foo$non_lazy_ptr: - OutStreamer.EmitLabel(Stubs[i].first); - // .long _foo - OutStreamer.EmitValue(MCSymbolRefExpr:: - Create(Stubs[i].second.getPointer(), - OutContext), - 4/*size*/, 0/*addrspace*/); - } - Stubs.clear(); - OutStreamer.AddBlankLine(); - } - - // Funny Darwin hack: This flag tells the linker that no global symbols - // contain code that falls through to other global symbols (e.g. the obvious - // implementation of multiple entry points). If this doesn't occur, the - // linker can safely perform dead code stripping. Since LLVM never - // generates code that does this, it is always safe to set. - OutStreamer.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols); - } - - if (Subtarget->isTargetCOFF()) { - X86COFFMachineModuleInfo &COFFMMI = - MMI->getObjFileInfo(); - - // Emit type information for external functions - typedef X86COFFMachineModuleInfo::externals_iterator externals_iterator; - for (externals_iterator I = COFFMMI.externals_begin(), - E = COFFMMI.externals_end(); - I != E; ++I) { - OutStreamer.BeginCOFFSymbolDef(CurrentFnSym); - OutStreamer.EmitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL); - OutStreamer.EmitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION - << COFF::SCT_COMPLEX_TYPE_SHIFT); - OutStreamer.EndCOFFSymbolDef(); - } - - // Necessary for dllexport support - std::vector DLLExportedFns, DLLExportedGlobals; - - const TargetLoweringObjectFileCOFF &TLOFCOFF = - static_cast(getObjFileLowering()); - - for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) - if (I->hasDLLExportLinkage()) - DLLExportedFns.push_back(Mang->getSymbol(I)); - - for (Module::const_global_iterator I = M.global_begin(), - E = M.global_end(); I != E; ++I) - if (I->hasDLLExportLinkage()) - DLLExportedGlobals.push_back(Mang->getSymbol(I)); - - // Output linker support code for dllexported globals on windows. - if (!DLLExportedGlobals.empty() || !DLLExportedFns.empty()) { - OutStreamer.SwitchSection(TLOFCOFF.getDrectveSection()); - SmallString<128> name; - for (unsigned i = 0, e = DLLExportedGlobals.size(); i != e; ++i) { - if (Subtarget->isTargetWindows()) - name = " /EXPORT:"; - else - name = " -export:"; - name += DLLExportedGlobals[i]->getName(); - if (Subtarget->isTargetWindows()) - name += ",DATA"; - else - name += ",data"; - OutStreamer.EmitBytes(name, 0); - } - - for (unsigned i = 0, e = DLLExportedFns.size(); i != e; ++i) { - if (Subtarget->isTargetWindows()) - name = " /EXPORT:"; - else - name = " -export:"; - name += DLLExportedFns[i]->getName(); - OutStreamer.EmitBytes(name, 0); - } - } - } - - if (Subtarget->isTargetELF()) { - const TargetLoweringObjectFileELF &TLOFELF = - static_cast(getObjFileLowering()); - - MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo(); - - // Output stubs for external and common global variables. - MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList(); - if (!Stubs.empty()) { - OutStreamer.SwitchSection(TLOFELF.getDataRelSection()); - const TargetData *TD = TM.getTargetData(); - - for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { - OutStreamer.EmitLabel(Stubs[i].first); - OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), - TD->getPointerSize(), 0); - } - Stubs.clear(); - } - } -} - - -//===----------------------------------------------------------------------===// -// Target Registry Stuff -//===----------------------------------------------------------------------===// - -static MCInstPrinter *createX86MCInstPrinter(const Target &T, - unsigned SyntaxVariant, - const MCAsmInfo &MAI) { - if (SyntaxVariant == 0) - return new X86ATTInstPrinter(MAI); - if (SyntaxVariant == 1) - return new X86IntelInstPrinter(MAI); - return 0; -} - -// Force static initialization. -extern "C" void LLVMInitializeX86AsmPrinter() { - RegisterAsmPrinter X(TheX86_32Target); - RegisterAsmPrinter Y(TheX86_64Target); - - TargetRegistry::RegisterMCInstPrinter(TheX86_32Target,createX86MCInstPrinter); - TargetRegistry::RegisterMCInstPrinter(TheX86_64Target,createX86MCInstPrinter); -} diff --git a/lib/Target/X86/AsmPrinter/X86AsmPrinter.h b/lib/Target/X86/AsmPrinter/X86AsmPrinter.h deleted file mode 100644 index b5a7f8d..0000000 --- a/lib/Target/X86/AsmPrinter/X86AsmPrinter.h +++ /dev/null @@ -1,89 +0,0 @@ -//===-- X86AsmPrinter.h - Convert X86 LLVM code to assembly -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// AT&T assembly code printer class. -// -//===----------------------------------------------------------------------===// - -#ifndef X86ASMPRINTER_H -#define X86ASMPRINTER_H - -#include "../X86.h" -#include "../X86MachineFunctionInfo.h" -#include "../X86TargetMachine.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/CodeGen/ValueTypes.h" -#include "llvm/Support/Compiler.h" - -namespace llvm { - -class MachineJumpTableInfo; -class MCContext; -class MCInst; -class MCStreamer; -class MCSymbol; - -class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter { - const X86Subtarget *Subtarget; - public: - explicit X86AsmPrinter(TargetMachine &TM, MCStreamer &Streamer) - : AsmPrinter(TM, Streamer) { - Subtarget = &TM.getSubtarget(); - } - - virtual const char *getPassName() const { - return "X86 AT&T-Style Assembly Printer"; - } - - const X86Subtarget &getSubtarget() const { return *Subtarget; } - - virtual void EmitStartOfAsmFile(Module &M); - - virtual void EmitEndOfAsmFile(Module &M); - - virtual void EmitInstruction(const MachineInstr *MI); - - void printSymbolOperand(const MachineOperand &MO, raw_ostream &O); - - // These methods are used by the tablegen'erated instruction printer. - void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O, - const char *Modifier = 0); - void print_pcrel_imm(const MachineInstr *MI, unsigned OpNo, raw_ostream &O); - - bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O); - bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, - unsigned AsmVariant, const char *ExtraCode, - raw_ostream &OS); - bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, - unsigned AsmVariant, const char *ExtraCode, - raw_ostream &OS); - - void printMachineInstruction(const MachineInstr *MI); - void printSSECC(const MachineInstr *MI, unsigned Op, raw_ostream &O); - void printMemReference(const MachineInstr *MI, unsigned Op, raw_ostream &O, - const char *Modifier=NULL); - void printLeaMemReference(const MachineInstr *MI, unsigned Op, raw_ostream &O, - const char *Modifier=NULL); - - void printPICLabel(const MachineInstr *MI, unsigned Op, raw_ostream &O); - - void PrintPICBaseSymbol(raw_ostream &O) const; - - bool runOnMachineFunction(MachineFunction &F); - - void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); - - MachineLocation getDebugValueLocation(const MachineInstr *MI) const; -}; - -} // end namespace llvm - -#endif diff --git a/lib/Target/X86/AsmPrinter/X86InstComments.cpp b/lib/Target/X86/AsmPrinter/X86InstComments.cpp new file mode 100644 index 0000000..da9d5a3 --- /dev/null +++ b/lib/Target/X86/AsmPrinter/X86InstComments.cpp @@ -0,0 +1,232 @@ +//===-- X86InstComments.cpp - Generate verbose-asm comments for instrs ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines functionality used to emit comments about X86 instructions to +// an output stream for -fverbose-asm. +// +//===----------------------------------------------------------------------===// + +#include "X86InstComments.h" +#include "X86GenInstrNames.inc" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/raw_ostream.h" +#include "../X86ShuffleDecode.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Top Level Entrypoint +//===----------------------------------------------------------------------===// + +/// EmitAnyX86InstComments - This function decodes x86 instructions and prints +/// newline terminated strings to the specified string if desired. This +/// information is shown in disassembly dumps when verbose assembly is enabled. +void llvm::EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS, + const char *(*getRegName)(unsigned)) { + // If this is a shuffle operation, the switch should fill in this state. + SmallVector ShuffleMask; + const char *DestName = 0, *Src1Name = 0, *Src2Name = 0; + + switch (MI->getOpcode()) { + case X86::INSERTPSrr: + Src1Name = getRegName(MI->getOperand(1).getReg()); + Src2Name = getRegName(MI->getOperand(2).getReg()); + DecodeINSERTPSMask(MI->getOperand(3).getImm(), ShuffleMask); + break; + + case X86::MOVLHPSrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + Src1Name = getRegName(MI->getOperand(0).getReg()); + DecodeMOVLHPSMask(2, ShuffleMask); + break; + + case X86::MOVHLPSrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + Src1Name = getRegName(MI->getOperand(0).getReg()); + DecodeMOVHLPSMask(2, ShuffleMask); + break; + + case X86::PSHUFDri: + Src1Name = getRegName(MI->getOperand(1).getReg()); + // FALL THROUGH. + case X86::PSHUFDmi: + DestName = getRegName(MI->getOperand(0).getReg()); + DecodePSHUFMask(4, MI->getOperand(MI->getNumOperands()-1).getImm(), + ShuffleMask); + break; + + case X86::PSHUFHWri: + Src1Name = getRegName(MI->getOperand(1).getReg()); + // FALL THROUGH. + case X86::PSHUFHWmi: + DestName = getRegName(MI->getOperand(0).getReg()); + DecodePSHUFHWMask(MI->getOperand(MI->getNumOperands()-1).getImm(), + ShuffleMask); + break; + case X86::PSHUFLWri: + Src1Name = getRegName(MI->getOperand(1).getReg()); + // FALL THROUGH. + case X86::PSHUFLWmi: + DestName = getRegName(MI->getOperand(0).getReg()); + DecodePSHUFLWMask(MI->getOperand(MI->getNumOperands()-1).getImm(), + ShuffleMask); + break; + + case X86::PUNPCKHBWrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + // FALL THROUGH. + case X86::PUNPCKHBWrm: + Src1Name = getRegName(MI->getOperand(0).getReg()); + DecodePUNPCKHMask(16, ShuffleMask); + break; + case X86::PUNPCKHWDrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + // FALL THROUGH. + case X86::PUNPCKHWDrm: + Src1Name = getRegName(MI->getOperand(0).getReg()); + DecodePUNPCKHMask(8, ShuffleMask); + break; + case X86::PUNPCKHDQrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + // FALL THROUGH. + case X86::PUNPCKHDQrm: + Src1Name = getRegName(MI->getOperand(0).getReg()); + DecodePUNPCKHMask(4, ShuffleMask); + break; + case X86::PUNPCKHQDQrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + // FALL THROUGH. + case X86::PUNPCKHQDQrm: + Src1Name = getRegName(MI->getOperand(0).getReg()); + DecodePUNPCKHMask(2, ShuffleMask); + break; + + case X86::PUNPCKLBWrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + // FALL THROUGH. + case X86::PUNPCKLBWrm: + Src1Name = getRegName(MI->getOperand(0).getReg()); + DecodePUNPCKLMask(16, ShuffleMask); + break; + case X86::PUNPCKLWDrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + // FALL THROUGH. + case X86::PUNPCKLWDrm: + Src1Name = getRegName(MI->getOperand(0).getReg()); + DecodePUNPCKLMask(8, ShuffleMask); + break; + case X86::PUNPCKLDQrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + // FALL THROUGH. + case X86::PUNPCKLDQrm: + Src1Name = getRegName(MI->getOperand(0).getReg()); + DecodePUNPCKLMask(4, ShuffleMask); + break; + case X86::PUNPCKLQDQrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + // FALL THROUGH. + case X86::PUNPCKLQDQrm: + Src1Name = getRegName(MI->getOperand(0).getReg()); + DecodePUNPCKLMask(2, ShuffleMask); + break; + + case X86::SHUFPDrri: + DecodeSHUFPSMask(2, MI->getOperand(3).getImm(), ShuffleMask); + Src1Name = getRegName(MI->getOperand(0).getReg()); + Src2Name = getRegName(MI->getOperand(2).getReg()); + break; + + case X86::SHUFPSrri: + Src2Name = getRegName(MI->getOperand(2).getReg()); + // FALL THROUGH. + case X86::SHUFPSrmi: + DecodeSHUFPSMask(4, MI->getOperand(3).getImm(), ShuffleMask); + Src1Name = getRegName(MI->getOperand(0).getReg()); + break; + + case X86::UNPCKLPDrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + // FALL THROUGH. + case X86::UNPCKLPDrm: + DecodeUNPCKLPMask(2, ShuffleMask); + Src1Name = getRegName(MI->getOperand(0).getReg()); + break; + case X86::UNPCKLPSrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + // FALL THROUGH. + case X86::UNPCKLPSrm: + DecodeUNPCKLPMask(4, ShuffleMask); + Src1Name = getRegName(MI->getOperand(0).getReg()); + break; + case X86::UNPCKHPDrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + // FALL THROUGH. + case X86::UNPCKHPDrm: + DecodeUNPCKHPMask(2, ShuffleMask); + Src1Name = getRegName(MI->getOperand(0).getReg()); + break; + case X86::UNPCKHPSrr: + Src2Name = getRegName(MI->getOperand(2).getReg()); + // FALL THROUGH. + case X86::UNPCKHPSrm: + DecodeUNPCKHPMask(4, ShuffleMask); + Src1Name = getRegName(MI->getOperand(0).getReg()); + break; + } + + + // If this was a shuffle operation, print the shuffle mask. + if (!ShuffleMask.empty()) { + if (DestName == 0) DestName = Src1Name; + OS << (DestName ? DestName : "mem") << " = "; + + // If the two sources are the same, canonicalize the input elements to be + // from the first src so that we get larger element spans. + if (Src1Name == Src2Name) { + for (unsigned i = 0, e = ShuffleMask.size(); i != e; ++i) { + if ((int)ShuffleMask[i] >= 0 && // Not sentinel. + ShuffleMask[i] >= e) // From second mask. + ShuffleMask[i] -= e; + } + } + + // The shuffle mask specifies which elements of the src1/src2 fill in the + // destination, with a few sentinel values. Loop through and print them + // out. + for (unsigned i = 0, e = ShuffleMask.size(); i != e; ++i) { + if (i != 0) + OS << ','; + if (ShuffleMask[i] == SM_SentinelZero) { + OS << "zero"; + continue; + } + + // Otherwise, it must come from src1 or src2. Print the span of elements + // that comes from this src. + bool isSrc1 = ShuffleMask[i] < ShuffleMask.size(); + const char *SrcName = isSrc1 ? Src1Name : Src2Name; + OS << (SrcName ? SrcName : "mem") << '['; + bool IsFirst = true; + while (i != e && + (int)ShuffleMask[i] >= 0 && + (ShuffleMask[i] < ShuffleMask.size()) == isSrc1) { + if (!IsFirst) + OS << ','; + else + IsFirst = false; + OS << ShuffleMask[i] % ShuffleMask.size(); + ++i; + } + OS << ']'; + --i; // For loop increments element #. + } + //MI->print(OS, 0); + OS << "\n"; + } + +} diff --git a/lib/Target/X86/AsmPrinter/X86InstComments.h b/lib/Target/X86/AsmPrinter/X86InstComments.h new file mode 100644 index 0000000..6b86db4 --- /dev/null +++ b/lib/Target/X86/AsmPrinter/X86InstComments.h @@ -0,0 +1,25 @@ +//===-- X86InstComments.h - Generate verbose-asm comments for instrs ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines functionality used to emit comments about X86 instructions to +// an output stream for -fverbose-asm. +// +//===----------------------------------------------------------------------===// + +#ifndef X86_INST_COMMENTS_H +#define X86_INST_COMMENTS_H + +namespace llvm { + class MCInst; + class raw_ostream; + void EmitAnyX86InstComments(const MCInst *MI, raw_ostream &OS, + const char *(*getRegName)(unsigned)); +} + +#endif diff --git a/lib/Target/X86/AsmPrinter/X86IntelInstPrinter.cpp b/lib/Target/X86/AsmPrinter/X86IntelInstPrinter.cpp index a632047..5625b0e 100644 --- a/lib/Target/X86/AsmPrinter/X86IntelInstPrinter.cpp +++ b/lib/Target/X86/AsmPrinter/X86IntelInstPrinter.cpp @@ -14,6 +14,7 @@ #define DEBUG_TYPE "asm-printer" #include "X86IntelInstPrinter.h" +#include "X86InstComments.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCExpr.h" @@ -30,6 +31,10 @@ using namespace llvm; void X86IntelInstPrinter::printInst(const MCInst *MI, raw_ostream &OS) { printInstruction(MI, OS); + + // If verbose assembly is enabled, we can print some informative comments. + if (CommentStream) + EmitAnyX86InstComments(MI, *CommentStream, getRegisterName); } StringRef X86IntelInstPrinter::getOpcodeName(unsigned Opcode) const { return getInstructionName(Opcode); diff --git a/lib/Target/X86/AsmPrinter/X86IntelInstPrinter.h b/lib/Target/X86/AsmPrinter/X86IntelInstPrinter.h index 4d68074..6f12032 100644 --- a/lib/Target/X86/AsmPrinter/X86IntelInstPrinter.h +++ b/lib/Target/X86/AsmPrinter/X86IntelInstPrinter.h @@ -64,6 +64,10 @@ public: O << "XMMWORD PTR "; printMemReference(MI, OpNo, O); } + void printi256mem(const MCInst *MI, unsigned OpNo, raw_ostream &O) { + O << "YMMWORD PTR "; + printMemReference(MI, OpNo, O); + } void printf32mem(const MCInst *MI, unsigned OpNo, raw_ostream &O) { O << "DWORD PTR "; printMemReference(MI, OpNo, O); diff --git a/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp b/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp deleted file mode 100644 index e67fc06..0000000 --- a/lib/Target/X86/AsmPrinter/X86MCInstLower.cpp +++ /dev/null @@ -1,632 +0,0 @@ -//===-- X86MCInstLower.cpp - Convert X86 MachineInstr to an MCInst --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains code to lower X86 MachineInstrs to their corresponding -// MCInst records. -// -//===----------------------------------------------------------------------===// - -#include "X86MCInstLower.h" -#include "X86AsmPrinter.h" -#include "X86COFFMachineModuleInfo.h" -#include "X86MCAsmInfo.h" -#include "llvm/Analysis/DebugInfo.h" -#include "llvm/CodeGen/MachineModuleInfoImpls.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSymbol.h" -#include "llvm/Target/Mangler.h" -#include "llvm/Support/FormattedStream.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Type.h" -using namespace llvm; - - -const X86Subtarget &X86MCInstLower::getSubtarget() const { - return AsmPrinter.getSubtarget(); -} - -MachineModuleInfoMachO &X86MCInstLower::getMachOMMI() const { - assert(getSubtarget().isTargetDarwin() &&"Can only get MachO info on darwin"); - return AsmPrinter.MMI->getObjFileInfo(); -} - - -MCSymbol *X86MCInstLower::GetPICBaseSymbol() const { - const TargetLowering *TLI = AsmPrinter.TM.getTargetLowering(); - return static_cast(TLI)-> - getPICBaseSymbol(AsmPrinter.MF, Ctx); -} - -/// GetSymbolFromOperand - Lower an MO_GlobalAddress or MO_ExternalSymbol -/// operand to an MCSymbol. -MCSymbol *X86MCInstLower:: -GetSymbolFromOperand(const MachineOperand &MO) const { - assert((MO.isGlobal() || MO.isSymbol()) && "Isn't a symbol reference"); - - SmallString<128> Name; - - if (!MO.isGlobal()) { - assert(MO.isSymbol()); - Name += AsmPrinter.MAI->getGlobalPrefix(); - Name += MO.getSymbolName(); - } else { - const GlobalValue *GV = MO.getGlobal(); - bool isImplicitlyPrivate = false; - if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB || - MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY || - MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE || - MO.getTargetFlags() == X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE) - isImplicitlyPrivate = true; - - Mang->getNameWithPrefix(Name, GV, isImplicitlyPrivate); - } - - // If the target flags on the operand changes the name of the symbol, do that - // before we return the symbol. - switch (MO.getTargetFlags()) { - default: break; - case X86II::MO_DLLIMPORT: { - // Handle dllimport linkage. - const char *Prefix = "__imp_"; - Name.insert(Name.begin(), Prefix, Prefix+strlen(Prefix)); - break; - } - case X86II::MO_DARWIN_NONLAZY: - case X86II::MO_DARWIN_NONLAZY_PIC_BASE: { - Name += "$non_lazy_ptr"; - MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name.str()); - - MachineModuleInfoImpl::StubValueTy &StubSym = - getMachOMMI().getGVStubEntry(Sym); - if (StubSym.getPointer() == 0) { - assert(MO.isGlobal() && "Extern symbol not handled yet"); - StubSym = - MachineModuleInfoImpl:: - StubValueTy(AsmPrinter.Mang->getSymbol(MO.getGlobal()), - !MO.getGlobal()->hasInternalLinkage()); - } - return Sym; - } - case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE: { - Name += "$non_lazy_ptr"; - MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name.str()); - MachineModuleInfoImpl::StubValueTy &StubSym = - getMachOMMI().getHiddenGVStubEntry(Sym); - if (StubSym.getPointer() == 0) { - assert(MO.isGlobal() && "Extern symbol not handled yet"); - StubSym = - MachineModuleInfoImpl:: - StubValueTy(AsmPrinter.Mang->getSymbol(MO.getGlobal()), - !MO.getGlobal()->hasInternalLinkage()); - } - return Sym; - } - case X86II::MO_DARWIN_STUB: { - Name += "$stub"; - MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name.str()); - MachineModuleInfoImpl::StubValueTy &StubSym = - getMachOMMI().getFnStubEntry(Sym); - if (StubSym.getPointer()) - return Sym; - - if (MO.isGlobal()) { - StubSym = - MachineModuleInfoImpl:: - StubValueTy(AsmPrinter.Mang->getSymbol(MO.getGlobal()), - !MO.getGlobal()->hasInternalLinkage()); - } else { - Name.erase(Name.end()-5, Name.end()); - StubSym = - MachineModuleInfoImpl:: - StubValueTy(Ctx.GetOrCreateSymbol(Name.str()), false); - } - return Sym; - } - } - - return Ctx.GetOrCreateSymbol(Name.str()); -} - -MCOperand X86MCInstLower::LowerSymbolOperand(const MachineOperand &MO, - MCSymbol *Sym) const { - // FIXME: We would like an efficient form for this, so we don't have to do a - // lot of extra uniquing. - const MCExpr *Expr = 0; - MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None; - - switch (MO.getTargetFlags()) { - default: llvm_unreachable("Unknown target flag on GV operand"); - case X86II::MO_NO_FLAG: // No flag. - // These affect the name of the symbol, not any suffix. - case X86II::MO_DARWIN_NONLAZY: - case X86II::MO_DLLIMPORT: - case X86II::MO_DARWIN_STUB: - break; - - case X86II::MO_TLVP: RefKind = MCSymbolRefExpr::VK_TLVP; break; - case X86II::MO_TLVP_PIC_BASE: - Expr = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_TLVP, Ctx); - // Subtract the pic base. - Expr = MCBinaryExpr::CreateSub(Expr, - MCSymbolRefExpr::Create(GetPICBaseSymbol(), - Ctx), - Ctx); - break; - case X86II::MO_TLSGD: RefKind = MCSymbolRefExpr::VK_TLSGD; break; - case X86II::MO_GOTTPOFF: RefKind = MCSymbolRefExpr::VK_GOTTPOFF; break; - case X86II::MO_INDNTPOFF: RefKind = MCSymbolRefExpr::VK_INDNTPOFF; break; - case X86II::MO_TPOFF: RefKind = MCSymbolRefExpr::VK_TPOFF; break; - case X86II::MO_NTPOFF: RefKind = MCSymbolRefExpr::VK_NTPOFF; break; - case X86II::MO_GOTPCREL: RefKind = MCSymbolRefExpr::VK_GOTPCREL; break; - case X86II::MO_GOT: RefKind = MCSymbolRefExpr::VK_GOT; break; - case X86II::MO_GOTOFF: RefKind = MCSymbolRefExpr::VK_GOTOFF; break; - case X86II::MO_PLT: RefKind = MCSymbolRefExpr::VK_PLT; break; - case X86II::MO_PIC_BASE_OFFSET: - case X86II::MO_DARWIN_NONLAZY_PIC_BASE: - case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE: - Expr = MCSymbolRefExpr::Create(Sym, Ctx); - // Subtract the pic base. - Expr = MCBinaryExpr::CreateSub(Expr, - MCSymbolRefExpr::Create(GetPICBaseSymbol(), Ctx), - Ctx); - if (MO.isJTI() && AsmPrinter.MAI->hasSetDirective()) { - // If .set directive is supported, use it to reduce the number of - // relocations the assembler will generate for differences between - // local labels. This is only safe when the symbols are in the same - // section so we are restricting it to jumptable references. - MCSymbol *Label = Ctx.CreateTempSymbol(); - AsmPrinter.OutStreamer.EmitAssignment(Label, Expr); - Expr = MCSymbolRefExpr::Create(Label, Ctx); - } - break; - } - - if (Expr == 0) - Expr = MCSymbolRefExpr::Create(Sym, RefKind, Ctx); - - if (!MO.isJTI() && MO.getOffset()) - Expr = MCBinaryExpr::CreateAdd(Expr, - MCConstantExpr::Create(MO.getOffset(), Ctx), - Ctx); - return MCOperand::CreateExpr(Expr); -} - - - -static void lower_subreg32(MCInst *MI, unsigned OpNo) { - // Convert registers in the addr mode according to subreg32. - unsigned Reg = MI->getOperand(OpNo).getReg(); - if (Reg != 0) - MI->getOperand(OpNo).setReg(getX86SubSuperRegister(Reg, MVT::i32)); -} - -static void lower_lea64_32mem(MCInst *MI, unsigned OpNo) { - // Convert registers in the addr mode according to subreg64. - for (unsigned i = 0; i != 4; ++i) { - if (!MI->getOperand(OpNo+i).isReg()) continue; - - unsigned Reg = MI->getOperand(OpNo+i).getReg(); - if (Reg == 0) continue; - - MI->getOperand(OpNo+i).setReg(getX86SubSuperRegister(Reg, MVT::i64)); - } -} - -/// LowerSubReg32_Op0 - Things like MOVZX16rr8 -> MOVZX32rr8. -static void LowerSubReg32_Op0(MCInst &OutMI, unsigned NewOpc) { - OutMI.setOpcode(NewOpc); - lower_subreg32(&OutMI, 0); -} -/// LowerUnaryToTwoAddr - R = setb -> R = sbb R, R -static void LowerUnaryToTwoAddr(MCInst &OutMI, unsigned NewOpc) { - OutMI.setOpcode(NewOpc); - OutMI.addOperand(OutMI.getOperand(0)); - OutMI.addOperand(OutMI.getOperand(0)); -} - -/// \brief Simplify FOO $imm, %{al,ax,eax,rax} to FOO $imm, for instruction with -/// a short fixed-register form. -static void SimplifyShortImmForm(MCInst &Inst, unsigned Opcode) { - unsigned ImmOp = Inst.getNumOperands() - 1; - assert(Inst.getOperand(0).isReg() && Inst.getOperand(ImmOp).isImm() && - ((Inst.getNumOperands() == 3 && Inst.getOperand(1).isReg() && - Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg()) || - Inst.getNumOperands() == 2) && "Unexpected instruction!"); - - // Check whether the destination register can be fixed. - unsigned Reg = Inst.getOperand(0).getReg(); - if (Reg != X86::AL && Reg != X86::AX && Reg != X86::EAX && Reg != X86::RAX) - return; - - // If so, rewrite the instruction. - MCOperand Saved = Inst.getOperand(ImmOp); - Inst = MCInst(); - Inst.setOpcode(Opcode); - Inst.addOperand(Saved); -} - -/// \brief Simplify things like MOV32rm to MOV32o32a. -static void SimplifyShortMoveForm(MCInst &Inst, unsigned Opcode) { - bool IsStore = Inst.getOperand(0).isReg() && Inst.getOperand(1).isReg(); - unsigned AddrBase = IsStore; - unsigned RegOp = IsStore ? 0 : 5; - unsigned AddrOp = AddrBase + 3; - assert(Inst.getNumOperands() == 6 && Inst.getOperand(RegOp).isReg() && - Inst.getOperand(AddrBase + 0).isReg() && // base - Inst.getOperand(AddrBase + 1).isImm() && // scale - Inst.getOperand(AddrBase + 2).isReg() && // index register - (Inst.getOperand(AddrOp).isExpr() || // address - Inst.getOperand(AddrOp).isImm())&& - Inst.getOperand(AddrBase + 4).isReg() && // segment - "Unexpected instruction!"); - - // Check whether the destination register can be fixed. - unsigned Reg = Inst.getOperand(RegOp).getReg(); - if (Reg != X86::AL && Reg != X86::AX && Reg != X86::EAX && Reg != X86::RAX) - return; - - // Check whether this is an absolute address. - // FIXME: We know TLVP symbol refs aren't, but there should be a better way - // to do this here. - bool Absolute = true; - if (Inst.getOperand(AddrOp).isExpr()) { - const MCExpr *MCE = Inst.getOperand(AddrOp).getExpr(); - if (const MCSymbolRefExpr *SRE = dyn_cast(MCE)) - if (SRE->getKind() == MCSymbolRefExpr::VK_TLVP) - Absolute = false; - } - - if (Absolute && - (Inst.getOperand(AddrBase + 0).getReg() != 0 || - Inst.getOperand(AddrBase + 2).getReg() != 0 || - Inst.getOperand(AddrBase + 4).getReg() != 0 || - Inst.getOperand(AddrBase + 1).getImm() != 1)) - return; - - // If so, rewrite the instruction. - MCOperand Saved = Inst.getOperand(AddrOp); - Inst = MCInst(); - Inst.setOpcode(Opcode); - Inst.addOperand(Saved); -} - -void X86MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { - OutMI.setOpcode(MI->getOpcode()); - - for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { - const MachineOperand &MO = MI->getOperand(i); - - MCOperand MCOp; - switch (MO.getType()) { - default: - MI->dump(); - llvm_unreachable("unknown operand type"); - case MachineOperand::MO_Register: - // Ignore all implicit register operands. - if (MO.isImplicit()) continue; - MCOp = MCOperand::CreateReg(MO.getReg()); - break; - case MachineOperand::MO_Immediate: - MCOp = MCOperand::CreateImm(MO.getImm()); - break; - case MachineOperand::MO_MachineBasicBlock: - MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( - MO.getMBB()->getSymbol(), Ctx)); - break; - case MachineOperand::MO_GlobalAddress: - MCOp = LowerSymbolOperand(MO, GetSymbolFromOperand(MO)); - break; - case MachineOperand::MO_ExternalSymbol: - MCOp = LowerSymbolOperand(MO, GetSymbolFromOperand(MO)); - break; - case MachineOperand::MO_JumpTableIndex: - MCOp = LowerSymbolOperand(MO, AsmPrinter.GetJTISymbol(MO.getIndex())); - break; - case MachineOperand::MO_ConstantPoolIndex: - MCOp = LowerSymbolOperand(MO, AsmPrinter.GetCPISymbol(MO.getIndex())); - break; - case MachineOperand::MO_BlockAddress: - MCOp = LowerSymbolOperand(MO, - AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress())); - break; - } - - OutMI.addOperand(MCOp); - } - - // Handle a few special cases to eliminate operand modifiers. - switch (OutMI.getOpcode()) { - case X86::LEA64_32r: // Handle 'subreg rewriting' for the lea64_32mem operand. - lower_lea64_32mem(&OutMI, 1); - // FALL THROUGH. - case X86::LEA64r: - case X86::LEA16r: - case X86::LEA32r: - // LEA should have a segment register, but it must be empty. - assert(OutMI.getNumOperands() == 1+X86::AddrNumOperands && - "Unexpected # of LEA operands"); - assert(OutMI.getOperand(1+X86::AddrSegmentReg).getReg() == 0 && - "LEA has segment specified!"); - break; - case X86::MOVZX16rr8: LowerSubReg32_Op0(OutMI, X86::MOVZX32rr8); break; - case X86::MOVZX16rm8: LowerSubReg32_Op0(OutMI, X86::MOVZX32rm8); break; - case X86::MOVSX16rr8: LowerSubReg32_Op0(OutMI, X86::MOVSX32rr8); break; - case X86::MOVSX16rm8: LowerSubReg32_Op0(OutMI, X86::MOVSX32rm8); break; - case X86::MOVZX64rr32: LowerSubReg32_Op0(OutMI, X86::MOV32rr); break; - case X86::MOVZX64rm32: LowerSubReg32_Op0(OutMI, X86::MOV32rm); break; - case X86::MOV64ri64i32: LowerSubReg32_Op0(OutMI, X86::MOV32ri); break; - case X86::MOVZX64rr8: LowerSubReg32_Op0(OutMI, X86::MOVZX32rr8); break; - case X86::MOVZX64rm8: LowerSubReg32_Op0(OutMI, X86::MOVZX32rm8); break; - case X86::MOVZX64rr16: LowerSubReg32_Op0(OutMI, X86::MOVZX32rr16); break; - case X86::MOVZX64rm16: LowerSubReg32_Op0(OutMI, X86::MOVZX32rm16); break; - case X86::SETB_C8r: LowerUnaryToTwoAddr(OutMI, X86::SBB8rr); break; - case X86::SETB_C16r: LowerUnaryToTwoAddr(OutMI, X86::SBB16rr); break; - case X86::SETB_C32r: LowerUnaryToTwoAddr(OutMI, X86::SBB32rr); break; - case X86::SETB_C64r: LowerUnaryToTwoAddr(OutMI, X86::SBB64rr); break; - case X86::MOV8r0: LowerUnaryToTwoAddr(OutMI, X86::XOR8rr); break; - case X86::MOV32r0: LowerUnaryToTwoAddr(OutMI, X86::XOR32rr); break; - case X86::MMX_V_SET0: LowerUnaryToTwoAddr(OutMI, X86::MMX_PXORrr); break; - case X86::MMX_V_SETALLONES: - LowerUnaryToTwoAddr(OutMI, X86::MMX_PCMPEQDrr); break; - case X86::FsFLD0SS: LowerUnaryToTwoAddr(OutMI, X86::PXORrr); break; - case X86::FsFLD0SD: LowerUnaryToTwoAddr(OutMI, X86::PXORrr); break; - case X86::V_SET0PS: LowerUnaryToTwoAddr(OutMI, X86::XORPSrr); break; - case X86::V_SET0PD: LowerUnaryToTwoAddr(OutMI, X86::XORPDrr); break; - case X86::V_SET0PI: LowerUnaryToTwoAddr(OutMI, X86::PXORrr); break; - case X86::V_SETALLONES: LowerUnaryToTwoAddr(OutMI, X86::PCMPEQDrr); break; - - case X86::MOV16r0: - LowerSubReg32_Op0(OutMI, X86::MOV32r0); // MOV16r0 -> MOV32r0 - LowerUnaryToTwoAddr(OutMI, X86::XOR32rr); // MOV32r0 -> XOR32rr - break; - case X86::MOV64r0: - LowerSubReg32_Op0(OutMI, X86::MOV32r0); // MOV64r0 -> MOV32r0 - LowerUnaryToTwoAddr(OutMI, X86::XOR32rr); // MOV32r0 -> XOR32rr - break; - - // TAILJMPr64, CALL64r, CALL64pcrel32 - These instructions have - // register inputs modeled as normal uses instead of implicit uses. As such, - // truncate off all but the first operand (the callee). FIXME: Change isel. - case X86::TAILJMPr64: - case X86::CALL64r: - case X86::CALL64pcrel32: { - unsigned Opcode = OutMI.getOpcode(); - MCOperand Saved = OutMI.getOperand(0); - OutMI = MCInst(); - OutMI.setOpcode(Opcode); - OutMI.addOperand(Saved); - break; - } - - // TAILJMPd, TAILJMPd64 - Lower to the correct jump instructions. - case X86::TAILJMPr: - case X86::TAILJMPd: - case X86::TAILJMPd64: { - unsigned Opcode; - switch (OutMI.getOpcode()) { - default: assert(0 && "Invalid opcode"); - case X86::TAILJMPr: Opcode = X86::JMP32r; break; - case X86::TAILJMPd: - case X86::TAILJMPd64: Opcode = X86::JMP_1; break; - } - - MCOperand Saved = OutMI.getOperand(0); - OutMI = MCInst(); - OutMI.setOpcode(Opcode); - OutMI.addOperand(Saved); - break; - } - - // The assembler backend wants to see branches in their small form and relax - // them to their large form. The JIT can only handle the large form because - // it does not do relaxation. For now, translate the large form to the - // small one here. - case X86::JMP_4: OutMI.setOpcode(X86::JMP_1); break; - case X86::JO_4: OutMI.setOpcode(X86::JO_1); break; - case X86::JNO_4: OutMI.setOpcode(X86::JNO_1); break; - case X86::JB_4: OutMI.setOpcode(X86::JB_1); break; - case X86::JAE_4: OutMI.setOpcode(X86::JAE_1); break; - case X86::JE_4: OutMI.setOpcode(X86::JE_1); break; - case X86::JNE_4: OutMI.setOpcode(X86::JNE_1); break; - case X86::JBE_4: OutMI.setOpcode(X86::JBE_1); break; - case X86::JA_4: OutMI.setOpcode(X86::JA_1); break; - case X86::JS_4: OutMI.setOpcode(X86::JS_1); break; - case X86::JNS_4: OutMI.setOpcode(X86::JNS_1); break; - case X86::JP_4: OutMI.setOpcode(X86::JP_1); break; - case X86::JNP_4: OutMI.setOpcode(X86::JNP_1); break; - case X86::JL_4: OutMI.setOpcode(X86::JL_1); break; - case X86::JGE_4: OutMI.setOpcode(X86::JGE_1); break; - case X86::JLE_4: OutMI.setOpcode(X86::JLE_1); break; - case X86::JG_4: OutMI.setOpcode(X86::JG_1); break; - - // We don't currently select the correct instruction form for instructions - // which have a short %eax, etc. form. Handle this by custom lowering, for - // now. - // - // Note, we are currently not handling the following instructions: - // MOV64ao8, MOV64o8a - // XCHG16ar, XCHG32ar, XCHG64ar - case X86::MOV8mr_NOREX: - case X86::MOV8mr: SimplifyShortMoveForm(OutMI, X86::MOV8ao8); break; - case X86::MOV8rm_NOREX: - case X86::MOV8rm: SimplifyShortMoveForm(OutMI, X86::MOV8o8a); break; - case X86::MOV16mr: SimplifyShortMoveForm(OutMI, X86::MOV16ao16); break; - case X86::MOV16rm: SimplifyShortMoveForm(OutMI, X86::MOV16o16a); break; - case X86::MOV32mr: SimplifyShortMoveForm(OutMI, X86::MOV32ao32); break; - case X86::MOV32rm: SimplifyShortMoveForm(OutMI, X86::MOV32o32a); break; - case X86::MOV64mr: SimplifyShortMoveForm(OutMI, X86::MOV64ao64); break; - case X86::MOV64rm: SimplifyShortMoveForm(OutMI, X86::MOV64o64a); break; - - case X86::ADC8ri: SimplifyShortImmForm(OutMI, X86::ADC8i8); break; - case X86::ADC16ri: SimplifyShortImmForm(OutMI, X86::ADC16i16); break; - case X86::ADC32ri: SimplifyShortImmForm(OutMI, X86::ADC32i32); break; - case X86::ADC64ri32: SimplifyShortImmForm(OutMI, X86::ADC64i32); break; - case X86::ADD8ri: SimplifyShortImmForm(OutMI, X86::ADD8i8); break; - case X86::ADD16ri: SimplifyShortImmForm(OutMI, X86::ADD16i16); break; - case X86::ADD32ri: SimplifyShortImmForm(OutMI, X86::ADD32i32); break; - case X86::ADD64ri32: SimplifyShortImmForm(OutMI, X86::ADD64i32); break; - case X86::AND8ri: SimplifyShortImmForm(OutMI, X86::AND8i8); break; - case X86::AND16ri: SimplifyShortImmForm(OutMI, X86::AND16i16); break; - case X86::AND32ri: SimplifyShortImmForm(OutMI, X86::AND32i32); break; - case X86::AND64ri32: SimplifyShortImmForm(OutMI, X86::AND64i32); break; - case X86::CMP8ri: SimplifyShortImmForm(OutMI, X86::CMP8i8); break; - case X86::CMP16ri: SimplifyShortImmForm(OutMI, X86::CMP16i16); break; - case X86::CMP32ri: SimplifyShortImmForm(OutMI, X86::CMP32i32); break; - case X86::CMP64ri32: SimplifyShortImmForm(OutMI, X86::CMP64i32); break; - case X86::OR8ri: SimplifyShortImmForm(OutMI, X86::OR8i8); break; - case X86::OR16ri: SimplifyShortImmForm(OutMI, X86::OR16i16); break; - case X86::OR32ri: SimplifyShortImmForm(OutMI, X86::OR32i32); break; - case X86::OR64ri32: SimplifyShortImmForm(OutMI, X86::OR64i32); break; - case X86::SBB8ri: SimplifyShortImmForm(OutMI, X86::SBB8i8); break; - case X86::SBB16ri: SimplifyShortImmForm(OutMI, X86::SBB16i16); break; - case X86::SBB32ri: SimplifyShortImmForm(OutMI, X86::SBB32i32); break; - case X86::SBB64ri32: SimplifyShortImmForm(OutMI, X86::SBB64i32); break; - case X86::SUB8ri: SimplifyShortImmForm(OutMI, X86::SUB8i8); break; - case X86::SUB16ri: SimplifyShortImmForm(OutMI, X86::SUB16i16); break; - case X86::SUB32ri: SimplifyShortImmForm(OutMI, X86::SUB32i32); break; - case X86::SUB64ri32: SimplifyShortImmForm(OutMI, X86::SUB64i32); break; - case X86::TEST8ri: SimplifyShortImmForm(OutMI, X86::TEST8i8); break; - case X86::TEST16ri: SimplifyShortImmForm(OutMI, X86::TEST16i16); break; - case X86::TEST32ri: SimplifyShortImmForm(OutMI, X86::TEST32i32); break; - case X86::TEST64ri32: SimplifyShortImmForm(OutMI, X86::TEST64i32); break; - case X86::XOR8ri: SimplifyShortImmForm(OutMI, X86::XOR8i8); break; - case X86::XOR16ri: SimplifyShortImmForm(OutMI, X86::XOR16i16); break; - case X86::XOR32ri: SimplifyShortImmForm(OutMI, X86::XOR32i32); break; - case X86::XOR64ri32: SimplifyShortImmForm(OutMI, X86::XOR64i32); break; - } -} - -void X86AsmPrinter::PrintDebugValueComment(const MachineInstr *MI, - raw_ostream &O) { - // Only the target-dependent form of DBG_VALUE should get here. - // Referencing the offset and metadata as NOps-2 and NOps-1 is - // probably portable to other targets; frame pointer location is not. - unsigned NOps = MI->getNumOperands(); - assert(NOps==7); - O << '\t' << MAI->getCommentString() << "DEBUG_VALUE: "; - // cast away const; DIetc do not take const operands for some reason. - DIVariable V(const_cast(MI->getOperand(NOps-1).getMetadata())); - if (V.getContext().isSubprogram()) - O << DISubprogram(V.getContext()).getDisplayName() << ":"; - O << V.getName(); - O << " <- "; - // Frame address. Currently handles register +- offset only. - O << '['; - if (MI->getOperand(0).isReg() && MI->getOperand(0).getReg()) - printOperand(MI, 0, O); - else - O << "undef"; - O << '+'; printOperand(MI, 3, O); - O << ']'; - O << "+"; - printOperand(MI, NOps-2, O); -} - -MachineLocation -X86AsmPrinter::getDebugValueLocation(const MachineInstr *MI) const { - MachineLocation Location; - assert (MI->getNumOperands() == 7 && "Invalid no. of machine operands!"); - // Frame address. Currently handles register +- offset only. - - if (MI->getOperand(0).isReg() && MI->getOperand(3).isImm()) - Location.set(MI->getOperand(0).getReg(), MI->getOperand(3).getImm()); - return Location; -} - - -void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) { - X86MCInstLower MCInstLowering(OutContext, Mang, *this); - switch (MI->getOpcode()) { - case TargetOpcode::DBG_VALUE: - if (isVerbose() && OutStreamer.hasRawTextSupport()) { - std::string TmpStr; - raw_string_ostream OS(TmpStr); - PrintDebugValueComment(MI, OS); - OutStreamer.EmitRawText(StringRef(OS.str())); - } - return; - - case X86::TAILJMPr: - case X86::TAILJMPd: - case X86::TAILJMPd64: - // Lower these as normal, but add some comments. - OutStreamer.AddComment("TAILCALL"); - break; - - case X86::MOVPC32r: { - MCInst TmpInst; - // This is a pseudo op for a two instruction sequence with a label, which - // looks like: - // call "L1$pb" - // "L1$pb": - // popl %esi - - // Emit the call. - MCSymbol *PICBase = MCInstLowering.GetPICBaseSymbol(); - TmpInst.setOpcode(X86::CALLpcrel32); - // FIXME: We would like an efficient form for this, so we don't have to do a - // lot of extra uniquing. - TmpInst.addOperand(MCOperand::CreateExpr(MCSymbolRefExpr::Create(PICBase, - OutContext))); - OutStreamer.EmitInstruction(TmpInst); - - // Emit the label. - OutStreamer.EmitLabel(PICBase); - - // popl $reg - TmpInst.setOpcode(X86::POP32r); - TmpInst.getOperand(0) = MCOperand::CreateReg(MI->getOperand(0).getReg()); - OutStreamer.EmitInstruction(TmpInst); - return; - } - - case X86::ADD32ri: { - // Lower the MO_GOT_ABSOLUTE_ADDRESS form of ADD32ri. - if (MI->getOperand(2).getTargetFlags() != X86II::MO_GOT_ABSOLUTE_ADDRESS) - break; - - // Okay, we have something like: - // EAX = ADD32ri EAX, MO_GOT_ABSOLUTE_ADDRESS(@MYGLOBAL) - - // For this, we want to print something like: - // MYGLOBAL + (. - PICBASE) - // However, we can't generate a ".", so just emit a new label here and refer - // to it. - MCSymbol *DotSym = OutContext.CreateTempSymbol(); - OutStreamer.EmitLabel(DotSym); - - // Now that we have emitted the label, lower the complex operand expression. - MCSymbol *OpSym = MCInstLowering.GetSymbolFromOperand(MI->getOperand(2)); - - const MCExpr *DotExpr = MCSymbolRefExpr::Create(DotSym, OutContext); - const MCExpr *PICBase = - MCSymbolRefExpr::Create(MCInstLowering.GetPICBaseSymbol(), OutContext); - DotExpr = MCBinaryExpr::CreateSub(DotExpr, PICBase, OutContext); - - DotExpr = MCBinaryExpr::CreateAdd(MCSymbolRefExpr::Create(OpSym,OutContext), - DotExpr, OutContext); - - MCInst TmpInst; - TmpInst.setOpcode(X86::ADD32ri); - TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); - TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); - TmpInst.addOperand(MCOperand::CreateExpr(DotExpr)); - OutStreamer.EmitInstruction(TmpInst); - return; - } - } - - MCInst TmpInst; - MCInstLowering.Lower(MI, TmpInst); - OutStreamer.EmitInstruction(TmpInst); -} - diff --git a/lib/Target/X86/AsmPrinter/X86MCInstLower.h b/lib/Target/X86/AsmPrinter/X86MCInstLower.h deleted file mode 100644 index 9e5474f..0000000 --- a/lib/Target/X86/AsmPrinter/X86MCInstLower.h +++ /dev/null @@ -1,51 +0,0 @@ -//===-- X86MCInstLower.h - Lower MachineInstr to MCInst -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef X86_MCINSTLOWER_H -#define X86_MCINSTLOWER_H - -#include "llvm/Support/Compiler.h" - -namespace llvm { - class MCContext; - class MCInst; - class MCOperand; - class MCSymbol; - class MachineInstr; - class MachineModuleInfoMachO; - class MachineOperand; - class Mangler; - class X86AsmPrinter; - class X86Subtarget; - -/// X86MCInstLower - This class is used to lower an MachineInstr into an MCInst. -class LLVM_LIBRARY_VISIBILITY X86MCInstLower { - MCContext &Ctx; - Mangler *Mang; - X86AsmPrinter &AsmPrinter; - - const X86Subtarget &getSubtarget() const; -public: - X86MCInstLower(MCContext &ctx, Mangler *mang, X86AsmPrinter &asmprinter) - : Ctx(ctx), Mang(mang), AsmPrinter(asmprinter) {} - - void Lower(const MachineInstr *MI, MCInst &OutMI) const; - - MCSymbol *GetPICBaseSymbol() const; - - MCSymbol *GetSymbolFromOperand(const MachineOperand &MO) const; - MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; - -private: - MachineModuleInfoMachO &getMachOMMI() const; -}; - -} - -#endif diff --git a/lib/Target/X86/CMakeLists.txt b/lib/Target/X86/CMakeLists.txt index 1334820..e9399f5 100644 --- a/lib/Target/X86/CMakeLists.txt +++ b/lib/Target/X86/CMakeLists.txt @@ -18,23 +18,24 @@ tablegen(X86GenEDInfo.inc -gen-enhanced-disassembly-info) set(sources SSEDomainFix.cpp X86AsmBackend.cpp - X86CodeEmitter.cpp + X86AsmPrinter.cpp X86COFFMachineModuleInfo.cpp + X86CodeEmitter.cpp X86ELFWriterInfo.cpp + X86FastISel.cpp X86FloatingPoint.cpp - X86FloatingPointRegKill.cpp X86ISelDAGToDAG.cpp X86ISelLowering.cpp X86InstrInfo.cpp X86JITInfo.cpp X86MCAsmInfo.cpp X86MCCodeEmitter.cpp + X86MCInstLower.cpp X86RegisterInfo.cpp + X86SelectionDAGInfo.cpp X86Subtarget.cpp X86TargetMachine.cpp X86TargetObjectFile.cpp - X86FastISel.cpp - X86SelectionDAGInfo.cpp ) if( CMAKE_CL_64 ) @@ -49,4 +50,3 @@ endif() add_llvm_target(X86CodeGen ${sources}) -target_link_libraries (LLVMX86CodeGen LLVMSelectionDAG) diff --git a/lib/Target/X86/README-FPStack.txt b/lib/Target/X86/README-FPStack.txt index be28e8b..39efd2d 100644 --- a/lib/Target/X86/README-FPStack.txt +++ b/lib/Target/X86/README-FPStack.txt @@ -27,8 +27,8 @@ def FpIADD32m : FpI<(ops RFP:$dst, RFP:$src1, i32mem:$src2), OneArgFPRW, //===---------------------------------------------------------------------===// -The FP stackifier needs to be global. Also, it should handle simple permutates -to reduce number of shuffle instructions, e.g. turning: +The FP stackifier should handle simple permutates to reduce number of shuffle +instructions, e.g. turning: fld P -> fld Q fld Q fld P diff --git a/lib/Target/X86/README-SSE.txt b/lib/Target/X86/README-SSE.txt index b6aba93..f96b22f 100644 --- a/lib/Target/X86/README-SSE.txt +++ b/lib/Target/X86/README-SSE.txt @@ -2,8 +2,46 @@ // Random ideas for the X86 backend: SSE-specific stuff. //===---------------------------------------------------------------------===// -- Consider eliminating the unaligned SSE load intrinsics, replacing them with - unaligned LLVM load instructions. +//===---------------------------------------------------------------------===// + +SSE Variable shift can be custom lowered to something like this, which uses a +small table + unaligned load + shuffle instead of going through memory. + +__m128i_shift_right: + .byte 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + .byte -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 + +... +__m128i shift_right(__m128i value, unsigned long offset) { + return _mm_shuffle_epi8(value, + _mm_loadu_si128((__m128 *) (___m128i_shift_right + offset))); +} + +//===---------------------------------------------------------------------===// + +SSE has instructions for doing operations on complex numbers, we should pattern +match them. Compiling this: + +_Complex float f32(_Complex float A, _Complex float B) { + return A+B; +} + +into: + +_f32: + movdqa %xmm0, %xmm2 + addss %xmm1, %xmm2 + pshufd $16, %xmm2, %xmm2 + pshufd $1, %xmm1, %xmm1 + pshufd $1, %xmm0, %xmm0 + addss %xmm1, %xmm0 + pshufd $16, %xmm0, %xmm1 + movdqa %xmm2, %xmm0 + unpcklps %xmm1, %xmm0 + ret + +seems silly. + //===---------------------------------------------------------------------===// diff --git a/lib/Target/X86/README.txt b/lib/Target/X86/README.txt index efc0cd8..a305ae6 100644 --- a/lib/Target/X86/README.txt +++ b/lib/Target/X86/README.txt @@ -1135,13 +1135,6 @@ void test(double *P) { //===---------------------------------------------------------------------===// -handling llvm.memory.barrier on pre SSE2 cpus - -should generate: -lock ; mov %esp, %esp - -//===---------------------------------------------------------------------===// - The generated code on x86 for checking for signed overflow on a multiply the obvious way is much longer than it needs to be. @@ -1870,3 +1863,100 @@ The code produced by gcc is 3 bytes shorter. This sort of construct often shows up with bitfields. //===---------------------------------------------------------------------===// + +Take the following C code: +int f(int a, int b) { return (unsigned char)a == (unsigned char)b; } + +We generate the following IR with clang: +define i32 @f(i32 %a, i32 %b) nounwind readnone { +entry: + %tmp = xor i32 %b, %a ; [#uses=1] + %tmp6 = and i32 %tmp, 255 ; [#uses=1] + %cmp = icmp eq i32 %tmp6, 0 ; [#uses=1] + %conv5 = zext i1 %cmp to i32 ; [#uses=1] + ret i32 %conv5 +} + +And the following x86 code: + xorl %esi, %edi + testb $-1, %dil + sete %al + movzbl %al, %eax + ret + +A cmpb instead of the xorl+testb would be one instruction shorter. + +//===---------------------------------------------------------------------===// + +Given the following C code: +int f(int a, int b) { return (signed char)a == (signed char)b; } + +We generate the following IR with clang: +define i32 @f(i32 %a, i32 %b) nounwind readnone { +entry: + %sext = shl i32 %a, 24 ; [#uses=1] + %conv1 = ashr i32 %sext, 24 ; [#uses=1] + %sext6 = shl i32 %b, 24 ; [#uses=1] + %conv4 = ashr i32 %sext6, 24 ; [#uses=1] + %cmp = icmp eq i32 %conv1, %conv4 ; [#uses=1] + %conv5 = zext i1 %cmp to i32 ; [#uses=1] + ret i32 %conv5 +} + +And the following x86 code: + movsbl %sil, %eax + movsbl %dil, %ecx + cmpl %eax, %ecx + sete %al + movzbl %al, %eax + ret + + +It should be possible to eliminate the sign extensions. + +//===---------------------------------------------------------------------===// + +LLVM misses a load+store narrowing opportunity in this code: + +%struct.bf = type { i64, i16, i16, i32 } + +@bfi = external global %struct.bf* ; <%struct.bf**> [#uses=2] + +define void @t1() nounwind ssp { +entry: + %0 = load %struct.bf** @bfi, align 8 ; <%struct.bf*> [#uses=1] + %1 = getelementptr %struct.bf* %0, i64 0, i32 1 ; [#uses=1] + %2 = bitcast i16* %1 to i32* ; [#uses=2] + %3 = load i32* %2, align 1 ; [#uses=1] + %4 = and i32 %3, -65537 ; [#uses=1] + store i32 %4, i32* %2, align 1 + %5 = load %struct.bf** @bfi, align 8 ; <%struct.bf*> [#uses=1] + %6 = getelementptr %struct.bf* %5, i64 0, i32 1 ; [#uses=1] + %7 = bitcast i16* %6 to i32* ; [#uses=2] + %8 = load i32* %7, align 1 ; [#uses=1] + %9 = and i32 %8, -131073 ; [#uses=1] + store i32 %9, i32* %7, align 1 + ret void +} + +LLVM currently emits this: + + movq bfi(%rip), %rax + andl $-65537, 8(%rax) + movq bfi(%rip), %rax + andl $-131073, 8(%rax) + ret + +It could narrow the loads and stores to emit this: + + movq bfi(%rip), %rax + andb $-2, 10(%rax) + movq bfi(%rip), %rax + andb $-3, 10(%rax) + ret + +The trouble is that there is a TokenFactor between the store and the +load, making it non-trivial to determine if there's anything between +the load and the store which would prohibit narrowing. + +//===---------------------------------------------------------------------===// diff --git a/lib/Target/X86/SSEDomainFix.cpp b/lib/Target/X86/SSEDomainFix.cpp index dab070e..13680c5 100644 --- a/lib/Target/X86/SSEDomainFix.cpp +++ b/lib/Target/X86/SSEDomainFix.cpp @@ -115,7 +115,7 @@ class SSEDomainFixPass : public MachineFunctionPass { unsigned Distance; public: - SSEDomainFixPass() : MachineFunctionPass(&ID) {} + SSEDomainFixPass() : MachineFunctionPass(ID) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); diff --git a/lib/Target/X86/X86.h b/lib/Target/X86/X86.h index 677781d..27e8850 100644 --- a/lib/Target/X86/X86.h +++ b/lib/Target/X86/X86.h @@ -49,11 +49,6 @@ FunctionPass *createX86FloatingPointStackifierPass(); /// crossings. FunctionPass *createSSEDomainFixPass(); -/// createX87FPRegKillInserterPass - This function returns a pass which -/// inserts FP_REG_KILL instructions where needed. -/// -FunctionPass *createX87FPRegKillInserterPass(); - /// createX86CodeEmitterPass - Return a pass that emits the collected X86 code /// to the specified MCE object. FunctionPass *createX86JITCodeEmitterPass(X86TargetMachine &TM, diff --git a/lib/Target/X86/X86.td b/lib/Target/X86/X86.td index a53f973..a19f1ac 100644 --- a/lib/Target/X86/X86.td +++ b/lib/Target/X86/X86.td @@ -67,6 +67,8 @@ def FeatureSSE4A : SubtargetFeature<"sse4a", "HasSSE4A", "true", def FeatureAVX : SubtargetFeature<"avx", "HasAVX", "true", "Enable AVX instructions">; +def FeatureCLMUL : SubtargetFeature<"clmul", "HasCLMUL", "true", + "Enable carry-less multiplication instructions">; def FeatureFMA3 : SubtargetFeature<"fma3", "HasFMA3", "true", "Enable three-operand fused multiple-add">; def FeatureFMA4 : SubtargetFeature<"fma4", "HasFMA4", "true", @@ -180,8 +182,6 @@ include "X86CallingConv.td" // Currently the X86 assembly parser only supports ATT syntax. def ATTAsmParser : AsmParser { string AsmParserClassName = "ATTAsmParser"; - string AsmParserInstCleanup = "InstructionCleanup"; - string MatchInstructionName = "MatchInstructionImpl"; int Variant = 0; // Discard comments in assembly strings. diff --git a/lib/Target/X86/X86AsmBackend.cpp b/lib/Target/X86/X86AsmBackend.cpp index 2cf65c1..69dc967 100644 --- a/lib/Target/X86/X86AsmBackend.cpp +++ b/lib/Target/X86/X86AsmBackend.cpp @@ -11,9 +11,11 @@ #include "X86.h" #include "X86FixupKinds.h" #include "llvm/ADT/Twine.h" +#include "llvm/MC/ELFObjectWriter.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MachObjectWriter.h" @@ -190,10 +192,6 @@ public: HasScatteredSymbols = true; } - MCObjectWriter *createObjectWriter(raw_ostream &OS) const { - return 0; - } - bool isVirtualSection(const MCSection &Section) const { const MCSectionELF &SE = static_cast(Section); return SE.getType() == MCSectionELF::SHT_NOBITS;; @@ -204,12 +202,43 @@ class ELFX86_32AsmBackend : public ELFX86AsmBackend { public: ELFX86_32AsmBackend(const Target &T) : ELFX86AsmBackend(T) {} + + MCObjectWriter *createObjectWriter(raw_ostream &OS) const { + return new ELFObjectWriter(OS, /*Is64Bit=*/false, + /*IsLittleEndian=*/true, + /*HasRelocationAddend=*/false); + } }; class ELFX86_64AsmBackend : public ELFX86AsmBackend { public: ELFX86_64AsmBackend(const Target &T) : ELFX86AsmBackend(T) {} + + MCObjectWriter *createObjectWriter(raw_ostream &OS) const { + return new ELFObjectWriter(OS, /*Is64Bit=*/true, + /*IsLittleEndian=*/true, + /*HasRelocationAddend=*/true); + } +}; + +class WindowsX86AsmBackend : public X86AsmBackend { + bool Is64Bit; +public: + WindowsX86AsmBackend(const Target &T, bool is64Bit) + : X86AsmBackend(T) + , Is64Bit(is64Bit) { + HasScatteredSymbols = true; + } + + MCObjectWriter *createObjectWriter(raw_ostream &OS) const { + return createWinCOFFObjectWriter(OS, Is64Bit); + } + + bool isVirtualSection(const MCSection &Section) const { + const MCSectionCOFF &SE = static_cast(Section); + return SE.getCharacteristics() & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; + } }; class DarwinX86AsmBackend : public X86AsmBackend { @@ -290,6 +319,10 @@ TargetAsmBackend *llvm::createX86_32AsmBackend(const Target &T, switch (Triple(TT).getOS()) { case Triple::Darwin: return new DarwinX86_32AsmBackend(T); + case Triple::MinGW32: + case Triple::Cygwin: + case Triple::Win32: + return new WindowsX86AsmBackend(T, false); default: return new ELFX86_32AsmBackend(T); } @@ -300,6 +333,10 @@ TargetAsmBackend *llvm::createX86_64AsmBackend(const Target &T, switch (Triple(TT).getOS()) { case Triple::Darwin: return new DarwinX86_64AsmBackend(T); + case Triple::MinGW64: + case Triple::Cygwin: + case Triple::Win32: + return new WindowsX86AsmBackend(T, true); default: return new ELFX86_64AsmBackend(T); } diff --git a/lib/Target/X86/X86AsmPrinter.cpp b/lib/Target/X86/X86AsmPrinter.cpp new file mode 100644 index 0000000..20110ad --- /dev/null +++ b/lib/Target/X86/X86AsmPrinter.cpp @@ -0,0 +1,727 @@ +//===-- X86AsmPrinter.cpp - Convert X86 LLVM code to AT&T assembly --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to X86 machine code. +// +//===----------------------------------------------------------------------===// + +#include "X86AsmPrinter.h" +#include "AsmPrinter/X86ATTInstPrinter.h" +#include "AsmPrinter/X86IntelInstPrinter.h" +#include "X86MCInstLower.h" +#include "X86.h" +#include "X86COFFMachineModuleInfo.h" +#include "X86MachineFunctionInfo.h" +#include "X86TargetMachine.h" +#include "llvm/CallingConv.h" +#include "llvm/DerivedTypes.h" +#include "llvm/Module.h" +#include "llvm/Type.h" +#include "llvm/Analysis/DebugInfo.h" +#include "llvm/Assembly/Writer.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/ADT/SmallString.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Primitive Helper Functions. +//===----------------------------------------------------------------------===// + +void X86AsmPrinter::PrintPICBaseSymbol(raw_ostream &O) const { + const TargetLowering *TLI = TM.getTargetLowering(); + O << *static_cast(TLI)->getPICBaseSymbol(MF, + OutContext); +} + +/// runOnMachineFunction - Emit the function body. +/// +bool X86AsmPrinter::runOnMachineFunction(MachineFunction &MF) { + SetupMachineFunction(MF); + + if (Subtarget->isTargetCOFF()) { + bool Intrn = MF.getFunction()->hasInternalLinkage(); + OutStreamer.BeginCOFFSymbolDef(CurrentFnSym); + OutStreamer.EmitCOFFSymbolStorageClass(Intrn ? COFF::IMAGE_SYM_CLASS_STATIC + : COFF::IMAGE_SYM_CLASS_EXTERNAL); + OutStreamer.EmitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION + << COFF::SCT_COMPLEX_TYPE_SHIFT); + OutStreamer.EndCOFFSymbolDef(); + } + + // Have common code print out the function header with linkage info etc. + EmitFunctionHeader(); + + // Emit the rest of the function body. + EmitFunctionBody(); + + // We didn't modify anything. + return false; +} + +/// printSymbolOperand - Print a raw symbol reference operand. This handles +/// jump tables, constant pools, global address and external symbols, all of +/// which print to a label with various suffixes for relocation types etc. +void X86AsmPrinter::printSymbolOperand(const MachineOperand &MO, + raw_ostream &O) { + switch (MO.getType()) { + default: llvm_unreachable("unknown symbol type!"); + case MachineOperand::MO_JumpTableIndex: + O << *GetJTISymbol(MO.getIndex()); + break; + case MachineOperand::MO_ConstantPoolIndex: + O << *GetCPISymbol(MO.getIndex()); + printOffset(MO.getOffset(), O); + break; + case MachineOperand::MO_GlobalAddress: { + const GlobalValue *GV = MO.getGlobal(); + + MCSymbol *GVSym; + if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB) + GVSym = GetSymbolWithGlobalValueBase(GV, "$stub"); + else if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY || + MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE || + MO.getTargetFlags() == X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE) + GVSym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); + else + GVSym = Mang->getSymbol(GV); + + // Handle dllimport linkage. + if (MO.getTargetFlags() == X86II::MO_DLLIMPORT) + GVSym = OutContext.GetOrCreateSymbol(Twine("__imp_") + GVSym->getName()); + + if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY || + MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE) { + MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); + MachineModuleInfoImpl::StubValueTy &StubSym = + MMI->getObjFileInfo().getGVStubEntry(Sym); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); + } else if (MO.getTargetFlags() == X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE){ + MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); + MachineModuleInfoImpl::StubValueTy &StubSym = + MMI->getObjFileInfo().getHiddenGVStubEntry(Sym); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); + } else if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB) { + MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$stub"); + MachineModuleInfoImpl::StubValueTy &StubSym = + MMI->getObjFileInfo().getFnStubEntry(Sym); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); + } + + // If the name begins with a dollar-sign, enclose it in parens. We do this + // to avoid having it look like an integer immediate to the assembler. + if (GVSym->getName()[0] != '$') + O << *GVSym; + else + O << '(' << *GVSym << ')'; + printOffset(MO.getOffset(), O); + break; + } + case MachineOperand::MO_ExternalSymbol: { + const MCSymbol *SymToPrint; + if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB) { + SmallString<128> TempNameStr; + TempNameStr += StringRef(MO.getSymbolName()); + TempNameStr += StringRef("$stub"); + + MCSymbol *Sym = GetExternalSymbolSymbol(TempNameStr.str()); + MachineModuleInfoImpl::StubValueTy &StubSym = + MMI->getObjFileInfo().getFnStubEntry(Sym); + if (StubSym.getPointer() == 0) { + TempNameStr.erase(TempNameStr.end()-5, TempNameStr.end()); + StubSym = MachineModuleInfoImpl:: + StubValueTy(OutContext.GetOrCreateSymbol(TempNameStr.str()), + true); + } + SymToPrint = StubSym.getPointer(); + } else { + SymToPrint = GetExternalSymbolSymbol(MO.getSymbolName()); + } + + // If the name begins with a dollar-sign, enclose it in parens. We do this + // to avoid having it look like an integer immediate to the assembler. + if (SymToPrint->getName()[0] != '$') + O << *SymToPrint; + else + O << '(' << *SymToPrint << '('; + break; + } + } + + switch (MO.getTargetFlags()) { + default: + llvm_unreachable("Unknown target flag on GV operand"); + case X86II::MO_NO_FLAG: // No flag. + break; + case X86II::MO_DARWIN_NONLAZY: + case X86II::MO_DLLIMPORT: + case X86II::MO_DARWIN_STUB: + // These affect the name of the symbol, not any suffix. + break; + case X86II::MO_GOT_ABSOLUTE_ADDRESS: + O << " + [.-"; + PrintPICBaseSymbol(O); + O << ']'; + break; + case X86II::MO_PIC_BASE_OFFSET: + case X86II::MO_DARWIN_NONLAZY_PIC_BASE: + case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE: + O << '-'; + PrintPICBaseSymbol(O); + break; + case X86II::MO_TLSGD: O << "@TLSGD"; break; + case X86II::MO_GOTTPOFF: O << "@GOTTPOFF"; break; + case X86II::MO_INDNTPOFF: O << "@INDNTPOFF"; break; + case X86II::MO_TPOFF: O << "@TPOFF"; break; + case X86II::MO_NTPOFF: O << "@NTPOFF"; break; + case X86II::MO_GOTPCREL: O << "@GOTPCREL"; break; + case X86II::MO_GOT: O << "@GOT"; break; + case X86II::MO_GOTOFF: O << "@GOTOFF"; break; + case X86II::MO_PLT: O << "@PLT"; break; + case X86II::MO_TLVP: O << "@TLVP"; break; + case X86II::MO_TLVP_PIC_BASE: + O << "@TLVP" << '-'; + PrintPICBaseSymbol(O); + break; + } +} + +/// print_pcrel_imm - This is used to print an immediate value that ends up +/// being encoded as a pc-relative value. These print slightly differently, for +/// example, a $ is not emitted. +void X86AsmPrinter::print_pcrel_imm(const MachineInstr *MI, unsigned OpNo, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(OpNo); + switch (MO.getType()) { + default: llvm_unreachable("Unknown pcrel immediate operand"); + case MachineOperand::MO_Register: + // pc-relativeness was handled when computing the value in the reg. + printOperand(MI, OpNo, O); + return; + case MachineOperand::MO_Immediate: + O << MO.getImm(); + return; + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + return; + case MachineOperand::MO_GlobalAddress: + case MachineOperand::MO_ExternalSymbol: + printSymbolOperand(MO, O); + return; + } +} + + +void X86AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, + raw_ostream &O, const char *Modifier) { + const MachineOperand &MO = MI->getOperand(OpNo); + switch (MO.getType()) { + default: llvm_unreachable("unknown operand type!"); + case MachineOperand::MO_Register: { + O << '%'; + unsigned Reg = MO.getReg(); + if (Modifier && strncmp(Modifier, "subreg", strlen("subreg")) == 0) { + EVT VT = (strcmp(Modifier+6,"64") == 0) ? + MVT::i64 : ((strcmp(Modifier+6, "32") == 0) ? MVT::i32 : + ((strcmp(Modifier+6,"16") == 0) ? MVT::i16 : MVT::i8)); + Reg = getX86SubSuperRegister(Reg, VT); + } + O << X86ATTInstPrinter::getRegisterName(Reg); + return; + } + + case MachineOperand::MO_Immediate: + O << '$' << MO.getImm(); + return; + + case MachineOperand::MO_JumpTableIndex: + case MachineOperand::MO_ConstantPoolIndex: + case MachineOperand::MO_GlobalAddress: + case MachineOperand::MO_ExternalSymbol: { + O << '$'; + printSymbolOperand(MO, O); + break; + } + } +} + +void X86AsmPrinter::printSSECC(const MachineInstr *MI, unsigned Op, + raw_ostream &O) { + unsigned char value = MI->getOperand(Op).getImm(); + assert(value <= 7 && "Invalid ssecc argument!"); + switch (value) { + case 0: O << "eq"; break; + case 1: O << "lt"; break; + case 2: O << "le"; break; + case 3: O << "unord"; break; + case 4: O << "neq"; break; + case 5: O << "nlt"; break; + case 6: O << "nle"; break; + case 7: O << "ord"; break; + } +} + +void X86AsmPrinter::printLeaMemReference(const MachineInstr *MI, unsigned Op, + raw_ostream &O, const char *Modifier) { + const MachineOperand &BaseReg = MI->getOperand(Op); + const MachineOperand &IndexReg = MI->getOperand(Op+2); + const MachineOperand &DispSpec = MI->getOperand(Op+3); + + // If we really don't want to print out (rip), don't. + bool HasBaseReg = BaseReg.getReg() != 0; + if (HasBaseReg && Modifier && !strcmp(Modifier, "no-rip") && + BaseReg.getReg() == X86::RIP) + HasBaseReg = false; + + // HasParenPart - True if we will print out the () part of the mem ref. + bool HasParenPart = IndexReg.getReg() || HasBaseReg; + + if (DispSpec.isImm()) { + int DispVal = DispSpec.getImm(); + if (DispVal || !HasParenPart) + O << DispVal; + } else { + assert(DispSpec.isGlobal() || DispSpec.isCPI() || + DispSpec.isJTI() || DispSpec.isSymbol()); + printSymbolOperand(MI->getOperand(Op+3), O); + } + + if (HasParenPart) { + assert(IndexReg.getReg() != X86::ESP && + "X86 doesn't allow scaling by ESP"); + + O << '('; + if (HasBaseReg) + printOperand(MI, Op, O, Modifier); + + if (IndexReg.getReg()) { + O << ','; + printOperand(MI, Op+2, O, Modifier); + unsigned ScaleVal = MI->getOperand(Op+1).getImm(); + if (ScaleVal != 1) + O << ',' << ScaleVal; + } + O << ')'; + } +} + +void X86AsmPrinter::printMemReference(const MachineInstr *MI, unsigned Op, + raw_ostream &O, const char *Modifier) { + assert(isMem(MI, Op) && "Invalid memory reference!"); + const MachineOperand &Segment = MI->getOperand(Op+4); + if (Segment.getReg()) { + printOperand(MI, Op+4, O, Modifier); + O << ':'; + } + printLeaMemReference(MI, Op, O, Modifier); +} + +void X86AsmPrinter::printPICLabel(const MachineInstr *MI, unsigned Op, + raw_ostream &O) { + PrintPICBaseSymbol(O); + O << '\n'; + PrintPICBaseSymbol(O); + O << ':'; +} + +bool X86AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode, + raw_ostream &O) { + unsigned Reg = MO.getReg(); + switch (Mode) { + default: return true; // Unknown mode. + case 'b': // Print QImode register + Reg = getX86SubSuperRegister(Reg, MVT::i8); + break; + case 'h': // Print QImode high register + Reg = getX86SubSuperRegister(Reg, MVT::i8, true); + break; + case 'w': // Print HImode register + Reg = getX86SubSuperRegister(Reg, MVT::i16); + break; + case 'k': // Print SImode register + Reg = getX86SubSuperRegister(Reg, MVT::i32); + break; + case 'q': // Print DImode register + Reg = getX86SubSuperRegister(Reg, MVT::i64); + break; + } + + O << '%' << X86ATTInstPrinter::getRegisterName(Reg); + return false; +} + +/// PrintAsmOperand - Print out an operand for an inline asm expression. +/// +bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, + const char *ExtraCode, raw_ostream &O) { + // Does this asm operand have a single letter operand modifier? + if (ExtraCode && ExtraCode[0]) { + if (ExtraCode[1] != 0) return true; // Unknown modifier. + + const MachineOperand &MO = MI->getOperand(OpNo); + + switch (ExtraCode[0]) { + default: return true; // Unknown modifier. + case 'a': // This is an address. Currently only 'i' and 'r' are expected. + if (MO.isImm()) { + O << MO.getImm(); + return false; + } + if (MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isSymbol()) { + printSymbolOperand(MO, O); + if (Subtarget->isPICStyleRIPRel()) + O << "(%rip)"; + return false; + } + if (MO.isReg()) { + O << '('; + printOperand(MI, OpNo, O); + O << ')'; + return false; + } + return true; + + case 'c': // Don't print "$" before a global var name or constant. + if (MO.isImm()) + O << MO.getImm(); + else if (MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isSymbol()) + printSymbolOperand(MO, O); + else + printOperand(MI, OpNo, O); + return false; + + case 'A': // Print '*' before a register (it must be a register) + if (MO.isReg()) { + O << '*'; + printOperand(MI, OpNo, O); + return false; + } + return true; + + case 'b': // Print QImode register + case 'h': // Print QImode high register + case 'w': // Print HImode register + case 'k': // Print SImode register + case 'q': // Print DImode register + if (MO.isReg()) + return printAsmMRegister(MO, ExtraCode[0], O); + printOperand(MI, OpNo, O); + return false; + + case 'P': // This is the operand of a call, treat specially. + print_pcrel_imm(MI, OpNo, O); + return false; + + case 'n': // Negate the immediate or print a '-' before the operand. + // Note: this is a temporary solution. It should be handled target + // independently as part of the 'MC' work. + if (MO.isImm()) { + O << -MO.getImm(); + return false; + } + O << '-'; + } + } + + printOperand(MI, OpNo, O); + return false; +} + +bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNo, unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &O) { + if (ExtraCode && ExtraCode[0]) { + if (ExtraCode[1] != 0) return true; // Unknown modifier. + + switch (ExtraCode[0]) { + default: return true; // Unknown modifier. + case 'b': // Print QImode register + case 'h': // Print QImode high register + case 'w': // Print HImode register + case 'k': // Print SImode register + case 'q': // Print SImode register + // These only apply to registers, ignore on mem. + break; + case 'P': // Don't print @PLT, but do print as memory. + printMemReference(MI, OpNo, O, "no-rip"); + return false; + } + } + printMemReference(MI, OpNo, O); + return false; +} + +void X86AsmPrinter::EmitStartOfAsmFile(Module &M) { + if (Subtarget->isTargetDarwin()) + OutStreamer.SwitchSection(getObjFileLowering().getTextSection()); +} + + +void X86AsmPrinter::EmitEndOfAsmFile(Module &M) { + if (Subtarget->isTargetDarwin()) { + // All darwin targets use mach-o. + MachineModuleInfoMachO &MMIMacho = + MMI->getObjFileInfo(); + + // Output stubs for dynamically-linked functions. + MachineModuleInfoMachO::SymbolListTy Stubs; + + Stubs = MMIMacho.GetFnStubList(); + if (!Stubs.empty()) { + const MCSection *TheSection = + OutContext.getMachOSection("__IMPORT", "__jump_table", + MCSectionMachO::S_SYMBOL_STUBS | + MCSectionMachO::S_ATTR_SELF_MODIFYING_CODE | + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 5, SectionKind::getMetadata()); + OutStreamer.SwitchSection(TheSection); + + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + // L_foo$stub: + OutStreamer.EmitLabel(Stubs[i].first); + // .indirect_symbol _foo + OutStreamer.EmitSymbolAttribute(Stubs[i].second.getPointer(), + MCSA_IndirectSymbol); + // hlt; hlt; hlt; hlt; hlt hlt = 0xf4 = -12. + const char HltInsts[] = { -12, -12, -12, -12, -12 }; + OutStreamer.EmitBytes(StringRef(HltInsts, 5), 0/*addrspace*/); + } + + Stubs.clear(); + OutStreamer.AddBlankLine(); + } + + // Output stubs for external and common global variables. + Stubs = MMIMacho.GetGVStubList(); + if (!Stubs.empty()) { + const MCSection *TheSection = + OutContext.getMachOSection("__IMPORT", "__pointers", + MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS, + SectionKind::getMetadata()); + OutStreamer.SwitchSection(TheSection); + + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + // L_foo$non_lazy_ptr: + OutStreamer.EmitLabel(Stubs[i].first); + // .indirect_symbol _foo + MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second; + OutStreamer.EmitSymbolAttribute(MCSym.getPointer(), + MCSA_IndirectSymbol); + // .long 0 + if (MCSym.getInt()) + // External to current translation unit. + OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/); + else + // Internal to current translation unit. + // + // When we place the LSDA into the TEXT section, the type info + // pointers need to be indirect and pc-rel. We accomplish this by + // using NLPs. However, sometimes the types are local to the file. So + // we need to fill in the value for the NLP in those cases. + OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym.getPointer(), + OutContext), + 4/*size*/, 0/*addrspace*/); + } + Stubs.clear(); + OutStreamer.AddBlankLine(); + } + + Stubs = MMIMacho.GetHiddenGVStubList(); + if (!Stubs.empty()) { + OutStreamer.SwitchSection(getObjFileLowering().getDataSection()); + EmitAlignment(2); + + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + // L_foo$non_lazy_ptr: + OutStreamer.EmitLabel(Stubs[i].first); + // .long _foo + OutStreamer.EmitValue(MCSymbolRefExpr:: + Create(Stubs[i].second.getPointer(), + OutContext), + 4/*size*/, 0/*addrspace*/); + } + Stubs.clear(); + OutStreamer.AddBlankLine(); + } + + // Funny Darwin hack: This flag tells the linker that no global symbols + // contain code that falls through to other global symbols (e.g. the obvious + // implementation of multiple entry points). If this doesn't occur, the + // linker can safely perform dead code stripping. Since LLVM never + // generates code that does this, it is always safe to set. + OutStreamer.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols); + } + + if (Subtarget->isTargetCOFF()) { + X86COFFMachineModuleInfo &COFFMMI = + MMI->getObjFileInfo(); + + // Emit type information for external functions + typedef X86COFFMachineModuleInfo::externals_iterator externals_iterator; + for (externals_iterator I = COFFMMI.externals_begin(), + E = COFFMMI.externals_end(); + I != E; ++I) { + OutStreamer.BeginCOFFSymbolDef(CurrentFnSym); + OutStreamer.EmitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL); + OutStreamer.EmitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION + << COFF::SCT_COMPLEX_TYPE_SHIFT); + OutStreamer.EndCOFFSymbolDef(); + } + + // Necessary for dllexport support + std::vector DLLExportedFns, DLLExportedGlobals; + + const TargetLoweringObjectFileCOFF &TLOFCOFF = + static_cast(getObjFileLowering()); + + for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) + if (I->hasDLLExportLinkage()) + DLLExportedFns.push_back(Mang->getSymbol(I)); + + for (Module::const_global_iterator I = M.global_begin(), + E = M.global_end(); I != E; ++I) + if (I->hasDLLExportLinkage()) + DLLExportedGlobals.push_back(Mang->getSymbol(I)); + + // Output linker support code for dllexported globals on windows. + if (!DLLExportedGlobals.empty() || !DLLExportedFns.empty()) { + OutStreamer.SwitchSection(TLOFCOFF.getDrectveSection()); + SmallString<128> name; + for (unsigned i = 0, e = DLLExportedGlobals.size(); i != e; ++i) { + if (Subtarget->isTargetWindows()) + name = " /EXPORT:"; + else + name = " -export:"; + name += DLLExportedGlobals[i]->getName(); + if (Subtarget->isTargetWindows()) + name += ",DATA"; + else + name += ",data"; + OutStreamer.EmitBytes(name, 0); + } + + for (unsigned i = 0, e = DLLExportedFns.size(); i != e; ++i) { + if (Subtarget->isTargetWindows()) + name = " /EXPORT:"; + else + name = " -export:"; + name += DLLExportedFns[i]->getName(); + OutStreamer.EmitBytes(name, 0); + } + } + } + + if (Subtarget->isTargetELF()) { + const TargetLoweringObjectFileELF &TLOFELF = + static_cast(getObjFileLowering()); + + MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo(); + + // Output stubs for external and common global variables. + MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList(); + if (!Stubs.empty()) { + OutStreamer.SwitchSection(TLOFELF.getDataRelSection()); + const TargetData *TD = TM.getTargetData(); + + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + OutStreamer.EmitLabel(Stubs[i].first); + OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), + TD->getPointerSize(), 0); + } + Stubs.clear(); + } + } +} + +MachineLocation +X86AsmPrinter::getDebugValueLocation(const MachineInstr *MI) const { + MachineLocation Location; + assert (MI->getNumOperands() == 7 && "Invalid no. of machine operands!"); + // Frame address. Currently handles register +- offset only. + + if (MI->getOperand(0).isReg() && MI->getOperand(3).isImm()) + Location.set(MI->getOperand(0).getReg(), MI->getOperand(3).getImm()); + else { + DEBUG(dbgs() << "DBG_VALUE instruction ignored! " << *MI << "\n"); + } + return Location; +} + +void X86AsmPrinter::PrintDebugValueComment(const MachineInstr *MI, + raw_ostream &O) { + // Only the target-dependent form of DBG_VALUE should get here. + // Referencing the offset and metadata as NOps-2 and NOps-1 is + // probably portable to other targets; frame pointer location is not. + unsigned NOps = MI->getNumOperands(); + assert(NOps==7); + O << '\t' << MAI->getCommentString() << "DEBUG_VALUE: "; + // cast away const; DIetc do not take const operands for some reason. + DIVariable V(const_cast(MI->getOperand(NOps-1).getMetadata())); + if (V.getContext().isSubprogram()) + O << DISubprogram(V.getContext()).getDisplayName() << ":"; + O << V.getName(); + O << " <- "; + // Frame address. Currently handles register +- offset only. + O << '['; + if (MI->getOperand(0).isReg() && MI->getOperand(0).getReg()) + printOperand(MI, 0, O); + else + O << "undef"; + O << '+'; printOperand(MI, 3, O); + O << ']'; + O << "+"; + printOperand(MI, NOps-2, O); +} + + + +//===----------------------------------------------------------------------===// +// Target Registry Stuff +//===----------------------------------------------------------------------===// + +static MCInstPrinter *createX86MCInstPrinter(const Target &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI) { + if (SyntaxVariant == 0) + return new X86ATTInstPrinter(MAI); + if (SyntaxVariant == 1) + return new X86IntelInstPrinter(MAI); + return 0; +} + +// Force static initialization. +extern "C" void LLVMInitializeX86AsmPrinter() { + RegisterAsmPrinter X(TheX86_32Target); + RegisterAsmPrinter Y(TheX86_64Target); + + TargetRegistry::RegisterMCInstPrinter(TheX86_32Target,createX86MCInstPrinter); + TargetRegistry::RegisterMCInstPrinter(TheX86_64Target,createX86MCInstPrinter); +} diff --git a/lib/Target/X86/X86AsmPrinter.h b/lib/Target/X86/X86AsmPrinter.h new file mode 100644 index 0000000..e61be66 --- /dev/null +++ b/lib/Target/X86/X86AsmPrinter.h @@ -0,0 +1,89 @@ +//===-- X86AsmPrinter.h - Convert X86 LLVM code to assembly -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// AT&T assembly code printer class. +// +//===----------------------------------------------------------------------===// + +#ifndef X86ASMPRINTER_H +#define X86ASMPRINTER_H + +#include "X86.h" +#include "X86MachineFunctionInfo.h" +#include "X86TargetMachine.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { + +class MachineJumpTableInfo; +class MCContext; +class MCInst; +class MCStreamer; +class MCSymbol; + +class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter { + const X86Subtarget *Subtarget; + public: + explicit X86AsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer) { + Subtarget = &TM.getSubtarget(); + } + + virtual const char *getPassName() const { + return "X86 AT&T-Style Assembly Printer"; + } + + const X86Subtarget &getSubtarget() const { return *Subtarget; } + + virtual void EmitStartOfAsmFile(Module &M); + + virtual void EmitEndOfAsmFile(Module &M); + + virtual void EmitInstruction(const MachineInstr *MI); + + void printSymbolOperand(const MachineOperand &MO, raw_ostream &O); + + // These methods are used by the tablegen'erated instruction printer. + void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O, + const char *Modifier = 0); + void print_pcrel_imm(const MachineInstr *MI, unsigned OpNo, raw_ostream &O); + + bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O); + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &OS); + bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &OS); + + void printMachineInstruction(const MachineInstr *MI); + void printSSECC(const MachineInstr *MI, unsigned Op, raw_ostream &O); + void printMemReference(const MachineInstr *MI, unsigned Op, raw_ostream &O, + const char *Modifier=NULL); + void printLeaMemReference(const MachineInstr *MI, unsigned Op, raw_ostream &O, + const char *Modifier=NULL); + + void printPICLabel(const MachineInstr *MI, unsigned Op, raw_ostream &O); + + void PrintPICBaseSymbol(raw_ostream &O) const; + + bool runOnMachineFunction(MachineFunction &F); + + void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); + + MachineLocation getDebugValueLocation(const MachineInstr *MI) const; +}; + +} // end namespace llvm + +#endif diff --git a/lib/Target/X86/X86CallingConv.td b/lib/Target/X86/X86CallingConv.td index a6a1e4e..e3409ef 100644 --- a/lib/Target/X86/X86CallingConv.td +++ b/lib/Target/X86/X86CallingConv.td @@ -33,13 +33,19 @@ def RetCC_X86Common : CallingConv<[ CCIfType<[i16], CCAssignToReg<[AX, DX]>>, CCIfType<[i32], CCAssignToReg<[EAX, EDX]>>, CCIfType<[i64], CCAssignToReg<[RAX, RDX]>>, - - // Vector types are returned in XMM0 and XMM1, when they fit. XMMM2 and XMM3 + + // Vector types are returned in XMM0 and XMM1, when they fit. XMM2 and XMM3 // can only be used by ABI non-compliant code. If the target doesn't have XMM // registers, it won't have vector types. CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], CCAssignToReg<[XMM0,XMM1,XMM2,XMM3]>>, + // 256-bit vectors are returned in YMM0 and XMM1, when they fit. YMM2 and YMM3 + // can only be used by ABI non-compliant code. This vector type is only + // supported while using the AVX target feature. + CCIfType<[v32i8, v16i16, v8i32, v4i64, v8f32, v4f64], + CCIfSubtarget<"hasAVX()", CCAssignToReg<[YMM0,YMM1,YMM2,YMM3]>>>, + // MMX vector types are always returned in MM0. If the target doesn't have // MM0, it doesn't support these vector types. CCIfType<[v8i8, v4i16, v2i32, v1i64], CCAssignToReg<[MM0]>>, @@ -164,11 +170,16 @@ def CC_X86_64_C : CallingConv<[ CCIfType<[f32, f64, v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], CCIfSubtarget<"hasSSE1()", CCAssignToReg<[XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7]>>>, - + + // The first 8 256-bit vector arguments are passed in YMM registers. + CCIfType<[v32i8, v16i16, v8i32, v4i64, v8f32, v4f64], + CCIfSubtarget<"hasAVX()", + CCAssignToReg<[YMM0, YMM1, YMM2, YMM3, YMM4, YMM5, YMM6, YMM7]>>>, + // Integer/FP values get stored in stack slots that are 8 bytes in size and // 8-byte aligned if there are no more registers to hold them. CCIfType<[i32, i64, f32, f64], CCAssignToStack<8, 8>>, - + // Long doubles get stack slots whose size and alignment depends on the // subtarget. CCIfType<[f80], CCAssignToStack<0, 0>>, @@ -176,6 +187,10 @@ def CC_X86_64_C : CallingConv<[ // Vectors get 16-byte stack slots that are 16-byte aligned. CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], CCAssignToStack<16, 16>>, + // 256-bit vectors get 32-byte stack slots that are 32-byte aligned. + CCIfType<[v32i8, v16i16, v8i32, v4i64, v8f32, v4f64], + CCAssignToStack<32, 32>>, + // __m64 vectors get 8-byte stack slots that are 8-byte aligned. CCIfType<[v8i8, v4i16, v2i32, v1i64], CCAssignToStack<8, 8>> ]>; @@ -271,9 +286,18 @@ def CC_X86_32_Common : CallingConv<[ CCIfNotVarArg>>, + // The first 4 AVX 256-bit vector arguments are passed in YMM registers. + CCIfNotVarArg>>>, + // Other SSE vectors get 16-byte stack slots that are 16-byte aligned. CCIfType<[v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], CCAssignToStack<16, 16>>, + // 256-bit AVX vectors get 32-byte stack slots that are 32-byte aligned. + CCIfType<[v32i8, v16i16, v8i32, v4i64, v8f32, v4f64], + CCAssignToStack<32, 32>>, + // __m64 vectors get 8-byte stack slots that are 4-byte aligned. They are // passed in the parameter area. CCIfType<[v8i8, v4i16, v2i32, v1i64], CCAssignToStack<8, 4>>]>; diff --git a/lib/Target/X86/X86CodeEmitter.cpp b/lib/Target/X86/X86CodeEmitter.cpp index f13669b..824021c 100644 --- a/lib/Target/X86/X86CodeEmitter.cpp +++ b/lib/Target/X86/X86CodeEmitter.cpp @@ -53,12 +53,12 @@ namespace { public: static char ID; explicit Emitter(X86TargetMachine &tm, CodeEmitter &mce) - : MachineFunctionPass(&ID), II(0), TD(0), TM(tm), + : MachineFunctionPass(ID), II(0), TD(0), TM(tm), MCE(mce), PICBaseOffset(0), Is64BitMode(false), IsPIC(TM.getRelocationModel() == Reloc::PIC_) {} Emitter(X86TargetMachine &tm, CodeEmitter &mce, const X86InstrInfo &ii, const TargetData &td, bool is64) - : MachineFunctionPass(&ID), II(&ii), TD(&td), TM(tm), + : MachineFunctionPass(ID), II(&ii), TD(&td), TM(tm), MCE(mce), PICBaseOffset(0), Is64BitMode(is64), IsPIC(TM.getRelocationModel() == Reloc::PIC_) {} @@ -146,6 +146,103 @@ bool Emitter::runOnMachineFunction(MachineFunction &MF) { return false; } +/// determineREX - Determine if the MachineInstr has to be encoded with a X86-64 +/// REX prefix which specifies 1) 64-bit instructions, 2) non-default operand +/// size, and 3) use of X86-64 extended registers. +static unsigned determineREX(const MachineInstr &MI) { + unsigned REX = 0; + const TargetInstrDesc &Desc = MI.getDesc(); + + // Pseudo instructions do not need REX prefix byte. + if ((Desc.TSFlags & X86II::FormMask) == X86II::Pseudo) + return 0; + if (Desc.TSFlags & X86II::REX_W) + REX |= 1 << 3; + + unsigned NumOps = Desc.getNumOperands(); + if (NumOps) { + bool isTwoAddr = NumOps > 1 && + Desc.getOperandConstraint(1, TOI::TIED_TO) != -1; + + // If it accesses SPL, BPL, SIL, or DIL, then it requires a 0x40 REX prefix. + unsigned i = isTwoAddr ? 1 : 0; + for (unsigned e = NumOps; i != e; ++i) { + const MachineOperand& MO = MI.getOperand(i); + if (MO.isReg()) { + unsigned Reg = MO.getReg(); + if (X86InstrInfo::isX86_64NonExtLowByteReg(Reg)) + REX |= 0x40; + } + } + + switch (Desc.TSFlags & X86II::FormMask) { + case X86II::MRMInitReg: + if (X86InstrInfo::isX86_64ExtendedReg(MI.getOperand(0))) + REX |= (1 << 0) | (1 << 2); + break; + case X86II::MRMSrcReg: { + if (X86InstrInfo::isX86_64ExtendedReg(MI.getOperand(0))) + REX |= 1 << 2; + i = isTwoAddr ? 2 : 1; + for (unsigned e = NumOps; i != e; ++i) { + const MachineOperand& MO = MI.getOperand(i); + if (X86InstrInfo::isX86_64ExtendedReg(MO)) + REX |= 1 << 0; + } + break; + } + case X86II::MRMSrcMem: { + if (X86InstrInfo::isX86_64ExtendedReg(MI.getOperand(0))) + REX |= 1 << 2; + unsigned Bit = 0; + i = isTwoAddr ? 2 : 1; + for (; i != NumOps; ++i) { + const MachineOperand& MO = MI.getOperand(i); + if (MO.isReg()) { + if (X86InstrInfo::isX86_64ExtendedReg(MO)) + REX |= 1 << Bit; + Bit++; + } + } + break; + } + case X86II::MRM0m: case X86II::MRM1m: + case X86II::MRM2m: case X86II::MRM3m: + case X86II::MRM4m: case X86II::MRM5m: + case X86II::MRM6m: case X86II::MRM7m: + case X86II::MRMDestMem: { + unsigned e = (isTwoAddr ? X86::AddrNumOperands+1 : X86::AddrNumOperands); + i = isTwoAddr ? 1 : 0; + if (NumOps > e && X86InstrInfo::isX86_64ExtendedReg(MI.getOperand(e))) + REX |= 1 << 2; + unsigned Bit = 0; + for (; i != e; ++i) { + const MachineOperand& MO = MI.getOperand(i); + if (MO.isReg()) { + if (X86InstrInfo::isX86_64ExtendedReg(MO)) + REX |= 1 << Bit; + Bit++; + } + } + break; + } + default: { + if (X86InstrInfo::isX86_64ExtendedReg(MI.getOperand(0))) + REX |= 1 << 0; + i = isTwoAddr ? 2 : 1; + for (unsigned e = NumOps; i != e; ++i) { + const MachineOperand& MO = MI.getOperand(i); + if (X86InstrInfo::isX86_64ExtendedReg(MO)) + REX |= 1 << 2; + } + break; + } + } + } + return REX; +} + + /// emitPCRelativeBlockAddress - This method keeps track of the information /// necessary to resolve the address of this block later and emits a dummy /// value. @@ -569,7 +666,7 @@ void Emitter::emitInstruction(const MachineInstr &MI, // Handle REX prefix. if (Is64BitMode) { - if (unsigned REX = X86InstrInfo::determineREX(MI)) + if (unsigned REX = determineREX(MI)) MCE.emitByte(0x40 | REX); } @@ -605,24 +702,29 @@ void Emitter::emitInstruction(const MachineInstr &MI, // base address. switch (Opcode) { default: - llvm_unreachable("psuedo instructions should be removed before code" + llvm_unreachable("pseudo instructions should be removed before code" " emission"); break; + // Do nothing for Int_MemBarrier - it's just a comment. Add a debug + // to make it slightly easier to see. + case X86::Int_MemBarrier: + DEBUG(dbgs() << "#MEMBARRIER\n"); + break; + case TargetOpcode::INLINEASM: // We allow inline assembler nodes with empty bodies - they can // implicitly define registers, which is ok for JIT. if (MI.getOperand(0).getSymbolName()[0]) report_fatal_error("JIT does not support inline asm!"); break; - case TargetOpcode::DBG_LABEL: + case TargetOpcode::PROLOG_LABEL: case TargetOpcode::GC_LABEL: case TargetOpcode::EH_LABEL: MCE.emitLabel(MI.getOperand(0).getMCSymbol()); break; - + case TargetOpcode::IMPLICIT_DEF: case TargetOpcode::KILL: - case X86::FP_REG_KILL: break; case X86::MOVPC32r: { // This emits the "call" portion of this pseudo instruction. @@ -674,7 +776,8 @@ void Emitter::emitInstruction(const MachineInstr &MI, } assert(MO.isImm() && "Unknown RawFrm operand!"); - if (Opcode == X86::CALLpcrel32 || Opcode == X86::CALL64pcrel32) { + if (Opcode == X86::CALLpcrel32 || Opcode == X86::CALL64pcrel32 || + Opcode == X86::WINCALL64pcrel32) { // Fix up immediate operand for pc relative calls. intptr_t Imm = (intptr_t)MO.getImm(); Imm = Imm - MCE.getCurrentPCValue() - 4; diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp index ce13707..0c70eec 100644 --- a/lib/Target/X86/X86FastISel.cpp +++ b/lib/Target/X86/X86FastISel.cpp @@ -960,9 +960,11 @@ bool X86FastISel::X86SelectBranch(const Instruction *I) { MachineBasicBlock *TrueMBB = FuncInfo.MBBMap[BI->getSuccessor(0)]; MachineBasicBlock *FalseMBB = FuncInfo.MBBMap[BI->getSuccessor(1)]; - // Fold the common case of a conditional branch with a comparison. + // Fold the common case of a conditional branch with a comparison + // in the same block (values defined on other blocks may not have + // initialized registers). if (const CmpInst *CI = dyn_cast(BI->getCondition())) { - if (CI->hasOneUse()) { + if (CI->hasOneUse() && CI->getParent() == I->getParent()) { EVT VT = TLI.getValueType(CI->getOperand(0)->getType()); // Try to take advantage of fallthrough opportunities. @@ -1058,10 +1060,8 @@ bool X86FastISel::X86SelectBranch(const Instruction *I) { const MachineInstr &MI = *RI; if (MI.definesRegister(Reg)) { - unsigned Src, Dst, SrcSR, DstSR; - - if (getInstrInfo()->isMoveInstr(MI, Src, Dst, SrcSR, DstSR)) { - Reg = Src; + if (MI.isCopy()) { + Reg = MI.getOperand(1).getReg(); continue; } @@ -1648,15 +1648,26 @@ bool X86FastISel::X86SelectCall(const Instruction *I) { MachineInstrBuilder MIB; if (CalleeOp) { // Register-indirect call. - unsigned CallOpc = Subtarget->is64Bit() ? X86::CALL64r : X86::CALL32r; + unsigned CallOpc; + if (Subtarget->isTargetWin64()) + CallOpc = X86::WINCALL64r; + else if (Subtarget->is64Bit()) + CallOpc = X86::CALL64r; + else + CallOpc = X86::CALL32r; MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CallOpc)) .addReg(CalleeOp); } else { // Direct call. assert(GV && "Not a direct call"); - unsigned CallOpc = - Subtarget->is64Bit() ? X86::CALL64pcrel32 : X86::CALLpcrel32; + unsigned CallOpc; + if (Subtarget->isTargetWin64()) + CallOpc = X86::WINCALL64pcrel32; + else if (Subtarget->is64Bit()) + CallOpc = X86::CALL64pcrel32; + else + CallOpc = X86::CALLpcrel32; // See if we need any target-specific flags on the GV operand. unsigned char OpFlags = 0; diff --git a/lib/Target/X86/X86FloatingPoint.cpp b/lib/Target/X86/X86FloatingPoint.cpp index cee4ad7..e6ebf66 100644 --- a/lib/Target/X86/X86FloatingPoint.cpp +++ b/lib/Target/X86/X86FloatingPoint.cpp @@ -8,23 +8,18 @@ //===----------------------------------------------------------------------===// // // This file defines the pass which converts floating point instructions from -// virtual registers into register stack instructions. This pass uses live +// pseudo registers into register stack instructions. This pass uses live // variable information to indicate where the FPn registers are used and their // lifetimes. // -// This pass is hampered by the lack of decent CFG manipulation routines for -// machine code. In particular, this wants to be able to split critical edges -// as necessary, traverse the machine basic block CFG in depth-first order, and -// allow there to be multiple machine basic blocks for each LLVM basicblock -// (needed for critical edge splitting). +// The x87 hardware tracks liveness of the stack registers, so it is necessary +// to implement exact liveness tracking between basic blocks. The CFG edges are +// partitioned into bundles where the same FP registers must be live in +// identical stack positions. Instructions are inserted at the end of each basic +// block to rearrange the live registers to match the outgoing bundle. // -// In particular, this pass currently barfs on critical edges. Because of this, -// it requires the instruction selector to insert FP_REG_KILL instructions on -// the exits of any basic block that has critical edges going from it, or which -// branch to a critical basic block. -// -// FIXME: this is not implemented yet. The stackifier pass only works on local -// basic blocks. +// This approach avoids splitting critical edges at the potential cost of more +// live register shuffling instructions when critical edges are present. // //===----------------------------------------------------------------------===// @@ -32,6 +27,7 @@ #include "X86.h" #include "X86InstrInfo.h" #include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" @@ -54,7 +50,12 @@ STATISTIC(NumFP , "Number of floating point instructions"); namespace { struct FPS : public MachineFunctionPass { static char ID; - FPS() : MachineFunctionPass(&ID) {} + FPS() : MachineFunctionPass(ID) { + // This is really only to keep valgrind quiet. + // The logic in isLive() is too much for it. + memset(Stack, 0, sizeof(Stack)); + memset(RegMap, 0, sizeof(RegMap)); + } virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); @@ -69,11 +70,71 @@ namespace { private: const TargetInstrInfo *TII; // Machine instruction info. + + // Two CFG edges are related if they leave the same block, or enter the same + // block. The transitive closure of an edge under this relation is a + // LiveBundle. It represents a set of CFG edges where the live FP stack + // registers must be allocated identically in the x87 stack. + // + // A LiveBundle is usually all the edges leaving a block, or all the edges + // entering a block, but it can contain more edges if critical edges are + // present. + // + // The set of live FP registers in a LiveBundle is calculated by bundleCFG, + // but the exact mapping of FP registers to stack slots is fixed later. + struct LiveBundle { + // Bit mask of live FP registers. Bit 0 = FP0, bit 1 = FP1, &c. + unsigned Mask; + + // Number of pre-assigned live registers in FixStack. This is 0 when the + // stack order has not yet been fixed. + unsigned FixCount; + + // Assigned stack order for live-in registers. + // FixStack[i] == getStackEntry(i) for all i < FixCount. + unsigned char FixStack[8]; + + LiveBundle(unsigned m = 0) : Mask(m), FixCount(0) {} + + // Have the live registers been assigned a stack order yet? + bool isFixed() const { return !Mask || FixCount; } + }; + + // Numbered LiveBundle structs. LiveBundles[0] is used for all CFG edges + // with no live FP registers. + SmallVector LiveBundles; + + // Map each MBB in the current function to an (ingoing, outgoing) index into + // LiveBundles. Blocks with no FP registers live in or out map to (0, 0) + // and are not actually stored in the map. + DenseMap > BlockBundle; + + // Return a bitmask of FP registers in block's live-in list. + unsigned calcLiveInMask(MachineBasicBlock *MBB) { + unsigned Mask = 0; + for (MachineBasicBlock::livein_iterator I = MBB->livein_begin(), + E = MBB->livein_end(); I != E; ++I) { + unsigned Reg = *I - X86::FP0; + if (Reg < 8) + Mask |= 1 << Reg; + } + return Mask; + } + + // Partition all the CFG edges into LiveBundles. + void bundleCFG(MachineFunction &MF); + MachineBasicBlock *MBB; // Current basic block unsigned Stack[8]; // FP Registers in each stack slot... unsigned RegMap[8]; // Track which stack slot contains each register unsigned StackTop; // The current top of the FP stack. + // Set up our stack model to match the incoming registers to MBB. + void setupBlockStack(); + + // Shuffle live registers to match the expectations of successor blocks. + void finishBlockStack(); + void dumpStack() const { dbgs() << "Stack contents:"; for (unsigned i = 0; i != StackTop; ++i) { @@ -82,27 +143,36 @@ namespace { } dbgs() << "\n"; } - private: - /// isStackEmpty - Return true if the FP stack is empty. - bool isStackEmpty() const { - return StackTop == 0; - } - - // getSlot - Return the stack slot number a particular register number is - // in. + + /// getSlot - Return the stack slot number a particular register number is + /// in. unsigned getSlot(unsigned RegNo) const { assert(RegNo < 8 && "Regno out of range!"); return RegMap[RegNo]; } - // getStackEntry - Return the X86::FP register in register ST(i). + /// isLive - Is RegNo currently live in the stack? + bool isLive(unsigned RegNo) const { + unsigned Slot = getSlot(RegNo); + return Slot < StackTop && Stack[Slot] == RegNo; + } + + /// getScratchReg - Return an FP register that is not currently in use. + unsigned getScratchReg() { + for (int i = 7; i >= 0; --i) + if (!isLive(i)) + return i; + llvm_unreachable("Ran out of scratch FP registers"); + } + + /// getStackEntry - Return the X86::FP register in register ST(i). unsigned getStackEntry(unsigned STi) const { assert(STi < StackTop && "Access past stack top!"); return Stack[StackTop-1-STi]; } - // getSTReg - Return the X86::ST(i) register which contains the specified - // FP register. + /// getSTReg - Return the X86::ST(i) register which contains the specified + /// FP register. unsigned getSTReg(unsigned RegNo) const { return StackTop - 1 - getSlot(RegNo) + llvm::X86::ST0; } @@ -117,10 +187,9 @@ namespace { bool isAtTop(unsigned RegNo) const { return getSlot(RegNo) == StackTop-1; } void moveToTop(unsigned RegNo, MachineBasicBlock::iterator I) { - MachineInstr *MI = I; - DebugLoc dl = MI->getDebugLoc(); + DebugLoc dl = I == MBB->end() ? DebugLoc() : I->getDebugLoc(); if (isAtTop(RegNo)) return; - + unsigned STReg = getSTReg(RegNo); unsigned RegOnTop = getStackEntry(0); @@ -137,24 +206,37 @@ namespace { } void duplicateToTop(unsigned RegNo, unsigned AsReg, MachineInstr *I) { - DebugLoc dl = I->getDebugLoc(); + DebugLoc dl = I == MBB->end() ? DebugLoc() : I->getDebugLoc(); unsigned STReg = getSTReg(RegNo); pushReg(AsReg); // New register on top of stack BuildMI(*MBB, I, dl, TII->get(X86::LD_Frr)).addReg(STReg); } - // popStackAfter - Pop the current value off of the top of the FP stack - // after the specified instruction. + /// popStackAfter - Pop the current value off of the top of the FP stack + /// after the specified instruction. void popStackAfter(MachineBasicBlock::iterator &I); - // freeStackSlotAfter - Free the specified register from the register stack, - // so that it is no longer in a register. If the register is currently at - // the top of the stack, we just pop the current instruction, otherwise we - // store the current top-of-stack into the specified slot, then pop the top - // of stack. + /// freeStackSlotAfter - Free the specified register from the register + /// stack, so that it is no longer in a register. If the register is + /// currently at the top of the stack, we just pop the current instruction, + /// otherwise we store the current top-of-stack into the specified slot, + /// then pop the top of stack. void freeStackSlotAfter(MachineBasicBlock::iterator &I, unsigned Reg); + /// freeStackSlotBefore - Just the pop, no folding. Return the inserted + /// instruction. + MachineBasicBlock::iterator + freeStackSlotBefore(MachineBasicBlock::iterator I, unsigned FPRegNo); + + /// Adjust the live registers to be the set in Mask. + void adjustLiveRegs(unsigned Mask, MachineBasicBlock::iterator I); + + /// Shuffle the top FixCount stack entries susch that FP reg FixStack[0] is + /// st(0), FP reg FixStack[1] is st(1) etc. + void shuffleStackTop(const unsigned char *FixStack, unsigned FixCount, + MachineBasicBlock::iterator I); + bool processBasicBlock(MachineFunction &MF, MachineBasicBlock &MBB); void handleZeroArgFP(MachineBasicBlock::iterator &I); @@ -181,7 +263,6 @@ static unsigned getFPReg(const MachineOperand &MO) { return Reg - X86::FP0; } - /// runOnMachineFunction - Loop over all of the basic blocks, transforming FP /// register references into FP stack references. /// @@ -201,6 +282,10 @@ bool FPS::runOnMachineFunction(MachineFunction &MF) { if (!FPIsUsed) return false; TII = MF.getTarget().getInstrInfo(); + + // Prepare cross-MBB liveness. + bundleCFG(MF); + StackTop = 0; // Process the function in depth first order so that we process at least one @@ -215,16 +300,111 @@ bool FPS::runOnMachineFunction(MachineFunction &MF) { Changed |= processBasicBlock(MF, **I); // Process any unreachable blocks in arbitrary order now. - if (MF.size() == Processed.size()) - return Changed; + if (MF.size() != Processed.size()) + for (MachineFunction::iterator BB = MF.begin(), E = MF.end(); BB != E; ++BB) + if (Processed.insert(BB)) + Changed |= processBasicBlock(MF, *BB); + + BlockBundle.clear(); + LiveBundles.clear(); - for (MachineFunction::iterator BB = MF.begin(), E = MF.end(); BB != E; ++BB) - if (Processed.insert(BB)) - Changed |= processBasicBlock(MF, *BB); - return Changed; } +/// bundleCFG - Scan all the basic blocks to determine consistent live-in and +/// live-out sets for the FP registers. Consistent means that the set of +/// registers live-out from a block is identical to the live-in set of all +/// successors. This is not enforced by the normal live-in lists since +/// registers may be implicitly defined, or not used by all successors. +void FPS::bundleCFG(MachineFunction &MF) { + assert(LiveBundles.empty() && "Stale data in LiveBundles"); + assert(BlockBundle.empty() && "Stale data in BlockBundle"); + SmallPtrSet PropDown, PropUp; + + // LiveBundle[0] is the empty live-in set. + LiveBundles.resize(1); + + // First gather the actual live-in masks for all MBBs. + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) { + MachineBasicBlock *MBB = I; + const unsigned Mask = calcLiveInMask(MBB); + if (!Mask) + continue; + // Ingoing bundle index. + unsigned &Idx = BlockBundle[MBB].first; + // Already assigned an ingoing bundle? + if (Idx) + continue; + // Allocate a new LiveBundle struct for this block's live-ins. + const unsigned BundleIdx = Idx = LiveBundles.size(); + DEBUG(dbgs() << "Creating LB#" << BundleIdx << ": in:BB#" + << MBB->getNumber()); + LiveBundles.push_back(Mask); + LiveBundle &Bundle = LiveBundles.back(); + + // Make sure all predecessors have the same live-out set. + PropUp.insert(MBB); + + // Keep pushing liveness up and down the CFG until convergence. + // Only critical edges cause iteration here, but when they do, multiple + // blocks can be assigned to the same LiveBundle index. + do { + // Assign BundleIdx as liveout from predecessors in PropUp. + for (SmallPtrSet::iterator I = PropUp.begin(), + E = PropUp.end(); I != E; ++I) { + MachineBasicBlock *MBB = *I; + for (MachineBasicBlock::const_pred_iterator LinkI = MBB->pred_begin(), + LinkE = MBB->pred_end(); LinkI != LinkE; ++LinkI) { + MachineBasicBlock *PredMBB = *LinkI; + // PredMBB's liveout bundle should be set to LIIdx. + unsigned &Idx = BlockBundle[PredMBB].second; + if (Idx) { + assert(Idx == BundleIdx && "Inconsistent CFG"); + continue; + } + Idx = BundleIdx; + DEBUG(dbgs() << " out:BB#" << PredMBB->getNumber()); + // Propagate to siblings. + if (PredMBB->succ_size() > 1) + PropDown.insert(PredMBB); + } + } + PropUp.clear(); + + // Assign BundleIdx as livein to successors in PropDown. + for (SmallPtrSet::iterator I = PropDown.begin(), + E = PropDown.end(); I != E; ++I) { + MachineBasicBlock *MBB = *I; + for (MachineBasicBlock::const_succ_iterator LinkI = MBB->succ_begin(), + LinkE = MBB->succ_end(); LinkI != LinkE; ++LinkI) { + MachineBasicBlock *SuccMBB = *LinkI; + // LinkMBB's livein bundle should be set to BundleIdx. + unsigned &Idx = BlockBundle[SuccMBB].first; + if (Idx) { + assert(Idx == BundleIdx && "Inconsistent CFG"); + continue; + } + Idx = BundleIdx; + DEBUG(dbgs() << " in:BB#" << SuccMBB->getNumber()); + // Propagate to siblings. + if (SuccMBB->pred_size() > 1) + PropUp.insert(SuccMBB); + // Also accumulate the bundle liveness mask from the liveins here. + Bundle.Mask |= calcLiveInMask(SuccMBB); + } + } + PropDown.clear(); + } while (!PropUp.empty()); + DEBUG({ + dbgs() << " live:"; + for (unsigned i = 0; i < 8; ++i) + if (Bundle.Mask & (1<getDesc().TSFlags; - + unsigned FPInstClass = Flags & X86II::FPTypeMask; if (MI->isInlineAsm()) FPInstClass = X86II::SpecialFP; @@ -302,10 +484,82 @@ bool FPS::processBasicBlock(MachineFunction &MF, MachineBasicBlock &BB) { Changed = true; } - assert(isStackEmpty() && "Stack not empty at end of basic block?"); + finishBlockStack(); + return Changed; } +/// setupBlockStack - Use the BlockBundle map to set up our model of the stack +/// to match predecessors' live out stack. +void FPS::setupBlockStack() { + DEBUG(dbgs() << "\nSetting up live-ins for BB#" << MBB->getNumber() + << " derived from " << MBB->getName() << ".\n"); + StackTop = 0; + const LiveBundle &Bundle = LiveBundles[BlockBundle.lookup(MBB).first]; + + if (!Bundle.Mask) { + DEBUG(dbgs() << "Block has no FP live-ins.\n"); + return; + } + + // Depth-first iteration should ensure that we always have an assigned stack. + assert(Bundle.isFixed() && "Reached block before any predecessors"); + + // Push the fixed live-in registers. + for (unsigned i = Bundle.FixCount; i > 0; --i) { + MBB->addLiveIn(X86::ST0+i-1); + DEBUG(dbgs() << "Live-in st(" << (i-1) << "): %FP" + << unsigned(Bundle.FixStack[i-1]) << '\n'); + pushReg(Bundle.FixStack[i-1]); + } + + // Kill off unwanted live-ins. This can happen with a critical edge. + // FIXME: We could keep these live registers around as zombies. They may need + // to be revived at the end of a short block. It might save a few instrs. + adjustLiveRegs(calcLiveInMask(MBB), MBB->begin()); + DEBUG(MBB->dump()); +} + +/// finishBlockStack - Revive live-outs that are implicitly defined out of +/// MBB. Shuffle live registers to match the expected fixed stack of any +/// predecessors, and ensure that all predecessors are expecting the same +/// stack. +void FPS::finishBlockStack() { + // The RET handling below takes care of return blocks for us. + if (MBB->succ_empty()) + return; + + DEBUG(dbgs() << "Setting up live-outs for BB#" << MBB->getNumber() + << " derived from " << MBB->getName() << ".\n"); + + unsigned BundleIdx = BlockBundle.lookup(MBB).second; + LiveBundle &Bundle = LiveBundles[BundleIdx]; + + // We may need to kill and define some registers to match successors. + // FIXME: This can probably be combined with the shuffle below. + MachineBasicBlock::iterator Term = MBB->getFirstTerminator(); + adjustLiveRegs(Bundle.Mask, Term); + + if (!Bundle.Mask) { + DEBUG(dbgs() << "No live-outs.\n"); + return; + } + + // Has the stack order been fixed yet? + DEBUG(dbgs() << "LB#" << BundleIdx << ": "); + if (Bundle.isFixed()) { + DEBUG(dbgs() << "Shuffling stack to match.\n"); + shuffleStackTop(Bundle.FixStack, Bundle.FixCount, Term); + } else { + // Not fixed yet, we get to choose. + DEBUG(dbgs() << "Fixing stack order now.\n"); + Bundle.FixCount = StackTop; + for (unsigned i = 0; i < StackTop; ++i) + Bundle.FixStack[i] = getStackEntry(i); + } +} + + //===----------------------------------------------------------------------===// // Efficient Lookup Table Support //===----------------------------------------------------------------------===// @@ -318,7 +572,7 @@ namespace { friend bool operator<(const TableEntry &TE, unsigned V) { return TE.from < V; } - friend bool operator<(unsigned V, const TableEntry &TE) { + friend bool ATTRIBUTE_USED operator<(unsigned V, const TableEntry &TE) { return V < TE.from; } }; @@ -597,6 +851,13 @@ void FPS::freeStackSlotAfter(MachineBasicBlock::iterator &I, unsigned FPRegNo) { // Otherwise, store the top of stack into the dead slot, killing the operand // without having to add in an explicit xchg then pop. // + I = freeStackSlotBefore(++I, FPRegNo); +} + +/// freeStackSlotBefore - Free the specified register without trying any +/// folding. +MachineBasicBlock::iterator +FPS::freeStackSlotBefore(MachineBasicBlock::iterator I, unsigned FPRegNo) { unsigned STReg = getSTReg(FPRegNo); unsigned OldSlot = getSlot(FPRegNo); unsigned TopReg = Stack[StackTop-1]; @@ -604,9 +865,90 @@ void FPS::freeStackSlotAfter(MachineBasicBlock::iterator &I, unsigned FPRegNo) { RegMap[TopReg] = OldSlot; RegMap[FPRegNo] = ~0; Stack[--StackTop] = ~0; - MachineInstr *MI = I; - DebugLoc dl = MI->getDebugLoc(); - I = BuildMI(*MBB, ++I, dl, TII->get(X86::ST_FPrr)).addReg(STReg); + return BuildMI(*MBB, I, DebugLoc(), TII->get(X86::ST_FPrr)).addReg(STReg); +} + +/// adjustLiveRegs - Kill and revive registers such that exactly the FP +/// registers with a bit in Mask are live. +void FPS::adjustLiveRegs(unsigned Mask, MachineBasicBlock::iterator I) { + unsigned Defs = Mask; + unsigned Kills = 0; + for (unsigned i = 0; i < StackTop; ++i) { + unsigned RegNo = Stack[i]; + if (!(Defs & (1 << RegNo))) + // This register is live, but we don't want it. + Kills |= (1 << RegNo); + else + // We don't need to imp-def this live register. + Defs &= ~(1 << RegNo); + } + assert((Kills & Defs) == 0 && "Register needs killing and def'ing?"); + + // Produce implicit-defs for free by using killed registers. + while (Kills && Defs) { + unsigned KReg = CountTrailingZeros_32(Kills); + unsigned DReg = CountTrailingZeros_32(Defs); + DEBUG(dbgs() << "Renaming %FP" << KReg << " as imp %FP" << DReg << "\n"); + std::swap(Stack[getSlot(KReg)], Stack[getSlot(DReg)]); + std::swap(RegMap[KReg], RegMap[DReg]); + Kills &= ~(1 << KReg); + Defs &= ~(1 << DReg); + } + + // Kill registers by popping. + if (Kills && I != MBB->begin()) { + MachineBasicBlock::iterator I2 = llvm::prior(I); + for (;;) { + unsigned KReg = getStackEntry(0); + if (!(Kills & (1 << KReg))) + break; + DEBUG(dbgs() << "Popping %FP" << KReg << "\n"); + popStackAfter(I2); + Kills &= ~(1 << KReg); + } + } + + // Manually kill the rest. + while (Kills) { + unsigned KReg = CountTrailingZeros_32(Kills); + DEBUG(dbgs() << "Killing %FP" << KReg << "\n"); + freeStackSlotBefore(I, KReg); + Kills &= ~(1 << KReg); + } + + // Load zeros for all the imp-defs. + while(Defs) { + unsigned DReg = CountTrailingZeros_32(Defs); + DEBUG(dbgs() << "Defining %FP" << DReg << " as 0\n"); + BuildMI(*MBB, I, DebugLoc(), TII->get(X86::LD_F0)); + pushReg(DReg); + Defs &= ~(1 << DReg); + } + + // Now we should have the correct registers live. + DEBUG(dumpStack()); + assert(StackTop == CountPopulation_32(Mask) && "Live count mismatch"); +} + +/// shuffleStackTop - emit fxch instructions before I to shuffle the top +/// FixCount entries into the order given by FixStack. +/// FIXME: Is there a better algorithm than insertion sort? +void FPS::shuffleStackTop(const unsigned char *FixStack, + unsigned FixCount, + MachineBasicBlock::iterator I) { + // Move items into place, starting from the desired stack bottom. + while (FixCount--) { + // Old register at position FixCount. + unsigned OldReg = getStackEntry(FixCount); + // Desired register at position FixCount. + unsigned Reg = FixStack[FixCount]; + if (Reg == OldReg) + continue; + // (Reg st0) (OldReg st0) = (Reg OldReg st0) + moveToTop(Reg, I); + moveToTop(OldReg, I); + } + DEBUG(dumpStack()); } @@ -660,7 +1002,7 @@ void FPS::handleOneArgFP(MachineBasicBlock::iterator &I) { MI->getOpcode() == X86::ISTT_Fp32m80 || MI->getOpcode() == X86::ISTT_Fp64m80 || MI->getOpcode() == X86::ST_FpP80m)) { - duplicateToTop(Reg, 7 /*temp register*/, I); + duplicateToTop(Reg, getScratchReg(), I); } else { moveToTop(Reg, I); // Move to the top of the stack... } @@ -1013,8 +1355,7 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) { if (!MI->killsRegister(X86::FP0 + Op0)) { // Duplicate Op0 into a temporary on the stack top. - // This actually assumes that FP7 is dead. - duplicateToTop(Op0, 7, I); + duplicateToTop(Op0, getScratchReg(), I); } else { // Op0 is killed, so just swap it into position. moveToTop(Op0, I); @@ -1034,8 +1375,7 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) { ++StackTop; unsigned RegOnTop = getStackEntry(0); // This reg must remain in st(0). if (!MI->killsRegister(X86::FP0 + Op0)) { - // Assume FP6 is not live, use it as a scratch register. - duplicateToTop(Op0, 6, I); + duplicateToTop(Op0, getScratchReg(), I); moveToTop(RegOnTop, I); } else if (getSTReg(Op0) != X86::ST1) { // We have the wrong value at st(1). Shuffle! Untested! @@ -1119,11 +1459,11 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) { case X86::RETI: // If RET has an FP register use operand, pass the first one in ST(0) and // the second one in ST(1). - if (isStackEmpty()) return; // Quick check to see if any are possible. - + // Find the register operands. unsigned FirstFPRegOp = ~0U, SecondFPRegOp = ~0U; - + unsigned LiveMask = 0; + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { MachineOperand &Op = MI->getOperand(i); if (!Op.isReg() || Op.getReg() < X86::FP0 || Op.getReg() > X86::FP6) @@ -1142,12 +1482,18 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) { assert(SecondFPRegOp == ~0U && "More than two fp operands!"); SecondFPRegOp = getFPReg(Op); } + LiveMask |= (1 << getFPReg(Op)); // Remove the operand so that later passes don't see it. MI->RemoveOperand(i); --i, --e; } - + + // We may have been carrying spurious live-ins, so make sure only the returned + // registers are left live. + adjustLiveRegs(LiveMask, MI); + if (!LiveMask) return; // Quick check to see if any are possible. + // There are only four possibilities here: // 1) we are returning a single FP value. In this case, it has to be in // ST(0) already, so just declare success by removing the value from the @@ -1173,7 +1519,7 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) { // Duplicate the TOS so that we return it twice. Just pick some other FPx // register to hold it. - unsigned NewReg = (FirstFPRegOp+1)%7; + unsigned NewReg = getScratchReg(); duplicateToTop(FirstFPRegOp, NewReg, MI); FirstFPRegOp = NewReg; } @@ -1197,7 +1543,14 @@ void FPS::handleSpecialFP(MachineBasicBlock::iterator &I) { } I = MBB->erase(I); // Remove the pseudo instruction - --I; + + // We want to leave I pointing to the previous instruction, but what if we + // just erased the first instruction? + if (I == MBB->begin()) { + DEBUG(dbgs() << "Inserting dummy KILL\n"); + I = BuildMI(*MBB, I, DebugLoc(), TII->get(TargetOpcode::KILL)); + } else + --I; } // Translate a COPY instruction to a pseudo-op that handleSpecialFP understands. diff --git a/lib/Target/X86/X86FloatingPointRegKill.cpp b/lib/Target/X86/X86FloatingPointRegKill.cpp deleted file mode 100644 index 2c98b96..0000000 --- a/lib/Target/X86/X86FloatingPointRegKill.cpp +++ /dev/null @@ -1,153 +0,0 @@ -//===-- X86FloatingPoint.cpp - FP_REG_KILL inserter -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the pass which inserts FP_REG_KILL instructions. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "x86-codegen" -#include "X86.h" -#include "X86InstrInfo.h" -#include "llvm/Instructions.h" -#include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/CodeGen/Passes.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/CFG.h" -#include "llvm/ADT/Statistic.h" -using namespace llvm; - -STATISTIC(NumFPKill, "Number of FP_REG_KILL instructions added"); - -namespace { - struct FPRegKiller : public MachineFunctionPass { - static char ID; - FPRegKiller() : MachineFunctionPass(&ID) {} - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesCFG(); - AU.addPreservedID(MachineLoopInfoID); - AU.addPreservedID(MachineDominatorsID); - MachineFunctionPass::getAnalysisUsage(AU); - } - - virtual bool runOnMachineFunction(MachineFunction &MF); - - virtual const char *getPassName() const { - return "X86 FP_REG_KILL inserter"; - } - }; - char FPRegKiller::ID = 0; -} - -FunctionPass *llvm::createX87FPRegKillInserterPass() { - return new FPRegKiller(); -} - -/// isFPStackVReg - Return true if the specified vreg is from a fp stack -/// register class. -static bool isFPStackVReg(unsigned RegNo, const MachineRegisterInfo &MRI) { - if (!TargetRegisterInfo::isVirtualRegister(RegNo)) - return false; - - switch (MRI.getRegClass(RegNo)->getID()) { - default: return false; - case X86::RFP32RegClassID: - case X86::RFP64RegClassID: - case X86::RFP80RegClassID: - return true; - } -} - - -/// ContainsFPStackCode - Return true if the specific MBB has floating point -/// stack code, and thus needs an FP_REG_KILL. -static bool ContainsFPStackCode(MachineBasicBlock *MBB, - const MachineRegisterInfo &MRI) { - // Scan the block, looking for instructions that define or use fp stack vregs. - for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); - I != E; ++I) { - for (unsigned op = 0, e = I->getNumOperands(); op != e; ++op) { - if (!I->getOperand(op).isReg()) - continue; - if (unsigned Reg = I->getOperand(op).getReg()) - if (isFPStackVReg(Reg, MRI)) - return true; - } - } - - // Check PHI nodes in successor blocks. These PHI's will be lowered to have - // a copy of the input value in this block, which is a definition of the - // value. - for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(), - E = MBB->succ_end(); SI != E; ++ SI) { - MachineBasicBlock *SuccBB = *SI; - for (MachineBasicBlock::iterator I = SuccBB->begin(), E = SuccBB->end(); - I != E; ++I) { - // All PHI nodes are at the top of the block. - if (!I->isPHI()) break; - - if (isFPStackVReg(I->getOperand(0).getReg(), MRI)) - return true; - } - } - - return false; -} - -bool FPRegKiller::runOnMachineFunction(MachineFunction &MF) { - // If we are emitting FP stack code, scan the basic block to determine if this - // block defines or uses any FP values. If so, put an FP_REG_KILL instruction - // before the terminator of the block. - - // Note that FP stack instructions are used in all modes for long double, - // so we always need to do this check. - // Also note that it's possible for an FP stack register to be live across - // an instruction that produces multiple basic blocks (SSE CMOV) so we - // must check all the generated basic blocks. - - // Scan all of the machine instructions in these MBBs, checking for FP - // stores. (RFP32 and RFP64 will not exist in SSE mode, but RFP80 might.) - - // Fast-path: If nothing is using the x87 registers, we don't need to do - // any scanning. - const MachineRegisterInfo &MRI = MF.getRegInfo(); - if (MRI.getRegClassVirtRegs(X86::RFP80RegisterClass).empty() && - MRI.getRegClassVirtRegs(X86::RFP64RegisterClass).empty() && - MRI.getRegClassVirtRegs(X86::RFP32RegisterClass).empty()) - return false; - - bool Changed = false; - MachineFunction::iterator MBBI = MF.begin(); - MachineFunction::iterator EndMBB = MF.end(); - for (; MBBI != EndMBB; ++MBBI) { - MachineBasicBlock *MBB = MBBI; - - // If this block returns, ignore it. We don't want to insert an FP_REG_KILL - // before the return. - if (!MBB->empty()) { - MachineBasicBlock::iterator EndI = MBB->end(); - --EndI; - if (EndI->getDesc().isReturn()) - continue; - } - - // If we find any FP stack code, emit the FP_REG_KILL instruction. - if (ContainsFPStackCode(MBB, MRI)) { - BuildMI(*MBB, MBBI->getFirstTerminator(), DebugLoc(), - MF.getTarget().getInstrInfo()->get(X86::FP_REG_KILL)); - ++NumFPKill; - Changed = true; - } - } - - return Changed; -} diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp index 72f2bc1..c523441 100644 --- a/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -171,6 +171,17 @@ namespace { virtual void PreprocessISelDAG(); + inline bool immSext8(SDNode *N) const { + return isInt<8>(cast(N)->getSExtValue()); + } + + // i64immSExt32 predicate - True if the 64-bit immediate fits in a 32-bit + // sign extended field. + inline bool i64immSExt32(SDNode *N) const { + uint64_t v = cast(N)->getZExtValue(); + return (int64_t)v == (int32_t)v; + } + // Include the pieces autogenerated from the target description. #include "X86GenDAGISel.inc" @@ -1312,13 +1323,6 @@ SDNode *X86DAGToDAGISel::getGlobalBaseReg() { return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode(); } -static SDNode *FindCallStartFromCall(SDNode *Node) { - if (Node->getOpcode() == ISD::CALLSEQ_START) return Node; - assert(Node->getOperand(0).getValueType() == MVT::Other && - "Node doesn't have a token chain argument!"); - return FindCallStartFromCall(Node->getOperand(0).getNode()); -} - SDNode *X86DAGToDAGISel::SelectAtomic64(SDNode *Node, unsigned Opc) { SDValue Chain = Node->getOperand(0); SDValue In1 = Node->getOperand(1); @@ -1403,7 +1407,7 @@ SDNode *X86DAGToDAGISel::SelectAtomicLoadAdd(SDNode *Node, EVT NVT) { Opc = X86::LOCK_DEC16m; else if (isSub) { if (isCN) { - if (Predicate_immSext8(Val.getNode())) + if (immSext8(Val.getNode())) Opc = X86::LOCK_SUB16mi8; else Opc = X86::LOCK_SUB16mi; @@ -1411,7 +1415,7 @@ SDNode *X86DAGToDAGISel::SelectAtomicLoadAdd(SDNode *Node, EVT NVT) { Opc = X86::LOCK_SUB16mr; } else { if (isCN) { - if (Predicate_immSext8(Val.getNode())) + if (immSext8(Val.getNode())) Opc = X86::LOCK_ADD16mi8; else Opc = X86::LOCK_ADD16mi; @@ -1426,7 +1430,7 @@ SDNode *X86DAGToDAGISel::SelectAtomicLoadAdd(SDNode *Node, EVT NVT) { Opc = X86::LOCK_DEC32m; else if (isSub) { if (isCN) { - if (Predicate_immSext8(Val.getNode())) + if (immSext8(Val.getNode())) Opc = X86::LOCK_SUB32mi8; else Opc = X86::LOCK_SUB32mi; @@ -1434,7 +1438,7 @@ SDNode *X86DAGToDAGISel::SelectAtomicLoadAdd(SDNode *Node, EVT NVT) { Opc = X86::LOCK_SUB32mr; } else { if (isCN) { - if (Predicate_immSext8(Val.getNode())) + if (immSext8(Val.getNode())) Opc = X86::LOCK_ADD32mi8; else Opc = X86::LOCK_ADD32mi; @@ -1450,17 +1454,17 @@ SDNode *X86DAGToDAGISel::SelectAtomicLoadAdd(SDNode *Node, EVT NVT) { else if (isSub) { Opc = X86::LOCK_SUB64mr; if (isCN) { - if (Predicate_immSext8(Val.getNode())) + if (immSext8(Val.getNode())) Opc = X86::LOCK_SUB64mi8; - else if (Predicate_i64immSExt32(Val.getNode())) + else if (i64immSExt32(Val.getNode())) Opc = X86::LOCK_SUB64mi32; } } else { Opc = X86::LOCK_ADD64mr; if (isCN) { - if (Predicate_immSext8(Val.getNode())) + if (immSext8(Val.getNode())) Opc = X86::LOCK_ADD64mi8; - else if (Predicate_i64immSExt32(Val.getNode())) + else if (i64immSExt32(Val.getNode())) Opc = X86::LOCK_ADD64mi32; } } @@ -1841,7 +1845,8 @@ SDNode *X86DAGToDAGISel::Select(SDNode *Node) { // Look for (X86cmp (and $op, $imm), 0) and see if we can convert it to // use a smaller encoding. - if (N0.getOpcode() == ISD::TRUNCATE && N0.hasOneUse()) + if (N0.getOpcode() == ISD::TRUNCATE && N0.hasOneUse() && + HasNoSignedComparisonUses(Node)) // Look past the truncate if CMP is the only use of it. N0 = N0.getOperand(0); if (N0.getNode()->getOpcode() == ISD::AND && N0.getNode()->hasOneUse() && diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index b3c4886..95dbb61 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -16,6 +16,7 @@ #include "X86.h" #include "X86InstrBuilder.h" #include "X86ISelLowering.h" +#include "X86ShuffleDecode.h" #include "X86TargetMachine.h" #include "X86TargetObjectFile.h" #include "llvm/CallingConv.h" @@ -343,8 +344,9 @@ X86TargetLowering::X86TargetLowering(X86TargetMachine &TM) if (Subtarget->hasSSE1()) setOperationAction(ISD::PREFETCH , MVT::Other, Legal); - if (!Subtarget->hasSSE2()) - setOperationAction(ISD::MEMBARRIER , MVT::Other, Expand); + // We may not have a libcall for MEMBARRIER so we should lower this. + setOperationAction(ISD::MEMBARRIER , MVT::Other, Custom); + // On X86 and X86-64, atomic operations are lowered to locked instructions. // Locked instructions, in turn, have implicit fence semantics (all memory // operations are flushed before issuing the locked instruction, and they @@ -837,6 +839,10 @@ X86TargetLowering::X86TargetLowering(X86TargetMachine &TM) // FIXME: Do we need to handle scalar-to-vector here? setOperationAction(ISD::MUL, MVT::v4i32, Legal); + // Can turn SHL into an integer multiply. + setOperationAction(ISD::SHL, MVT::v4i32, Custom); + setOperationAction(ISD::SHL, MVT::v16i8, Custom); + // i8 and i16 vectors are custom , because the source register and source // source memory operand types are not the same width. f32 vectors are // custom since the immediate controlling the insert encodes additional @@ -866,6 +872,7 @@ X86TargetLowering::X86TargetLowering(X86TargetMachine &TM) addRegisterClass(MVT::v4f64, X86::VR256RegisterClass); addRegisterClass(MVT::v8i32, X86::VR256RegisterClass); addRegisterClass(MVT::v4i64, X86::VR256RegisterClass); + addRegisterClass(MVT::v32i8, X86::VR256RegisterClass); setOperationAction(ISD::LOAD, MVT::v8f32, Legal); setOperationAction(ISD::LOAD, MVT::v8i32, Legal); @@ -877,7 +884,7 @@ X86TargetLowering::X86TargetLowering(X86TargetMachine &TM) setOperationAction(ISD::FDIV, MVT::v8f32, Legal); setOperationAction(ISD::FSQRT, MVT::v8f32, Legal); setOperationAction(ISD::FNEG, MVT::v8f32, Custom); - //setOperationAction(ISD::BUILD_VECTOR, MVT::v8f32, Custom); + setOperationAction(ISD::BUILD_VECTOR, MVT::v8f32, Custom); //setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v8f32, Custom); //setOperationAction(ISD::EXTRACT_VECTOR_ELT, MVT::v8f32, Custom); //setOperationAction(ISD::SELECT, MVT::v8f32, Custom); @@ -1189,6 +1196,50 @@ unsigned X86TargetLowering::getFunctionAlignment(const Function *F) const { return F->hasFnAttr(Attribute::OptimizeForSize) ? 0 : 4; } +std::pair +X86TargetLowering::findRepresentativeClass(EVT VT) const{ + const TargetRegisterClass *RRC = 0; + uint8_t Cost = 1; + switch (VT.getSimpleVT().SimpleTy) { + default: + return TargetLowering::findRepresentativeClass(VT); + case MVT::i8: case MVT::i16: case MVT::i32: case MVT::i64: + RRC = (Subtarget->is64Bit() + ? X86::GR64RegisterClass : X86::GR32RegisterClass); + break; + case MVT::v8i8: case MVT::v4i16: + case MVT::v2i32: case MVT::v1i64: + RRC = X86::VR64RegisterClass; + break; + case MVT::f32: case MVT::f64: + case MVT::v16i8: case MVT::v8i16: case MVT::v4i32: case MVT::v2i64: + case MVT::v4f32: case MVT::v2f64: + case MVT::v32i8: case MVT::v8i32: case MVT::v4i64: case MVT::v8f32: + case MVT::v4f64: + RRC = X86::VR128RegisterClass; + break; + } + return std::make_pair(RRC, Cost); +} + +unsigned +X86TargetLowering::getRegPressureLimit(const TargetRegisterClass *RC, + MachineFunction &MF) const { + unsigned FPDiff = RegInfo->hasFP(MF) ? 1 : 0; + switch (RC->getID()) { + default: + return 0; + case X86::GR32RegClassID: + return 4 - FPDiff; + case X86::GR64RegClassID: + return 8 - FPDiff; + case X86::VR128RegClassID: + return Subtarget->is64Bit() ? 10 : 4; + case X86::VR64RegClassID: + return 4; + } +} + bool X86TargetLowering::getStackCookieLocation(unsigned &AddressSpace, unsigned &Offset) const { if (!Subtarget->isTargetLinux()) @@ -1259,6 +1310,19 @@ X86TargetLowering::LowerReturn(SDValue Chain, CCValAssign &VA = RVLocs[i]; assert(VA.isRegLoc() && "Can only return in registers!"); SDValue ValToCopy = OutVals[i]; + EVT ValVT = ValToCopy.getValueType(); + + // If this is x86-64, and we disabled SSE, we can't return FP values + if ((ValVT == MVT::f32 || ValVT == MVT::f64) && + (Subtarget->is64Bit() && !Subtarget->hasSSE1())) { + report_fatal_error("SSE register return with SSE disabled"); + } + // Likewise we can't return F64 values with SSE1 only. gcc does so, but + // llvm-gcc has never done it right and no one has noticed, so this + // should be OK for now. + if (ValVT == MVT::f64 && + (Subtarget->is64Bit() && !Subtarget->hasSSE2())) + report_fatal_error("SSE2 register return with SSE2 disabled"); // Returns in ST0/ST1 are handled specially: these are pushed as operands to // the RET instruction and handled by the FP Stackifier. @@ -1276,14 +1340,20 @@ X86TargetLowering::LowerReturn(SDValue Chain, // 64-bit vector (MMX) values are returned in XMM0 / XMM1 except for v1i64 // which is returned in RAX / RDX. if (Subtarget->is64Bit()) { - EVT ValVT = ValToCopy.getValueType(); if (ValVT.isVector() && ValVT.getSizeInBits() == 64) { ValToCopy = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i64, ValToCopy); - if (VA.getLocReg() == X86::XMM0 || VA.getLocReg() == X86::XMM1) - ValToCopy = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, MVT::v2i64, ValToCopy); + if (VA.getLocReg() == X86::XMM0 || VA.getLocReg() == X86::XMM1) { + ValToCopy = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, MVT::v2i64, + ValToCopy); + + // If we don't have SSE2 available, convert to v4f32 so the generated + // register is legal. + if (!Subtarget->hasSSE2()) + ValToCopy = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::v4f32,ValToCopy); + } } } - + Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), ValToCopy, Flag); Flag = Chain.getValue(1); } @@ -1570,6 +1640,8 @@ X86TargetLowering::LowerFormalArguments(SDValue Chain, RC = X86::FR32RegisterClass; else if (RegVT == MVT::f64) RC = X86::FR64RegisterClass; + else if (RegVT.isVector() && RegVT.getSizeInBits() == 256) + RC = X86::VR256RegisterClass; else if (RegVT.isVector() && RegVT.getSizeInBits() == 128) RC = X86::VR128RegisterClass; else if (RegVT.isVector() && RegVT.getSizeInBits() == 64) @@ -1937,6 +2009,19 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee, if (VA.isRegLoc()) { RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); + if (isVarArg && Subtarget->isTargetWin64()) { + // Win64 ABI requires argument XMM reg to be copied to the corresponding + // shadow reg if callee is a varargs function. + unsigned ShadowReg = 0; + switch (VA.getLocReg()) { + case X86::XMM0: ShadowReg = X86::RCX; break; + case X86::XMM1: ShadowReg = X86::RDX; break; + case X86::XMM2: ShadowReg = X86::R8; break; + case X86::XMM3: ShadowReg = X86::R9; break; + } + if (ShadowReg) + RegsToPass.push_back(std::make_pair(ShadowReg, Arg)); + } } else if (!IsSibcall && (!isTailCall || isByVal)) { assert(VA.isMemLoc()); if (StackPtr.getNode() == 0) @@ -1990,7 +2075,7 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee, } } - if (Is64Bit && isVarArg) { + if (Is64Bit && isVarArg && !Subtarget->isTargetWin64()) { // From AMD64 ABI document: // For calls that may call functions that use varargs or stdargs // (prototype-less calls or calls to functions containing ellipsis (...) in @@ -1999,7 +2084,6 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee, // the number of registers, but must be an ubound on the number of SSE // registers used and is in the range 0 - 8 inclusive. - // FIXME: Verify this on Win64 // Count the number of XMM registers allocated. static const unsigned XMMArgRegs[] = { X86::XMM0, X86::XMM1, X86::XMM2, X86::XMM3, @@ -2165,8 +2249,8 @@ X86TargetLowering::LowerCall(SDValue Chain, SDValue Callee, if (!isTailCall && Subtarget->isPICStyleGOT()) Ops.push_back(DAG.getRegister(X86::EBX, getPointerTy())); - // Add an implicit use of AL for x86 vararg functions. - if (Is64Bit && isVarArg) + // Add an implicit use of AL for non-Windows x86 64-bit vararg functions. + if (Is64Bit && isVarArg && !Subtarget->isTargetWin64()) Ops.push_back(DAG.getRegister(X86::AL, MVT::i8)); if (InFlag.getNode()) @@ -2356,8 +2440,8 @@ X86TargetLowering::IsEligibleForTailCallOptimization(SDValue Callee, if (RegInfo->needsStackRealignment(MF)) return false; - // Do not sibcall optimize vararg calls unless the call site is not passing any - // arguments. + // Do not sibcall optimize vararg calls unless the call site is not passing + // any arguments. if (isVarArg && !Outs.empty()) return false; @@ -2493,6 +2577,112 @@ X86TargetLowering::createFastISel(FunctionLoweringInfo &funcInfo) const { // Other Lowering Hooks //===----------------------------------------------------------------------===// +static bool MayFoldLoad(SDValue Op) { + return Op.hasOneUse() && ISD::isNormalLoad(Op.getNode()); +} + +static bool MayFoldIntoStore(SDValue Op) { + return Op.hasOneUse() && ISD::isNormalStore(*Op.getNode()->use_begin()); +} + +static bool isTargetShuffle(unsigned Opcode) { + switch(Opcode) { + default: return false; + case X86ISD::PSHUFD: + case X86ISD::PSHUFHW: + case X86ISD::PSHUFLW: + case X86ISD::SHUFPD: + case X86ISD::SHUFPS: + case X86ISD::MOVLHPS: + case X86ISD::MOVLHPD: + case X86ISD::MOVHLPS: + case X86ISD::MOVLPS: + case X86ISD::MOVLPD: + case X86ISD::MOVSHDUP: + case X86ISD::MOVSLDUP: + case X86ISD::MOVSS: + case X86ISD::MOVSD: + case X86ISD::UNPCKLPS: + case X86ISD::UNPCKLPD: + case X86ISD::PUNPCKLWD: + case X86ISD::PUNPCKLBW: + case X86ISD::PUNPCKLDQ: + case X86ISD::PUNPCKLQDQ: + case X86ISD::UNPCKHPS: + case X86ISD::UNPCKHPD: + case X86ISD::PUNPCKHWD: + case X86ISD::PUNPCKHBW: + case X86ISD::PUNPCKHDQ: + case X86ISD::PUNPCKHQDQ: + return true; + } + return false; +} + +static SDValue getTargetShuffleNode(unsigned Opc, DebugLoc dl, EVT VT, + SDValue V1, SelectionDAG &DAG) { + switch(Opc) { + default: llvm_unreachable("Unknown x86 shuffle node"); + case X86ISD::MOVSHDUP: + case X86ISD::MOVSLDUP: + return DAG.getNode(Opc, dl, VT, V1); + } + + return SDValue(); +} + +static SDValue getTargetShuffleNode(unsigned Opc, DebugLoc dl, EVT VT, + SDValue V1, unsigned TargetMask, SelectionDAG &DAG) { + switch(Opc) { + default: llvm_unreachable("Unknown x86 shuffle node"); + case X86ISD::PSHUFD: + case X86ISD::PSHUFHW: + case X86ISD::PSHUFLW: + return DAG.getNode(Opc, dl, VT, V1, DAG.getConstant(TargetMask, MVT::i8)); + } + + return SDValue(); +} + +static SDValue getTargetShuffleNode(unsigned Opc, DebugLoc dl, EVT VT, + SDValue V1, SDValue V2, unsigned TargetMask, SelectionDAG &DAG) { + switch(Opc) { + default: llvm_unreachable("Unknown x86 shuffle node"); + case X86ISD::SHUFPD: + case X86ISD::SHUFPS: + return DAG.getNode(Opc, dl, VT, V1, V2, + DAG.getConstant(TargetMask, MVT::i8)); + } + return SDValue(); +} + +static SDValue getTargetShuffleNode(unsigned Opc, DebugLoc dl, EVT VT, + SDValue V1, SDValue V2, SelectionDAG &DAG) { + switch(Opc) { + default: llvm_unreachable("Unknown x86 shuffle node"); + case X86ISD::MOVLHPS: + case X86ISD::MOVLHPD: + case X86ISD::MOVHLPS: + case X86ISD::MOVLPS: + case X86ISD::MOVLPD: + case X86ISD::MOVSS: + case X86ISD::MOVSD: + case X86ISD::UNPCKLPS: + case X86ISD::UNPCKLPD: + case X86ISD::PUNPCKLWD: + case X86ISD::PUNPCKLBW: + case X86ISD::PUNPCKLDQ: + case X86ISD::PUNPCKLQDQ: + case X86ISD::UNPCKHPS: + case X86ISD::UNPCKHPD: + case X86ISD::PUNPCKHWD: + case X86ISD::PUNPCKHBW: + case X86ISD::PUNPCKHDQ: + case X86ISD::PUNPCKHQDQ: + return DAG.getNode(Opc, dl, VT, V1, V2); + } + return SDValue(); +} SDValue X86TargetLowering::getReturnAddressFrameIndex(SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); @@ -3347,18 +3537,27 @@ static SDValue getZeroVector(EVT VT, bool HasSSE2, SelectionDAG &DAG, DebugLoc dl) { assert(VT.isVector() && "Expected a vector type"); - // Always build zero vectors as <4 x i32> or <2 x i32> bitcasted to their dest - // type. This ensures they get CSE'd. + // Always build zero vectors as <4 x i32> or <2 x i32> bitcasted + // to their dest type. This ensures they get CSE'd. SDValue Vec; if (VT.getSizeInBits() == 64) { // MMX SDValue Cst = DAG.getTargetConstant(0, MVT::i32); Vec = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v2i32, Cst, Cst); - } else if (HasSSE2) { // SSE2 - SDValue Cst = DAG.getTargetConstant(0, MVT::i32); - Vec = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v4i32, Cst, Cst, Cst, Cst); - } else { // SSE1 + } else if (VT.getSizeInBits() == 128) { + if (HasSSE2) { // SSE2 + SDValue Cst = DAG.getTargetConstant(0, MVT::i32); + Vec = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v4i32, Cst, Cst, Cst, Cst); + } else { // SSE1 + SDValue Cst = DAG.getTargetConstantFP(+0.0, MVT::f32); + Vec = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v4f32, Cst, Cst, Cst, Cst); + } + } else if (VT.getSizeInBits() == 256) { // AVX + // 256-bit logic and arithmetic instructions in AVX are + // all floating-point, no support for integer ops. Default + // to emitting fp zeroed vectors then. SDValue Cst = DAG.getTargetConstantFP(+0.0, MVT::f32); - Vec = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v4f32, Cst, Cst, Cst, Cst); + SDValue Ops[] = { Cst, Cst, Cst, Cst, Cst, Cst, Cst, Cst }; + Vec = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v8f32, Ops, 8); } return DAG.getNode(ISD::BIT_CONVERT, dl, VT, Vec); } @@ -3372,9 +3571,9 @@ static SDValue getOnesVector(EVT VT, SelectionDAG &DAG, DebugLoc dl) { // type. This ensures they get CSE'd. SDValue Cst = DAG.getTargetConstant(~0U, MVT::i32); SDValue Vec; - if (VT.getSizeInBits() == 64) // MMX + if (VT.getSizeInBits() == 64) // MMX Vec = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v2i32, Cst, Cst); - else // SSE + else // SSE Vec = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v4i32, Cst, Cst, Cst, Cst); return DAG.getNode(ISD::BIT_CONVERT, dl, VT, Vec); } @@ -3439,9 +3638,8 @@ static SDValue getUnpackh(SelectionDAG &DAG, DebugLoc dl, EVT VT, SDValue V1, return DAG.getVectorShuffle(VT, dl, V1, V2, &Mask[0]); } -/// PromoteSplat - Promote a splat of v4f32, v8i16 or v16i8 to v4i32. -static SDValue PromoteSplat(ShuffleVectorSDNode *SV, SelectionDAG &DAG, - bool HasSSE2) { +/// PromoteSplat - Promote a splat of v4i32, v8i16 or v16i8 to v4f32. +static SDValue PromoteSplat(ShuffleVectorSDNode *SV, SelectionDAG &DAG) { if (SV->getValueType(0).getVectorNumElements() <= 4) return SDValue(SV, 0); @@ -3488,68 +3686,253 @@ static SDValue getShuffleVectorZeroOrUndef(SDValue V2, unsigned Idx, return DAG.getVectorShuffle(VT, V2.getDebugLoc(), V1, V2, &MaskVec[0]); } -/// getNumOfConsecutiveZeros - Return the number of elements in a result of -/// a shuffle that is zero. -static -unsigned getNumOfConsecutiveZeros(ShuffleVectorSDNode *SVOp, int NumElems, - bool Low, SelectionDAG &DAG) { - unsigned NumZeros = 0; - for (int i = 0; i < NumElems; ++i) { - unsigned Index = Low ? i : NumElems-i-1; - int Idx = SVOp->getMaskElt(Index); - if (Idx < 0) { - ++NumZeros; - continue; - } - SDValue Elt = DAG.getShuffleScalarElt(SVOp, Index); - if (Elt.getNode() && X86::isZeroNode(Elt)) - ++NumZeros; - else +/// getShuffleScalarElt - Returns the scalar element that will make up the ith +/// element of the result of the vector shuffle. +SDValue getShuffleScalarElt(SDNode *N, int Index, SelectionDAG &DAG, + unsigned Depth) { + if (Depth == 6) + return SDValue(); // Limit search depth. + + SDValue V = SDValue(N, 0); + EVT VT = V.getValueType(); + unsigned Opcode = V.getOpcode(); + + // Recurse into ISD::VECTOR_SHUFFLE node to find scalars. + if (const ShuffleVectorSDNode *SV = dyn_cast(N)) { + Index = SV->getMaskElt(Index); + + if (Index < 0) + return DAG.getUNDEF(VT.getVectorElementType()); + + int NumElems = VT.getVectorNumElements(); + SDValue NewV = (Index < NumElems) ? SV->getOperand(0) : SV->getOperand(1); + return getShuffleScalarElt(NewV.getNode(), Index % NumElems, DAG, Depth+1); + } + + // Recurse into target specific vector shuffles to find scalars. + if (isTargetShuffle(Opcode)) { + int NumElems = VT.getVectorNumElements(); + SmallVector ShuffleMask; + SDValue ImmN; + + switch(Opcode) { + case X86ISD::SHUFPS: + case X86ISD::SHUFPD: + ImmN = N->getOperand(N->getNumOperands()-1); + DecodeSHUFPSMask(NumElems, + cast(ImmN)->getZExtValue(), + ShuffleMask); + break; + case X86ISD::PUNPCKHBW: + case X86ISD::PUNPCKHWD: + case X86ISD::PUNPCKHDQ: + case X86ISD::PUNPCKHQDQ: + DecodePUNPCKHMask(NumElems, ShuffleMask); break; + case X86ISD::UNPCKHPS: + case X86ISD::UNPCKHPD: + DecodeUNPCKHPMask(NumElems, ShuffleMask); + break; + case X86ISD::PUNPCKLBW: + case X86ISD::PUNPCKLWD: + case X86ISD::PUNPCKLDQ: + case X86ISD::PUNPCKLQDQ: + DecodePUNPCKLMask(NumElems, ShuffleMask); + break; + case X86ISD::UNPCKLPS: + case X86ISD::UNPCKLPD: + DecodeUNPCKLPMask(NumElems, ShuffleMask); + break; + case X86ISD::MOVHLPS: + DecodeMOVHLPSMask(NumElems, ShuffleMask); + break; + case X86ISD::MOVLHPS: + DecodeMOVLHPSMask(NumElems, ShuffleMask); + break; + case X86ISD::PSHUFD: + ImmN = N->getOperand(N->getNumOperands()-1); + DecodePSHUFMask(NumElems, + cast(ImmN)->getZExtValue(), + ShuffleMask); + break; + case X86ISD::PSHUFHW: + ImmN = N->getOperand(N->getNumOperands()-1); + DecodePSHUFHWMask(cast(ImmN)->getZExtValue(), + ShuffleMask); + break; + case X86ISD::PSHUFLW: + ImmN = N->getOperand(N->getNumOperands()-1); + DecodePSHUFLWMask(cast(ImmN)->getZExtValue(), + ShuffleMask); + break; + case X86ISD::MOVSS: + case X86ISD::MOVSD: { + // The index 0 always comes from the first element of the second source, + // this is why MOVSS and MOVSD are used in the first place. The other + // elements come from the other positions of the first source vector. + unsigned OpNum = (Index == 0) ? 1 : 0; + return getShuffleScalarElt(V.getOperand(OpNum).getNode(), Index, DAG, + Depth+1); + } + default: + assert("not implemented for target shuffle node"); + return SDValue(); + } + + Index = ShuffleMask[Index]; + if (Index < 0) + return DAG.getUNDEF(VT.getVectorElementType()); + + SDValue NewV = (Index < NumElems) ? N->getOperand(0) : N->getOperand(1); + return getShuffleScalarElt(NewV.getNode(), Index % NumElems, DAG, + Depth+1); } - return NumZeros; -} -/// isVectorShift - Returns true if the shuffle can be implemented as a -/// logical left or right shift of a vector. -/// FIXME: split into pslldqi, psrldqi, palignr variants. -static bool isVectorShift(ShuffleVectorSDNode *SVOp, SelectionDAG &DAG, - bool &isLeft, SDValue &ShVal, unsigned &ShAmt) { - unsigned NumElems = SVOp->getValueType(0).getVectorNumElements(); + // Actual nodes that may contain scalar elements + if (Opcode == ISD::BIT_CONVERT) { + V = V.getOperand(0); + EVT SrcVT = V.getValueType(); + unsigned NumElems = VT.getVectorNumElements(); - isLeft = true; - unsigned NumZeros = getNumOfConsecutiveZeros(SVOp, NumElems, true, DAG); - if (!NumZeros) { - isLeft = false; - NumZeros = getNumOfConsecutiveZeros(SVOp, NumElems, false, DAG); - if (!NumZeros) - return false; + if (!SrcVT.isVector() || SrcVT.getVectorNumElements() != NumElems) + return SDValue(); + } + + if (V.getOpcode() == ISD::SCALAR_TO_VECTOR) + return (Index == 0) ? V.getOperand(0) + : DAG.getUNDEF(VT.getVectorElementType()); + + if (V.getOpcode() == ISD::BUILD_VECTOR) + return V.getOperand(Index); + + return SDValue(); +} + +/// getNumOfConsecutiveZeros - Return the number of elements of a vector +/// shuffle operation which come from a consecutively from a zero. The +/// search can start in two diferent directions, from left or right. +static +unsigned getNumOfConsecutiveZeros(SDNode *N, int NumElems, + bool ZerosFromLeft, SelectionDAG &DAG) { + int i = 0; + + while (i < NumElems) { + unsigned Index = ZerosFromLeft ? i : NumElems-i-1; + SDValue Elt = getShuffleScalarElt(N, Index, DAG, 0); + if (!(Elt.getNode() && + (Elt.getOpcode() == ISD::UNDEF || X86::isZeroNode(Elt)))) + break; + ++i; } + + return i; +} + +/// isShuffleMaskConsecutive - Check if the shuffle mask indicies from MaskI to +/// MaskE correspond consecutively to elements from one of the vector operands, +/// starting from its index OpIdx. Also tell OpNum which source vector operand. +static +bool isShuffleMaskConsecutive(ShuffleVectorSDNode *SVOp, int MaskI, int MaskE, + int OpIdx, int NumElems, unsigned &OpNum) { bool SeenV1 = false; bool SeenV2 = false; - for (unsigned i = NumZeros; i < NumElems; ++i) { - unsigned Val = isLeft ? (i - NumZeros) : i; - int Idx_ = SVOp->getMaskElt(isLeft ? i : (i - NumZeros)); - if (Idx_ < 0) + + for (int i = MaskI; i <= MaskE; ++i, ++OpIdx) { + int Idx = SVOp->getMaskElt(i); + // Ignore undef indicies + if (Idx < 0) continue; - unsigned Idx = (unsigned) Idx_; + if (Idx < NumElems) SeenV1 = true; - else { - Idx -= NumElems; + else SeenV2 = true; - } - if (Idx != Val) + + // Only accept consecutive elements from the same vector + if ((Idx % NumElems != OpIdx) || (SeenV1 && SeenV2)) return false; } - if (SeenV1 && SeenV2) + + OpNum = SeenV1 ? 0 : 1; + return true; +} + +/// isVectorShiftRight - Returns true if the shuffle can be implemented as a +/// logical left shift of a vector. +static bool isVectorShiftRight(ShuffleVectorSDNode *SVOp, SelectionDAG &DAG, + bool &isLeft, SDValue &ShVal, unsigned &ShAmt) { + unsigned NumElems = SVOp->getValueType(0).getVectorNumElements(); + unsigned NumZeros = getNumOfConsecutiveZeros(SVOp, NumElems, + false /* check zeros from right */, DAG); + unsigned OpSrc; + + if (!NumZeros) + return false; + + // Considering the elements in the mask that are not consecutive zeros, + // check if they consecutively come from only one of the source vectors. + // + // V1 = {X, A, B, C} 0 + // \ \ \ / + // vector_shuffle V1, V2 <1, 2, 3, X> + // + if (!isShuffleMaskConsecutive(SVOp, + 0, // Mask Start Index + NumElems-NumZeros-1, // Mask End Index + NumZeros, // Where to start looking in the src vector + NumElems, // Number of elements in vector + OpSrc)) // Which source operand ? + return false; + + isLeft = false; + ShAmt = NumZeros; + ShVal = SVOp->getOperand(OpSrc); + return true; +} + +/// isVectorShiftLeft - Returns true if the shuffle can be implemented as a +/// logical left shift of a vector. +static bool isVectorShiftLeft(ShuffleVectorSDNode *SVOp, SelectionDAG &DAG, + bool &isLeft, SDValue &ShVal, unsigned &ShAmt) { + unsigned NumElems = SVOp->getValueType(0).getVectorNumElements(); + unsigned NumZeros = getNumOfConsecutiveZeros(SVOp, NumElems, + true /* check zeros from left */, DAG); + unsigned OpSrc; + + if (!NumZeros) + return false; + + // Considering the elements in the mask that are not consecutive zeros, + // check if they consecutively come from only one of the source vectors. + // + // 0 { A, B, X, X } = V2 + // / \ / / + // vector_shuffle V1, V2 + // + if (!isShuffleMaskConsecutive(SVOp, + NumZeros, // Mask Start Index + NumElems-1, // Mask End Index + 0, // Where to start looking in the src vector + NumElems, // Number of elements in vector + OpSrc)) // Which source operand ? return false; - ShVal = SeenV1 ? SVOp->getOperand(0) : SVOp->getOperand(1); + isLeft = true; ShAmt = NumZeros; + ShVal = SVOp->getOperand(OpSrc); return true; } +/// isVectorShift - Returns true if the shuffle can be implemented as a +/// logical left or right shift of a vector. +static bool isVectorShift(ShuffleVectorSDNode *SVOp, SelectionDAG &DAG, + bool &isLeft, SDValue &ShVal, unsigned &ShAmt) { + if (isVectorShiftLeft(SVOp, DAG, isLeft, ShVal, ShAmt) || + isVectorShiftRight(SVOp, DAG, isLeft, ShVal, ShAmt)) + return true; + + return false; +} /// LowerBuildVectorv16i8 - Custom lower build_vector of v16i8. /// @@ -3779,9 +4162,13 @@ static SDValue EltsFromConsecutiveLoads(EVT VT, SmallVectorImpl &Elts, SDValue X86TargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const { DebugLoc dl = Op.getDebugLoc(); - // All zero's are handled with pxor, all one's are handled with pcmpeqd. - if (ISD::isBuildVectorAllZeros(Op.getNode()) - || ISD::isBuildVectorAllOnes(Op.getNode())) { + // All zero's are handled with pxor in SSE2 and above, xorps in SSE1. + // All one's are handled with pcmpeqd. In AVX, zero's are handled with + // vpxor in 128-bit and xor{pd,ps} in 256-bit, but no 256 version of pcmpeqd + // is present, so AllOnes is ignored. + if (ISD::isBuildVectorAllZeros(Op.getNode()) || + (Op.getValueType().getSizeInBits() != 256 && + ISD::isBuildVectorAllOnes(Op.getNode()))) { // Canonicalize this to either <4 x i32> or <2 x i32> (SSE vs MMX) to // 1) ensure the zero vectors are CSE'd, and 2) ensure that i64 scalars are // eliminated on x86-32 hosts. @@ -3819,10 +4206,9 @@ X86TargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const { } } - if (NumNonZero == 0) { - // All undef vector. Return an UNDEF. All zero vectors were handled above. + // All undef vector. Return an UNDEF. All zero vectors were handled above. + if (NumNonZero == 0) return DAG.getUNDEF(VT); - } // Special case for single non-zero, non-undef, element. if (NumNonZero == 1) { @@ -3960,7 +4346,7 @@ X86TargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const { if (EVTBits == 16 && NumElems == 8) { SDValue V = LowerBuildVectorv8i16(Op, NonZeros,NumNonZero,NumZero, DAG, - *this); + *this); if (V.getNode()) return V; } @@ -4014,28 +4400,51 @@ X86TargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const { if (LD.getNode()) return LD; - // For SSE 4.1, use inserts into undef. + // For SSE 4.1, use insertps to put the high elements into the low element. if (getSubtarget()->hasSSE41()) { - V[0] = DAG.getUNDEF(VT); - for (unsigned i = 0; i < NumElems; ++i) - if (Op.getOperand(i).getOpcode() != ISD::UNDEF) - V[0] = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, VT, V[0], + SDValue Result; + if (Op.getOperand(0).getOpcode() != ISD::UNDEF) + Result = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Op.getOperand(0)); + else + Result = DAG.getUNDEF(VT); + + for (unsigned i = 1; i < NumElems; ++i) { + if (Op.getOperand(i).getOpcode() == ISD::UNDEF) continue; + Result = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, VT, Result, Op.getOperand(i), DAG.getIntPtrConstant(i)); - return V[0]; + } + return Result; } - // Otherwise, expand into a number of unpckl* - // e.g. for v4f32 + // Otherwise, expand into a number of unpckl*, start by extending each of + // our (non-undef) elements to the full vector width with the element in the + // bottom slot of the vector (which generates no code for SSE). + for (unsigned i = 0; i < NumElems; ++i) { + if (Op.getOperand(i).getOpcode() != ISD::UNDEF) + V[i] = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Op.getOperand(i)); + else + V[i] = DAG.getUNDEF(VT); + } + + // Next, we iteratively mix elements, e.g. for v4f32: // Step 1: unpcklps 0, 2 ==> X: // : unpcklps 1, 3 ==> Y: // Step 2: unpcklps X, Y ==> <3, 2, 1, 0> - for (unsigned i = 0; i < NumElems; ++i) - V[i] = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, VT, Op.getOperand(i)); - NumElems >>= 1; - while (NumElems != 0) { - for (unsigned i = 0; i < NumElems; ++i) - V[i] = getUnpackl(DAG, dl, VT, V[i], V[i + NumElems]); - NumElems >>= 1; + unsigned EltStride = NumElems >> 1; + while (EltStride != 0) { + for (unsigned i = 0; i < EltStride; ++i) { + // If V[i+EltStride] is undef and this is the first round of mixing, + // then it is safe to just drop this shuffle: V[i] is already in the + // right place, the one element (since it's the first round) being + // inserted as undef can be dropped. This isn't safe for successive + // rounds because they will permute elements within both vectors. + if (V[i+EltStride].getOpcode() == ISD::UNDEF && + EltStride == NumElems/2) + continue; + + V[i] = getUnpackl(DAG, dl, VT, V[i], V[i + EltStride]); + } + EltStride >>= 1; } return V[0]; } @@ -4074,10 +4483,10 @@ X86TargetLowering::LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) const { // 2. [ssse3] 1 x pshufb // 3. [ssse3] 2 x pshufb + 1 x por // 4. [all] mov + pshuflw + pshufhw + N x (pextrw + pinsrw) -static -SDValue LowerVECTOR_SHUFFLEv8i16(ShuffleVectorSDNode *SVOp, - SelectionDAG &DAG, - const X86TargetLowering &TLI) { +SDValue +X86TargetLowering::LowerVECTOR_SHUFFLEv8i16(SDValue Op, + SelectionDAG &DAG) const { + ShuffleVectorSDNode *SVOp = cast(Op); SDValue V1 = SVOp->getOperand(0); SDValue V2 = SVOp->getOperand(1); DebugLoc dl = SVOp->getDebugLoc(); @@ -4128,7 +4537,7 @@ SDValue LowerVECTOR_SHUFFLEv8i16(ShuffleVectorSDNode *SVOp, // quads, disable the next transformation since it does not help SSSE3. bool V1Used = InputQuads[0] || InputQuads[1]; bool V2Used = InputQuads[2] || InputQuads[3]; - if (TLI.getSubtarget()->hasSSSE3()) { + if (Subtarget->hasSSSE3()) { if (InputQuads.count() == 2 && V1Used && V2Used) { BestLoQuad = InputQuads.find_first(); BestHiQuad = InputQuads.find_next(BestLoQuad); @@ -4187,15 +4596,21 @@ SDValue LowerVECTOR_SHUFFLEv8i16(ShuffleVectorSDNode *SVOp, // If we've eliminated the use of V2, and the new mask is a pshuflw or // pshufhw, that's as cheap as it gets. Return the new shuffle. if ((pshufhw && InOrder[0]) || (pshuflw && InOrder[1])) { - return DAG.getVectorShuffle(MVT::v8i16, dl, NewV, + unsigned Opc = pshufhw ? X86ISD::PSHUFHW : X86ISD::PSHUFLW; + unsigned TargetMask = 0; + NewV = DAG.getVectorShuffle(MVT::v8i16, dl, NewV, DAG.getUNDEF(MVT::v8i16), &MaskVals[0]); + TargetMask = pshufhw ? X86::getShufflePSHUFHWImmediate(NewV.getNode()): + X86::getShufflePSHUFLWImmediate(NewV.getNode()); + V1 = NewV.getOperand(0); + return getTargetShuffleNode(Opc, dl, MVT::v8i16, V1, TargetMask, DAG); } } // If we have SSSE3, and all words of the result are from 1 input vector, // case 2 is generated, otherwise case 3 is generated. If no SSSE3 // is present, fall back to case 4. - if (TLI.getSubtarget()->hasSSSE3()) { + if (Subtarget->hasSSSE3()) { SmallVector pshufbMask; // If we have elements from both input vectors, set the high bit of the @@ -4262,6 +4677,12 @@ SDValue LowerVECTOR_SHUFFLEv8i16(ShuffleVectorSDNode *SVOp, MaskV.push_back(i); NewV = DAG.getVectorShuffle(MVT::v8i16, dl, NewV, DAG.getUNDEF(MVT::v8i16), &MaskV[0]); + + if (NewV.getOpcode() == ISD::VECTOR_SHUFFLE && Subtarget->hasSSSE3()) + NewV = getTargetShuffleNode(X86ISD::PSHUFLW, dl, MVT::v8i16, + NewV.getOperand(0), + X86::getShufflePSHUFLWImmediate(NewV.getNode()), + DAG); } // If BestHi >= 0, generate a pshufhw to put the high elements in order, @@ -4284,6 +4705,12 @@ SDValue LowerVECTOR_SHUFFLEv8i16(ShuffleVectorSDNode *SVOp, } NewV = DAG.getVectorShuffle(MVT::v8i16, dl, NewV, DAG.getUNDEF(MVT::v8i16), &MaskV[0]); + + if (NewV.getOpcode() == ISD::VECTOR_SHUFFLE && Subtarget->hasSSSE3()) + NewV = getTargetShuffleNode(X86ISD::PSHUFHW, dl, MVT::v8i16, + NewV.getOperand(0), + X86::getShufflePSHUFHWImmediate(NewV.getNode()), + DAG); } // In case BestHi & BestLo were both -1, which means each quadword has a word @@ -4473,7 +4900,7 @@ SDValue RewriteAsNarrowerShuffle(ShuffleVectorSDNode *SVOp, SDValue V2 = SVOp->getOperand(1); unsigned NumElems = VT.getVectorNumElements(); unsigned NewWidth = (NumElems == 4) ? 2 : 4; - EVT MaskVT = MVT::getIntVectorWithNumElements(NewWidth); + EVT MaskVT = (NewWidth == 4) ? MVT::v4i16 : MVT::v2i32; EVT NewVT = MaskVT; switch (VT.getSimpleVT().SimpleTy) { default: assert(false && "Unexpected!"); @@ -4697,6 +5124,129 @@ LowerVECTOR_SHUFFLE_4wide(ShuffleVectorSDNode *SVOp, SelectionDAG &DAG) { return DAG.getVectorShuffle(VT, dl, LoShuffle, HiShuffle, &MaskOps[0]); } +static bool MayFoldVectorLoad(SDValue V) { + if (V.hasOneUse() && V.getOpcode() == ISD::BIT_CONVERT) + V = V.getOperand(0); + if (V.hasOneUse() && V.getOpcode() == ISD::SCALAR_TO_VECTOR) + V = V.getOperand(0); + if (MayFoldLoad(V)) + return true; + return false; +} + +static +SDValue getMOVLowToHigh(SDValue &Op, DebugLoc &dl, SelectionDAG &DAG, + bool HasSSE2) { + SDValue V1 = Op.getOperand(0); + SDValue V2 = Op.getOperand(1); + EVT VT = Op.getValueType(); + + assert(VT != MVT::v2i64 && "unsupported shuffle type"); + + if (HasSSE2 && VT == MVT::v2f64) + return getTargetShuffleNode(X86ISD::MOVLHPD, dl, VT, V1, V2, DAG); + + // v4f32 or v4i32 + return getTargetShuffleNode(X86ISD::MOVLHPS, dl, VT, V1, V2, DAG); +} + +static +SDValue getMOVHighToLow(SDValue &Op, DebugLoc &dl, SelectionDAG &DAG) { + SDValue V1 = Op.getOperand(0); + SDValue V2 = Op.getOperand(1); + EVT VT = Op.getValueType(); + + assert((VT == MVT::v4i32 || VT == MVT::v4f32) && + "unsupported shuffle type"); + + if (V2.getOpcode() == ISD::UNDEF) + V2 = V1; + + // v4i32 or v4f32 + return getTargetShuffleNode(X86ISD::MOVHLPS, dl, VT, V1, V2, DAG); +} + +static +SDValue getMOVLP(SDValue &Op, DebugLoc &dl, SelectionDAG &DAG, bool HasSSE2) { + SDValue V1 = Op.getOperand(0); + SDValue V2 = Op.getOperand(1); + EVT VT = Op.getValueType(); + unsigned NumElems = VT.getVectorNumElements(); + + // Use MOVLPS and MOVLPD in case V1 or V2 are loads. During isel, the second + // operand of these instructions is only memory, so check if there's a + // potencial load folding here, otherwise use SHUFPS or MOVSD to match the + // same masks. + bool CanFoldLoad = false; + + // Trivial case, when V2 comes from a load. + if (MayFoldVectorLoad(V2)) + CanFoldLoad = true; + + // When V1 is a load, it can be folded later into a store in isel, example: + // (store (v4f32 (X86Movlps (load addr:$src1), VR128:$src2)), addr:$src1) + // turns into: + // (MOVLPSmr addr:$src1, VR128:$src2) + // So, recognize this potential and also use MOVLPS or MOVLPD + if (MayFoldVectorLoad(V1) && MayFoldIntoStore(Op)) + CanFoldLoad = true; + + if (CanFoldLoad) { + if (HasSSE2 && NumElems == 2) + return getTargetShuffleNode(X86ISD::MOVLPD, dl, VT, V1, V2, DAG); + + if (NumElems == 4) + return getTargetShuffleNode(X86ISD::MOVLPS, dl, VT, V1, V2, DAG); + } + + ShuffleVectorSDNode *SVOp = cast(Op); + // movl and movlp will both match v2i64, but v2i64 is never matched by + // movl earlier because we make it strict to avoid messing with the movlp load + // folding logic (see the code above getMOVLP call). Match it here then, + // this is horrible, but will stay like this until we move all shuffle + // matching to x86 specific nodes. Note that for the 1st condition all + // types are matched with movsd. + if ((HasSSE2 && NumElems == 2) || !X86::isMOVLMask(SVOp)) + return getTargetShuffleNode(X86ISD::MOVSD, dl, VT, V1, V2, DAG); + else if (HasSSE2) + return getTargetShuffleNode(X86ISD::MOVSS, dl, VT, V1, V2, DAG); + + + assert(VT != MVT::v4i32 && "unsupported shuffle type"); + + // Invert the operand order and use SHUFPS to match it. + return getTargetShuffleNode(X86ISD::SHUFPS, dl, VT, V2, V1, + X86::getShuffleSHUFImmediate(SVOp), DAG); +} + +static inline unsigned getUNPCKLOpcode(EVT VT) { + switch(VT.getSimpleVT().SimpleTy) { + case MVT::v4i32: return X86ISD::PUNPCKLDQ; + case MVT::v2i64: return X86ISD::PUNPCKLQDQ; + case MVT::v4f32: return X86ISD::UNPCKLPS; + case MVT::v2f64: return X86ISD::UNPCKLPD; + case MVT::v16i8: return X86ISD::PUNPCKLBW; + case MVT::v8i16: return X86ISD::PUNPCKLWD; + default: + llvm_unreachable("Unknow type for unpckl"); + } + return 0; +} + +static inline unsigned getUNPCKHOpcode(EVT VT) { + switch(VT.getSimpleVT().SimpleTy) { + case MVT::v4i32: return X86ISD::PUNPCKHDQ; + case MVT::v2i64: return X86ISD::PUNPCKHQDQ; + case MVT::v4f32: return X86ISD::UNPCKHPS; + case MVT::v2f64: return X86ISD::UNPCKHPD; + case MVT::v16i8: return X86ISD::PUNPCKHBW; + case MVT::v8i16: return X86ISD::PUNPCKHWD; + default: + llvm_unreachable("Unknow type for unpckh"); + } + return 0; +} + SDValue X86TargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const { ShuffleVectorSDNode *SVOp = cast(Op); @@ -4710,6 +5260,10 @@ X86TargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const { bool V2IsUndef = V2.getOpcode() == ISD::UNDEF; bool V1IsSplat = false; bool V2IsSplat = false; + bool HasSSE2 = Subtarget->hasSSE2() || Subtarget->hasAVX(); + bool HasSSE3 = Subtarget->hasSSE3() || Subtarget->hasAVX(); + MachineFunction &MF = DAG.getMachineFunction(); + bool OptForSize = MF.getFunction()->hasFnAttr(Attribute::OptimizeForSize); if (isZeroShuffle(SVOp)) return getZeroVector(VT, Subtarget->hasSSE2(), DAG, dl); @@ -4718,7 +5272,7 @@ X86TargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const { if (SVOp->isSplat()) { if (isMMX || NumElems < 4) return Op; - return PromoteSplat(SVOp, DAG, Subtarget->hasSSE2()); + return PromoteSplat(SVOp, DAG); } // If the shuffle can be profitably rewritten as a narrower shuffle, then @@ -4746,8 +5300,35 @@ X86TargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const { } } - if (X86::isPSHUFDMask(SVOp)) - return Op; + // NOTE: isPSHUFDMask can also match both masks below (unpckl_undef and + // unpckh_undef). Only use pshufd if speed is more important than size. + if (OptForSize && X86::isUNPCKL_v_undef_Mask(SVOp)) + if (VT != MVT::v2i64 && VT != MVT::v2f64) + return getTargetShuffleNode(getUNPCKLOpcode(VT), dl, VT, V1, V1, DAG); + if (OptForSize && X86::isUNPCKH_v_undef_Mask(SVOp)) + if (VT != MVT::v2i64 && VT != MVT::v2f64) + return getTargetShuffleNode(getUNPCKHOpcode(VT), dl, VT, V1, V1, DAG); + + if (X86::isPSHUFDMask(SVOp)) { + // The actual implementation will match the mask in the if above and then + // during isel it can match several different instructions, not only pshufd + // as its name says, sad but true, emulate the behavior for now... + if (X86::isMOVDDUPMask(SVOp) && ((VT == MVT::v4f32 || VT == MVT::v2i64))) + return getTargetShuffleNode(X86ISD::MOVLHPS, dl, VT, V1, V1, DAG); + + unsigned TargetMask = X86::getShuffleSHUFImmediate(SVOp); + + if (HasSSE2 && (VT == MVT::v4f32 || VT == MVT::v4i32)) + return getTargetShuffleNode(X86ISD::PSHUFD, dl, VT, V1, TargetMask, DAG); + + if (HasSSE2 && (VT == MVT::v2i64 || VT == MVT::v2f64)) + return getTargetShuffleNode(X86ISD::SHUFPD, dl, VT, V1, V1, + TargetMask, DAG); + + if (VT == MVT::v4f32) + return getTargetShuffleNode(X86ISD::SHUFPS, dl, VT, V1, V1, + TargetMask, DAG); + } // Check if this can be converted into a logical shift. bool isLeft = false; @@ -4768,17 +5349,32 @@ X86TargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const { return V2; if (ISD::isBuildVectorAllZeros(V1.getNode())) return getVZextMovL(VT, VT, V2, DAG, Subtarget, dl); - if (!isMMX) - return Op; + if (!isMMX && !X86::isMOVLPMask(SVOp)) { + if (HasSSE2 && (VT == MVT::v2i64 || VT == MVT::v2f64)) + return getTargetShuffleNode(X86ISD::MOVSD, dl, VT, V1, V2, DAG); + + if (VT == MVT::v4i32 || VT == MVT::v4f32) + return getTargetShuffleNode(X86ISD::MOVSS, dl, VT, V1, V2, DAG); + } } // FIXME: fold these into legal mask. - if (!isMMX && (X86::isMOVSHDUPMask(SVOp) || - X86::isMOVSLDUPMask(SVOp) || - X86::isMOVHLPSMask(SVOp) || - X86::isMOVLHPSMask(SVOp) || - X86::isMOVLPMask(SVOp))) - return Op; + if (!isMMX) { + if (X86::isMOVLHPSMask(SVOp) && !X86::isUNPCKLMask(SVOp)) + return getMOVLowToHigh(Op, dl, DAG, HasSSE2); + + if (X86::isMOVHLPSMask(SVOp)) + return getMOVHighToLow(Op, dl, DAG); + + if (X86::isMOVSHDUPMask(SVOp) && HasSSE3 && V2IsUndef && NumElems == 4) + return getTargetShuffleNode(X86ISD::MOVSHDUP, dl, VT, V1, DAG); + + if (X86::isMOVSLDUPMask(SVOp) && HasSSE3 && V2IsUndef && NumElems == 4) + return getTargetShuffleNode(X86ISD::MOVSLDUP, dl, VT, V1, DAG); + + if (X86::isMOVLPMask(SVOp)) + return getMOVLP(Op, dl, DAG, HasSSE2); + } if (ShouldXformToMOVHLPS(SVOp) || ShouldXformToMOVLP(V1.getNode(), V2.getNode(), SVOp)) @@ -4818,11 +5414,13 @@ X86TargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const { return getMOVL(DAG, dl, VT, V2, V1); } - if (X86::isUNPCKL_v_undef_Mask(SVOp) || - X86::isUNPCKH_v_undef_Mask(SVOp) || - X86::isUNPCKLMask(SVOp) || - X86::isUNPCKHMask(SVOp)) - return Op; + if (X86::isUNPCKLMask(SVOp)) + return (isMMX) ? + Op : getTargetShuffleNode(getUNPCKLOpcode(VT), dl, VT, V1, V2, DAG); + + if (X86::isUNPCKHMask(SVOp)) + return (isMMX) ? + Op : getTargetShuffleNode(getUNPCKHOpcode(VT), dl, VT, V1, V2, DAG); if (V2IsSplat) { // Normalize mask so all entries that point to V2 points to its first @@ -4844,11 +5442,14 @@ X86TargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const { // FIXME: this seems wrong. SDValue NewOp = CommuteVectorShuffle(SVOp, DAG); ShuffleVectorSDNode *NewSVOp = cast(NewOp); - if (X86::isUNPCKL_v_undef_Mask(NewSVOp) || - X86::isUNPCKH_v_undef_Mask(NewSVOp) || - X86::isUNPCKLMask(NewSVOp) || - X86::isUNPCKHMask(NewSVOp)) - return NewOp; + + if (X86::isUNPCKLMask(NewSVOp)) + return (isMMX) ? + NewOp : getTargetShuffleNode(getUNPCKLOpcode(VT), dl, VT, V2, V1, DAG); + + if (X86::isUNPCKHMask(NewSVOp)) + return (isMMX) ? + NewOp : getTargetShuffleNode(getUNPCKHOpcode(VT), dl, VT, V2, V1, DAG); } // FIXME: for mmx, bitcast v2i32 to v4i16 for shuffle. @@ -4857,15 +5458,52 @@ X86TargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) const { if (!isMMX && V2.getOpcode() != ISD::UNDEF && isCommutedSHUFP(SVOp)) return CommuteVectorShuffle(SVOp, DAG); - // Check for legal shuffle and return? - SmallVector PermMask; - SVOp->getMask(PermMask); - if (isShuffleMaskLegal(PermMask, VT)) + // The checks below are all present in isShuffleMaskLegal, but they are + // inlined here right now to enable us to directly emit target specific + // nodes, and remove one by one until they don't return Op anymore. + SmallVector M; + SVOp->getMask(M); + + // Very little shuffling can be done for 64-bit vectors right now. + if (VT.getSizeInBits() == 64) + return isPALIGNRMask(M, VT, Subtarget->hasSSSE3()) ? Op : SDValue(); + + // FIXME: pshufb, blends, shifts. + if (VT.getVectorNumElements() == 2 || + ShuffleVectorSDNode::isSplatMask(&M[0], VT) || + isPALIGNRMask(M, VT, Subtarget->hasSSSE3())) return Op; + if (isPSHUFHWMask(M, VT)) + return getTargetShuffleNode(X86ISD::PSHUFHW, dl, VT, V1, + X86::getShufflePSHUFHWImmediate(SVOp), + DAG); + + if (isPSHUFLWMask(M, VT)) + return getTargetShuffleNode(X86ISD::PSHUFLW, dl, VT, V1, + X86::getShufflePSHUFLWImmediate(SVOp), + DAG); + + if (isSHUFPMask(M, VT)) { + unsigned TargetMask = X86::getShuffleSHUFImmediate(SVOp); + if (VT == MVT::v4f32 || VT == MVT::v4i32) + return getTargetShuffleNode(X86ISD::SHUFPS, dl, VT, V1, V2, + TargetMask, DAG); + if (VT == MVT::v2f64 || VT == MVT::v2i64) + return getTargetShuffleNode(X86ISD::SHUFPD, dl, VT, V1, V2, + TargetMask, DAG); + } + + if (X86::isUNPCKL_v_undef_Mask(SVOp)) + if (VT != MVT::v2i64 && VT != MVT::v2f64) + return getTargetShuffleNode(getUNPCKLOpcode(VT), dl, VT, V1, V1, DAG); + if (X86::isUNPCKH_v_undef_Mask(SVOp)) + if (VT != MVT::v2i64 && VT != MVT::v2f64) + return getTargetShuffleNode(getUNPCKHOpcode(VT), dl, VT, V1, V1, DAG); + // Handle v8i16 specifically since SSE can do byte extraction and insertion. if (VT == MVT::v8i16) { - SDValue NewOp = LowerVECTOR_SHUFFLEv8i16(SVOp, DAG, *this); + SDValue NewOp = LowerVECTOR_SHUFFLEv8i16(Op, DAG); if (NewOp.getNode()) return NewOp; } @@ -6922,24 +7560,58 @@ X86TargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const DAG.getConstant(X86CC, MVT::i8), Cond); return DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, SetCC); } - // ptest intrinsics. The intrinsic these come from are designed to return - // an integer value, not just an instruction so lower it to the ptest - // pattern and a setcc for the result. + // ptest and testp intrinsics. The intrinsic these come from are designed to + // return an integer value, not just an instruction so lower it to the ptest + // or testp pattern and a setcc for the result. case Intrinsic::x86_sse41_ptestz: case Intrinsic::x86_sse41_ptestc: - case Intrinsic::x86_sse41_ptestnzc:{ + case Intrinsic::x86_sse41_ptestnzc: + case Intrinsic::x86_avx_ptestz_256: + case Intrinsic::x86_avx_ptestc_256: + case Intrinsic::x86_avx_ptestnzc_256: + case Intrinsic::x86_avx_vtestz_ps: + case Intrinsic::x86_avx_vtestc_ps: + case Intrinsic::x86_avx_vtestnzc_ps: + case Intrinsic::x86_avx_vtestz_pd: + case Intrinsic::x86_avx_vtestc_pd: + case Intrinsic::x86_avx_vtestnzc_pd: + case Intrinsic::x86_avx_vtestz_ps_256: + case Intrinsic::x86_avx_vtestc_ps_256: + case Intrinsic::x86_avx_vtestnzc_ps_256: + case Intrinsic::x86_avx_vtestz_pd_256: + case Intrinsic::x86_avx_vtestc_pd_256: + case Intrinsic::x86_avx_vtestnzc_pd_256: { + bool IsTestPacked = false; unsigned X86CC = 0; switch (IntNo) { default: llvm_unreachable("Bad fallthrough in Intrinsic lowering."); + case Intrinsic::x86_avx_vtestz_ps: + case Intrinsic::x86_avx_vtestz_pd: + case Intrinsic::x86_avx_vtestz_ps_256: + case Intrinsic::x86_avx_vtestz_pd_256: + IsTestPacked = true; // Fallthrough case Intrinsic::x86_sse41_ptestz: + case Intrinsic::x86_avx_ptestz_256: // ZF = 1 X86CC = X86::COND_E; break; + case Intrinsic::x86_avx_vtestc_ps: + case Intrinsic::x86_avx_vtestc_pd: + case Intrinsic::x86_avx_vtestc_ps_256: + case Intrinsic::x86_avx_vtestc_pd_256: + IsTestPacked = true; // Fallthrough case Intrinsic::x86_sse41_ptestc: + case Intrinsic::x86_avx_ptestc_256: // CF = 1 X86CC = X86::COND_B; break; + case Intrinsic::x86_avx_vtestnzc_ps: + case Intrinsic::x86_avx_vtestnzc_pd: + case Intrinsic::x86_avx_vtestnzc_ps_256: + case Intrinsic::x86_avx_vtestnzc_pd_256: + IsTestPacked = true; // Fallthrough case Intrinsic::x86_sse41_ptestnzc: + case Intrinsic::x86_avx_ptestnzc_256: // ZF and CF = 0 X86CC = X86::COND_A; break; @@ -6947,7 +7619,8 @@ X86TargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const SDValue LHS = Op.getOperand(1); SDValue RHS = Op.getOperand(2); - SDValue Test = DAG.getNode(X86ISD::PTEST, dl, MVT::i32, LHS, RHS); + unsigned TestOpc = IsTestPacked ? X86ISD::TESTP : X86ISD::PTEST; + SDValue Test = DAG.getNode(TestOpc, dl, MVT::i32, LHS, RHS); SDValue CC = DAG.getConstant(X86CC, MVT::i8); SDValue SetCC = DAG.getNode(X86ISD::SETCC, dl, MVT::i8, CC, Test); return DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i32, SetCC); @@ -7110,12 +7783,13 @@ SDValue X86TargetLowering::LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const { SDValue Handler = Op.getOperand(2); DebugLoc dl = Op.getDebugLoc(); - SDValue Frame = DAG.getRegister(Subtarget->is64Bit() ? X86::RBP : X86::EBP, - getPointerTy()); + SDValue Frame = DAG.getCopyFromReg(DAG.getEntryNode(), dl, + Subtarget->is64Bit() ? X86::RBP : X86::EBP, + getPointerTy()); unsigned StoreAddrReg = (Subtarget->is64Bit() ? X86::RCX : X86::ECX); - SDValue StoreAddr = DAG.getNode(ISD::SUB, dl, getPointerTy(), Frame, - DAG.getIntPtrConstant(-TD->getPointerSize())); + SDValue StoreAddr = DAG.getNode(ISD::ADD, dl, getPointerTy(), Frame, + DAG.getIntPtrConstant(TD->getPointerSize())); StoreAddr = DAG.getNode(ISD::ADD, dl, getPointerTy(), StoreAddr, Offset); Chain = DAG.getStore(Chain, dl, Handler, StoreAddr, NULL, 0, false, false, 0); Chain = DAG.getCopyToReg(Chain, dl, StoreAddrReg, StoreAddr); @@ -7218,7 +7892,8 @@ SDValue X86TargetLowering::LowerTRAMPOLINE(SDValue Op, InRegCount += (TD->getTypeSizeInBits(*I) + 31) / 32; if (InRegCount > 2) { - report_fatal_error("Nest register in use - reduce number of inreg parameters!"); + report_fatal_error("Nest register in use - reduce number of inreg" + " parameters!"); } } break; @@ -7439,6 +8114,86 @@ SDValue X86TargetLowering::LowerMUL_V2I64(SDValue Op, SelectionDAG &DAG) const { return Res; } +SDValue X86TargetLowering::LowerSHL(SDValue Op, SelectionDAG &DAG) const { + EVT VT = Op.getValueType(); + DebugLoc dl = Op.getDebugLoc(); + SDValue R = Op.getOperand(0); + + LLVMContext *Context = DAG.getContext(); + + assert(Subtarget->hasSSE41() && "Cannot lower SHL without SSE4.1 or later"); + + if (VT == MVT::v4i32) { + Op = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, + DAG.getConstant(Intrinsic::x86_sse2_pslli_d, MVT::i32), + Op.getOperand(1), DAG.getConstant(23, MVT::i32)); + + ConstantInt *CI = ConstantInt::get(*Context, APInt(32, 0x3f800000U)); + + std::vector CV(4, CI); + Constant *C = ConstantVector::get(CV); + SDValue CPIdx = DAG.getConstantPool(C, getPointerTy(), 16); + SDValue Addend = DAG.getLoad(VT, dl, DAG.getEntryNode(), CPIdx, + PseudoSourceValue::getConstantPool(), 0, + false, false, 16); + + Op = DAG.getNode(ISD::ADD, dl, VT, Op, Addend); + Op = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::v4f32, Op); + Op = DAG.getNode(ISD::FP_TO_SINT, dl, VT, Op); + return DAG.getNode(ISD::MUL, dl, VT, Op, R); + } + if (VT == MVT::v16i8) { + // a = a << 5; + Op = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, + DAG.getConstant(Intrinsic::x86_sse2_pslli_w, MVT::i32), + Op.getOperand(1), DAG.getConstant(5, MVT::i32)); + + ConstantInt *CM1 = ConstantInt::get(*Context, APInt(8, 15)); + ConstantInt *CM2 = ConstantInt::get(*Context, APInt(8, 63)); + + std::vector CVM1(16, CM1); + std::vector CVM2(16, CM2); + Constant *C = ConstantVector::get(CVM1); + SDValue CPIdx = DAG.getConstantPool(C, getPointerTy(), 16); + SDValue M = DAG.getLoad(VT, dl, DAG.getEntryNode(), CPIdx, + PseudoSourceValue::getConstantPool(), 0, + false, false, 16); + + // r = pblendv(r, psllw(r & (char16)15, 4), a); + M = DAG.getNode(ISD::AND, dl, VT, R, M); + M = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, + DAG.getConstant(Intrinsic::x86_sse2_pslli_w, MVT::i32), M, + DAG.getConstant(4, MVT::i32)); + R = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, + DAG.getConstant(Intrinsic::x86_sse41_pblendvb, MVT::i32), + R, M, Op); + // a += a + Op = DAG.getNode(ISD::ADD, dl, VT, Op, Op); + + C = ConstantVector::get(CVM2); + CPIdx = DAG.getConstantPool(C, getPointerTy(), 16); + M = DAG.getLoad(VT, dl, DAG.getEntryNode(), CPIdx, + PseudoSourceValue::getConstantPool(), 0, false, false, 16); + + // r = pblendv(r, psllw(r & (char16)63, 2), a); + M = DAG.getNode(ISD::AND, dl, VT, R, M); + M = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, + DAG.getConstant(Intrinsic::x86_sse2_pslli_w, MVT::i32), M, + DAG.getConstant(2, MVT::i32)); + R = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, + DAG.getConstant(Intrinsic::x86_sse41_pblendvb, MVT::i32), + R, M, Op); + // a += a + Op = DAG.getNode(ISD::ADD, dl, VT, Op, Op); + + // return pblendv(r, r+r, a); + R = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, + DAG.getConstant(Intrinsic::x86_sse41_pblendvb, MVT::i32), + R, DAG.getNode(ISD::ADD, dl, VT, R, R), Op); + return R; + } + return SDValue(); +} SDValue X86TargetLowering::LowerXALUO(SDValue Op, SelectionDAG &DAG) const { // Lower the "add/sub/mul with overflow" instruction into a regular ins plus @@ -7508,6 +8263,50 @@ SDValue X86TargetLowering::LowerXALUO(SDValue Op, SelectionDAG &DAG) const { return Sum; } +SDValue X86TargetLowering::LowerMEMBARRIER(SDValue Op, SelectionDAG &DAG) const{ + DebugLoc dl = Op.getDebugLoc(); + + if (!Subtarget->hasSSE2()) { + SDValue Chain = Op.getOperand(0); + SDValue Zero = DAG.getConstant(0, + Subtarget->is64Bit() ? MVT::i64 : MVT::i32); + SDValue Ops[] = { + DAG.getRegister(X86::ESP, MVT::i32), // Base + DAG.getTargetConstant(1, MVT::i8), // Scale + DAG.getRegister(0, MVT::i32), // Index + DAG.getTargetConstant(0, MVT::i32), // Disp + DAG.getRegister(0, MVT::i32), // Segment. + Zero, + Chain + }; + SDNode *Res = + DAG.getMachineNode(X86::OR32mrLocked, dl, MVT::Other, Ops, + array_lengthof(Ops)); + return SDValue(Res, 0); + } + + unsigned isDev = cast(Op.getOperand(5))->getZExtValue(); + if (!isDev) + return DAG.getNode(X86ISD::MEMBARRIER, dl, MVT::Other, Op.getOperand(0)); + + unsigned Op1 = cast(Op.getOperand(1))->getZExtValue(); + unsigned Op2 = cast(Op.getOperand(2))->getZExtValue(); + unsigned Op3 = cast(Op.getOperand(3))->getZExtValue(); + unsigned Op4 = cast(Op.getOperand(4))->getZExtValue(); + + // def : Pat<(membarrier (i8 0), (i8 0), (i8 0), (i8 1), (i8 1)), (SFENCE)>; + if (!Op1 && !Op2 && !Op3 && Op4) + return DAG.getNode(X86ISD::SFENCE, dl, MVT::Other, Op.getOperand(0)); + + // def : Pat<(membarrier (i8 1), (i8 0), (i8 0), (i8 0), (i8 1)), (LFENCE)>; + if (Op1 && !Op2 && !Op3 && !Op4) + return DAG.getNode(X86ISD::LFENCE, dl, MVT::Other, Op.getOperand(0)); + + // def : Pat<(membarrier (i8 imm), (i8 imm), (i8 imm), (i8 imm), (i8 1)), + // (MFENCE)>; + return DAG.getNode(X86ISD::MFENCE, dl, MVT::Other, Op.getOperand(0)); +} + SDValue X86TargetLowering::LowerCMP_SWAP(SDValue Op, SelectionDAG &DAG) const { EVT T = Op.getValueType(); DebugLoc dl = Op.getDebugLoc(); @@ -7597,6 +8396,7 @@ SDValue X86TargetLowering::LowerLOAD_SUB(SDValue Op, SelectionDAG &DAG) const { SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { default: llvm_unreachable("Should not custom lower this!"); + case ISD::MEMBARRIER: return LowerMEMBARRIER(Op,DAG); case ISD::ATOMIC_CMP_SWAP: return LowerCMP_SWAP(Op,DAG); case ISD::ATOMIC_LOAD_SUB: return LowerLOAD_SUB(Op,DAG); case ISD::BUILD_VECTOR: return LowerBUILD_VECTOR(Op, DAG); @@ -7640,6 +8440,7 @@ SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::CTLZ: return LowerCTLZ(Op, DAG); case ISD::CTTZ: return LowerCTTZ(Op, DAG); case ISD::MUL: return LowerMUL_V2I64(Op, DAG); + case ISD::SHL: return LowerSHL(Op, DAG); case ISD::SADDO: case ISD::UADDO: case ISD::SSUBO: @@ -7852,6 +8653,40 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const { case X86ISD::AND: return "X86ISD::AND"; case X86ISD::MUL_IMM: return "X86ISD::MUL_IMM"; case X86ISD::PTEST: return "X86ISD::PTEST"; + case X86ISD::TESTP: return "X86ISD::TESTP"; + case X86ISD::PALIGN: return "X86ISD::PALIGN"; + case X86ISD::PSHUFD: return "X86ISD::PSHUFD"; + case X86ISD::PSHUFHW: return "X86ISD::PSHUFHW"; + case X86ISD::PSHUFHW_LD: return "X86ISD::PSHUFHW_LD"; + case X86ISD::PSHUFLW: return "X86ISD::PSHUFLW"; + case X86ISD::PSHUFLW_LD: return "X86ISD::PSHUFLW_LD"; + case X86ISD::SHUFPS: return "X86ISD::SHUFPS"; + case X86ISD::SHUFPD: return "X86ISD::SHUFPD"; + case X86ISD::MOVLHPS: return "X86ISD::MOVLHPS"; + case X86ISD::MOVLHPD: return "X86ISD::MOVLHPD"; + case X86ISD::MOVHLPS: return "X86ISD::MOVHLPS"; + case X86ISD::MOVHLPD: return "X86ISD::MOVHLPD"; + case X86ISD::MOVLPS: return "X86ISD::MOVLPS"; + case X86ISD::MOVLPD: return "X86ISD::MOVLPD"; + case X86ISD::MOVDDUP: return "X86ISD::MOVDDUP"; + case X86ISD::MOVSHDUP: return "X86ISD::MOVSHDUP"; + case X86ISD::MOVSLDUP: return "X86ISD::MOVSLDUP"; + case X86ISD::MOVSHDUP_LD: return "X86ISD::MOVSHDUP_LD"; + case X86ISD::MOVSLDUP_LD: return "X86ISD::MOVSLDUP_LD"; + case X86ISD::MOVSD: return "X86ISD::MOVSD"; + case X86ISD::MOVSS: return "X86ISD::MOVSS"; + case X86ISD::UNPCKLPS: return "X86ISD::UNPCKLPS"; + case X86ISD::UNPCKLPD: return "X86ISD::UNPCKLPD"; + case X86ISD::UNPCKHPS: return "X86ISD::UNPCKHPS"; + case X86ISD::UNPCKHPD: return "X86ISD::UNPCKHPD"; + case X86ISD::PUNPCKLBW: return "X86ISD::PUNPCKLBW"; + case X86ISD::PUNPCKLWD: return "X86ISD::PUNPCKLWD"; + case X86ISD::PUNPCKLDQ: return "X86ISD::PUNPCKLDQ"; + case X86ISD::PUNPCKLQDQ: return "X86ISD::PUNPCKLQDQ"; + case X86ISD::PUNPCKHBW: return "X86ISD::PUNPCKHBW"; + case X86ISD::PUNPCKHWD: return "X86ISD::PUNPCKHWD"; + case X86ISD::PUNPCKHDQ: return "X86ISD::PUNPCKHDQ"; + case X86ISD::PUNPCKHQDQ: return "X86ISD::PUNPCKHQDQ"; case X86ISD::VASTART_SAVE_XMM_REGS: return "X86ISD::VASTART_SAVE_XMM_REGS"; case X86ISD::MINGW_ALLOCA: return "X86ISD::MINGW_ALLOCA"; } @@ -7863,6 +8698,7 @@ bool X86TargetLowering::isLegalAddressingMode(const AddrMode &AM, const Type *Ty) const { // X86 supports extremely general addressing modes. CodeModel::Model M = getTargetMachine().getCodeModel(); + Reloc::Model R = getTargetMachine().getRelocationModel(); // X86 allows a sign-extended 32-bit immediate field as a displacement. if (!X86::isOffsetSuitableForCodeModel(AM.BaseOffs, M, AM.BaseGV != NULL)) @@ -7882,7 +8718,8 @@ bool X86TargetLowering::isLegalAddressingMode(const AddrMode &AM, return false; // If lower 4G is not available, then we must use rip-relative addressing. - if (Subtarget->is64Bit() && (AM.BaseOffs || AM.Scale > 1)) + if ((M != CodeModel::Small || R != Reloc::Static) && + Subtarget->is64Bit() && (AM.BaseOffs || AM.Scale > 1)) return false; } @@ -8368,19 +9205,31 @@ X86TargetLowering::EmitAtomicMinMaxWithCustomInserter(MachineInstr *mInstr, } // FIXME: When we get size specific XMM0 registers, i.e. XMM0_V16I8 -// all of this code can be replaced with that in the .td file. +// or XMM0_V32I8 in AVX all of this code can be replaced with that +// in the .td file. MachineBasicBlock * X86TargetLowering::EmitPCMP(MachineInstr *MI, MachineBasicBlock *BB, unsigned numArgs, bool memArg) const { + assert((Subtarget->hasSSE42() || Subtarget->hasAVX()) && + "Target must have SSE4.2 or AVX features enabled"); + DebugLoc dl = MI->getDebugLoc(); const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); unsigned Opc; - if (memArg) - Opc = numArgs == 3 ? X86::PCMPISTRM128rm : X86::PCMPESTRM128rm; - else - Opc = numArgs == 3 ? X86::PCMPISTRM128rr : X86::PCMPESTRM128rr; + + if (!Subtarget->hasAVX()) { + if (memArg) + Opc = numArgs == 3 ? X86::PCMPISTRM128rm : X86::PCMPESTRM128rm; + else + Opc = numArgs == 3 ? X86::PCMPISTRM128rr : X86::PCMPESTRM128rr; + } else { + if (memArg) + Opc = numArgs == 3 ? X86::VPCMPISTRM128rm : X86::VPCMPESTRM128rm; + else + Opc = numArgs == 3 ? X86::VPCMPISTRM128rr : X86::VPCMPESTRM128rr; + } MachineInstrBuilder MIB = BuildMI(BB, dl, TII->get(Opc)); @@ -8562,7 +9411,8 @@ X86TargetLowering::EmitLoweredMingwAlloca(MachineInstr *MI, .addReg(X86::EAX, RegState::Implicit) .addReg(X86::ESP, RegState::Implicit) .addReg(X86::EAX, RegState::Define | RegState::Implicit) - .addReg(X86::ESP, RegState::Define | RegState::Implicit); + .addReg(X86::ESP, RegState::Define | RegState::Implicit) + .addReg(X86::EFLAGS, RegState::Define | RegState::Implicit); MI->eraseFromParent(); // The pseudo instruction is gone now. return BB; @@ -8579,6 +9429,7 @@ X86TargetLowering::EmitLoweredTLSCall(MachineInstr *MI, = static_cast(getTargetMachine().getInstrInfo()); DebugLoc DL = MI->getDebugLoc(); MachineFunction *F = BB->getParent(); + bool IsWin64 = Subtarget->isTargetWin64(); assert(MI->getOperand(3).isGlobal() && "This should be a global"); @@ -8590,7 +9441,7 @@ X86TargetLowering::EmitLoweredTLSCall(MachineInstr *MI, .addGlobalAddress(MI->getOperand(3).getGlobal(), 0, MI->getOperand(3).getTargetFlags()) .addReg(0); - MIB = BuildMI(*BB, MI, DL, TII->get(X86::CALL64m)); + MIB = BuildMI(*BB, MI, DL, TII->get(IsWin64 ? X86::WINCALL64m : X86::CALL64m)); addDirectMem(MIB, X86::RDI); } else if (getTargetMachine().getRelocationModel() != Reloc::PIC_) { MachineInstrBuilder MIB = BuildMI(*BB, MI, DL, @@ -8727,12 +9578,16 @@ X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, } // String/text processing lowering. case X86::PCMPISTRM128REG: + case X86::VPCMPISTRM128REG: return EmitPCMP(MI, BB, 3, false /* in-mem */); case X86::PCMPISTRM128MEM: + case X86::VPCMPISTRM128MEM: return EmitPCMP(MI, BB, 3, true /* in-mem */); case X86::PCMPESTRM128REG: + case X86::VPCMPESTRM128REG: return EmitPCMP(MI, BB, 5, false /* in mem */); case X86::PCMPESTRM128MEM: + case X86::VPCMPESTRM128MEM: return EmitPCMP(MI, BB, 5, true /* in mem */); // Atomic Lowering. @@ -8966,21 +9821,20 @@ static SDValue PerformShuffleCombine(SDNode *N, SelectionDAG &DAG, const TargetLowering &TLI) { DebugLoc dl = N->getDebugLoc(); EVT VT = N->getValueType(0); - ShuffleVectorSDNode *SVN = cast(N); if (VT.getSizeInBits() != 128) return SDValue(); SmallVector Elts; for (unsigned i = 0, e = VT.getVectorNumElements(); i != e; ++i) - Elts.push_back(DAG.getShuffleScalarElt(SVN, i)); - + Elts.push_back(getShuffleScalarElt(N, i, DAG, 0)); + return EltsFromConsecutiveLoads(VT, Elts, dl, DAG); } -/// PerformShuffleCombine - Detect vector gather/scatter index generation -/// and convert it from being a bunch of shuffles and extracts to a simple -/// store and scalar loads to extract the elements. +/// PerformEXTRACT_VECTOR_ELTCombine - Detect vector gather/scatter index +/// generation and convert it from being a bunch of shuffles and extracts +/// to a simple store and scalar loads to extract the elements. static SDValue PerformEXTRACT_VECTOR_ELTCombine(SDNode *N, SelectionDAG &DAG, const TargetLowering &TLI) { SDValue InputVector = N->getOperand(0); @@ -9030,8 +9884,8 @@ static SDValue PerformEXTRACT_VECTOR_ELTCombine(SDNode *N, SelectionDAG &DAG, // Store the value to a temporary stack slot. SDValue StackPtr = DAG.CreateStackTemporary(InputVector.getValueType()); - SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, InputVector, StackPtr, NULL, 0, - false, false, 0); + SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, InputVector, StackPtr, NULL, + 0, false, false, 0); // Replace each use (extract) with a load of the appropriate element. for (SmallVectorImpl::iterator UI = Uses.begin(), @@ -9045,11 +9899,12 @@ static SDValue PerformEXTRACT_VECTOR_ELTCombine(SDNode *N, SelectionDAG &DAG, uint64_t Offset = EltSize * cast(Idx)->getZExtValue(); SDValue OffsetVal = DAG.getConstant(Offset, TLI.getPointerTy()); - SDValue ScalarAddr = DAG.getNode(ISD::ADD, dl, Idx.getValueType(), OffsetVal, StackPtr); + SDValue ScalarAddr = DAG.getNode(ISD::ADD, dl, Idx.getValueType(), + OffsetVal, StackPtr); // Load the scalar. - SDValue LoadScalar = DAG.getLoad(Extract->getValueType(0), dl, Ch, ScalarAddr, - NULL, 0, false, false, 0); + SDValue LoadScalar = DAG.getLoad(Extract->getValueType(0), dl, Ch, + ScalarAddr, NULL, 0, false, false, 0); // Replace the exact with the load. DAG.ReplaceAllUsesOfValueWith(SDValue(Extract, 0), LoadScalar); @@ -9087,8 +9942,7 @@ static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG &DAG, // Converting this to a min would handle NaNs incorrectly, and swapping // the operands would cause it to handle comparisons between positive // and negative zero incorrectly. - if (!FiniteOnlyFPMath() && - (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))) { + if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS)) { if (!UnsafeFPMath && !(DAG.isKnownNeverZero(LHS) || DAG.isKnownNeverZero(RHS))) break; @@ -9126,8 +9980,7 @@ static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG &DAG, // Converting this to a max would handle NaNs incorrectly, and swapping // the operands would cause it to handle comparisons between positive // and negative zero incorrectly. - if (!FiniteOnlyFPMath() && - (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))) { + if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS)) { if (!UnsafeFPMath && !(DAG.isKnownNeverZero(LHS) || DAG.isKnownNeverZero(RHS))) break; @@ -9156,8 +10009,7 @@ static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG &DAG, // cause it to handle NaNs incorrectly. if (!UnsafeFPMath && !(DAG.isKnownNeverZero(LHS) || DAG.isKnownNeverZero(RHS))) { - if (!FiniteOnlyFPMath() && - (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))) + if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS)) break; std::swap(LHS, RHS); } @@ -9182,8 +10034,7 @@ static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG &DAG, case ISD::SETULT: // Converting this to a max would handle NaNs incorrectly. - if (!FiniteOnlyFPMath() && - (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))) + if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS)) break; Opcode = X86ISD::FMAX; break; @@ -9193,8 +10044,7 @@ static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG &DAG, // cause it to handle NaNs incorrectly. if (!UnsafeFPMath && !DAG.isKnownNeverZero(LHS) && !DAG.isKnownNeverZero(RHS)) { - if (!FiniteOnlyFPMath() && - (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))) + if (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS)) break; std::swap(LHS, RHS); } @@ -9905,7 +10755,6 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N, SelectionDAG &DAG = DCI.DAG; switch (N->getOpcode()) { default: break; - case ISD::VECTOR_SHUFFLE: return PerformShuffleCombine(N, DAG, *this); case ISD::EXTRACT_VECTOR_ELT: return PerformEXTRACT_VECTOR_ELTCombine(N, DAG, *this); case ISD::SELECT: return PerformSELECTCombine(N, DAG, Subtarget); @@ -9922,6 +10771,28 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N, case X86ISD::BT: return PerformBTCombine(N, DAG, DCI); case X86ISD::VZEXT_MOVL: return PerformVZEXT_MOVLCombine(N, DAG); case ISD::ZERO_EXTEND: return PerformZExtCombine(N, DAG); + case X86ISD::SHUFPS: // Handle all target specific shuffles + case X86ISD::SHUFPD: + case X86ISD::PUNPCKHBW: + case X86ISD::PUNPCKHWD: + case X86ISD::PUNPCKHDQ: + case X86ISD::PUNPCKHQDQ: + case X86ISD::UNPCKHPS: + case X86ISD::UNPCKHPD: + case X86ISD::PUNPCKLBW: + case X86ISD::PUNPCKLWD: + case X86ISD::PUNPCKLDQ: + case X86ISD::PUNPCKLQDQ: + case X86ISD::UNPCKLPS: + case X86ISD::UNPCKLPD: + case X86ISD::MOVHLPS: + case X86ISD::MOVLHPS: + case X86ISD::PSHUFD: + case X86ISD::PSHUFHW: + case X86ISD::PSHUFLW: + case X86ISD::MOVSS: + case X86ISD::MOVSD: + case ISD::VECTOR_SHUFFLE: return PerformShuffleCombine(N, DAG, *this); } return SDValue(); @@ -9956,14 +10827,6 @@ bool X86TargetLowering::isTypeDesirableForOp(unsigned Opc, EVT VT) const { } } -static bool MayFoldLoad(SDValue Op) { - return Op.hasOneUse() && ISD::isNormalLoad(Op.getNode()); -} - -static bool MayFoldIntoStore(SDValue Op) { - return Op.hasOneUse() && ISD::isNormalStore(*Op.getNode()->use_begin()); -} - /// IsDesirableToPromoteOp - This method query the target whether it is /// beneficial for dag combiner to promote the specified node. If true, it /// should return the desired promotion type by reference. diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index 4e4daa4..d2d9b28 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -248,6 +248,44 @@ namespace llvm { // PTEST - Vector bitwise comparisons PTEST, + // TESTP - Vector packed fp sign bitwise comparisons + TESTP, + + // Several flavors of instructions with vector shuffle behaviors. + PALIGN, + PSHUFD, + PSHUFHW, + PSHUFLW, + PSHUFHW_LD, + PSHUFLW_LD, + SHUFPD, + SHUFPS, + MOVDDUP, + MOVSHDUP, + MOVSLDUP, + MOVSHDUP_LD, + MOVSLDUP_LD, + MOVLHPS, + MOVLHPD, + MOVHLPS, + MOVHLPD, + MOVLPS, + MOVLPD, + MOVSD, + MOVSS, + UNPCKLPS, + UNPCKLPD, + UNPCKHPS, + UNPCKHPD, + PUNPCKLBW, + PUNPCKLWD, + PUNPCKLDQ, + PUNPCKLQDQ, + PUNPCKHBW, + PUNPCKHWD, + PUNPCKHDQ, + PUNPCKHQDQ, + // VASTART_SAVE_XMM_REGS - Save xmm argument registers to the stack, // according to %al. An operator is needed so that this can be expanded // with control flow. @@ -265,7 +303,13 @@ namespace llvm { ATOMXOR64_DAG, ATOMAND64_DAG, ATOMNAND64_DAG, - ATOMSWAP64_DAG + ATOMSWAP64_DAG, + + // Memory barrier + MEMBARRIER, + MFENCE, + SFENCE, + LFENCE // WARNING: Do not add anything in the end unless you want the node to // have memop! In fact, starting from ATOMADD64_DAG all opcodes will be @@ -584,12 +628,19 @@ namespace llvm { /// getFunctionAlignment - Return the Log2 alignment of this function. virtual unsigned getFunctionAlignment(const Function *F) const; + unsigned getRegPressureLimit(const TargetRegisterClass *RC, + MachineFunction &MF) const; + /// getStackCookieLocation - Return true if the target stores stack /// protector cookies at a fixed offset in some non-standard address /// space, and populates the address space and offset as /// appropriate. virtual bool getStackCookieLocation(unsigned &AddressSpace, unsigned &Offset) const; + protected: + std::pair + findRepresentativeClass(EVT VT) const; + private: /// Subtarget - Keep a pointer to the X86Subtarget around so that we can /// make the right decision when generating code for different targets. @@ -710,11 +761,16 @@ namespace llvm { SDValue LowerCTLZ(SDValue Op, SelectionDAG &DAG) const; SDValue LowerCTTZ(SDValue Op, SelectionDAG &DAG) const; SDValue LowerMUL_V2I64(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerSHL(SDValue Op, SelectionDAG &DAG) const; SDValue LowerXALUO(SDValue Op, SelectionDAG &DAG) const; SDValue LowerCMP_SWAP(SDValue Op, SelectionDAG &DAG) const; SDValue LowerLOAD_SUB(SDValue Op, SelectionDAG &DAG) const; SDValue LowerREADCYCLECOUNTER(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerMEMBARRIER(SDValue Op, SelectionDAG &DAG) const; + + // Utility functions to help LowerVECTOR_SHUFFLE + SDValue LowerVECTOR_SHUFFLEv8i16(SDValue Op, SelectionDAG &DAG) const; virtual SDValue LowerFormalArguments(SDValue Chain, diff --git a/lib/Target/X86/X86Instr64bit.td b/lib/Target/X86/X86Instr64bit.td index 42d0e7f..0884b61 100644 --- a/lib/Target/X86/X86Instr64bit.td +++ b/lib/Target/X86/X86Instr64bit.td @@ -73,11 +73,7 @@ def GetLo32XForm : SDNodeXFormgetZExtValue()); }]>; -def i64immSExt32 : PatLeaf<(i64 imm), [{ - // i64immSExt32 predicate - True if the 64-bit immediate fits in a 32-bit - // sign extended field. - return (int64_t)N->getZExtValue() == (int32_t)N->getZExtValue(); -}]>; +def i64immSExt32 : PatLeaf<(i64 imm), [{ return i64immSExt32(N); }]>; def i64immZExt32 : PatLeaf<(i64 imm), [{ @@ -158,7 +154,7 @@ let isCall = 1 in // FIXME: We need to teach codegen about single list of call-clobbered // registers. -let isCall = 1 in +let isCall = 1, isCodeGenOnly = 1 in // All calls clobber the non-callee saved registers. RSP is marked as // a use to prevent stack-pointer assignments that appear immediately // before calls from potentially appearing dead. Uses for argument @@ -168,7 +164,7 @@ let isCall = 1 in MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, EFLAGS], Uses = [RSP] in { - def WINCALL64pcrel32 : I<0xE8, RawFrm, + def WINCALL64pcrel32 : Ii32PCRel<0xE8, RawFrm, (outs), (ins i64i32imm_pcrel:$dst, variable_ops), "call\t$dst", []>, Requires<[IsWin64]>; @@ -182,7 +178,8 @@ let isCall = 1 in } -let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in +let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, + isCodeGenOnly = 1 in let Defs = [RAX, RCX, RDX, RSI, RDI, R8, R9, R10, R11, FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0, ST1, MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, @@ -216,9 +213,9 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { def JMP64pcrel32 : I<0xE9, RawFrm, (outs), (ins brtarget:$dst), "jmp{q}\t$dst", []>; def JMP64r : I<0xFF, MRM4r, (outs), (ins GR64:$dst), "jmp{q}\t{*}$dst", - [(brind GR64:$dst)]>; + [(brind GR64:$dst)]>, Requires<[In64BitMode]>; def JMP64m : I<0xFF, MRM4m, (outs), (ins i64mem:$dst), "jmp{q}\t{*}$dst", - [(brind (loadi64 addr:$dst))]>; + [(brind (loadi64 addr:$dst))]>, Requires<[In64BitMode]>; def FARJMP64 : RI<0xFF, MRM5m, (outs), (ins opaque80mem:$dst), "ljmp{q}\t{*}$dst", []>; } @@ -246,7 +243,7 @@ def POPCNT64rm : RI<0xB8, MRMSrcMem, (outs GR64:$dst), (ins i64mem:$src), let Defs = [RBP,RSP], Uses = [RBP,RSP], mayLoad = 1, neverHasSideEffects = 1 in def LEAVE64 : I<0xC9, RawFrm, - (outs), (ins), "leave", []>; + (outs), (ins), "leave", []>, Requires<[In64BitMode]>; let Defs = [RSP], Uses = [RSP], neverHasSideEffects=1 in { let mayLoad = 1 in { def POP64r : I<0x58, AddRegFrm, @@ -330,7 +327,7 @@ def CMPS64 : RI<0xA7, RawFrm, (outs), (ins), "cmpsq", []>; // Fast system-call instructions def SYSEXIT64 : RI<0x35, RawFrm, - (outs), (ins), "sysexit", []>, TB; + (outs), (ins), "sysexit", []>, TB, Requires<[In64BitMode]>; //===----------------------------------------------------------------------===// // Move Instructions... @@ -374,6 +371,7 @@ def MOV64mi32 : RIi32<0xC7, MRM0m, (outs), (ins i64mem:$dst, i64i32imm:$src), [(store i64immSExt32:$src, addr:$dst)]>; /// Versions of MOV64rr, MOV64rm, and MOV64mr for i64mem_TC and GR64_TC. +let isCodeGenOnly = 1 in { let neverHasSideEffects = 1 in def MOV64rr_TC : RI<0x89, MRMDestReg, (outs GR64_TC:$dst), (ins GR64_TC:$src), "mov{q}\t{$src, $dst|$dst, $src}", []>; @@ -388,7 +386,13 @@ let mayStore = 1 in def MOV64mr_TC : RI<0x89, MRMDestMem, (outs), (ins i64mem_TC:$dst, GR64_TC:$src), "mov{q}\t{$src, $dst|$dst, $src}", []>; +} +// FIXME: These definitions are utterly broken +// Just leave them commented out for now because they're useless outside +// of the large code model, and most compilers won't generate the instructions +// in question. +/* def MOV64o8a : RIi8<0xA0, RawFrm, (outs), (ins offset8:$src), "mov{q}\t{$src, %rax|%rax, $src}", []>; def MOV64o64a : RIi32<0xA1, RawFrm, (outs), (ins offset64:$src), @@ -397,6 +401,7 @@ def MOV64ao8 : RIi8<0xA2, RawFrm, (outs offset8:$dst), (ins), "mov{q}\t{%rax, $dst|$dst, %rax}", []>; def MOV64ao64 : RIi32<0xA3, RawFrm, (outs offset64:$dst), (ins), "mov{q}\t{%rax, $dst|$dst, %rax}", []>; +*/ // Moves to and from segment registers def MOV64rs : RI<0x8C, MRMDestReg, (outs GR64:$dst), (ins SEGMENT_REG:$src), @@ -1316,14 +1321,13 @@ def BT64mr : RI<0xA3, MRMDestMem, (outs), (ins i64mem:$src1, GR64:$src2), [] >, TB; -def BT64ri8 : Ii8<0xBA, MRM4r, (outs), (ins GR64:$src1, i64i8imm:$src2), +def BT64ri8 : RIi8<0xBA, MRM4r, (outs), (ins GR64:$src1, i64i8imm:$src2), "bt{q}\t{$src2, $src1|$src1, $src2}", - [(set EFLAGS, (X86bt GR64:$src1, i64immSExt8:$src2))]>, TB, - REX_W; + [(set EFLAGS, (X86bt GR64:$src1, i64immSExt8:$src2))]>, TB; // Note that these instructions don't need FastBTMem because that // only applies when the other operand is in a register. When it's // an immediate, bt is still fast. -def BT64mi8 : Ii8<0xBA, MRM4m, (outs), (ins i64mem:$src1, i64i8imm:$src2), +def BT64mi8 : RIi8<0xBA, MRM4m, (outs), (ins i64mem:$src1, i64i8imm:$src2), "bt{q}\t{$src2, $src1|$src1, $src2}", [(set EFLAGS, (X86bt (loadi64 addr:$src1), i64immSExt8:$src2))]>, TB; @@ -1537,116 +1541,6 @@ def : Pat<(i64 (anyext (i8 (X86setcc_c X86_COND_B, EFLAGS)))), (SETB_C64r)>; //===----------------------------------------------------------------------===// -// Conversion Instructions... -// - -// f64 -> signed i64 -def CVTSD2SI64rr: RSDI<0x2D, MRMSrcReg, (outs GR64:$dst), (ins FR64:$src), - "cvtsd2si{q}\t{$src, $dst|$dst, $src}", []>; -def CVTSD2SI64rm: RSDI<0x2D, MRMSrcMem, (outs GR64:$dst), (ins f64mem:$src), - "cvtsd2si{q}\t{$src, $dst|$dst, $src}", []>; -def Int_CVTSD2SI64rr: RSDI<0x2D, MRMSrcReg, (outs GR64:$dst), (ins VR128:$src), - "cvtsd2si{q}\t{$src, $dst|$dst, $src}", - [(set GR64:$dst, - (int_x86_sse2_cvtsd2si64 VR128:$src))]>; -def Int_CVTSD2SI64rm: RSDI<0x2D, MRMSrcMem, (outs GR64:$dst), - (ins f128mem:$src), - "cvtsd2si{q}\t{$src, $dst|$dst, $src}", - [(set GR64:$dst, (int_x86_sse2_cvtsd2si64 - (load addr:$src)))]>; -def CVTTSD2SI64rr: RSDI<0x2C, MRMSrcReg, (outs GR64:$dst), (ins FR64:$src), - "cvttsd2si{q}\t{$src, $dst|$dst, $src}", - [(set GR64:$dst, (fp_to_sint FR64:$src))]>; -def CVTTSD2SI64rm: RSDI<0x2C, MRMSrcMem, (outs GR64:$dst), (ins f64mem:$src), - "cvttsd2si{q}\t{$src, $dst|$dst, $src}", - [(set GR64:$dst, (fp_to_sint (loadf64 addr:$src)))]>; -def Int_CVTTSD2SI64rr: RSDI<0x2C, MRMSrcReg, (outs GR64:$dst), (ins VR128:$src), - "cvttsd2si{q}\t{$src, $dst|$dst, $src}", - [(set GR64:$dst, - (int_x86_sse2_cvttsd2si64 VR128:$src))]>; -def Int_CVTTSD2SI64rm: RSDI<0x2C, MRMSrcMem, (outs GR64:$dst), - (ins f128mem:$src), - "cvttsd2si{q}\t{$src, $dst|$dst, $src}", - [(set GR64:$dst, - (int_x86_sse2_cvttsd2si64 - (load addr:$src)))]>; - -// Signed i64 -> f64 -def CVTSI2SD64rr: RSDI<0x2A, MRMSrcReg, (outs FR64:$dst), (ins GR64:$src), - "cvtsi2sd{q}\t{$src, $dst|$dst, $src}", - [(set FR64:$dst, (sint_to_fp GR64:$src))]>; -def CVTSI2SD64rm: RSDI<0x2A, MRMSrcMem, (outs FR64:$dst), (ins i64mem:$src), - "cvtsi2sd{q}\t{$src, $dst|$dst, $src}", - [(set FR64:$dst, (sint_to_fp (loadi64 addr:$src)))]>; - -let Constraints = "$src1 = $dst" in { -def Int_CVTSI2SD64rr: RSDI<0x2A, MRMSrcReg, - (outs VR128:$dst), (ins VR128:$src1, GR64:$src2), - "cvtsi2sd{q}\t{$src2, $dst|$dst, $src2}", - [(set VR128:$dst, - (int_x86_sse2_cvtsi642sd VR128:$src1, - GR64:$src2))]>; -def Int_CVTSI2SD64rm: RSDI<0x2A, MRMSrcMem, - (outs VR128:$dst), (ins VR128:$src1, i64mem:$src2), - "cvtsi2sd{q}\t{$src2, $dst|$dst, $src2}", - [(set VR128:$dst, - (int_x86_sse2_cvtsi642sd VR128:$src1, - (loadi64 addr:$src2)))]>; -} // Constraints = "$src1 = $dst" - -// Signed i64 -> f32 -def CVTSI2SS64rr: RSSI<0x2A, MRMSrcReg, (outs FR32:$dst), (ins GR64:$src), - "cvtsi2ss{q}\t{$src, $dst|$dst, $src}", - [(set FR32:$dst, (sint_to_fp GR64:$src))]>; -def CVTSI2SS64rm: RSSI<0x2A, MRMSrcMem, (outs FR32:$dst), (ins i64mem:$src), - "cvtsi2ss{q}\t{$src, $dst|$dst, $src}", - [(set FR32:$dst, (sint_to_fp (loadi64 addr:$src)))]>; - -let Constraints = "$src1 = $dst" in { - def Int_CVTSI2SS64rr : RSSI<0x2A, MRMSrcReg, - (outs VR128:$dst), (ins VR128:$src1, GR64:$src2), - "cvtsi2ss{q}\t{$src2, $dst|$dst, $src2}", - [(set VR128:$dst, - (int_x86_sse_cvtsi642ss VR128:$src1, - GR64:$src2))]>; - def Int_CVTSI2SS64rm : RSSI<0x2A, MRMSrcMem, - (outs VR128:$dst), - (ins VR128:$src1, i64mem:$src2), - "cvtsi2ss{q}\t{$src2, $dst|$dst, $src2}", - [(set VR128:$dst, - (int_x86_sse_cvtsi642ss VR128:$src1, - (loadi64 addr:$src2)))]>; -} // Constraints = "$src1 = $dst" - -// f32 -> signed i64 -def CVTSS2SI64rr: RSSI<0x2D, MRMSrcReg, (outs GR64:$dst), (ins FR32:$src), - "cvtss2si{q}\t{$src, $dst|$dst, $src}", []>; -def CVTSS2SI64rm: RSSI<0x2D, MRMSrcMem, (outs GR64:$dst), (ins f32mem:$src), - "cvtss2si{q}\t{$src, $dst|$dst, $src}", []>; -def Int_CVTSS2SI64rr: RSSI<0x2D, MRMSrcReg, (outs GR64:$dst), (ins VR128:$src), - "cvtss2si{q}\t{$src, $dst|$dst, $src}", - [(set GR64:$dst, - (int_x86_sse_cvtss2si64 VR128:$src))]>; -def Int_CVTSS2SI64rm: RSSI<0x2D, MRMSrcMem, (outs GR64:$dst), (ins f32mem:$src), - "cvtss2si{q}\t{$src, $dst|$dst, $src}", - [(set GR64:$dst, (int_x86_sse_cvtss2si64 - (load addr:$src)))]>; -def CVTTSS2SI64rr: RSSI<0x2C, MRMSrcReg, (outs GR64:$dst), (ins FR32:$src), - "cvttss2si{q}\t{$src, $dst|$dst, $src}", - [(set GR64:$dst, (fp_to_sint FR32:$src))]>; -def CVTTSS2SI64rm: RSSI<0x2C, MRMSrcMem, (outs GR64:$dst), (ins f32mem:$src), - "cvttss2si{q}\t{$src, $dst|$dst, $src}", - [(set GR64:$dst, (fp_to_sint (loadf32 addr:$src)))]>; -def Int_CVTTSS2SI64rr: RSSI<0x2C, MRMSrcReg, (outs GR64:$dst), (ins VR128:$src), - "cvttss2si{q}\t{$src, $dst|$dst, $src}", - [(set GR64:$dst, - (int_x86_sse_cvttss2si64 VR128:$src))]>; -def Int_CVTTSS2SI64rm: RSSI<0x2C, MRMSrcMem, (outs GR64:$dst), - (ins f32mem:$src), - "cvttss2si{q}\t{$src, $dst|$dst, $src}", - [(set GR64:$dst, - (int_x86_sse_cvttss2si64 (load addr:$src)))]>; - // Descriptor-table support instructions // LLDT is not interpreted specially in 64-bit mode because there is no sign @@ -1726,6 +1620,14 @@ def MOV64FSrm : RI<0x8B, MRMSrcMem, (outs GR64:$dst), (ins i64mem:$src), // Atomic Instructions //===----------------------------------------------------------------------===// +// TODO: Get this to fold the constant into the instruction. +let hasSideEffects = 1, Defs = [ESP] in +def Int_MemBarrierNoSSE64 : RI<0x09, MRM1r, (outs), (ins GR64:$zero), + "lock\n\t" + "or{q}\t{$zero, (%rsp)|(%rsp), $zero}", + [(X86MemBarrierNoSSE GR64:$zero)]>, + Requires<[In64BitMode]>, LOCK; + let Defs = [RAX, EFLAGS], Uses = [RAX] in { def LCMPXCHG64 : RI<0xB1, MRMDestMem, (outs), (ins i64mem:$ptr, GR64:$swap), "lock\n\t" @@ -1772,7 +1674,7 @@ def XCHG64ar : RI<0x90, AddRegFrm, (outs), (ins GR64:$src), // Optimized codegen when the non-memory output is not used. let Defs = [EFLAGS], mayLoad = 1, mayStore = 1 in { // FIXME: Use normal add / sub instructions and add lock prefix dynamically. -def LOCK_ADD64mr : RI<0x03, MRMDestMem, (outs), (ins i64mem:$dst, GR64:$src2), +def LOCK_ADD64mr : RI<0x01, MRMDestMem, (outs), (ins i64mem:$dst, GR64:$src2), "lock\n\t" "add{q}\t{$src2, $dst|$dst, $src2}", []>, LOCK; def LOCK_ADD64mi8 : RIi8<0x83, MRM0m, (outs), diff --git a/lib/Target/X86/X86InstrFMA.td b/lib/Target/X86/X86InstrFMA.td new file mode 100644 index 0000000..d868773 --- /dev/null +++ b/lib/Target/X86/X86InstrFMA.td @@ -0,0 +1,60 @@ +//====- X86InstrFMA.td - Describe the X86 Instruction Set --*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes FMA (Fused Multiply-Add) instructions. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// FMA3 - Intel 3 operand Fused Multiply-Add instructions +//===----------------------------------------------------------------------===// + +multiclass fma_rm opc, string OpcodeStr> { + def r : FMA3; + def m : FMA3; + def rY : FMA3; + def mY : FMA3; +} + +multiclass fma_forms opc132, bits<8> opc213, bits<8> opc231, + string OpcodeStr, string PackTy> { + defm r132 : fma_rm; + defm r213 : fma_rm; + defm r231 : fma_rm; +} + +let isAsmParserOnly = 1 in { + // Fused Multiply-Add + defm VFMADDPS : fma_forms<0x98, 0xA8, 0xB8, "vfmadd", "ps">; + defm VFMADDPD : fma_forms<0x98, 0xA8, 0xB8, "vfmadd", "pd">, VEX_W; + defm VFMADDSUBPS : fma_forms<0x96, 0xA6, 0xB6, "vfmaddsub", "ps">; + defm VFMADDSUBPD : fma_forms<0x96, 0xA6, 0xB6, "vfmaddsub", "pd">, VEX_W; + defm VFMSUBADDPS : fma_forms<0x97, 0xA7, 0xB7, "vfmsubadd", "ps">; + defm VFMSUBADDPD : fma_forms<0x97, 0xA7, 0xB7, "vfmsubadd", "pd">, VEX_W; + defm VFMSUBPS : fma_forms<0x9A, 0xAA, 0xBA, "vfmsub", "ps">; + defm VFMSUBPD : fma_forms<0x9A, 0xAA, 0xBA, "vfmsub", "pd">, VEX_W; + + // Fused Negative Multiply-Add + defm VFNMADDPS : fma_forms<0x9C, 0xAC, 0xBC, "vfnmadd", "ps">; + defm VFNMADDPD : fma_forms<0x9C, 0xAC, 0xBC, "vfnmadd", "pd">, VEX_W; + defm VFNMSUBPS : fma_forms<0x9E, 0xAE, 0xBE, "vfnmsub", "ps">; + defm VFNMSUBPD : fma_forms<0x9E, 0xAE, 0xBE, "vfnmsub", "pd">, VEX_W; +} diff --git a/lib/Target/X86/X86InstrFPStack.td b/lib/Target/X86/X86InstrFPStack.td index da93de9..9c9bcc7 100644 --- a/lib/Target/X86/X86InstrFPStack.td +++ b/lib/Target/X86/X86InstrFPStack.td @@ -108,10 +108,6 @@ let usesCustomInserter = 1 in { // Expanded after instruction selection. [(X86fp_to_i64mem RFP80:$src, addr:$dst)]>; } -let isTerminator = 1 in - let Defs = [FP0, FP1, FP2, FP3, FP4, FP5, FP6] in - def FP_REG_KILL : I<0, Pseudo, (outs), (ins), "##FP_REG_KILL", []>; - // All FP Stack operations are represented with four instructions here. The // first three instructions, generated by the instruction selector, use "RFP32" // "RFP64" or "RFP80" registers: traditional register files to reference 32-bit, @@ -157,7 +153,7 @@ def FpSET_ST1_64 : FpI_<(outs), (ins RFP64:$src), SpecialFP, []>; // ST(1) = FPR def FpSET_ST1_80 : FpI_<(outs), (ins RFP80:$src), SpecialFP, []>; // ST(1) = FPR } -// FpIf32, FpIf64 - Floating Point Psuedo Instruction template. +// FpIf32, FpIf64 - Floating Point Pseudo Instruction template. // f32 instructions can use SSE1 and are predicated on FPStackf32 == !SSE1. // f64 instructions can use SSE2 and are predicated on FPStackf64 == !SSE2. // f80 instructions cannot use SSE and use neither of these. diff --git a/lib/Target/X86/X86InstrFormats.td b/lib/Target/X86/X86InstrFormats.td index cc3fdf1..79187e9 100644 --- a/lib/Target/X86/X86InstrFormats.td +++ b/lib/Target/X86/X86InstrFormats.td @@ -39,6 +39,7 @@ def MRM_E8 : Format<39>; def MRM_F0 : Format<40>; def MRM_F8 : Format<41>; def MRM_F9 : Format<42>; +def RawFrmImm16 : Format<43>; // ImmType - This specifies the immediate type used by an instruction. This is // part of the ad-hoc solution used to emit machine instruction encodings by our @@ -210,7 +211,7 @@ class Ii32PCRel o, Format f, dag outs, dag ins, string asm, class FPI o, Format F, dag outs, dag ins, string asm> : I {} -// FpI_ - Floating Point Psuedo Instruction template. Not Predicated. +// FpI_ - Floating Point Pseudo Instruction template. Not Predicated. class FpI_ pattern> : X86Inst<0, Pseudo, NoImm, outs, ins, ""> { let FPForm = fp; @@ -224,13 +225,13 @@ class FpI_ pattern> // Iseg32 - 16-bit segment selector, 32-bit offset class Iseg16 o, Format f, dag outs, dag ins, string asm, - list pattern> : X86Inst { + list pattern> : X86Inst { let Pattern = pattern; let CodeSize = 3; } class Iseg32 o, Format f, dag outs, dag ins, string asm, - list pattern> : X86Inst { + list pattern> : X86Inst { let Pattern = pattern; let CodeSize = 3; } @@ -411,6 +412,20 @@ class SS42AI o, Format F, dag outs, dag ins, string asm, : Ii8, TA, Requires<[HasSSE42]>; +// AVX Instruction Templates: +// Instructions introduced in AVX (no SSE equivalent forms) +// +// AVX8I - AVX instructions with T8 and OpSize prefix. +// AVXAIi8 - AVX instructions with TA, OpSize prefix and ImmT = Imm8. +class AVX8I o, Format F, dag outs, dag ins, string asm, + list pattern> + : I, T8, OpSize, + Requires<[HasAVX]>; +class AVXAIi8 o, Format F, dag outs, dag ins, string asm, + list pattern> + : Ii8, TA, OpSize, + Requires<[HasAVX]>; + // AES Instruction Templates: // // AES8I @@ -425,6 +440,18 @@ class AESAI o, Format F, dag outs, dag ins, string asm, : Ii8, TA, Requires<[HasAES]>; +// CLMUL Instruction Templates +class CLMULIi8 o, Format F, dag outs, dag ins, string asm, + listpattern> + : Ii8, TA, + OpSize, VEX_4V, Requires<[HasAVX, HasCLMUL]>; + +// FMA3 Instruction Templates +class FMA3 o, Format F, dag outs, dag ins, string asm, + listpattern> + : I, T8, + OpSize, VEX_4V, Requires<[HasFMA3]>; + // X86-64 Instruction templates... // diff --git a/lib/Target/X86/X86InstrFragmentsSIMD.td b/lib/Target/X86/X86InstrFragmentsSIMD.td index 71c4e8b..01149b6 100644 --- a/lib/Target/X86/X86InstrFragmentsSIMD.td +++ b/lib/Target/X86/X86InstrFragmentsSIMD.td @@ -117,9 +117,67 @@ def X86pcmpgtd : SDNode<"X86ISD::PCMPGTD", SDTIntBinOp>; def X86pcmpgtq : SDNode<"X86ISD::PCMPGTQ", SDTIntBinOp>; def SDTX86CmpPTest : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, - SDTCisVT<1, v4f32>, - SDTCisVT<2, v4f32>]>; + SDTCisVec<1>, + SDTCisSameAs<2, 1>]>; def X86ptest : SDNode<"X86ISD::PTEST", SDTX86CmpPTest>; +def X86testp : SDNode<"X86ISD::TESTP", SDTX86CmpPTest>; + +// Specific shuffle nodes - At some point ISD::VECTOR_SHUFFLE will always get +// translated into one of the target nodes below during lowering. +// Note: this is a work in progress... +def SDTShuff1Op : SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisSameAs<0,1>]>; +def SDTShuff2Op : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisSameAs<0,1>, + SDTCisSameAs<0,2>]>; + +def SDTShuff2OpI : SDTypeProfile<1, 2, [SDTCisVec<0>, + SDTCisSameAs<0,1>, SDTCisInt<2>]>; +def SDTShuff3OpI : SDTypeProfile<1, 3, [SDTCisVec<0>, SDTCisSameAs<0,1>, + SDTCisSameAs<0,2>, SDTCisInt<3>]>; + +def SDTShuff2OpLdI : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisPtrTy<1>, + SDTCisInt<2>]>; + +def X86PAlign : SDNode<"X86ISD::PALIGN", SDTShuff3OpI>; + +def X86PShufd : SDNode<"X86ISD::PSHUFD", SDTShuff2OpI>; +def X86PShufhw : SDNode<"X86ISD::PSHUFHW", SDTShuff2OpI>; +def X86PShuflw : SDNode<"X86ISD::PSHUFLW", SDTShuff2OpI>; + +def X86PShufhwLd : SDNode<"X86ISD::PSHUFHW_LD", SDTShuff2OpLdI>; +def X86PShuflwLd : SDNode<"X86ISD::PSHUFLW_LD", SDTShuff2OpLdI>; + +def X86Shufpd : SDNode<"X86ISD::SHUFPD", SDTShuff3OpI>; +def X86Shufps : SDNode<"X86ISD::SHUFPS", SDTShuff3OpI>; + +def X86Movddup : SDNode<"X86ISD::MOVDDUP", SDTShuff1Op>; +def X86Movshdup : SDNode<"X86ISD::MOVSHDUP", SDTShuff1Op>; +def X86Movsldup : SDNode<"X86ISD::MOVSLDUP", SDTShuff1Op>; + +def X86Movsd : SDNode<"X86ISD::MOVSD", SDTShuff2Op>; +def X86Movss : SDNode<"X86ISD::MOVSS", SDTShuff2Op>; + +def X86Movlhps : SDNode<"X86ISD::MOVLHPS", SDTShuff2Op>; +def X86Movlhpd : SDNode<"X86ISD::MOVLHPD", SDTShuff2Op>; +def X86Movhlps : SDNode<"X86ISD::MOVHLPS", SDTShuff2Op>; +def X86Movhlpd : SDNode<"X86ISD::MOVHLPD", SDTShuff2Op>; + +def X86Movlps : SDNode<"X86ISD::MOVLPS", SDTShuff2Op>; +def X86Movlpd : SDNode<"X86ISD::MOVLPD", SDTShuff2Op>; + +def X86Unpcklps : SDNode<"X86ISD::UNPCKLPS", SDTShuff2Op>; +def X86Unpcklpd : SDNode<"X86ISD::UNPCKLPD", SDTShuff2Op>; +def X86Unpckhps : SDNode<"X86ISD::UNPCKHPS", SDTShuff2Op>; +def X86Unpckhpd : SDNode<"X86ISD::UNPCKHPD", SDTShuff2Op>; + +def X86Punpcklbw : SDNode<"X86ISD::PUNPCKLBW", SDTShuff2Op>; +def X86Punpcklwd : SDNode<"X86ISD::PUNPCKLWD", SDTShuff2Op>; +def X86Punpckldq : SDNode<"X86ISD::PUNPCKLDQ", SDTShuff2Op>; +def X86Punpcklqdq : SDNode<"X86ISD::PUNPCKLQDQ", SDTShuff2Op>; + +def X86Punpckhbw : SDNode<"X86ISD::PUNPCKHBW", SDTShuff2Op>; +def X86Punpckhwd : SDNode<"X86ISD::PUNPCKHWD", SDTShuff2Op>; +def X86Punpckhdq : SDNode<"X86ISD::PUNPCKHDQ", SDTShuff2Op>; +def X86Punpckhqdq : SDNode<"X86ISD::PUNPCKHQDQ", SDTShuff2Op>; //===----------------------------------------------------------------------===// // SSE Complex Patterns @@ -148,12 +206,13 @@ def sdmem : Operand { // SSE pattern fragments //===----------------------------------------------------------------------===// +// 128-bit load pattern fragments def loadv4f32 : PatFrag<(ops node:$ptr), (v4f32 (load node:$ptr))>; def loadv2f64 : PatFrag<(ops node:$ptr), (v2f64 (load node:$ptr))>; def loadv4i32 : PatFrag<(ops node:$ptr), (v4i32 (load node:$ptr))>; def loadv2i64 : PatFrag<(ops node:$ptr), (v2i64 (load node:$ptr))>; -// FIXME: move this to a more appropriate place after all AVX is done. +// 256-bit load pattern fragments def loadv8f32 : PatFrag<(ops node:$ptr), (v8f32 (load node:$ptr))>; def loadv4f64 : PatFrag<(ops node:$ptr), (v4f64 (load node:$ptr))>; def loadv8i32 : PatFrag<(ops node:$ptr), (v8i32 (load node:$ptr))>; @@ -174,6 +233,8 @@ def alignedloadfsf32 : PatFrag<(ops node:$ptr), (f32 (alignedload node:$ptr))>; def alignedloadfsf64 : PatFrag<(ops node:$ptr), (f64 (alignedload node:$ptr))>; + +// 128-bit aligned load pattern fragments def alignedloadv4f32 : PatFrag<(ops node:$ptr), (v4f32 (alignedload node:$ptr))>; def alignedloadv2f64 : PatFrag<(ops node:$ptr), @@ -183,7 +244,7 @@ def alignedloadv4i32 : PatFrag<(ops node:$ptr), def alignedloadv2i64 : PatFrag<(ops node:$ptr), (v2i64 (alignedload node:$ptr))>; -// FIXME: move this to a more appropriate place after all AVX is done. +// 256-bit aligned load pattern fragments def alignedloadv8f32 : PatFrag<(ops node:$ptr), (v8f32 (alignedload node:$ptr))>; def alignedloadv4f64 : PatFrag<(ops node:$ptr), @@ -206,15 +267,20 @@ def memop : PatFrag<(ops node:$ptr), (load node:$ptr), [{ def memopfsf32 : PatFrag<(ops node:$ptr), (f32 (memop node:$ptr))>; def memopfsf64 : PatFrag<(ops node:$ptr), (f64 (memop node:$ptr))>; + +// 128-bit memop pattern fragments def memopv4f32 : PatFrag<(ops node:$ptr), (v4f32 (memop node:$ptr))>; def memopv2f64 : PatFrag<(ops node:$ptr), (v2f64 (memop node:$ptr))>; def memopv4i32 : PatFrag<(ops node:$ptr), (v4i32 (memop node:$ptr))>; def memopv2i64 : PatFrag<(ops node:$ptr), (v2i64 (memop node:$ptr))>; def memopv16i8 : PatFrag<(ops node:$ptr), (v16i8 (memop node:$ptr))>; -// FIXME: move this to a more appropriate place after all AVX is done. +// 256-bit memop pattern fragments +def memopv32i8 : PatFrag<(ops node:$ptr), (v32i8 (memop node:$ptr))>; def memopv8f32 : PatFrag<(ops node:$ptr), (v8f32 (memop node:$ptr))>; def memopv4f64 : PatFrag<(ops node:$ptr), (v4f64 (memop node:$ptr))>; +def memopv4i64 : PatFrag<(ops node:$ptr), (v4i64 (memop node:$ptr))>; +def memopv8i32 : PatFrag<(ops node:$ptr), (v8i32 (memop node:$ptr))>; // SSSE3 uses MMX registers for some instructions. They aren't aligned on a // 16-byte boundary. @@ -254,6 +320,7 @@ def unalignednontemporalstore : PatFrag<(ops node:$val, node:$ptr), return false; }]>; +// 128-bit bitconvert pattern fragments def bc_v4f32 : PatFrag<(ops node:$in), (v4f32 (bitconvert node:$in))>; def bc_v2f64 : PatFrag<(ops node:$in), (v2f64 (bitconvert node:$in))>; def bc_v16i8 : PatFrag<(ops node:$in), (v16i8 (bitconvert node:$in))>; @@ -261,6 +328,9 @@ def bc_v8i16 : PatFrag<(ops node:$in), (v8i16 (bitconvert node:$in))>; def bc_v4i32 : PatFrag<(ops node:$in), (v4i32 (bitconvert node:$in))>; def bc_v2i64 : PatFrag<(ops node:$in), (v2i64 (bitconvert node:$in))>; +// 256-bit bitconvert pattern fragments +def bc_v8i32 : PatFrag<(ops node:$in), (v8i32 (bitconvert node:$in))>; + def vzmovl_v2i64 : PatFrag<(ops node:$src), (bitconvert (v2i64 (X86vzmovl (v2i64 (scalar_to_vector (loadi64 node:$src))))))>; diff --git a/lib/Target/X86/X86InstrInfo.cpp b/lib/Target/X86/X86InstrInfo.cpp index ce471ea..5280940 100644 --- a/lib/Target/X86/X86InstrInfo.cpp +++ b/lib/Target/X86/X86InstrInfo.cpp @@ -235,6 +235,7 @@ X86InstrInfo::X86InstrInfo(X86TargetMachine &tm) { X86::BT64ri8, X86::BT64mi8, 1, 0 }, { X86::CALL32r, X86::CALL32m, 1, 0 }, { X86::CALL64r, X86::CALL64m, 1, 0 }, + { X86::WINCALL64r, X86::WINCALL64m, 1, 0 }, { X86::CMP16ri, X86::CMP16mi, 1, 0 }, { X86::CMP16ri8, X86::CMP16mi8, 1, 0 }, { X86::CMP16rr, X86::CMP16mr, 1, 0 }, @@ -667,46 +668,6 @@ X86InstrInfo::X86InstrInfo(X86TargetMachine &tm) assert(AmbEntries.empty() && "Duplicated entries in unfolding maps?"); } -bool X86InstrInfo::isMoveInstr(const MachineInstr& MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const { - switch (MI.getOpcode()) { - default: - return false; - case X86::MOV8rr: - case X86::MOV8rr_NOREX: - case X86::MOV16rr: - case X86::MOV32rr: - case X86::MOV64rr: - case X86::MOV32rr_TC: - case X86::MOV64rr_TC: - - // FP Stack register class copies - case X86::MOV_Fp3232: case X86::MOV_Fp6464: case X86::MOV_Fp8080: - case X86::MOV_Fp3264: case X86::MOV_Fp3280: - case X86::MOV_Fp6432: case X86::MOV_Fp8032: - - // Note that MOVSSrr and MOVSDrr are not considered copies. FR32 and FR64 - // copies are done with FsMOVAPSrr and FsMOVAPDrr. - - case X86::FsMOVAPSrr: - case X86::FsMOVAPDrr: - case X86::MOVAPSrr: - case X86::MOVAPDrr: - case X86::MOVDQArr: - case X86::MMX_MOVQ64rr: - assert(MI.getNumOperands() >= 2 && - MI.getOperand(0).isReg() && - MI.getOperand(1).isReg() && - "invalid register-register move instruction"); - SrcReg = MI.getOperand(1).getReg(); - DstReg = MI.getOperand(0).getReg(); - SrcSubIdx = MI.getOperand(1).getSubReg(); - DstSubIdx = MI.getOperand(0).getSubReg(); - return true; - } -} - bool X86InstrInfo::isCoalescableExtInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg, @@ -827,7 +788,7 @@ static bool isFrameStoreOpcode(int Opcode) { unsigned X86InstrInfo::isLoadFromStackSlot(const MachineInstr *MI, int &FrameIndex) const { if (isFrameLoadOpcode(MI->getOpcode())) - if (isFrameOperand(MI, 1, FrameIndex)) + if (MI->getOperand(0).getSubReg() == 0 && isFrameOperand(MI, 1, FrameIndex)) return MI->getOperand(0).getReg(); return 0; } @@ -866,7 +827,8 @@ bool X86InstrInfo::hasLoadFromStackSlot(const MachineInstr *MI, unsigned X86InstrInfo::isStoreToStackSlot(const MachineInstr *MI, int &FrameIndex) const { if (isFrameStoreOpcode(MI->getOpcode())) - if (isFrameOperand(MI, 0, FrameIndex)) + if (MI->getOperand(X86::AddrNumOperands).getSubReg() == 0 && + isFrameOperand(MI, 0, FrameIndex)) return MI->getOperand(X86::AddrNumOperands).getReg(); return 0; } @@ -1664,14 +1626,6 @@ bool X86InstrInfo::isUnpredicatedTerminator(const MachineInstr *MI) const { return !isPredicated(MI); } -// For purposes of branch analysis do not count FP_REG_KILL as a terminator. -static bool isBrAnalysisUnpredicatedTerminator(const MachineInstr *MI, - const X86InstrInfo &TII) { - if (MI->getOpcode() == X86::FP_REG_KILL) - return false; - return TII.isUnpredicatedTerminator(MI); -} - bool X86InstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, @@ -1688,7 +1642,7 @@ bool X86InstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, // Working from the bottom, when we see a non-terminator instruction, we're // done. - if (!isBrAnalysisUnpredicatedTerminator(I, *this)) + if (!isUnpredicatedTerminator(I)) break; // A terminator that isn't a branch can't easily be handled by this @@ -1891,6 +1845,33 @@ static bool isHReg(unsigned Reg) { return X86::GR8_ABCD_HRegClass.contains(Reg); } +// Try and copy between VR128/VR64 and GR64 registers. +static unsigned CopyToFromAsymmetricReg(unsigned DestReg, unsigned SrcReg) { + // SrcReg(VR128) -> DestReg(GR64) + // SrcReg(VR64) -> DestReg(GR64) + // SrcReg(GR64) -> DestReg(VR128) + // SrcReg(GR64) -> DestReg(VR64) + + if (X86::GR64RegClass.contains(DestReg)) { + if (X86::VR128RegClass.contains(SrcReg)) { + // Copy from a VR128 register to a GR64 register. + return X86::MOVPQIto64rr; + } else if (X86::VR64RegClass.contains(SrcReg)) { + // Copy from a VR64 register to a GR64 register. + return X86::MOVSDto64rr; + } + } else if (X86::GR64RegClass.contains(SrcReg)) { + // Copy from a GR64 register to a VR128 register. + if (X86::VR128RegClass.contains(DestReg)) + return X86::MOV64toPQIrr; + // Copy from a GR64 register to a VR64 register. + else if (X86::VR64RegClass.contains(DestReg)) + return X86::MOV64toSDrr; + } + + return 0; +} + void X86InstrInfo::copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, DebugLoc DL, unsigned DestReg, unsigned SrcReg, @@ -1915,6 +1896,8 @@ void X86InstrInfo::copyPhysReg(MachineBasicBlock &MBB, Opc = X86::MOVAPSrr; else if (X86::VR64RegClass.contains(DestReg, SrcReg)) Opc = X86::MMX_MOVQ64rr; + else + Opc = CopyToFromAsymmetricReg(DestReg, SrcReg); if (Opc) { BuildMI(MBB, MI, DL, get(Opc), DestReg) @@ -2046,6 +2029,8 @@ void X86InstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, const TargetRegisterClass *RC, const TargetRegisterInfo *TRI) const { const MachineFunction &MF = *MBB.getParent(); + assert(MF.getFrameInfo()->getObjectSize(FrameIdx) >= RC->getSize() && + "Stack slot too small for store"); bool isAligned = (RI.getStackAlignment() >= 16) || RI.canRealignStack(MF); unsigned Opc = getStoreRegOpcode(SrcReg, RC, isAligned, TM); DebugLoc DL = MBB.findDebugLoc(MI); @@ -2130,8 +2115,9 @@ bool X86InstrInfo::spillCalleeSavedRegisters(MachineBasicBlock &MBB, CalleeFrameSize += SlotSize; BuildMI(MBB, MI, DL, get(Opc)).addReg(Reg, RegState::Kill); } else { + const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); storeRegToStackSlot(MBB, MI, Reg, true, CSI[i-1].getFrameIdx(), - &X86::VR128RegClass, &RI); + RC, &RI); } } @@ -2161,8 +2147,9 @@ bool X86InstrInfo::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, if (!X86::VR128RegClass.contains(Reg) && !isWin64) { BuildMI(MBB, MI, DL, get(Opc), Reg); } else { + const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); loadRegFromStackSlot(MBB, MI, Reg, CSI[i].getFrameIdx(), - &X86::VR128RegClass, &RI); + RC, &RI); } } return true; @@ -2423,10 +2410,17 @@ MachineInstr* X86InstrInfo::foldMemoryOperandImpl(MachineFunction &MF, Alignment = (*LoadMI->memoperands_begin())->getAlignment(); else switch (LoadMI->getOpcode()) { + case X86::AVX_SET0PSY: + case X86::AVX_SET0PDY: + Alignment = 32; + break; case X86::V_SET0PS: case X86::V_SET0PD: case X86::V_SET0PI: case X86::V_SETALLONES: + case X86::AVX_SET0PS: + case X86::AVX_SET0PD: + case X86::AVX_SET0PI: Alignment = 16; break; case X86::FsFLD0SD: @@ -2453,12 +2447,22 @@ MachineInstr* X86InstrInfo::foldMemoryOperandImpl(MachineFunction &MF, } else if (Ops.size() != 1) return NULL; + // Make sure the subregisters match. + // Otherwise we risk changing the size of the load. + if (LoadMI->getOperand(0).getSubReg() != MI->getOperand(Ops[0]).getSubReg()) + return NULL; + SmallVector MOs; switch (LoadMI->getOpcode()) { case X86::V_SET0PS: case X86::V_SET0PD: case X86::V_SET0PI: case X86::V_SETALLONES: + case X86::AVX_SET0PS: + case X86::AVX_SET0PD: + case X86::AVX_SET0PI: + case X86::AVX_SET0PSY: + case X86::AVX_SET0PDY: case X86::FsFLD0SD: case X86::FsFLD0SS: { // Folding a V_SET0P? or V_SETALLONES as a load, to ease register pressure. @@ -2485,10 +2489,13 @@ MachineInstr* X86InstrInfo::foldMemoryOperandImpl(MachineFunction &MF, // Create a constant-pool entry. MachineConstantPool &MCP = *MF.getConstantPool(); const Type *Ty; - if (LoadMI->getOpcode() == X86::FsFLD0SS) + unsigned Opc = LoadMI->getOpcode(); + if (Opc == X86::FsFLD0SS) Ty = Type::getFloatTy(MF.getFunction()->getContext()); - else if (LoadMI->getOpcode() == X86::FsFLD0SD) + else if (Opc == X86::FsFLD0SD) Ty = Type::getDoubleTy(MF.getFunction()->getContext()); + else if (Opc == X86::AVX_SET0PSY || Opc == X86::AVX_SET0PDY) + Ty = VectorType::get(Type::getFloatTy(MF.getFunction()->getContext()), 8); else Ty = VectorType::get(Type::getInt32Ty(MF.getFunction()->getContext()), 4); const Constant *C = LoadMI->getOpcode() == X86::V_SETALLONES ? @@ -2991,561 +2998,6 @@ bool X86InstrInfo::isX86_64ExtendedReg(unsigned RegNo) { return false; } - -/// determineREX - Determine if the MachineInstr has to be encoded with a X86-64 -/// REX prefix which specifies 1) 64-bit instructions, 2) non-default operand -/// size, and 3) use of X86-64 extended registers. -unsigned X86InstrInfo::determineREX(const MachineInstr &MI) { - unsigned REX = 0; - const TargetInstrDesc &Desc = MI.getDesc(); - - // Pseudo instructions do not need REX prefix byte. - if ((Desc.TSFlags & X86II::FormMask) == X86II::Pseudo) - return 0; - if (Desc.TSFlags & X86II::REX_W) - REX |= 1 << 3; - - unsigned NumOps = Desc.getNumOperands(); - if (NumOps) { - bool isTwoAddr = NumOps > 1 && - Desc.getOperandConstraint(1, TOI::TIED_TO) != -1; - - // If it accesses SPL, BPL, SIL, or DIL, then it requires a 0x40 REX prefix. - unsigned i = isTwoAddr ? 1 : 0; - for (unsigned e = NumOps; i != e; ++i) { - const MachineOperand& MO = MI.getOperand(i); - if (MO.isReg()) { - unsigned Reg = MO.getReg(); - if (isX86_64NonExtLowByteReg(Reg)) - REX |= 0x40; - } - } - - switch (Desc.TSFlags & X86II::FormMask) { - case X86II::MRMInitReg: - if (isX86_64ExtendedReg(MI.getOperand(0))) - REX |= (1 << 0) | (1 << 2); - break; - case X86II::MRMSrcReg: { - if (isX86_64ExtendedReg(MI.getOperand(0))) - REX |= 1 << 2; - i = isTwoAddr ? 2 : 1; - for (unsigned e = NumOps; i != e; ++i) { - const MachineOperand& MO = MI.getOperand(i); - if (isX86_64ExtendedReg(MO)) - REX |= 1 << 0; - } - break; - } - case X86II::MRMSrcMem: { - if (isX86_64ExtendedReg(MI.getOperand(0))) - REX |= 1 << 2; - unsigned Bit = 0; - i = isTwoAddr ? 2 : 1; - for (; i != NumOps; ++i) { - const MachineOperand& MO = MI.getOperand(i); - if (MO.isReg()) { - if (isX86_64ExtendedReg(MO)) - REX |= 1 << Bit; - Bit++; - } - } - break; - } - case X86II::MRM0m: case X86II::MRM1m: - case X86II::MRM2m: case X86II::MRM3m: - case X86II::MRM4m: case X86II::MRM5m: - case X86II::MRM6m: case X86II::MRM7m: - case X86II::MRMDestMem: { - unsigned e = (isTwoAddr ? X86::AddrNumOperands+1 : X86::AddrNumOperands); - i = isTwoAddr ? 1 : 0; - if (NumOps > e && isX86_64ExtendedReg(MI.getOperand(e))) - REX |= 1 << 2; - unsigned Bit = 0; - for (; i != e; ++i) { - const MachineOperand& MO = MI.getOperand(i); - if (MO.isReg()) { - if (isX86_64ExtendedReg(MO)) - REX |= 1 << Bit; - Bit++; - } - } - break; - } - default: { - if (isX86_64ExtendedReg(MI.getOperand(0))) - REX |= 1 << 0; - i = isTwoAddr ? 2 : 1; - for (unsigned e = NumOps; i != e; ++i) { - const MachineOperand& MO = MI.getOperand(i); - if (isX86_64ExtendedReg(MO)) - REX |= 1 << 2; - } - break; - } - } - } - return REX; -} - -/// sizePCRelativeBlockAddress - This method returns the size of a PC -/// relative block address instruction -/// -static unsigned sizePCRelativeBlockAddress() { - return 4; -} - -/// sizeGlobalAddress - Give the size of the emission of this global address -/// -static unsigned sizeGlobalAddress(bool dword) { - return dword ? 8 : 4; -} - -/// sizeConstPoolAddress - Give the size of the emission of this constant -/// pool address -/// -static unsigned sizeConstPoolAddress(bool dword) { - return dword ? 8 : 4; -} - -/// sizeExternalSymbolAddress - Give the size of the emission of this external -/// symbol -/// -static unsigned sizeExternalSymbolAddress(bool dword) { - return dword ? 8 : 4; -} - -/// sizeJumpTableAddress - Give the size of the emission of this jump -/// table address -/// -static unsigned sizeJumpTableAddress(bool dword) { - return dword ? 8 : 4; -} - -static unsigned sizeConstant(unsigned Size) { - return Size; -} - -static unsigned sizeRegModRMByte(){ - return 1; -} - -static unsigned sizeSIBByte(){ - return 1; -} - -static unsigned getDisplacementFieldSize(const MachineOperand *RelocOp) { - unsigned FinalSize = 0; - // If this is a simple integer displacement that doesn't require a relocation. - if (!RelocOp) { - FinalSize += sizeConstant(4); - return FinalSize; - } - - // Otherwise, this is something that requires a relocation. - if (RelocOp->isGlobal()) { - FinalSize += sizeGlobalAddress(false); - } else if (RelocOp->isCPI()) { - FinalSize += sizeConstPoolAddress(false); - } else if (RelocOp->isJTI()) { - FinalSize += sizeJumpTableAddress(false); - } else { - llvm_unreachable("Unknown value to relocate!"); - } - return FinalSize; -} - -static unsigned getMemModRMByteSize(const MachineInstr &MI, unsigned Op, - bool IsPIC, bool Is64BitMode) { - const MachineOperand &Op3 = MI.getOperand(Op+3); - int DispVal = 0; - const MachineOperand *DispForReloc = 0; - unsigned FinalSize = 0; - - // Figure out what sort of displacement we have to handle here. - if (Op3.isGlobal()) { - DispForReloc = &Op3; - } else if (Op3.isCPI()) { - if (Is64BitMode || IsPIC) { - DispForReloc = &Op3; - } else { - DispVal = 1; - } - } else if (Op3.isJTI()) { - if (Is64BitMode || IsPIC) { - DispForReloc = &Op3; - } else { - DispVal = 1; - } - } else { - DispVal = 1; - } - - const MachineOperand &Base = MI.getOperand(Op); - const MachineOperand &IndexReg = MI.getOperand(Op+2); - - unsigned BaseReg = Base.getReg(); - - // Is a SIB byte needed? - if ((!Is64BitMode || DispForReloc || BaseReg != 0) && - IndexReg.getReg() == 0 && - (BaseReg == 0 || X86RegisterInfo::getX86RegNum(BaseReg) != N86::ESP)) { - if (BaseReg == 0) { // Just a displacement? - // Emit special case [disp32] encoding - ++FinalSize; - FinalSize += getDisplacementFieldSize(DispForReloc); - } else { - unsigned BaseRegNo = X86RegisterInfo::getX86RegNum(BaseReg); - if (!DispForReloc && DispVal == 0 && BaseRegNo != N86::EBP) { - // Emit simple indirect register encoding... [EAX] f.e. - ++FinalSize; - // Be pessimistic and assume it's a disp32, not a disp8 - } else { - // Emit the most general non-SIB encoding: [REG+disp32] - ++FinalSize; - FinalSize += getDisplacementFieldSize(DispForReloc); - } - } - - } else { // We need a SIB byte, so start by outputting the ModR/M byte first - assert(IndexReg.getReg() != X86::ESP && - IndexReg.getReg() != X86::RSP && "Cannot use ESP as index reg!"); - - bool ForceDisp32 = false; - if (BaseReg == 0 || DispForReloc) { - // Emit the normal disp32 encoding. - ++FinalSize; - ForceDisp32 = true; - } else { - ++FinalSize; - } - - FinalSize += sizeSIBByte(); - - // Do we need to output a displacement? - if (DispVal != 0 || ForceDisp32) { - FinalSize += getDisplacementFieldSize(DispForReloc); - } - } - return FinalSize; -} - - -static unsigned GetInstSizeWithDesc(const MachineInstr &MI, - const TargetInstrDesc *Desc, - bool IsPIC, bool Is64BitMode) { - - unsigned Opcode = Desc->Opcode; - unsigned FinalSize = 0; - - // Emit the lock opcode prefix as needed. - if (Desc->TSFlags & X86II::LOCK) ++FinalSize; - - // Emit segment override opcode prefix as needed. - switch (Desc->TSFlags & X86II::SegOvrMask) { - case X86II::FS: - case X86II::GS: - ++FinalSize; - break; - default: llvm_unreachable("Invalid segment!"); - case 0: break; // No segment override! - } - - // Emit the repeat opcode prefix as needed. - if ((Desc->TSFlags & X86II::Op0Mask) == X86II::REP) ++FinalSize; - - // Emit the operand size opcode prefix as needed. - if (Desc->TSFlags & X86II::OpSize) ++FinalSize; - - // Emit the address size opcode prefix as needed. - if (Desc->TSFlags & X86II::AdSize) ++FinalSize; - - bool Need0FPrefix = false; - switch (Desc->TSFlags & X86II::Op0Mask) { - case X86II::TB: // Two-byte opcode prefix - case X86II::T8: // 0F 38 - case X86II::TA: // 0F 3A - Need0FPrefix = true; - break; - case X86II::TF: // F2 0F 38 - ++FinalSize; - Need0FPrefix = true; - break; - case X86II::REP: break; // already handled. - case X86II::XS: // F3 0F - ++FinalSize; - Need0FPrefix = true; - break; - case X86II::XD: // F2 0F - ++FinalSize; - Need0FPrefix = true; - break; - case X86II::D8: case X86II::D9: case X86II::DA: case X86II::DB: - case X86II::DC: case X86II::DD: case X86II::DE: case X86II::DF: - ++FinalSize; - break; // Two-byte opcode prefix - default: llvm_unreachable("Invalid prefix!"); - case 0: break; // No prefix! - } - - if (Is64BitMode) { - // REX prefix - unsigned REX = X86InstrInfo::determineREX(MI); - if (REX) - ++FinalSize; - } - - // 0x0F escape code must be emitted just before the opcode. - if (Need0FPrefix) - ++FinalSize; - - switch (Desc->TSFlags & X86II::Op0Mask) { - case X86II::T8: // 0F 38 - ++FinalSize; - break; - case X86II::TA: // 0F 3A - ++FinalSize; - break; - case X86II::TF: // F2 0F 38 - ++FinalSize; - break; - } - - // If this is a two-address instruction, skip one of the register operands. - unsigned NumOps = Desc->getNumOperands(); - unsigned CurOp = 0; - if (NumOps > 1 && Desc->getOperandConstraint(1, TOI::TIED_TO) != -1) - CurOp++; - else if (NumOps > 2 && Desc->getOperandConstraint(NumOps-1, TOI::TIED_TO)== 0) - // Skip the last source operand that is tied_to the dest reg. e.g. LXADD32 - --NumOps; - - switch (Desc->TSFlags & X86II::FormMask) { - default: llvm_unreachable("Unknown FormMask value in X86 MachineCodeEmitter!"); - case X86II::Pseudo: - // Remember the current PC offset, this is the PIC relocation - // base address. - switch (Opcode) { - default: - break; - case TargetOpcode::INLINEASM: { - const MachineFunction *MF = MI.getParent()->getParent(); - const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo(); - FinalSize += TII.getInlineAsmLength(MI.getOperand(0).getSymbolName(), - *MF->getTarget().getMCAsmInfo()); - break; - } - case TargetOpcode::DBG_LABEL: - case TargetOpcode::EH_LABEL: - case TargetOpcode::DBG_VALUE: - break; - case TargetOpcode::IMPLICIT_DEF: - case TargetOpcode::KILL: - case X86::FP_REG_KILL: - break; - case X86::MOVPC32r: { - // This emits the "call" portion of this pseudo instruction. - ++FinalSize; - FinalSize += sizeConstant(X86II::getSizeOfImm(Desc->TSFlags)); - break; - } - } - CurOp = NumOps; - break; - case X86II::RawFrm: - ++FinalSize; - - if (CurOp != NumOps) { - const MachineOperand &MO = MI.getOperand(CurOp++); - if (MO.isMBB()) { - FinalSize += sizePCRelativeBlockAddress(); - } else if (MO.isGlobal()) { - FinalSize += sizeGlobalAddress(false); - } else if (MO.isSymbol()) { - FinalSize += sizeExternalSymbolAddress(false); - } else if (MO.isImm()) { - FinalSize += sizeConstant(X86II::getSizeOfImm(Desc->TSFlags)); - } else { - llvm_unreachable("Unknown RawFrm operand!"); - } - } - break; - - case X86II::AddRegFrm: - ++FinalSize; - ++CurOp; - - if (CurOp != NumOps) { - const MachineOperand &MO1 = MI.getOperand(CurOp++); - unsigned Size = X86II::getSizeOfImm(Desc->TSFlags); - if (MO1.isImm()) - FinalSize += sizeConstant(Size); - else { - bool dword = false; - if (Opcode == X86::MOV64ri) - dword = true; - if (MO1.isGlobal()) { - FinalSize += sizeGlobalAddress(dword); - } else if (MO1.isSymbol()) - FinalSize += sizeExternalSymbolAddress(dword); - else if (MO1.isCPI()) - FinalSize += sizeConstPoolAddress(dword); - else if (MO1.isJTI()) - FinalSize += sizeJumpTableAddress(dword); - } - } - break; - - case X86II::MRMDestReg: { - ++FinalSize; - FinalSize += sizeRegModRMByte(); - CurOp += 2; - if (CurOp != NumOps) { - ++CurOp; - FinalSize += sizeConstant(X86II::getSizeOfImm(Desc->TSFlags)); - } - break; - } - case X86II::MRMDestMem: { - ++FinalSize; - FinalSize += getMemModRMByteSize(MI, CurOp, IsPIC, Is64BitMode); - CurOp += X86::AddrNumOperands + 1; - if (CurOp != NumOps) { - ++CurOp; - FinalSize += sizeConstant(X86II::getSizeOfImm(Desc->TSFlags)); - } - break; - } - - case X86II::MRMSrcReg: - ++FinalSize; - FinalSize += sizeRegModRMByte(); - CurOp += 2; - if (CurOp != NumOps) { - ++CurOp; - FinalSize += sizeConstant(X86II::getSizeOfImm(Desc->TSFlags)); - } - break; - - case X86II::MRMSrcMem: { - ++FinalSize; - FinalSize += getMemModRMByteSize(MI, CurOp+1, IsPIC, Is64BitMode); - CurOp += X86::AddrNumOperands + 1; - if (CurOp != NumOps) { - ++CurOp; - FinalSize += sizeConstant(X86II::getSizeOfImm(Desc->TSFlags)); - } - break; - } - - case X86II::MRM0r: case X86II::MRM1r: - case X86II::MRM2r: case X86II::MRM3r: - case X86II::MRM4r: case X86II::MRM5r: - case X86II::MRM6r: case X86II::MRM7r: - ++FinalSize; - if (Desc->getOpcode() == X86::LFENCE || - Desc->getOpcode() == X86::MFENCE) { - // Special handling of lfence and mfence; - FinalSize += sizeRegModRMByte(); - } else if (Desc->getOpcode() == X86::MONITOR || - Desc->getOpcode() == X86::MWAIT) { - // Special handling of monitor and mwait. - FinalSize += sizeRegModRMByte() + 1; // +1 for the opcode. - } else { - ++CurOp; - FinalSize += sizeRegModRMByte(); - } - - if (CurOp != NumOps) { - const MachineOperand &MO1 = MI.getOperand(CurOp++); - unsigned Size = X86II::getSizeOfImm(Desc->TSFlags); - if (MO1.isImm()) - FinalSize += sizeConstant(Size); - else { - bool dword = false; - if (Opcode == X86::MOV64ri32) - dword = true; - if (MO1.isGlobal()) { - FinalSize += sizeGlobalAddress(dword); - } else if (MO1.isSymbol()) - FinalSize += sizeExternalSymbolAddress(dword); - else if (MO1.isCPI()) - FinalSize += sizeConstPoolAddress(dword); - else if (MO1.isJTI()) - FinalSize += sizeJumpTableAddress(dword); - } - } - break; - - case X86II::MRM0m: case X86II::MRM1m: - case X86II::MRM2m: case X86II::MRM3m: - case X86II::MRM4m: case X86II::MRM5m: - case X86II::MRM6m: case X86II::MRM7m: { - - ++FinalSize; - FinalSize += getMemModRMByteSize(MI, CurOp, IsPIC, Is64BitMode); - CurOp += X86::AddrNumOperands; - - if (CurOp != NumOps) { - const MachineOperand &MO = MI.getOperand(CurOp++); - unsigned Size = X86II::getSizeOfImm(Desc->TSFlags); - if (MO.isImm()) - FinalSize += sizeConstant(Size); - else { - bool dword = false; - if (Opcode == X86::MOV64mi32) - dword = true; - if (MO.isGlobal()) { - FinalSize += sizeGlobalAddress(dword); - } else if (MO.isSymbol()) - FinalSize += sizeExternalSymbolAddress(dword); - else if (MO.isCPI()) - FinalSize += sizeConstPoolAddress(dword); - else if (MO.isJTI()) - FinalSize += sizeJumpTableAddress(dword); - } - } - break; - - case X86II::MRM_C1: - case X86II::MRM_C8: - case X86II::MRM_C9: - case X86II::MRM_E8: - case X86II::MRM_F0: - FinalSize += 2; - break; - } - - case X86II::MRMInitReg: - ++FinalSize; - // Duplicate register, used by things like MOV8r0 (aka xor reg,reg). - FinalSize += sizeRegModRMByte(); - ++CurOp; - break; - } - - if (!Desc->isVariadic() && CurOp != NumOps) { - std::string msg; - raw_string_ostream Msg(msg); - Msg << "Cannot determine size: " << MI; - report_fatal_error(Msg.str()); - } - - - return FinalSize; -} - - -unsigned X86InstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const { - const TargetInstrDesc &Desc = MI->getDesc(); - bool IsPIC = TM.getRelocationModel() == Reloc::PIC_; - bool Is64BitMode = TM.getSubtargetImpl()->is64Bit(); - unsigned Size = GetInstSizeWithDesc(*MI, &Desc, IsPIC, Is64BitMode); - if (Desc.getOpcode() == X86::MOVPC32r) - Size += GetInstSizeWithDesc(*MI, &get(X86::POP32r), IsPIC, Is64BitMode); - return Size; -} - /// getGlobalBaseReg - Return a virtual register initialized with the /// the global base register value. Output instructions required to /// initialize the register in the function entry block, if necessary. @@ -3573,7 +3025,7 @@ unsigned X86InstrInfo::getGlobalBaseReg(MachineFunction *MF) const { // that we don't include here. We don't want to replace instructions selected // by intrinsics. static const unsigned ReplaceableInstrs[][3] = { - //PackedInt PackedSingle PackedDouble + //PackedSingle PackedDouble PackedInt { X86::MOVAPSmr, X86::MOVAPDmr, X86::MOVDQAmr }, { X86::MOVAPSrm, X86::MOVAPDrm, X86::MOVDQArm }, { X86::MOVAPSrr, X86::MOVAPDrr, X86::MOVDQArr }, @@ -3589,6 +3041,22 @@ static const unsigned ReplaceableInstrs[][3] = { { X86::V_SET0PS, X86::V_SET0PD, X86::V_SET0PI }, { X86::XORPSrm, X86::XORPDrm, X86::PXORrm }, { X86::XORPSrr, X86::XORPDrr, X86::PXORrr }, + // AVX 128-bit support + { X86::VMOVAPSmr, X86::VMOVAPDmr, X86::VMOVDQAmr }, + { X86::VMOVAPSrm, X86::VMOVAPDrm, X86::VMOVDQArm }, + { X86::VMOVAPSrr, X86::VMOVAPDrr, X86::VMOVDQArr }, + { X86::VMOVUPSmr, X86::VMOVUPDmr, X86::VMOVDQUmr }, + { X86::VMOVUPSrm, X86::VMOVUPDrm, X86::VMOVDQUrm }, + { X86::VMOVNTPSmr, X86::VMOVNTPDmr, X86::VMOVNTDQmr }, + { X86::VANDNPSrm, X86::VANDNPDrm, X86::VPANDNrm }, + { X86::VANDNPSrr, X86::VANDNPDrr, X86::VPANDNrr }, + { X86::VANDPSrm, X86::VANDPDrm, X86::VPANDrm }, + { X86::VANDPSrr, X86::VANDPDrr, X86::VPANDrr }, + { X86::VORPSrm, X86::VORPDrm, X86::VPORrm }, + { X86::VORPSrr, X86::VORPDrr, X86::VPORrr }, + { X86::AVX_SET0PS, X86::AVX_SET0PD, X86::AVX_SET0PI }, + { X86::VXORPSrm, X86::VXORPDrm, X86::VPXORrm }, + { X86::VXORPSrr, X86::VXORPDrr, X86::VPXORrr }, }; // FIXME: Some shuffle and unpack instructions have equivalents in different @@ -3627,7 +3095,7 @@ namespace { /// global base register for x86-32. struct CGBR : public MachineFunctionPass { static char ID; - CGBR() : MachineFunctionPass(&ID) {} + CGBR() : MachineFunctionPass(ID) {} virtual bool runOnMachineFunction(MachineFunction &MF) { const X86TargetMachine *TM = diff --git a/lib/Target/X86/X86InstrInfo.h b/lib/Target/X86/X86InstrInfo.h index ad0217a..f336206 100644 --- a/lib/Target/X86/X86InstrInfo.h +++ b/lib/Target/X86/X86InstrInfo.h @@ -311,6 +311,12 @@ namespace X86II { MRM_F0 = 40, MRM_F8 = 41, MRM_F9 = 42, + + /// RawFrmImm16 - This is used for CALL FAR instructions, which have two + /// immediates, the first of which is a 16 or 32-bit immediate (specified by + /// the imm encoding) and the second is a 16-bit fixed value. In the AMD + /// manual, this operand is described as pntr16:32 and pntr16:16 + RawFrmImm16 = 43, FormMask = 63, @@ -439,27 +445,27 @@ namespace X86II { //===------------------------------------------------------------------===// // VEX - The opcode prefix used by AVX instructions - VEX = 1ULL << 32, + VEX = 1U << 0, // VEX_W - Has a opcode specific functionality, but is used in the same // way as REX_W is for regular SSE instructions. - VEX_W = 1ULL << 33, + VEX_W = 1U << 1, // VEX_4V - Used to specify an additional AVX/SSE register. Several 2 // address instructions in SSE are represented as 3 address ones in AVX // and the additional register is encoded in VEX_VVVV prefix. - VEX_4V = 1ULL << 34, + VEX_4V = 1U << 2, // VEX_I8IMM - Specifies that the last register used in a AVX instruction, // must be encoded in the i8 immediate field. This usually happens in // instructions with 4 operands. - VEX_I8IMM = 1ULL << 35, + VEX_I8IMM = 1U << 3, // VEX_L - Stands for a bit in the VEX opcode prefix meaning the current // instruction uses 256-bit wide registers. This is usually auto detected if // a VR256 register is used, but some AVX instructions also have this field // marked when using a f256 memory references. - VEX_L = 1ULL << 36 + VEX_L = 1U << 4 }; // getBaseOpcodeFor - This function returns the "base" X86 opcode for the @@ -522,11 +528,12 @@ namespace X86II { case X86II::AddRegFrm: case X86II::MRMDestReg: case X86II::MRMSrcReg: + case X86II::RawFrmImm16: return -1; case X86II::MRMDestMem: return 0; case X86II::MRMSrcMem: { - bool HasVEX_4V = TSFlags & X86II::VEX_4V; + bool HasVEX_4V = (TSFlags >> 32) & X86II::VEX_4V; unsigned FirstMemOp = 1; if (HasVEX_4V) ++FirstMemOp;// Skip the register source (which is encoded in VEX_VVVV). @@ -610,12 +617,6 @@ public: /// virtual const X86RegisterInfo &getRegisterInfo() const { return RI; } - /// Return true if the instruction is a register to register move and return - /// the source and dest operands and their sub-register indices by reference. - virtual bool isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const; - /// isCoalescableExtInstr - Return true if the instruction is a "coalescable" /// extension instruction. That is, it's like a copy where it's legal for the /// source to overlap the destination. e.g. X86::MOVSX64rr32. If this returns @@ -826,16 +827,11 @@ public: if (!MO.isReg()) return false; return isX86_64ExtendedReg(MO.getReg()); } - static unsigned determineREX(const MachineInstr &MI); /// isX86_64ExtendedReg - Is the MachineOperand a x86-64 extended (r8 or /// higher) register? e.g. r8, xmm8, xmm13, etc. static bool isX86_64ExtendedReg(unsigned RegNo); - /// GetInstSize - Returns the size of the specified MachineInstr. - /// - virtual unsigned GetInstSizeInBytes(const MachineInstr *MI) const; - /// getGlobalBaseReg - Return a virtual register initialized with the /// the global base register value. Output instructions required to /// initialize the register in the function entry block, if necessary. diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index 1efef5a..09b7721 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -80,6 +80,21 @@ def SDT_X86EHRET : SDTypeProfile<0, 1, [SDTCisInt<0>]>; def SDT_X86TCRET : SDTypeProfile<0, 2, [SDTCisPtrTy<0>, SDTCisVT<1, i32>]>; +def SDT_X86MEMBARRIER : SDTypeProfile<0, 0, []>; +def SDT_X86MEMBARRIERNoSSE : SDTypeProfile<0, 1, [SDTCisInt<0>]>; + +def X86MemBarrier : SDNode<"X86ISD::MEMBARRIER", SDT_X86MEMBARRIER, + [SDNPHasChain]>; +def X86MemBarrierNoSSE : SDNode<"X86ISD::MEMBARRIER", SDT_X86MEMBARRIERNoSSE, + [SDNPHasChain]>; +def X86MFence : SDNode<"X86ISD::MFENCE", SDT_X86MEMBARRIER, + [SDNPHasChain]>; +def X86SFence : SDNode<"X86ISD::SFENCE", SDT_X86MEMBARRIER, + [SDNPHasChain]>; +def X86LFence : SDNode<"X86ISD::LFENCE", SDT_X86MEMBARRIER, + [SDNPHasChain]>; + + def X86bsf : SDNode<"X86ISD::BSF", SDTUnaryArithWithFlags>; def X86bsr : SDNode<"X86ISD::BSR", SDTUnaryArithWithFlags>; def X86shld : SDNode<"X86ISD::SHLD", SDTIntShiftDOp>; @@ -222,7 +237,7 @@ def i16mem : X86MemOperand<"printi16mem">; def i32mem : X86MemOperand<"printi32mem">; def i64mem : X86MemOperand<"printi64mem">; def i128mem : X86MemOperand<"printi128mem">; -//def i256mem : X86MemOperand<"printi256mem">; +def i256mem : X86MemOperand<"printi256mem">; def f32mem : X86MemOperand<"printf32mem">; def f64mem : X86MemOperand<"printf64mem">; def f80mem : X86MemOperand<"printf80mem">; @@ -333,15 +348,21 @@ def tls32addr : ComplexPatternhasCMov()">; def NoCMov : Predicate<"!Subtarget->hasCMov()">; -def HasMMX : Predicate<"Subtarget->hasMMX()">; -def HasSSE1 : Predicate<"Subtarget->hasSSE1()">; -def HasSSE2 : Predicate<"Subtarget->hasSSE2()">; -def HasSSE3 : Predicate<"Subtarget->hasSSE3()">; -def HasSSSE3 : Predicate<"Subtarget->hasSSSE3()">; -def HasSSE41 : Predicate<"Subtarget->hasSSE41()">; -def HasSSE42 : Predicate<"Subtarget->hasSSE42()">; -def HasSSE4A : Predicate<"Subtarget->hasSSE4A()">; + +// FIXME: temporary hack to let codegen assert or generate poor code in case +// no AVX version of the desired intructions is present, this is better for +// incremental dev (without fallbacks it's easier to spot what's missing) +def HasMMX : Predicate<"Subtarget->hasMMX() && !Subtarget->hasAVX()">; +def HasSSE1 : Predicate<"Subtarget->hasSSE1() && !Subtarget->hasAVX()">; +def HasSSE2 : Predicate<"Subtarget->hasSSE2() && !Subtarget->hasAVX()">; +def HasSSE3 : Predicate<"Subtarget->hasSSE3() && !Subtarget->hasAVX()">; +def HasSSSE3 : Predicate<"Subtarget->hasSSSE3() && !Subtarget->hasAVX()">; +def HasSSE41 : Predicate<"Subtarget->hasSSE41() && !Subtarget->hasAVX()">; +def HasSSE42 : Predicate<"Subtarget->hasSSE42() && !Subtarget->hasAVX()">; +def HasSSE4A : Predicate<"Subtarget->hasSSE4A() && !Subtarget->hasAVX()">; + def HasAVX : Predicate<"Subtarget->hasAVX()">; +def HasCLMUL : Predicate<"Subtarget->hasCLMUL()">; def HasFMA3 : Predicate<"Subtarget->hasFMA3()">; def HasFMA4 : Predicate<"Subtarget->hasFMA4()">; def FPStackf32 : Predicate<"!Subtarget->hasSSE1()">; @@ -393,9 +414,7 @@ def X86_COND_O : PatLeaf<(i8 13)>; def X86_COND_P : PatLeaf<(i8 14)>; // alt. COND_PE def X86_COND_S : PatLeaf<(i8 15)>; -def immSext8 : PatLeaf<(imm), [{ - return N->getSExtValue() == (int8_t)N->getSExtValue(); -}]>; +def immSext8 : PatLeaf<(imm), [{ return immSext8(N); }]>; def i16immSExt8 : PatLeaf<(i16 immSext8)>; def i32immSExt8 : PatLeaf<(i32 immSext8)>; @@ -559,9 +578,10 @@ def VASTART_SAVE_XMM_REGS : I<0, Pseudo, // The main point of having separate instruction are extra unmodelled effects // (compared to ordinary calls) like stack pointer change. -def MINGW_ALLOCA : I<0, Pseudo, (outs), (ins), - "# dynamic stack allocation", - [(X86MingwAlloca)]>; +let Defs = [EAX, ESP, EFLAGS], Uses = [ESP] in + def MINGW_ALLOCA : I<0, Pseudo, (outs), (ins), + "# dynamic stack allocation", + [(X86MingwAlloca)]>; } // Nop @@ -574,10 +594,14 @@ let neverHasSideEffects = 1 in { } // Trap -def INTO : I<0xce, RawFrm, (outs), (ins), "into", []>; -def INT3 : I<0xcc, RawFrm, (outs), (ins), "int3", []>; +let Uses = [EFLAGS] in { + def INTO : I<0xce, RawFrm, (outs), (ins), "into", []>; +} +def INT3 : I<0xcc, RawFrm, (outs), (ins), "int3", + [(int_x86_int (i8 3))]>; // FIXME: need to make sure that "int $3" matches int3 -def INT : Ii8<0xcd, RawFrm, (outs), (ins i8imm:$trap), "int\t$trap", []>; +def INT : Ii8<0xcd, RawFrm, (outs), (ins i8imm:$trap), "int\t$trap", + [(int_x86_int imm:$trap)]>; def IRET16 : I<0xcf, RawFrm, (outs), (ins), "iret{w}", []>, OpSize; def IRET32 : I<0xcf, RawFrm, (outs), (ins), "iret{l}", []>; @@ -650,16 +674,16 @@ let Uses = [ECX], isBranch = 1, isTerminator = 1 in // Indirect branches let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { def JMP32r : I<0xFF, MRM4r, (outs), (ins GR32:$dst), "jmp{l}\t{*}$dst", - [(brind GR32:$dst)]>; + [(brind GR32:$dst)]>, Requires<[In32BitMode]>; def JMP32m : I<0xFF, MRM4m, (outs), (ins i32mem:$dst), "jmp{l}\t{*}$dst", - [(brind (loadi32 addr:$dst))]>; + [(brind (loadi32 addr:$dst))]>, Requires<[In32BitMode]>; - def FARJMP16i : Iseg16<0xEA, RawFrm, (outs), - (ins i16imm:$seg, i16imm:$off), - "ljmp{w}\t$seg, $off", []>, OpSize; - def FARJMP32i : Iseg32<0xEA, RawFrm, (outs), - (ins i16imm:$seg, i32imm:$off), - "ljmp{l}\t$seg, $off", []>; + def FARJMP16i : Iseg16<0xEA, RawFrmImm16, (outs), + (ins i16imm:$off, i16imm:$seg), + "ljmp{w}\t{$seg, $off|$off, $seg}", []>, OpSize; + def FARJMP32i : Iseg32<0xEA, RawFrmImm16, (outs), + (ins i32imm:$off, i16imm:$seg), + "ljmp{l}\t{$seg, $off|$off, $seg}", []>; def FARJMP16m : I<0xFF, MRM5m, (outs), (ins opaque32mem:$dst), "ljmp{w}\t{*}$dst", []>, OpSize; @@ -670,9 +694,9 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { // Loop instructions -def LOOP : I<0xE2, RawFrm, (outs), (ins brtarget8:$dst), "loop\t$dst", []>; -def LOOPE : I<0xE1, RawFrm, (outs), (ins brtarget8:$dst), "loope\t$dst", []>; -def LOOPNE : I<0xE0, RawFrm, (outs), (ins brtarget8:$dst), "loopne\t$dst", []>; +def LOOP : Ii8PCRel<0xE2, RawFrm, (outs), (ins brtarget8:$dst), "loop\t$dst", []>; +def LOOPE : Ii8PCRel<0xE1, RawFrm, (outs), (ins brtarget8:$dst), "loope\t$dst", []>; +def LOOPNE : Ii8PCRel<0xE0, RawFrm, (outs), (ins brtarget8:$dst), "loopne\t$dst", []>; //===----------------------------------------------------------------------===// // Call Instructions... @@ -695,12 +719,12 @@ let isCall = 1 in def CALL32m : I<0xFF, MRM2m, (outs), (ins i32mem:$dst, variable_ops), "call\t{*}$dst", [(X86call (loadi32 addr:$dst))]>; - def FARCALL16i : Iseg16<0x9A, RawFrm, (outs), - (ins i16imm:$seg, i16imm:$off), - "lcall{w}\t$seg, $off", []>, OpSize; - def FARCALL32i : Iseg32<0x9A, RawFrm, (outs), - (ins i16imm:$seg, i32imm:$off), - "lcall{l}\t$seg, $off", []>; + def FARCALL16i : Iseg16<0x9A, RawFrmImm16, (outs), + (ins i16imm:$off, i16imm:$seg), + "lcall{w}\t{$seg, $off|$off, $seg}", []>, OpSize; + def FARCALL32i : Iseg32<0x9A, RawFrmImm16, (outs), + (ins i32imm:$off, i16imm:$seg), + "lcall{l}\t{$seg, $off|$off, $seg}", []>; def FARCALL16m : I<0xFF, MRM3m, (outs), (ins opaque32mem:$dst), "lcall{w}\t{*}$dst", []>, OpSize; @@ -721,7 +745,8 @@ def ENTER : I<0xC8, RawFrm, (outs), (ins i16imm:$len, i8imm:$lvl), // Tail call stuff. -let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in +let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, + isCodeGenOnly = 1 in let Defs = [EAX, ECX, EDX, FP0, FP1, FP2, FP3, FP4, FP5, FP6, ST0, MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7, XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, @@ -756,7 +781,7 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in // let Defs = [EBP, ESP], Uses = [EBP, ESP], mayLoad = 1, neverHasSideEffects=1 in def LEAVE : I<0xC9, RawFrm, - (outs), (ins), "leave", []>; + (outs), (ins), "leave", []>, Requires<[In32BitMode]>; def POPCNT16rr : I<0xB8, MRMSrcReg, (outs GR16:$dst), (ins GR16:$src), "popcnt{w}\t{$src, $dst|$dst, $src}", []>, OpSize, XS; @@ -934,7 +959,7 @@ def SYSRET : I<0x07, RawFrm, def SYSENTER : I<0x34, RawFrm, (outs), (ins), "sysenter", []>, TB; def SYSEXIT : I<0x35, RawFrm, - (outs), (ins), "sysexit", []>, TB; + (outs), (ins), "sysexit", []>, TB, Requires<[In32BitMode]>; def WAIT : I<0x9B, RawFrm, (outs), (ins), "wait", []>; @@ -1025,17 +1050,23 @@ def MOV32mi : Ii32<0xC7, MRM0m, (outs), (ins i32mem:$dst, i32imm:$src), /// moffs8, moffs16 and moffs32 versions of moves. The immediate is a /// 32-bit offset from the PC. These are only valid in x86-32 mode. def MOV8o8a : Ii32 <0xA0, RawFrm, (outs), (ins offset8:$src), - "mov{b}\t{$src, %al|%al, $src}", []>; + "mov{b}\t{$src, %al|%al, $src}", []>, + Requires<[In32BitMode]>; def MOV16o16a : Ii32 <0xA1, RawFrm, (outs), (ins offset16:$src), - "mov{w}\t{$src, %ax|%ax, $src}", []>, OpSize; + "mov{w}\t{$src, %ax|%ax, $src}", []>, OpSize, + Requires<[In32BitMode]>; def MOV32o32a : Ii32 <0xA1, RawFrm, (outs), (ins offset32:$src), - "mov{l}\t{$src, %eax|%eax, $src}", []>; + "mov{l}\t{$src, %eax|%eax, $src}", []>, + Requires<[In32BitMode]>; def MOV8ao8 : Ii32 <0xA2, RawFrm, (outs offset8:$dst), (ins), - "mov{b}\t{%al, $dst|$dst, %al}", []>; + "mov{b}\t{%al, $dst|$dst, %al}", []>, + Requires<[In32BitMode]>; def MOV16ao16 : Ii32 <0xA3, RawFrm, (outs offset16:$dst), (ins), - "mov{w}\t{%ax, $dst|$dst, %ax}", []>, OpSize; + "mov{w}\t{%ax, $dst|$dst, %ax}", []>, OpSize, + Requires<[In32BitMode]>; def MOV32ao32 : Ii32 <0xA3, RawFrm, (outs offset32:$dst), (ins), - "mov{l}\t{%eax, $dst|$dst, %eax}", []>; + "mov{l}\t{%eax, $dst|$dst, %eax}", []>, + Requires<[In32BitMode]>; // Moves to and from segment registers def MOV16rs : I<0x8C, MRMDestReg, (outs GR16:$dst), (ins SEGMENT_REG:$src), @@ -1087,6 +1118,7 @@ def MOV32mr : I<0x89, MRMDestMem, (outs), (ins i32mem:$dst, GR32:$src), [(store GR32:$src, addr:$dst)]>; /// Versions of MOV32rr, MOV32rm, and MOV32mr for i32mem_TC and GR32_TC. +let isCodeGenOnly = 1 in { let neverHasSideEffects = 1 in def MOV32rr_TC : I<0x89, MRMDestReg, (outs GR32_TC:$dst), (ins GR32_TC:$src), "mov{l}\t{$src, $dst|$dst, $src}", []>; @@ -1101,10 +1133,12 @@ let mayStore = 1 in def MOV32mr_TC : I<0x89, MRMDestMem, (outs), (ins i32mem_TC:$dst, GR32_TC:$src), "mov{l}\t{$src, $dst|$dst, $src}", []>; +} // Versions of MOV8rr, MOV8mr, and MOV8rm that use i8mem_NOREX and GR8_NOREX so // that they can be used for copying and storing h registers, which can't be // encoded when a REX prefix is present. +let isCodeGenOnly = 1 in { let neverHasSideEffects = 1 in def MOV8rr_NOREX : I<0x88, MRMDestReg, (outs GR8_NOREX:$dst), (ins GR8_NOREX:$src), @@ -1118,6 +1152,7 @@ let mayLoad = 1, def MOV8rm_NOREX : I<0x8A, MRMSrcMem, (outs GR8_NOREX:$dst), (ins i8mem_NOREX:$src), "mov{b}\t{$src, $dst|$dst, $src} # NOREX", []>; +} // Moves to and from debug registers def MOV32rd : I<0x21, MRMDestReg, (outs GR32:$dst), (ins DEBUG_REG:$src), @@ -1137,7 +1172,7 @@ def MOV32cr : I<0x22, MRMSrcReg, (outs CONTROL_REG:$dst), (ins GR32:$src), // Extra precision multiplication -// AL is really implied by AX, by the registers in Defs must match the +// AL is really implied by AX, but the registers in Defs must match the // SDNode results (i8, i32). let Defs = [AL,EFLAGS,AX], Uses = [AL] in def MUL8r : I<0xF6, MRM4r, (outs), (ins GR8:$src), "mul{b}\t$src", @@ -3895,6 +3930,20 @@ def EH_RETURN : I<0xC3, RawFrm, (outs), (ins GR32:$addr), // Atomic support // +// Memory barriers + +// TODO: Get this to fold the constant into the instruction. +def OR32mrLocked : I<0x09, MRMDestMem, (outs), (ins i32mem:$dst, GR32:$zero), + "lock\n\t" + "or{l}\t{$zero, $dst|$dst, $zero}", + []>, Requires<[In32BitMode]>, LOCK; + +let hasSideEffects = 1 in { +def Int_MemBarrier : I<0, Pseudo, (outs), (ins), + "#MEMBARRIER", + [(X86MemBarrier)]>, Requires<[HasSSE2]>; +} + // Atomic swap. These are just normal xchg instructions. But since a memory // operand is referenced, the atomicity is ensured. let Constraints = "$val = $dst" in { @@ -4928,6 +4977,12 @@ include "X86Instr64bit.td" include "X86InstrFragmentsSIMD.td" //===----------------------------------------------------------------------===// +// FMA - Fused Multiply-Add support (requires FMA) +//===----------------------------------------------------------------------===// + +include "X86InstrFMA.td" + +//===----------------------------------------------------------------------===// // XMM Floating point support (requires SSE / SSE2) //===----------------------------------------------------------------------===// diff --git a/lib/Target/X86/X86InstrMMX.td b/lib/Target/X86/X86InstrMMX.td index 6cf7ac8..11d4179 100644 --- a/lib/Target/X86/X86InstrMMX.td +++ b/lib/Target/X86/X86InstrMMX.td @@ -164,7 +164,7 @@ let neverHasSideEffects = 1 in def MMX_MOVQ2FR64rr: SSDIi8<0xD6, MRMSrcReg, (outs FR64:$dst), (ins VR64:$src), "movq2dq\t{$src, $dst|$dst, $src}", []>; -def MMX_MOVFR642Qrr: SSDIi8<0xD6, MRMSrcReg, (outs VR64:$dst), (ins FR64:$src), +def MMX_MOVFR642Qrr: SDIi8<0xD6, MRMSrcReg, (outs VR64:$dst), (ins FR64:$src), "movdq2q\t{$src, $dst|$dst, $src}", []>; def MMX_MOVNTQmr : MMXI<0xE7, MRMDestMem, (outs), (ins i64mem:$dst, VR64:$src), diff --git a/lib/Target/X86/X86InstrSSE.td b/lib/Target/X86/X86InstrSSE.td index ebe161b..f5466f8 100644 --- a/lib/Target/X86/X86InstrSSE.td +++ b/lib/Target/X86/X86InstrSSE.td @@ -142,7 +142,7 @@ multiclass sse12_fp_packed_int opc, string OpcodeStr, RegisterClass RC, !if(Is2Addr, !strconcat(asm, "\t{$src2, $dst|$dst, $src2}"), !strconcat(asm, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")), - [(set RC:$dst, (!nameconcat("int_x86_sse", + [(set RC:$dst, (!nameconcat("int_x86_", !strconcat(SSEVer, !strconcat("_", !strconcat(OpcodeStr, FPSizeStr)))) RC:$src1, RC:$src2))], d>; @@ -150,7 +150,7 @@ multiclass sse12_fp_packed_int opc, string OpcodeStr, RegisterClass RC, !if(Is2Addr, !strconcat(asm, "\t{$src2, $dst|$dst, $src2}"), !strconcat(asm, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")), - [(set RC:$dst, (!nameconcat("int_x86_sse", + [(set RC:$dst, (!nameconcat("int_x86_", !strconcat(SSEVer, !strconcat("_", !strconcat(OpcodeStr, FPSizeStr)))) RC:$src1, (mem_frag addr:$src2)))], d>; @@ -256,10 +256,10 @@ def MOVSDmr : SDI<0x11, MRMDestMem, (outs), (ins f64mem:$dst, FR64:$src), let isAsmParserOnly = 1 in { def VMOVSSmr : SI<0x11, MRMDestMem, (outs), (ins f32mem:$dst, FR32:$src), "movss\t{$src, $dst|$dst, $src}", - [(store FR32:$src, addr:$dst)]>, XS, VEX_4V; + [(store FR32:$src, addr:$dst)]>, XS, VEX; def VMOVSDmr : SI<0x11, MRMDestMem, (outs), (ins f64mem:$dst, FR64:$src), "movsd\t{$src, $dst|$dst, $src}", - [(store FR64:$src, addr:$dst)]>, XD, VEX_4V; + [(store FR64:$src, addr:$dst)]>, XD, VEX; } // Extract and store. @@ -340,6 +340,15 @@ def VMOVUPDYmr : VPDI<0x11, MRMDestMem, (outs), (ins f256mem:$dst, VR256:$src), "movupd\t{$src, $dst|$dst, $src}", [(store (v4f64 VR256:$src), addr:$dst)]>, VEX; } + +def : Pat<(int_x86_avx_loadu_ps_256 addr:$src), (VMOVUPSYrm addr:$src)>; +def : Pat<(int_x86_avx_storeu_ps_256 addr:$dst, VR256:$src), + (VMOVUPSYmr addr:$dst, VR256:$src)>; + +def : Pat<(int_x86_avx_loadu_pd_256 addr:$src), (VMOVUPDYrm addr:$src)>; +def : Pat<(int_x86_avx_storeu_pd_256 addr:$dst, VR256:$src), + (VMOVUPDYmr addr:$dst, VR256:$src)>; + def MOVAPSmr : PSI<0x29, MRMDestMem, (outs), (ins f128mem:$dst, VR128:$src), "movaps\t{$src, $dst|$dst, $src}", [(alignedstore (v4f32 VR128:$src), addr:$dst)]>; @@ -516,6 +525,14 @@ multiclass sse12_cvt_s opc, RegisterClass SrcRC, RegisterClass DstRC, [(set DstRC:$dst, (OpNode (ld_frag addr:$src)))]>; } +multiclass sse12_cvt_s_np opc, RegisterClass SrcRC, RegisterClass DstRC, + X86MemOperand x86memop, string asm> { + def rr : SI; + def rm : SI; +} + multiclass sse12_cvt_p opc, RegisterClass SrcRC, RegisterClass DstRC, SDNode OpNode, X86MemOperand x86memop, PatFrag ld_frag, string asm, Domain d> { @@ -526,35 +543,58 @@ multiclass sse12_cvt_p opc, RegisterClass SrcRC, RegisterClass DstRC, } multiclass sse12_vcvt_avx opc, RegisterClass SrcRC, RegisterClass DstRC, - SDNode OpNode, X86MemOperand x86memop, PatFrag ld_frag, - string asm> { + X86MemOperand x86memop, string asm> { def rr : SI; + !strconcat(asm,"\t{$src, $src1, $dst|$dst, $src1, $src}"), []>; def rm : SI; + (ins DstRC:$src1, x86memop:$src), + !strconcat(asm,"\t{$src, $src1, $dst|$dst, $src1, $src}"), []>; } let isAsmParserOnly = 1 in { -defm VCVTTSS2SI : sse12_cvt_s<0x2C, FR32, GR32, fp_to_sint, f32mem, loadf32, - "cvttss2si\t{$src, $dst|$dst, $src}">, XS, VEX; -defm VCVTTSD2SI : sse12_cvt_s<0x2C, FR64, GR32, fp_to_sint, f64mem, loadf64, - "cvttsd2si\t{$src, $dst|$dst, $src}">, XD, VEX; -defm VCVTSI2SS : sse12_vcvt_avx<0x2A, GR32, FR32, sint_to_fp, i32mem, loadi32, - "cvtsi2ss\t{$src, $src1, $dst|$dst, $src1, $src}">, XS, - VEX_4V; -defm VCVTSI2SD : sse12_vcvt_avx<0x2A, GR32, FR64, sint_to_fp, i32mem, loadi32, - "cvtsi2sd\t{$src, $src1, $dst|$dst, $src1, $src}">, XD, - VEX_4V; +defm VCVTTSS2SI : sse12_cvt_s<0x2C, FR32, GR32, fp_to_sint, f32mem, loadf32, + "cvttss2si\t{$src, $dst|$dst, $src}">, XS, VEX; +defm VCVTTSS2SI64 : sse12_cvt_s<0x2C, FR32, GR64, fp_to_sint, f32mem, loadf32, + "cvttss2si\t{$src, $dst|$dst, $src}">, XS, VEX, + VEX_W; +defm VCVTTSD2SI : sse12_cvt_s<0x2C, FR64, GR32, fp_to_sint, f64mem, loadf64, + "cvttsd2si\t{$src, $dst|$dst, $src}">, XD, VEX; +defm VCVTTSD2SI64 : sse12_cvt_s<0x2C, FR64, GR64, fp_to_sint, f64mem, loadf64, + "cvttsd2si\t{$src, $dst|$dst, $src}">, XD, + VEX, VEX_W; + +// The assembler can recognize rr 64-bit instructions by seeing a rxx +// register, but the same isn't true when only using memory operands, +// provide other assembly "l" and "q" forms to address this explicitly +// where appropriate to do so. +defm VCVTSI2SS : sse12_vcvt_avx<0x2A, GR32, FR32, i32mem, "cvtsi2ss">, XS, + VEX_4V; +defm VCVTSI2SS64 : sse12_vcvt_avx<0x2A, GR64, FR32, i64mem, "cvtsi2ss{q}">, XS, + VEX_4V, VEX_W; +defm VCVTSI2SD : sse12_vcvt_avx<0x2A, GR32, FR64, i32mem, "cvtsi2sd">, XD, + VEX_4V; +defm VCVTSI2SDL : sse12_vcvt_avx<0x2A, GR32, FR64, i32mem, "cvtsi2sd{l}">, XD, + VEX_4V; +defm VCVTSI2SD64 : sse12_vcvt_avx<0x2A, GR64, FR64, i64mem, "cvtsi2sd{q}">, XD, + VEX_4V, VEX_W; } defm CVTTSS2SI : sse12_cvt_s<0x2C, FR32, GR32, fp_to_sint, f32mem, loadf32, "cvttss2si\t{$src, $dst|$dst, $src}">, XS; +defm CVTTSS2SI64 : sse12_cvt_s<0x2C, FR32, GR64, fp_to_sint, f32mem, loadf32, + "cvttss2si{q}\t{$src, $dst|$dst, $src}">, XS, REX_W; defm CVTTSD2SI : sse12_cvt_s<0x2C, FR64, GR32, fp_to_sint, f64mem, loadf64, "cvttsd2si\t{$src, $dst|$dst, $src}">, XD; +defm CVTTSD2SI64 : sse12_cvt_s<0x2C, FR64, GR64, fp_to_sint, f64mem, loadf64, + "cvttsd2si{q}\t{$src, $dst|$dst, $src}">, XD, REX_W; defm CVTSI2SS : sse12_cvt_s<0x2A, GR32, FR32, sint_to_fp, i32mem, loadi32, "cvtsi2ss\t{$src, $dst|$dst, $src}">, XS; +defm CVTSI2SS64 : sse12_cvt_s<0x2A, GR64, FR32, sint_to_fp, i64mem, loadi64, + "cvtsi2ss{q}\t{$src, $dst|$dst, $src}">, XS, REX_W; defm CVTSI2SD : sse12_cvt_s<0x2A, GR32, FR64, sint_to_fp, i32mem, loadi32, "cvtsi2sd\t{$src, $dst|$dst, $src}">, XD; +defm CVTSI2SD64 : sse12_cvt_s<0x2A, GR64, FR64, sint_to_fp, i64mem, loadi64, + "cvtsi2sd{q}\t{$src, $dst|$dst, $src}">, XD, REX_W; // Conversion Instructions Intrinsics - Match intrinsics which expect MM // and/or XMM operand(s). @@ -570,10 +610,12 @@ multiclass sse12_cvt_pint opc, RegisterClass SrcRC, RegisterClass DstRC, multiclass sse12_cvt_sint opc, RegisterClass SrcRC, RegisterClass DstRC, Intrinsic Int, X86MemOperand x86memop, PatFrag ld_frag, string asm> { - def rr : SI; - def rm : SI; + def rr : SI; + def rm : SI; } multiclass sse12_cvt_pint_3addr opc, RegisterClass SrcRC, @@ -588,35 +630,79 @@ multiclass sse12_cvt_pint_3addr opc, RegisterClass SrcRC, multiclass sse12_cvt_sint_3addr opc, RegisterClass SrcRC, RegisterClass DstRC, Intrinsic Int, X86MemOperand x86memop, - PatFrag ld_frag, string asm> { + PatFrag ld_frag, string asm, bit Is2Addr = 1> { def rr : SI; + !if(Is2Addr, + !strconcat(asm, "\t{$src2, $dst|$dst, $src2}"), + !strconcat(asm, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")), + [(set DstRC:$dst, (Int DstRC:$src1, SrcRC:$src2))]>; def rm : SI; } let isAsmParserOnly = 1 in { defm Int_VCVTSS2SI : sse12_cvt_sint<0x2D, VR128, GR32, int_x86_sse_cvtss2si, - f32mem, load, "cvtss2si\t{$src, $dst|$dst, $src}">, XS, - VEX; + f32mem, load, "cvtss2si">, XS, VEX; + defm Int_VCVTSS2SI64 : sse12_cvt_sint<0x2D, VR128, GR64, + int_x86_sse_cvtss2si64, f32mem, load, "cvtss2si">, + XS, VEX, VEX_W; defm Int_VCVTSD2SI : sse12_cvt_sint<0x2D, VR128, GR32, int_x86_sse2_cvtsd2si, - f128mem, load, "cvtsd2si\t{$src, $dst|$dst, $src}">, XD, - VEX; + f128mem, load, "cvtsd2si">, XD, VEX; + defm Int_VCVTSD2SI64 : sse12_cvt_sint<0x2D, VR128, GR64, + int_x86_sse2_cvtsd2si64, f128mem, load, "cvtsd2si">, + XD, VEX, VEX_W; + + // FIXME: The asm matcher has a hack to ignore instructions with _Int and Int_ + // Get rid of this hack or rename the intrinsics, there are several + // intructions that only match with the intrinsic form, why create duplicates + // to let them be recognized by the assembler? + defm VCVTSD2SI_alt : sse12_cvt_s_np<0x2D, FR64, GR32, f64mem, + "cvtsd2si\t{$src, $dst|$dst, $src}">, XD, VEX; + defm VCVTSD2SI64 : sse12_cvt_s_np<0x2D, FR64, GR64, f64mem, + "cvtsd2si\t{$src, $dst|$dst, $src}">, XD, VEX, VEX_W; } defm Int_CVTSS2SI : sse12_cvt_sint<0x2D, VR128, GR32, int_x86_sse_cvtss2si, - f32mem, load, "cvtss2si\t{$src, $dst|$dst, $src}">, XS; + f32mem, load, "cvtss2si">, XS; +defm Int_CVTSS2SI64 : sse12_cvt_sint<0x2D, VR128, GR64, int_x86_sse_cvtss2si64, + f32mem, load, "cvtss2si{q}">, XS, REX_W; defm Int_CVTSD2SI : sse12_cvt_sint<0x2D, VR128, GR32, int_x86_sse2_cvtsd2si, - f128mem, load, "cvtsd2si\t{$src, $dst|$dst, $src}">, XD; + f128mem, load, "cvtsd2si">, XD; +defm Int_CVTSD2SI64 : sse12_cvt_sint<0x2D, VR128, GR64, int_x86_sse2_cvtsd2si64, + f128mem, load, "cvtsd2si">, XD, REX_W; +defm CVTSD2SI64 : sse12_cvt_s_np<0x2D, VR128, GR64, f64mem, "cvtsd2si{q}">, XD, + REX_W; + +let isAsmParserOnly = 1 in { + defm Int_VCVTSI2SS : sse12_cvt_sint_3addr<0x2A, GR32, VR128, + int_x86_sse_cvtsi2ss, i32mem, loadi32, "cvtsi2ss", 0>, XS, VEX_4V; + defm Int_VCVTSI2SS64 : sse12_cvt_sint_3addr<0x2A, GR64, VR128, + int_x86_sse_cvtsi642ss, i64mem, loadi64, "cvtsi2ss", 0>, XS, VEX_4V, + VEX_W; + defm Int_VCVTSI2SD : sse12_cvt_sint_3addr<0x2A, GR32, VR128, + int_x86_sse2_cvtsi2sd, i32mem, loadi32, "cvtsi2sd", 0>, XD, VEX_4V; + defm Int_VCVTSI2SD64 : sse12_cvt_sint_3addr<0x2A, GR64, VR128, + int_x86_sse2_cvtsi642sd, i64mem, loadi64, "cvtsi2sd", 0>, XD, + VEX_4V, VEX_W; +} let Constraints = "$src1 = $dst" in { defm Int_CVTSI2SS : sse12_cvt_sint_3addr<0x2A, GR32, VR128, int_x86_sse_cvtsi2ss, i32mem, loadi32, - "cvtsi2ss\t{$src2, $dst|$dst, $src2}">, XS; + "cvtsi2ss">, XS; + defm Int_CVTSI2SS64 : sse12_cvt_sint_3addr<0x2A, GR64, VR128, + int_x86_sse_cvtsi642ss, i64mem, loadi64, + "cvtsi2ss{q}">, XS, REX_W; defm Int_CVTSI2SD : sse12_cvt_sint_3addr<0x2A, GR32, VR128, int_x86_sse2_cvtsi2sd, i32mem, loadi32, - "cvtsi2ss\t{$src2, $dst|$dst, $src2}">, XD; + "cvtsi2sd">, XD; + defm Int_CVTSI2SD64 : sse12_cvt_sint_3addr<0x2A, GR64, VR128, + int_x86_sse2_cvtsi642sd, i64mem, loadi64, + "cvtsi2sd">, XD, REX_W; } // Instructions below don't have an AVX form. @@ -645,35 +731,48 @@ let Constraints = "$src1 = $dst" in { /// SSE 1 Only // Aliases for intrinsics -let isAsmParserOnly = 1, Pattern = [] in { -defm Int_VCVTTSS2SI : sse12_cvt_sint_3addr<0x2C, VR128, GR32, - int_x86_sse_cvttss2si, f32mem, load, - "cvttss2si\t{$src2, $src1, $dst|$dst, $src1, $src2}">, XS; -defm Int_VCVTTSD2SI : sse12_cvt_sint_3addr<0x2C, VR128, GR32, - int_x86_sse2_cvttsd2si, f128mem, load, - "cvttss2si\t{$src2, $src1, $dst|$dst, $src1, $src2}">, XD; +let isAsmParserOnly = 1 in { +defm Int_VCVTTSS2SI : sse12_cvt_sint<0x2C, VR128, GR32, int_x86_sse_cvttss2si, + f32mem, load, "cvttss2si">, XS, VEX; +defm Int_VCVTTSS2SI64 : sse12_cvt_sint<0x2C, VR128, GR64, + int_x86_sse_cvttss2si64, f32mem, load, + "cvttss2si">, XS, VEX, VEX_W; +defm Int_VCVTTSD2SI : sse12_cvt_sint<0x2C, VR128, GR32, int_x86_sse2_cvttsd2si, + f128mem, load, "cvttss2si">, XD, VEX; +defm Int_VCVTTSD2SI64 : sse12_cvt_sint<0x2C, VR128, GR64, + int_x86_sse2_cvttsd2si64, f128mem, load, + "cvttss2si">, XD, VEX, VEX_W; } defm Int_CVTTSS2SI : sse12_cvt_sint<0x2C, VR128, GR32, int_x86_sse_cvttss2si, - f32mem, load, "cvttss2si\t{$src, $dst|$dst, $src}">, - XS; + f32mem, load, "cvttss2si">, XS; +defm Int_CVTTSS2SI64 : sse12_cvt_sint<0x2C, VR128, GR64, + int_x86_sse_cvttss2si64, f32mem, load, + "cvttss2si{q}">, XS, REX_W; defm Int_CVTTSD2SI : sse12_cvt_sint<0x2C, VR128, GR32, int_x86_sse2_cvttsd2si, - f128mem, load, "cvttss2si\t{$src, $dst|$dst, $src}">, - XD; + f128mem, load, "cvttss2si">, XD; +defm Int_CVTTSD2SI64 : sse12_cvt_sint<0x2C, VR128, GR64, + int_x86_sse2_cvttsd2si64, f128mem, load, + "cvttss2si{q}">, XD, REX_W; let isAsmParserOnly = 1, Pattern = [] in { -defm VCVTSS2SI : sse12_cvt_s<0x2D, FR32, GR32, undef, f32mem, load, - "cvtss2si{l}\t{$src, $dst|$dst, $src}">, XS, VEX; -defm VCVTDQ2PS : sse12_cvt_p<0x5B, VR128, VR128, undef, f128mem, load, - "cvtdq2ps\t{$src, $dst|$dst, $src}", - SSEPackedSingle>, TB, VEX; -defm VCVTDQ2PSY : sse12_cvt_p<0x5B, VR256, VR256, undef, f256mem, load, - "cvtdq2ps\t{$src, $dst|$dst, $src}", - SSEPackedSingle>, TB, VEX; +defm VCVTSS2SI : sse12_cvt_s<0x2D, FR32, GR32, undef, f32mem, load, + "cvtss2si{l}\t{$src, $dst|$dst, $src}">, XS, VEX; +defm VCVTSS2SI64 : sse12_cvt_s<0x2D, FR32, GR64, undef, f32mem, load, + "cvtss2si\t{$src, $dst|$dst, $src}">, XS, VEX, + VEX_W; +defm VCVTDQ2PS : sse12_cvt_p<0x5B, VR128, VR128, undef, i128mem, load, + "cvtdq2ps\t{$src, $dst|$dst, $src}", + SSEPackedSingle>, TB, VEX; +defm VCVTDQ2PSY : sse12_cvt_p<0x5B, VR256, VR256, undef, i256mem, load, + "cvtdq2ps\t{$src, $dst|$dst, $src}", + SSEPackedSingle>, TB, VEX; } let Pattern = [] in { defm CVTSS2SI : sse12_cvt_s<0x2D, FR32, GR32, undef, f32mem, load /*dummy*/, "cvtss2si{l}\t{$src, $dst|$dst, $src}">, XS; -defm CVTDQ2PS : sse12_cvt_p<0x5B, VR128, VR128, undef, f128mem, load /*dummy*/, +defm CVTSS2SI64 : sse12_cvt_s<0x2D, FR32, GR64, undef, f32mem, load /*dummy*/, + "cvtss2si{q}\t{$src, $dst|$dst, $src}">, XS, REX_W; +defm CVTDQ2PS : sse12_cvt_p<0x5B, VR128, VR128, undef, i128mem, load /*dummy*/, "cvtdq2ps\t{$src, $dst|$dst, $src}", SSEPackedSingle>, TB; /* PD SSE3 form is avaiable */ } @@ -701,13 +800,11 @@ def CVTSD2SSrm : I<0x5A, MRMSrcMem, (outs FR32:$dst), (ins f64mem:$src), let isAsmParserOnly = 1 in defm Int_VCVTSD2SS: sse12_cvt_sint_3addr<0x5A, VR128, VR128, - int_x86_sse2_cvtsd2ss, f64mem, load, - "cvtsd2ss\t{$src2, $src1, $dst|$dst, $src1, $src2}">, - XS, VEX_4V; + int_x86_sse2_cvtsd2ss, f64mem, load, "cvtsd2ss", 0>, + XS, VEX_4V; let Constraints = "$src1 = $dst" in defm Int_CVTSD2SS: sse12_cvt_sint_3addr<0x5A, VR128, VR128, - int_x86_sse2_cvtsd2ss, f64mem, load, - "cvtsd2ss\t{$src2, $dst|$dst, $src2}">, XS; + int_x86_sse2_cvtsd2ss, f64mem, load, "cvtsd2ss">, XS; // Convert scalar single to scalar double let isAsmParserOnly = 1 in { // SSE2 instructions with XS prefix @@ -806,6 +903,7 @@ def Int_CVTDQ2PDrm : I<0xE6, MRMSrcMem, (outs VR128:$dst), (ins i64mem:$src), (bitconvert (memopv2i64 addr:$src))))]>, XS, Requires<[HasSSE2]>; + // Convert packed single/double fp to doubleword let isAsmParserOnly = 1 in { def VCVTPS2DQrr : VPDI<0x5B, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src), @@ -964,11 +1062,11 @@ def CVTPS2PDrm : I<0x5A, MRMSrcMem, (outs VR128:$dst), (ins f64mem:$src), let isAsmParserOnly = 1 in { def Int_VCVTPS2PDrr : I<0x5A, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src), - "cvtps2pd\t{$src, $dst|$dst, $src}", + "vcvtps2pd\t{$src, $dst|$dst, $src}", [(set VR128:$dst, (int_x86_sse2_cvtps2pd VR128:$src))]>, VEX, Requires<[HasAVX]>; def Int_VCVTPS2PDrm : I<0x5A, MRMSrcMem, (outs VR128:$dst), (ins f64mem:$src), - "cvtps2pd\t{$src, $dst|$dst, $src}", + "vcvtps2pd\t{$src, $dst|$dst, $src}", [(set VR128:$dst, (int_x86_sse2_cvtps2pd (load addr:$src)))]>, VEX, Requires<[HasAVX]>; @@ -1029,6 +1127,39 @@ def Int_CVTPD2PSrm : PDI<0x5A, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src), [(set VR128:$dst, (int_x86_sse2_cvtpd2ps (memop addr:$src)))]>; +// AVX 256-bit register conversion intrinsics +// FIXME: Migrate SSE conversion intrinsics matching to use patterns as below +// whenever possible to avoid declaring two versions of each one. +def : Pat<(int_x86_avx_cvtdq2_ps_256 VR256:$src), + (VCVTDQ2PSYrr VR256:$src)>; +def : Pat<(int_x86_avx_cvtdq2_ps_256 (memopv8i32 addr:$src)), + (VCVTDQ2PSYrm addr:$src)>; + +def : Pat<(int_x86_avx_cvt_pd2_ps_256 VR256:$src), + (VCVTPD2PSYrr VR256:$src)>; +def : Pat<(int_x86_avx_cvt_pd2_ps_256 (memopv4f64 addr:$src)), + (VCVTPD2PSYrm addr:$src)>; + +def : Pat<(int_x86_avx_cvt_ps2dq_256 VR256:$src), + (VCVTPS2DQYrr VR256:$src)>; +def : Pat<(int_x86_avx_cvt_ps2dq_256 (memopv8f32 addr:$src)), + (VCVTPS2DQYrm addr:$src)>; + +def : Pat<(int_x86_avx_cvt_ps2_pd_256 VR128:$src), + (VCVTPS2PDYrr VR128:$src)>; +def : Pat<(int_x86_avx_cvt_ps2_pd_256 (memopv4f32 addr:$src)), + (VCVTPS2PDYrm addr:$src)>; + +def : Pat<(int_x86_avx_cvtt_pd2dq_256 VR256:$src), + (VCVTTPD2DQYrr VR256:$src)>; +def : Pat<(int_x86_avx_cvtt_pd2dq_256 (memopv4f64 addr:$src)), + (VCVTTPD2DQYrm addr:$src)>; + +def : Pat<(int_x86_avx_cvtt_ps2dq_256 VR256:$src), + (VCVTTPS2DQYrr VR256:$src)>; +def : Pat<(int_x86_avx_cvtt_ps2dq_256 (memopv8f32 addr:$src)), + (VCVTTPS2DQYrm addr:$src)>; + //===----------------------------------------------------------------------===// // SSE 1 & 2 - Compare Instructions //===----------------------------------------------------------------------===// @@ -1193,16 +1324,14 @@ let isAsmParserOnly = 1 in { "cmp${cc}pd\t{$src, $src1, $dst|$dst, $src1, $src}", "cmppd\t{$src2, $src, $src1, $dst|$dst, $src1, $src, $src2}", SSEPackedDouble>, OpSize, VEX_4V; - let Pattern = [] in { - defm VCMPPSY : sse12_cmp_packed, VEX_4V; - defm VCMPPDY : sse12_cmp_packed, OpSize, VEX_4V; - } + defm VCMPPSY : sse12_cmp_packed, VEX_4V; + defm VCMPPDY : sse12_cmp_packed, OpSize, VEX_4V; } let Constraints = "$src1 = $dst" in { defm CMPPS : sse12_cmp_packed { - def rmi : PIi8<0xC6, MRMSrcMem, (outs VR128:$dst), - (ins VR128:$src1, f128mem:$src2, i8imm:$src3), asm, - [(set VR128:$dst, (vt (shufp:$src3 - VR128:$src1, (mem_frag addr:$src2))))], d>; + def rmi : PIi8<0xC6, MRMSrcMem, (outs RC:$dst), + (ins RC:$src1, f128mem:$src2, i8imm:$src3), asm, + [(set RC:$dst, (vt (shufp:$src3 + RC:$src1, (mem_frag addr:$src2))))], d>; let isConvertibleToThreeAddress = IsConvertibleToThreeAddress in - def rri : PIi8<0xC6, MRMSrcReg, (outs VR128:$dst), - (ins VR128:$src1, VR128:$src2, i8imm:$src3), asm, - [(set VR128:$dst, - (vt (shufp:$src3 VR128:$src1, VR128:$src2)))], d>; + def rri : PIi8<0xC6, MRMSrcReg, (outs RC:$dst), + (ins RC:$src1, RC:$src2, i8imm:$src3), asm, + [(set RC:$dst, + (vt (shufp:$src3 RC:$src1, RC:$src2)))], d>; } let isAsmParserOnly = 1 in { - defm VSHUFPS : sse12_shuffle, VEX_4V; - defm VSHUFPD : sse12_shuffle, OpSize, VEX_4V; + defm VSHUFPS : sse12_shuffle, VEX_4V; + defm VSHUFPSY : sse12_shuffle, VEX_4V; + defm VSHUFPD : sse12_shuffle, OpSize, VEX_4V; + defm VSHUFPDY : sse12_shuffle, OpSize, VEX_4V; } let Constraints = "$src1 = $dst" in { @@ -1351,12 +1486,23 @@ let isAsmParserOnly = 1 in { defm VMOVMSKPD : sse12_extr_sign_mask, OpSize, VEX; - // FIXME: merge with multiclass above when the intrinsics come. - def VMOVMSKPSYrr : PI<0x50, MRMSrcReg, (outs GR32:$dst), (ins VR256:$src), + defm VMOVMSKPSY : sse12_extr_sign_mask, VEX; + defm VMOVMSKPDY : sse12_extr_sign_mask, OpSize, + VEX; + + // Assembler Only + def VMOVMSKPSr64r : PI<0x50, MRMSrcReg, (outs GR64:$dst), (ins VR128:$src), + "movmskps\t{$src, $dst|$dst, $src}", [], SSEPackedSingle>, VEX; + def VMOVMSKPDr64r : PI<0x50, MRMSrcReg, (outs GR64:$dst), (ins VR128:$src), + "movmskpd\t{$src, $dst|$dst, $src}", [], SSEPackedDouble>, OpSize, + VEX; + def VMOVMSKPSYr64r : PI<0x50, MRMSrcReg, (outs GR64:$dst), (ins VR256:$src), "movmskps\t{$src, $dst|$dst, $src}", [], SSEPackedSingle>, VEX; - def VMOVMSKPDYrr : PI<0x50, MRMSrcReg, (outs GR32:$dst), (ins VR256:$src), + def VMOVMSKPDYr64r : PI<0x50, MRMSrcReg, (outs GR64:$dst), (ins VR256:$src), "movmskpd\t{$src, $dst|$dst, $src}", [], SSEPackedDouble>, OpSize, - VEX; + VEX; } //===----------------------------------------------------------------------===// @@ -1536,6 +1682,9 @@ let isCommutable = 0 in /// /// These three forms can each be reg+reg or reg+mem. /// + +/// FIXME: once all 256-bit intrinsics are matched, cleanup and refactor those +/// classes below multiclass basic_sse12_fp_binop_s opc, string OpcodeStr, SDNode OpNode, bit Is2Addr = 1> { defm SS : sse12_fp_scalar opc, string OpcodeStr, } multiclass basic_sse12_fp_binop_s_int opc, string OpcodeStr, - bit Is2Addr = 1> { + bit Is2Addr = 1> { defm SS : sse12_fp_scalar_int, XS; defm SD : sse12_fp_scalar_int opc, string OpcodeStr, } multiclass basic_sse12_fp_binop_p_int opc, string OpcodeStr, - bit Is2Addr = 1> { + bit Is2Addr = 1> { defm PS : sse12_fp_packed_int, TB; defm PD : sse12_fp_packed_int, TB, OpSize; } +multiclass basic_sse12_fp_binop_p_y_int opc, string OpcodeStr> { + defm PSY : sse12_fp_packed_int, TB; + + defm PDY : sse12_fp_packed_int, TB, OpSize; +} + // Binary Arithmetic instructions let isAsmParserOnly = 1 in { defm VADD : basic_sse12_fp_binop_s<0x58, "add", fadd, 0>, + basic_sse12_fp_binop_s_int<0x58, "add", 0>, basic_sse12_fp_binop_p<0x58, "add", fadd, 0>, basic_sse12_fp_binop_p_y<0x58, "add", fadd>, VEX_4V; defm VMUL : basic_sse12_fp_binop_s<0x59, "mul", fmul, 0>, + basic_sse12_fp_binop_s_int<0x59, "mul", 0>, basic_sse12_fp_binop_p<0x59, "mul", fmul, 0>, basic_sse12_fp_binop_p_y<0x59, "mul", fmul>, VEX_4V; let isCommutable = 0 in { defm VSUB : basic_sse12_fp_binop_s<0x5C, "sub", fsub, 0>, + basic_sse12_fp_binop_s_int<0x5C, "sub", 0>, basic_sse12_fp_binop_p<0x5C, "sub", fsub, 0>, basic_sse12_fp_binop_p_y<0x5C, "sub", fsub>, VEX_4V; defm VDIV : basic_sse12_fp_binop_s<0x5E, "div", fdiv, 0>, + basic_sse12_fp_binop_s_int<0x5E, "div", 0>, basic_sse12_fp_binop_p<0x5E, "div", fdiv, 0>, basic_sse12_fp_binop_p_y<0x5E, "div", fdiv>, VEX_4V; defm VMAX : basic_sse12_fp_binop_s<0x5F, "max", X86fmax, 0>, + basic_sse12_fp_binop_s_int<0x5F, "max", 0>, basic_sse12_fp_binop_p<0x5F, "max", X86fmax, 0>, - basic_sse12_fp_binop_p_y<0x5F, "max", X86fmax>, VEX_4V; + basic_sse12_fp_binop_p_int<0x5F, "max", 0>, + basic_sse12_fp_binop_p_y<0x5F, "max", X86fmax>, + basic_sse12_fp_binop_p_y_int<0x5F, "max">, VEX_4V; defm VMIN : basic_sse12_fp_binop_s<0x5D, "min", X86fmin, 0>, + basic_sse12_fp_binop_s_int<0x5D, "min", 0>, basic_sse12_fp_binop_p<0x5D, "min", X86fmin, 0>, + basic_sse12_fp_binop_p_int<0x5D, "min", 0>, + basic_sse12_fp_binop_p_y_int<0x5D, "min">, basic_sse12_fp_binop_p_y<0x5D, "min", X86fmin>, VEX_4V; } } @@ -1668,20 +1837,20 @@ multiclass sse1_fp_unop_s opc, string OpcodeStr, multiclass sse1_fp_unop_s_avx opc, string OpcodeStr, SDNode OpNode, Intrinsic F32Int> { def SSr : SSI; def SSm : I, XS, Requires<[HasAVX, OptForSize]>; - def SSr_Int : SSI; - def SSm_Int : SSI; + def SSr_Int : SSI; + def SSm_Int : SSI; } /// sse1_fp_unop_p - SSE1 unops in packed form. @@ -1715,6 +1884,16 @@ multiclass sse1_fp_unop_p_int opc, string OpcodeStr, [(set VR128:$dst, (V4F32Int (memopv4f32 addr:$src)))]>; } +/// sse1_fp_unop_p_y_int - AVX 256-bit intrinsics unops in packed forms. +multiclass sse1_fp_unop_p_y_int opc, string OpcodeStr, + Intrinsic V4F32Int> { + def PSYr_Int : PSI; + def PSYm_Int : PSI; +} /// sse2_fp_unop_s - SSE2 unops in scalar form. multiclass sse2_fp_unop_s opc, string OpcodeStr, @@ -1738,21 +1917,19 @@ multiclass sse2_fp_unop_s opc, string OpcodeStr, /// sse2_fp_unop_s_avx - AVX SSE2 unops in scalar form. multiclass sse2_fp_unop_s_avx opc, string OpcodeStr, SDNode OpNode, Intrinsic F64Int> { - def SDr : VSDI; - def SDm : VSDI; - def SDr_Int : VSDI; - def SDm_Int : VSDI; + def SDr : SDI; + def SDm : SDI; + def SDr_Int : SDI; + def SDm_Int : SDI; } /// sse2_fp_unop_p - SSE2 unops in vector forms. @@ -1787,29 +1964,48 @@ multiclass sse2_fp_unop_p_int opc, string OpcodeStr, [(set VR128:$dst, (V2F64Int (memopv2f64 addr:$src)))]>; } +/// sse2_fp_unop_p_y_int - AVX 256-bit intrinsic unops in vector forms. +multiclass sse2_fp_unop_p_y_int opc, string OpcodeStr, + Intrinsic V2F64Int> { + def PDYr_Int : PDI; + def PDYm_Int : PDI; +} + let isAsmParserOnly = 1, Predicates = [HasAVX] in { // Square root. - defm VSQRT : sse1_fp_unop_s_avx<0x51, "sqrt", fsqrt, int_x86_sse_sqrt_ss>, - sse2_fp_unop_s_avx<0x51, "sqrt", fsqrt, int_x86_sse2_sqrt_sd>, + defm VSQRT : sse1_fp_unop_s_avx<0x51, "vsqrt", fsqrt, int_x86_sse_sqrt_ss>, + sse2_fp_unop_s_avx<0x51, "vsqrt", fsqrt, int_x86_sse2_sqrt_sd>, VEX_4V; defm VSQRT : sse1_fp_unop_p<0x51, "vsqrt", fsqrt>, sse2_fp_unop_p<0x51, "vsqrt", fsqrt>, sse1_fp_unop_p_y<0x51, "vsqrt", fsqrt>, sse2_fp_unop_p_y<0x51, "vsqrt", fsqrt>, + sse1_fp_unop_p_int<0x51, "vsqrt", int_x86_sse_sqrt_ps>, + sse2_fp_unop_p_int<0x51, "vsqrt", int_x86_sse2_sqrt_pd>, + sse1_fp_unop_p_y_int<0x51, "vsqrt", int_x86_avx_sqrt_ps_256>, + sse2_fp_unop_p_y_int<0x51, "vsqrt", int_x86_avx_sqrt_pd_256>, VEX; // Reciprocal approximations. Note that these typically require refinement // in order to obtain suitable precision. - defm VRSQRT : sse1_fp_unop_s_avx<0x52, "rsqrt", X86frsqrt, + defm VRSQRT : sse1_fp_unop_s_avx<0x52, "vrsqrt", X86frsqrt, int_x86_sse_rsqrt_ss>, VEX_4V; defm VRSQRT : sse1_fp_unop_p<0x52, "vrsqrt", X86frsqrt>, - sse1_fp_unop_p_y<0x52, "vrsqrt", X86frsqrt>, VEX; + sse1_fp_unop_p_y<0x52, "vrsqrt", X86frsqrt>, + sse1_fp_unop_p_y_int<0x52, "vrsqrt", int_x86_avx_rsqrt_ps_256>, + sse1_fp_unop_p_int<0x52, "vrsqrt", int_x86_sse_rsqrt_ps>, VEX; - defm VRCP : sse1_fp_unop_s_avx<0x53, "rcp", X86frcp, int_x86_sse_rcp_ss>, + defm VRCP : sse1_fp_unop_s_avx<0x53, "vrcp", X86frcp, int_x86_sse_rcp_ss>, VEX_4V; defm VRCP : sse1_fp_unop_p<0x53, "vrcp", X86frcp>, - sse1_fp_unop_p_y<0x53, "vrcp", X86frcp>, VEX; + sse1_fp_unop_p_y<0x53, "vrcp", X86frcp>, + sse1_fp_unop_p_y_int<0x53, "vrcp", int_x86_avx_rcp_ps_256>, + sse1_fp_unop_p_int<0x53, "vrcp", int_x86_sse_rcp_ps>, VEX; } // Square root. @@ -1898,6 +2094,13 @@ let isAsmParserOnly = 1 in { } } +def : Pat<(int_x86_avx_movnt_dq_256 addr:$dst, VR256:$src), + (VMOVNTDQYmr addr:$dst, VR256:$src)>; +def : Pat<(int_x86_avx_movnt_pd_256 addr:$dst, VR256:$src), + (VMOVNTPDYmr addr:$dst, VR256:$src)>; +def : Pat<(int_x86_avx_movnt_ps_256 addr:$dst, VR256:$src), + (VMOVNTPSYmr addr:$dst, VR256:$src)>; + def MOVNTPSmr_Int : PSI<0x2B, MRMDestMem, (outs), (ins i128mem:$dst, VR128:$src), "movntps\t{$src, $dst|$dst, $src}", [(int_x86_sse_movnt_ps addr:$dst, VR128:$src)]>; @@ -1961,11 +2164,14 @@ def PREFETCHNTA : PSI<0x18, MRM0m, (outs), (ins i8mem:$src), // Load, store, and memory fence def SFENCE : I<0xAE, MRM_F8, (outs), (ins), "sfence", [(int_x86_sse_sfence)]>, TB, Requires<[HasSSE1]>; +def : Pat<(X86SFence), (SFENCE)>; // Alias instructions that map zero vector to pxor / xorp* for sse. // We set canFoldAsLoad because this can be converted to a constant-pool // load of an all-zeros value if folding it would be beneficial. -// FIXME: Change encoding to pseudo! +// FIXME: Change encoding to pseudo! This is blocked right now by the x86 +// JIT implementatioan, it does not expand the instructions below like +// X86MCInstLower does. let isReMaterializable = 1, isAsCheapAsAMove = 1, canFoldAsLoad = 1, isCodeGenOnly = 1 in { def V_SET0PS : PSI<0x57, MRMInitReg, (outs VR128:$dst), (ins), "", @@ -1977,6 +2183,26 @@ def V_SET0PI : PDI<0xEF, MRMInitReg, (outs VR128:$dst), (ins), "", [(set VR128:$dst, (v4i32 immAllZerosV))]>; } +// The same as done above but for AVX. The 128-bit versions are the +// same, but re-encoded. The 256-bit does not support PI version. +// FIXME: Change encoding to pseudo! This is blocked right now by the x86 +// JIT implementatioan, it does not expand the instructions below like +// X86MCInstLower does. +let isReMaterializable = 1, isAsCheapAsAMove = 1, canFoldAsLoad = 1, + isCodeGenOnly = 1, Predicates = [HasAVX] in { +def AVX_SET0PS : PSI<0x57, MRMInitReg, (outs VR128:$dst), (ins), "", + [(set VR128:$dst, (v4f32 immAllZerosV))]>, VEX_4V; +def AVX_SET0PD : PDI<0x57, MRMInitReg, (outs VR128:$dst), (ins), "", + [(set VR128:$dst, (v2f64 immAllZerosV))]>, VEX_4V; +def AVX_SET0PSY : PSI<0x57, MRMInitReg, (outs VR256:$dst), (ins), "", + [(set VR256:$dst, (v8f32 immAllZerosV))]>, VEX_4V; +def AVX_SET0PDY : PDI<0x57, MRMInitReg, (outs VR256:$dst), (ins), "", + [(set VR256:$dst, (v4f64 immAllZerosV))]>, VEX_4V; +let ExeDomain = SSEPackedInt in +def AVX_SET0PI : PDI<0xEF, MRMInitReg, (outs VR128:$dst), (ins), "", + [(set VR128:$dst, (v4i32 immAllZerosV))]>; +} + def : Pat<(v2i64 immAllZerosV), (V_SET0PI)>; def : Pat<(v8i16 immAllZerosV), (V_SET0PI)>; def : Pat<(v16i8 immAllZerosV), (V_SET0PI)>; @@ -2003,35 +2229,47 @@ def STMXCSR : PSI<0xAE, MRM3m, (outs), (ins i32mem:$dst), //===---------------------------------------------------------------------===// // SSE2 - Move Aligned/Unaligned Packed Integer Instructions //===---------------------------------------------------------------------===// + let ExeDomain = SSEPackedInt in { // SSE integer instructions let isAsmParserOnly = 1 in { - let neverHasSideEffects = 1 in - def VMOVDQArr : VPDI<0x6F, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src), - "movdqa\t{$src, $dst|$dst, $src}", []>, VEX; - def VMOVDQUrr : VPDI<0x6F, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src), - "movdqu\t{$src, $dst|$dst, $src}", []>, XS, VEX; + let neverHasSideEffects = 1 in { + def VMOVDQArr : VPDI<0x6F, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src), + "movdqa\t{$src, $dst|$dst, $src}", []>, VEX; + def VMOVDQAYrr : VPDI<0x6F, MRMSrcReg, (outs VR256:$dst), (ins VR256:$src), + "movdqa\t{$src, $dst|$dst, $src}", []>, VEX; + } + def VMOVDQUrr : VPDI<0x6F, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src), + "movdqu\t{$src, $dst|$dst, $src}", []>, XS, VEX; + def VMOVDQUYrr : VPDI<0x6F, MRMSrcReg, (outs VR256:$dst), (ins VR256:$src), + "movdqu\t{$src, $dst|$dst, $src}", []>, XS, VEX; let canFoldAsLoad = 1, mayLoad = 1 in { - def VMOVDQArm : VPDI<0x6F, MRMSrcMem, (outs VR128:$dst), (ins i128mem:$src), - "movdqa\t{$src, $dst|$dst, $src}", - [/*(set VR128:$dst, (alignedloadv2i64 addr:$src))*/]>, - VEX; - def VMOVDQUrm : I<0x6F, MRMSrcMem, (outs VR128:$dst), (ins i128mem:$src), - "vmovdqu\t{$src, $dst|$dst, $src}", - [/*(set VR128:$dst, (loadv2i64 addr:$src))*/]>, - XS, VEX, Requires<[HasAVX]>; + def VMOVDQArm : VPDI<0x6F, MRMSrcMem, (outs VR128:$dst), (ins i128mem:$src), + "movdqa\t{$src, $dst|$dst, $src}", []>, VEX; + def VMOVDQAYrm : VPDI<0x6F, MRMSrcMem, (outs VR256:$dst), (ins i256mem:$src), + "movdqa\t{$src, $dst|$dst, $src}", []>, VEX; + let Predicates = [HasAVX] in { + def VMOVDQUrm : I<0x6F, MRMSrcMem, (outs VR128:$dst), (ins i128mem:$src), + "vmovdqu\t{$src, $dst|$dst, $src}",[]>, XS, VEX; + def VMOVDQUYrm : I<0x6F, MRMSrcMem, (outs VR256:$dst), (ins i256mem:$src), + "vmovdqu\t{$src, $dst|$dst, $src}",[]>, XS, VEX; + } } let mayStore = 1 in { - def VMOVDQAmr : VPDI<0x7F, MRMDestMem, (outs), - (ins i128mem:$dst, VR128:$src), - "movdqa\t{$src, $dst|$dst, $src}", - [/*(alignedstore (v2i64 VR128:$src), addr:$dst)*/]>, VEX; - def VMOVDQUmr : I<0x7F, MRMDestMem, (outs), (ins i128mem:$dst, VR128:$src), - "vmovdqu\t{$src, $dst|$dst, $src}", - [/*(store (v2i64 VR128:$src), addr:$dst)*/]>, - XS, VEX, Requires<[HasAVX]>; + def VMOVDQAmr : VPDI<0x7F, MRMDestMem, (outs), + (ins i128mem:$dst, VR128:$src), + "movdqa\t{$src, $dst|$dst, $src}", []>, VEX; + def VMOVDQAYmr : VPDI<0x7F, MRMDestMem, (outs), + (ins i256mem:$dst, VR256:$src), + "movdqa\t{$src, $dst|$dst, $src}", []>, VEX; + let Predicates = [HasAVX] in { + def VMOVDQUmr : I<0x7F, MRMDestMem, (outs), (ins i128mem:$dst, VR128:$src), + "vmovdqu\t{$src, $dst|$dst, $src}",[]>, XS, VEX; + def VMOVDQUYmr : I<0x7F, MRMDestMem, (outs), (ins i256mem:$dst, VR256:$src), + "vmovdqu\t{$src, $dst|$dst, $src}",[]>, XS, VEX; + } } } @@ -2084,6 +2322,10 @@ def MOVDQUmr_Int : I<0x7F, MRMDestMem, (outs), (ins i128mem:$dst, VR128:$src), } // ExeDomain = SSEPackedInt +def : Pat<(int_x86_avx_loadu_dq_256 addr:$src), (VMOVDQUYrm addr:$src)>; +def : Pat<(int_x86_avx_storeu_dq_256 addr:$dst, VR256:$src), + (VMOVDQUYmr addr:$dst, VR256:$src)>; + //===---------------------------------------------------------------------===// // SSE2 - Packed Integer Arithmetic Instructions //===---------------------------------------------------------------------===// @@ -2376,6 +2618,25 @@ let ExeDomain = SSEPackedInt in { } } // Constraints = "$src1 = $dst" +let Predicates = [HasAVX] in { + def : Pat<(int_x86_sse2_psll_dq VR128:$src1, imm:$src2), + (v2i64 (VPSLLDQri VR128:$src1, (BYTE_imm imm:$src2)))>; + def : Pat<(int_x86_sse2_psrl_dq VR128:$src1, imm:$src2), + (v2i64 (VPSRLDQri VR128:$src1, (BYTE_imm imm:$src2)))>; + def : Pat<(int_x86_sse2_psll_dq_bs VR128:$src1, imm:$src2), + (v2i64 (VPSLLDQri VR128:$src1, imm:$src2))>; + def : Pat<(int_x86_sse2_psrl_dq_bs VR128:$src1, imm:$src2), + (v2i64 (VPSRLDQri VR128:$src1, imm:$src2))>; + def : Pat<(v2f64 (X86fsrl VR128:$src1, i32immSExt8:$src2)), + (v2f64 (VPSRLDQri VR128:$src1, (BYTE_imm imm:$src2)))>; + + // Shift up / down and insert zero's. + def : Pat<(v2i64 (X86vshl VR128:$src, (i8 imm:$amt))), + (v2i64 (VPSLLDQri VR128:$src, (BYTE_imm imm:$amt)))>; + def : Pat<(v2i64 (X86vshr VR128:$src, (i8 imm:$amt))), + (v2i64 (VPSRLDQri VR128:$src, (BYTE_imm imm:$amt)))>; +} + let Predicates = [HasSSE2] in { def : Pat<(int_x86_sse2_psll_dq VR128:$src1, imm:$src2), (v2i64 (PSLLDQri VR128:$src1, (BYTE_imm imm:$src2)))>; @@ -2662,11 +2923,16 @@ def PEXTRWri : PDIi8<0xC5, MRMSrcReg, imm:$src2))]>; // Insert -let isAsmParserOnly = 1, Predicates = [HasAVX] in - defm PINSRW : sse2_pinsrw<0>, OpSize, VEX_4V; +let isAsmParserOnly = 1, Predicates = [HasAVX] in { + defm VPINSRW : sse2_pinsrw<0>, OpSize, VEX_4V; + def VPINSRWrr64i : Ii8<0xC4, MRMSrcReg, (outs VR128:$dst), + (ins VR128:$src1, GR64:$src2, i32i8imm:$src3), + "vpinsrw\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}", + []>, OpSize, VEX_4V; +} let Constraints = "$src1 = $dst" in - defm VPINSRW : sse2_pinsrw, TB, OpSize; + defm PINSRW : sse2_pinsrw, TB, OpSize, Requires<[HasSSE2]>; } // ExeDomain = SSEPackedInt @@ -2676,10 +2942,13 @@ let Constraints = "$src1 = $dst" in let ExeDomain = SSEPackedInt in { -let isAsmParserOnly = 1 in -def VPMOVMSKBrr : VPDI<0xD7, MRMSrcReg, (outs GR32:$dst), (ins VR128:$src), +let isAsmParserOnly = 1 in { +def VPMOVMSKBrr : VPDI<0xD7, MRMSrcReg, (outs GR32:$dst), (ins VR128:$src), "pmovmskb\t{$src, $dst|$dst, $src}", [(set GR32:$dst, (int_x86_sse2_pmovmskb_128 VR128:$src))]>, VEX; +def VPMOVMSKBr64r : VPDI<0xD7, MRMSrcReg, (outs GR64:$dst), (ins VR128:$src), + "pmovmskb\t{$src, $dst|$dst, $src}", []>, VEX; +} def PMOVMSKBrr : PDI<0xD7, MRMSrcReg, (outs GR32:$dst), (ins VR128:$src), "pmovmskb\t{$src, $dst|$dst, $src}", [(set GR32:$dst, (int_x86_sse2_pmovmskb_128 VR128:$src))]>; @@ -2939,18 +3208,20 @@ def : Pat<(v2i64 (X86vzmovl (bc_v2i64 (loadv4i32 addr:$src)))), // Instructions to match in the assembler let isAsmParserOnly = 1 in { -// This instructions is in fact an alias to movd with 64 bit dst def VMOVQs64rr : VPDI<0x6E, MRMSrcReg, (outs VR128:$dst), (ins GR64:$src), "movq\t{$src, $dst|$dst, $src}", []>, VEX, VEX_W; def VMOVQd64rr : VPDI<0x7E, MRMDestReg, (outs GR64:$dst), (ins VR128:$src), "movq\t{$src, $dst|$dst, $src}", []>, VEX, VEX_W; +// Recognize "movd" with GR64 destination, but encode as a "movq" +def VMOVQd64rr_alt : VPDI<0x7E, MRMDestReg, (outs GR64:$dst), (ins VR128:$src), + "movd\t{$src, $dst|$dst, $src}", []>, VEX, VEX_W; } // Instructions for the disassembler // xr = XMM register // xm = mem64 -let isAsmParserOnly = 1 in +let isAsmParserOnly = 1, Predicates = [HasAVX] in def VMOVQxrxr: I<0x7E, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src), "vmovq\t{$src, $dst|$dst, $src}", []>, VEX, XS; def MOVQxrxr : I<0x7E, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src), @@ -2970,19 +3241,14 @@ def LFENCE : I<0xAE, MRM_E8, (outs), (ins), "lfence", [(int_x86_sse2_lfence)]>, TB, Requires<[HasSSE2]>; def MFENCE : I<0xAE, MRM_F0, (outs), (ins), "mfence", [(int_x86_sse2_mfence)]>, TB, Requires<[HasSSE2]>; +def : Pat<(X86LFence), (LFENCE)>; +def : Pat<(X86MFence), (MFENCE)>; + // Pause. This "instruction" is encoded as "rep; nop", so even though it // was introduced with SSE2, it's backward compatible. def PAUSE : I<0x90, RawFrm, (outs), (ins), "pause", []>, REP; -//TODO: custom lower this so as to never even generate the noop -def : Pat<(membarrier (i8 imm), (i8 imm), (i8 imm), (i8 imm), - (i8 0)), (NOOP)>; -def : Pat<(membarrier (i8 0), (i8 0), (i8 0), (i8 1), (i8 1)), (SFENCE)>; -def : Pat<(membarrier (i8 1), (i8 0), (i8 0), (i8 0), (i8 1)), (LFENCE)>; -def : Pat<(membarrier (i8 imm), (i8 imm), (i8 imm), (i8 imm), - (i8 1)), (MFENCE)>; - // Alias instructions that map zero vector to pxor / xorp* for sse. // We set canFoldAsLoad because this can be converted to a constant-pool // load of an all-ones value if folding it would be beneficial. @@ -3027,13 +3293,13 @@ def CVTPD2DQrr : S3DI<0xE6, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src), // Convert Packed DW Integers to Packed Double FP let isAsmParserOnly = 1, Predicates = [HasAVX] in { def VCVTDQ2PDrm : S3SI<0xE6, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src), - "vcvtdq2pd\t{$src, $dst|$dst, $src}", []>, VEX; + "vcvtdq2pd\t{$src, $dst|$dst, $src}", []>, VEX; def VCVTDQ2PDrr : S3SI<0xE6, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src), - "vcvtdq2pd\t{$src, $dst|$dst, $src}", []>, VEX; + "vcvtdq2pd\t{$src, $dst|$dst, $src}", []>, VEX; def VCVTDQ2PDYrm : S3SI<0xE6, MRMSrcMem, (outs VR256:$dst), (ins f128mem:$src), - "vcvtdq2pd\t{$src, $dst|$dst, $src}", []>, VEX; + "vcvtdq2pd\t{$src, $dst|$dst, $src}", []>, VEX; def VCVTDQ2PDYrr : S3SI<0xE6, MRMSrcReg, (outs VR256:$dst), (ins VR128:$src), - "vcvtdq2pd\t{$src, $dst|$dst, $src}", []>, VEX; + "vcvtdq2pd\t{$src, $dst|$dst, $src}", []>, VEX; } def CVTDQ2PDrm : S3SI<0xE6, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src), @@ -3041,6 +3307,17 @@ def CVTDQ2PDrm : S3SI<0xE6, MRMSrcMem, (outs VR128:$dst), (ins f128mem:$src), def CVTDQ2PDrr : S3SI<0xE6, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src), "cvtdq2pd\t{$src, $dst|$dst, $src}", []>; +// AVX 256-bit register conversion intrinsics +def : Pat<(int_x86_avx_cvtdq2_pd_256 VR128:$src), + (VCVTDQ2PDYrr VR128:$src)>; +def : Pat<(int_x86_avx_cvtdq2_pd_256 (memopv4i32 addr:$src)), + (VCVTDQ2PDYrm addr:$src)>; + +def : Pat<(int_x86_avx_cvt_pd2dq_256 VR256:$src), + (VCVTPD2DQYrr VR256:$src)>; +def : Pat<(int_x86_avx_cvt_pd2dq_256 (memopv4f64 addr:$src)), + (VCVTPD2DQYrm addr:$src)>; + //===---------------------------------------------------------------------===// // SSE3 - Move Instructions //===---------------------------------------------------------------------===// @@ -3057,9 +3334,20 @@ def rm : S3SI; } +multiclass sse3_replicate_sfp_y op, PatFrag rep_frag, + string OpcodeStr> { +def rr : S3SI; +def rm : S3SI; +} + let isAsmParserOnly = 1, Predicates = [HasAVX] in { -defm VMOVSHDUP : sse3_replicate_sfp<0x16, movshdup, "vmovshdup">, VEX; -defm VMOVSLDUP : sse3_replicate_sfp<0x12, movsldup, "vmovsldup">, VEX; + // FIXME: Merge above classes when we have patterns for the ymm version + defm VMOVSHDUP : sse3_replicate_sfp<0x16, movshdup, "vmovshdup">, VEX; + defm VMOVSLDUP : sse3_replicate_sfp<0x12, movsldup, "vmovsldup">, VEX; + defm VMOVSHDUPY : sse3_replicate_sfp_y<0x16, movshdup, "vmovshdup">, VEX; + defm VMOVSLDUPY : sse3_replicate_sfp_y<0x12, movsldup, "vmovsldup">, VEX; } defm MOVSHDUP : sse3_replicate_sfp<0x16, movshdup, "movshdup">; defm MOVSLDUP : sse3_replicate_sfp<0x12, movsldup, "movsldup">; @@ -3076,15 +3364,31 @@ def rm : S3DI<0x12, MRMSrcMem, (outs VR128:$dst), (ins f64mem:$src), (undef))))]>; } -let isAsmParserOnly = 1, Predicates = [HasAVX] in - defm VMOVDDUP : sse3_replicate_dfp<"vmovddup">, VEX; +multiclass sse3_replicate_dfp_y { +def rr : S3DI<0x12, MRMSrcReg, (outs VR256:$dst), (ins VR256:$src), + !strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"), + []>; +def rm : S3DI<0x12, MRMSrcMem, (outs VR256:$dst), (ins f256mem:$src), + !strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"), + []>; +} + +let isAsmParserOnly = 1, Predicates = [HasAVX] in { + // FIXME: Merge above classes when we have patterns for the ymm version + defm VMOVDDUP : sse3_replicate_dfp<"vmovddup">, VEX; + defm VMOVDDUPY : sse3_replicate_dfp_y<"vmovddup">, VEX; +} defm MOVDDUP : sse3_replicate_dfp<"movddup">; // Move Unaligned Integer -let isAsmParserOnly = 1 in +let isAsmParserOnly = 1, Predicates = [HasAVX] in { def VLDDQUrm : S3DI<0xF0, MRMSrcMem, (outs VR128:$dst), (ins i128mem:$src), - "vlddqu\t{$src, $dst|$dst, $src}", - [(set VR128:$dst, (int_x86_sse3_ldu_dq addr:$src))]>, VEX; + "vlddqu\t{$src, $dst|$dst, $src}", + [(set VR128:$dst, (int_x86_sse3_ldu_dq addr:$src))]>, VEX; + def VLDDQUYrm : S3DI<0xF0, MRMSrcMem, (outs VR256:$dst), (ins i256mem:$src), + "vlddqu\t{$src, $dst|$dst, $src}", + [(set VR256:$dst, (int_x86_avx_ldu_dq_256 addr:$src))]>, VEX; +} def LDDQUrm : S3DI<0xF0, MRMSrcMem, (outs VR128:$dst), (ins i128mem:$src), "lddqu\t{$src, $dst|$dst, $src}", [(set VR128:$dst, (int_x86_sse3_ldu_dq addr:$src))]>; @@ -3125,35 +3429,39 @@ let AddedComplexity = 20 in // SSE3 - Arithmetic //===---------------------------------------------------------------------===// -multiclass sse3_addsub { +multiclass sse3_addsub { def rr : I<0xD0, MRMSrcReg, - (outs VR128:$dst), (ins VR128:$src1, VR128:$src2), + (outs RC:$dst), (ins RC:$src1, RC:$src2), !if(Is2Addr, !strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"), !strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")), - [(set VR128:$dst, (Int VR128:$src1, - VR128:$src2))]>; + [(set RC:$dst, (Int RC:$src1, RC:$src2))]>; def rm : I<0xD0, MRMSrcMem, - (outs VR128:$dst), (ins VR128:$src1, f128mem:$src2), + (outs RC:$dst), (ins RC:$src1, x86memop:$src2), !if(Is2Addr, !strconcat(OpcodeStr, "\t{$src2, $dst|$dst, $src2}"), !strconcat(OpcodeStr, "\t{$src2, $src1, $dst|$dst, $src1, $src2}")), - [(set VR128:$dst, (Int VR128:$src1, - (memop addr:$src2)))]>; - + [(set RC:$dst, (Int RC:$src1, (memop addr:$src2)))]>; } let isAsmParserOnly = 1, Predicates = [HasAVX], ExeDomain = SSEPackedDouble in { - defm VADDSUBPS : sse3_addsub, XD, - VEX_4V; - defm VADDSUBPD : sse3_addsub, OpSize, - VEX_4V; + defm VADDSUBPS : sse3_addsub, XD, VEX_4V; + defm VADDSUBPD : sse3_addsub, OpSize, VEX_4V; + defm VADDSUBPSY : sse3_addsub, XD, VEX_4V; + defm VADDSUBPDY : sse3_addsub, OpSize, VEX_4V; } let Constraints = "$src1 = $dst", Predicates = [HasSSE3], ExeDomain = SSEPackedDouble in { - defm ADDSUBPS : sse3_addsub, XD; - defm ADDSUBPD : sse3_addsub, TB, OpSize; + defm ADDSUBPS : sse3_addsub, XD; + defm ADDSUBPD : sse3_addsub, TB, OpSize; } //===---------------------------------------------------------------------===// @@ -3161,61 +3469,72 @@ let Constraints = "$src1 = $dst", Predicates = [HasSSE3], //===---------------------------------------------------------------------===// // Horizontal ops -class S3D_Intrr o, string OpcodeStr, Intrinsic IntId, bit Is2Addr = 1> - : S3DI o, string OpcodeStr, ValueType vt, RegisterClass RC, + X86MemOperand x86memop, Intrinsic IntId, bit Is2Addr = 1> { + def rr : S3DI; -class S3D_Intrm o, string OpcodeStr, Intrinsic IntId, bit Is2Addr = 1> - : S3DI; + + def rm : S3DI; -class S3_Intrr o, string OpcodeStr, Intrinsic IntId, bit Is2Addr = 1> - : S3I; +} +multiclass S3_Int o, string OpcodeStr, ValueType vt, RegisterClass RC, + X86MemOperand x86memop, Intrinsic IntId, bit Is2Addr = 1> { + def rr : S3I; -class S3_Intrm o, string OpcodeStr, Intrinsic IntId, bit Is2Addr = 1> - : S3I; + + def rm : S3I; + [(set RC:$dst, (vt (IntId RC:$src1, (memop addr:$src2))))]>; +} let isAsmParserOnly = 1, Predicates = [HasAVX] in { - def VHADDPSrr : S3D_Intrr<0x7C, "vhaddps", int_x86_sse3_hadd_ps, 0>, VEX_4V; - def VHADDPSrm : S3D_Intrm<0x7C, "vhaddps", int_x86_sse3_hadd_ps, 0>, VEX_4V; - def VHADDPDrr : S3_Intrr <0x7C, "vhaddpd", int_x86_sse3_hadd_pd, 0>, VEX_4V; - def VHADDPDrm : S3_Intrm <0x7C, "vhaddpd", int_x86_sse3_hadd_pd, 0>, VEX_4V; - def VHSUBPSrr : S3D_Intrr<0x7D, "vhsubps", int_x86_sse3_hsub_ps, 0>, VEX_4V; - def VHSUBPSrm : S3D_Intrm<0x7D, "vhsubps", int_x86_sse3_hsub_ps, 0>, VEX_4V; - def VHSUBPDrr : S3_Intrr <0x7D, "vhsubpd", int_x86_sse3_hsub_pd, 0>, VEX_4V; - def VHSUBPDrm : S3_Intrm <0x7D, "vhsubpd", int_x86_sse3_hsub_pd, 0>, VEX_4V; + defm VHADDPS : S3D_Int<0x7C, "vhaddps", v4f32, VR128, f128mem, + int_x86_sse3_hadd_ps, 0>, VEX_4V; + defm VHADDPD : S3_Int <0x7C, "vhaddpd", v2f64, VR128, f128mem, + int_x86_sse3_hadd_pd, 0>, VEX_4V; + defm VHSUBPS : S3D_Int<0x7D, "vhsubps", v4f32, VR128, f128mem, + int_x86_sse3_hsub_ps, 0>, VEX_4V; + defm VHSUBPD : S3_Int <0x7D, "vhsubpd", v2f64, VR128, f128mem, + int_x86_sse3_hsub_pd, 0>, VEX_4V; + defm VHADDPSY : S3D_Int<0x7C, "vhaddps", v8f32, VR256, f256mem, + int_x86_avx_hadd_ps_256, 0>, VEX_4V; + defm VHADDPDY : S3_Int <0x7C, "vhaddpd", v4f64, VR256, f256mem, + int_x86_avx_hadd_pd_256, 0>, VEX_4V; + defm VHSUBPSY : S3D_Int<0x7D, "vhsubps", v8f32, VR256, f256mem, + int_x86_avx_hsub_ps_256, 0>, VEX_4V; + defm VHSUBPDY : S3_Int <0x7D, "vhsubpd", v4f64, VR256, f256mem, + int_x86_avx_hsub_pd_256, 0>, VEX_4V; } let Constraints = "$src1 = $dst" in { - def HADDPSrr : S3D_Intrr<0x7C, "haddps", int_x86_sse3_hadd_ps>; - def HADDPSrm : S3D_Intrm<0x7C, "haddps", int_x86_sse3_hadd_ps>; - def HADDPDrr : S3_Intrr <0x7C, "haddpd", int_x86_sse3_hadd_pd>; - def HADDPDrm : S3_Intrm <0x7C, "haddpd", int_x86_sse3_hadd_pd>; - def HSUBPSrr : S3D_Intrr<0x7D, "hsubps", int_x86_sse3_hsub_ps>; - def HSUBPSrm : S3D_Intrm<0x7D, "hsubps", int_x86_sse3_hsub_ps>; - def HSUBPDrr : S3_Intrr <0x7D, "hsubpd", int_x86_sse3_hsub_pd>; - def HSUBPDrm : S3_Intrm <0x7D, "hsubpd", int_x86_sse3_hsub_pd>; + defm HADDPS : S3D_Int<0x7C, "haddps", v4f32, VR128, f128mem, + int_x86_sse3_hadd_ps>; + defm HADDPD : S3_Int<0x7C, "haddpd", v2f64, VR128, f128mem, + int_x86_sse3_hadd_pd>; + defm HSUBPS : S3D_Int<0x7D, "hsubps", v4f32, VR128, f128mem, + int_x86_sse3_hsub_ps>; + defm HSUBPD : S3_Int<0x7D, "hsubpd", v2f64, VR128, f128mem, + int_x86_sse3_hsub_pd>; } //===---------------------------------------------------------------------===// // SSSE3 - Packed Absolute Instructions //===---------------------------------------------------------------------===// -/// SS3I_unop_rm_int - Simple SSSE3 unary op whose type can be v*{i8,i16,i32}. -multiclass SS3I_unop_rm_int opc, string OpcodeStr, - PatFrag mem_frag64, PatFrag mem_frag128, - Intrinsic IntId64, Intrinsic IntId128> { +/// SS3I_unop_rm_int_mm - Simple SSSE3 unary whose type can be v*{i8,i16,i32}. +multiclass SS3I_unop_rm_int_mm opc, string OpcodeStr, + PatFrag mem_frag64, Intrinsic IntId64> { def rr64 : SS38I; @@ -3224,7 +3543,11 @@ multiclass SS3I_unop_rm_int opc, string OpcodeStr, !strconcat(OpcodeStr, "\t{$src, $dst|$dst, $src}"), [(set VR64:$dst, (IntId64 (bitconvert (mem_frag64 addr:$src))))]>; +} +/// SS3I_unop_rm_int - Simple SSSE3 unary op whose type can be v*{i8,i16,i32}. +multiclass SS3I_unop_rm_int opc, string OpcodeStr, + PatFrag mem_frag128, Intrinsic IntId128> { def rr128 : SS38I opc, string OpcodeStr, } let isAsmParserOnly = 1, Predicates = [HasAVX] in { - defm VPABSB : SS3I_unop_rm_int<0x1C, "vpabsb", memopv8i8, memopv16i8, - int_x86_ssse3_pabs_b, + defm VPABSB : SS3I_unop_rm_int<0x1C, "vpabsb", memopv16i8, int_x86_ssse3_pabs_b_128>, VEX; - defm VPABSW : SS3I_unop_rm_int<0x1D, "vpabsw", memopv4i16, memopv8i16, - int_x86_ssse3_pabs_w, + defm VPABSW : SS3I_unop_rm_int<0x1D, "vpabsw", memopv8i16, int_x86_ssse3_pabs_w_128>, VEX; - defm VPABSD : SS3I_unop_rm_int<0x1E, "vpabsd", memopv2i32, memopv4i32, - int_x86_ssse3_pabs_d, + defm VPABSD : SS3I_unop_rm_int<0x1E, "vpabsd", memopv4i32, int_x86_ssse3_pabs_d_128>, VEX; } -defm PABSB : SS3I_unop_rm_int<0x1C, "pabsb", memopv8i8, memopv16i8, - int_x86_ssse3_pabs_b, - int_x86_ssse3_pabs_b_128>; -defm PABSW : SS3I_unop_rm_int<0x1D, "pabsw", memopv4i16, memopv8i16, - int_x86_ssse3_pabs_w, - int_x86_ssse3_pabs_w_128>; -defm PABSD : SS3I_unop_rm_int<0x1E, "pabsd", memopv2i32, memopv4i32, - int_x86_ssse3_pabs_d, - int_x86_ssse3_pabs_d_128>; +defm PABSB : SS3I_unop_rm_int<0x1C, "pabsb", memopv16i8, + int_x86_ssse3_pabs_b_128>, + SS3I_unop_rm_int_mm<0x1C, "pabsb", memopv8i8, + int_x86_ssse3_pabs_b>; + +defm PABSW : SS3I_unop_rm_int<0x1D, "pabsw", memopv8i16, + int_x86_ssse3_pabs_w_128>, + SS3I_unop_rm_int_mm<0x1D, "pabsw", memopv4i16, + int_x86_ssse3_pabs_w>; + +defm PABSD : SS3I_unop_rm_int<0x1E, "pabsd", memopv4i32, + int_x86_ssse3_pabs_d_128>, + SS3I_unop_rm_int_mm<0x1E, "pabsd", memopv2i32, + int_x86_ssse3_pabs_d>; //===---------------------------------------------------------------------===// // SSSE3 - Packed Binary Operator Instructions @@ -3267,26 +3592,9 @@ defm PABSD : SS3I_unop_rm_int<0x1E, "pabsd", memopv2i32, memopv4i32, /// SS3I_binop_rm_int - Simple SSSE3 bin op whose type can be v*{i8,i16,i32}. multiclass SS3I_binop_rm_int opc, string OpcodeStr, - PatFrag mem_frag64, PatFrag mem_frag128, - Intrinsic IntId64, Intrinsic IntId128, + PatFrag mem_frag128, Intrinsic IntId128, bit Is2Addr = 1> { let isCommutable = 1 in - def rr64 : SS38I; - def rm64 : SS38I; - - let isCommutable = 1 in def rr128 : SS38I opc, string OpcodeStr, (IntId128 VR128:$src1, (bitconvert (memopv16i8 addr:$src2))))]>, OpSize; } +multiclass SS3I_binop_rm_int_mm opc, string OpcodeStr, + PatFrag mem_frag64, Intrinsic IntId64> { + let isCommutable = 1 in + def rr64 : SS38I; + def rm64 : SS38I; +} let isAsmParserOnly = 1, Predicates = [HasAVX] in { let isCommutable = 0 in { - defm VPHADDW : SS3I_binop_rm_int<0x01, "vphaddw", memopv4i16, memopv8i16, - int_x86_ssse3_phadd_w, + defm VPHADDW : SS3I_binop_rm_int<0x01, "vphaddw", memopv8i16, int_x86_ssse3_phadd_w_128, 0>, VEX_4V; - defm VPHADDD : SS3I_binop_rm_int<0x02, "vphaddd", memopv2i32, memopv4i32, - int_x86_ssse3_phadd_d, + defm VPHADDD : SS3I_binop_rm_int<0x02, "vphaddd", memopv4i32, int_x86_ssse3_phadd_d_128, 0>, VEX_4V; - defm VPHADDSW : SS3I_binop_rm_int<0x03, "vphaddsw", memopv4i16, memopv8i16, - int_x86_ssse3_phadd_sw, + defm VPHADDSW : SS3I_binop_rm_int<0x03, "vphaddsw", memopv8i16, int_x86_ssse3_phadd_sw_128, 0>, VEX_4V; - defm VPHSUBW : SS3I_binop_rm_int<0x05, "vphsubw", memopv4i16, memopv8i16, - int_x86_ssse3_phsub_w, + defm VPHSUBW : SS3I_binop_rm_int<0x05, "vphsubw", memopv8i16, int_x86_ssse3_phsub_w_128, 0>, VEX_4V; - defm VPHSUBD : SS3I_binop_rm_int<0x06, "vphsubd", memopv2i32, memopv4i32, - int_x86_ssse3_phsub_d, + defm VPHSUBD : SS3I_binop_rm_int<0x06, "vphsubd", memopv4i32, int_x86_ssse3_phsub_d_128, 0>, VEX_4V; - defm VPHSUBSW : SS3I_binop_rm_int<0x07, "vphsubsw", memopv4i16, memopv8i16, - int_x86_ssse3_phsub_sw, + defm VPHSUBSW : SS3I_binop_rm_int<0x07, "vphsubsw", memopv8i16, int_x86_ssse3_phsub_sw_128, 0>, VEX_4V; - defm VPMADDUBSW : SS3I_binop_rm_int<0x04, "vpmaddubsw", memopv8i8, memopv16i8, - int_x86_ssse3_pmadd_ub_sw, + defm VPMADDUBSW : SS3I_binop_rm_int<0x04, "vpmaddubsw", memopv16i8, int_x86_ssse3_pmadd_ub_sw_128, 0>, VEX_4V; - defm VPSHUFB : SS3I_binop_rm_int<0x00, "vpshufb", memopv8i8, memopv16i8, - int_x86_ssse3_pshuf_b, + defm VPSHUFB : SS3I_binop_rm_int<0x00, "vpshufb", memopv16i8, int_x86_ssse3_pshuf_b_128, 0>, VEX_4V; - defm VPSIGNB : SS3I_binop_rm_int<0x08, "vpsignb", memopv8i8, memopv16i8, - int_x86_ssse3_psign_b, + defm VPSIGNB : SS3I_binop_rm_int<0x08, "vpsignb", memopv16i8, int_x86_ssse3_psign_b_128, 0>, VEX_4V; - defm VPSIGNW : SS3I_binop_rm_int<0x09, "vpsignw", memopv4i16, memopv8i16, - int_x86_ssse3_psign_w, + defm VPSIGNW : SS3I_binop_rm_int<0x09, "vpsignw", memopv8i16, int_x86_ssse3_psign_w_128, 0>, VEX_4V; - defm VPSIGND : SS3I_binop_rm_int<0x0A, "vpsignd", memopv2i32, memopv4i32, - int_x86_ssse3_psign_d, + defm VPSIGND : SS3I_binop_rm_int<0x0A, "vpsignd", memopv4i32, int_x86_ssse3_psign_d_128, 0>, VEX_4V; } -defm VPMULHRSW : SS3I_binop_rm_int<0x0B, "vpmulhrsw", memopv4i16, memopv8i16, - int_x86_ssse3_pmul_hr_sw, +defm VPMULHRSW : SS3I_binop_rm_int<0x0B, "vpmulhrsw", memopv8i16, int_x86_ssse3_pmul_hr_sw_128, 0>, VEX_4V; } // None of these have i8 immediate fields. let ImmT = NoImm, Constraints = "$src1 = $dst" in { let isCommutable = 0 in { - defm PHADDW : SS3I_binop_rm_int<0x01, "phaddw", memopv4i16, memopv8i16, - int_x86_ssse3_phadd_w, - int_x86_ssse3_phadd_w_128>; - defm PHADDD : SS3I_binop_rm_int<0x02, "phaddd", memopv2i32, memopv4i32, - int_x86_ssse3_phadd_d, - int_x86_ssse3_phadd_d_128>; - defm PHADDSW : SS3I_binop_rm_int<0x03, "phaddsw", memopv4i16, memopv8i16, - int_x86_ssse3_phadd_sw, - int_x86_ssse3_phadd_sw_128>; - defm PHSUBW : SS3I_binop_rm_int<0x05, "phsubw", memopv4i16, memopv8i16, - int_x86_ssse3_phsub_w, - int_x86_ssse3_phsub_w_128>; - defm PHSUBD : SS3I_binop_rm_int<0x06, "phsubd", memopv2i32, memopv4i32, - int_x86_ssse3_phsub_d, - int_x86_ssse3_phsub_d_128>; - defm PHSUBSW : SS3I_binop_rm_int<0x07, "phsubsw", memopv4i16, memopv8i16, - int_x86_ssse3_phsub_sw, - int_x86_ssse3_phsub_sw_128>; - defm PMADDUBSW : SS3I_binop_rm_int<0x04, "pmaddubsw", memopv8i8, memopv16i8, - int_x86_ssse3_pmadd_ub_sw, - int_x86_ssse3_pmadd_ub_sw_128>; - defm PSHUFB : SS3I_binop_rm_int<0x00, "pshufb", memopv8i8, memopv16i8, - int_x86_ssse3_pshuf_b, - int_x86_ssse3_pshuf_b_128>; - defm PSIGNB : SS3I_binop_rm_int<0x08, "psignb", memopv8i8, memopv16i8, - int_x86_ssse3_psign_b, - int_x86_ssse3_psign_b_128>; - defm PSIGNW : SS3I_binop_rm_int<0x09, "psignw", memopv4i16, memopv8i16, - int_x86_ssse3_psign_w, - int_x86_ssse3_psign_w_128>; - defm PSIGND : SS3I_binop_rm_int<0x0A, "psignd", memopv2i32, memopv4i32, - int_x86_ssse3_psign_d, - int_x86_ssse3_psign_d_128>; -} -defm PMULHRSW : SS3I_binop_rm_int<0x0B, "pmulhrsw", memopv4i16, memopv8i16, - int_x86_ssse3_pmul_hr_sw, - int_x86_ssse3_pmul_hr_sw_128>; + defm PHADDW : SS3I_binop_rm_int<0x01, "phaddw", memopv8i16, + int_x86_ssse3_phadd_w_128>, + SS3I_binop_rm_int_mm<0x01, "phaddw", memopv4i16, + int_x86_ssse3_phadd_w>; + defm PHADDD : SS3I_binop_rm_int<0x02, "phaddd", memopv4i32, + int_x86_ssse3_phadd_d_128>, + SS3I_binop_rm_int_mm<0x02, "phaddd", memopv2i32, + int_x86_ssse3_phadd_d>; + defm PHADDSW : SS3I_binop_rm_int<0x03, "phaddsw", memopv8i16, + int_x86_ssse3_phadd_sw_128>, + SS3I_binop_rm_int_mm<0x03, "phaddsw", memopv4i16, + int_x86_ssse3_phadd_sw>; + defm PHSUBW : SS3I_binop_rm_int<0x05, "phsubw", memopv8i16, + int_x86_ssse3_phsub_w_128>, + SS3I_binop_rm_int_mm<0x05, "phsubw", memopv4i16, + int_x86_ssse3_phsub_w>; + defm PHSUBD : SS3I_binop_rm_int<0x06, "phsubd", memopv4i32, + int_x86_ssse3_phsub_d_128>, + SS3I_binop_rm_int_mm<0x06, "phsubd", memopv2i32, + int_x86_ssse3_phsub_d>; + defm PHSUBSW : SS3I_binop_rm_int<0x07, "phsubsw", memopv8i16, + int_x86_ssse3_phsub_sw_128>, + SS3I_binop_rm_int_mm<0x07, "phsubsw", memopv4i16, + int_x86_ssse3_phsub_sw>; + defm PMADDUBSW : SS3I_binop_rm_int<0x04, "pmaddubsw", memopv16i8, + int_x86_ssse3_pmadd_ub_sw_128>, + SS3I_binop_rm_int_mm<0x04, "pmaddubsw", memopv8i8, + int_x86_ssse3_pmadd_ub_sw>; + defm PSHUFB : SS3I_binop_rm_int<0x00, "pshufb", memopv8i8, + int_x86_ssse3_pshuf_b_128>, + SS3I_binop_rm_int_mm<0x00, "pshufb", memopv8i8, + int_x86_ssse3_pshuf_b>; + defm PSIGNB : SS3I_binop_rm_int<0x08, "psignb", memopv16i8, + int_x86_ssse3_psign_b_128>, + SS3I_binop_rm_int_mm<0x08, "psignb", memopv8i8, + int_x86_ssse3_psign_b>; + defm PSIGNW : SS3I_binop_rm_int<0x09, "psignw", memopv8i16, + int_x86_ssse3_psign_w_128>, + SS3I_binop_rm_int_mm<0x09, "psignw", memopv4i16, + int_x86_ssse3_psign_w>; + defm PSIGND : SS3I_binop_rm_int<0x0A, "psignd", memopv4i32, + int_x86_ssse3_psign_d_128>, + SS3I_binop_rm_int_mm<0x0A, "psignd", memopv2i32, + int_x86_ssse3_psign_d>; +} +defm PMULHRSW : SS3I_binop_rm_int<0x0B, "pmulhrsw", memopv8i16, + int_x86_ssse3_pmul_hr_sw_128>, + SS3I_binop_rm_int_mm<0x0B, "pmulhrsw", memopv4i16, + int_x86_ssse3_pmul_hr_sw>; } def : Pat<(X86pshufb VR128:$src, VR128:$mask), @@ -3396,22 +3718,16 @@ def : Pat<(X86pshufb VR128:$src, (bc_v16i8 (memopv2i64 addr:$mask))), // SSSE3 - Packed Align Instruction Patterns //===---------------------------------------------------------------------===// -multiclass sse3_palign { +multiclass ssse3_palign_mm { def R64rr : SS3AI<0x0F, MRMSrcReg, (outs VR64:$dst), (ins VR64:$src1, VR64:$src2, i8imm:$src3), - !if(Is2Addr, - !strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"), - !strconcat(asm, - "\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}")), - []>; + !strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"), []>; def R64rm : SS3AI<0x0F, MRMSrcMem, (outs VR64:$dst), (ins VR64:$src1, i64mem:$src2, i8imm:$src3), - !if(Is2Addr, - !strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"), - !strconcat(asm, - "\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}")), - []>; + !strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"), []>; +} +multiclass ssse3_palign { def R128rr : SS3AI<0x0F, MRMSrcReg, (outs VR128:$dst), (ins VR128:$src1, VR128:$src2, i8imm:$src3), !if(Is2Addr, @@ -3429,9 +3745,10 @@ multiclass sse3_palign { } let isAsmParserOnly = 1, Predicates = [HasAVX] in - defm VPALIGN : sse3_palign<"vpalignr", 0>, VEX_4V; + defm VPALIGN : ssse3_palign<"vpalignr", 0>, VEX_4V; let Constraints = "$src1 = $dst" in - defm PALIGN : sse3_palign<"palignr">; + defm PALIGN : ssse3_palign<"palignr">, + ssse3_palign_mm<"palignr">; let AddedComplexity = 5 in { @@ -3732,31 +4049,62 @@ def : Pat<(v2i32 (fp_to_sint (v2f64 VR128:$src))), (Int_CVTTPD2PIrr VR128:$src)>, Requires<[HasSSE2]>; // Use movaps / movups for SSE integer load / store (one byte shorter). -def : Pat<(alignedloadv4i32 addr:$src), - (MOVAPSrm addr:$src)>; -def : Pat<(loadv4i32 addr:$src), - (MOVUPSrm addr:$src)>; -def : Pat<(alignedloadv2i64 addr:$src), - (MOVAPSrm addr:$src)>; -def : Pat<(loadv2i64 addr:$src), - (MOVUPSrm addr:$src)>; - -def : Pat<(alignedstore (v2i64 VR128:$src), addr:$dst), - (MOVAPSmr addr:$dst, VR128:$src)>; -def : Pat<(alignedstore (v4i32 VR128:$src), addr:$dst), - (MOVAPSmr addr:$dst, VR128:$src)>; -def : Pat<(alignedstore (v8i16 VR128:$src), addr:$dst), - (MOVAPSmr addr:$dst, VR128:$src)>; -def : Pat<(alignedstore (v16i8 VR128:$src), addr:$dst), - (MOVAPSmr addr:$dst, VR128:$src)>; -def : Pat<(store (v2i64 VR128:$src), addr:$dst), - (MOVUPSmr addr:$dst, VR128:$src)>; -def : Pat<(store (v4i32 VR128:$src), addr:$dst), - (MOVUPSmr addr:$dst, VR128:$src)>; -def : Pat<(store (v8i16 VR128:$src), addr:$dst), - (MOVUPSmr addr:$dst, VR128:$src)>; -def : Pat<(store (v16i8 VR128:$src), addr:$dst), - (MOVUPSmr addr:$dst, VR128:$src)>; +let Predicates = [HasSSE1] in { + def : Pat<(alignedloadv4i32 addr:$src), + (MOVAPSrm addr:$src)>; + def : Pat<(loadv4i32 addr:$src), + (MOVUPSrm addr:$src)>; + def : Pat<(alignedloadv2i64 addr:$src), + (MOVAPSrm addr:$src)>; + def : Pat<(loadv2i64 addr:$src), + (MOVUPSrm addr:$src)>; + + def : Pat<(alignedstore (v2i64 VR128:$src), addr:$dst), + (MOVAPSmr addr:$dst, VR128:$src)>; + def : Pat<(alignedstore (v4i32 VR128:$src), addr:$dst), + (MOVAPSmr addr:$dst, VR128:$src)>; + def : Pat<(alignedstore (v8i16 VR128:$src), addr:$dst), + (MOVAPSmr addr:$dst, VR128:$src)>; + def : Pat<(alignedstore (v16i8 VR128:$src), addr:$dst), + (MOVAPSmr addr:$dst, VR128:$src)>; + def : Pat<(store (v2i64 VR128:$src), addr:$dst), + (MOVUPSmr addr:$dst, VR128:$src)>; + def : Pat<(store (v4i32 VR128:$src), addr:$dst), + (MOVUPSmr addr:$dst, VR128:$src)>; + def : Pat<(store (v8i16 VR128:$src), addr:$dst), + (MOVUPSmr addr:$dst, VR128:$src)>; + def : Pat<(store (v16i8 VR128:$src), addr:$dst), + (MOVUPSmr addr:$dst, VR128:$src)>; +} + +// Use vmovaps/vmovups for AVX 128-bit integer load/store (one byte shorter). +let Predicates = [HasAVX] in { + def : Pat<(alignedloadv4i32 addr:$src), + (VMOVAPSrm addr:$src)>; + def : Pat<(loadv4i32 addr:$src), + (VMOVUPSrm addr:$src)>; + def : Pat<(alignedloadv2i64 addr:$src), + (VMOVAPSrm addr:$src)>; + def : Pat<(loadv2i64 addr:$src), + (VMOVUPSrm addr:$src)>; + + def : Pat<(alignedstore (v2i64 VR128:$src), addr:$dst), + (VMOVAPSmr addr:$dst, VR128:$src)>; + def : Pat<(alignedstore (v4i32 VR128:$src), addr:$dst), + (VMOVAPSmr addr:$dst, VR128:$src)>; + def : Pat<(alignedstore (v8i16 VR128:$src), addr:$dst), + (VMOVAPSmr addr:$dst, VR128:$src)>; + def : Pat<(alignedstore (v16i8 VR128:$src), addr:$dst), + (VMOVAPSmr addr:$dst, VR128:$src)>; + def : Pat<(store (v2i64 VR128:$src), addr:$dst), + (VMOVUPSmr addr:$dst, VR128:$src)>; + def : Pat<(store (v4i32 VR128:$src), addr:$dst), + (VMOVUPSmr addr:$dst, VR128:$src)>; + def : Pat<(store (v8i16 VR128:$src), addr:$dst), + (VMOVUPSmr addr:$dst, VR128:$src)>; + def : Pat<(store (v16i8 VR128:$src), addr:$dst), + (VMOVUPSmr addr:$dst, VR128:$src)>; +} //===----------------------------------------------------------------------===// // SSE4.1 - Packed Move with Sign/Zero Extend @@ -3923,8 +4271,12 @@ multiclass SS41I_extract8 opc, string OpcodeStr> { // (store (i8 (trunc (X86pextrb (v16i8 VR128:$src1), imm:$src2))), addr:$dst) } -let isAsmParserOnly = 1, Predicates = [HasAVX] in +let isAsmParserOnly = 1, Predicates = [HasAVX] in { defm VPEXTRB : SS41I_extract8<0x14, "vpextrb">, VEX; + def VPEXTRBrr64 : SS4AIi8<0x14, MRMDestReg, (outs GR64:$dst), + (ins VR128:$src1, i32i8imm:$src2), + "vpextrb\t{$src2, $src1, $dst|$dst, $src1, $src2}", []>, OpSize, VEX; +} defm PEXTRB : SS41I_extract8<0x14, "pextrb">; @@ -4007,8 +4359,13 @@ multiclass SS41I_extractf32 opc, string OpcodeStr> { addr:$dst)]>, OpSize; } -let isAsmParserOnly = 1, Predicates = [HasAVX] in +let isAsmParserOnly = 1, Predicates = [HasAVX] in { defm VEXTRACTPS : SS41I_extractf32<0x17, "vextractps">, VEX; + def VEXTRACTPSrr64 : SS4AIi8<0x17, MRMDestReg, (outs GR64:$dst), + (ins VR128:$src1, i32i8imm:$src2), + "vextractps \t{$src2, $src1, $dst|$dst, $src1, $src2}", + []>, OpSize, VEX; +} defm EXTRACTPS : SS41I_extractf32<0x17, "extractps">; // Also match an EXTRACTPS store when the store is done as f32 instead of i32. @@ -4131,80 +4488,84 @@ let isAsmParserOnly = 1, Predicates = [HasAVX] in defm VINSERTPS : SS41I_insertf32<0x21, "vinsertps", 0>, VEX_4V; def : Pat<(int_x86_sse41_insertps VR128:$src1, VR128:$src2, imm:$src3), - (INSERTPSrr VR128:$src1, VR128:$src2, imm:$src3)>; + (VINSERTPSrr VR128:$src1, VR128:$src2, imm:$src3)>, + Requires<[HasAVX]>; +def : Pat<(int_x86_sse41_insertps VR128:$src1, VR128:$src2, imm:$src3), + (INSERTPSrr VR128:$src1, VR128:$src2, imm:$src3)>, + Requires<[HasSSE41]>; //===----------------------------------------------------------------------===// // SSE4.1 - Round Instructions //===----------------------------------------------------------------------===// -multiclass sse41_fp_unop_rm opcps, bits<8> opcpd, - string OpcodeStr, - Intrinsic V4F32Int, - Intrinsic V2F64Int> { +multiclass sse41_fp_unop_rm opcps, bits<8> opcpd, string OpcodeStr, + X86MemOperand x86memop, RegisterClass RC, + PatFrag mem_frag32, PatFrag mem_frag64, + Intrinsic V4F32Int, Intrinsic V2F64Int> { // Intrinsic operation, reg. // Vector intrinsic operation, reg def PSr_Int : SS4AIi8, + [(set RC:$dst, (V4F32Int RC:$src1, imm:$src2))]>, OpSize; // Vector intrinsic operation, mem def PSm_Int : Ii8, + [(set RC:$dst, + (V4F32Int (mem_frag32 addr:$src1),imm:$src2))]>, TA, OpSize, Requires<[HasSSE41]>; // Vector intrinsic operation, reg def PDr_Int : SS4AIi8, + [(set RC:$dst, (V2F64Int RC:$src1, imm:$src2))]>, OpSize; // Vector intrinsic operation, mem def PDm_Int : SS4AIi8, + [(set RC:$dst, + (V2F64Int (mem_frag64 addr:$src1),imm:$src2))]>, OpSize; } -multiclass sse41_fp_unop_rm_avx opcps, bits<8> opcpd, - string OpcodeStr> { +multiclass sse41_fp_unop_rm_avx_p opcps, bits<8> opcpd, + RegisterClass RC, X86MemOperand x86memop, string OpcodeStr> { // Intrinsic operation, reg. // Vector intrinsic operation, reg def PSr : SS4AIi8, OpSize; // Vector intrinsic operation, mem def PSm : Ii8, TA, OpSize, Requires<[HasSSE41]>; // Vector intrinsic operation, reg def PDr : SS4AIi8, OpSize; // Vector intrinsic operation, mem def PDm : SS4AIi8, OpSize; @@ -4261,8 +4622,8 @@ multiclass sse41_fp_binop_rm opcss, bits<8> opcsd, OpSize; } -multiclass sse41_fp_binop_rm_avx opcss, bits<8> opcsd, - string OpcodeStr> { +multiclass sse41_fp_binop_rm_avx_s opcss, bits<8> opcsd, + string OpcodeStr> { // Intrinsic operation, reg. def SSr : SS4AIi8 opcss, bits<8> opcsd, // FP round - roundss, roundps, roundsd, roundpd let isAsmParserOnly = 1, Predicates = [HasAVX] in { // Intrinsic form - defm VROUND : sse41_fp_unop_rm<0x08, 0x09, "vround", - int_x86_sse41_round_ps, int_x86_sse41_round_pd>, - VEX; + defm VROUND : sse41_fp_unop_rm<0x08, 0x09, "vround", f128mem, VR128, + memopv4f32, memopv2f64, + int_x86_sse41_round_ps, + int_x86_sse41_round_pd>, VEX; + defm VROUNDY : sse41_fp_unop_rm<0x08, 0x09, "vround", f256mem, VR256, + memopv8f32, memopv4f64, + int_x86_avx_round_ps_256, + int_x86_avx_round_pd_256>, VEX; defm VROUND : sse41_fp_binop_rm<0x0A, 0x0B, "vround", - int_x86_sse41_round_ss, int_x86_sse41_round_sd, - 0>, VEX_4V; + int_x86_sse41_round_ss, + int_x86_sse41_round_sd, 0>, VEX_4V; + // Instructions for the assembler - defm VROUND : sse41_fp_unop_rm_avx<0x08, 0x09, "vround">, VEX; - defm VROUND : sse41_fp_binop_rm_avx<0x0A, 0x0B, "vround">, VEX_4V; + defm VROUND : sse41_fp_unop_rm_avx_p<0x08, 0x09, VR128, f128mem, "vround">, + VEX; + defm VROUNDY : sse41_fp_unop_rm_avx_p<0x08, 0x09, VR256, f256mem, "vround">, + VEX; + defm VROUND : sse41_fp_binop_rm_avx_s<0x0A, 0x0B, "vround">, VEX_4V; } -defm ROUND : sse41_fp_unop_rm<0x08, 0x09, "round", +defm ROUND : sse41_fp_unop_rm<0x08, 0x09, "round", f128mem, VR128, + memopv4f32, memopv2f64, int_x86_sse41_round_ps, int_x86_sse41_round_pd>; let Constraints = "$src1 = $dst" in defm ROUND : sse41_fp_binop_rm<0x0A, 0x0B, "round", int_x86_sse41_round_ss, int_x86_sse41_round_sd>; //===----------------------------------------------------------------------===// +// SSE4.1 - Packed Bit Test +//===----------------------------------------------------------------------===// + +// ptest instruction we'll lower to this in X86ISelLowering primarily from +// the intel intrinsic that corresponds to this. +let Defs = [EFLAGS], isAsmParserOnly = 1, Predicates = [HasAVX] in { +def VPTESTrr : SS48I<0x17, MRMSrcReg, (outs), (ins VR128:$src1, VR128:$src2), + "vptest\t{$src2, $src1|$src1, $src2}", + [(set EFLAGS, (X86ptest VR128:$src1, (v4f32 VR128:$src2)))]>, + OpSize, VEX; +def VPTESTrm : SS48I<0x17, MRMSrcMem, (outs), (ins VR128:$src1, f128mem:$src2), + "vptest\t{$src2, $src1|$src1, $src2}", + [(set EFLAGS,(X86ptest VR128:$src1, (memopv4f32 addr:$src2)))]>, + OpSize, VEX; + +def VPTESTYrr : SS48I<0x17, MRMSrcReg, (outs), (ins VR256:$src1, VR256:$src2), + "vptest\t{$src2, $src1|$src1, $src2}", + [(set EFLAGS, (X86ptest VR256:$src1, (v4i64 VR256:$src2)))]>, + OpSize, VEX; +def VPTESTYrm : SS48I<0x17, MRMSrcMem, (outs), (ins VR256:$src1, i256mem:$src2), + "vptest\t{$src2, $src1|$src1, $src2}", + [(set EFLAGS,(X86ptest VR256:$src1, (memopv4i64 addr:$src2)))]>, + OpSize, VEX; +} + +let Defs = [EFLAGS] in { +def PTESTrr : SS48I<0x17, MRMSrcReg, (outs), (ins VR128:$src1, VR128:$src2), + "ptest \t{$src2, $src1|$src1, $src2}", + [(set EFLAGS, (X86ptest VR128:$src1, (v4f32 VR128:$src2)))]>, + OpSize; +def PTESTrm : SS48I<0x17, MRMSrcMem, (outs), (ins VR128:$src1, f128mem:$src2), + "ptest \t{$src2, $src1|$src1, $src2}", + [(set EFLAGS, (X86ptest VR128:$src1, (memopv4f32 addr:$src2)))]>, + OpSize; +} + +// The bit test instructions below are AVX only +multiclass avx_bittest opc, string OpcodeStr, RegisterClass RC, + X86MemOperand x86memop, PatFrag mem_frag, ValueType vt> { + def rr : SS48I, OpSize, VEX; + def rm : SS48I, + OpSize, VEX; +} + +let Defs = [EFLAGS], isAsmParserOnly = 1, Predicates = [HasAVX] in { +defm VTESTPS : avx_bittest<0x0E, "vtestps", VR128, f128mem, memopv4f32, v4f32>; +defm VTESTPSY : avx_bittest<0x0E, "vtestps", VR256, f256mem, memopv8f32, v8f32>; +defm VTESTPD : avx_bittest<0x0F, "vtestpd", VR128, f128mem, memopv2f64, v2f64>; +defm VTESTPDY : avx_bittest<0x0F, "vtestpd", VR256, f256mem, memopv4f64, v4f64>; +} + +//===----------------------------------------------------------------------===// // SSE4.1 - Misc Instructions //===----------------------------------------------------------------------===// @@ -4431,79 +4858,104 @@ let Constraints = "$src1 = $dst" in /// SS41I_binop_rmi_int - SSE 4.1 binary operator with 8-bit immediate multiclass SS41I_binop_rmi_int opc, string OpcodeStr, - Intrinsic IntId128, bit Is2Addr = 1> { + Intrinsic IntId, RegisterClass RC, PatFrag memop_frag, + X86MemOperand x86memop, bit Is2Addr = 1> { let isCommutable = 1 in - def rri : SS4AIi8, + [(set RC:$dst, (IntId RC:$src1, RC:$src2, imm:$src3))]>, OpSize; - def rmi : SS4AIi8, + [(set RC:$dst, + (IntId RC:$src1, + (bitconvert (memop_frag addr:$src2)), imm:$src3))]>, OpSize; } let isAsmParserOnly = 1, Predicates = [HasAVX] in { let isCommutable = 0 in { defm VBLENDPS : SS41I_binop_rmi_int<0x0C, "vblendps", int_x86_sse41_blendps, - 0>, VEX_4V; + VR128, memopv16i8, i128mem, 0>, VEX_4V; defm VBLENDPD : SS41I_binop_rmi_int<0x0D, "vblendpd", int_x86_sse41_blendpd, - 0>, VEX_4V; + VR128, memopv16i8, i128mem, 0>, VEX_4V; + defm VBLENDPSY : SS41I_binop_rmi_int<0x0C, "vblendps", + int_x86_avx_blend_ps_256, VR256, memopv32i8, i256mem, 0>, VEX_4V; + defm VBLENDPDY : SS41I_binop_rmi_int<0x0D, "vblendpd", + int_x86_avx_blend_pd_256, VR256, memopv32i8, i256mem, 0>, VEX_4V; defm VPBLENDW : SS41I_binop_rmi_int<0x0E, "vpblendw", int_x86_sse41_pblendw, - 0>, VEX_4V; + VR128, memopv16i8, i128mem, 0>, VEX_4V; defm VMPSADBW : SS41I_binop_rmi_int<0x42, "vmpsadbw", int_x86_sse41_mpsadbw, - 0>, VEX_4V; + VR128, memopv16i8, i128mem, 0>, VEX_4V; } defm VDPPS : SS41I_binop_rmi_int<0x40, "vdpps", int_x86_sse41_dpps, - 0>, VEX_4V; + VR128, memopv16i8, i128mem, 0>, VEX_4V; defm VDPPD : SS41I_binop_rmi_int<0x41, "vdppd", int_x86_sse41_dppd, - 0>, VEX_4V; + VR128, memopv16i8, i128mem, 0>, VEX_4V; + defm VDPPSY : SS41I_binop_rmi_int<0x40, "vdpps", int_x86_avx_dp_ps_256, + VR256, memopv32i8, i256mem, 0>, VEX_4V; } let Constraints = "$src1 = $dst" in { let isCommutable = 0 in { - defm BLENDPS : SS41I_binop_rmi_int<0x0C, "blendps", int_x86_sse41_blendps>; - defm BLENDPD : SS41I_binop_rmi_int<0x0D, "blendpd", int_x86_sse41_blendpd>; - defm PBLENDW : SS41I_binop_rmi_int<0x0E, "pblendw", int_x86_sse41_pblendw>; - defm MPSADBW : SS41I_binop_rmi_int<0x42, "mpsadbw", int_x86_sse41_mpsadbw>; + defm BLENDPS : SS41I_binop_rmi_int<0x0C, "blendps", int_x86_sse41_blendps, + VR128, memopv16i8, i128mem>; + defm BLENDPD : SS41I_binop_rmi_int<0x0D, "blendpd", int_x86_sse41_blendpd, + VR128, memopv16i8, i128mem>; + defm PBLENDW : SS41I_binop_rmi_int<0x0E, "pblendw", int_x86_sse41_pblendw, + VR128, memopv16i8, i128mem>; + defm MPSADBW : SS41I_binop_rmi_int<0x42, "mpsadbw", int_x86_sse41_mpsadbw, + VR128, memopv16i8, i128mem>; } - defm DPPS : SS41I_binop_rmi_int<0x40, "dpps", int_x86_sse41_dpps>; - defm DPPD : SS41I_binop_rmi_int<0x41, "dppd", int_x86_sse41_dppd>; + defm DPPS : SS41I_binop_rmi_int<0x40, "dpps", int_x86_sse41_dpps, + VR128, memopv16i8, i128mem>; + defm DPPD : SS41I_binop_rmi_int<0x41, "dppd", int_x86_sse41_dppd, + VR128, memopv16i8, i128mem>; } /// SS41I_quaternary_int_avx - AVX SSE 4.1 with 4 operators let isAsmParserOnly = 1, Predicates = [HasAVX] in { - multiclass SS41I_quaternary_int_avx opc, string OpcodeStr> { - def rr : I, OpSize, TA, VEX_4V, VEX_I8IMM; - - def rm : I, OpSize, TA, VEX_4V, VEX_I8IMM; - } -} - -defm VBLENDVPD : SS41I_quaternary_int_avx<0x4B, "vblendvpd">; -defm VBLENDVPS : SS41I_quaternary_int_avx<0x4A, "vblendvps">; -defm VPBLENDVB : SS41I_quaternary_int_avx<0x4C, "vpblendvb">; +multiclass SS41I_quaternary_int_avx opc, string OpcodeStr, + RegisterClass RC, X86MemOperand x86memop, + PatFrag mem_frag, Intrinsic IntId> { + def rr : I, OpSize, TA, VEX_4V, VEX_I8IMM; + + def rm : I, OpSize, TA, VEX_4V, VEX_I8IMM; +} +} + +defm VBLENDVPD : SS41I_quaternary_int_avx<0x4B, "vblendvpd", VR128, i128mem, + memopv16i8, int_x86_sse41_blendvpd>; +defm VBLENDVPS : SS41I_quaternary_int_avx<0x4A, "vblendvps", VR128, i128mem, + memopv16i8, int_x86_sse41_blendvps>; +defm VPBLENDVB : SS41I_quaternary_int_avx<0x4C, "vpblendvb", VR128, i128mem, + memopv16i8, int_x86_sse41_pblendvb>; +defm VBLENDVPDY : SS41I_quaternary_int_avx<0x4B, "vblendvpd", VR256, i256mem, + memopv32i8, int_x86_avx_blendv_pd_256>; +defm VBLENDVPSY : SS41I_quaternary_int_avx<0x4A, "vblendvps", VR256, i256mem, + memopv32i8, int_x86_avx_blendv_ps_256>; /// SS41I_ternary_int - SSE 4.1 ternary operator let Uses = [XMM0], Constraints = "$src1 = $dst" in { @@ -4529,30 +4981,6 @@ defm BLENDVPD : SS41I_ternary_int<0x15, "blendvpd", int_x86_sse41_blendvpd>; defm BLENDVPS : SS41I_ternary_int<0x14, "blendvps", int_x86_sse41_blendvps>; defm PBLENDVB : SS41I_ternary_int<0x10, "pblendvb", int_x86_sse41_pblendvb>; -// ptest instruction we'll lower to this in X86ISelLowering primarily from -// the intel intrinsic that corresponds to this. -let Defs = [EFLAGS], isAsmParserOnly = 1, Predicates = [HasAVX] in { -def VPTESTrr : SS48I<0x17, MRMSrcReg, (outs), (ins VR128:$src1, VR128:$src2), - "vptest\t{$src2, $src1|$src1, $src2}", - [(set EFLAGS, (X86ptest VR128:$src1, VR128:$src2))]>, - OpSize, VEX; -def VPTESTrm : SS48I<0x17, MRMSrcMem, (outs), (ins VR128:$src1, i128mem:$src2), - "vptest\t{$src2, $src1|$src1, $src2}", - [(set EFLAGS, (X86ptest VR128:$src1, (load addr:$src2)))]>, - OpSize, VEX; -} - -let Defs = [EFLAGS] in { -def PTESTrr : SS48I<0x17, MRMSrcReg, (outs), (ins VR128:$src1, VR128:$src2), - "ptest \t{$src2, $src1|$src1, $src2}", - [(set EFLAGS, (X86ptest VR128:$src1, VR128:$src2))]>, - OpSize; -def PTESTrm : SS48I<0x17, MRMSrcMem, (outs), (ins VR128:$src1, i128mem:$src2), - "ptest \t{$src2, $src1|$src1, $src2}", - [(set EFLAGS, (X86ptest VR128:$src1, (load addr:$src2)))]>, - OpSize; -} - let isAsmParserOnly = 1, Predicates = [HasAVX] in def VMOVNTDQArm : SS48I<0x2A, MRMSrcMem, (outs VR128:$dst), (ins i128mem:$src), "vmovntdqa\t{$src, $dst|$dst, $src}", @@ -4603,17 +5031,20 @@ def : Pat<(v2i64 (X86pcmpgtq VR128:$src1, (memop addr:$src2))), //===----------------------------------------------------------------------===// // Packed Compare Implicit Length Strings, Return Mask -let Defs = [EFLAGS], usesCustomInserter = 1 in { - def PCMPISTRM128REG : SS42AI<0, Pseudo, (outs VR128:$dst), - (ins VR128:$src1, VR128:$src2, i8imm:$src3), - "#PCMPISTRM128rr PSEUDO!", +multiclass pseudo_pcmpistrm { + def REG : Ii8<0, Pseudo, (outs VR128:$dst), + (ins VR128:$src1, VR128:$src2, i8imm:$src3), !strconcat(asm, "rr PSEUDO"), [(set VR128:$dst, (int_x86_sse42_pcmpistrm128 VR128:$src1, VR128:$src2, - imm:$src3))]>, OpSize; - def PCMPISTRM128MEM : SS42AI<0, Pseudo, (outs VR128:$dst), - (ins VR128:$src1, i128mem:$src2, i8imm:$src3), - "#PCMPISTRM128rm PSEUDO!", + imm:$src3))]>; + def MEM : Ii8<0, Pseudo, (outs VR128:$dst), + (ins VR128:$src1, i128mem:$src2, i8imm:$src3), !strconcat(asm, "rm PSEUDO"), [(set VR128:$dst, (int_x86_sse42_pcmpistrm128 - VR128:$src1, (load addr:$src2), imm:$src3))]>, OpSize; + VR128:$src1, (load addr:$src2), imm:$src3))]>; +} + +let Defs = [EFLAGS], usesCustomInserter = 1 in { + defm PCMPISTRM128 : pseudo_pcmpistrm<"#PCMPISTRM128">, Requires<[HasSSE42]>; + defm VPCMPISTRM128 : pseudo_pcmpistrm<"#VPCMPISTRM128">, Requires<[HasAVX]>; } let Defs = [XMM0, EFLAGS], isAsmParserOnly = 1, @@ -4636,20 +5067,20 @@ let Defs = [XMM0, EFLAGS] in { } // Packed Compare Explicit Length Strings, Return Mask -let Defs = [EFLAGS], Uses = [EAX, EDX], usesCustomInserter = 1 in { - def PCMPESTRM128REG : SS42AI<0, Pseudo, (outs VR128:$dst), - (ins VR128:$src1, VR128:$src3, i8imm:$src5), - "#PCMPESTRM128rr PSEUDO!", - [(set VR128:$dst, - (int_x86_sse42_pcmpestrm128 - VR128:$src1, EAX, VR128:$src3, EDX, imm:$src5))]>, OpSize; - - def PCMPESTRM128MEM : SS42AI<0, Pseudo, (outs VR128:$dst), - (ins VR128:$src1, i128mem:$src3, i8imm:$src5), - "#PCMPESTRM128rm PSEUDO!", +multiclass pseudo_pcmpestrm { + def REG : Ii8<0, Pseudo, (outs VR128:$dst), + (ins VR128:$src1, VR128:$src3, i8imm:$src5), !strconcat(asm, "rr PSEUDO"), + [(set VR128:$dst, (int_x86_sse42_pcmpestrm128 + VR128:$src1, EAX, VR128:$src3, EDX, imm:$src5))]>; + def MEM : Ii8<0, Pseudo, (outs VR128:$dst), + (ins VR128:$src1, i128mem:$src3, i8imm:$src5), !strconcat(asm, "rm PSEUDO"), [(set VR128:$dst, (int_x86_sse42_pcmpestrm128 - VR128:$src1, EAX, (load addr:$src3), EDX, imm:$src5))]>, - OpSize; + VR128:$src1, EAX, (load addr:$src3), EDX, imm:$src5))]>; +} + +let Defs = [EFLAGS], Uses = [EAX, EDX], usesCustomInserter = 1 in { + defm PCMPESTRM128 : pseudo_pcmpestrm<"#PCMPESTRM128">, Requires<[HasSSE42]>; + defm VPCMPESTRM128 : pseudo_pcmpestrm<"#VPCMPESTRM128">, Requires<[HasAVX]>; } let isAsmParserOnly = 1, Predicates = [HasAVX], @@ -4941,3 +5372,579 @@ def AESKEYGENASSIST128rm : AESAI<0xDF, MRMSrcMem, (outs VR128:$dst), (int_x86_aesni_aeskeygenassist (bitconvert (memopv2i64 addr:$src1)), imm:$src2))]>, OpSize; + +//===----------------------------------------------------------------------===// +// CLMUL Instructions +//===----------------------------------------------------------------------===// + +// Only the AVX version of CLMUL instructions are described here. + +// Carry-less Multiplication instructions +let isAsmParserOnly = 1 in { +def VPCLMULQDQrr : CLMULIi8<0x44, MRMSrcReg, (outs VR128:$dst), + (ins VR128:$src1, VR128:$src2, i8imm:$src3), + "vpclmulqdq\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}", + []>; + +def VPCLMULQDQrm : CLMULIi8<0x44, MRMSrcMem, (outs VR128:$dst), + (ins VR128:$src1, i128mem:$src2, i8imm:$src3), + "vpclmulqdq\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}", + []>; + +// Assembler Only +multiclass avx_vpclmul { + def rr : I<0, Pseudo, (outs VR128:$dst), (ins VR128:$src1, VR128:$src2), + !strconcat(asm, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"), + []>; + + def rm : I<0, Pseudo, (outs VR128:$dst), (ins VR128:$src1, i128mem:$src2), + !strconcat(asm, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"), + []>; +} +defm VPCLMULHQHQDQ : avx_vpclmul<"vpclmulhqhqdq">; +defm VPCLMULHQLQDQ : avx_vpclmul<"vpclmulhqlqdq">; +defm VPCLMULLQHQDQ : avx_vpclmul<"vpclmullqhqdq">; +defm VPCLMULLQLQDQ : avx_vpclmul<"vpclmullqlqdq">; + +} // isAsmParserOnly + +//===----------------------------------------------------------------------===// +// AVX Instructions +//===----------------------------------------------------------------------===// + +let isAsmParserOnly = 1 in { + +// Load from memory and broadcast to all elements of the destination operand +class avx_broadcast opc, string OpcodeStr, RegisterClass RC, + X86MemOperand x86memop, Intrinsic Int> : + AVX8I, VEX; + +def VBROADCASTSS : avx_broadcast<0x18, "vbroadcastss", VR128, f32mem, + int_x86_avx_vbroadcastss>; +def VBROADCASTSSY : avx_broadcast<0x18, "vbroadcastss", VR256, f32mem, + int_x86_avx_vbroadcastss_256>; +def VBROADCASTSD : avx_broadcast<0x19, "vbroadcastsd", VR256, f64mem, + int_x86_avx_vbroadcast_sd_256>; +def VBROADCASTF128 : avx_broadcast<0x1A, "vbroadcastf128", VR256, f128mem, + int_x86_avx_vbroadcastf128_pd_256>; + +// Insert packed floating-point values +def VINSERTF128rr : AVXAIi8<0x18, MRMSrcReg, (outs VR256:$dst), + (ins VR256:$src1, VR128:$src2, i8imm:$src3), + "vinsertf128\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}", + []>, VEX_4V; +def VINSERTF128rm : AVXAIi8<0x18, MRMSrcMem, (outs VR256:$dst), + (ins VR256:$src1, f128mem:$src2, i8imm:$src3), + "vinsertf128\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}", + []>, VEX_4V; + +// Extract packed floating-point values +def VEXTRACTF128rr : AVXAIi8<0x19, MRMDestReg, (outs VR128:$dst), + (ins VR256:$src1, i8imm:$src2), + "vextractf128\t{$src2, $src1, $dst|$dst, $src1, $src2}", + []>, VEX; +def VEXTRACTF128mr : AVXAIi8<0x19, MRMDestMem, (outs), + (ins f128mem:$dst, VR256:$src1, i8imm:$src2), + "vextractf128\t{$src2, $src1, $dst|$dst, $src1, $src2}", + []>, VEX; + +// Conditional SIMD Packed Loads and Stores +multiclass avx_movmask_rm opc_rm, bits<8> opc_mr, string OpcodeStr, + Intrinsic IntLd, Intrinsic IntLd256, + Intrinsic IntSt, Intrinsic IntSt256, + PatFrag pf128, PatFrag pf256> { + def rm : AVX8I, + VEX_4V; + def Yrm : AVX8I, + VEX_4V; + def mr : AVX8I, VEX_4V; + def Ymr : AVX8I, VEX_4V; +} + +defm VMASKMOVPS : avx_movmask_rm<0x2C, 0x2E, "vmaskmovps", + int_x86_avx_maskload_ps, + int_x86_avx_maskload_ps_256, + int_x86_avx_maskstore_ps, + int_x86_avx_maskstore_ps_256, + memopv4f32, memopv8f32>; +defm VMASKMOVPD : avx_movmask_rm<0x2D, 0x2F, "vmaskmovpd", + int_x86_avx_maskload_pd, + int_x86_avx_maskload_pd_256, + int_x86_avx_maskstore_pd, + int_x86_avx_maskstore_pd_256, + memopv2f64, memopv4f64>; + +// Permute Floating-Point Values +multiclass avx_permil opc_rm, bits<8> opc_rmi, string OpcodeStr, + RegisterClass RC, X86MemOperand x86memop_f, + X86MemOperand x86memop_i, PatFrag f_frag, PatFrag i_frag, + Intrinsic IntVar, Intrinsic IntImm> { + def rr : AVX8I, VEX_4V; + def rm : AVX8I, VEX_4V; + + def ri : AVXAIi8, VEX; + def mi : AVXAIi8, VEX; +} + +defm VPERMILPS : avx_permil<0x0C, 0x04, "vpermilps", VR128, f128mem, i128mem, + memopv4f32, memopv4i32, + int_x86_avx_vpermilvar_ps, + int_x86_avx_vpermil_ps>; +defm VPERMILPSY : avx_permil<0x0C, 0x04, "vpermilps", VR256, f256mem, i256mem, + memopv8f32, memopv8i32, + int_x86_avx_vpermilvar_ps_256, + int_x86_avx_vpermil_ps_256>; +defm VPERMILPD : avx_permil<0x0D, 0x05, "vpermilpd", VR128, f128mem, i128mem, + memopv2f64, memopv2i64, + int_x86_avx_vpermilvar_pd, + int_x86_avx_vpermil_pd>; +defm VPERMILPDY : avx_permil<0x0D, 0x05, "vpermilpd", VR256, f256mem, i256mem, + memopv4f64, memopv4i64, + int_x86_avx_vpermilvar_pd_256, + int_x86_avx_vpermil_pd_256>; + +def VPERM2F128rr : AVXAIi8<0x06, MRMSrcReg, (outs VR256:$dst), + (ins VR256:$src1, VR256:$src2, i8imm:$src3), + "vperm2f128\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}", + []>, VEX_4V; +def VPERM2F128rm : AVXAIi8<0x06, MRMSrcMem, (outs VR256:$dst), + (ins VR256:$src1, f256mem:$src2, i8imm:$src3), + "vperm2f128\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}", + []>, VEX_4V; + +// Zero All YMM registers +def VZEROALL : I<0x77, RawFrm, (outs), (ins), "vzeroall", + [(int_x86_avx_vzeroall)]>, VEX, VEX_L, Requires<[HasAVX]>; + +// Zero Upper bits of YMM registers +def VZEROUPPER : I<0x77, RawFrm, (outs), (ins), "vzeroupper", + [(int_x86_avx_vzeroupper)]>, VEX, Requires<[HasAVX]>; + +} // isAsmParserOnly + +def : Pat<(int_x86_avx_vinsertf128_pd_256 VR256:$src1, VR128:$src2, imm:$src3), + (VINSERTF128rr VR256:$src1, VR128:$src2, imm:$src3)>; +def : Pat<(int_x86_avx_vinsertf128_ps_256 VR256:$src1, VR128:$src2, imm:$src3), + (VINSERTF128rr VR256:$src1, VR128:$src2, imm:$src3)>; +def : Pat<(int_x86_avx_vinsertf128_si_256 VR256:$src1, VR128:$src2, imm:$src3), + (VINSERTF128rr VR256:$src1, VR128:$src2, imm:$src3)>; + +def : Pat<(int_x86_avx_vextractf128_pd_256 VR256:$src1, imm:$src2), + (VEXTRACTF128rr VR256:$src1, imm:$src2)>; +def : Pat<(int_x86_avx_vextractf128_ps_256 VR256:$src1, imm:$src2), + (VEXTRACTF128rr VR256:$src1, imm:$src2)>; +def : Pat<(int_x86_avx_vextractf128_si_256 VR256:$src1, imm:$src2), + (VEXTRACTF128rr VR256:$src1, imm:$src2)>; + +def : Pat<(int_x86_avx_vbroadcastf128_ps_256 addr:$src), + (VBROADCASTF128 addr:$src)>; + +def : Pat<(int_x86_avx_vperm2f128_ps_256 VR256:$src1, VR256:$src2, imm:$src3), + (VPERM2F128rr VR256:$src1, VR256:$src2, imm:$src3)>; +def : Pat<(int_x86_avx_vperm2f128_pd_256 VR256:$src1, VR256:$src2, imm:$src3), + (VPERM2F128rr VR256:$src1, VR256:$src2, imm:$src3)>; +def : Pat<(int_x86_avx_vperm2f128_si_256 VR256:$src1, VR256:$src2, imm:$src3), + (VPERM2F128rr VR256:$src1, VR256:$src2, imm:$src3)>; + +def : Pat<(int_x86_avx_vperm2f128_ps_256 + VR256:$src1, (memopv8f32 addr:$src2), imm:$src3), + (VPERM2F128rm VR256:$src1, addr:$src2, imm:$src3)>; +def : Pat<(int_x86_avx_vperm2f128_pd_256 + VR256:$src1, (memopv4f64 addr:$src2), imm:$src3), + (VPERM2F128rm VR256:$src1, addr:$src2, imm:$src3)>; +def : Pat<(int_x86_avx_vperm2f128_si_256 + VR256:$src1, (memopv8i32 addr:$src2), imm:$src3), + (VPERM2F128rm VR256:$src1, addr:$src2, imm:$src3)>; + +//===----------------------------------------------------------------------===// +// SSE Shuffle pattern fragments +//===----------------------------------------------------------------------===// + +// This is part of a "work in progress" refactoring. The idea is that all +// vector shuffles are going to be translated into target specific nodes and +// directly matched by the patterns below (which can be changed along the way) +// The AVX version of some but not all of them are described here, and more +// should come in a near future. + +// Shuffle with PSHUFD instruction folding loads. The first two patterns match +// SSE2 loads, which are always promoted to v2i64. The last one should match +// the SSE1 case, where the only legal load is v4f32, but there is no PSHUFD +// in SSE2, how does it ever worked? Anyway, the pattern will remain here until +// we investigate further. +def : Pat<(v4i32 (X86PShufd (bc_v4i32 (memopv2i64 addr:$src1)), + (i8 imm:$imm))), + (VPSHUFDmi addr:$src1, imm:$imm)>, Requires<[HasAVX]>; +def : Pat<(v4i32 (X86PShufd (bc_v4i32 (memopv2i64 addr:$src1)), + (i8 imm:$imm))), + (PSHUFDmi addr:$src1, imm:$imm)>; +def : Pat<(v4i32 (X86PShufd (bc_v4i32 (memopv4f32 addr:$src1)), + (i8 imm:$imm))), + (PSHUFDmi addr:$src1, imm:$imm)>; // FIXME: has this ever worked? + +// Shuffle with PSHUFD instruction. +def : Pat<(v4f32 (X86PShufd VR128:$src1, (i8 imm:$imm))), + (VPSHUFDri VR128:$src1, imm:$imm)>, Requires<[HasAVX]>; +def : Pat<(v4f32 (X86PShufd VR128:$src1, (i8 imm:$imm))), + (PSHUFDri VR128:$src1, imm:$imm)>; + +def : Pat<(v4i32 (X86PShufd VR128:$src1, (i8 imm:$imm))), + (VPSHUFDri VR128:$src1, imm:$imm)>, Requires<[HasAVX]>; +def : Pat<(v4i32 (X86PShufd VR128:$src1, (i8 imm:$imm))), + (PSHUFDri VR128:$src1, imm:$imm)>; + +// Shuffle with SHUFPD instruction. +def : Pat<(v2f64 (X86Shufps VR128:$src1, + (memopv2f64 addr:$src2), (i8 imm:$imm))), + (VSHUFPDrmi VR128:$src1, addr:$src2, imm:$imm)>, Requires<[HasAVX]>; +def : Pat<(v2f64 (X86Shufps VR128:$src1, + (memopv2f64 addr:$src2), (i8 imm:$imm))), + (SHUFPDrmi VR128:$src1, addr:$src2, imm:$imm)>; + +def : Pat<(v2i64 (X86Shufpd VR128:$src1, VR128:$src2, (i8 imm:$imm))), + (VSHUFPDrri VR128:$src1, VR128:$src2, imm:$imm)>, Requires<[HasAVX]>; +def : Pat<(v2i64 (X86Shufpd VR128:$src1, VR128:$src2, (i8 imm:$imm))), + (SHUFPDrri VR128:$src1, VR128:$src2, imm:$imm)>; + +def : Pat<(v2f64 (X86Shufpd VR128:$src1, VR128:$src2, (i8 imm:$imm))), + (VSHUFPDrri VR128:$src1, VR128:$src2, imm:$imm)>, Requires<[HasAVX]>; +def : Pat<(v2f64 (X86Shufpd VR128:$src1, VR128:$src2, (i8 imm:$imm))), + (SHUFPDrri VR128:$src1, VR128:$src2, imm:$imm)>; + +// Shuffle with SHUFPS instruction. +def : Pat<(v4f32 (X86Shufps VR128:$src1, + (memopv4f32 addr:$src2), (i8 imm:$imm))), + (VSHUFPSrmi VR128:$src1, addr:$src2, imm:$imm)>, Requires<[HasAVX]>; +def : Pat<(v4f32 (X86Shufps VR128:$src1, + (memopv4f32 addr:$src2), (i8 imm:$imm))), + (SHUFPSrmi VR128:$src1, addr:$src2, imm:$imm)>; + +def : Pat<(v4f32 (X86Shufps VR128:$src1, VR128:$src2, (i8 imm:$imm))), + (VSHUFPSrri VR128:$src1, VR128:$src2, imm:$imm)>, Requires<[HasAVX]>; +def : Pat<(v4f32 (X86Shufps VR128:$src1, VR128:$src2, (i8 imm:$imm))), + (SHUFPSrri VR128:$src1, VR128:$src2, imm:$imm)>; + +def : Pat<(v4i32 (X86Shufps VR128:$src1, + (bc_v4i32 (memopv2i64 addr:$src2)), (i8 imm:$imm))), + (VSHUFPSrmi VR128:$src1, addr:$src2, imm:$imm)>, Requires<[HasAVX]>; +def : Pat<(v4i32 (X86Shufps VR128:$src1, + (bc_v4i32 (memopv2i64 addr:$src2)), (i8 imm:$imm))), + (SHUFPSrmi VR128:$src1, addr:$src2, imm:$imm)>; + +def : Pat<(v4i32 (X86Shufps VR128:$src1, VR128:$src2, (i8 imm:$imm))), + (VSHUFPSrri VR128:$src1, VR128:$src2, imm:$imm)>, Requires<[HasAVX]>; +def : Pat<(v4i32 (X86Shufps VR128:$src1, VR128:$src2, (i8 imm:$imm))), + (SHUFPSrri VR128:$src1, VR128:$src2, imm:$imm)>; + +// Shuffle with MOVHLPS instruction +def : Pat<(v4f32 (X86Movhlps VR128:$src1, VR128:$src2)), + (MOVHLPSrr VR128:$src1, VR128:$src2)>; +def : Pat<(v4i32 (X86Movhlps VR128:$src1, VR128:$src2)), + (MOVHLPSrr VR128:$src1, VR128:$src2)>; + +// Shuffle with MOVDDUP instruction +def : Pat<(X86Movddup (memopv2f64 addr:$src)), + (VMOVDDUPrm addr:$src)>, Requires<[HasAVX]>; +def : Pat<(X86Movddup (memopv2f64 addr:$src)), + (MOVDDUPrm addr:$src)>; + +def : Pat<(X86Movddup (bc_v4f32 (memopv2f64 addr:$src))), + (VMOVDDUPrm addr:$src)>, Requires<[HasAVX]>; +def : Pat<(X86Movddup (bc_v4f32 (memopv2f64 addr:$src))), + (MOVDDUPrm addr:$src)>; + +def : Pat<(X86Movddup (memopv2i64 addr:$src)), + (VMOVDDUPrm addr:$src)>, Requires<[HasAVX]>; +def : Pat<(X86Movddup (memopv2i64 addr:$src)), + (MOVDDUPrm addr:$src)>; + +def : Pat<(X86Movddup (bc_v4i32 (memopv2i64 addr:$src))), + (VMOVDDUPrm addr:$src)>, Requires<[HasAVX]>; +def : Pat<(X86Movddup (bc_v4i32 (memopv2i64 addr:$src))), + (MOVDDUPrm addr:$src)>; + +def : Pat<(X86Movddup (v2f64 (scalar_to_vector (loadf64 addr:$src)))), + (VMOVDDUPrm addr:$src)>, Requires<[HasAVX]>; +def : Pat<(X86Movddup (v2f64 (scalar_to_vector (loadf64 addr:$src)))), + (MOVDDUPrm addr:$src)>; + +def : Pat<(X86Movddup (bc_v2f64 + (v2i64 (scalar_to_vector (loadi64 addr:$src))))), + (VMOVDDUPrm addr:$src)>, Requires<[HasAVX]>; +def : Pat<(X86Movddup (bc_v2f64 + (v2i64 (scalar_to_vector (loadi64 addr:$src))))), + (MOVDDUPrm addr:$src)>; + +// Shuffle with UNPCKLPS +def : Pat<(v4f32 (X86Unpcklps VR128:$src1, (memopv4f32 addr:$src2))), + (VUNPCKLPSrm VR128:$src1, addr:$src2)>, Requires<[HasAVX]>; +def : Pat<(v4f32 (X86Unpcklps VR128:$src1, (memopv4f32 addr:$src2))), + (UNPCKLPSrm VR128:$src1, addr:$src2)>; + +def : Pat<(v4f32 (X86Unpcklps VR128:$src1, VR128:$src2)), + (VUNPCKLPSrr VR128:$src1, VR128:$src2)>, Requires<[HasAVX]>; +def : Pat<(v4f32 (X86Unpcklps VR128:$src1, VR128:$src2)), + (UNPCKLPSrr VR128:$src1, VR128:$src2)>; + +// Shuffle with UNPCKHPS +def : Pat<(v4f32 (X86Unpckhps VR128:$src1, (memopv4f32 addr:$src2))), + (VUNPCKHPSrm VR128:$src1, addr:$src2)>, Requires<[HasAVX]>; +def : Pat<(v4f32 (X86Unpckhps VR128:$src1, (memopv4f32 addr:$src2))), + (UNPCKHPSrm VR128:$src1, addr:$src2)>; + +def : Pat<(v4f32 (X86Unpckhps VR128:$src1, VR128:$src2)), + (VUNPCKHPSrr VR128:$src1, VR128:$src2)>, Requires<[HasAVX]>; +def : Pat<(v4f32 (X86Unpckhps VR128:$src1, VR128:$src2)), + (UNPCKHPSrr VR128:$src1, VR128:$src2)>; + +// Shuffle with UNPCKLPD +def : Pat<(v2f64 (X86Unpcklpd VR128:$src1, (memopv2f64 addr:$src2))), + (VUNPCKLPSrm VR128:$src1, addr:$src2)>, Requires<[HasAVX]>; +def : Pat<(v2f64 (X86Unpcklpd VR128:$src1, (memopv2f64 addr:$src2))), + (UNPCKLPSrm VR128:$src1, addr:$src2)>; + +def : Pat<(v2f64 (X86Unpcklpd VR128:$src1, VR128:$src2)), + (VUNPCKLPDrr VR128:$src1, VR128:$src2)>, Requires<[HasAVX]>; +def : Pat<(v2f64 (X86Unpcklpd VR128:$src1, VR128:$src2)), + (UNPCKLPDrr VR128:$src1, VR128:$src2)>; + +// Shuffle with UNPCKHPD +def : Pat<(v2f64 (X86Unpckhpd VR128:$src1, (memopv2f64 addr:$src2))), + (VUNPCKLPSrm VR128:$src1, addr:$src2)>, Requires<[HasAVX]>; +def : Pat<(v2f64 (X86Unpckhpd VR128:$src1, (memopv2f64 addr:$src2))), + (UNPCKLPSrm VR128:$src1, addr:$src2)>; + +def : Pat<(v2f64 (X86Unpckhpd VR128:$src1, VR128:$src2)), + (VUNPCKHPDrr VR128:$src1, VR128:$src2)>, Requires<[HasAVX]>; +def : Pat<(v2f64 (X86Unpckhpd VR128:$src1, VR128:$src2)), + (UNPCKHPDrr VR128:$src1, VR128:$src2)>; + +// Shuffle with PUNPCKLBW +def : Pat<(v16i8 (X86Punpcklbw VR128:$src1, + (bc_v16i8 (memopv2i64 addr:$src2)))), + (PUNPCKLBWrm VR128:$src1, addr:$src2)>; +def : Pat<(v16i8 (X86Punpcklbw VR128:$src1, VR128:$src2)), + (PUNPCKLBWrr VR128:$src1, VR128:$src2)>; + +// Shuffle with PUNPCKLWD +def : Pat<(v8i16 (X86Punpcklwd VR128:$src1, + (bc_v8i16 (memopv2i64 addr:$src2)))), + (PUNPCKLWDrm VR128:$src1, addr:$src2)>; +def : Pat<(v8i16 (X86Punpcklwd VR128:$src1, VR128:$src2)), + (PUNPCKLWDrr VR128:$src1, VR128:$src2)>; + +// Shuffle with PUNPCKLDQ +def : Pat<(v4i32 (X86Punpckldq VR128:$src1, + (bc_v4i32 (memopv2i64 addr:$src2)))), + (PUNPCKLDQrm VR128:$src1, addr:$src2)>; +def : Pat<(v4i32 (X86Punpckldq VR128:$src1, VR128:$src2)), + (PUNPCKLDQrr VR128:$src1, VR128:$src2)>; + +// Shuffle with PUNPCKLQDQ +def : Pat<(v2i64 (X86Punpcklqdq VR128:$src1, (memopv2i64 addr:$src2))), + (PUNPCKLQDQrm VR128:$src1, addr:$src2)>; +def : Pat<(v2i64 (X86Punpcklqdq VR128:$src1, VR128:$src2)), + (PUNPCKLQDQrr VR128:$src1, VR128:$src2)>; + +// Shuffle with PUNPCKHBW +def : Pat<(v16i8 (X86Punpckhbw VR128:$src1, + (bc_v16i8 (memopv2i64 addr:$src2)))), + (PUNPCKHBWrm VR128:$src1, addr:$src2)>; +def : Pat<(v16i8 (X86Punpckhbw VR128:$src1, VR128:$src2)), + (PUNPCKHBWrr VR128:$src1, VR128:$src2)>; + +// Shuffle with PUNPCKHWD +def : Pat<(v8i16 (X86Punpckhwd VR128:$src1, + (bc_v8i16 (memopv2i64 addr:$src2)))), + (PUNPCKHWDrm VR128:$src1, addr:$src2)>; +def : Pat<(v8i16 (X86Punpckhwd VR128:$src1, VR128:$src2)), + (PUNPCKHWDrr VR128:$src1, VR128:$src2)>; + +// Shuffle with PUNPCKHDQ +def : Pat<(v4i32 (X86Punpckhdq VR128:$src1, + (bc_v4i32 (memopv2i64 addr:$src2)))), + (PUNPCKHDQrm VR128:$src1, addr:$src2)>; +def : Pat<(v4i32 (X86Punpckhdq VR128:$src1, VR128:$src2)), + (PUNPCKHDQrr VR128:$src1, VR128:$src2)>; + +// Shuffle with PUNPCKHQDQ +def : Pat<(v2i64 (X86Punpckhqdq VR128:$src1, (memopv2i64 addr:$src2))), + (PUNPCKHQDQrm VR128:$src1, addr:$src2)>; +def : Pat<(v2i64 (X86Punpckhqdq VR128:$src1, VR128:$src2)), + (PUNPCKHQDQrr VR128:$src1, VR128:$src2)>; + +// Shuffle with MOVLHPS +def : Pat<(X86Movlhps VR128:$src1, + (bc_v4f32 (v2f64 (scalar_to_vector (loadf64 addr:$src2))))), + (MOVHPSrm VR128:$src1, addr:$src2)>; +def : Pat<(X86Movlhps VR128:$src1, + (bc_v4i32 (v2i64 (X86vzload addr:$src2)))), + (MOVHPSrm VR128:$src1, addr:$src2)>; +def : Pat<(v4f32 (X86Movlhps VR128:$src1, VR128:$src2)), + (MOVLHPSrr VR128:$src1, VR128:$src2)>; +def : Pat<(v4i32 (X86Movlhps VR128:$src1, VR128:$src2)), + (MOVLHPSrr VR128:$src1, VR128:$src2)>; +def : Pat<(v2i64 (X86Movlhps VR128:$src1, VR128:$src2)), + (MOVLHPSrr (v2i64 VR128:$src1), VR128:$src2)>; + +// Shuffle with MOVLHPD +def : Pat<(v2f64 (X86Movlhpd VR128:$src1, + (scalar_to_vector (loadf64 addr:$src2)))), + (MOVHPDrm VR128:$src1, addr:$src2)>; +// FIXME: Instead of X86Unpcklpd, there should be a X86Movlhpd here, the problem +// is during lowering, where it's not possible to recognize the load fold cause +// it has two uses through a bitcast. One use disappears at isel time and the +// fold opportunity reappears. +def : Pat<(v2f64 (X86Unpcklpd VR128:$src1, + (scalar_to_vector (loadf64 addr:$src2)))), + (MOVHPDrm VR128:$src1, addr:$src2)>; + +// Shuffle with MOVSS +def : Pat<(v4f32 (X86Movss VR128:$src1, (scalar_to_vector FR32:$src2))), + (MOVSSrr VR128:$src1, FR32:$src2)>; +def : Pat<(v4i32 (X86Movss VR128:$src1, VR128:$src2)), + (MOVSSrr (v4i32 VR128:$src1), + (EXTRACT_SUBREG (v4i32 VR128:$src2), sub_ss))>; +def : Pat<(v4f32 (X86Movss VR128:$src1, VR128:$src2)), + (MOVSSrr (v4f32 VR128:$src1), + (EXTRACT_SUBREG (v4f32 VR128:$src2), sub_ss))>; +// FIXME: Instead of a X86Movss there should be a X86Movlps here, the problem +// is during lowering, where it's not possible to recognize the load fold cause +// it has two uses through a bitcast. One use disappears at isel time and the +// fold opportunity reappears. +def : Pat<(X86Movss VR128:$src1, + (bc_v4i32 (v2i64 (load addr:$src2)))), + (MOVLPSrm VR128:$src1, addr:$src2)>; + +// Shuffle with MOVSD +def : Pat<(v2f64 (X86Movsd VR128:$src1, (scalar_to_vector FR64:$src2))), + (MOVSDrr VR128:$src1, FR64:$src2)>; +def : Pat<(v2i64 (X86Movsd VR128:$src1, VR128:$src2)), + (MOVSDrr (v2i64 VR128:$src1), + (EXTRACT_SUBREG (v2i64 VR128:$src2), sub_sd))>; +def : Pat<(v2f64 (X86Movsd VR128:$src1, VR128:$src2)), + (MOVSDrr (v2f64 VR128:$src1), + (EXTRACT_SUBREG (v2f64 VR128:$src2), sub_sd))>; +def : Pat<(v4f32 (X86Movsd VR128:$src1, VR128:$src2)), + (MOVSDrr VR128:$src1, (EXTRACT_SUBREG (v4f32 VR128:$src2), sub_sd))>; +def : Pat<(v4i32 (X86Movsd VR128:$src1, VR128:$src2)), + (MOVSDrr VR128:$src1, (EXTRACT_SUBREG (v4i32 VR128:$src2), sub_sd))>; + +// Shuffle with MOVSHDUP +def : Pat<(v4i32 (X86Movshdup VR128:$src)), + (MOVSHDUPrr VR128:$src)>; +def : Pat<(X86Movshdup (bc_v4i32 (memopv2i64 addr:$src))), + (MOVSHDUPrm addr:$src)>; + +def : Pat<(v4f32 (X86Movshdup VR128:$src)), + (MOVSHDUPrr VR128:$src)>; +def : Pat<(X86Movshdup (memopv4f32 addr:$src)), + (MOVSHDUPrm addr:$src)>; + +// Shuffle with MOVSLDUP +def : Pat<(v4i32 (X86Movsldup VR128:$src)), + (MOVSLDUPrr VR128:$src)>; +def : Pat<(X86Movsldup (bc_v4i32 (memopv2i64 addr:$src))), + (MOVSLDUPrm addr:$src)>; + +def : Pat<(v4f32 (X86Movsldup VR128:$src)), + (MOVSLDUPrr VR128:$src)>; +def : Pat<(X86Movsldup (memopv4f32 addr:$src)), + (MOVSLDUPrm addr:$src)>; + +// Shuffle with PSHUFHW +def : Pat<(v8i16 (X86PShufhwLd addr:$src, (i8 imm:$imm))), + (PSHUFHWmi addr:$src, imm:$imm)>; +def : Pat<(v8i16 (X86PShufhw VR128:$src, (i8 imm:$imm))), + (PSHUFHWri VR128:$src, imm:$imm)>; +def : Pat<(v8i16 (X86PShufhw (bc_v8i16 (memopv2i64 addr:$src)), (i8 imm:$imm))), + (PSHUFHWmi addr:$src, imm:$imm)>; + +// Shuffle with PSHUFLW +def : Pat<(v8i16 (X86PShuflwLd addr:$src, (i8 imm:$imm))), + (PSHUFLWmi addr:$src, imm:$imm)>; +def : Pat<(v8i16 (X86PShuflw VR128:$src, (i8 imm:$imm))), + (PSHUFLWri VR128:$src, imm:$imm)>; +def : Pat<(v8i16 (X86PShuflw (bc_v8i16 (memopv2i64 addr:$src)), (i8 imm:$imm))), + (PSHUFLWmi addr:$src, imm:$imm)>; + +// Shuffle with PALIGN +def : Pat<(v1i64 (X86PAlign VR64:$src1, VR64:$src2, (i8 imm:$imm))), + (PALIGNR64rr VR64:$src2, VR64:$src1, imm:$imm)>; +def : Pat<(v2i32 (X86PAlign VR64:$src1, VR64:$src2, (i8 imm:$imm))), + (PALIGNR64rr VR64:$src2, VR64:$src1, imm:$imm)>; +def : Pat<(v4i16 (X86PAlign VR64:$src1, VR64:$src2, (i8 imm:$imm))), + (PALIGNR64rr VR64:$src2, VR64:$src1, imm:$imm)>; +def : Pat<(v8i8 (X86PAlign VR64:$src1, VR64:$src2, (i8 imm:$imm))), + (PALIGNR64rr VR64:$src2, VR64:$src1, imm:$imm)>; + +def : Pat<(v4i32 (X86PAlign VR128:$src1, VR128:$src2, (i8 imm:$imm))), + (PALIGNR128rr VR128:$src2, VR128:$src1, imm:$imm)>; +def : Pat<(v4f32 (X86PAlign VR128:$src1, VR128:$src2, (i8 imm:$imm))), + (PALIGNR128rr VR128:$src2, VR128:$src1, imm:$imm)>; +def : Pat<(v8i16 (X86PAlign VR128:$src1, VR128:$src2, (i8 imm:$imm))), + (PALIGNR128rr VR128:$src2, VR128:$src1, imm:$imm)>; +def : Pat<(v16i8 (X86PAlign VR128:$src1, VR128:$src2, (i8 imm:$imm))), + (PALIGNR128rr VR128:$src2, VR128:$src1, imm:$imm)>; + +// Shuffle with MOVLPS +def : Pat<(v4f32 (X86Movlps VR128:$src1, (load addr:$src2))), + (MOVLPSrm VR128:$src1, addr:$src2)>; +def : Pat<(v4i32 (X86Movlps VR128:$src1, (load addr:$src2))), + (MOVLPSrm VR128:$src1, addr:$src2)>; +def : Pat<(X86Movlps VR128:$src1, + (bc_v4f32 (v2f64 (scalar_to_vector (loadf64 addr:$src2))))), + (MOVLPSrm VR128:$src1, addr:$src2)>; + +// Shuffle with MOVLPD +def : Pat<(v2f64 (X86Movlpd VR128:$src1, (load addr:$src2))), + (MOVLPDrm VR128:$src1, addr:$src2)>; +def : Pat<(v2i64 (X86Movlpd VR128:$src1, (load addr:$src2))), + (MOVLPDrm VR128:$src1, addr:$src2)>; +def : Pat<(v2f64 (X86Movlpd VR128:$src1, + (scalar_to_vector (loadf64 addr:$src2)))), + (MOVLPDrm VR128:$src1, addr:$src2)>; + +// Extra patterns to match stores with MOVHPS/PD and MOVLPS/PD +def : Pat<(store (f64 (vector_extract + (v2f64 (X86Unpckhps VR128:$src, (undef))), (iPTR 0))),addr:$dst), + (MOVHPSmr addr:$dst, VR128:$src)>; +def : Pat<(store (f64 (vector_extract + (v2f64 (X86Unpckhpd VR128:$src, (undef))), (iPTR 0))),addr:$dst), + (MOVHPDmr addr:$dst, VR128:$src)>; + +def : Pat<(store (v4f32 (X86Movlps (load addr:$src1), VR128:$src2)),addr:$src1), + (MOVLPSmr addr:$src1, VR128:$src2)>; +def : Pat<(store (v4i32 (X86Movlps + (bc_v4i32 (loadv2i64 addr:$src1)), VR128:$src2)), addr:$src1), + (MOVLPSmr addr:$src1, VR128:$src2)>; + +def : Pat<(store (v2f64 (X86Movlpd (load addr:$src1), VR128:$src2)),addr:$src1), + (MOVLPDmr addr:$src1, VR128:$src2)>; +def : Pat<(store (v2i64 (X86Movlpd (load addr:$src1), VR128:$src2)),addr:$src1), + (MOVLPDmr addr:$src1, VR128:$src2)>; diff --git a/lib/Target/X86/X86MCAsmInfo.cpp b/lib/Target/X86/X86MCAsmInfo.cpp index 2b8720b..36badb4 100644 --- a/lib/Target/X86/X86MCAsmInfo.cpp +++ b/lib/Target/X86/X86MCAsmInfo.cpp @@ -103,6 +103,9 @@ getNonexecutableStackSection(MCContext &Ctx) const { } X86MCAsmInfoCOFF::X86MCAsmInfoCOFF(const Triple &Triple) { + if (Triple.getArch() == Triple::x86_64) + GlobalPrefix = ""; + AsmTransCBE = x86_asm_table; AssemblerDialect = AsmWriterFlavor; diff --git a/lib/Target/X86/X86MCCodeEmitter.cpp b/lib/Target/X86/X86MCCodeEmitter.cpp index 23b0666..9564fe0 100644 --- a/lib/Target/X86/X86MCCodeEmitter.cpp +++ b/lib/Target/X86/X86MCCodeEmitter.cpp @@ -365,7 +365,7 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte, const TargetInstrDesc &Desc, raw_ostream &OS) const { bool HasVEX_4V = false; - if (TSFlags & X86II::VEX_4V) + if ((TSFlags >> 32) & X86II::VEX_4V) HasVEX_4V = true; // VEX_R: opcode externsion equivalent to REX.R in @@ -429,10 +429,10 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte, if (TSFlags & X86II::OpSize) VEX_PP = 0x01; - if (TSFlags & X86II::VEX_W) + if ((TSFlags >> 32) & X86II::VEX_W) VEX_W = 1; - if (TSFlags & X86II::VEX_L) + if ((TSFlags >> 32) & X86II::VEX_L) VEX_L = 1; switch (TSFlags & X86II::Op0Mask) { @@ -469,33 +469,39 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte, unsigned NumOps = MI.getNumOperands(); unsigned CurOp = 0; + bool IsDestMem = false; switch (TSFlags & X86II::FormMask) { case X86II::MRMInitReg: assert(0 && "FIXME: Remove this!"); + case X86II::MRMDestMem: + IsDestMem = true; + // The important info for the VEX prefix is never beyond the address + // registers. Don't check beyond that. + NumOps = CurOp = X86::AddrNumOperands; case X86II::MRM0m: case X86II::MRM1m: case X86II::MRM2m: case X86II::MRM3m: case X86II::MRM4m: case X86II::MRM5m: case X86II::MRM6m: case X86II::MRM7m: - case X86II::MRMDestMem: - NumOps = CurOp = X86::AddrNumOperands; case X86II::MRMSrcMem: case X86II::MRMSrcReg: if (MI.getNumOperands() > CurOp && MI.getOperand(CurOp).isReg() && X86InstrInfo::isX86_64ExtendedReg(MI.getOperand(CurOp).getReg())) VEX_R = 0x0; - - // CurOp and NumOps are equal when VEX_R represents a register used - // to index a memory destination (which is the last operand) - CurOp = (CurOp == NumOps) ? 0 : CurOp+1; + CurOp++; if (HasVEX_4V) { - VEX_4V = getVEXRegisterEncoding(MI, CurOp); + VEX_4V = getVEXRegisterEncoding(MI, IsDestMem ? CurOp-1 : CurOp); CurOp++; } + // To only check operands before the memory address ones, start + // the search from the begining + if (IsDestMem) + CurOp = 0; + // If the last register should be encoded in the immediate field // do not use any bit from VEX prefix to this register, ignore it - if (TSFlags & X86II::VEX_I8IMM) + if ((TSFlags >> 32) & X86II::VEX_I8IMM) NumOps--; for (; CurOp != NumOps; ++CurOp) { @@ -508,7 +514,10 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte, VEX_X = 0x0; } break; - default: // MRMDestReg, MRM0r-MRM7r + default: // MRMDestReg, MRM0r-MRM7r, RawFrm + if (!MI.getNumOperands()) + break; + if (MI.getOperand(CurOp).isReg() && X86InstrInfo::isX86_64ExtendedReg(MI.getOperand(CurOp).getReg())) VEX_B = 0; @@ -524,7 +533,6 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte, VEX_R = 0x0; } break; - assert(0 && "Not implemented!"); } // Emit segment override opcode prefix as needed. @@ -793,9 +801,9 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, // It uses the VEX.VVVV field? bool HasVEX_4V = false; - if (TSFlags & X86II::VEX) + if ((TSFlags >> 32) & X86II::VEX) HasVEXPrefix = true; - if (TSFlags & X86II::VEX_4V) + if ((TSFlags >> 32) & X86II::VEX_4V) HasVEX_4V = true; // Determine where the memory operand starts, if present. @@ -819,6 +827,14 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, case X86II::RawFrm: EmitByte(BaseOpcode, CurByte, OS); break; + + case X86II::RawFrmImm16: + EmitByte(BaseOpcode, CurByte, OS); + EmitImmediate(MI.getOperand(CurOp++), + X86II::getSizeOfImm(TSFlags), getImmFixupKind(TSFlags), + CurByte, OS, Fixups); + EmitImmediate(MI.getOperand(CurOp++), 2, FK_Data_2, CurByte, OS, Fixups); + break; case X86II::AddRegFrm: EmitByte(BaseOpcode + GetX86RegNum(MI.getOperand(CurOp++)), CurByte, OS); @@ -833,10 +849,15 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, case X86II::MRMDestMem: EmitByte(BaseOpcode, CurByte, OS); + SrcRegNum = CurOp + X86::AddrNumOperands; + + if (HasVEX_4V) // Skip 1st src (which is encoded in VEX_VVVV) + SrcRegNum++; + EmitMemModRMByte(MI, CurOp, - GetX86RegNum(MI.getOperand(CurOp + X86::AddrNumOperands)), + GetX86RegNum(MI.getOperand(SrcRegNum)), TSFlags, CurByte, OS, Fixups); - CurOp += X86::AddrNumOperands + 1; + CurOp = SrcRegNum + 1; break; case X86II::MRMSrcReg: @@ -934,7 +955,7 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, if (CurOp != NumOps) { // The last source register of a 4 operand instruction in AVX is encoded // in bits[7:4] of a immediate byte, and bits[3:0] are ignored. - if (TSFlags & X86II::VEX_I8IMM) { + if ((TSFlags >> 32) & X86II::VEX_I8IMM) { const MCOperand &MO = MI.getOperand(CurOp++); bool IsExtReg = X86InstrInfo::isX86_64ExtendedReg(MO.getReg()); diff --git a/lib/Target/X86/X86MCInstLower.cpp b/lib/Target/X86/X86MCInstLower.cpp new file mode 100644 index 0000000..8c4620f --- /dev/null +++ b/lib/Target/X86/X86MCInstLower.cpp @@ -0,0 +1,609 @@ +//===-- X86MCInstLower.cpp - Convert X86 MachineInstr to an MCInst --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains code to lower X86 MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "X86MCInstLower.h" +#include "X86AsmPrinter.h" +#include "X86COFFMachineModuleInfo.h" +#include "X86MCAsmInfo.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Type.h" +using namespace llvm; + +X86MCInstLower::X86MCInstLower(Mangler *mang, const MachineFunction &mf, + X86AsmPrinter &asmprinter) +: Ctx(mf.getContext()), Mang(mang), MF(mf), TM(mf.getTarget()), + MAI(*TM.getMCAsmInfo()), AsmPrinter(asmprinter) {} + +MachineModuleInfoMachO &X86MCInstLower::getMachOMMI() const { + return MF.getMMI().getObjFileInfo(); +} + + +MCSymbol *X86MCInstLower::GetPICBaseSymbol() const { + return static_cast(TM.getTargetLowering())-> + getPICBaseSymbol(&MF, Ctx); +} + +/// GetSymbolFromOperand - Lower an MO_GlobalAddress or MO_ExternalSymbol +/// operand to an MCSymbol. +MCSymbol *X86MCInstLower:: +GetSymbolFromOperand(const MachineOperand &MO) const { + assert((MO.isGlobal() || MO.isSymbol()) && "Isn't a symbol reference"); + + SmallString<128> Name; + + if (!MO.isGlobal()) { + assert(MO.isSymbol()); + Name += MAI.getGlobalPrefix(); + Name += MO.getSymbolName(); + } else { + const GlobalValue *GV = MO.getGlobal(); + bool isImplicitlyPrivate = false; + if (MO.getTargetFlags() == X86II::MO_DARWIN_STUB || + MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY || + MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE || + MO.getTargetFlags() == X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE) + isImplicitlyPrivate = true; + + Mang->getNameWithPrefix(Name, GV, isImplicitlyPrivate); + } + + // If the target flags on the operand changes the name of the symbol, do that + // before we return the symbol. + switch (MO.getTargetFlags()) { + default: break; + case X86II::MO_DLLIMPORT: { + // Handle dllimport linkage. + const char *Prefix = "__imp_"; + Name.insert(Name.begin(), Prefix, Prefix+strlen(Prefix)); + break; + } + case X86II::MO_DARWIN_NONLAZY: + case X86II::MO_DARWIN_NONLAZY_PIC_BASE: { + Name += "$non_lazy_ptr"; + MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name.str()); + + MachineModuleInfoImpl::StubValueTy &StubSym = + getMachOMMI().getGVStubEntry(Sym); + if (StubSym.getPointer() == 0) { + assert(MO.isGlobal() && "Extern symbol not handled yet"); + StubSym = + MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(MO.getGlobal()), + !MO.getGlobal()->hasInternalLinkage()); + } + return Sym; + } + case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE: { + Name += "$non_lazy_ptr"; + MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name.str()); + MachineModuleInfoImpl::StubValueTy &StubSym = + getMachOMMI().getHiddenGVStubEntry(Sym); + if (StubSym.getPointer() == 0) { + assert(MO.isGlobal() && "Extern symbol not handled yet"); + StubSym = + MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(MO.getGlobal()), + !MO.getGlobal()->hasInternalLinkage()); + } + return Sym; + } + case X86II::MO_DARWIN_STUB: { + Name += "$stub"; + MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name.str()); + MachineModuleInfoImpl::StubValueTy &StubSym = + getMachOMMI().getFnStubEntry(Sym); + if (StubSym.getPointer()) + return Sym; + + if (MO.isGlobal()) { + StubSym = + MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(MO.getGlobal()), + !MO.getGlobal()->hasInternalLinkage()); + } else { + Name.erase(Name.end()-5, Name.end()); + StubSym = + MachineModuleInfoImpl:: + StubValueTy(Ctx.GetOrCreateSymbol(Name.str()), false); + } + return Sym; + } + } + + return Ctx.GetOrCreateSymbol(Name.str()); +} + +MCOperand X86MCInstLower::LowerSymbolOperand(const MachineOperand &MO, + MCSymbol *Sym) const { + // FIXME: We would like an efficient form for this, so we don't have to do a + // lot of extra uniquing. + const MCExpr *Expr = 0; + MCSymbolRefExpr::VariantKind RefKind = MCSymbolRefExpr::VK_None; + + switch (MO.getTargetFlags()) { + default: llvm_unreachable("Unknown target flag on GV operand"); + case X86II::MO_NO_FLAG: // No flag. + // These affect the name of the symbol, not any suffix. + case X86II::MO_DARWIN_NONLAZY: + case X86II::MO_DLLIMPORT: + case X86II::MO_DARWIN_STUB: + break; + + case X86II::MO_TLVP: RefKind = MCSymbolRefExpr::VK_TLVP; break; + case X86II::MO_TLVP_PIC_BASE: + Expr = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_TLVP, Ctx); + // Subtract the pic base. + Expr = MCBinaryExpr::CreateSub(Expr, + MCSymbolRefExpr::Create(GetPICBaseSymbol(), + Ctx), + Ctx); + break; + case X86II::MO_TLSGD: RefKind = MCSymbolRefExpr::VK_TLSGD; break; + case X86II::MO_GOTTPOFF: RefKind = MCSymbolRefExpr::VK_GOTTPOFF; break; + case X86II::MO_INDNTPOFF: RefKind = MCSymbolRefExpr::VK_INDNTPOFF; break; + case X86II::MO_TPOFF: RefKind = MCSymbolRefExpr::VK_TPOFF; break; + case X86II::MO_NTPOFF: RefKind = MCSymbolRefExpr::VK_NTPOFF; break; + case X86II::MO_GOTPCREL: RefKind = MCSymbolRefExpr::VK_GOTPCREL; break; + case X86II::MO_GOT: RefKind = MCSymbolRefExpr::VK_GOT; break; + case X86II::MO_GOTOFF: RefKind = MCSymbolRefExpr::VK_GOTOFF; break; + case X86II::MO_PLT: RefKind = MCSymbolRefExpr::VK_PLT; break; + case X86II::MO_PIC_BASE_OFFSET: + case X86II::MO_DARWIN_NONLAZY_PIC_BASE: + case X86II::MO_DARWIN_HIDDEN_NONLAZY_PIC_BASE: + Expr = MCSymbolRefExpr::Create(Sym, Ctx); + // Subtract the pic base. + Expr = MCBinaryExpr::CreateSub(Expr, + MCSymbolRefExpr::Create(GetPICBaseSymbol(), Ctx), + Ctx); + if (MO.isJTI() && MAI.hasSetDirective()) { + // If .set directive is supported, use it to reduce the number of + // relocations the assembler will generate for differences between + // local labels. This is only safe when the symbols are in the same + // section so we are restricting it to jumptable references. + MCSymbol *Label = Ctx.CreateTempSymbol(); + AsmPrinter.OutStreamer.EmitAssignment(Label, Expr); + Expr = MCSymbolRefExpr::Create(Label, Ctx); + } + break; + } + + if (Expr == 0) + Expr = MCSymbolRefExpr::Create(Sym, RefKind, Ctx); + + if (!MO.isJTI() && MO.getOffset()) + Expr = MCBinaryExpr::CreateAdd(Expr, + MCConstantExpr::Create(MO.getOffset(), Ctx), + Ctx); + return MCOperand::CreateExpr(Expr); +} + + + +static void lower_subreg32(MCInst *MI, unsigned OpNo) { + // Convert registers in the addr mode according to subreg32. + unsigned Reg = MI->getOperand(OpNo).getReg(); + if (Reg != 0) + MI->getOperand(OpNo).setReg(getX86SubSuperRegister(Reg, MVT::i32)); +} + +static void lower_lea64_32mem(MCInst *MI, unsigned OpNo) { + // Convert registers in the addr mode according to subreg64. + for (unsigned i = 0; i != 4; ++i) { + if (!MI->getOperand(OpNo+i).isReg()) continue; + + unsigned Reg = MI->getOperand(OpNo+i).getReg(); + if (Reg == 0) continue; + + MI->getOperand(OpNo+i).setReg(getX86SubSuperRegister(Reg, MVT::i64)); + } +} + +/// LowerSubReg32_Op0 - Things like MOVZX16rr8 -> MOVZX32rr8. +static void LowerSubReg32_Op0(MCInst &OutMI, unsigned NewOpc) { + OutMI.setOpcode(NewOpc); + lower_subreg32(&OutMI, 0); +} +/// LowerUnaryToTwoAddr - R = setb -> R = sbb R, R +static void LowerUnaryToTwoAddr(MCInst &OutMI, unsigned NewOpc) { + OutMI.setOpcode(NewOpc); + OutMI.addOperand(OutMI.getOperand(0)); + OutMI.addOperand(OutMI.getOperand(0)); +} + +/// \brief Simplify FOO $imm, %{al,ax,eax,rax} to FOO $imm, for instruction with +/// a short fixed-register form. +static void SimplifyShortImmForm(MCInst &Inst, unsigned Opcode) { + unsigned ImmOp = Inst.getNumOperands() - 1; + assert(Inst.getOperand(0).isReg() && Inst.getOperand(ImmOp).isImm() && + ((Inst.getNumOperands() == 3 && Inst.getOperand(1).isReg() && + Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg()) || + Inst.getNumOperands() == 2) && "Unexpected instruction!"); + + // Check whether the destination register can be fixed. + unsigned Reg = Inst.getOperand(0).getReg(); + if (Reg != X86::AL && Reg != X86::AX && Reg != X86::EAX && Reg != X86::RAX) + return; + + // If so, rewrite the instruction. + MCOperand Saved = Inst.getOperand(ImmOp); + Inst = MCInst(); + Inst.setOpcode(Opcode); + Inst.addOperand(Saved); +} + +/// \brief Simplify things like MOV32rm to MOV32o32a. +static void SimplifyShortMoveForm(X86AsmPrinter &Printer, MCInst &Inst, + unsigned Opcode) { + // Don't make these simplifications in 64-bit mode; other assemblers don't + // perform them because they make the code larger. + if (Printer.getSubtarget().is64Bit()) + return; + + bool IsStore = Inst.getOperand(0).isReg() && Inst.getOperand(1).isReg(); + unsigned AddrBase = IsStore; + unsigned RegOp = IsStore ? 0 : 5; + unsigned AddrOp = AddrBase + 3; + assert(Inst.getNumOperands() == 6 && Inst.getOperand(RegOp).isReg() && + Inst.getOperand(AddrBase + 0).isReg() && // base + Inst.getOperand(AddrBase + 1).isImm() && // scale + Inst.getOperand(AddrBase + 2).isReg() && // index register + (Inst.getOperand(AddrOp).isExpr() || // address + Inst.getOperand(AddrOp).isImm())&& + Inst.getOperand(AddrBase + 4).isReg() && // segment + "Unexpected instruction!"); + + // Check whether the destination register can be fixed. + unsigned Reg = Inst.getOperand(RegOp).getReg(); + if (Reg != X86::AL && Reg != X86::AX && Reg != X86::EAX && Reg != X86::RAX) + return; + + // Check whether this is an absolute address. + // FIXME: We know TLVP symbol refs aren't, but there should be a better way + // to do this here. + bool Absolute = true; + if (Inst.getOperand(AddrOp).isExpr()) { + const MCExpr *MCE = Inst.getOperand(AddrOp).getExpr(); + if (const MCSymbolRefExpr *SRE = dyn_cast(MCE)) + if (SRE->getKind() == MCSymbolRefExpr::VK_TLVP) + Absolute = false; + } + + if (Absolute && + (Inst.getOperand(AddrBase + 0).getReg() != 0 || + Inst.getOperand(AddrBase + 2).getReg() != 0 || + Inst.getOperand(AddrBase + 4).getReg() != 0 || + Inst.getOperand(AddrBase + 1).getImm() != 1)) + return; + + // If so, rewrite the instruction. + MCOperand Saved = Inst.getOperand(AddrOp); + Inst = MCInst(); + Inst.setOpcode(Opcode); + Inst.addOperand(Saved); +} + +void X86MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + + MCOperand MCOp; + switch (MO.getType()) { + default: + MI->dump(); + llvm_unreachable("unknown operand type"); + case MachineOperand::MO_Register: + // Ignore all implicit register operands. + if (MO.isImplicit()) continue; + MCOp = MCOperand::CreateReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::CreateImm(MO.getImm()); + break; + case MachineOperand::MO_MachineBasicBlock: + MCOp = MCOperand::CreateExpr(MCSymbolRefExpr::Create( + MO.getMBB()->getSymbol(), Ctx)); + break; + case MachineOperand::MO_GlobalAddress: + MCOp = LowerSymbolOperand(MO, GetSymbolFromOperand(MO)); + break; + case MachineOperand::MO_ExternalSymbol: + MCOp = LowerSymbolOperand(MO, GetSymbolFromOperand(MO)); + break; + case MachineOperand::MO_JumpTableIndex: + MCOp = LowerSymbolOperand(MO, AsmPrinter.GetJTISymbol(MO.getIndex())); + break; + case MachineOperand::MO_ConstantPoolIndex: + MCOp = LowerSymbolOperand(MO, AsmPrinter.GetCPISymbol(MO.getIndex())); + break; + case MachineOperand::MO_BlockAddress: + MCOp = LowerSymbolOperand(MO, + AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress())); + break; + } + + OutMI.addOperand(MCOp); + } + + // Handle a few special cases to eliminate operand modifiers. + switch (OutMI.getOpcode()) { + case X86::LEA64_32r: // Handle 'subreg rewriting' for the lea64_32mem operand. + lower_lea64_32mem(&OutMI, 1); + // FALL THROUGH. + case X86::LEA64r: + case X86::LEA16r: + case X86::LEA32r: + // LEA should have a segment register, but it must be empty. + assert(OutMI.getNumOperands() == 1+X86::AddrNumOperands && + "Unexpected # of LEA operands"); + assert(OutMI.getOperand(1+X86::AddrSegmentReg).getReg() == 0 && + "LEA has segment specified!"); + break; + case X86::MOVZX16rr8: LowerSubReg32_Op0(OutMI, X86::MOVZX32rr8); break; + case X86::MOVZX16rm8: LowerSubReg32_Op0(OutMI, X86::MOVZX32rm8); break; + case X86::MOVSX16rr8: LowerSubReg32_Op0(OutMI, X86::MOVSX32rr8); break; + case X86::MOVSX16rm8: LowerSubReg32_Op0(OutMI, X86::MOVSX32rm8); break; + case X86::MOVZX64rr32: LowerSubReg32_Op0(OutMI, X86::MOV32rr); break; + case X86::MOVZX64rm32: LowerSubReg32_Op0(OutMI, X86::MOV32rm); break; + case X86::MOV64ri64i32: LowerSubReg32_Op0(OutMI, X86::MOV32ri); break; + case X86::MOVZX64rr8: LowerSubReg32_Op0(OutMI, X86::MOVZX32rr8); break; + case X86::MOVZX64rm8: LowerSubReg32_Op0(OutMI, X86::MOVZX32rm8); break; + case X86::MOVZX64rr16: LowerSubReg32_Op0(OutMI, X86::MOVZX32rr16); break; + case X86::MOVZX64rm16: LowerSubReg32_Op0(OutMI, X86::MOVZX32rm16); break; + case X86::SETB_C8r: LowerUnaryToTwoAddr(OutMI, X86::SBB8rr); break; + case X86::SETB_C16r: LowerUnaryToTwoAddr(OutMI, X86::SBB16rr); break; + case X86::SETB_C32r: LowerUnaryToTwoAddr(OutMI, X86::SBB32rr); break; + case X86::SETB_C64r: LowerUnaryToTwoAddr(OutMI, X86::SBB64rr); break; + case X86::MOV8r0: LowerUnaryToTwoAddr(OutMI, X86::XOR8rr); break; + case X86::MOV32r0: LowerUnaryToTwoAddr(OutMI, X86::XOR32rr); break; + case X86::MMX_V_SET0: LowerUnaryToTwoAddr(OutMI, X86::MMX_PXORrr); break; + case X86::MMX_V_SETALLONES: + LowerUnaryToTwoAddr(OutMI, X86::MMX_PCMPEQDrr); break; + case X86::FsFLD0SS: LowerUnaryToTwoAddr(OutMI, X86::PXORrr); break; + case X86::FsFLD0SD: LowerUnaryToTwoAddr(OutMI, X86::PXORrr); break; + case X86::V_SET0PS: LowerUnaryToTwoAddr(OutMI, X86::XORPSrr); break; + case X86::V_SET0PD: LowerUnaryToTwoAddr(OutMI, X86::XORPDrr); break; + case X86::V_SET0PI: LowerUnaryToTwoAddr(OutMI, X86::PXORrr); break; + case X86::V_SETALLONES: LowerUnaryToTwoAddr(OutMI, X86::PCMPEQDrr); break; + case X86::AVX_SET0PS: LowerUnaryToTwoAddr(OutMI, X86::VXORPSrr); break; + case X86::AVX_SET0PSY: LowerUnaryToTwoAddr(OutMI, X86::VXORPSYrr); break; + case X86::AVX_SET0PD: LowerUnaryToTwoAddr(OutMI, X86::VXORPDrr); break; + case X86::AVX_SET0PDY: LowerUnaryToTwoAddr(OutMI, X86::VXORPDYrr); break; + case X86::AVX_SET0PI: LowerUnaryToTwoAddr(OutMI, X86::VPXORrr); break; + + case X86::MOV16r0: + LowerSubReg32_Op0(OutMI, X86::MOV32r0); // MOV16r0 -> MOV32r0 + LowerUnaryToTwoAddr(OutMI, X86::XOR32rr); // MOV32r0 -> XOR32rr + break; + case X86::MOV64r0: + LowerSubReg32_Op0(OutMI, X86::MOV32r0); // MOV64r0 -> MOV32r0 + LowerUnaryToTwoAddr(OutMI, X86::XOR32rr); // MOV32r0 -> XOR32rr + break; + + // TAILJMPr64, [WIN]CALL64r, [WIN]CALL64pcrel32 - These instructions have + // register inputs modeled as normal uses instead of implicit uses. As such, + // truncate off all but the first operand (the callee). FIXME: Change isel. + case X86::TAILJMPr64: + case X86::CALL64r: + case X86::CALL64pcrel32: + case X86::WINCALL64r: + case X86::WINCALL64pcrel32: { + unsigned Opcode = OutMI.getOpcode(); + MCOperand Saved = OutMI.getOperand(0); + OutMI = MCInst(); + OutMI.setOpcode(Opcode); + OutMI.addOperand(Saved); + break; + } + + // TAILJMPd, TAILJMPd64 - Lower to the correct jump instructions. + case X86::TAILJMPr: + case X86::TAILJMPd: + case X86::TAILJMPd64: { + unsigned Opcode; + switch (OutMI.getOpcode()) { + default: assert(0 && "Invalid opcode"); + case X86::TAILJMPr: Opcode = X86::JMP32r; break; + case X86::TAILJMPd: + case X86::TAILJMPd64: Opcode = X86::JMP_1; break; + } + + MCOperand Saved = OutMI.getOperand(0); + OutMI = MCInst(); + OutMI.setOpcode(Opcode); + OutMI.addOperand(Saved); + break; + } + + // The assembler backend wants to see branches in their small form and relax + // them to their large form. The JIT can only handle the large form because + // it does not do relaxation. For now, translate the large form to the + // small one here. + case X86::JMP_4: OutMI.setOpcode(X86::JMP_1); break; + case X86::JO_4: OutMI.setOpcode(X86::JO_1); break; + case X86::JNO_4: OutMI.setOpcode(X86::JNO_1); break; + case X86::JB_4: OutMI.setOpcode(X86::JB_1); break; + case X86::JAE_4: OutMI.setOpcode(X86::JAE_1); break; + case X86::JE_4: OutMI.setOpcode(X86::JE_1); break; + case X86::JNE_4: OutMI.setOpcode(X86::JNE_1); break; + case X86::JBE_4: OutMI.setOpcode(X86::JBE_1); break; + case X86::JA_4: OutMI.setOpcode(X86::JA_1); break; + case X86::JS_4: OutMI.setOpcode(X86::JS_1); break; + case X86::JNS_4: OutMI.setOpcode(X86::JNS_1); break; + case X86::JP_4: OutMI.setOpcode(X86::JP_1); break; + case X86::JNP_4: OutMI.setOpcode(X86::JNP_1); break; + case X86::JL_4: OutMI.setOpcode(X86::JL_1); break; + case X86::JGE_4: OutMI.setOpcode(X86::JGE_1); break; + case X86::JLE_4: OutMI.setOpcode(X86::JLE_1); break; + case X86::JG_4: OutMI.setOpcode(X86::JG_1); break; + + // We don't currently select the correct instruction form for instructions + // which have a short %eax, etc. form. Handle this by custom lowering, for + // now. + // + // Note, we are currently not handling the following instructions: + // MOV64ao8, MOV64o8a + // XCHG16ar, XCHG32ar, XCHG64ar + case X86::MOV8mr_NOREX: + case X86::MOV8mr: SimplifyShortMoveForm(AsmPrinter, OutMI, X86::MOV8ao8); break; + case X86::MOV8rm_NOREX: + case X86::MOV8rm: SimplifyShortMoveForm(AsmPrinter, OutMI, X86::MOV8o8a); break; + case X86::MOV16mr: SimplifyShortMoveForm(AsmPrinter, OutMI, X86::MOV16ao16); break; + case X86::MOV16rm: SimplifyShortMoveForm(AsmPrinter, OutMI, X86::MOV16o16a); break; + case X86::MOV32mr: SimplifyShortMoveForm(AsmPrinter, OutMI, X86::MOV32ao32); break; + case X86::MOV32rm: SimplifyShortMoveForm(AsmPrinter, OutMI, X86::MOV32o32a); break; + + case X86::ADC8ri: SimplifyShortImmForm(OutMI, X86::ADC8i8); break; + case X86::ADC16ri: SimplifyShortImmForm(OutMI, X86::ADC16i16); break; + case X86::ADC32ri: SimplifyShortImmForm(OutMI, X86::ADC32i32); break; + case X86::ADC64ri32: SimplifyShortImmForm(OutMI, X86::ADC64i32); break; + case X86::ADD8ri: SimplifyShortImmForm(OutMI, X86::ADD8i8); break; + case X86::ADD16ri: SimplifyShortImmForm(OutMI, X86::ADD16i16); break; + case X86::ADD32ri: SimplifyShortImmForm(OutMI, X86::ADD32i32); break; + case X86::ADD64ri32: SimplifyShortImmForm(OutMI, X86::ADD64i32); break; + case X86::AND8ri: SimplifyShortImmForm(OutMI, X86::AND8i8); break; + case X86::AND16ri: SimplifyShortImmForm(OutMI, X86::AND16i16); break; + case X86::AND32ri: SimplifyShortImmForm(OutMI, X86::AND32i32); break; + case X86::AND64ri32: SimplifyShortImmForm(OutMI, X86::AND64i32); break; + case X86::CMP8ri: SimplifyShortImmForm(OutMI, X86::CMP8i8); break; + case X86::CMP16ri: SimplifyShortImmForm(OutMI, X86::CMP16i16); break; + case X86::CMP32ri: SimplifyShortImmForm(OutMI, X86::CMP32i32); break; + case X86::CMP64ri32: SimplifyShortImmForm(OutMI, X86::CMP64i32); break; + case X86::OR8ri: SimplifyShortImmForm(OutMI, X86::OR8i8); break; + case X86::OR16ri: SimplifyShortImmForm(OutMI, X86::OR16i16); break; + case X86::OR32ri: SimplifyShortImmForm(OutMI, X86::OR32i32); break; + case X86::OR64ri32: SimplifyShortImmForm(OutMI, X86::OR64i32); break; + case X86::SBB8ri: SimplifyShortImmForm(OutMI, X86::SBB8i8); break; + case X86::SBB16ri: SimplifyShortImmForm(OutMI, X86::SBB16i16); break; + case X86::SBB32ri: SimplifyShortImmForm(OutMI, X86::SBB32i32); break; + case X86::SBB64ri32: SimplifyShortImmForm(OutMI, X86::SBB64i32); break; + case X86::SUB8ri: SimplifyShortImmForm(OutMI, X86::SUB8i8); break; + case X86::SUB16ri: SimplifyShortImmForm(OutMI, X86::SUB16i16); break; + case X86::SUB32ri: SimplifyShortImmForm(OutMI, X86::SUB32i32); break; + case X86::SUB64ri32: SimplifyShortImmForm(OutMI, X86::SUB64i32); break; + case X86::TEST8ri: SimplifyShortImmForm(OutMI, X86::TEST8i8); break; + case X86::TEST16ri: SimplifyShortImmForm(OutMI, X86::TEST16i16); break; + case X86::TEST32ri: SimplifyShortImmForm(OutMI, X86::TEST32i32); break; + case X86::TEST64ri32: SimplifyShortImmForm(OutMI, X86::TEST64i32); break; + case X86::XOR8ri: SimplifyShortImmForm(OutMI, X86::XOR8i8); break; + case X86::XOR16ri: SimplifyShortImmForm(OutMI, X86::XOR16i16); break; + case X86::XOR32ri: SimplifyShortImmForm(OutMI, X86::XOR32i32); break; + case X86::XOR64ri32: SimplifyShortImmForm(OutMI, X86::XOR64i32); break; + } +} + + +void X86AsmPrinter::EmitInstruction(const MachineInstr *MI) { + X86MCInstLower MCInstLowering(Mang, *MF, *this); + switch (MI->getOpcode()) { + case TargetOpcode::DBG_VALUE: + if (isVerbose() && OutStreamer.hasRawTextSupport()) { + std::string TmpStr; + raw_string_ostream OS(TmpStr); + PrintDebugValueComment(MI, OS); + OutStreamer.EmitRawText(StringRef(OS.str())); + } + return; + + // Emit nothing here but a comment if we can. + case X86::Int_MemBarrier: + if (OutStreamer.hasRawTextSupport()) + OutStreamer.EmitRawText(StringRef("\t#MEMBARRIER")); + return; + + case X86::TAILJMPr: + case X86::TAILJMPd: + case X86::TAILJMPd64: + // Lower these as normal, but add some comments. + OutStreamer.AddComment("TAILCALL"); + break; + + case X86::MOVPC32r: { + MCInst TmpInst; + // This is a pseudo op for a two instruction sequence with a label, which + // looks like: + // call "L1$pb" + // "L1$pb": + // popl %esi + + // Emit the call. + MCSymbol *PICBase = MCInstLowering.GetPICBaseSymbol(); + TmpInst.setOpcode(X86::CALLpcrel32); + // FIXME: We would like an efficient form for this, so we don't have to do a + // lot of extra uniquing. + TmpInst.addOperand(MCOperand::CreateExpr(MCSymbolRefExpr::Create(PICBase, + OutContext))); + OutStreamer.EmitInstruction(TmpInst); + + // Emit the label. + OutStreamer.EmitLabel(PICBase); + + // popl $reg + TmpInst.setOpcode(X86::POP32r); + TmpInst.getOperand(0) = MCOperand::CreateReg(MI->getOperand(0).getReg()); + OutStreamer.EmitInstruction(TmpInst); + return; + } + + case X86::ADD32ri: { + // Lower the MO_GOT_ABSOLUTE_ADDRESS form of ADD32ri. + if (MI->getOperand(2).getTargetFlags() != X86II::MO_GOT_ABSOLUTE_ADDRESS) + break; + + // Okay, we have something like: + // EAX = ADD32ri EAX, MO_GOT_ABSOLUTE_ADDRESS(@MYGLOBAL) + + // For this, we want to print something like: + // MYGLOBAL + (. - PICBASE) + // However, we can't generate a ".", so just emit a new label here and refer + // to it. + MCSymbol *DotSym = OutContext.CreateTempSymbol(); + OutStreamer.EmitLabel(DotSym); + + // Now that we have emitted the label, lower the complex operand expression. + MCSymbol *OpSym = MCInstLowering.GetSymbolFromOperand(MI->getOperand(2)); + + const MCExpr *DotExpr = MCSymbolRefExpr::Create(DotSym, OutContext); + const MCExpr *PICBase = + MCSymbolRefExpr::Create(MCInstLowering.GetPICBaseSymbol(), OutContext); + DotExpr = MCBinaryExpr::CreateSub(DotExpr, PICBase, OutContext); + + DotExpr = MCBinaryExpr::CreateAdd(MCSymbolRefExpr::Create(OpSym,OutContext), + DotExpr, OutContext); + + MCInst TmpInst; + TmpInst.setOpcode(X86::ADD32ri); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); + TmpInst.addOperand(MCOperand::CreateExpr(DotExpr)); + OutStreamer.EmitInstruction(TmpInst); + return; + } + } + + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + OutStreamer.EmitInstruction(TmpInst); +} + diff --git a/lib/Target/X86/X86MCInstLower.h b/lib/Target/X86/X86MCInstLower.h new file mode 100644 index 0000000..539b09b --- /dev/null +++ b/lib/Target/X86/X86MCInstLower.h @@ -0,0 +1,54 @@ +//===-- X86MCInstLower.h - Lower MachineInstr to MCInst -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef X86_MCINSTLOWER_H +#define X86_MCINSTLOWER_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { + class MCAsmInfo; + class MCContext; + class MCInst; + class MCOperand; + class MCSymbol; + class MachineInstr; + class MachineFunction; + class MachineModuleInfoMachO; + class MachineOperand; + class Mangler; + class TargetMachine; + class X86AsmPrinter; + +/// X86MCInstLower - This class is used to lower an MachineInstr into an MCInst. +class LLVM_LIBRARY_VISIBILITY X86MCInstLower { + MCContext &Ctx; + Mangler *Mang; + const MachineFunction &MF; + const TargetMachine &TM; + const MCAsmInfo &MAI; + X86AsmPrinter &AsmPrinter; +public: + X86MCInstLower(Mangler *mang, const MachineFunction &MF, + X86AsmPrinter &asmprinter); + + void Lower(const MachineInstr *MI, MCInst &OutMI) const; + + MCSymbol *GetPICBaseSymbol() const; + + MCSymbol *GetSymbolFromOperand(const MachineOperand &MO) const; + MCOperand LowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym) const; + +private: + MachineModuleInfoMachO &getMachOMMI() const; +}; + +} + +#endif diff --git a/lib/Target/X86/X86RegisterInfo.cpp b/lib/Target/X86/X86RegisterInfo.cpp index 5f31e00..fedd49e 100644 --- a/lib/Target/X86/X86RegisterInfo.cpp +++ b/lib/Target/X86/X86RegisterInfo.cpp @@ -38,8 +38,15 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/CommandLine.h" using namespace llvm; +static cl::opt +ForceStackAlign("force-align-stack", + cl::desc("Force align the stack to the minimum alignment" + " needed for the function."), + cl::init(false), cl::Hidden); + X86RegisterInfo::X86RegisterInfo(X86TargetMachine &tm, const TargetInstrInfo &tii) : X86GenRegisterInfo(tm.getSubtarget().is64Bit() ? @@ -193,6 +200,12 @@ unsigned X86RegisterInfo::getX86RegNum(unsigned RegNo) { case X86::DR7: return 7; + // Pseudo index registers are equivalent to a "none" + // scaled index (See Intel Manual 2A, table 2-3) + case X86::EIZ: + case X86::RIZ: + return 4; + default: assert(isVirtualRegister(RegNo) && "Unknown physical register!"); llvm_unreachable("Register allocator hasn't allocated reg correctly yet!"); @@ -456,26 +469,29 @@ bool X86RegisterInfo::canRealignStack(const MachineFunction &MF) const { bool X86RegisterInfo::needsStackRealignment(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); const Function *F = MF.getFunction(); - bool requiresRealignment = - RealignStack && ((MFI->getMaxAlignment() > StackAlign) || - F->hasFnAttr(Attribute::StackAlignment)); + bool requiresRealignment = ((MFI->getMaxAlignment() > StackAlign) || + F->hasFnAttr(Attribute::StackAlignment)); // FIXME: Currently we don't support stack realignment for functions with // variable-sized allocas. - // FIXME: Temporary disable the error - it seems to be too conservative. + // FIXME: It's more complicated than this... if (0 && requiresRealignment && MFI->hasVarSizedObjects()) report_fatal_error( "Stack realignment in presense of dynamic allocas is not supported"); - - return (requiresRealignment && !MFI->hasVarSizedObjects()); + + // If we've requested that we force align the stack do so now. + if (ForceStackAlign) + return canRealignStack(MF); + + return requiresRealignment && canRealignStack(MF); } -bool X86RegisterInfo::hasReservedCallFrame(MachineFunction &MF) const { +bool X86RegisterInfo::hasReservedCallFrame(const MachineFunction &MF) const { return !MF.getFrameInfo()->hasVarSizedObjects(); } -bool X86RegisterInfo::hasReservedSpillSlot(MachineFunction &MF, unsigned Reg, - int &FrameIdx) const { +bool X86RegisterInfo::hasReservedSpillSlot(const MachineFunction &MF, + unsigned Reg, int &FrameIdx) const { if (Reg == FramePtr && hasFP(MF)) { FrameIdx = MF.getFrameInfo()->getObjectIndexBegin(); return true; @@ -610,10 +626,9 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MBB.erase(I); } -unsigned +void X86RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value, - RegScavenger *RS) const{ + int SPAdj, RegScavenger *RS) const{ assert(SPAdj == 0 && "Unexpected"); unsigned i = 0; @@ -660,7 +675,6 @@ X86RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, uint64_t Offset = FIOffset + (uint64_t)MI.getOperand(i+3).getOffset(); MI.getOperand(i+3).setOffset(Offset); } - return 0; } void @@ -750,7 +764,7 @@ void mergeSPUpdatesUp(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, } } -/// mergeSPUpdatesUp - Merge two stack-manipulating instructions lower iterator. +/// mergeSPUpdatesDown - Merge two stack-manipulating instructions lower iterator. static void mergeSPUpdatesDown(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, @@ -901,6 +915,17 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { bool HasFP = hasFP(MF); DebugLoc DL; + // If we're forcing a stack realignment we can't rely on just the frame + // info, we need to know the ABI stack alignment as well in case we + // have a call out. Otherwise just make sure we have some alignment - we'll + // go with the minimum SlotSize. + if (ForceStackAlign) { + if (MFI->hasCalls()) + MaxAlign = (StackAlign > MaxAlign) ? StackAlign : MaxAlign; + else if (MaxAlign < SlotSize) + MaxAlign = SlotSize; + } + // Add RETADDR move area to callee saved frame size. int TailCallReturnAddrDelta = X86FI->getTCReturnAddrDelta(); if (TailCallReturnAddrDelta < 0) @@ -979,7 +1004,7 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { if (needsFrameMoves) { // Mark the place where EBP/RBP was saved. MCSymbol *FrameLabel = MMI.getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, DL, TII.get(X86::DBG_LABEL)).addSym(FrameLabel); + BuildMI(MBB, MBBI, DL, TII.get(X86::PROLOG_LABEL)).addSym(FrameLabel); // Define the current CFA rule to use the provided offset. if (StackSize) { @@ -1007,7 +1032,7 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { if (needsFrameMoves) { // Mark effective beginning of when frame pointer becomes valid. MCSymbol *FrameLabel = MMI.getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, DL, TII.get(X86::DBG_LABEL)).addSym(FrameLabel); + BuildMI(MBB, MBBI, DL, TII.get(X86::PROLOG_LABEL)).addSym(FrameLabel); // Define the current CFA to use the EBP/RBP register. MachineLocation FPDst(FramePtr); @@ -1047,7 +1072,7 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { if (!HasFP && needsFrameMoves) { // Mark callee-saved push instruction. MCSymbol *Label = MMI.getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, DL, TII.get(X86::DBG_LABEL)).addSym(Label); + BuildMI(MBB, MBBI, DL, TII.get(X86::PROLOG_LABEL)).addSym(Label); // Define the current CFA rule to use the provided offset. unsigned Ptr = StackSize ? @@ -1062,7 +1087,17 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { DL = MBB.findDebugLoc(MBBI); // Adjust stack pointer: ESP -= numbytes. - if (NumBytes >= 4096 && Subtarget->isTargetCygMing()) { + + // Windows and cygwin/mingw require a prologue helper routine when allocating + // more than 4K bytes on the stack. Windows uses __chkstk and cygwin/mingw + // uses __alloca. __alloca and the 32-bit version of __chkstk will probe + // the stack and adjust the stack pointer in one go. The 64-bit version + // of __chkstk is only responsible for probing the stack. The 64-bit + // prologue is responsible for adjusting the stack pointer. Touching the + // stack at 4K increments is necessary to ensure that the guard pages used + // by the OS virtual memory manager are allocated in correct sequence. + if (NumBytes >= 4096 && + (Subtarget->isTargetCygMing() || Subtarget->isTargetWin32())) { // Check, whether EAX is livein for this function. bool isEAXAlive = false; for (MachineRegisterInfo::livein_iterator @@ -1073,16 +1108,16 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { Reg == X86::AH || Reg == X86::AL); } - // Function prologue calls _alloca to probe the stack when allocating more - // than 4k bytes in one go. Touching the stack at 4K increments is necessary - // to ensure that the guard pages used by the OS virtual memory manager are - // allocated in correct sequence. + + const char *StackProbeSymbol = + Subtarget->isTargetWindows() ? "_chkstk" : "_alloca"; if (!isEAXAlive) { BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32ri), X86::EAX) .addImm(NumBytes); BuildMI(MBB, MBBI, DL, TII.get(X86::CALLpcrel32)) - .addExternalSymbol("_alloca") - .addReg(StackPtr, RegState::Define | RegState::Implicit); + .addExternalSymbol(StackProbeSymbol) + .addReg(StackPtr, RegState::Define | RegState::Implicit) + .addReg(X86::EFLAGS, RegState::Define | RegState::Implicit); } else { // Save EAX BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH32r)) @@ -1093,8 +1128,9 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { BuildMI(MBB, MBBI, DL, TII.get(X86::MOV32ri), X86::EAX) .addImm(NumBytes - 4); BuildMI(MBB, MBBI, DL, TII.get(X86::CALLpcrel32)) - .addExternalSymbol("_alloca") - .addReg(StackPtr, RegState::Define | RegState::Implicit); + .addExternalSymbol(StackProbeSymbol) + .addReg(StackPtr, RegState::Define | RegState::Implicit) + .addReg(X86::EFLAGS, RegState::Define | RegState::Implicit); // Restore EAX MachineInstr *MI = addRegOffset(BuildMI(MF, DL, TII.get(X86::MOV32rm), @@ -1119,7 +1155,7 @@ void X86RegisterInfo::emitPrologue(MachineFunction &MF) const { if ((NumBytes || PushedRegs) && needsFrameMoves) { // Mark end of stack pointer adjustment. MCSymbol *Label = MMI.getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, DL, TII.get(X86::DBG_LABEL)).addSym(Label); + BuildMI(MBB, MBBI, DL, TII.get(X86::PROLOG_LABEL)).addSym(Label); if (!HasFP && NumBytes) { // Define the current CFA rule to use the provided offset. @@ -1172,6 +1208,17 @@ void X86RegisterInfo::emitEpilogue(MachineFunction &MF, unsigned CSSize = X86FI->getCalleeSavedFrameSize(); uint64_t NumBytes = 0; + // If we're forcing a stack realignment we can't rely on just the frame + // info, we need to know the ABI stack alignment as well in case we + // have a call out. Otherwise just make sure we have some alignment - we'll + // go with the minimum. + if (ForceStackAlign) { + if (MFI->hasCalls()) + MaxAlign = (StackAlign > MaxAlign) ? StackAlign : MaxAlign; + else + MaxAlign = MaxAlign ? MaxAlign : 4; + } + if (hasFP(MF)) { // Calculate required stack adjustment. uint64_t FrameSize = StackSize - SlotSize; @@ -1519,7 +1566,7 @@ unsigned getX86SubSuperRegister(unsigned Reg, EVT VT, bool High) { namespace { struct MSAH : public MachineFunctionPass { static char ID; - MSAH() : MachineFunctionPass(&ID) {} + MSAH() : MachineFunctionPass(ID) {} virtual bool runOnMachineFunction(MachineFunction &MF) { const X86TargetMachine *TM = diff --git a/lib/Target/X86/X86RegisterInfo.h b/lib/Target/X86/X86RegisterInfo.h index d852bcd..527df05 100644 --- a/lib/Target/X86/X86RegisterInfo.h +++ b/lib/Target/X86/X86RegisterInfo.h @@ -117,18 +117,17 @@ public: bool needsStackRealignment(const MachineFunction &MF) const; - bool hasReservedCallFrame(MachineFunction &MF) const; + bool hasReservedCallFrame(const MachineFunction &MF) const; - bool hasReservedSpillSlot(MachineFunction &MF, unsigned Reg, + bool hasReservedSpillSlot(const MachineFunction &MF, unsigned Reg, int &FrameIdx) const; void eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const; - unsigned eliminateFrameIndex(MachineBasicBlock::iterator MI, - int SPAdj, FrameIndexValue *Value = NULL, - RegScavenger *RS = NULL) const; + void eliminateFrameIndex(MachineBasicBlock::iterator MI, + int SPAdj, RegScavenger *RS = NULL) const; void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, RegScavenger *RS = NULL) const; diff --git a/lib/Target/X86/X86RegisterInfo.td b/lib/Target/X86/X86RegisterInfo.td index 9f0382e..95269b1 100644 --- a/lib/Target/X86/X86RegisterInfo.td +++ b/lib/Target/X86/X86RegisterInfo.td @@ -241,6 +241,10 @@ let Namespace = "X86" in { def CR6 : Register<"cr6">; def CR7 : Register<"cr7">; def CR8 : Register<"cr8">; + + // Pseudo index registers + def EIZ : Register<"eiz">; + def RIZ : Register<"riz">; } @@ -804,7 +808,7 @@ def VR128 : RegisterClass<"X86", [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64],128, }]; } -def VR256 : RegisterClass<"X86", [v8i32, v4i64, v8f32, v4f64], 256, +def VR256 : RegisterClass<"X86", [v32i8, v8i32, v4i64, v8f32, v4f64], 256, [YMM0, YMM1, YMM2, YMM3, YMM4, YMM5, YMM6, YMM7, YMM8, YMM9, YMM10, YMM11, YMM12, YMM13, YMM14, YMM15]> { @@ -829,4 +833,15 @@ def VR256 : RegisterClass<"X86", [v8i32, v4i64, v8f32, v4f64], 256, // Status flags registers. def CCR : RegisterClass<"X86", [i32], 32, [EFLAGS]> { let CopyCost = -1; // Don't allow copying of status registers. + + // EFLAGS is not allocatable. + let MethodProtos = [{ + iterator allocation_order_end(const MachineFunction &MF) const; + }]; + let MethodBodies = [{ + CCRClass::iterator + CCRClass::allocation_order_end(const MachineFunction &MF) const { + return allocation_order_begin(MF); + } + }]; } diff --git a/lib/Target/X86/X86ShuffleDecode.h b/lib/Target/X86/X86ShuffleDecode.h new file mode 100644 index 0000000..df04052 --- /dev/null +++ b/lib/Target/X86/X86ShuffleDecode.h @@ -0,0 +1,155 @@ +//===-- X86ShuffleDecode.h - X86 shuffle decode logic ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Define several functions to decode x86 specific shuffle semantics into a +// generic vector mask. +// +//===----------------------------------------------------------------------===// + +#ifndef X86_SHUFFLE_DECODE_H +#define X86_SHUFFLE_DECODE_H + +#include "llvm/ADT/SmallVector.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Vector Mask Decoding +//===----------------------------------------------------------------------===// + +enum { + SM_SentinelZero = ~0U +}; + +static inline +void DecodeINSERTPSMask(unsigned Imm, SmallVectorImpl &ShuffleMask) { + // Defaults the copying the dest value. + ShuffleMask.push_back(0); + ShuffleMask.push_back(1); + ShuffleMask.push_back(2); + ShuffleMask.push_back(3); + + // Decode the immediate. + unsigned ZMask = Imm & 15; + unsigned CountD = (Imm >> 4) & 3; + unsigned CountS = (Imm >> 6) & 3; + + // CountS selects which input element to use. + unsigned InVal = 4+CountS; + // CountD specifies which element of destination to update. + ShuffleMask[CountD] = InVal; + // ZMask zaps values, potentially overriding the CountD elt. + if (ZMask & 1) ShuffleMask[0] = SM_SentinelZero; + if (ZMask & 2) ShuffleMask[1] = SM_SentinelZero; + if (ZMask & 4) ShuffleMask[2] = SM_SentinelZero; + if (ZMask & 8) ShuffleMask[3] = SM_SentinelZero; +} + +// <3,1> or <6,7,2,3> +static void DecodeMOVHLPSMask(unsigned NElts, + SmallVectorImpl &ShuffleMask) { + for (unsigned i = NElts/2; i != NElts; ++i) + ShuffleMask.push_back(NElts+i); + + for (unsigned i = NElts/2; i != NElts; ++i) + ShuffleMask.push_back(i); +} + +// <0,2> or <0,1,4,5> +static void DecodeMOVLHPSMask(unsigned NElts, + SmallVectorImpl &ShuffleMask) { + for (unsigned i = 0; i != NElts/2; ++i) + ShuffleMask.push_back(i); + + for (unsigned i = 0; i != NElts/2; ++i) + ShuffleMask.push_back(NElts+i); +} + +static void DecodePSHUFMask(unsigned NElts, unsigned Imm, + SmallVectorImpl &ShuffleMask) { + for (unsigned i = 0; i != NElts; ++i) { + ShuffleMask.push_back(Imm % NElts); + Imm /= NElts; + } +} + +static void DecodePSHUFHWMask(unsigned Imm, + SmallVectorImpl &ShuffleMask) { + ShuffleMask.push_back(0); + ShuffleMask.push_back(1); + ShuffleMask.push_back(2); + ShuffleMask.push_back(3); + for (unsigned i = 0; i != 4; ++i) { + ShuffleMask.push_back(4+(Imm & 3)); + Imm >>= 2; + } +} + +static void DecodePSHUFLWMask(unsigned Imm, + SmallVectorImpl &ShuffleMask) { + for (unsigned i = 0; i != 4; ++i) { + ShuffleMask.push_back((Imm & 3)); + Imm >>= 2; + } + ShuffleMask.push_back(4); + ShuffleMask.push_back(5); + ShuffleMask.push_back(6); + ShuffleMask.push_back(7); +} + +static void DecodePUNPCKLMask(unsigned NElts, + SmallVectorImpl &ShuffleMask) { + for (unsigned i = 0; i != NElts/2; ++i) { + ShuffleMask.push_back(i); + ShuffleMask.push_back(i+NElts); + } +} + +static void DecodePUNPCKHMask(unsigned NElts, + SmallVectorImpl &ShuffleMask) { + for (unsigned i = 0; i != NElts/2; ++i) { + ShuffleMask.push_back(i+NElts/2); + ShuffleMask.push_back(i+NElts+NElts/2); + } +} + +static void DecodeSHUFPSMask(unsigned NElts, unsigned Imm, + SmallVectorImpl &ShuffleMask) { + // Part that reads from dest. + for (unsigned i = 0; i != NElts/2; ++i) { + ShuffleMask.push_back(Imm % NElts); + Imm /= NElts; + } + // Part that reads from src. + for (unsigned i = 0; i != NElts/2; ++i) { + ShuffleMask.push_back(Imm % NElts + NElts); + Imm /= NElts; + } +} + +static void DecodeUNPCKHPMask(unsigned NElts, + SmallVectorImpl &ShuffleMask) { + for (unsigned i = 0; i != NElts/2; ++i) { + ShuffleMask.push_back(i+NElts/2); // Reads from dest + ShuffleMask.push_back(i+NElts+NElts/2); // Reads from src + } +} + + +/// DecodeUNPCKLPMask - This decodes the shuffle masks for unpcklps/unpcklpd +/// etc. NElts indicates the number of elements in the vector allowing it to +/// handle different datatypes and vector widths. +static void DecodeUNPCKLPMask(unsigned NElts, + SmallVectorImpl &ShuffleMask) { + for (unsigned i = 0; i != NElts/2; ++i) { + ShuffleMask.push_back(i); // Reads from dest + ShuffleMask.push_back(i+NElts); // Reads from src + } +} + +#endif diff --git a/lib/Target/X86/X86Subtarget.cpp b/lib/Target/X86/X86Subtarget.cpp index 4a10be5..0d02e5e 100644 --- a/lib/Target/X86/X86Subtarget.cpp +++ b/lib/Target/X86/X86Subtarget.cpp @@ -73,7 +73,7 @@ ClassifyGlobalReference(const GlobalValue *GV, const TargetMachine &TM) const { if (GV->hasDefaultVisibility() && (isDecl || GV->isWeakForLinker())) return X86II::MO_GOTPCREL; - } else { + } else if (!isTargetWin64()) { assert(isTargetELF() && "Unknown rip-relative target"); // Extra load is needed for all externally visible. @@ -260,9 +260,10 @@ void X86Subtarget::AutoDetectSubtargetFeatures() { bool IsIntel = memcmp(text.c, "GenuineIntel", 12) == 0; bool IsAMD = !IsIntel && memcmp(text.c, "AuthenticAMD", 12) == 0; - HasFMA3 = IsIntel && ((ECX >> 12) & 0x1); - HasAVX = ((ECX >> 28) & 0x1); - HasAES = IsIntel && ((ECX >> 25) & 0x1); + HasCLMUL = IsIntel && ((ECX >> 1) & 0x1); + HasFMA3 = IsIntel && ((ECX >> 12) & 0x1); + HasAVX = ((ECX >> 28) & 0x1); + HasAES = IsIntel && ((ECX >> 25) & 0x1); if (IsIntel || IsAMD) { // Determine if bit test memory instructions are slow. @@ -291,6 +292,7 @@ X86Subtarget::X86Subtarget(const std::string &TT, const std::string &FS, , HasSSE4A(false) , HasAVX(false) , HasAES(false) + , HasCLMUL(false) , HasFMA3(false) , HasFMA4(false) , IsBTMemSlow(false) diff --git a/lib/Target/X86/X86Subtarget.h b/lib/Target/X86/X86Subtarget.h index 486dbc4..0ee91ab 100644 --- a/lib/Target/X86/X86Subtarget.h +++ b/lib/Target/X86/X86Subtarget.h @@ -74,6 +74,9 @@ protected: /// HasAES - Target has AES instructions bool HasAES; + /// HasCLMUL - Target has carry-less multiplication + bool HasCLMUL; + /// HasFMA3 - Target has 3-operand fused multiply-add bool HasFMA3; @@ -149,6 +152,7 @@ public: bool has3DNowA() const { return X863DNowLevel >= ThreeDNowA; } bool hasAVX() const { return HasAVX; } bool hasAES() const { return HasAES; } + bool hasCLMUL() const { return HasCLMUL; } bool hasFMA3() const { return HasFMA3; } bool hasFMA4() const { return HasFMA4; } bool isBTMemSlow() const { return IsBTMemSlow; } @@ -182,6 +186,10 @@ public: return Is64Bit && (isTargetMingw() || isTargetWindows()); } + bool isTargetWin32() const { + return !Is64Bit && (isTargetMingw() || isTargetWindows()); + } + std::string getDataLayout() const { const char *p; if (is64Bit()) diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp index df00d3f..ce8636eb 100644 --- a/lib/Target/X86/X86TargetMachine.cpp +++ b/lib/Target/X86/X86TargetMachine.cpp @@ -46,8 +46,15 @@ static MCStreamer *createMCStreamer(const Target &T, const std::string &TT, bool RelaxAll) { Triple TheTriple(TT); switch (TheTriple.getOS()) { - default: + case Triple::Darwin: return createMachOStreamer(Ctx, TAB, _OS, _Emitter, RelaxAll); + case Triple::MinGW32: + case Triple::MinGW64: + case Triple::Cygwin: + case Triple::Win32: + return createWinCOFFStreamer(Ctx, TAB, *_Emitter, _OS, RelaxAll); + default: + return createELFStreamer(Ctx, TAB, _OS, _Emitter, RelaxAll); } } @@ -105,15 +112,21 @@ X86TargetMachine::X86TargetMachine(const Target &T, const std::string &TT, InstrInfo(*this), JITInfo(*this), TLInfo(*this), TSInfo(*this), ELFWriterInfo(*this) { DefRelocModel = getRelocationModel(); - + // If no relocation model was picked, default as appropriate for the target. if (getRelocationModel() == Reloc::Default) { - if (!Subtarget.isTargetDarwin()) - setRelocationModel(Reloc::Static); - else if (Subtarget.is64Bit()) + // Darwin defaults to PIC in 64 bit mode and dynamic-no-pic in 32 bit mode. + // Win64 requires rip-rel addressing, thus we force it to PIC. Otherwise we + // use static relocation model by default. + if (Subtarget.isTargetDarwin()) { + if (Subtarget.is64Bit()) + setRelocationModel(Reloc::PIC_); + else + setRelocationModel(Reloc::DynamicNoPIC); + } else if (Subtarget.isTargetWin64()) setRelocationModel(Reloc::PIC_); else - setRelocationModel(Reloc::DynamicNoPIC); + setRelocationModel(Reloc::Static); } assert(getRelocationModel() != Reloc::Default && @@ -136,29 +149,27 @@ X86TargetMachine::X86TargetMachine(const Target &T, const std::string &TT, Subtarget.isTargetDarwin() && is64Bit) setRelocationModel(Reloc::PIC_); - + // Determine the PICStyle based on the target selected. if (getRelocationModel() == Reloc::Static) { // Unless we're in PIC or DynamicNoPIC mode, set the PIC style to None. Subtarget.setPICStyle(PICStyles::None); + } else if (Subtarget.is64Bit()) { + // PIC in 64 bit mode is always rip-rel. + Subtarget.setPICStyle(PICStyles::RIPRel); } else if (Subtarget.isTargetCygMing()) { Subtarget.setPICStyle(PICStyles::None); } else if (Subtarget.isTargetDarwin()) { - if (Subtarget.is64Bit()) - Subtarget.setPICStyle(PICStyles::RIPRel); - else if (getRelocationModel() == Reloc::PIC_) + if (getRelocationModel() == Reloc::PIC_) Subtarget.setPICStyle(PICStyles::StubPIC); else { assert(getRelocationModel() == Reloc::DynamicNoPIC); Subtarget.setPICStyle(PICStyles::StubDynamicNoPIC); } } else if (Subtarget.isTargetELF()) { - if (Subtarget.is64Bit()) - Subtarget.setPICStyle(PICStyles::RIPRel); - else - Subtarget.setPICStyle(PICStyles::GOT); + Subtarget.setPICStyle(PICStyles::GOT); } - + // Finally, if we have "none" as our PIC style, force to static mode. if (Subtarget.getPICStyle() == PICStyles::None) setRelocationModel(Reloc::Static); @@ -182,9 +193,6 @@ bool X86TargetMachine::addInstSelector(PassManagerBase &PM, bool X86TargetMachine::addPreRegAlloc(PassManagerBase &PM, CodeGenOpt::Level OptLevel) { - // Install a pass to insert x87 FP_REG_KILL instructions, as needed. - PM.add(createX87FPRegKillInserterPass()); - PM.add(createX86MaxStackAlignmentHeuristicPass()); return false; // -print-machineinstr shouldn't print after this. } diff --git a/lib/Target/XCore/AsmPrinter/XCoreAsmPrinter.cpp b/lib/Target/XCore/AsmPrinter/XCoreAsmPrinter.cpp index 6656bdc..8f06dd3 100644 --- a/lib/Target/XCore/AsmPrinter/XCoreAsmPrinter.cpp +++ b/lib/Target/XCore/AsmPrinter/XCoreAsmPrinter.cpp @@ -264,15 +264,13 @@ bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, void XCoreAsmPrinter::EmitInstruction(const MachineInstr *MI) { SmallString<128> Str; raw_svector_ostream O(Str); - + // Check for mov mnemonic - unsigned src, dst, srcSR, dstSR; - if (TM.getInstrInfo()->isMoveInstr(*MI, src, dst, srcSR, dstSR)) { - O << "\tmov " << getRegisterName(dst) << ", "; - O << getRegisterName(src); - } else { + if (MI->getOpcode() == XCore::ADD_2rus && !MI->getOperand(2).getImm()) + O << "\tmov " << getRegisterName(MI->getOperand(0).getReg()) << ", " + << getRegisterName(MI->getOperand(1).getReg()); + else printInstruction(MI, O); - } OutStreamer.EmitRawText(O.str()); } diff --git a/lib/Target/XCore/CMakeLists.txt b/lib/Target/XCore/CMakeLists.txt index 1b8e7ed..38b35d7 100644 --- a/lib/Target/XCore/CMakeLists.txt +++ b/lib/Target/XCore/CMakeLists.txt @@ -10,7 +10,7 @@ tablegen(XCoreGenDAGISel.inc -gen-dag-isel) tablegen(XCoreGenCallingConv.inc -gen-callingconv) tablegen(XCoreGenSubtarget.inc -gen-subtarget) -add_llvm_target(XCore +add_llvm_target(XCoreCodeGen XCoreFrameInfo.cpp XCoreInstrInfo.cpp XCoreISelDAGToDAG.cpp diff --git a/lib/Target/XCore/XCoreISelDAGToDAG.cpp b/lib/Target/XCore/XCoreISelDAGToDAG.cpp index 5564ddf..755ece7 100644 --- a/lib/Target/XCore/XCoreISelDAGToDAG.cpp +++ b/lib/Target/XCore/XCoreISelDAGToDAG.cpp @@ -56,6 +56,17 @@ namespace { return CurDAG->getTargetConstant(Imm, MVT::i32); } + inline bool immMskBitp(SDNode *inN) const { + ConstantSDNode *N = cast(inN); + uint32_t value = (uint32_t)N->getZExtValue(); + if (!isMask_32(value)) { + return false; + } + int msksize = 32 - CountLeadingZeros_32(value); + return (msksize >= 1 && msksize <= 8) || + msksize == 16 || msksize == 24 || msksize == 32; + } + // Complex Pattern Selectors. bool SelectADDRspii(SDNode *Op, SDValue Addr, SDValue &Base, SDValue &Offset); @@ -151,17 +162,15 @@ SDNode *XCoreDAGToDAGISel::Select(SDNode *N) { switch (N->getOpcode()) { default: break; case ISD::Constant: { - if (Predicate_immMskBitp(N)) { + uint64_t Val = cast(N)->getZExtValue(); + if (immMskBitp(N)) { // Transformation function: get the size of a mask - int64_t MaskVal = cast(N)->getZExtValue(); - assert(isMask_32(MaskVal)); // Look for the first non-zero bit - SDValue MskSize = getI32Imm(32 - CountLeadingZeros_32(MaskVal)); + SDValue MskSize = getI32Imm(32 - CountLeadingZeros_32(Val)); return CurDAG->getMachineNode(XCore::MKMSK_rus, dl, MVT::i32, MskSize); } - else if (! Predicate_immU16(N)) { - unsigned Val = cast(N)->getZExtValue(); + else if (!isUInt<16>(Val)) { SDValue CPIdx = CurDAG->getTargetConstantPool(ConstantInt::get( Type::getInt32Ty(*CurDAG->getContext()), Val), diff --git a/lib/Target/XCore/XCoreInstrInfo.cpp b/lib/Target/XCore/XCoreInstrInfo.cpp index dd90ea9..ad00046 100644 --- a/lib/Target/XCore/XCoreInstrInfo.cpp +++ b/lib/Target/XCore/XCoreInstrInfo.cpp @@ -46,33 +46,6 @@ static bool isZeroImm(const MachineOperand &op) { return op.isImm() && op.getImm() == 0; } -/// Return true if the instruction is a register to register move and -/// leave the source and dest operands in the passed parameters. -/// -bool XCoreInstrInfo::isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSR, unsigned &DstSR) const { - SrcSR = DstSR = 0; // No sub-registers. - - // We look for 4 kinds of patterns here: - // add dst, src, 0 - // sub dst, src, 0 - // or dst, src, src - // and dst, src, src - if ((MI.getOpcode() == XCore::ADD_2rus || MI.getOpcode() == XCore::SUB_2rus) - && isZeroImm(MI.getOperand(2))) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(1).getReg(); - return true; - } else if ((MI.getOpcode() == XCore::OR_3r || MI.getOpcode() == XCore::AND_3r) - && MI.getOperand(1).getReg() == MI.getOperand(2).getReg()) { - DstReg = MI.getOperand(0).getReg(); - SrcReg = MI.getOperand(1).getReg(); - return true; - } - return false; -} - /// isLoadFromStackSlot - If the specified machine instruction is a direct /// load from a stack slot, return the virtual or physical register number of /// the destination along with the FrameIndex of the loaded stack slot. If @@ -437,7 +410,7 @@ bool XCoreInstrInfo::spillCalleeSavedRegisters(MachineBasicBlock &MBB, it->getFrameIdx(), RC, &RI); if (emitFrameMoves) { MCSymbol *SaveLabel = MF->getContext().CreateTempSymbol(); - BuildMI(MBB, MI, DL, get(XCore::DBG_LABEL)).addSym(SaveLabel); + BuildMI(MBB, MI, DL, get(XCore::PROLOG_LABEL)).addSym(SaveLabel); XFI->getSpillLabels().push_back(std::make_pair(SaveLabel, *it)); } } diff --git a/lib/Target/XCore/XCoreInstrInfo.h b/lib/Target/XCore/XCoreInstrInfo.h index e5b0171..d2b116e 100644 --- a/lib/Target/XCore/XCoreInstrInfo.h +++ b/lib/Target/XCore/XCoreInstrInfo.h @@ -30,12 +30,6 @@ public: /// virtual const TargetRegisterInfo &getRegisterInfo() const { return RI; } - /// Return true if the instruction is a register to register move and return - /// the source and dest operands and their sub-register indices by reference. - virtual bool isMoveInstr(const MachineInstr &MI, - unsigned &SrcReg, unsigned &DstReg, - unsigned &SrcSubIdx, unsigned &DstSubIdx) const; - /// isLoadFromStackSlot - If the specified machine instruction is a direct /// load from a stack slot, return the virtual or physical register number of /// the destination along with the FrameIndex of the loaded stack slot. If diff --git a/lib/Target/XCore/XCoreInstrInfo.td b/lib/Target/XCore/XCoreInstrInfo.td index 19b9b1f..6b3b39b 100644 --- a/lib/Target/XCore/XCoreInstrInfo.td +++ b/lib/Target/XCore/XCoreInstrInfo.td @@ -140,17 +140,7 @@ def immU20 : PatLeaf<(imm), [{ return (uint32_t)N->getZExtValue() < (1 << 20); }]>; -def immMskBitp : PatLeaf<(imm), [{ - uint32_t value = (uint32_t)N->getZExtValue(); - if (!isMask_32(value)) { - return false; - } - int msksize = 32 - CountLeadingZeros_32(value); - return (msksize >= 1 && msksize <= 8) - || msksize == 16 - || msksize == 24 - || msksize == 32; -}]>; +def immMskBitp : PatLeaf<(imm), [{ return immMskBitp(N); }]>; def immBitp : PatLeaf<(imm), [{ uint32_t value = (uint32_t)N->getZExtValue(); diff --git a/lib/Target/XCore/XCoreRegisterInfo.cpp b/lib/Target/XCore/XCoreRegisterInfo.cpp index 2a88342..f82e598 100644 --- a/lib/Target/XCore/XCoreRegisterInfo.cpp +++ b/lib/Target/XCore/XCoreRegisterInfo.cpp @@ -155,10 +155,9 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MBB.erase(I); } -unsigned +void XCoreRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value, - RegScavenger *RS) const { + int SPAdj, RegScavenger *RS) const { assert(SPAdj == 0 && "Unexpected"); MachineInstr &MI = *II; DebugLoc dl = MI.getDebugLoc(); @@ -291,7 +290,6 @@ XCoreRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, } // Erase old instruction. MBB.erase(II); - return 0; } void @@ -420,7 +418,7 @@ void XCoreRegisterInfo::emitPrologue(MachineFunction &MF) const { // Show update of SP. MCSymbol *FrameLabel = MMI->getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, dl, TII.get(XCore::DBG_LABEL)).addSym(FrameLabel); + BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(FrameLabel); MachineLocation SPDst(MachineLocation::VirtualFP); MachineLocation SPSrc(MachineLocation::VirtualFP, -FrameSize * 4); @@ -439,7 +437,7 @@ void XCoreRegisterInfo::emitPrologue(MachineFunction &MF) const { if (emitFrameMoves) { MCSymbol *SaveLRLabel = MMI->getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, dl, TII.get(XCore::DBG_LABEL)).addSym(SaveLRLabel); + BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(SaveLRLabel); MachineLocation CSDst(MachineLocation::VirtualFP, LRSpillOffset); MachineLocation CSSrc(XCore::LR); MMI->getFrameMoves().push_back(MachineMove(SaveLRLabel, CSDst, CSSrc)); @@ -455,7 +453,7 @@ void XCoreRegisterInfo::emitPrologue(MachineFunction &MF) const { MBB.addLiveIn(XCore::R10); if (emitFrameMoves) { MCSymbol *SaveR10Label = MMI->getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, dl, TII.get(XCore::DBG_LABEL)).addSym(SaveR10Label); + BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(SaveR10Label); MachineLocation CSDst(MachineLocation::VirtualFP, FPSpillOffset); MachineLocation CSSrc(XCore::R10); MMI->getFrameMoves().push_back(MachineMove(SaveR10Label, CSDst, CSSrc)); @@ -467,7 +465,7 @@ void XCoreRegisterInfo::emitPrologue(MachineFunction &MF) const { if (emitFrameMoves) { // Show FP is now valid. MCSymbol *FrameLabel = MMI->getContext().CreateTempSymbol(); - BuildMI(MBB, MBBI, dl, TII.get(XCore::DBG_LABEL)).addSym(FrameLabel); + BuildMI(MBB, MBBI, dl, TII.get(XCore::PROLOG_LABEL)).addSym(FrameLabel); MachineLocation SPDst(FramePtr); MachineLocation SPSrc(MachineLocation::VirtualFP); MMI->getFrameMoves().push_back(MachineMove(FrameLabel, SPDst, SPSrc)); diff --git a/lib/Target/XCore/XCoreRegisterInfo.h b/lib/Target/XCore/XCoreRegisterInfo.h index 66132ba..e636c1c 100644 --- a/lib/Target/XCore/XCoreRegisterInfo.h +++ b/lib/Target/XCore/XCoreRegisterInfo.h @@ -54,9 +54,8 @@ public: MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; - unsigned eliminateFrameIndex(MachineBasicBlock::iterator II, - int SPAdj, FrameIndexValue *Value = NULL, - RegScavenger *RS = NULL) const; + void eliminateFrameIndex(MachineBasicBlock::iterator II, + int SPAdj, RegScavenger *RS = NULL) const; void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, RegScavenger *RS = NULL) const; diff --git a/lib/Transforms/Hello/Hello.cpp b/lib/Transforms/Hello/Hello.cpp index abfa514..838d550 100644 --- a/lib/Transforms/Hello/Hello.cpp +++ b/lib/Transforms/Hello/Hello.cpp @@ -25,7 +25,7 @@ namespace { // Hello - The first implementation, without getAnalysisUsage. struct Hello : public FunctionPass { static char ID; // Pass identification, replacement for typeid - Hello() : FunctionPass(&ID) {} + Hello() : FunctionPass(ID) {} virtual bool runOnFunction(Function &F) { ++HelloCounter; @@ -37,13 +37,13 @@ namespace { } char Hello::ID = 0; -static RegisterPass X("hello", "Hello World Pass"); +INITIALIZE_PASS(Hello, "hello", "Hello World Pass", false, false); namespace { // Hello2 - The second implementation with getAnalysisUsage implemented. struct Hello2 : public FunctionPass { static char ID; // Pass identification, replacement for typeid - Hello2() : FunctionPass(&ID) {} + Hello2() : FunctionPass(ID) {} virtual bool runOnFunction(Function &F) { ++HelloCounter; @@ -60,5 +60,6 @@ namespace { } char Hello2::ID = 0; -static RegisterPass -Y("hello2", "Hello World Pass (with getAnalysisUsage implemented)"); +INITIALIZE_PASS(Hello2, "hello2", + "Hello World Pass (with getAnalysisUsage implemented)", + false, false); diff --git a/lib/Transforms/IPO/ArgumentPromotion.cpp b/lib/Transforms/IPO/ArgumentPromotion.cpp index 28ea079..0c77e1f 100644 --- a/lib/Transforms/IPO/ArgumentPromotion.cpp +++ b/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -67,7 +67,7 @@ namespace { virtual bool runOnSCC(CallGraphSCC &SCC); static char ID; // Pass identification, replacement for typeid explicit ArgPromotion(unsigned maxElements = 3) - : CallGraphSCCPass(&ID), maxElements(maxElements) {} + : CallGraphSCCPass(ID), maxElements(maxElements) {} /// A vector used to hold the indices of a single GEP instruction typedef std::vector IndicesVector; @@ -84,8 +84,8 @@ namespace { } char ArgPromotion::ID = 0; -static RegisterPass -X("argpromotion", "Promote 'by reference' arguments to scalars"); +INITIALIZE_PASS(ArgPromotion, "argpromotion", + "Promote 'by reference' arguments to scalars", false, false); Pass *llvm::createArgumentPromotionPass(unsigned maxElements) { return new ArgPromotion(maxElements); @@ -208,8 +208,8 @@ static bool AllCalleesPassInValidPointerForArgument(Argument *Arg) { // have direct callees. for (Value::use_iterator UI = Callee->use_begin(), E = Callee->use_end(); UI != E; ++UI) { - CallSite CS = CallSite::get(*UI); - assert(CS.getInstruction() && "Should only have direct calls!"); + CallSite CS(*UI); + assert(CS && "Should only have direct calls!"); if (!IsAlwaysValidPointer(CS.getArgument(ArgNo))) return false; @@ -619,14 +619,13 @@ CallGraphNode *ArgPromotion::DoPromotion(Function *F, // Get a new callgraph node for NF. CallGraphNode *NF_CGN = CG.getOrInsertFunction(NF); - // Loop over all of the callers of the function, transforming the call sites // to pass in the loaded pointers. // SmallVector Args; while (!F->use_empty()) { - CallSite CS = CallSite::get(F->use_back()); + CallSite CS(F->use_back()); assert(CS.getCalledFunction() == F); Instruction *Call = CS.getInstruction(); const AttrListPtr &CallPAL = CS.getAttributes(); diff --git a/lib/Transforms/IPO/ConstantMerge.cpp b/lib/Transforms/IPO/ConstantMerge.cpp index 3c05f88..64e8d79 100644 --- a/lib/Transforms/IPO/ConstantMerge.cpp +++ b/lib/Transforms/IPO/ConstantMerge.cpp @@ -19,10 +19,12 @@ #define DEBUG_TYPE "constmerge" #include "llvm/Transforms/IPO.h" +#include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Module.h" #include "llvm/Pass.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" using namespace llvm; @@ -31,7 +33,7 @@ STATISTIC(NumMerged, "Number of global constants merged"); namespace { struct ConstantMerge : public ModulePass { static char ID; // Pass identification, replacement for typeid - ConstantMerge() : ModulePass(&ID) {} + ConstantMerge() : ModulePass(ID) {} // run - For this pass, process all of the globals in the module, // eliminating duplicate constants. @@ -41,12 +43,32 @@ namespace { } char ConstantMerge::ID = 0; -static RegisterPass -X("constmerge", "Merge Duplicate Global Constants"); +INITIALIZE_PASS(ConstantMerge, "constmerge", + "Merge Duplicate Global Constants", false, false); ModulePass *llvm::createConstantMergePass() { return new ConstantMerge(); } + + +/// Find values that are marked as llvm.used. +static void FindUsedValues(GlobalVariable *LLVMUsed, + SmallPtrSet &UsedValues) { + if (LLVMUsed == 0) return; + ConstantArray *Inits = dyn_cast(LLVMUsed->getInitializer()); + if (Inits == 0) return; + + for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) + if (GlobalValue *GV = + dyn_cast(Inits->getOperand(i)->stripPointerCasts())) + UsedValues.insert(GV); +} + bool ConstantMerge::runOnModule(Module &M) { + // Find all the globals that are marked "used". These cannot be merged. + SmallPtrSet UsedGlobals; + FindUsedValues(M.getGlobalVariable("llvm.used"), UsedGlobals); + FindUsedValues(M.getGlobalVariable("llvm.compiler.used"), UsedGlobals); + // Map unique constant/section pairs to globals. We don't want to merge // globals in different sections. DenseMap CMap; @@ -79,9 +101,13 @@ bool ConstantMerge::runOnModule(Module &M) { // Only process constants with initializers in the default addres space. if (!GV->isConstant() ||!GV->hasDefinitiveInitializer() || - GV->getType()->getAddressSpace() != 0 || !GV->getSection().empty()) + GV->getType()->getAddressSpace() != 0 || !GV->getSection().empty() || + // Don't touch values marked with attribute(used). + UsedGlobals.count(GV)) continue; + + Constant *Init = GV->getInitializer(); // Check to see if the initializer is already known. diff --git a/lib/Transforms/IPO/DeadArgumentElimination.cpp b/lib/Transforms/IPO/DeadArgumentElimination.cpp index 475eee8..47df235 100644 --- a/lib/Transforms/IPO/DeadArgumentElimination.cpp +++ b/lib/Transforms/IPO/DeadArgumentElimination.cpp @@ -122,11 +122,11 @@ namespace { protected: // DAH uses this to specify a different ID. - explicit DAE(void *ID) : ModulePass(ID) {} + explicit DAE(char &ID) : ModulePass(ID) {} public: static char ID; // Pass identification, replacement for typeid - DAE() : ModulePass(&ID) {} + DAE() : ModulePass(ID) {} bool runOnModule(Module &M); @@ -151,8 +151,7 @@ namespace { char DAE::ID = 0; -static RegisterPass -X("deadargelim", "Dead Argument Elimination"); +INITIALIZE_PASS(DAE, "deadargelim", "Dead Argument Elimination", false, false); namespace { /// DAH - DeadArgumentHacking pass - Same as dead argument elimination, but @@ -160,15 +159,16 @@ namespace { /// by bugpoint. struct DAH : public DAE { static char ID; - DAH() : DAE(&ID) {} + DAH() : DAE(ID) {} virtual bool ShouldHackArguments() const { return true; } }; } char DAH::ID = 0; -static RegisterPass -Y("deadarghaX0r", "Dead Argument Hacking (BUGPOINT USE ONLY; DO NOT USE)"); +INITIALIZE_PASS(DAH, "deadarghaX0r", + "Dead Argument Hacking (BUGPOINT USE ONLY; DO NOT USE)", + false, false); /// createDeadArgEliminationPass - This pass removes arguments from functions /// which are not used by the body of the function. @@ -220,11 +220,11 @@ bool DAE::DeleteDeadVarargs(Function &Fn) { // std::vector Args; while (!Fn.use_empty()) { - CallSite CS = CallSite::get(Fn.use_back()); + CallSite CS(Fn.use_back()); Instruction *Call = CS.getInstruction(); // Pass all the same arguments. - Args.assign(CS.arg_begin(), CS.arg_begin()+NumArgs); + Args.assign(CS.arg_begin(), CS.arg_begin() + NumArgs); // Drop any attributes that were on the vararg arguments. AttrListPtr PAL = CS.getAttributes(); @@ -250,8 +250,7 @@ bool DAE::DeleteDeadVarargs(Function &Fn) { if (cast(Call)->isTailCall()) cast(New)->setTailCall(); } - if (MDNode *N = Call->getDbgMetadata()) - New->setDbgMetadata(N); + New->setDebugLoc(Call->getDebugLoc()); Args.clear(); @@ -725,7 +724,7 @@ bool DAE::RemoveDeadStuffFromFunction(Function *F) { // std::vector Args; while (!F->use_empty()) { - CallSite CS = CallSite::get(F->use_back()); + CallSite CS(F->use_back()); Instruction *Call = CS.getInstruction(); AttributesVec.clear(); @@ -780,8 +779,7 @@ bool DAE::RemoveDeadStuffFromFunction(Function *F) { if (cast(Call)->isTailCall()) cast(New)->setTailCall(); } - if (MDNode *N = Call->getDbgMetadata()) - New->setDbgMetadata(N); + New->setDebugLoc(Call->getDebugLoc()); Args.clear(); diff --git a/lib/Transforms/IPO/DeadTypeElimination.cpp b/lib/Transforms/IPO/DeadTypeElimination.cpp index 662fbb5..5dc50c5 100644 --- a/lib/Transforms/IPO/DeadTypeElimination.cpp +++ b/lib/Transforms/IPO/DeadTypeElimination.cpp @@ -26,7 +26,7 @@ STATISTIC(NumKilled, "Number of unused typenames removed from symtab"); namespace { struct DTE : public ModulePass { static char ID; // Pass identification, replacement for typeid - DTE() : ModulePass(&ID) {} + DTE() : ModulePass(ID) {} // doPassInitialization - For this pass, it removes global symbol table // entries for primitive types. These are never used for linking in GCC and @@ -45,7 +45,7 @@ namespace { } char DTE::ID = 0; -static RegisterPass X("deadtypeelim", "Dead Type Elimination"); +INITIALIZE_PASS(DTE, "deadtypeelim", "Dead Type Elimination", false, false); ModulePass *llvm::createDeadTypeEliminationPass() { return new DTE(); diff --git a/lib/Transforms/IPO/ExtractGV.cpp b/lib/Transforms/IPO/ExtractGV.cpp index 7f67e48..45c5fe7 100644 --- a/lib/Transforms/IPO/ExtractGV.cpp +++ b/lib/Transforms/IPO/ExtractGV.cpp @@ -17,15 +17,15 @@ #include "llvm/Pass.h" #include "llvm/Constants.h" #include "llvm/Transforms/IPO.h" +#include "llvm/ADT/SetVector.h" #include using namespace llvm; namespace { /// @brief A pass to extract specific functions and their dependencies. class GVExtractorPass : public ModulePass { - std::vector Named; + SetVector Named; bool deleteStuff; - bool reLink; public: static char ID; // Pass identification, replacement for typeid @@ -33,135 +33,42 @@ namespace { /// specified function. Otherwise, it deletes as much of the module as /// possible, except for the function specified. /// - explicit GVExtractorPass(std::vector& GVs, bool deleteS = true, - bool relinkCallees = false) - : ModulePass(&ID), Named(GVs), deleteStuff(deleteS), - reLink(relinkCallees) {} + explicit GVExtractorPass(std::vector& GVs, bool deleteS = true) + : ModulePass(ID), Named(GVs.begin(), GVs.end()), deleteStuff(deleteS) {} bool runOnModule(Module &M) { - if (Named.size() == 0) { - return false; // Nothing to extract - } - - - if (deleteStuff) - return deleteGV(); - M.setModuleInlineAsm(""); - return isolateGV(M); - } - - bool deleteGV() { - for (std::vector::iterator GI = Named.begin(), - GE = Named.end(); GI != GE; ++GI) { - if (Function* NamedFunc = dyn_cast(*GI)) { - // If we're in relinking mode, set linkage of all internal callees to - // external. This will allow us extract function, and then - link - // everything together - if (reLink) { - for (Function::iterator B = NamedFunc->begin(), BE = NamedFunc->end(); - B != BE; ++B) { - for (BasicBlock::iterator I = B->begin(), E = B->end(); - I != E; ++I) { - if (CallInst* callInst = dyn_cast(&*I)) { - Function* Callee = callInst->getCalledFunction(); - if (Callee && Callee->hasLocalLinkage()) - Callee->setLinkage(GlobalValue::ExternalLinkage); - } - } - } - } - - NamedFunc->setLinkage(GlobalValue::ExternalLinkage); - NamedFunc->deleteBody(); - assert(NamedFunc->isDeclaration() && "This didn't make the function external!"); - } else { - if (!(*GI)->isDeclaration()) { - cast(*GI)->setInitializer(0); //clear the initializer - (*GI)->setLinkage(GlobalValue::ExternalLinkage); - } - } - } - return true; - } - - bool isolateGV(Module &M) { - // Mark all globals internal - // FIXME: what should we do with private linkage? - for (Module::global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) + // Visit the global inline asm. + if (!deleteStuff) + M.setModuleInlineAsm(""); + + // For simplicity, just give all GlobalValues ExternalLinkage. A trickier + // implementation could figure out which GlobalValues are actually + // referenced by the Named set, and which GlobalValues in the rest of + // the module are referenced by the NamedSet, and get away with leaving + // more internal and private things internal and private. But for now, + // be conservative and simple. + + // Visit the GlobalVariables. + for (Module::global_iterator I = M.global_begin(), E = M.global_end(); + I != E; ++I) if (!I->isDeclaration()) { - I->setLinkage(GlobalValue::InternalLinkage); + if (I->hasLocalLinkage()) + I->setVisibility(GlobalValue::HiddenVisibility); + I->setLinkage(GlobalValue::ExternalLinkage); + if (deleteStuff == Named.count(I)) + I->setInitializer(0); } + + // Visit the Functions. for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) if (!I->isDeclaration()) { - I->setLinkage(GlobalValue::InternalLinkage); - } - - // Make sure our result is globally accessible... - // by putting them in the used array - { - std::vector AUGs; - const Type *SBP= - Type::getInt8PtrTy(M.getContext()); - for (std::vector::iterator GI = Named.begin(), - GE = Named.end(); GI != GE; ++GI) { - (*GI)->setLinkage(GlobalValue::ExternalLinkage); - AUGs.push_back(ConstantExpr::getBitCast(*GI, SBP)); - } - ArrayType *AT = ArrayType::get(SBP, AUGs.size()); - Constant *Init = ConstantArray::get(AT, AUGs); - GlobalValue *gv = new GlobalVariable(M, AT, false, - GlobalValue::AppendingLinkage, - Init, "llvm.used"); - gv->setSection("llvm.metadata"); - } - - // All of the functions may be used by global variables or the named - // globals. Loop through them and create a new, external functions that - // can be "used", instead of ones with bodies. - std::vector NewFunctions; - - Function *Last = --M.end(); // Figure out where the last real fn is. - - for (Module::iterator I = M.begin(); ; ++I) { - if (std::find(Named.begin(), Named.end(), &*I) == Named.end()) { - Function *New = Function::Create(I->getFunctionType(), - GlobalValue::ExternalLinkage); - New->copyAttributesFrom(I); - - // If it's not the named function, delete the body of the function - I->dropAllReferences(); - - M.getFunctionList().push_back(New); - NewFunctions.push_back(New); - New->takeName(I); + if (I->hasLocalLinkage()) + I->setVisibility(GlobalValue::HiddenVisibility); + I->setLinkage(GlobalValue::ExternalLinkage); + if (deleteStuff == Named.count(I)) + I->deleteBody(); } - if (&*I == Last) break; // Stop after processing the last function - } - - // Now that we have replacements all set up, loop through the module, - // deleting the old functions, replacing them with the newly created - // functions. - if (!NewFunctions.empty()) { - unsigned FuncNum = 0; - Module::iterator I = M.begin(); - do { - if (std::find(Named.begin(), Named.end(), &*I) == Named.end()) { - // Make everything that uses the old function use the new dummy fn - I->replaceAllUsesWith(NewFunctions[FuncNum++]); - - Function *Old = I; - ++I; // Move the iterator to the new function - - // Delete the old function! - M.getFunctionList().erase(Old); - - } else { - ++I; // Skip the function we are extracting - } - } while (&*I != NewFunctions[0]); - } - return true; } }; @@ -170,6 +77,6 @@ namespace { } ModulePass *llvm::createGVExtractionPass(std::vector& GVs, - bool deleteFn, bool relinkCallees) { - return new GVExtractorPass(GVs, deleteFn, relinkCallees); + bool deleteFn) { + return new GVExtractorPass(GVs, deleteFn); } diff --git a/lib/Transforms/IPO/FunctionAttrs.cpp b/lib/Transforms/IPO/FunctionAttrs.cpp index 9bd7af6..6165ba0 100644 --- a/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/lib/Transforms/IPO/FunctionAttrs.cpp @@ -41,7 +41,7 @@ STATISTIC(NumNoAlias, "Number of function returns marked noalias"); namespace { struct FunctionAttrs : public CallGraphSCCPass { static char ID; // Pass identification, replacement for typeid - FunctionAttrs() : CallGraphSCCPass(&ID) {} + FunctionAttrs() : CallGraphSCCPass(ID) {} // runOnSCC - Analyze the SCC, performing the transformation if possible. bool runOnSCC(CallGraphSCC &SCC); @@ -69,8 +69,8 @@ namespace { } char FunctionAttrs::ID = 0; -static RegisterPass -X("functionattrs", "Deduce function attributes"); +INITIALIZE_PASS(FunctionAttrs, "functionattrs", + "Deduce function attributes", false, false); Pass *llvm::createFunctionAttrsPass() { return new FunctionAttrs(); } @@ -162,14 +162,14 @@ bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) { // Some instructions can be ignored even if they read or write memory. // Detect these now, skipping to the next instruction if one is found. - CallSite CS = CallSite::get(I); - if (CS.getInstruction() && CS.getCalledFunction()) { + CallSite CS(cast(I)); + if (CS && CS.getCalledFunction()) { // Ignore calls to functions in the same SCC. if (SCCNodes.count(CS.getCalledFunction())) continue; // Ignore intrinsics that only access local memory. if (unsigned id = CS.getCalledFunction()->getIntrinsicID()) - if (AliasAnalysis::getModRefBehavior(id) == + if (AliasAnalysis::getIntrinsicModRefBehavior(id) == AliasAnalysis::AccessesArguments) { // Check that all pointer arguments point to local memory. for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end(); diff --git a/lib/Transforms/IPO/GlobalDCE.cpp b/lib/Transforms/IPO/GlobalDCE.cpp index 44216a6..aa18601 100644 --- a/lib/Transforms/IPO/GlobalDCE.cpp +++ b/lib/Transforms/IPO/GlobalDCE.cpp @@ -31,7 +31,7 @@ STATISTIC(NumVariables, "Number of global variables removed"); namespace { struct GlobalDCE : public ModulePass { static char ID; // Pass identification, replacement for typeid - GlobalDCE() : ModulePass(&ID) {} + GlobalDCE() : ModulePass(ID) {} // run - Do the GlobalDCE pass on the specified module, optionally updating // the specified callgraph to reflect the changes. @@ -51,7 +51,8 @@ namespace { } char GlobalDCE::ID = 0; -static RegisterPass X("globaldce", "Dead Global Elimination"); +INITIALIZE_PASS(GlobalDCE, "globaldce", + "Dead Global Elimination", false, false); ModulePass *llvm::createGlobalDCEPass() { return new GlobalDCE(); } diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index 735a1c4..a77af54 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/lib/Transforms/IPO/GlobalOpt.cpp @@ -59,7 +59,7 @@ namespace { virtual void getAnalysisUsage(AnalysisUsage &AU) const { } static char ID; // Pass identification, replacement for typeid - GlobalOpt() : ModulePass(&ID) {} + GlobalOpt() : ModulePass(ID) {} bool runOnModule(Module &M); @@ -74,7 +74,8 @@ namespace { } char GlobalOpt::ID = 0; -static RegisterPass X("globalopt", "Global Variable Optimizer"); +INITIALIZE_PASS(GlobalOpt, "globalopt", + "Global Variable Optimizer", false, false); ModulePass *llvm::createGlobalOptimizerPass() { return new GlobalOpt(); } @@ -1467,7 +1468,7 @@ static bool TryToOptimizeStoreOfMallocToGlobal(GlobalVariable *GV, TargetData *TD) { if (!TD) return false; - + // If this is a malloc of an abstract type, don't touch it. if (!AllocTy->isSized()) return false; @@ -2077,7 +2078,7 @@ static bool isSimpleEnoughPointerToCommit(Constant *C) { return false; // The first index must be zero. - ConstantInt *CI = dyn_cast(*next(CE->op_begin())); + ConstantInt *CI = dyn_cast(*llvm::next(CE->op_begin())); if (!CI || !CI->isZero()) return false; // The remaining indices must be compile-time known integers within the @@ -2302,7 +2303,8 @@ static bool EvaluateFunction(Function *F, Constant *&RetVal, if (isa(CI->getCalledValue())) return false; // Resolve function pointers. - Function *Callee = dyn_cast(getVal(Values, CI->getCalledValue())); + Function *Callee = dyn_cast(getVal(Values, + CI->getCalledValue())); if (!Callee) return false; // Cannot resolve. SmallVector Formals; diff --git a/lib/Transforms/IPO/IPConstantPropagation.cpp b/lib/Transforms/IPO/IPConstantPropagation.cpp index e4db235..1b3cf78 100644 --- a/lib/Transforms/IPO/IPConstantPropagation.cpp +++ b/lib/Transforms/IPO/IPConstantPropagation.cpp @@ -35,7 +35,7 @@ namespace { /// struct IPCP : public ModulePass { static char ID; // Pass identification, replacement for typeid - IPCP() : ModulePass(&ID) {} + IPCP() : ModulePass(ID) {} bool runOnModule(Module &M); private: @@ -45,8 +45,8 @@ namespace { } char IPCP::ID = 0; -static RegisterPass -X("ipconstprop", "Interprocedural constant propagation"); +INITIALIZE_PASS(IPCP, "ipconstprop", + "Interprocedural constant propagation", false, false); ModulePass *llvm::createIPConstantPropagationPass() { return new IPCP(); } @@ -94,7 +94,7 @@ bool IPCP::PropagateConstantsIntoArguments(Function &F) { if (!isa(U) && !isa(U)) return false; - CallSite CS = CallSite::get(cast(U)); + CallSite CS(cast(U)); if (!CS.isCallee(UI)) return false; @@ -219,7 +219,7 @@ bool IPCP::PropagateConstantReturn(Function &F) { // constant. bool MadeChange = false; for (Value::use_iterator UI = F.use_begin(), E = F.use_end(); UI != E; ++UI) { - CallSite CS = CallSite::get(*UI); + CallSite CS(*UI); Instruction* Call = CS.getInstruction(); // Not a call instruction or a call instruction that's not calling F diff --git a/lib/Transforms/IPO/InlineAlways.cpp b/lib/Transforms/IPO/InlineAlways.cpp index 8e312e7..ecc60ad 100644 --- a/lib/Transforms/IPO/InlineAlways.cpp +++ b/lib/Transforms/IPO/InlineAlways.cpp @@ -36,7 +36,7 @@ namespace { InlineCostAnalyzer CA; public: // Use extremely low threshold. - AlwaysInliner() : Inliner(&ID, -2000000000) {} + AlwaysInliner() : Inliner(ID, -2000000000) {} static char ID; // Pass identification, replacement for typeid InlineCost getInlineCost(CallSite CS) { return CA.getInlineCost(CS, NeverInline); @@ -61,8 +61,8 @@ namespace { } char AlwaysInliner::ID = 0; -static RegisterPass -X("always-inline", "Inliner for always_inline functions"); +INITIALIZE_PASS(AlwaysInliner, "always-inline", + "Inliner for always_inline functions", false, false); Pass *llvm::createAlwaysInlinerPass() { return new AlwaysInliner(); } diff --git a/lib/Transforms/IPO/InlineSimple.cpp b/lib/Transforms/IPO/InlineSimple.cpp index 74b4a1c..9c6637d 100644 --- a/lib/Transforms/IPO/InlineSimple.cpp +++ b/lib/Transforms/IPO/InlineSimple.cpp @@ -33,8 +33,8 @@ namespace { SmallPtrSet NeverInline; InlineCostAnalyzer CA; public: - SimpleInliner() : Inliner(&ID) {} - SimpleInliner(int Threshold) : Inliner(&ID, Threshold) {} + SimpleInliner() : Inliner(ID) {} + SimpleInliner(int Threshold) : Inliner(ID, Threshold) {} static char ID; // Pass identification, replacement for typeid InlineCost getInlineCost(CallSite CS) { return CA.getInlineCost(CS, NeverInline); @@ -56,8 +56,8 @@ namespace { } char SimpleInliner::ID = 0; -static RegisterPass -X("inline", "Function Integration/Inlining"); +INITIALIZE_PASS(SimpleInliner, "inline", + "Function Integration/Inlining", false, false); Pass *llvm::createFunctionInliningPass() { return new SimpleInliner(); } diff --git a/lib/Transforms/IPO/Inliner.cpp b/lib/Transforms/IPO/Inliner.cpp index 9bb01f5..4983e8e 100644 --- a/lib/Transforms/IPO/Inliner.cpp +++ b/lib/Transforms/IPO/Inliner.cpp @@ -48,10 +48,10 @@ HintThreshold("inlinehint-threshold", cl::Hidden, cl::init(325), // Threshold to use when optsize is specified (and there is no -inline-limit). const int OptSizeThreshold = 75; -Inliner::Inliner(void *ID) +Inliner::Inliner(char &ID) : CallGraphSCCPass(ID), InlineThreshold(InlineLimit) {} -Inliner::Inliner(void *ID, int Threshold) +Inliner::Inliner(char &ID, int Threshold) : CallGraphSCCPass(ID), InlineThreshold(Threshold) {} /// getAnalysisUsage - For this class, we declare that we require and preserve @@ -238,11 +238,11 @@ bool Inliner::shouldInline(CallSite CS) { bool someOuterCallWouldNotBeInlined = false; for (Value::use_iterator I = Caller->use_begin(), E =Caller->use_end(); I != E; ++I) { - CallSite CS2 = CallSite::get(*I); + CallSite CS2(*I); // If this isn't a call to Caller (it could be some other sort // of reference) skip it. - if (CS2.getInstruction() == 0 || CS2.getCalledFunction() != Caller) + if (!CS2 || CS2.getCalledFunction() != Caller) continue; InlineCost IC2 = getInlineCost(CS2); @@ -334,10 +334,10 @@ bool Inliner::runOnSCC(CallGraphSCC &SCC) { for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { - CallSite CS = CallSite::get(I); + CallSite CS(cast(I)); // If this isn't a call, or it is a call to an intrinsic, it can // never be inlined. - if (CS.getInstruction() == 0 || isa(I)) + if (!CS || isa(I)) continue; // If this is a direct call to an external function, we can never inline diff --git a/lib/Transforms/IPO/Internalize.cpp b/lib/Transforms/IPO/Internalize.cpp index 47abb7d..a1d919f 100644 --- a/lib/Transforms/IPO/Internalize.cpp +++ b/lib/Transforms/IPO/Internalize.cpp @@ -63,11 +63,11 @@ namespace { } // end anonymous namespace char InternalizePass::ID = 0; -static RegisterPass -X("internalize", "Internalize Global Symbols"); +INITIALIZE_PASS(InternalizePass, "internalize", + "Internalize Global Symbols", false, false); InternalizePass::InternalizePass(bool AllButMain) - : ModulePass(&ID), AllButMain(AllButMain){ + : ModulePass(ID), AllButMain(AllButMain){ if (!APIFile.empty()) // If a filename is specified, use it. LoadFile(APIFile.c_str()); if (!APIList.empty()) // If a list is specified, use it as well. @@ -75,7 +75,7 @@ InternalizePass::InternalizePass(bool AllButMain) } InternalizePass::InternalizePass(const std::vector&exportList) - : ModulePass(&ID), AllButMain(false){ + : ModulePass(ID), AllButMain(false){ for(std::vector::const_iterator itr = exportList.begin(); itr != exportList.end(); itr++) { ExternalNames.insert(*itr); diff --git a/lib/Transforms/IPO/LoopExtractor.cpp b/lib/Transforms/IPO/LoopExtractor.cpp index cb81330..f88dff6 100644 --- a/lib/Transforms/IPO/LoopExtractor.cpp +++ b/lib/Transforms/IPO/LoopExtractor.cpp @@ -37,7 +37,7 @@ namespace { unsigned NumLoops; explicit LoopExtractor(unsigned numLoops = ~0) - : LoopPass(&ID), NumLoops(numLoops) {} + : LoopPass(ID), NumLoops(numLoops) {} virtual bool runOnLoop(Loop *L, LPPassManager &LPM); @@ -50,8 +50,8 @@ namespace { } char LoopExtractor::ID = 0; -static RegisterPass -X("loop-extract", "Extract loops into new functions"); +INITIALIZE_PASS(LoopExtractor, "loop-extract", + "Extract loops into new functions", false, false); namespace { /// SingleLoopExtractor - For bugpoint. @@ -62,8 +62,8 @@ namespace { } // End anonymous namespace char SingleLoopExtractor::ID = 0; -static RegisterPass -Y("loop-extract-single", "Extract at most one loop into a new function"); +INITIALIZE_PASS(SingleLoopExtractor, "loop-extract-single", + "Extract at most one loop into a new function", false, false); // createLoopExtractorPass - This pass extracts all natural loops from the // program into a function if it can. @@ -147,27 +147,26 @@ namespace { std::vector > BlocksToNotExtractByName; public: static char ID; // Pass identification, replacement for typeid - explicit BlockExtractorPass(const std::vector &B) - : ModulePass(&ID), BlocksToNotExtract(B) { + BlockExtractorPass() : ModulePass(ID) { if (!BlockFile.empty()) LoadFile(BlockFile.c_str()); } - BlockExtractorPass() : ModulePass(&ID) {} bool runOnModule(Module &M); }; } char BlockExtractorPass::ID = 0; -static RegisterPass -XX("extract-blocks", "Extract Basic Blocks From Module (for bugpoint use)"); +INITIALIZE_PASS(BlockExtractorPass, "extract-blocks", + "Extract Basic Blocks From Module (for bugpoint use)", + false, false); // createBlockExtractorPass - This pass extracts all blocks (except those // specified in the argument list) from the functions in the module. // -ModulePass *llvm::createBlockExtractorPass(const std::vector &BTNE) +ModulePass *llvm::createBlockExtractorPass() { - return new BlockExtractorPass(BTNE); + return new BlockExtractorPass(); } void BlockExtractorPass::LoadFile(const char *Filename) { diff --git a/lib/Transforms/IPO/LowerSetJmp.cpp b/lib/Transforms/IPO/LowerSetJmp.cpp index 76cfef8..6c715de 100644 --- a/lib/Transforms/IPO/LowerSetJmp.cpp +++ b/lib/Transforms/IPO/LowerSetJmp.cpp @@ -109,7 +109,7 @@ namespace { bool IsTransformableFunction(StringRef Name); public: static char ID; // Pass identification, replacement for typeid - LowerSetJmp() : ModulePass(&ID) {} + LowerSetJmp() : ModulePass(ID) {} void visitCallInst(CallInst& CI); void visitInvokeInst(InvokeInst& II); @@ -122,7 +122,7 @@ namespace { } // end anonymous namespace char LowerSetJmp::ID = 0; -static RegisterPass X("lowersetjmp", "Lower Set Jump"); +INITIALIZE_PASS(LowerSetJmp, "lowersetjmp", "Lower Set Jump", false, false); // run - Run the transformation on the program. We grab the function // prototypes for longjmp and setjmp. If they are used in the program, diff --git a/lib/Transforms/IPO/MergeFunctions.cpp b/lib/Transforms/IPO/MergeFunctions.cpp index aeeafe7..5d838f9 100644 --- a/lib/Transforms/IPO/MergeFunctions.cpp +++ b/lib/Transforms/IPO/MergeFunctions.cpp @@ -29,44 +29,27 @@ // // Many functions have their address taken by the virtual function table for // the object they belong to. However, as long as it's only used for a lookup -// and call, this is irrelevant, and we'd like to fold such implementations. +// and call, this is irrelevant, and we'd like to fold such functions. // -// * use SCC to cut down on pair-wise comparisons and solve larger cycles. +// * switch from n^2 pair-wise comparisons to an n-way comparison for each +// bucket. // -// The current implementation loops over a pair-wise comparison of all -// functions in the program where the two functions in the pair are treated as -// assumed to be equal until proven otherwise. We could both use fewer -// comparisons and optimize more complex cases if we used strongly connected -// components of the call graph. -// -// * be smarter about bitcast. +// * be smarter about bitcasts. // // In order to fold functions, we will sometimes add either bitcast instructions // or bitcast constant expressions. Unfortunately, this can confound further // analysis since the two functions differ where one has a bitcast and the -// other doesn't. We should learn to peer through bitcasts without imposing bad -// performance properties. -// -// * don't emit aliases for Mach-O. -// -// Mach-O doesn't support aliases which means that we must avoid introducing -// them in the bitcode on architectures which don't support them, such as -// Mac OSX. There's a few approaches to this problem; -// a) teach codegen to lower global aliases to thunks on platforms which don't -// support them. -// b) always emit thunks, and create a separate thunk-to-alias pass which -// runs on ELF systems. This has the added benefit of transforming other -// thunks such as those produced by a C++ frontend into aliases when legal -// to do so. +// other doesn't. We should learn to look through bitcasts. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "mergefunc" #include "llvm/Transforms/IPO.h" -#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Constants.h" #include "llvm/InlineAsm.h" #include "llvm/Instructions.h" @@ -76,68 +59,103 @@ #include "llvm/Support/CallSite.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/IRBuilder.h" +#include "llvm/Support/ValueHandle.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetData.h" -#include #include using namespace llvm; STATISTIC(NumFunctionsMerged, "Number of functions merged"); namespace { + /// MergeFunctions finds functions which will generate identical machine code, + /// by considering all pointer types to be equivalent. Once identified, + /// MergeFunctions will fold them by replacing a call to one to a call to a + /// bitcast of the other. + /// class MergeFunctions : public ModulePass { public: - static char ID; // Pass identification, replacement for typeid - MergeFunctions() : ModulePass(&ID) {} + static char ID; + MergeFunctions() : ModulePass(ID) {} bool runOnModule(Module &M); private: - bool isEquivalentGEP(const GetElementPtrInst *GEP1, - const GetElementPtrInst *GEP2); - - bool equals(const BasicBlock *BB1, const BasicBlock *BB2); - bool equals(const Function *F, const Function *G); + /// MergeTwoFunctions - Merge two equivalent functions. Upon completion, G + /// may be deleted, or may be converted into a thunk. In either case, it + /// should never be visited again. + void MergeTwoFunctions(Function *F, Function *G) const; - bool compare(const Value *V1, const Value *V2); + /// WriteThunk - Replace G with a simple tail call to bitcast(F). Also + /// replace direct uses of G with bitcast(F). + void WriteThunk(Function *F, Function *G) const; - const Function *LHS, *RHS; - typedef DenseMap IDMap; - IDMap Map; - DenseMap Domains; - DenseMap DomainCount; TargetData *TD; }; } char MergeFunctions::ID = 0; -static RegisterPass X("mergefunc", "Merge Functions"); +INITIALIZE_PASS(MergeFunctions, "mergefunc", "Merge Functions", false, false); ModulePass *llvm::createMergeFunctionsPass() { return new MergeFunctions(); } -// ===----------------------------------------------------------------------=== -// Comparison of functions -// ===----------------------------------------------------------------------=== +namespace { +/// FunctionComparator - Compares two functions to determine whether or not +/// they will generate machine code with the same behaviour. TargetData is +/// used if available. The comparator always fails conservatively (erring on the +/// side of claiming that two functions are different). +class FunctionComparator { +public: + FunctionComparator(const TargetData *TD, const Function *F1, + const Function *F2) + : F1(F1), F2(F2), TD(TD), IDMap1Count(0), IDMap2Count(0) {} + + /// Compare - test whether the two functions have equivalent behaviour. + bool Compare(); + +private: + /// Compare - test whether two basic blocks have equivalent behaviour. + bool Compare(const BasicBlock *BB1, const BasicBlock *BB2); + + /// Enumerate - Assign or look up previously assigned numbers for the two + /// values, and return whether the numbers are equal. Numbers are assigned in + /// the order visited. + bool Enumerate(const Value *V1, const Value *V2); + + /// isEquivalentOperation - Compare two Instructions for equivalence, similar + /// to Instruction::isSameOperationAs but with modifications to the type + /// comparison. + bool isEquivalentOperation(const Instruction *I1, + const Instruction *I2) const; + + /// isEquivalentGEP - Compare two GEPs for equivalent pointer arithmetic. + bool isEquivalentGEP(const GEPOperator *GEP1, const GEPOperator *GEP2); + bool isEquivalentGEP(const GetElementPtrInst *GEP1, + const GetElementPtrInst *GEP2) { + return isEquivalentGEP(cast(GEP1), cast(GEP2)); + } -static unsigned long hash(const Function *F) { - const FunctionType *FTy = F->getFunctionType(); + /// isEquivalentType - Compare two Types, treating all pointer types as equal. + bool isEquivalentType(const Type *Ty1, const Type *Ty2) const; - FoldingSetNodeID ID; - ID.AddInteger(F->size()); - ID.AddInteger(F->getCallingConv()); - ID.AddBoolean(F->hasGC()); - ID.AddBoolean(FTy->isVarArg()); - ID.AddInteger(FTy->getReturnType()->getTypeID()); - for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) - ID.AddInteger(FTy->getParamType(i)->getTypeID()); - return ID.ComputeHash(); + // The two functions undergoing comparison. + const Function *F1, *F2; + + const TargetData *TD; + + typedef DenseMap IDMap; + IDMap Map1, Map2; + unsigned long IDMap1Count, IDMap2Count; +}; } -/// isEquivalentType - any two pointers are equivalent. Otherwise, standard -/// type equivalence rules apply. -static bool isEquivalentType(const Type *Ty1, const Type *Ty2) { +/// isEquivalentType - any two pointers in the same address space are +/// equivalent. Otherwise, standard type equivalence rules apply. +bool FunctionComparator::isEquivalentType(const Type *Ty1, + const Type *Ty2) const { if (Ty1 == Ty2) return true; if (Ty1->getTypeID() != Ty2->getTypeID()) @@ -184,21 +202,6 @@ static bool isEquivalentType(const Type *Ty1, const Type *Ty2) { return true; } - case Type::UnionTyID: { - const UnionType *UTy1 = cast(Ty1); - const UnionType *UTy2 = cast(Ty2); - - // TODO: we could be fancy with union(A, union(A, B)) === union(A, B), etc. - if (UTy1->getNumElements() != UTy2->getNumElements()) - return false; - - for (unsigned i = 0, e = UTy1->getNumElements(); i != e; ++i) { - if (!isEquivalentType(UTy1->getElementType(i), UTy2->getElementType(i))) - return false; - } - return true; - } - case Type::FunctionTyID: { const FunctionType *FTy1 = cast(Ty1); const FunctionType *FTy2 = cast(Ty2); @@ -216,11 +219,18 @@ static bool isEquivalentType(const Type *Ty1, const Type *Ty2) { return true; } - case Type::ArrayTyID: + case Type::ArrayTyID: { + const ArrayType *ATy1 = cast(Ty1); + const ArrayType *ATy2 = cast(Ty2); + return ATy1->getNumElements() == ATy2->getNumElements() && + isEquivalentType(ATy1->getElementType(), ATy2->getElementType()); + } + case Type::VectorTyID: { - const SequentialType *STy1 = cast(Ty1); - const SequentialType *STy2 = cast(Ty2); - return isEquivalentType(STy1->getElementType(), STy2->getElementType()); + const VectorType *VTy1 = cast(Ty1); + const VectorType *VTy2 = cast(Ty2); + return VTy1->getNumElements() == VTy2->getNumElements() && + isEquivalentType(VTy1->getElementType(), VTy2->getElementType()); } } } @@ -228,8 +238,8 @@ static bool isEquivalentType(const Type *Ty1, const Type *Ty2) { /// isEquivalentOperation - determine whether the two operations are the same /// except that pointer-to-A and pointer-to-B are equivalent. This should be /// kept in sync with Instruction::isSameOperationAs. -static bool -isEquivalentOperation(const Instruction *I1, const Instruction *I2) { +bool FunctionComparator::isEquivalentOperation(const Instruction *I1, + const Instruction *I2) const { if (I1->getOpcode() != I2->getOpcode() || I1->getNumOperands() != I2->getNumOperands() || !isEquivalentType(I1->getType(), I2->getType()) || @@ -281,18 +291,15 @@ isEquivalentOperation(const Instruction *I1, const Instruction *I2) { return true; } -bool MergeFunctions::isEquivalentGEP(const GetElementPtrInst *GEP1, - const GetElementPtrInst *GEP2) { +/// isEquivalentGEP - determine whether two GEP operations perform the same +/// underlying arithmetic. +bool FunctionComparator::isEquivalentGEP(const GEPOperator *GEP1, + const GEPOperator *GEP2) { + // When we have target data, we can reduce the GEP down to the value in bytes + // added to the address. if (TD && GEP1->hasAllConstantIndices() && GEP2->hasAllConstantIndices()) { - SmallVector Indices1, Indices2; - for (GetElementPtrInst::const_op_iterator I = GEP1->idx_begin(), - E = GEP1->idx_end(); I != E; ++I) { - Indices1.push_back(*I); - } - for (GetElementPtrInst::const_op_iterator I = GEP2->idx_begin(), - E = GEP2->idx_end(); I != E; ++I) { - Indices2.push_back(*I); - } + SmallVector Indices1(GEP1->idx_begin(), GEP1->idx_end()); + SmallVector Indices2(GEP2->idx_begin(), GEP2->idx_end()); uint64_t Offset1 = TD->getIndexedOffset(GEP1->getPointerOperandType(), Indices1.data(), Indices1.size()); uint64_t Offset2 = TD->getIndexedOffset(GEP2->getPointerOperandType(), @@ -300,7 +307,6 @@ bool MergeFunctions::isEquivalentGEP(const GetElementPtrInst *GEP1, return Offset1 == Offset2; } - // Equivalent types aren't enough. if (GEP1->getPointerOperand()->getType() != GEP2->getPointerOperand()->getType()) return false; @@ -309,19 +315,26 @@ bool MergeFunctions::isEquivalentGEP(const GetElementPtrInst *GEP1, return false; for (unsigned i = 0, e = GEP1->getNumOperands(); i != e; ++i) { - if (!compare(GEP1->getOperand(i), GEP2->getOperand(i))) + if (!Enumerate(GEP1->getOperand(i), GEP2->getOperand(i))) return false; } return true; } -bool MergeFunctions::compare(const Value *V1, const Value *V2) { - if (V1 == LHS || V1 == RHS) - if (V2 == LHS || V2 == RHS) - return true; +/// Enumerate - Compare two values used by the two functions under pair-wise +/// comparison. If this is the first time the values are seen, they're added to +/// the mapping so that we will detect mismatches on next use. +bool FunctionComparator::Enumerate(const Value *V1, const Value *V2) { + // Check for function @f1 referring to itself and function @f2 referring to + // itself, or referring to each other, or both referring to either of them. + // They're all equivalent if the two functions are otherwise equivalent. + if (V1 == F1 && V2 == F2) + return true; + if (V1 == F2 && V2 == F1) + return true; - // TODO: constant expressions in terms of LHS and RHS + // TODO: constant expressions with GEP or references to F1 or F2. if (isa(V1)) return V1 == V2; @@ -332,228 +345,138 @@ bool MergeFunctions::compare(const Value *V1, const Value *V2) { IA1->getConstraintString() == IA2->getConstraintString(); } - // We enumerate constants globally and arguments, basic blocks or - // instructions within the function they belong to. - const Function *Domain1 = NULL; - if (const Argument *A = dyn_cast(V1)) { - Domain1 = A->getParent(); - } else if (const BasicBlock *BB = dyn_cast(V1)) { - Domain1 = BB->getParent(); - } else if (const Instruction *I = dyn_cast(V1)) { - Domain1 = I->getParent()->getParent(); - } - - const Function *Domain2 = NULL; - if (const Argument *A = dyn_cast(V2)) { - Domain2 = A->getParent(); - } else if (const BasicBlock *BB = dyn_cast(V2)) { - Domain2 = BB->getParent(); - } else if (const Instruction *I = dyn_cast(V2)) { - Domain2 = I->getParent()->getParent(); - } - - if (Domain1 != Domain2) - if (Domain1 != LHS && Domain1 != RHS) - if (Domain2 != LHS && Domain2 != RHS) - return false; - - IDMap &Map1 = Domains[Domain1]; unsigned long &ID1 = Map1[V1]; if (!ID1) - ID1 = ++DomainCount[Domain1]; + ID1 = ++IDMap1Count; - IDMap &Map2 = Domains[Domain2]; unsigned long &ID2 = Map2[V2]; if (!ID2) - ID2 = ++DomainCount[Domain2]; + ID2 = ++IDMap2Count; return ID1 == ID2; } -bool MergeFunctions::equals(const BasicBlock *BB1, const BasicBlock *BB2) { - BasicBlock::const_iterator FI = BB1->begin(), FE = BB1->end(); - BasicBlock::const_iterator GI = BB2->begin(), GE = BB2->end(); +/// Compare - test whether two basic blocks have equivalent behaviour. +bool FunctionComparator::Compare(const BasicBlock *BB1, const BasicBlock *BB2) { + BasicBlock::const_iterator F1I = BB1->begin(), F1E = BB1->end(); + BasicBlock::const_iterator F2I = BB2->begin(), F2E = BB2->end(); do { - if (!compare(FI, GI)) + if (!Enumerate(F1I, F2I)) return false; - if (isa(FI) && isa(GI)) { - const GetElementPtrInst *GEP1 = cast(FI); - const GetElementPtrInst *GEP2 = cast(GI); + if (const GetElementPtrInst *GEP1 = dyn_cast(F1I)) { + const GetElementPtrInst *GEP2 = dyn_cast(F2I); + if (!GEP2) + return false; - if (!compare(GEP1->getPointerOperand(), GEP2->getPointerOperand())) + if (!Enumerate(GEP1->getPointerOperand(), GEP2->getPointerOperand())) return false; if (!isEquivalentGEP(GEP1, GEP2)) return false; } else { - if (!isEquivalentOperation(FI, GI)) + if (!isEquivalentOperation(F1I, F2I)) return false; - for (unsigned i = 0, e = FI->getNumOperands(); i != e; ++i) { - Value *OpF = FI->getOperand(i); - Value *OpG = GI->getOperand(i); + assert(F1I->getNumOperands() == F2I->getNumOperands()); + for (unsigned i = 0, e = F1I->getNumOperands(); i != e; ++i) { + Value *OpF1 = F1I->getOperand(i); + Value *OpF2 = F2I->getOperand(i); - if (!compare(OpF, OpG)) + if (!Enumerate(OpF1, OpF2)) return false; - if (OpF->getValueID() != OpG->getValueID() || - !isEquivalentType(OpF->getType(), OpG->getType())) + if (OpF1->getValueID() != OpF2->getValueID() || + !isEquivalentType(OpF1->getType(), OpF2->getType())) return false; } } - ++FI, ++GI; - } while (FI != FE && GI != GE); + ++F1I, ++F2I; + } while (F1I != F1E && F2I != F2E); - return FI == FE && GI == GE; + return F1I == F1E && F2I == F2E; } -bool MergeFunctions::equals(const Function *F, const Function *G) { +/// Compare - test whether the two functions have equivalent behaviour. +bool FunctionComparator::Compare() { // We need to recheck everything, but check the things that weren't included // in the hash first. - if (F->getAttributes() != G->getAttributes()) + if (F1->getAttributes() != F2->getAttributes()) return false; - if (F->hasGC() != G->hasGC()) + if (F1->hasGC() != F2->hasGC()) return false; - if (F->hasGC() && F->getGC() != G->getGC()) + if (F1->hasGC() && F1->getGC() != F2->getGC()) return false; - if (F->hasSection() != G->hasSection()) + if (F1->hasSection() != F2->hasSection()) return false; - if (F->hasSection() && F->getSection() != G->getSection()) + if (F1->hasSection() && F1->getSection() != F2->getSection()) return false; - if (F->isVarArg() != G->isVarArg()) + if (F1->isVarArg() != F2->isVarArg()) return false; // TODO: if it's internal and only used in direct calls, we could handle this // case too. - if (F->getCallingConv() != G->getCallingConv()) + if (F1->getCallingConv() != F2->getCallingConv()) return false; - if (!isEquivalentType(F->getFunctionType(), G->getFunctionType())) + if (!isEquivalentType(F1->getFunctionType(), F2->getFunctionType())) return false; - assert(F->arg_size() == G->arg_size() && + assert(F1->arg_size() == F2->arg_size() && "Identical functions have a different number of args."); - LHS = F; - RHS = G; - // Visit the arguments so that they get enumerated in the order they're // passed in. - for (Function::const_arg_iterator fi = F->arg_begin(), gi = G->arg_begin(), - fe = F->arg_end(); fi != fe; ++fi, ++gi) { - if (!compare(fi, gi)) + for (Function::const_arg_iterator f1i = F1->arg_begin(), + f2i = F2->arg_begin(), f1e = F1->arg_end(); f1i != f1e; ++f1i, ++f2i) { + if (!Enumerate(f1i, f2i)) llvm_unreachable("Arguments repeat"); } - SmallVector FBBs, GBBs; - SmallSet VisitedBBs; // in terms of F. - FBBs.push_back(&F->getEntryBlock()); - GBBs.push_back(&G->getEntryBlock()); - VisitedBBs.insert(FBBs[0]); - while (!FBBs.empty()) { - const BasicBlock *FBB = FBBs.pop_back_val(); - const BasicBlock *GBB = GBBs.pop_back_val(); - if (!compare(FBB, GBB) || !equals(FBB, GBB)) { - Domains.clear(); - DomainCount.clear(); - return false; - } - const TerminatorInst *FTI = FBB->getTerminator(); - const TerminatorInst *GTI = GBB->getTerminator(); - assert(FTI->getNumSuccessors() == GTI->getNumSuccessors()); - for (unsigned i = 0, e = FTI->getNumSuccessors(); i != e; ++i) { - if (!VisitedBBs.insert(FTI->getSuccessor(i))) - continue; - FBBs.push_back(FTI->getSuccessor(i)); - GBBs.push_back(GTI->getSuccessor(i)); - } - } + // We do a CFG-ordered walk since the actual ordering of the blocks in the + // linked list is immaterial. Our walk starts at the entry block for both + // functions, then takes each block from each terminator in order. As an + // artifact, this also means that unreachable blocks are ignored. + SmallVector F1BBs, F2BBs; + SmallSet VisitedBBs; // in terms of F1. - Domains.clear(); - DomainCount.clear(); - return true; -} + F1BBs.push_back(&F1->getEntryBlock()); + F2BBs.push_back(&F2->getEntryBlock()); -// ===----------------------------------------------------------------------=== -// Folding of functions -// ===----------------------------------------------------------------------=== - -// Cases: -// * F is external strong, G is external strong: -// turn G into a thunk to F (1) -// * F is external strong, G is external weak: -// turn G into a thunk to F (1) -// * F is external weak, G is external weak: -// unfoldable -// * F is external strong, G is internal: -// address of G taken: -// turn G into a thunk to F (1) -// address of G not taken: -// make G an alias to F (2) -// * F is internal, G is external weak -// address of F is taken: -// turn G into a thunk to F (1) -// address of F is not taken: -// make G an alias of F (2) -// * F is internal, G is internal: -// address of F and G are taken: -// turn G into a thunk to F (1) -// address of G is not taken: -// make G an alias to F (2) -// -// alias requires linkage == (external,local,weak) fallback to creating a thunk -// external means 'externally visible' linkage != (internal,private) -// internal means linkage == (internal,private) -// weak means linkage mayBeOverridable -// being external implies that the address is taken -// -// 1. turn G into a thunk to F -// 2. make G an alias to F + VisitedBBs.insert(F1BBs[0]); + while (!F1BBs.empty()) { + const BasicBlock *F1BB = F1BBs.pop_back_val(); + const BasicBlock *F2BB = F2BBs.pop_back_val(); -enum LinkageCategory { - ExternalStrong, - ExternalWeak, - Internal -}; + if (!Enumerate(F1BB, F2BB) || !Compare(F1BB, F2BB)) + return false; -static LinkageCategory categorize(const Function *F) { - switch (F->getLinkage()) { - case GlobalValue::InternalLinkage: - case GlobalValue::PrivateLinkage: - case GlobalValue::LinkerPrivateLinkage: - return Internal; - - case GlobalValue::WeakAnyLinkage: - case GlobalValue::WeakODRLinkage: - case GlobalValue::ExternalWeakLinkage: - case GlobalValue::LinkerPrivateWeakLinkage: - return ExternalWeak; - - case GlobalValue::ExternalLinkage: - case GlobalValue::AvailableExternallyLinkage: - case GlobalValue::LinkOnceAnyLinkage: - case GlobalValue::LinkOnceODRLinkage: - case GlobalValue::AppendingLinkage: - case GlobalValue::DLLImportLinkage: - case GlobalValue::DLLExportLinkage: - case GlobalValue::CommonLinkage: - return ExternalStrong; - } + const TerminatorInst *F1TI = F1BB->getTerminator(); + const TerminatorInst *F2TI = F2BB->getTerminator(); - llvm_unreachable("Unknown LinkageType."); - return ExternalWeak; + assert(F1TI->getNumSuccessors() == F2TI->getNumSuccessors()); + for (unsigned i = 0, e = F1TI->getNumSuccessors(); i != e; ++i) { + if (!VisitedBBs.insert(F1TI->getSuccessor(i))) + continue; + + F1BBs.push_back(F1TI->getSuccessor(i)); + F2BBs.push_back(F2TI->getSuccessor(i)); + } + } + return true; } -static void ThunkGToF(Function *F, Function *G) { +/// WriteThunk - Replace G with a simple tail call to bitcast(F). Also replace +/// direct uses of G with bitcast(F). +void MergeFunctions::WriteThunk(Function *F, Function *G) const { if (!G->mayBeOverridden()) { // Redirect direct callers of G to F. Constant *BitcastF = ConstantExpr::getBitCast(F, G->getType()); @@ -567,33 +490,34 @@ static void ThunkGToF(Function *F, Function *G) { } } + // If G was internal then we may have replaced all uses if G with F. If so, + // stop here and delete G. There's no need for a thunk. + if (G->hasLocalLinkage() && G->use_empty()) { + G->eraseFromParent(); + return; + } + Function *NewG = Function::Create(G->getFunctionType(), G->getLinkage(), "", G->getParent()); BasicBlock *BB = BasicBlock::Create(F->getContext(), "", NewG); + IRBuilder Builder(BB); SmallVector Args; unsigned i = 0; const FunctionType *FFTy = F->getFunctionType(); for (Function::arg_iterator AI = NewG->arg_begin(), AE = NewG->arg_end(); AI != AE; ++AI) { - if (FFTy->getParamType(i) == AI->getType()) { - Args.push_back(AI); - } else { - Args.push_back(new BitCastInst(AI, FFTy->getParamType(i), "", BB)); - } + Args.push_back(Builder.CreateBitCast(AI, FFTy->getParamType(i))); ++i; } - CallInst *CI = CallInst::Create(F, Args.begin(), Args.end(), "", BB); + CallInst *CI = Builder.CreateCall(F, Args.begin(), Args.end()); CI->setTailCall(); CI->setCallingConv(F->getCallingConv()); if (NewG->getReturnType()->isVoidTy()) { - ReturnInst::Create(F->getContext(), BB); - } else if (CI->getType() != NewG->getReturnType()) { - Value *BCI = new BitCastInst(CI, NewG->getReturnType(), "", BB); - ReturnInst::Create(F->getContext(), BCI, BB); + Builder.CreateRetVoid(); } else { - ReturnInst::Create(F->getContext(), CI, BB); + Builder.CreateRet(Builder.CreateBitCast(CI, NewG->getReturnType())); } NewG->copyAttributesFrom(G); @@ -602,152 +526,126 @@ static void ThunkGToF(Function *F, Function *G) { G->eraseFromParent(); } -static void AliasGToF(Function *F, Function *G) { - // Darwin will trigger llvm_unreachable if asked to codegen an alias. - return ThunkGToF(F, G); - -#if 0 - if (!G->hasExternalLinkage() && !G->hasLocalLinkage() && !G->hasWeakLinkage()) - return ThunkGToF(F, G); - - GlobalAlias *GA = new GlobalAlias( - G->getType(), G->getLinkage(), "", - ConstantExpr::getBitCast(F, G->getType()), G->getParent()); - F->setAlignment(std::max(F->getAlignment(), G->getAlignment())); - GA->takeName(G); - GA->setVisibility(G->getVisibility()); - G->replaceAllUsesWith(GA); - G->eraseFromParent(); -#endif -} - -static bool fold(std::vector &FnVec, unsigned i, unsigned j) { - Function *F = FnVec[i]; - Function *G = FnVec[j]; - - LinkageCategory catF = categorize(F); - LinkageCategory catG = categorize(G); - - if (catF == ExternalWeak || (catF == Internal && catG == ExternalStrong)) { - std::swap(FnVec[i], FnVec[j]); - std::swap(F, G); - std::swap(catF, catG); - } - - switch (catF) { - case ExternalStrong: - switch (catG) { - case ExternalStrong: - case ExternalWeak: - ThunkGToF(F, G); - break; - case Internal: - if (G->hasAddressTaken()) - ThunkGToF(F, G); - else - AliasGToF(F, G); - break; - } - break; - - case ExternalWeak: { - assert(catG == ExternalWeak); +/// MergeTwoFunctions - Merge two equivalent functions. Upon completion, +/// Function G is deleted. +void MergeFunctions::MergeTwoFunctions(Function *F, Function *G) const { + if (F->isWeakForLinker()) { + assert(G->isWeakForLinker()); // Make them both thunks to the same internal function. - F->setAlignment(std::max(F->getAlignment(), G->getAlignment())); Function *H = Function::Create(F->getFunctionType(), F->getLinkage(), "", F->getParent()); H->copyAttributesFrom(F); H->takeName(F); F->replaceAllUsesWith(H); - ThunkGToF(F, G); - ThunkGToF(F, H); + unsigned MaxAlignment = std::max(G->getAlignment(), H->getAlignment()); - F->setLinkage(GlobalValue::InternalLinkage); - } break; - - case Internal: - switch (catG) { - case ExternalStrong: - llvm_unreachable(0); - // fall-through - case ExternalWeak: - if (F->hasAddressTaken()) - ThunkGToF(F, G); - else - AliasGToF(F, G); - break; - case Internal: { - bool addrTakenF = F->hasAddressTaken(); - bool addrTakenG = G->hasAddressTaken(); - if (!addrTakenF && addrTakenG) { - std::swap(FnVec[i], FnVec[j]); - std::swap(F, G); - std::swap(addrTakenF, addrTakenG); - } + WriteThunk(F, G); + WriteThunk(F, H); - if (addrTakenF && addrTakenG) { - ThunkGToF(F, G); - } else { - assert(!addrTakenG); - AliasGToF(F, G); - } - } break; - } break; + F->setAlignment(MaxAlignment); + F->setLinkage(GlobalValue::InternalLinkage); + } else { + WriteThunk(F, G); } ++NumFunctionsMerged; - return true; } -// ===----------------------------------------------------------------------=== -// Pass definition -// ===----------------------------------------------------------------------=== +static unsigned ProfileFunction(const Function *F) { + const FunctionType *FTy = F->getFunctionType(); -bool MergeFunctions::runOnModule(Module &M) { - bool Changed = false; + FoldingSetNodeID ID; + ID.AddInteger(F->size()); + ID.AddInteger(F->getCallingConv()); + ID.AddBoolean(F->hasGC()); + ID.AddBoolean(FTy->isVarArg()); + ID.AddInteger(FTy->getReturnType()->getTypeID()); + for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i) + ID.AddInteger(FTy->getParamType(i)->getTypeID()); + return ID.ComputeHash(); +} - std::map > FnMap; +class ComparableFunction { +public: + ComparableFunction(Function *Func, TargetData *TD) + : Func(Func), Hash(ProfileFunction(Func)), TD(TD) {} - for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { - if (F->isDeclaration()) - continue; + AssertingVH const Func; + const unsigned Hash; + TargetData * const TD; +}; - FnMap[hash(F)].push_back(F); +struct MergeFunctionsEqualityInfo { + static ComparableFunction *getEmptyKey() { + return reinterpret_cast(0); + } + static ComparableFunction *getTombstoneKey() { + return reinterpret_cast(-1); } + static unsigned getHashValue(const ComparableFunction *CF) { + return CF->Hash; + } + static bool isEqual(const ComparableFunction *LHS, + const ComparableFunction *RHS) { + if (LHS == RHS) + return true; + if (LHS == getEmptyKey() || LHS == getTombstoneKey() || + RHS == getEmptyKey() || RHS == getTombstoneKey()) + return false; + assert(LHS->TD == RHS->TD && "Comparing functions for different targets"); + return FunctionComparator(LHS->TD, LHS->Func, RHS->Func).Compare(); + } +}; +bool MergeFunctions::runOnModule(Module &M) { + typedef DenseSet FnSetType; + + bool Changed = false; TD = getAnalysisIfAvailable(); + std::vector Funcs; + for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { + if (!F->isDeclaration() && !F->hasAvailableExternallyLinkage()) + Funcs.push_back(F); + } + bool LocalChanged; do { LocalChanged = false; - DEBUG(dbgs() << "size: " << FnMap.size() << "\n"); - for (std::map >::iterator - I = FnMap.begin(), E = FnMap.end(); I != E; ++I) { - std::vector &FnVec = I->second; - DEBUG(dbgs() << "hash (" << I->first << "): " << FnVec.size() << "\n"); - - for (int i = 0, e = FnVec.size(); i != e; ++i) { - for (int j = i + 1; j != e; ++j) { - bool isEqual = equals(FnVec[i], FnVec[j]); - - DEBUG(dbgs() << " " << FnVec[i]->getName() - << (isEqual ? " == " : " != ") - << FnVec[j]->getName() << "\n"); - - if (isEqual) { - if (fold(FnVec, i, j)) { - LocalChanged = true; - FnVec.erase(FnVec.begin() + j); - --j, --e; - } - } - } - } + FnSetType FnSet; + for (unsigned i = 0, e = Funcs.size(); i != e;) { + Function *F = Funcs[i]; + ComparableFunction *NewF = new ComparableFunction(F, TD); + std::pair Result = FnSet.insert(NewF); + if (!Result.second) { + ComparableFunction *&OldF = *Result.first; + assert(OldF && "Expected a hash collision"); + + // NewF will be deleted in favour of OldF unless NewF is strong and + // OldF is weak in which case swap them to keep the strong definition. + + if (OldF->Func->isWeakForLinker() && !NewF->Func->isWeakForLinker()) + std::swap(OldF, NewF); + + DEBUG(dbgs() << " " << OldF->Func->getName() << " == " + << NewF->Func->getName() << '\n'); + + Funcs.erase(Funcs.begin() + i); + --e; + + Function *DeleteF = NewF->Func; + delete NewF; + MergeTwoFunctions(OldF->Func, DeleteF); + LocalChanged = true; + Changed = true; + } else { + ++i; + } } - Changed |= LocalChanged; + DeleteContainerPointers(FnSet); } while (LocalChanged); return Changed; diff --git a/lib/Transforms/IPO/PartialInlining.cpp b/lib/Transforms/IPO/PartialInlining.cpp index 6b9814c..432f7c5 100644 --- a/lib/Transforms/IPO/PartialInlining.cpp +++ b/lib/Transforms/IPO/PartialInlining.cpp @@ -30,7 +30,7 @@ namespace { struct PartialInliner : public ModulePass { virtual void getAnalysisUsage(AnalysisUsage &AU) const { } static char ID; // Pass identification, replacement for typeid - PartialInliner() : ModulePass(&ID) {} + PartialInliner() : ModulePass(ID) {} bool runOnModule(Module& M); @@ -40,7 +40,8 @@ namespace { } char PartialInliner::ID = 0; -static RegisterPass X("partial-inliner", "Partial Inliner"); +INITIALIZE_PASS(PartialInliner, "partial-inliner", + "Partial Inliner", false, false); ModulePass* llvm::createPartialInliningPass() { return new PartialInliner(); } @@ -67,7 +68,8 @@ Function* PartialInliner::unswitchFunction(Function* F) { // Clone the function, so that we can hack away on it. ValueMap VMap; - Function* duplicateFunction = CloneFunction(F, VMap); + Function* duplicateFunction = CloneFunction(F, VMap, + /*ModuleLevelChanges=*/false); duplicateFunction->setLinkage(GlobalValue::InternalLinkage); F->getParent()->getFunctionList().push_back(duplicateFunction); BasicBlock* newEntryBlock = cast(VMap[entryBlock]); @@ -159,7 +161,7 @@ bool PartialInliner::runOnModule(Module& M) { bool recursive = false; for (Function::use_iterator UI = currFunc->use_begin(), UE = currFunc->use_end(); UI != UE; ++UI) - if (Instruction* I = dyn_cast(UI)) + if (Instruction* I = dyn_cast(*UI)) if (I->getParent()->getParent() == currFunc) { recursive = true; break; diff --git a/lib/Transforms/IPO/PartialSpecialization.cpp b/lib/Transforms/IPO/PartialSpecialization.cpp index 58e1448..4a99a41 100644 --- a/lib/Transforms/IPO/PartialSpecialization.cpp +++ b/lib/Transforms/IPO/PartialSpecialization.cpp @@ -50,14 +50,14 @@ namespace { int scanDistribution(Function&, int, std::map&); public : static char ID; // Pass identification, replacement for typeid - PartSpec() : ModulePass(&ID) {} + PartSpec() : ModulePass(ID) {} bool runOnModule(Module &M); }; } char PartSpec::ID = 0; -static RegisterPass -X("partialspecialization", "Partial Specialization"); +INITIALIZE_PASS(PartSpec, "partialspecialization", + "Partial Specialization", false, false); // Specialize F by replacing the arguments (keys) in replacements with the // constants (values). Replace all calls to F with those constants with @@ -74,7 +74,8 @@ SpecializeFunction(Function* F, deleted[arg->getArgNo()] = arg; } - Function* NF = CloneFunction(F, replacements); + Function* NF = CloneFunction(F, replacements, + /*ModuleLevelChanges=*/false); NF->setLinkage(GlobalValue::InternalLinkage); F->getParent()->getFunctionList().push_back(NF); @@ -82,10 +83,10 @@ SpecializeFunction(Function* F, ii != ee; ) { Value::use_iterator i = ii; ++ii; - if (isa(i) || isa(i)) { - CallSite CS(cast(i)); + User *U = *i; + CallSite CS(U); + if (CS) { if (CS.getCalledFunction() == F) { - SmallVector args; // Assemble the non-specialized arguments for the updated callsite. // In the process, make sure that the specialized arguments are @@ -105,13 +106,13 @@ SpecializeFunction(Function* F, } } Value* NCall; - if (CallInst *CI = dyn_cast(i)) { + if (CallInst *CI = dyn_cast(U)) { NCall = CallInst::Create(NF, args.begin(), args.end(), CI->getName(), CI); cast(NCall)->setTailCall(CI->isTailCall()); cast(NCall)->setCallingConv(CI->getCallingConv()); } else { - InvokeInst *II = cast(i); + InvokeInst *II = cast(U); NCall = InvokeInst::Create(NF, II->getNormalDest(), II->getUnwindDest(), args.begin(), args.end(), @@ -123,8 +124,7 @@ SpecializeFunction(Function* F, ++numReplaced; } } - next_use: - ; + next_use:; } return NF; } @@ -174,14 +174,14 @@ void PartSpec::scanForInterest(Function& F, InterestingArgVector& args) { ui != ue; ++ui) { bool interesting = false; - - if (isa(ui)) interesting = true; - else if (isa(ui)) + User *U = *ui; + if (isa(U)) interesting = true; + else if (isa(U)) interesting = ui->getOperand(0) == ii; - else if (isa(ui)) + else if (isa(U)) interesting = ui->getOperand(0) == ii; - else if (isa(ui)) interesting = true; - else if (isa(ui)) interesting = true; + else if (isa(U)) interesting = true; + else if (isa(U)) interesting = true; if (interesting) { args.push_back(std::distance(F.arg_begin(), ii)); @@ -196,14 +196,16 @@ int PartSpec::scanDistribution(Function& F, int arg, std::map& dist) { bool hasIndirect = false; int total = 0; - for(Value::use_iterator ii = F.use_begin(), ee = F.use_end(); - ii != ee; ++ii) - if ((isa(ii) || isa(ii)) - && ii->getOperand(0) == &F) { - ++dist[dyn_cast(ii->getOperand(arg + 1))]; + for (Value::use_iterator ii = F.use_begin(), ee = F.use_end(); + ii != ee; ++ii) { + User *U = *ii; + CallSite CS(U); + if (CS && CS.getCalledFunction() == &F) { + ++dist[dyn_cast(CS.getArgument(arg))]; ++total; } else hasIndirect = true; + } // Preserve the original address taken function even if all other uses // will be specialized. diff --git a/lib/Transforms/IPO/PruneEH.cpp b/lib/Transforms/IPO/PruneEH.cpp index de6099c..09ac76f 100644 --- a/lib/Transforms/IPO/PruneEH.cpp +++ b/lib/Transforms/IPO/PruneEH.cpp @@ -37,7 +37,7 @@ STATISTIC(NumUnreach, "Number of noreturn calls optimized"); namespace { struct PruneEH : public CallGraphSCCPass { static char ID; // Pass identification, replacement for typeid - PruneEH() : CallGraphSCCPass(&ID) {} + PruneEH() : CallGraphSCCPass(ID) {} // runOnSCC - Analyze the SCC, performing the transformation if possible. bool runOnSCC(CallGraphSCC &SCC); @@ -48,8 +48,8 @@ namespace { } char PruneEH::ID = 0; -static RegisterPass -X("prune-eh", "Remove unused exception handling info"); +INITIALIZE_PASS(PruneEH, "prune-eh", + "Remove unused exception handling info", false, false); Pass *llvm::createPruneEHPass() { return new PruneEH(); } diff --git a/lib/Transforms/IPO/StripDeadPrototypes.cpp b/lib/Transforms/IPO/StripDeadPrototypes.cpp index 4566a76..ee10ad0 100644 --- a/lib/Transforms/IPO/StripDeadPrototypes.cpp +++ b/lib/Transforms/IPO/StripDeadPrototypes.cpp @@ -29,15 +29,15 @@ namespace { class StripDeadPrototypesPass : public ModulePass { public: static char ID; // Pass identification, replacement for typeid - StripDeadPrototypesPass() : ModulePass(&ID) { } + StripDeadPrototypesPass() : ModulePass(ID) { } virtual bool runOnModule(Module &M); }; } // end anonymous namespace char StripDeadPrototypesPass::ID = 0; -static RegisterPass -X("strip-dead-prototypes", "Strip Unused Function Prototypes"); +INITIALIZE_PASS(StripDeadPrototypesPass, "strip-dead-prototypes", + "Strip Unused Function Prototypes", false, false); bool StripDeadPrototypesPass::runOnModule(Module &M) { bool MadeChange = false; diff --git a/lib/Transforms/IPO/StripSymbols.cpp b/lib/Transforms/IPO/StripSymbols.cpp index 12e8db8..20b7b8f 100644 --- a/lib/Transforms/IPO/StripSymbols.cpp +++ b/lib/Transforms/IPO/StripSymbols.cpp @@ -39,7 +39,7 @@ namespace { public: static char ID; // Pass identification, replacement for typeid explicit StripSymbols(bool ODI = false) - : ModulePass(&ID), OnlyDebugInfo(ODI) {} + : ModulePass(ID), OnlyDebugInfo(ODI) {} virtual bool runOnModule(Module &M); @@ -52,7 +52,7 @@ namespace { public: static char ID; // Pass identification, replacement for typeid explicit StripNonDebugSymbols() - : ModulePass(&ID) {} + : ModulePass(ID) {} virtual bool runOnModule(Module &M); @@ -65,7 +65,7 @@ namespace { public: static char ID; // Pass identification, replacement for typeid explicit StripDebugDeclare() - : ModulePass(&ID) {} + : ModulePass(ID) {} virtual bool runOnModule(Module &M); @@ -78,7 +78,7 @@ namespace { public: static char ID; // Pass identification, replacement for typeid explicit StripDeadDebugInfo() - : ModulePass(&ID) {} + : ModulePass(ID) {} virtual bool runOnModule(Module &M); @@ -89,32 +89,33 @@ namespace { } char StripSymbols::ID = 0; -static RegisterPass -X("strip", "Strip all symbols from a module"); +INITIALIZE_PASS(StripSymbols, "strip", + "Strip all symbols from a module", false, false); ModulePass *llvm::createStripSymbolsPass(bool OnlyDebugInfo) { return new StripSymbols(OnlyDebugInfo); } char StripNonDebugSymbols::ID = 0; -static RegisterPass -Y("strip-nondebug", "Strip all symbols, except dbg symbols, from a module"); +INITIALIZE_PASS(StripNonDebugSymbols, "strip-nondebug", + "Strip all symbols, except dbg symbols, from a module", + false, false); ModulePass *llvm::createStripNonDebugSymbolsPass() { return new StripNonDebugSymbols(); } char StripDebugDeclare::ID = 0; -static RegisterPass -Z("strip-debug-declare", "Strip all llvm.dbg.declare intrinsics"); +INITIALIZE_PASS(StripDebugDeclare, "strip-debug-declare", + "Strip all llvm.dbg.declare intrinsics", false, false); ModulePass *llvm::createStripDebugDeclarePass() { return new StripDebugDeclare(); } char StripDeadDebugInfo::ID = 0; -static RegisterPass -A("strip-dead-debug-info", "Strip debug info for unused symbols"); +INITIALIZE_PASS(StripDeadDebugInfo, "strip-dead-debug-info", + "Strip debug info for unused symbols", false, false); ModulePass *llvm::createStripDeadDebugInfoPass() { return new StripDeadDebugInfo(); @@ -254,14 +255,15 @@ static bool StripDebugInfo(Module &M) { } } - unsigned MDDbgKind = M.getMDKindID("dbg"); for (Module::iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) for (Function::iterator FI = MI->begin(), FE = MI->end(); FI != FE; ++FI) for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) { - Changed = true; // FIXME: Only set if there was debug metadata. - BI->setMetadata(MDDbgKind, 0); + if (!BI->getDebugLoc().isUnknown()) { + Changed = true; + BI->setDebugLoc(DebugLoc()); + } } return Changed; @@ -348,8 +350,8 @@ bool StripDeadDebugInfo::runOnModule(Module &M) { for (SmallVector::iterator I = MDs.begin(), E = MDs.end(); I != E; ++I) { - if (M.getGlobalVariable(DIGlobalVariable(*I).getGlobal()->getName(), - true)) { + GlobalVariable *GV = DIGlobalVariable(*I).getGlobal(); + if (GV && M.getGlobalVariable(GV->getName(), true)) { if (!NMD) NMD = M.getOrInsertNamedMetadata("llvm.dbg.gv"); NMD->addOperand(*I); diff --git a/lib/Transforms/IPO/StructRetPromotion.cpp b/lib/Transforms/IPO/StructRetPromotion.cpp index a74686f..b82b03f 100644 --- a/lib/Transforms/IPO/StructRetPromotion.cpp +++ b/lib/Transforms/IPO/StructRetPromotion.cpp @@ -1,4 +1,4 @@ -//===-- StructRetPromotion.cpp - Promote sret arguments ------------------===// +//===-- StructRetPromotion.cpp - Promote sret arguments -------------------===// // // The LLVM Compiler Infrastructure // @@ -50,20 +50,19 @@ namespace { virtual bool runOnSCC(CallGraphSCC &SCC); static char ID; // Pass identification, replacement for typeid - SRETPromotion() : CallGraphSCCPass(&ID) {} + SRETPromotion() : CallGraphSCCPass(ID) {} private: CallGraphNode *PromoteReturn(CallGraphNode *CGN); bool isSafeToUpdateAllCallers(Function *F); Function *cloneFunctionBody(Function *F, const StructType *STy); CallGraphNode *updateCallSites(Function *F, Function *NF); - bool nestedStructType(const StructType *STy); }; } char SRETPromotion::ID = 0; -static RegisterPass -X("sretpromotion", "Promote sret arguments to multiple ret values"); +INITIALIZE_PASS(SRETPromotion, "sretpromotion", + "Promote sret arguments to multiple ret values", false, false); Pass *llvm::createStructRetPromotionPass() { return new SRETPromotion(); @@ -156,7 +155,7 @@ bool SRETPromotion::isSafeToUpdateAllCallers(Function *F) { FnUseI != FnUseE; ++FnUseI) { // The function is passed in as an argument to (possibly) another function, // we can't change it! - CallSite CS = CallSite::get(*FnUseI); + CallSite CS(*FnUseI); Instruction *Call = CS.getInstruction(); // The function is used by something else than a call or invoke instruction, // we can't change it! @@ -187,7 +186,7 @@ bool SRETPromotion::isSafeToUpdateAllCallers(Function *F) { return false; for (Value::use_iterator GEPI = GEP->use_begin(), GEPE = GEP->use_end(); GEPI != GEPE; ++GEPI) - if (!isa(GEPI)) + if (!isa(*GEPI)) return false; } // Any other FirstArg users make this function unsuitable for sret @@ -271,7 +270,7 @@ CallGraphNode *SRETPromotion::updateCallSites(Function *F, Function *NF) { CallGraphNode *NF_CGN = CG.getOrInsertFunction(NF); while (!F->use_empty()) { - CallSite CS = CallSite::get(*F->use_begin()); + CallSite CS(*F->use_begin()); Instruction *Call = CS.getInstruction(); const AttrListPtr &PAL = F->getAttributes(); @@ -351,14 +350,3 @@ CallGraphNode *SRETPromotion::updateCallSites(Function *F, Function *NF) { return NF_CGN; } -/// nestedStructType - Return true if STy includes any -/// other aggregate types -bool SRETPromotion::nestedStructType(const StructType *STy) { - unsigned Num = STy->getNumElements(); - for (unsigned i = 0; i < Num; i++) { - const Type *Ty = STy->getElementType(i); - if (!Ty->isSingleValueType() && !Ty->isVoidTy()) - return true; - } - return false; -} diff --git a/lib/Transforms/InstCombine/InstCombine.h b/lib/Transforms/InstCombine/InstCombine.h index 24e0528..6f9609c 100644 --- a/lib/Transforms/InstCombine/InstCombine.h +++ b/lib/Transforms/InstCombine/InstCombine.h @@ -81,7 +81,7 @@ public: BuilderTy *Builder; static char ID; // Pass identification, replacement for typeid - InstCombiner() : FunctionPass(&ID), TD(0), Builder(0) {} + InstCombiner() : FunctionPass(ID), TD(0), Builder(0) {} public: virtual bool runOnFunction(Function &F); diff --git a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 5876f40..19a05bf 100644 --- a/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -474,19 +474,16 @@ Value *InstCombiner::FoldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS) { } // (icmp ne (A & C1), 0) & (icmp ne (A & C2), 0) --> - // (icmp eq (A & (C1|C2)), (C1|C2)) + // (icmp eq (A & (C1|C2)), (C1|C2)) where C1 and C2 are non-zero POT if (LHSCC == ICmpInst::ICMP_NE && LHSCst->isZero()) { - Instruction *I1 = dyn_cast(Val); - Instruction *I2 = dyn_cast(Val2); - if (I1 && I1->getOpcode() == Instruction::And && - I2 && I2->getOpcode() == Instruction::And && - I1->getOperand(0) == I1->getOperand(0)) { - ConstantInt *CI1 = dyn_cast(I1->getOperand(1)); - ConstantInt *CI2 = dyn_cast(I2->getOperand(1)); - if (CI1 && !CI1->isZero() && CI2 && !CI2->isZero() && - CI1->getValue().operator&(CI2->getValue()) == 0) { + Value *Op1 = 0, *Op2 = 0; + ConstantInt *CI1 = 0, *CI2 = 0; + if (match(LHS->getOperand(0), m_And(m_Value(Op1), m_ConstantInt(CI1))) && + match(RHS->getOperand(0), m_And(m_Value(Op2), m_ConstantInt(CI2)))) { + if (Op1 == Op2 && !CI1->isZero() && !CI2->isZero() && + CI1->getValue().isPowerOf2() && CI2->getValue().isPowerOf2()) { Constant *ConstOr = ConstantExpr::getOr(CI1, CI2); - Value *NewAnd = Builder->CreateAnd(I1->getOperand(0), ConstOr); + Value *NewAnd = Builder->CreateAnd(Op1, ConstOr); return Builder->CreateICmp(ICmpInst::ICMP_EQ, NewAnd, ConstOr); } } @@ -1170,11 +1167,28 @@ Value *InstCombiner::FoldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS) { ConstantInt *RHSCst = dyn_cast(RHS->getOperand(1)); if (LHSCst == 0 || RHSCst == 0) return 0; - // (icmp ne A, 0) | (icmp ne B, 0) --> (icmp ne (A|B), 0) - if (LHSCst == RHSCst && LHSCC == RHSCC && - LHSCC == ICmpInst::ICMP_NE && LHSCst->isZero()) { - Value *NewOr = Builder->CreateOr(Val, Val2); - return Builder->CreateICmp(LHSCC, NewOr, LHSCst); + if (LHSCst == RHSCst && LHSCC == RHSCC) { + // (icmp ne A, 0) | (icmp ne B, 0) --> (icmp ne (A|B), 0) + if (LHSCC == ICmpInst::ICMP_NE && LHSCst->isZero()) { + Value *NewOr = Builder->CreateOr(Val, Val2); + return Builder->CreateICmp(LHSCC, NewOr, LHSCst); + } + + // (icmp eq (A & C1), 0) | (icmp eq (A & C2), 0) --> + // (icmp ne (A & (C1|C2)), (C1|C2)) where C1 and C2 are non-zero POT + if (LHSCC == ICmpInst::ICMP_EQ && LHSCst->isZero()) { + Value *Op1 = 0, *Op2 = 0; + ConstantInt *CI1 = 0, *CI2 = 0; + if (match(LHS->getOperand(0), m_And(m_Value(Op1), m_ConstantInt(CI1))) && + match(RHS->getOperand(0), m_And(m_Value(Op2), m_ConstantInt(CI2)))) { + if (Op1 == Op2 && !CI1->isZero() && !CI2->isZero() && + CI1->getValue().isPowerOf2() && CI2->getValue().isPowerOf2()) { + Constant *ConstOr = ConstantExpr::getOr(CI1, CI2); + Value *NewAnd = Builder->CreateAnd(Op1, ConstOr); + return Builder->CreateICmp(ICmpInst::ICMP_NE, NewAnd, ConstOr); + } + } + } } // From here on, we only handle: diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index 85251a8..0ebe3b4 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -96,14 +96,23 @@ static unsigned EnforceKnownAlignment(Value *V, /// increase the alignment of the ultimate object, making this check succeed. unsigned InstCombiner::GetOrEnforceKnownAlignment(Value *V, unsigned PrefAlign) { - unsigned BitWidth = TD ? TD->getTypeSizeInBits(V->getType()) : - sizeof(PrefAlign) * CHAR_BIT; + assert(V->getType()->isPointerTy() && + "GetOrEnforceKnownAlignment expects a pointer!"); + unsigned BitWidth = TD ? TD->getPointerSizeInBits() : 64; APInt Mask = APInt::getAllOnesValue(BitWidth); APInt KnownZero(BitWidth, 0), KnownOne(BitWidth, 0); ComputeMaskedBits(V, Mask, KnownZero, KnownOne); unsigned TrailZ = KnownZero.countTrailingOnes(); + + // Avoid trouble with rediculously large TrailZ values, such as + // those computed from a null pointer. + TrailZ = std::min(TrailZ, unsigned(sizeof(unsigned) * CHAR_BIT - 1)); + unsigned Align = 1u << std::min(BitWidth - 1, TrailZ); + // LLVM doesn't support alignments larger than this currently. + Align = std::min(Align, +Value::MaximumAlignment); + if (PrefAlign > Align) Align = EnforceKnownAlignment(V, Align, PrefAlign); @@ -529,7 +538,7 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { // X + 0 -> {X, false} if (RHS->isZero()) { Constant *V[] = { - UndefValue::get(II->getCalledValue()->getType()), + UndefValue::get(II->getArgOperand(0)->getType()), ConstantInt::getFalse(II->getContext()) }; Constant *Struct = ConstantStruct::get(II->getContext(), V, 2, false); @@ -630,8 +639,8 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { cast(II->getArgOperand(0)->getType())->getNumElements(); APInt DemandedElts(VWidth, 1); APInt UndefElts(VWidth, 0); - if (Value *V = SimplifyDemandedVectorElts(II->getArgOperand(0), DemandedElts, - UndefElts)) { + if (Value *V = SimplifyDemandedVectorElts(II->getArgOperand(0), + DemandedElts, UndefElts)) { II->setArgOperand(0, V); return II; } @@ -655,8 +664,10 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { if (AllEltsOk) { // Cast the input vectors to byte vectors. - Value *Op0 = Builder->CreateBitCast(II->getArgOperand(0), Mask->getType()); - Value *Op1 = Builder->CreateBitCast(II->getArgOperand(1), Mask->getType()); + Value *Op0 = Builder->CreateBitCast(II->getArgOperand(0), + Mask->getType()); + Value *Op1 = Builder->CreateBitCast(II->getArgOperand(1), + Mask->getType()); Value *Result = UndefValue::get(Op0->getType()); // Only extract each element once. @@ -772,13 +783,15 @@ protected: NewInstruction = IC->ReplaceInstUsesWith(*CI, With); } bool isFoldable(unsigned SizeCIOp, unsigned SizeArgOp, bool isString) const { - if (ConstantInt *SizeCI = dyn_cast(CI->getArgOperand(SizeCIOp - CallInst::ArgOffset))) { + if (ConstantInt *SizeCI = + dyn_cast(CI->getArgOperand(SizeCIOp))) { if (SizeCI->isAllOnesValue()) return true; if (isString) return SizeCI->getZExtValue() >= - GetStringLength(CI->getArgOperand(SizeArgOp - CallInst::ArgOffset)); - if (ConstantInt *Arg = dyn_cast(CI->getArgOperand(SizeArgOp - CallInst::ArgOffset))) + GetStringLength(CI->getArgOperand(SizeArgOp)); + if (ConstantInt *Arg = dyn_cast( + CI->getArgOperand(SizeArgOp))) return SizeCI->getZExtValue() >= Arg->getZExtValue(); } return false; @@ -1140,7 +1153,7 @@ Instruction *InstCombiner::transformCallThroughTrampoline(CallSite CS) { IntrinsicInst *Tramp = cast(cast(Callee)->getOperand(0)); - Function *NestF = cast(Tramp->getArgOperand(1)->stripPointerCasts()); + Function *NestF =cast(Tramp->getArgOperand(1)->stripPointerCasts()); const PointerType *NestFPTy = cast(NestF->getType()); const FunctionType *NestFTy = cast(NestFPTy->getElementType()); diff --git a/lib/Transforms/InstCombine/InstCombineCasts.cpp b/lib/Transforms/InstCombine/InstCombineCasts.cpp index 505a0bf..79a9b09 100644 --- a/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -396,6 +396,11 @@ static bool CanEvaluateTruncated(Value *V, const Type *Ty) { case Instruction::Trunc: // trunc(trunc(x)) -> trunc(x) return true; + case Instruction::ZExt: + case Instruction::SExt: + // trunc(ext(x)) -> ext(x) if the source type is smaller than the new dest + // trunc(ext(x)) -> trunc(x) if the source type is larger than the new dest + return true; case Instruction::Select: { SelectInst *SI = cast(I); return CanEvaluateTruncated(SI->getTrueValue(), Ty) && @@ -454,6 +459,29 @@ Instruction *InstCombiner::visitTrunc(TruncInst &CI) { Value *Zero = Constant::getNullValue(Src->getType()); return new ICmpInst(ICmpInst::ICMP_NE, Src, Zero); } + + // Transform trunc(lshr (zext A), Cst) to eliminate one type conversion. + Value *A = 0; ConstantInt *Cst = 0; + if (match(Src, m_LShr(m_ZExt(m_Value(A)), m_ConstantInt(Cst))) && + Src->hasOneUse()) { + // We have three types to worry about here, the type of A, the source of + // the truncate (MidSize), and the destination of the truncate. We know that + // ASize < MidSize and MidSize > ResultSize, but don't know the relation + // between ASize and ResultSize. + unsigned ASize = A->getType()->getPrimitiveSizeInBits(); + + // If the shift amount is larger than the size of A, then the result is + // known to be zero because all the input bits got shifted out. + if (Cst->getZExtValue() >= ASize) + return ReplaceInstUsesWith(CI, Constant::getNullValue(CI.getType())); + + // Since we're doing an lshr and a zero extend, and know that the shift + // amount is smaller than ASize, it is always safe to do the shift in A's + // type, then zero extend or truncate to the result. + Value *Shift = Builder->CreateLShr(A, Cst->getZExtValue()); + Shift->takeName(Src); + return CastInst::CreateIntegerCast(Shift, CI.getType(), false); + } return 0; } @@ -538,8 +566,7 @@ Instruction *InstCombiner::transformZExtICmp(ICmpInst *ICI, Instruction &CI, if (CI.getType() == In->getType()) return ReplaceInstUsesWith(CI, In); - else - return CastInst::CreateIntegerCast(In, CI.getType(), false/*ZExt*/); + return CastInst::CreateIntegerCast(In, CI.getType(), false/*ZExt*/); } } } @@ -1097,6 +1124,38 @@ Instruction *InstCombiner::visitFPTrunc(FPTruncInst &CI) { break; } } + + // Fold (fptrunc (sqrt (fpext x))) -> (sqrtf x) + // NOTE: This should be disabled by -fno-builtin-sqrt if we ever support it. + CallInst *Call = dyn_cast(CI.getOperand(0)); + if (Call && Call->getCalledFunction() && + Call->getCalledFunction()->getName() == "sqrt" && + Call->getNumArgOperands() == 1) { + CastInst *Arg = dyn_cast(Call->getArgOperand(0)); + if (Arg && Arg->getOpcode() == Instruction::FPExt && + CI.getType()->isFloatTy() && + Call->getType()->isDoubleTy() && + Arg->getType()->isDoubleTy() && + Arg->getOperand(0)->getType()->isFloatTy()) { + Function *Callee = Call->getCalledFunction(); + Module *M = CI.getParent()->getParent()->getParent(); + Constant *SqrtfFunc = M->getOrInsertFunction("sqrtf", + Callee->getAttributes(), + Builder->getFloatTy(), + Builder->getFloatTy(), + NULL); + CallInst *ret = CallInst::Create(SqrtfFunc, Arg->getOperand(0), + "sqrtfcall"); + ret->setAttributes(Callee->getAttributes()); + + + // Remove the old Call. With -fmath-errno, it won't get marked readnone. + Call->replaceAllUsesWith(UndefValue::get(Call->getType())); + EraseInstFromFunction(*Call); + return ret; + } + } + return 0; } @@ -1308,6 +1367,199 @@ static Instruction *OptimizeVectorResize(Value *InVal, const VectorType *DestTy, return new ShuffleVectorInst(InVal, V2, Mask); } +static bool isMultipleOfTypeSize(unsigned Value, const Type *Ty) { + return Value % Ty->getPrimitiveSizeInBits() == 0; +} + +static unsigned getTypeSizeIndex(unsigned Value, const Type *Ty) { + return Value / Ty->getPrimitiveSizeInBits(); +} + +/// CollectInsertionElements - V is a value which is inserted into a vector of +/// VecEltTy. Look through the value to see if we can decompose it into +/// insertions into the vector. See the example in the comment for +/// OptimizeIntegerToVectorInsertions for the pattern this handles. +/// The type of V is always a non-zero multiple of VecEltTy's size. +/// +/// This returns false if the pattern can't be matched or true if it can, +/// filling in Elements with the elements found here. +static bool CollectInsertionElements(Value *V, unsigned ElementIndex, + SmallVectorImpl &Elements, + const Type *VecEltTy) { + // Undef values never contribute useful bits to the result. + if (isa(V)) return true; + + // If we got down to a value of the right type, we win, try inserting into the + // right element. + if (V->getType() == VecEltTy) { + // Inserting null doesn't actually insert any elements. + if (Constant *C = dyn_cast(V)) + if (C->isNullValue()) + return true; + + // Fail if multiple elements are inserted into this slot. + if (ElementIndex >= Elements.size() || Elements[ElementIndex] != 0) + return false; + + Elements[ElementIndex] = V; + return true; + } + + if (Constant *C = dyn_cast(V)) { + // Figure out the # elements this provides, and bitcast it or slice it up + // as required. + unsigned NumElts = getTypeSizeIndex(C->getType()->getPrimitiveSizeInBits(), + VecEltTy); + // If the constant is the size of a vector element, we just need to bitcast + // it to the right type so it gets properly inserted. + if (NumElts == 1) + return CollectInsertionElements(ConstantExpr::getBitCast(C, VecEltTy), + ElementIndex, Elements, VecEltTy); + + // Okay, this is a constant that covers multiple elements. Slice it up into + // pieces and insert each element-sized piece into the vector. + if (!isa(C->getType())) + C = ConstantExpr::getBitCast(C, IntegerType::get(V->getContext(), + C->getType()->getPrimitiveSizeInBits())); + unsigned ElementSize = VecEltTy->getPrimitiveSizeInBits(); + const Type *ElementIntTy = IntegerType::get(C->getContext(), ElementSize); + + for (unsigned i = 0; i != NumElts; ++i) { + Constant *Piece = ConstantExpr::getLShr(C, ConstantInt::get(C->getType(), + i*ElementSize)); + Piece = ConstantExpr::getTrunc(Piece, ElementIntTy); + if (!CollectInsertionElements(Piece, ElementIndex+i, Elements, VecEltTy)) + return false; + } + return true; + } + + if (!V->hasOneUse()) return false; + + Instruction *I = dyn_cast(V); + if (I == 0) return false; + switch (I->getOpcode()) { + default: return false; // Unhandled case. + case Instruction::BitCast: + return CollectInsertionElements(I->getOperand(0), ElementIndex, + Elements, VecEltTy); + case Instruction::ZExt: + if (!isMultipleOfTypeSize( + I->getOperand(0)->getType()->getPrimitiveSizeInBits(), + VecEltTy)) + return false; + return CollectInsertionElements(I->getOperand(0), ElementIndex, + Elements, VecEltTy); + case Instruction::Or: + return CollectInsertionElements(I->getOperand(0), ElementIndex, + Elements, VecEltTy) && + CollectInsertionElements(I->getOperand(1), ElementIndex, + Elements, VecEltTy); + case Instruction::Shl: { + // Must be shifting by a constant that is a multiple of the element size. + ConstantInt *CI = dyn_cast(I->getOperand(1)); + if (CI == 0) return false; + if (!isMultipleOfTypeSize(CI->getZExtValue(), VecEltTy)) return false; + unsigned IndexShift = getTypeSizeIndex(CI->getZExtValue(), VecEltTy); + + return CollectInsertionElements(I->getOperand(0), ElementIndex+IndexShift, + Elements, VecEltTy); + } + + } +} + + +/// OptimizeIntegerToVectorInsertions - If the input is an 'or' instruction, we +/// may be doing shifts and ors to assemble the elements of the vector manually. +/// Try to rip the code out and replace it with insertelements. This is to +/// optimize code like this: +/// +/// %tmp37 = bitcast float %inc to i32 +/// %tmp38 = zext i32 %tmp37 to i64 +/// %tmp31 = bitcast float %inc5 to i32 +/// %tmp32 = zext i32 %tmp31 to i64 +/// %tmp33 = shl i64 %tmp32, 32 +/// %ins35 = or i64 %tmp33, %tmp38 +/// %tmp43 = bitcast i64 %ins35 to <2 x float> +/// +/// Into two insertelements that do "buildvector{%inc, %inc5}". +static Value *OptimizeIntegerToVectorInsertions(BitCastInst &CI, + InstCombiner &IC) { + const VectorType *DestVecTy = cast(CI.getType()); + Value *IntInput = CI.getOperand(0); + + SmallVector Elements(DestVecTy->getNumElements()); + if (!CollectInsertionElements(IntInput, 0, Elements, + DestVecTy->getElementType())) + return 0; + + // If we succeeded, we know that all of the element are specified by Elements + // or are zero if Elements has a null entry. Recast this as a set of + // insertions. + Value *Result = Constant::getNullValue(CI.getType()); + for (unsigned i = 0, e = Elements.size(); i != e; ++i) { + if (Elements[i] == 0) continue; // Unset element. + + Result = IC.Builder->CreateInsertElement(Result, Elements[i], + IC.Builder->getInt32(i)); + } + + return Result; +} + + +/// OptimizeIntToFloatBitCast - See if we can optimize an integer->float/double +/// bitcast. The various long double bitcasts can't get in here. +static Instruction *OptimizeIntToFloatBitCast(BitCastInst &CI,InstCombiner &IC){ + Value *Src = CI.getOperand(0); + const Type *DestTy = CI.getType(); + + // If this is a bitcast from int to float, check to see if the int is an + // extraction from a vector. + Value *VecInput = 0; + // bitcast(trunc(bitcast(somevector))) + if (match(Src, m_Trunc(m_BitCast(m_Value(VecInput)))) && + isa(VecInput->getType())) { + const VectorType *VecTy = cast(VecInput->getType()); + unsigned DestWidth = DestTy->getPrimitiveSizeInBits(); + + if (VecTy->getPrimitiveSizeInBits() % DestWidth == 0) { + // If the element type of the vector doesn't match the result type, + // bitcast it to be a vector type we can extract from. + if (VecTy->getElementType() != DestTy) { + VecTy = VectorType::get(DestTy, + VecTy->getPrimitiveSizeInBits() / DestWidth); + VecInput = IC.Builder->CreateBitCast(VecInput, VecTy); + } + + return ExtractElementInst::Create(VecInput, IC.Builder->getInt32(0)); + } + } + + // bitcast(trunc(lshr(bitcast(somevector), cst)) + ConstantInt *ShAmt = 0; + if (match(Src, m_Trunc(m_LShr(m_BitCast(m_Value(VecInput)), + m_ConstantInt(ShAmt)))) && + isa(VecInput->getType())) { + const VectorType *VecTy = cast(VecInput->getType()); + unsigned DestWidth = DestTy->getPrimitiveSizeInBits(); + if (VecTy->getPrimitiveSizeInBits() % DestWidth == 0 && + ShAmt->getZExtValue() % DestWidth == 0) { + // If the element type of the vector doesn't match the result type, + // bitcast it to be a vector type we can extract from. + if (VecTy->getElementType() != DestTy) { + VecTy = VectorType::get(DestTy, + VecTy->getPrimitiveSizeInBits() / DestWidth); + VecInput = IC.Builder->CreateBitCast(VecInput, VecTy); + } + + unsigned Elt = ShAmt->getZExtValue() / DestWidth; + return ExtractElementInst::Create(VecInput, IC.Builder->getInt32(Elt)); + } + } + return 0; +} Instruction *InstCombiner::visitBitCast(BitCastInst &CI) { // If the operands are integer typed then apply the integer transforms, @@ -1359,6 +1611,11 @@ Instruction *InstCombiner::visitBitCast(BitCastInst &CI) { ((Instruction*)NULL)); } } + + // Try to optimize int -> float bitcasts. + if ((DestTy->isFloatTy() || DestTy->isDoubleTy()) && isa(SrcTy)) + if (Instruction *I = OptimizeIntToFloatBitCast(CI, *this)) + return I; if (const VectorType *DestVTy = dyn_cast(DestTy)) { if (DestVTy->getNumElements() == 1 && !SrcTy->isVectorTy()) { @@ -1368,16 +1625,24 @@ Instruction *InstCombiner::visitBitCast(BitCastInst &CI) { // FIXME: Canonicalize bitcast(insertelement) -> insertelement(bitcast) } - // If this is a cast from an integer to vector, check to see if the input - // is a trunc or zext of a bitcast from vector. If so, we can replace all - // the casts with a shuffle and (potentially) a bitcast. - if (isa(SrcTy) && (isa(Src) || isa(Src))){ - CastInst *SrcCast = cast(Src); - if (BitCastInst *BCIn = dyn_cast(SrcCast->getOperand(0))) - if (isa(BCIn->getOperand(0)->getType())) - if (Instruction *I = OptimizeVectorResize(BCIn->getOperand(0), + if (isa(SrcTy)) { + // If this is a cast from an integer to vector, check to see if the input + // is a trunc or zext of a bitcast from vector. If so, we can replace all + // the casts with a shuffle and (potentially) a bitcast. + if (isa(Src) || isa(Src)) { + CastInst *SrcCast = cast(Src); + if (BitCastInst *BCIn = dyn_cast(SrcCast->getOperand(0))) + if (isa(BCIn->getOperand(0)->getType())) + if (Instruction *I = OptimizeVectorResize(BCIn->getOperand(0), cast(DestTy), *this)) - return I; + return I; + } + + // If the input is an 'or' instruction, we may be doing shifts and ors to + // assemble the elements of the vector manually. Try to rip the code out + // and replace it with insertelements. + if (Value *V = OptimizeIntegerToVectorInsertions(CI, *this)) + return ReplaceInstUsesWith(CI, V); } } diff --git a/lib/Transforms/InstCombine/InstCombineCompares.cpp b/lib/Transforms/InstCombine/InstCombineCompares.cpp index 6c00586..d7e2b72 100644 --- a/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1374,7 +1374,7 @@ Instruction *InstCombiner::visitICmpInstWithInstAndIntCst(ICmpInst &ICI, case Instruction::Or: // If bits are being or'd in that are not present in the constant we // are comparing against, then the comparison could never succeed! - if (Constant *BOC = dyn_cast(BO->getOperand(1))) { + if (ConstantInt *BOC = dyn_cast(BO->getOperand(1))) { Constant *NotCI = ConstantExpr::getNot(RHS); if (!ConstantExpr::getAnd(BOC, NotCI)->isNullValue()) return ReplaceInstUsesWith(ICI, diff --git a/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp index 8933a0b..b68fbc2 100644 --- a/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ b/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -146,10 +146,14 @@ Instruction *InstCombiner::visitLoadInst(LoadInst &LI) { if (TD) { unsigned KnownAlign = GetOrEnforceKnownAlignment(Op, TD->getPrefTypeAlignment(LI.getType())); - if (KnownAlign > - (LI.getAlignment() == 0 ? TD->getABITypeAlignment(LI.getType()) : - LI.getAlignment())) + unsigned LoadAlign = LI.getAlignment(); + unsigned EffectiveLoadAlign = LoadAlign != 0 ? LoadAlign : + TD->getABITypeAlignment(LI.getType()); + + if (KnownAlign > EffectiveLoadAlign) LI.setAlignment(KnownAlign); + else if (LoadAlign == 0) + LI.setAlignment(EffectiveLoadAlign); } // load (cast X) --> cast (load X) iff safe. @@ -369,7 +373,7 @@ DbgDeclareInst *InstCombiner::hasOneUsePlusDeclare(Value *V) { if (DbgDeclareInst *DI = dyn_cast(U)) return DI; if (isa(U) && U->hasOneUse()) { - if (DbgDeclareInst *DI = dyn_cast(U->use_begin())) + if (DbgDeclareInst *DI = dyn_cast(*U->use_begin())) return DI; } } @@ -411,10 +415,14 @@ Instruction *InstCombiner::visitStoreInst(StoreInst &SI) { if (TD) { unsigned KnownAlign = GetOrEnforceKnownAlignment(Ptr, TD->getPrefTypeAlignment(Val->getType())); - if (KnownAlign > - (SI.getAlignment() == 0 ? TD->getABITypeAlignment(Val->getType()) : - SI.getAlignment())) + unsigned StoreAlign = SI.getAlignment(); + unsigned EffectiveStoreAlign = StoreAlign != 0 ? StoreAlign : + TD->getABITypeAlignment(Val->getType()); + + if (KnownAlign > EffectiveStoreAlign) SI.setAlignment(KnownAlign); + else if (StoreAlign == 0) + SI.setAlignment(EffectiveStoreAlign); } // Do really simple DSE, to catch cases where there are several consecutive diff --git a/lib/Transforms/InstCombine/InstCombineSelect.cpp b/lib/Transforms/InstCombine/InstCombineSelect.cpp index f9ffdb1..c44fe9d 100644 --- a/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -699,34 +699,6 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { SI.setOperand(2, TrueVal); return &SI; } - - // select (A == 0 | B == 0), T, F--> select (A != 0 & B != 0), F, T - // Note: This is a canonicalization rather than an optimization, and is used - // to expose opportunities to other instcombine transforms. - Instruction* CondInst = dyn_cast(CondVal); - if (CondInst && CondInst->hasOneUse() && - CondInst->getOpcode() == Instruction::Or) { - ICmpInst *LHSCmp = dyn_cast(CondInst->getOperand(0)); - ICmpInst *RHSCmp = dyn_cast(CondInst->getOperand(1)); - if (LHSCmp && LHSCmp->hasOneUse() && - LHSCmp->getPredicate() == ICmpInst::ICMP_EQ && - RHSCmp && RHSCmp->hasOneUse() && - RHSCmp->getPredicate() == ICmpInst::ICMP_EQ) { - ConstantInt* C1 = dyn_cast(LHSCmp->getOperand(1)); - ConstantInt* C2 = dyn_cast(RHSCmp->getOperand(1)); - if (C1 && C1->isZero() && C2 && C2->isZero()) { - LHSCmp->setPredicate(ICmpInst::ICMP_NE); - RHSCmp->setPredicate(ICmpInst::ICMP_NE); - Value *And = - InsertNewInstBefore(BinaryOperator::CreateAnd(LHSCmp, RHSCmp, - "and."+CondVal->getName()), SI); - SI.setOperand(0, And); - SI.setOperand(1, FalseVal); - SI.setOperand(2, TrueVal); - return &SI; - } - } - } return 0; } diff --git a/lib/Transforms/InstCombine/InstCombineShifts.cpp b/lib/Transforms/InstCombine/InstCombineShifts.cpp index e5ce8a6..27716b8 100644 --- a/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -56,10 +56,270 @@ Instruction *InstCombiner::commonShiftTransforms(BinaryOperator &I) { return 0; } +/// CanEvaluateShifted - See if we can compute the specified value, but shifted +/// logically to the left or right by some number of bits. This should return +/// true if the expression can be computed for the same cost as the current +/// expression tree. This is used to eliminate extraneous shifting from things +/// like: +/// %C = shl i128 %A, 64 +/// %D = shl i128 %B, 96 +/// %E = or i128 %C, %D +/// %F = lshr i128 %E, 64 +/// where the client will ask if E can be computed shifted right by 64-bits. If +/// this succeeds, the GetShiftedValue function will be called to produce the +/// value. +static bool CanEvaluateShifted(Value *V, unsigned NumBits, bool isLeftShift, + InstCombiner &IC) { + // We can always evaluate constants shifted. + if (isa(V)) + return true; + + Instruction *I = dyn_cast(V); + if (!I) return false; + + // If this is the opposite shift, we can directly reuse the input of the shift + // if the needed bits are already zero in the input. This allows us to reuse + // the value which means that we don't care if the shift has multiple uses. + // TODO: Handle opposite shift by exact value. + ConstantInt *CI; + if ((isLeftShift && match(I, m_LShr(m_Value(), m_ConstantInt(CI)))) || + (!isLeftShift && match(I, m_Shl(m_Value(), m_ConstantInt(CI))))) { + if (CI->getZExtValue() == NumBits) { + // TODO: Check that the input bits are already zero with MaskedValueIsZero +#if 0 + // If this is a truncate of a logical shr, we can truncate it to a smaller + // lshr iff we know that the bits we would otherwise be shifting in are + // already zeros. + uint32_t OrigBitWidth = OrigTy->getScalarSizeInBits(); + uint32_t BitWidth = Ty->getScalarSizeInBits(); + if (MaskedValueIsZero(I->getOperand(0), + APInt::getHighBitsSet(OrigBitWidth, OrigBitWidth-BitWidth)) && + CI->getLimitedValue(BitWidth) < BitWidth) { + return CanEvaluateTruncated(I->getOperand(0), Ty); + } +#endif + + } + } + + // We can't mutate something that has multiple uses: doing so would + // require duplicating the instruction in general, which isn't profitable. + if (!I->hasOneUse()) return false; + + switch (I->getOpcode()) { + default: return false; + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + // Bitwise operators can all arbitrarily be arbitrarily evaluated shifted. + return CanEvaluateShifted(I->getOperand(0), NumBits, isLeftShift, IC) && + CanEvaluateShifted(I->getOperand(1), NumBits, isLeftShift, IC); + + case Instruction::Shl: { + // We can often fold the shift into shifts-by-a-constant. + CI = dyn_cast(I->getOperand(1)); + if (CI == 0) return false; + + // We can always fold shl(c1)+shl(c2) -> shl(c1+c2). + if (isLeftShift) return true; + + // We can always turn shl(c)+shr(c) -> and(c2). + if (CI->getValue() == NumBits) return true; + + unsigned TypeWidth = I->getType()->getScalarSizeInBits(); + + // We can turn shl(c1)+shr(c2) -> shl(c3)+and(c4), but it isn't + // profitable unless we know the and'd out bits are already zero. + if (CI->getZExtValue() > NumBits) { + unsigned HighBits = CI->getZExtValue() - NumBits; + if (MaskedValueIsZero(I->getOperand(0), + APInt::getHighBitsSet(TypeWidth, HighBits))) + return true; + } + + return false; + } + case Instruction::LShr: { + // We can often fold the shift into shifts-by-a-constant. + CI = dyn_cast(I->getOperand(1)); + if (CI == 0) return false; + + // We can always fold lshr(c1)+lshr(c2) -> lshr(c1+c2). + if (!isLeftShift) return true; + + // We can always turn lshr(c)+shl(c) -> and(c2). + if (CI->getValue() == NumBits) return true; + + unsigned TypeWidth = I->getType()->getScalarSizeInBits(); + + // We can always turn lshr(c1)+shl(c2) -> lshr(c3)+and(c4), but it isn't + // profitable unless we know the and'd out bits are already zero. + if (CI->getZExtValue() > NumBits) { + unsigned LowBits = CI->getZExtValue() - NumBits; + if (MaskedValueIsZero(I->getOperand(0), + APInt::getLowBitsSet(TypeWidth, LowBits))) + return true; + } + + return false; + } + case Instruction::Select: { + SelectInst *SI = cast(I); + return CanEvaluateShifted(SI->getTrueValue(), NumBits, isLeftShift, IC) && + CanEvaluateShifted(SI->getFalseValue(), NumBits, isLeftShift, IC); + } + case Instruction::PHI: { + // We can change a phi if we can change all operands. Note that we never + // get into trouble with cyclic PHIs here because we only consider + // instructions with a single use. + PHINode *PN = cast(I); + for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) + if (!CanEvaluateShifted(PN->getIncomingValue(i), NumBits, isLeftShift,IC)) + return false; + return true; + } + } +} + +/// GetShiftedValue - When CanEvaluateShifted returned true for an expression, +/// this value inserts the new computation that produces the shifted value. +static Value *GetShiftedValue(Value *V, unsigned NumBits, bool isLeftShift, + InstCombiner &IC) { + // We can always evaluate constants shifted. + if (Constant *C = dyn_cast(V)) { + if (isLeftShift) + V = IC.Builder->CreateShl(C, NumBits); + else + V = IC.Builder->CreateLShr(C, NumBits); + // If we got a constantexpr back, try to simplify it with TD info. + if (ConstantExpr *CE = dyn_cast(V)) + V = ConstantFoldConstantExpression(CE, IC.getTargetData()); + return V; + } + + Instruction *I = cast(V); + IC.Worklist.Add(I); + + switch (I->getOpcode()) { + default: assert(0 && "Inconsistency with CanEvaluateShifted"); + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + // Bitwise operators can all arbitrarily be arbitrarily evaluated shifted. + I->setOperand(0, GetShiftedValue(I->getOperand(0), NumBits,isLeftShift,IC)); + I->setOperand(1, GetShiftedValue(I->getOperand(1), NumBits,isLeftShift,IC)); + return I; + + case Instruction::Shl: { + unsigned TypeWidth = I->getType()->getScalarSizeInBits(); + + // We only accept shifts-by-a-constant in CanEvaluateShifted. + ConstantInt *CI = cast(I->getOperand(1)); + + // We can always fold shl(c1)+shl(c2) -> shl(c1+c2). + if (isLeftShift) { + // If this is oversized composite shift, then unsigned shifts get 0. + unsigned NewShAmt = NumBits+CI->getZExtValue(); + if (NewShAmt >= TypeWidth) + return Constant::getNullValue(I->getType()); + + I->setOperand(1, ConstantInt::get(I->getType(), NewShAmt)); + return I; + } + + // We turn shl(c)+lshr(c) -> and(c2) if the input doesn't already have + // zeros. + if (CI->getValue() == NumBits) { + APInt Mask(APInt::getLowBitsSet(TypeWidth, TypeWidth - NumBits)); + V = IC.Builder->CreateAnd(I->getOperand(0), + ConstantInt::get(I->getContext(), Mask)); + if (Instruction *VI = dyn_cast(V)) { + VI->moveBefore(I); + VI->takeName(I); + } + return V; + } + + // We turn shl(c1)+shr(c2) -> shl(c3)+and(c4), but only when we know that + // the and won't be needed. + assert(CI->getZExtValue() > NumBits); + I->setOperand(1, ConstantInt::get(I->getType(), + CI->getZExtValue() - NumBits)); + return I; + } + case Instruction::LShr: { + unsigned TypeWidth = I->getType()->getScalarSizeInBits(); + // We only accept shifts-by-a-constant in CanEvaluateShifted. + ConstantInt *CI = cast(I->getOperand(1)); + + // We can always fold lshr(c1)+lshr(c2) -> lshr(c1+c2). + if (!isLeftShift) { + // If this is oversized composite shift, then unsigned shifts get 0. + unsigned NewShAmt = NumBits+CI->getZExtValue(); + if (NewShAmt >= TypeWidth) + return Constant::getNullValue(I->getType()); + + I->setOperand(1, ConstantInt::get(I->getType(), NewShAmt)); + return I; + } + + // We turn lshr(c)+shl(c) -> and(c2) if the input doesn't already have + // zeros. + if (CI->getValue() == NumBits) { + APInt Mask(APInt::getHighBitsSet(TypeWidth, TypeWidth - NumBits)); + V = IC.Builder->CreateAnd(I->getOperand(0), + ConstantInt::get(I->getContext(), Mask)); + if (Instruction *VI = dyn_cast(V)) { + VI->moveBefore(I); + VI->takeName(I); + } + return V; + } + + // We turn lshr(c1)+shl(c2) -> lshr(c3)+and(c4), but only when we know that + // the and won't be needed. + assert(CI->getZExtValue() > NumBits); + I->setOperand(1, ConstantInt::get(I->getType(), + CI->getZExtValue() - NumBits)); + return I; + } + + case Instruction::Select: + I->setOperand(1, GetShiftedValue(I->getOperand(1), NumBits,isLeftShift,IC)); + I->setOperand(2, GetShiftedValue(I->getOperand(2), NumBits,isLeftShift,IC)); + return I; + case Instruction::PHI: { + // We can change a phi if we can change all operands. Note that we never + // get into trouble with cyclic PHIs here because we only consider + // instructions with a single use. + PHINode *PN = cast(I); + for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) + PN->setIncomingValue(i, GetShiftedValue(PN->getIncomingValue(i), + NumBits, isLeftShift, IC)); + return PN; + } + } +} + + + Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, ConstantInt *Op1, BinaryOperator &I) { bool isLeftShift = I.getOpcode() == Instruction::Shl; - + + + // See if we can propagate this shift into the input, this covers the trivial + // cast of lshr(shl(x,c1),c2) as well as other more complex cases. + if (I.getOpcode() != Instruction::AShr && + CanEvaluateShifted(Op0, Op1->getZExtValue(), isLeftShift, *this)) { + DEBUG(dbgs() << "ICE: GetShiftedValue propagating shift through expression" + " to eliminate shift:\n IN: " << *Op0 << "\n SH: " << I <<"\n"); + + return ReplaceInstUsesWith(I, + GetShiftedValue(Op0, Op1->getZExtValue(), isLeftShift, *this)); + } + + // See if we can simplify any instructions used by the instruction whose sole // purpose is to compute bits we don't care about. uint32_t TypeBits = Op0->getType()->getScalarSizeInBits(); @@ -288,39 +548,17 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, ConstantInt *Op1, ConstantInt::get(Ty, AmtSum)); } - if (ShiftOp->getOpcode() == Instruction::LShr && - I.getOpcode() == Instruction::AShr) { - if (AmtSum >= TypeBits) - return ReplaceInstUsesWith(I, Constant::getNullValue(I.getType())); - - // ((X >>u C1) >>s C2) -> (X >>u (C1+C2)) since C1 != 0. - return BinaryOperator::CreateLShr(X, ConstantInt::get(Ty, AmtSum)); - } - - if (ShiftOp->getOpcode() == Instruction::AShr && - I.getOpcode() == Instruction::LShr) { - // ((X >>s C1) >>u C2) -> ((X >>s (C1+C2)) & mask) since C1 != 0. - if (AmtSum >= TypeBits) - AmtSum = TypeBits-1; - - Value *Shift = Builder->CreateAShr(X, ConstantInt::get(Ty, AmtSum)); - - APInt Mask(APInt::getLowBitsSet(TypeBits, TypeBits - ShiftAmt2)); - return BinaryOperator::CreateAnd(Shift, - ConstantInt::get(I.getContext(), Mask)); - } - - // Okay, if we get here, one shift must be left, and the other shift must be - // right. See if the amounts are equal. if (ShiftAmt1 == ShiftAmt2) { // If we have ((X >>? C) << C), turn this into X & (-1 << C). - if (I.getOpcode() == Instruction::Shl) { + if (I.getOpcode() == Instruction::Shl && + ShiftOp->getOpcode() != Instruction::Shl) { APInt Mask(APInt::getHighBitsSet(TypeBits, TypeBits - ShiftAmt1)); return BinaryOperator::CreateAnd(X, ConstantInt::get(I.getContext(),Mask)); } // If we have ((X << C) >>u C), turn this into X & (-1 >>u C). - if (I.getOpcode() == Instruction::LShr) { + if (I.getOpcode() == Instruction::LShr && + ShiftOp->getOpcode() == Instruction::Shl) { APInt Mask(APInt::getLowBitsSet(TypeBits, TypeBits - ShiftAmt1)); return BinaryOperator::CreateAnd(X, ConstantInt::get(I.getContext(), Mask)); @@ -329,7 +567,8 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, ConstantInt *Op1, uint32_t ShiftDiff = ShiftAmt2-ShiftAmt1; // (X >>? C1) << C2 --> X << (C2-C1) & (-1 << C2) - if (I.getOpcode() == Instruction::Shl) { + if (I.getOpcode() == Instruction::Shl && + ShiftOp->getOpcode() != Instruction::Shl) { assert(ShiftOp->getOpcode() == Instruction::LShr || ShiftOp->getOpcode() == Instruction::AShr); Value *Shift = Builder->CreateShl(X, ConstantInt::get(Ty, ShiftDiff)); @@ -340,7 +579,8 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, ConstantInt *Op1, } // (X << C1) >>u C2 --> X >>u (C2-C1) & (-1 >> C2) - if (I.getOpcode() == Instruction::LShr) { + if (I.getOpcode() == Instruction::LShr && + ShiftOp->getOpcode() == Instruction::Shl) { assert(ShiftOp->getOpcode() == Instruction::Shl); Value *Shift = Builder->CreateLShr(X, ConstantInt::get(Ty, ShiftDiff)); @@ -355,9 +595,8 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, ConstantInt *Op1, uint32_t ShiftDiff = ShiftAmt1-ShiftAmt2; // (X >>? C1) << C2 --> X >>? (C1-C2) & (-1 << C2) - if (I.getOpcode() == Instruction::Shl) { - assert(ShiftOp->getOpcode() == Instruction::LShr || - ShiftOp->getOpcode() == Instruction::AShr); + if (I.getOpcode() == Instruction::Shl && + ShiftOp->getOpcode() != Instruction::Shl) { Value *Shift = Builder->CreateBinOp(ShiftOp->getOpcode(), X, ConstantInt::get(Ty, ShiftDiff)); @@ -367,8 +606,8 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, ConstantInt *Op1, } // (X << C1) >>u C2 --> X << (C1-C2) & (-1 >> C2) - if (I.getOpcode() == Instruction::LShr) { - assert(ShiftOp->getOpcode() == Instruction::Shl); + if (I.getOpcode() == Instruction::LShr && + ShiftOp->getOpcode() == Instruction::Shl) { Value *Shift = Builder->CreateShl(X, ConstantInt::get(Ty, ShiftDiff)); APInt Mask(APInt::getLowBitsSet(TypeBits, TypeBits - ShiftAmt2)); diff --git a/lib/Transforms/InstCombine/InstructionCombining.cpp b/lib/Transforms/InstCombine/InstructionCombining.cpp index af2958f..e46c679 100644 --- a/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -60,8 +60,8 @@ STATISTIC(NumSunkInst , "Number of instructions sunk"); char InstCombiner::ID = 0; -static RegisterPass -X("instcombine", "Combine redundant instructions"); +INITIALIZE_PASS(InstCombiner, "instcombine", + "Combine redundant instructions", false, false); void InstCombiner::getAnalysisUsage(AnalysisUsage &AU) const { AU.addPreservedID(LCSSAID); diff --git a/lib/Transforms/Instrumentation/EdgeProfiling.cpp b/lib/Transforms/Instrumentation/EdgeProfiling.cpp index 9ae3786..a77d70c 100644 --- a/lib/Transforms/Instrumentation/EdgeProfiling.cpp +++ b/lib/Transforms/Instrumentation/EdgeProfiling.cpp @@ -34,7 +34,7 @@ namespace { bool runOnModule(Module &M); public: static char ID; // Pass identification, replacement for typeid - EdgeProfiler() : ModulePass(&ID) {} + EdgeProfiler() : ModulePass(ID) {} virtual const char *getPassName() const { return "Edge Profiler"; @@ -43,8 +43,8 @@ namespace { } char EdgeProfiler::ID = 0; -static RegisterPass -X("insert-edge-profiling", "Insert instrumentation for edge profiling"); +INITIALIZE_PASS(EdgeProfiler, "insert-edge-profiling", + "Insert instrumentation for edge profiling", false, false); ModulePass *llvm::createEdgeProfilerPass() { return new EdgeProfiler(); } diff --git a/lib/Transforms/Instrumentation/OptimalEdgeProfiling.cpp b/lib/Transforms/Instrumentation/OptimalEdgeProfiling.cpp index 41e3a39..8eec987 100644 --- a/lib/Transforms/Instrumentation/OptimalEdgeProfiling.cpp +++ b/lib/Transforms/Instrumentation/OptimalEdgeProfiling.cpp @@ -36,7 +36,7 @@ namespace { bool runOnModule(Module &M); public: static char ID; // Pass identification, replacement for typeid - OptimalEdgeProfiler() : ModulePass(&ID) {} + OptimalEdgeProfiler() : ModulePass(ID) {} void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequiredID(ProfileEstimatorPassID); @@ -50,9 +50,9 @@ namespace { } char OptimalEdgeProfiler::ID = 0; -static RegisterPass -X("insert-optimal-edge-profiling", - "Insert optimal instrumentation for edge profiling"); +INITIALIZE_PASS(OptimalEdgeProfiler, "insert-optimal-edge-profiling", + "Insert optimal instrumentation for edge profiling", + false, false); ModulePass *llvm::createOptimalEdgeProfilerPass() { return new OptimalEdgeProfiler(); diff --git a/lib/Transforms/Scalar/ABCD.cpp b/lib/Transforms/Scalar/ABCD.cpp deleted file mode 100644 index dcf14a6..0000000 --- a/lib/Transforms/Scalar/ABCD.cpp +++ /dev/null @@ -1,1112 +0,0 @@ -//===------- ABCD.cpp - Removes redundant conditional branches ------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass removes redundant branch instructions. This algorithm was -// described by Rastislav Bodik, Rajiv Gupta and Vivek Sarkar in their paper -// "ABCD: Eliminating Array Bounds Checks on Demand (2000)". The original -// Algorithm was created to remove array bound checks for strongly typed -// languages. This implementation expands the idea and removes any conditional -// branches that can be proved redundant, not only those used in array bound -// checks. With the SSI representation, each variable has a -// constraint. By analyzing these constraints we can prove that a branch is -// redundant. When a branch is proved redundant it means that -// one direction will always be taken; thus, we can change this branch into an -// unconditional jump. -// It is advisable to run SimplifyCFG and Aggressive Dead Code Elimination -// after ABCD to clean up the code. -// This implementation was created based on the implementation of the ABCD -// algorithm implemented for the compiler Jitrino. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "abcd" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Constants.h" -#include "llvm/Function.h" -#include "llvm/Instructions.h" -#include "llvm/Pass.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Debug.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Utils/SSI.h" - -using namespace llvm; - -STATISTIC(NumBranchTested, "Number of conditional branches analyzed"); -STATISTIC(NumBranchRemoved, "Number of conditional branches removed"); - -namespace { - -class ABCD : public FunctionPass { - public: - static char ID; // Pass identification, replacement for typeid. - ABCD() : FunctionPass(&ID) {} - - void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - } - - bool runOnFunction(Function &F); - - private: - /// Keep track of whether we've modified the program yet. - bool modified; - - enum ProveResult { - False = 0, - Reduced = 1, - True = 2 - }; - - typedef ProveResult (*meet_function)(ProveResult, ProveResult); - static ProveResult max(ProveResult res1, ProveResult res2) { - return (ProveResult) std::max(res1, res2); - } - static ProveResult min(ProveResult res1, ProveResult res2) { - return (ProveResult) std::min(res1, res2); - } - - class Bound { - public: - Bound(APInt v, bool upper) : value(v), upper_bound(upper) {} - Bound(const Bound &b, int cnst) - : value(b.value - cnst), upper_bound(b.upper_bound) {} - Bound(const Bound &b, const APInt &cnst) - : value(b.value - cnst), upper_bound(b.upper_bound) {} - - /// Test if Bound is an upper bound - bool isUpperBound() const { return upper_bound; } - - /// Get the bitwidth of this bound - int32_t getBitWidth() const { return value.getBitWidth(); } - - /// Creates a Bound incrementing the one received - static Bound createIncrement(const Bound &b) { - return Bound(b.isUpperBound() ? b.value+1 : b.value-1, - b.upper_bound); - } - - /// Creates a Bound decrementing the one received - static Bound createDecrement(const Bound &b) { - return Bound(b.isUpperBound() ? b.value-1 : b.value+1, - b.upper_bound); - } - - /// Test if two bounds are equal - static bool eq(const Bound *a, const Bound *b) { - if (!a || !b) return false; - - assert(a->isUpperBound() == b->isUpperBound()); - return a->value == b->value; - } - - /// Test if val is less than or equal to Bound b - static bool leq(APInt val, const Bound &b) { - return b.isUpperBound() ? val.sle(b.value) : val.sge(b.value); - } - - /// Test if Bound a is less then or equal to Bound - static bool leq(const Bound &a, const Bound &b) { - assert(a.isUpperBound() == b.isUpperBound()); - return a.isUpperBound() ? a.value.sle(b.value) : - a.value.sge(b.value); - } - - /// Test if Bound a is less then Bound b - static bool lt(const Bound &a, const Bound &b) { - assert(a.isUpperBound() == b.isUpperBound()); - return a.isUpperBound() ? a.value.slt(b.value) : - a.value.sgt(b.value); - } - - /// Test if Bound b is greater then or equal val - static bool geq(const Bound &b, APInt val) { - return leq(val, b); - } - - /// Test if Bound a is greater then or equal Bound b - static bool geq(const Bound &a, const Bound &b) { - return leq(b, a); - } - - private: - APInt value; - bool upper_bound; - }; - - /// This class is used to store results some parts of the graph, - /// so information does not need to be recalculated. The maximum false, - /// minimum true and minimum reduced results are stored - class MemoizedResultChart { - public: - MemoizedResultChart() {} - MemoizedResultChart(const MemoizedResultChart &other) { - if (other.max_false) - max_false.reset(new Bound(*other.max_false)); - if (other.min_true) - min_true.reset(new Bound(*other.min_true)); - if (other.min_reduced) - min_reduced.reset(new Bound(*other.min_reduced)); - } - - /// Returns the max false - const Bound *getFalse() const { return max_false.get(); } - - /// Returns the min true - const Bound *getTrue() const { return min_true.get(); } - - /// Returns the min reduced - const Bound *getReduced() const { return min_reduced.get(); } - - /// Return the stored result for this bound - ProveResult getResult(const Bound &bound) const; - - /// Stores a false found - void addFalse(const Bound &bound); - - /// Stores a true found - void addTrue(const Bound &bound); - - /// Stores a Reduced found - void addReduced(const Bound &bound); - - /// Clears redundant reduced - /// If a min_true is smaller than a min_reduced then the min_reduced - /// is unnecessary and then removed. It also works for min_reduced - /// begin smaller than max_false. - void clearRedundantReduced(); - - void clear() { - max_false.reset(); - min_true.reset(); - min_reduced.reset(); - } - - private: - OwningPtr max_false, min_true, min_reduced; - }; - - /// This class stores the result found for a node of the graph, - /// so these results do not need to be recalculated, only searched for. - class MemoizedResult { - public: - /// Test if there is true result stored from b to a - /// that is less then the bound - bool hasTrue(Value *b, const Bound &bound) const { - const Bound *trueBound = map.lookup(b).getTrue(); - return trueBound && Bound::leq(*trueBound, bound); - } - - /// Test if there is false result stored from b to a - /// that is less then the bound - bool hasFalse(Value *b, const Bound &bound) const { - const Bound *falseBound = map.lookup(b).getFalse(); - return falseBound && Bound::leq(*falseBound, bound); - } - - /// Test if there is reduced result stored from b to a - /// that is less then the bound - bool hasReduced(Value *b, const Bound &bound) const { - const Bound *reducedBound = map.lookup(b).getReduced(); - return reducedBound && Bound::leq(*reducedBound, bound); - } - - /// Returns the stored bound for b - ProveResult getBoundResult(Value *b, const Bound &bound) { - return map[b].getResult(bound); - } - - /// Clears the map - void clear() { - DenseMapIterator begin = map.begin(); - DenseMapIterator end = map.end(); - for (; begin != end; ++begin) { - begin->second.clear(); - } - map.clear(); - } - - /// Stores the bound found - void updateBound(Value *b, const Bound &bound, const ProveResult res); - - private: - // Maps a nod in the graph with its results found. - DenseMap map; - }; - - /// This class represents an edge in the inequality graph used by the - /// ABCD algorithm. An edge connects node v to node u with a value c if - /// we could infer a constraint v <= u + c in the source program. - class Edge { - public: - Edge(Value *V, APInt val, bool upper) - : vertex(V), value(val), upper_bound(upper) {} - - Value *getVertex() const { return vertex; } - const APInt &getValue() const { return value; } - bool isUpperBound() const { return upper_bound; } - - private: - Value *vertex; - APInt value; - bool upper_bound; - }; - - /// Weighted and Directed graph to represent constraints. - /// There is one type of constraint, a <= b + X, which will generate an - /// edge from b to a with weight X. - class InequalityGraph { - public: - - /// Adds an edge from V_from to V_to with weight value - void addEdge(Value *V_from, Value *V_to, APInt value, bool upper); - - /// Test if there is a node V - bool hasNode(Value *V) const { return graph.count(V); } - - /// Test if there is any edge from V in the upper direction - bool hasEdge(Value *V, bool upper) const; - - /// Returns all edges pointed by vertex V - SmallVector getEdges(Value *V) const { - return graph.lookup(V); - } - - /// Prints the graph in dot format. - /// Blue edges represent upper bound and Red lower bound. - void printGraph(raw_ostream &OS, Function &F) const { - printHeader(OS, F); - printBody(OS); - printFooter(OS); - } - - /// Clear the graph - void clear() { - graph.clear(); - } - - private: - DenseMap > graph; - - /// Prints the header of the dot file - void printHeader(raw_ostream &OS, Function &F) const; - - /// Prints the footer of the dot file - void printFooter(raw_ostream &OS) const { - OS << "}\n"; - } - - /// Prints the body of the dot file - void printBody(raw_ostream &OS) const; - - /// Prints vertex source to the dot file - void printVertex(raw_ostream &OS, Value *source) const; - - /// Prints the edge to the dot file - void printEdge(raw_ostream &OS, Value *source, const Edge &edge) const; - - void printName(raw_ostream &OS, Value *info) const; - }; - - /// Iterates through all BasicBlocks, if the Terminator Instruction - /// uses an Comparator Instruction, all operands of this comparator - /// are sent to be transformed to SSI. Only Instruction operands are - /// transformed. - void createSSI(Function &F); - - /// Creates the graphs for this function. - /// It will look for all comparators used in branches, and create them. - /// These comparators will create constraints for any instruction as an - /// operand. - void executeABCD(Function &F); - - /// Seeks redundancies in the comparator instruction CI. - /// If the ABCD algorithm can prove that the comparator CI always - /// takes one way, then the Terminator Instruction TI is substituted from - /// a conditional branch to a unconditional one. - /// This code basically receives a comparator, and verifies which kind of - /// instruction it is. Depending on the kind of instruction, we use different - /// strategies to prove its redundancy. - void seekRedundancy(ICmpInst *ICI, TerminatorInst *TI); - - /// Substitutes Terminator Instruction TI, that is a conditional branch, - /// with one unconditional branch. Succ_edge determines if the new - /// unconditional edge will be the first or second edge of the former TI - /// instruction. - void removeRedundancy(TerminatorInst *TI, bool Succ_edge); - - /// When an conditional branch is removed, the BasicBlock that is no longer - /// reachable will have problems in phi functions. This method fixes these - /// phis removing the former BasicBlock from the list of incoming BasicBlocks - /// of all phis. In case the phi remains with no predecessor it will be - /// marked to be removed later. - void fixPhi(BasicBlock *BB, BasicBlock *Succ); - - /// Removes phis that have no predecessor - void removePhis(); - - /// Creates constraints for Instructions. - /// If the constraint for this instruction has already been created - /// nothing is done. - void createConstraintInstruction(Instruction *I); - - /// Creates constraints for Binary Operators. - /// It will create constraints only for addition and subtraction, - /// the other binary operations are not treated by ABCD. - /// For additions in the form a = b + X and a = X + b, where X is a constant, - /// the constraint a <= b + X can be obtained. For this constraint, an edge - /// a->b with weight X is added to the lower bound graph, and an edge - /// b->a with weight -X is added to the upper bound graph. - /// Only subtractions in the format a = b - X is used by ABCD. - /// Edges are created using the same semantic as addition. - void createConstraintBinaryOperator(BinaryOperator *BO); - - /// Creates constraints for Comparator Instructions. - /// Only comparators that have any of the following operators - /// are used to create constraints: >=, >, <=, <. And only if - /// at least one operand is an Instruction. In a Comparator Instruction - /// a op b, there will be 4 sigma functions a_t, a_f, b_t and b_f. Where - /// t and f represent sigma for operands in true and false branches. The - /// following constraints can be obtained. a_t <= a, a_f <= a, b_t <= b and - /// b_f <= b. There are two more constraints that depend on the operator. - /// For the operator <= : a_t <= b_t and b_f <= a_f-1 - /// For the operator < : a_t <= b_t-1 and b_f <= a_f - /// For the operator >= : b_t <= a_t and a_f <= b_f-1 - /// For the operator > : b_t <= a_t-1 and a_f <= b_f - void createConstraintCmpInst(ICmpInst *ICI, TerminatorInst *TI); - - /// Creates constraints for PHI nodes. - /// In a PHI node a = phi(b,c) we can create the constraint - /// a<= max(b,c). With this constraint there will be the edges, - /// b->a and c->a with weight 0 in the lower bound graph, and the edges - /// a->b and a->c with weight 0 in the upper bound graph. - void createConstraintPHINode(PHINode *PN); - - /// Given a binary operator, we are only interest in the case - /// that one operand is an Instruction and the other is a ConstantInt. In - /// this case the method returns true, otherwise false. It also obtains the - /// Instruction and ConstantInt from the BinaryOperator and returns it. - bool createBinaryOperatorInfo(BinaryOperator *BO, Instruction **I1, - Instruction **I2, ConstantInt **C1, - ConstantInt **C2); - - /// This method creates a constraint between a Sigma and an Instruction. - /// These constraints are created as soon as we find a comparator that uses a - /// SSI variable. - void createConstraintSigInst(Instruction *I_op, BasicBlock *BB_succ_t, - BasicBlock *BB_succ_f, PHINode **SIG_op_t, - PHINode **SIG_op_f); - - /// If PN_op1 and PN_o2 are different from NULL, create a constraint - /// PN_op2 -> PN_op1 with value. In case any of them is NULL, replace - /// with the respective V_op#, if V_op# is a ConstantInt. - void createConstraintSigSig(PHINode *SIG_op1, PHINode *SIG_op2, - ConstantInt *V_op1, ConstantInt *V_op2, - APInt value); - - /// Returns the sigma representing the Instruction I in BasicBlock BB. - /// Returns NULL in case there is no sigma for this Instruction in this - /// Basic Block. This methods assume that sigmas are the first instructions - /// in a block, and that there can be only two sigmas in a block. So it will - /// only look on the first two instructions of BasicBlock BB. - PHINode *findSigma(BasicBlock *BB, Instruction *I); - - /// Original ABCD algorithm to prove redundant checks. - /// This implementation works on any kind of inequality branch. - bool demandProve(Value *a, Value *b, int c, bool upper_bound); - - /// Prove that distance between b and a is <= bound - ProveResult prove(Value *a, Value *b, const Bound &bound, unsigned level); - - /// Updates the distance value for a and b - void updateMemDistance(Value *a, Value *b, const Bound &bound, unsigned level, - meet_function meet); - - InequalityGraph inequality_graph; - MemoizedResult mem_result; - DenseMap active; - SmallPtrSet created; - SmallVector phis_to_remove; -}; - -} // end anonymous namespace. - -char ABCD::ID = 0; -static RegisterPass X("abcd", "ABCD: Eliminating Array Bounds Checks on Demand"); - - -bool ABCD::runOnFunction(Function &F) { - modified = false; - createSSI(F); - executeABCD(F); - DEBUG(inequality_graph.printGraph(dbgs(), F)); - removePhis(); - - inequality_graph.clear(); - mem_result.clear(); - active.clear(); - created.clear(); - phis_to_remove.clear(); - return modified; -} - -/// Iterates through all BasicBlocks, if the Terminator Instruction -/// uses an Comparator Instruction, all operands of this comparator -/// are sent to be transformed to SSI. Only Instruction operands are -/// transformed. -void ABCD::createSSI(Function &F) { - SSI *ssi = &getAnalysis(); - - SmallVector Insts; - - for (Function::iterator begin = F.begin(), end = F.end(); - begin != end; ++begin) { - BasicBlock *BB = begin; - TerminatorInst *TI = BB->getTerminator(); - if (TI->getNumOperands() == 0) - continue; - - if (ICmpInst *ICI = dyn_cast(TI->getOperand(0))) { - if (Instruction *I = dyn_cast(ICI->getOperand(0))) { - modified = true; // XXX: but yet createSSI might do nothing - Insts.push_back(I); - } - if (Instruction *I = dyn_cast(ICI->getOperand(1))) { - modified = true; - Insts.push_back(I); - } - } - } - ssi->createSSI(Insts); -} - -/// Creates the graphs for this function. -/// It will look for all comparators used in branches, and create them. -/// These comparators will create constraints for any instruction as an -/// operand. -void ABCD::executeABCD(Function &F) { - for (Function::iterator begin = F.begin(), end = F.end(); - begin != end; ++begin) { - BasicBlock *BB = begin; - TerminatorInst *TI = BB->getTerminator(); - if (TI->getNumOperands() == 0) - continue; - - ICmpInst *ICI = dyn_cast(TI->getOperand(0)); - if (!ICI || !ICI->getOperand(0)->getType()->isIntegerTy()) - continue; - - createConstraintCmpInst(ICI, TI); - seekRedundancy(ICI, TI); - } -} - -/// Seeks redundancies in the comparator instruction CI. -/// If the ABCD algorithm can prove that the comparator CI always -/// takes one way, then the Terminator Instruction TI is substituted from -/// a conditional branch to a unconditional one. -/// This code basically receives a comparator, and verifies which kind of -/// instruction it is. Depending on the kind of instruction, we use different -/// strategies to prove its redundancy. -void ABCD::seekRedundancy(ICmpInst *ICI, TerminatorInst *TI) { - CmpInst::Predicate Pred = ICI->getPredicate(); - - Value *source, *dest; - int distance1, distance2; - bool upper; - - switch(Pred) { - case CmpInst::ICMP_SGT: // signed greater than - upper = false; - distance1 = 1; - distance2 = 0; - break; - - case CmpInst::ICMP_SGE: // signed greater or equal - upper = false; - distance1 = 0; - distance2 = -1; - break; - - case CmpInst::ICMP_SLT: // signed less than - upper = true; - distance1 = -1; - distance2 = 0; - break; - - case CmpInst::ICMP_SLE: // signed less or equal - upper = true; - distance1 = 0; - distance2 = 1; - break; - - default: - return; - } - - ++NumBranchTested; - source = ICI->getOperand(0); - dest = ICI->getOperand(1); - if (demandProve(dest, source, distance1, upper)) { - removeRedundancy(TI, true); - } else if (demandProve(dest, source, distance2, !upper)) { - removeRedundancy(TI, false); - } -} - -/// Substitutes Terminator Instruction TI, that is a conditional branch, -/// with one unconditional branch. Succ_edge determines if the new -/// unconditional edge will be the first or second edge of the former TI -/// instruction. -void ABCD::removeRedundancy(TerminatorInst *TI, bool Succ_edge) { - BasicBlock *Succ; - if (Succ_edge) { - Succ = TI->getSuccessor(0); - fixPhi(TI->getParent(), TI->getSuccessor(1)); - } else { - Succ = TI->getSuccessor(1); - fixPhi(TI->getParent(), TI->getSuccessor(0)); - } - - BranchInst::Create(Succ, TI); - TI->eraseFromParent(); // XXX: invoke - ++NumBranchRemoved; - modified = true; -} - -/// When an conditional branch is removed, the BasicBlock that is no longer -/// reachable will have problems in phi functions. This method fixes these -/// phis removing the former BasicBlock from the list of incoming BasicBlocks -/// of all phis. In case the phi remains with no predecessor it will be -/// marked to be removed later. -void ABCD::fixPhi(BasicBlock *BB, BasicBlock *Succ) { - BasicBlock::iterator begin = Succ->begin(); - while (PHINode *PN = dyn_cast(begin++)) { - PN->removeIncomingValue(BB, false); - if (PN->getNumIncomingValues() == 0) - phis_to_remove.push_back(PN); - } -} - -/// Removes phis that have no predecessor -void ABCD::removePhis() { - for (unsigned i = 0, e = phis_to_remove.size(); i != e; ++i) { - PHINode *PN = phis_to_remove[i]; - PN->replaceAllUsesWith(UndefValue::get(PN->getType())); - PN->eraseFromParent(); - } -} - -/// Creates constraints for Instructions. -/// If the constraint for this instruction has already been created -/// nothing is done. -void ABCD::createConstraintInstruction(Instruction *I) { - // Test if this instruction has not been created before - if (created.insert(I)) { - if (BinaryOperator *BO = dyn_cast(I)) { - createConstraintBinaryOperator(BO); - } else if (PHINode *PN = dyn_cast(I)) { - createConstraintPHINode(PN); - } - } -} - -/// Creates constraints for Binary Operators. -/// It will create constraints only for addition and subtraction, -/// the other binary operations are not treated by ABCD. -/// For additions in the form a = b + X and a = X + b, where X is a constant, -/// the constraint a <= b + X can be obtained. For this constraint, an edge -/// a->b with weight X is added to the lower bound graph, and an edge -/// b->a with weight -X is added to the upper bound graph. -/// Only subtractions in the format a = b - X is used by ABCD. -/// Edges are created using the same semantic as addition. -void ABCD::createConstraintBinaryOperator(BinaryOperator *BO) { - Instruction *I1 = NULL, *I2 = NULL; - ConstantInt *CI1 = NULL, *CI2 = NULL; - - // Test if an operand is an Instruction and the other is a Constant - if (!createBinaryOperatorInfo(BO, &I1, &I2, &CI1, &CI2)) - return; - - Instruction *I = 0; - APInt value; - - switch (BO->getOpcode()) { - case Instruction::Add: - if (I1) { - I = I1; - value = CI2->getValue(); - } else if (I2) { - I = I2; - value = CI1->getValue(); - } - break; - - case Instruction::Sub: - // Instructions like a = X-b, where X is a constant are not represented - // in the graph. - if (!I1) - return; - - I = I1; - value = -CI2->getValue(); - break; - - default: - return; - } - - inequality_graph.addEdge(I, BO, value, true); - inequality_graph.addEdge(BO, I, -value, false); - createConstraintInstruction(I); -} - -/// Given a binary operator, we are only interest in the case -/// that one operand is an Instruction and the other is a ConstantInt. In -/// this case the method returns true, otherwise false. It also obtains the -/// Instruction and ConstantInt from the BinaryOperator and returns it. -bool ABCD::createBinaryOperatorInfo(BinaryOperator *BO, Instruction **I1, - Instruction **I2, ConstantInt **C1, - ConstantInt **C2) { - Value *op1 = BO->getOperand(0); - Value *op2 = BO->getOperand(1); - - if ((*I1 = dyn_cast(op1))) { - if ((*C2 = dyn_cast(op2))) - return true; // First is Instruction and second ConstantInt - - return false; // Both are Instruction - } else { - if ((*C1 = dyn_cast(op1)) && - (*I2 = dyn_cast(op2))) - return true; // First is ConstantInt and second Instruction - - return false; // Both are not Instruction - } -} - -/// Creates constraints for Comparator Instructions. -/// Only comparators that have any of the following operators -/// are used to create constraints: >=, >, <=, <. And only if -/// at least one operand is an Instruction. In a Comparator Instruction -/// a op b, there will be 4 sigma functions a_t, a_f, b_t and b_f. Where -/// t and f represent sigma for operands in true and false branches. The -/// following constraints can be obtained. a_t <= a, a_f <= a, b_t <= b and -/// b_f <= b. There are two more constraints that depend on the operator. -/// For the operator <= : a_t <= b_t and b_f <= a_f-1 -/// For the operator < : a_t <= b_t-1 and b_f <= a_f -/// For the operator >= : b_t <= a_t and a_f <= b_f-1 -/// For the operator > : b_t <= a_t-1 and a_f <= b_f -void ABCD::createConstraintCmpInst(ICmpInst *ICI, TerminatorInst *TI) { - Value *V_op1 = ICI->getOperand(0); - Value *V_op2 = ICI->getOperand(1); - - if (!V_op1->getType()->isIntegerTy()) - return; - - Instruction *I_op1 = dyn_cast(V_op1); - Instruction *I_op2 = dyn_cast(V_op2); - - // Test if at least one operand is an Instruction - if (!I_op1 && !I_op2) - return; - - BasicBlock *BB_succ_t = TI->getSuccessor(0); - BasicBlock *BB_succ_f = TI->getSuccessor(1); - - PHINode *SIG_op1_t = NULL, *SIG_op1_f = NULL, - *SIG_op2_t = NULL, *SIG_op2_f = NULL; - - createConstraintSigInst(I_op1, BB_succ_t, BB_succ_f, &SIG_op1_t, &SIG_op1_f); - createConstraintSigInst(I_op2, BB_succ_t, BB_succ_f, &SIG_op2_t, &SIG_op2_f); - - int32_t width = cast(V_op1->getType())->getBitWidth(); - APInt MinusOne = APInt::getAllOnesValue(width); - APInt Zero = APInt::getNullValue(width); - - CmpInst::Predicate Pred = ICI->getPredicate(); - ConstantInt *CI1 = dyn_cast(V_op1); - ConstantInt *CI2 = dyn_cast(V_op2); - switch (Pred) { - case CmpInst::ICMP_SGT: // signed greater than - createConstraintSigSig(SIG_op2_t, SIG_op1_t, CI2, CI1, MinusOne); - createConstraintSigSig(SIG_op1_f, SIG_op2_f, CI1, CI2, Zero); - break; - - case CmpInst::ICMP_SGE: // signed greater or equal - createConstraintSigSig(SIG_op2_t, SIG_op1_t, CI2, CI1, Zero); - createConstraintSigSig(SIG_op1_f, SIG_op2_f, CI1, CI2, MinusOne); - break; - - case CmpInst::ICMP_SLT: // signed less than - createConstraintSigSig(SIG_op1_t, SIG_op2_t, CI1, CI2, MinusOne); - createConstraintSigSig(SIG_op2_f, SIG_op1_f, CI2, CI1, Zero); - break; - - case CmpInst::ICMP_SLE: // signed less or equal - createConstraintSigSig(SIG_op1_t, SIG_op2_t, CI1, CI2, Zero); - createConstraintSigSig(SIG_op2_f, SIG_op1_f, CI2, CI1, MinusOne); - break; - - default: - break; - } - - if (I_op1) - createConstraintInstruction(I_op1); - if (I_op2) - createConstraintInstruction(I_op2); -} - -/// Creates constraints for PHI nodes. -/// In a PHI node a = phi(b,c) we can create the constraint -/// a<= max(b,c). With this constraint there will be the edges, -/// b->a and c->a with weight 0 in the lower bound graph, and the edges -/// a->b and a->c with weight 0 in the upper bound graph. -void ABCD::createConstraintPHINode(PHINode *PN) { - // FIXME: We really want to disallow sigma nodes, but I don't know the best - // way to detect the other than this. - if (PN->getNumOperands() == 2) return; - - int32_t width = cast(PN->getType())->getBitWidth(); - for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { - Value *V = PN->getIncomingValue(i); - if (Instruction *I = dyn_cast(V)) { - createConstraintInstruction(I); - } - inequality_graph.addEdge(V, PN, APInt(width, 0), true); - inequality_graph.addEdge(V, PN, APInt(width, 0), false); - } -} - -/// This method creates a constraint between a Sigma and an Instruction. -/// These constraints are created as soon as we find a comparator that uses a -/// SSI variable. -void ABCD::createConstraintSigInst(Instruction *I_op, BasicBlock *BB_succ_t, - BasicBlock *BB_succ_f, PHINode **SIG_op_t, - PHINode **SIG_op_f) { - *SIG_op_t = findSigma(BB_succ_t, I_op); - *SIG_op_f = findSigma(BB_succ_f, I_op); - - if (*SIG_op_t) { - int32_t width = cast((*SIG_op_t)->getType())->getBitWidth(); - inequality_graph.addEdge(I_op, *SIG_op_t, APInt(width, 0), true); - inequality_graph.addEdge(*SIG_op_t, I_op, APInt(width, 0), false); - } - if (*SIG_op_f) { - int32_t width = cast((*SIG_op_f)->getType())->getBitWidth(); - inequality_graph.addEdge(I_op, *SIG_op_f, APInt(width, 0), true); - inequality_graph.addEdge(*SIG_op_f, I_op, APInt(width, 0), false); - } -} - -/// If PN_op1 and PN_o2 are different from NULL, create a constraint -/// PN_op2 -> PN_op1 with value. In case any of them is NULL, replace -/// with the respective V_op#, if V_op# is a ConstantInt. -void ABCD::createConstraintSigSig(PHINode *SIG_op1, PHINode *SIG_op2, - ConstantInt *V_op1, ConstantInt *V_op2, - APInt value) { - if (SIG_op1 && SIG_op2) { - inequality_graph.addEdge(SIG_op2, SIG_op1, value, true); - inequality_graph.addEdge(SIG_op1, SIG_op2, -value, false); - } else if (SIG_op1 && V_op2) { - inequality_graph.addEdge(V_op2, SIG_op1, value, true); - inequality_graph.addEdge(SIG_op1, V_op2, -value, false); - } else if (SIG_op2 && V_op1) { - inequality_graph.addEdge(SIG_op2, V_op1, value, true); - inequality_graph.addEdge(V_op1, SIG_op2, -value, false); - } -} - -/// Returns the sigma representing the Instruction I in BasicBlock BB. -/// Returns NULL in case there is no sigma for this Instruction in this -/// Basic Block. This methods assume that sigmas are the first instructions -/// in a block, and that there can be only two sigmas in a block. So it will -/// only look on the first two instructions of BasicBlock BB. -PHINode *ABCD::findSigma(BasicBlock *BB, Instruction *I) { - // BB has more than one predecessor, BB cannot have sigmas. - if (I == NULL || BB->getSinglePredecessor() == NULL) - return NULL; - - BasicBlock::iterator begin = BB->begin(); - BasicBlock::iterator end = BB->end(); - - for (unsigned i = 0; i < 2 && begin != end; ++i, ++begin) { - Instruction *I_succ = begin; - if (PHINode *PN = dyn_cast(I_succ)) - if (PN->getIncomingValue(0) == I) - return PN; - } - - return NULL; -} - -/// Original ABCD algorithm to prove redundant checks. -/// This implementation works on any kind of inequality branch. -bool ABCD::demandProve(Value *a, Value *b, int c, bool upper_bound) { - int32_t width = cast(a->getType())->getBitWidth(); - Bound bound(APInt(width, c), upper_bound); - - mem_result.clear(); - active.clear(); - - ProveResult res = prove(a, b, bound, 0); - return res != False; -} - -/// Prove that distance between b and a is <= bound -ABCD::ProveResult ABCD::prove(Value *a, Value *b, const Bound &bound, - unsigned level) { - // if (C[b-a<=e] == True for some e <= bound - // Same or stronger difference was already proven - if (mem_result.hasTrue(b, bound)) - return True; - - // if (C[b-a<=e] == False for some e >= bound - // Same or weaker difference was already disproved - if (mem_result.hasFalse(b, bound)) - return False; - - // if (C[b-a<=e] == Reduced for some e <= bound - // b is on a cycle that was reduced for same or stronger difference - if (mem_result.hasReduced(b, bound)) - return Reduced; - - // traversal reached the source vertex - if (a == b && Bound::geq(bound, APInt(bound.getBitWidth(), 0, true))) - return True; - - // if b has no predecessor then fail - if (!inequality_graph.hasEdge(b, bound.isUpperBound())) - return False; - - // a cycle was encountered - if (active.count(b)) { - if (Bound::leq(*active.lookup(b), bound)) - return Reduced; // a "harmless" cycle - - return False; // an amplifying cycle - } - - active[b] = &bound; - PHINode *PN = dyn_cast(b); - - // Test if a Value is a Phi. If it is a PHINode with more than 1 incoming - // value, then it is a phi, if it has 1 incoming value it is a sigma. - if (PN && PN->getNumIncomingValues() > 1) - updateMemDistance(a, b, bound, level, min); - else - updateMemDistance(a, b, bound, level, max); - - active.erase(b); - - ABCD::ProveResult res = mem_result.getBoundResult(b, bound); - return res; -} - -/// Updates the distance value for a and b -void ABCD::updateMemDistance(Value *a, Value *b, const Bound &bound, - unsigned level, meet_function meet) { - ABCD::ProveResult res = (meet == max) ? False : True; - - SmallVector Edges = inequality_graph.getEdges(b); - SmallVector::iterator begin = Edges.begin(), end = Edges.end(); - - for (; begin != end ; ++begin) { - if (((res >= Reduced) && (meet == max)) || - ((res == False) && (meet == min))) { - break; - } - const Edge &in = *begin; - if (in.isUpperBound() == bound.isUpperBound()) { - Value *succ = in.getVertex(); - res = meet(res, prove(a, succ, Bound(bound, in.getValue()), - level+1)); - } - } - - mem_result.updateBound(b, bound, res); -} - -/// Return the stored result for this bound -ABCD::ProveResult ABCD::MemoizedResultChart::getResult(const Bound &bound)const{ - if (max_false && Bound::leq(bound, *max_false)) - return False; - if (min_true && Bound::leq(*min_true, bound)) - return True; - if (min_reduced && Bound::leq(*min_reduced, bound)) - return Reduced; - return False; -} - -/// Stores a false found -void ABCD::MemoizedResultChart::addFalse(const Bound &bound) { - if (!max_false || Bound::leq(*max_false, bound)) - max_false.reset(new Bound(bound)); - - if (Bound::eq(max_false.get(), min_reduced.get())) - min_reduced.reset(new Bound(Bound::createIncrement(*min_reduced))); - if (Bound::eq(max_false.get(), min_true.get())) - min_true.reset(new Bound(Bound::createIncrement(*min_true))); - if (Bound::eq(min_reduced.get(), min_true.get())) - min_reduced.reset(); - clearRedundantReduced(); -} - -/// Stores a true found -void ABCD::MemoizedResultChart::addTrue(const Bound &bound) { - if (!min_true || Bound::leq(bound, *min_true)) - min_true.reset(new Bound(bound)); - - if (Bound::eq(min_true.get(), min_reduced.get())) - min_reduced.reset(new Bound(Bound::createDecrement(*min_reduced))); - if (Bound::eq(min_true.get(), max_false.get())) - max_false.reset(new Bound(Bound::createDecrement(*max_false))); - if (Bound::eq(max_false.get(), min_reduced.get())) - min_reduced.reset(); - clearRedundantReduced(); -} - -/// Stores a Reduced found -void ABCD::MemoizedResultChart::addReduced(const Bound &bound) { - if (!min_reduced || Bound::leq(bound, *min_reduced)) - min_reduced.reset(new Bound(bound)); - - if (Bound::eq(min_reduced.get(), min_true.get())) - min_true.reset(new Bound(Bound::createIncrement(*min_true))); - if (Bound::eq(min_reduced.get(), max_false.get())) - max_false.reset(new Bound(Bound::createDecrement(*max_false))); -} - -/// Clears redundant reduced -/// If a min_true is smaller than a min_reduced then the min_reduced -/// is unnecessary and then removed. It also works for min_reduced -/// begin smaller than max_false. -void ABCD::MemoizedResultChart::clearRedundantReduced() { - if (min_true && min_reduced && Bound::lt(*min_true, *min_reduced)) - min_reduced.reset(); - if (max_false && min_reduced && Bound::lt(*min_reduced, *max_false)) - min_reduced.reset(); -} - -/// Stores the bound found -void ABCD::MemoizedResult::updateBound(Value *b, const Bound &bound, - const ProveResult res) { - if (res == False) { - map[b].addFalse(bound); - } else if (res == True) { - map[b].addTrue(bound); - } else { - map[b].addReduced(bound); - } -} - -/// Adds an edge from V_from to V_to with weight value -void ABCD::InequalityGraph::addEdge(Value *V_to, Value *V_from, - APInt value, bool upper) { - assert(V_from->getType() == V_to->getType()); - assert(cast(V_from->getType())->getBitWidth() == - value.getBitWidth()); - - graph[V_from].push_back(Edge(V_to, value, upper)); -} - -/// Test if there is any edge from V in the upper direction -bool ABCD::InequalityGraph::hasEdge(Value *V, bool upper) const { - SmallVector it = graph.lookup(V); - - SmallVector::iterator begin = it.begin(); - SmallVector::iterator end = it.end(); - for (; begin != end; ++begin) { - if (begin->isUpperBound() == upper) { - return true; - } - } - return false; -} - -/// Prints the header of the dot file -void ABCD::InequalityGraph::printHeader(raw_ostream &OS, Function &F) const { - OS << "digraph dotgraph {\n"; - OS << "label=\"Inequality Graph for \'"; - OS << F.getNameStr() << "\' function\";\n"; - OS << "node [shape=record,fontname=\"Times-Roman\",fontsize=14];\n"; -} - -/// Prints the body of the dot file -void ABCD::InequalityGraph::printBody(raw_ostream &OS) const { - DenseMap >::const_iterator begin = - graph.begin(), end = graph.end(); - - for (; begin != end ; ++begin) { - SmallVector::const_iterator begin_par = - begin->second.begin(), end_par = begin->second.end(); - Value *source = begin->first; - - printVertex(OS, source); - - for (; begin_par != end_par ; ++begin_par) { - const Edge &edge = *begin_par; - printEdge(OS, source, edge); - } - } -} - -/// Prints vertex source to the dot file -/// -void ABCD::InequalityGraph::printVertex(raw_ostream &OS, Value *source) const { - OS << "\""; - printName(OS, source); - OS << "\""; - OS << " [label=\"{"; - printName(OS, source); - OS << "}\"];\n"; -} - -/// Prints the edge to the dot file -void ABCD::InequalityGraph::printEdge(raw_ostream &OS, Value *source, - const Edge &edge) const { - Value *dest = edge.getVertex(); - APInt value = edge.getValue(); - bool upper = edge.isUpperBound(); - - OS << "\""; - printName(OS, source); - OS << "\""; - OS << " -> "; - OS << "\""; - printName(OS, dest); - OS << "\""; - OS << " [label=\"" << value << "\""; - if (upper) { - OS << "color=\"blue\""; - } else { - OS << "color=\"red\""; - } - OS << "];\n"; -} - -void ABCD::InequalityGraph::printName(raw_ostream &OS, Value *info) const { - if (ConstantInt *CI = dyn_cast(info)) { - OS << *CI; - } else { - if (!info->hasName()) { - info->setName("V"); - } - OS << info->getNameStr(); - } -} - -/// createABCDPass - The public interface to this file... -FunctionPass *llvm::createABCDPass() { - return new ABCD(); -} diff --git a/lib/Transforms/Scalar/ADCE.cpp b/lib/Transforms/Scalar/ADCE.cpp index 2d19467..ada086e 100644 --- a/lib/Transforms/Scalar/ADCE.cpp +++ b/lib/Transforms/Scalar/ADCE.cpp @@ -33,7 +33,7 @@ STATISTIC(NumRemoved, "Number of instructions removed"); namespace { struct ADCE : public FunctionPass { static char ID; // Pass identification, replacement for typeid - ADCE() : FunctionPass(&ID) {} + ADCE() : FunctionPass(ID) {} virtual bool runOnFunction(Function& F); @@ -45,7 +45,7 @@ namespace { } char ADCE::ID = 0; -static RegisterPass X("adce", "Aggressive Dead Code Elimination"); +INITIALIZE_PASS(ADCE, "adce", "Aggressive Dead Code Elimination", false, false); bool ADCE::runOnFunction(Function& F) { SmallPtrSet alive; diff --git a/lib/Transforms/Scalar/BasicBlockPlacement.cpp b/lib/Transforms/Scalar/BasicBlockPlacement.cpp index 54533f5..b144678 100644 --- a/lib/Transforms/Scalar/BasicBlockPlacement.cpp +++ b/lib/Transforms/Scalar/BasicBlockPlacement.cpp @@ -41,7 +41,7 @@ STATISTIC(NumMoved, "Number of basic blocks moved"); namespace { struct BlockPlacement : public FunctionPass { static char ID; // Pass identification, replacement for typeid - BlockPlacement() : FunctionPass(&ID) {} + BlockPlacement() : FunctionPass(ID) {} virtual bool runOnFunction(Function &F); @@ -74,8 +74,8 @@ namespace { } char BlockPlacement::ID = 0; -static RegisterPass -X("block-placement", "Profile Guided Basic Block Placement"); +INITIALIZE_PASS(BlockPlacement, "block-placement", + "Profile Guided Basic Block Placement", false, false); FunctionPass *llvm::createBlockPlacementPass() { return new BlockPlacement(); } diff --git a/lib/Transforms/Scalar/CMakeLists.txt b/lib/Transforms/Scalar/CMakeLists.txt index 1a3b10c..b7598ea 100644 --- a/lib/Transforms/Scalar/CMakeLists.txt +++ b/lib/Transforms/Scalar/CMakeLists.txt @@ -1,9 +1,9 @@ add_llvm_library(LLVMScalarOpts - ABCD.cpp ADCE.cpp BasicBlockPlacement.cpp CodeGenPrepare.cpp ConstantProp.cpp + CorrelatedValuePropagation.cpp DCE.cpp DeadStoreElimination.cpp GEPSplitter.cpp @@ -17,6 +17,7 @@ add_llvm_library(LLVMScalarOpts LoopStrengthReduce.cpp LoopUnrollPass.cpp LoopUnswitch.cpp + LowerAtomic.cpp MemCpyOptimizer.cpp Reassociate.cpp Reg2Mem.cpp diff --git a/lib/Transforms/Scalar/CodeGenPrepare.cpp b/lib/Transforms/Scalar/CodeGenPrepare.cpp index 272066c..e07b761 100644 --- a/lib/Transforms/Scalar/CodeGenPrepare.cpp +++ b/lib/Transforms/Scalar/CodeGenPrepare.cpp @@ -33,6 +33,7 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/Assembly/Writer.h" #include "llvm/Support/CallSite.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/PatternMatch.h" @@ -41,6 +42,11 @@ using namespace llvm; using namespace llvm::PatternMatch; +static cl::opt +CriticalEdgeSplit("cgp-critical-edge-splitting", + cl::desc("Split critical edges during codegen prepare"), + cl::init(true), cl::Hidden); + namespace { class CodeGenPrepare : public FunctionPass { /// TLI - Keep a pointer of a TargetLowering to consult for determining @@ -54,7 +60,7 @@ namespace { public: static char ID; // Pass identification, replacement for typeid explicit CodeGenPrepare(const TargetLowering *tli = 0) - : FunctionPass(&ID), TLI(tli) {} + : FunctionPass(ID), TLI(tli) {} bool runOnFunction(Function &F); virtual void getAnalysisUsage(AnalysisUsage &AU) const { @@ -82,8 +88,8 @@ namespace { } char CodeGenPrepare::ID = 0; -static RegisterPass X("codegenprepare", - "Optimize for code generation"); +INITIALIZE_PASS(CodeGenPrepare, "codegenprepare", + "Optimize for code generation", false, false); FunctionPass *llvm::createCodeGenPreparePass(const TargetLowering *TLI) { return new CodeGenPrepare(TLI); @@ -427,9 +433,9 @@ static bool OptimizeNoopCopyExpression(CastInst *CI, const TargetLowering &TLI){ // If these values will be promoted, find out what they will be promoted // to. This helps us consider truncates on PPC as noop copies when they // are. - if (TLI.getTypeAction(CI->getContext(), SrcVT) == TargetLowering::Promote) + if (TLI.getTypeAction(SrcVT) == TargetLowering::Promote) SrcVT = TLI.getTypeToTransformTo(CI->getContext(), SrcVT); - if (TLI.getTypeAction(CI->getContext(), DstVT) == TargetLowering::Promote) + if (TLI.getTypeAction(DstVT) == TargetLowering::Promote) DstVT = TLI.getTypeToTransformTo(CI->getContext(), DstVT); // If, after promotion, these are the same types, this is a noop copy. @@ -548,9 +554,9 @@ protected: CI->eraseFromParent(); } bool isFoldable(unsigned SizeCIOp, unsigned, bool) const { - if (ConstantInt *SizeCI = dyn_cast(CI->getArgOperand(SizeCIOp - - CallInst::ArgOffset))) - return SizeCI->isAllOnesValue(); + if (ConstantInt *SizeCI = + dyn_cast(CI->getArgOperand(SizeCIOp))) + return SizeCI->isAllOnesValue(); return false; } }; @@ -891,12 +897,14 @@ bool CodeGenPrepare::OptimizeBlock(BasicBlock &BB) { bool MadeChange = false; // Split all critical edges where the dest block has a PHI. - TerminatorInst *BBTI = BB.getTerminator(); - if (BBTI->getNumSuccessors() > 1 && !isa(BBTI)) { - for (unsigned i = 0, e = BBTI->getNumSuccessors(); i != e; ++i) { - BasicBlock *SuccBB = BBTI->getSuccessor(i); - if (isa(SuccBB->begin()) && isCriticalEdge(BBTI, i, true)) - SplitEdgeNicely(BBTI, i, BackEdges, this); + if (CriticalEdgeSplit) { + TerminatorInst *BBTI = BB.getTerminator(); + if (BBTI->getNumSuccessors() > 1 && !isa(BBTI)) { + for (unsigned i = 0, e = BBTI->getNumSuccessors(); i != e; ++i) { + BasicBlock *SuccBB = BBTI->getSuccessor(i); + if (isa(SuccBB->begin()) && isCriticalEdge(BBTI, i, true)) + SplitEdgeNicely(BBTI, i, BackEdges, this); + } } } diff --git a/lib/Transforms/Scalar/ConstantProp.cpp b/lib/Transforms/Scalar/ConstantProp.cpp index ea20813..a0ea369 100644 --- a/lib/Transforms/Scalar/ConstantProp.cpp +++ b/lib/Transforms/Scalar/ConstantProp.cpp @@ -34,7 +34,7 @@ STATISTIC(NumInstKilled, "Number of instructions killed"); namespace { struct ConstantPropagation : public FunctionPass { static char ID; // Pass identification, replacement for typeid - ConstantPropagation() : FunctionPass(&ID) {} + ConstantPropagation() : FunctionPass(ID) {} bool runOnFunction(Function &F); @@ -45,8 +45,8 @@ namespace { } char ConstantPropagation::ID = 0; -static RegisterPass -X("constprop", "Simple constant propagation"); +INITIALIZE_PASS(ConstantPropagation, "constprop", + "Simple constant propagation", false, false); FunctionPass *llvm::createConstantPropagationPass() { return new ConstantPropagation(); diff --git a/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp new file mode 100644 index 0000000..0d4e45d --- /dev/null +++ b/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -0,0 +1,200 @@ +//===- CorrelatedValuePropagation.cpp - Propagate CFG-derived info --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Correlated Value Propagation pass. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "correlated-value-propagation" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Function.h" +#include "llvm/Instructions.h" +#include "llvm/Pass.h" +#include "llvm/Analysis/LazyValueInfo.h" +#include "llvm/Support/CFG.h" +#include "llvm/Transforms/Utils/Local.h" +#include "llvm/ADT/Statistic.h" +using namespace llvm; + +STATISTIC(NumPhis, "Number of phis propagated"); +STATISTIC(NumSelects, "Number of selects propagated"); +STATISTIC(NumMemAccess, "Number of memory access targets propagated"); +STATISTIC(NumCmps, "Number of comparisons propagated"); + +namespace { + class CorrelatedValuePropagation : public FunctionPass { + LazyValueInfo *LVI; + + bool processSelect(SelectInst *SI); + bool processPHI(PHINode *P); + bool processMemAccess(Instruction *I); + bool processCmp(CmpInst *C); + + public: + static char ID; + CorrelatedValuePropagation(): FunctionPass(ID) { } + + bool runOnFunction(Function &F); + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + } + }; +} + +char CorrelatedValuePropagation::ID = 0; +INITIALIZE_PASS(CorrelatedValuePropagation, "correlated-propagation", + "Value Propagation", false, false); + +// Public interface to the Value Propagation pass +Pass *llvm::createCorrelatedValuePropagationPass() { + return new CorrelatedValuePropagation(); +} + +bool CorrelatedValuePropagation::processSelect(SelectInst *S) { + if (S->getType()->isVectorTy()) return false; + if (isa(S->getOperand(0))) return false; + + Constant *C = LVI->getConstant(S->getOperand(0), S->getParent()); + if (!C) return false; + + ConstantInt *CI = dyn_cast(C); + if (!CI) return false; + + S->replaceAllUsesWith(S->getOperand(CI->isOne() ? 1 : 2)); + S->eraseFromParent(); + + ++NumSelects; + + return true; +} + +bool CorrelatedValuePropagation::processPHI(PHINode *P) { + bool Changed = false; + + BasicBlock *BB = P->getParent(); + for (unsigned i = 0, e = P->getNumIncomingValues(); i < e; ++i) { + Value *Incoming = P->getIncomingValue(i); + if (isa(Incoming)) continue; + + Constant *C = LVI->getConstantOnEdge(P->getIncomingValue(i), + P->getIncomingBlock(i), + BB); + if (!C) continue; + + P->setIncomingValue(i, C); + Changed = true; + } + + if (Value *ConstVal = P->hasConstantValue()) { + P->replaceAllUsesWith(ConstVal); + P->eraseFromParent(); + Changed = true; + } + + ++NumPhis; + + return Changed; +} + +bool CorrelatedValuePropagation::processMemAccess(Instruction *I) { + Value *Pointer = 0; + if (LoadInst *L = dyn_cast(I)) + Pointer = L->getPointerOperand(); + else + Pointer = cast(I)->getPointerOperand(); + + if (isa(Pointer)) return false; + + Constant *C = LVI->getConstant(Pointer, I->getParent()); + if (!C) return false; + + ++NumMemAccess; + I->replaceUsesOfWith(Pointer, C); + return true; +} + +/// processCmp - If the value of this comparison could be determined locally, +/// constant propagation would already have figured it out. Instead, walk +/// the predecessors and statically evaluate the comparison based on information +/// available on that edge. If a given static evaluation is true on ALL +/// incoming edges, then it's true universally and we can simplify the compare. +bool CorrelatedValuePropagation::processCmp(CmpInst *C) { + Value *Op0 = C->getOperand(0); + if (isa(Op0) && + cast(Op0)->getParent() == C->getParent()) + return false; + + Constant *Op1 = dyn_cast(C->getOperand(1)); + if (!Op1) return false; + + pred_iterator PI = pred_begin(C->getParent()), PE = pred_end(C->getParent()); + if (PI == PE) return false; + + LazyValueInfo::Tristate Result = LVI->getPredicateOnEdge(C->getPredicate(), + C->getOperand(0), Op1, *PI, C->getParent()); + if (Result == LazyValueInfo::Unknown) return false; + + ++PI; + while (PI != PE) { + LazyValueInfo::Tristate Res = LVI->getPredicateOnEdge(C->getPredicate(), + C->getOperand(0), Op1, *PI, C->getParent()); + if (Res != Result) return false; + ++PI; + } + + ++NumCmps; + + if (Result == LazyValueInfo::True) + C->replaceAllUsesWith(ConstantInt::getTrue(C->getContext())); + else + C->replaceAllUsesWith(ConstantInt::getFalse(C->getContext())); + + C->eraseFromParent(); + + return true; +} + +bool CorrelatedValuePropagation::runOnFunction(Function &F) { + LVI = &getAnalysis(); + + bool FnChanged = false; + + for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) { + bool BBChanged = false; + for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ) { + Instruction *II = BI++; + switch (II->getOpcode()) { + case Instruction::Select: + BBChanged |= processSelect(cast(II)); + break; + case Instruction::PHI: + BBChanged |= processPHI(cast(II)); + break; + case Instruction::ICmp: + case Instruction::FCmp: + BBChanged |= processCmp(cast(II)); + break; + case Instruction::Load: + case Instruction::Store: + BBChanged |= processMemAccess(II); + break; + } + } + + // Propagating correlated values might leave cruft around. + // Try to clean it up before we continue. + if (BBChanged) + SimplifyInstructionsInBlock(FI); + + FnChanged |= BBChanged; + } + + return FnChanged; +} diff --git a/lib/Transforms/Scalar/DCE.cpp b/lib/Transforms/Scalar/DCE.cpp index 39940c3..87ea803 100644 --- a/lib/Transforms/Scalar/DCE.cpp +++ b/lib/Transforms/Scalar/DCE.cpp @@ -35,7 +35,7 @@ namespace { // struct DeadInstElimination : public BasicBlockPass { static char ID; // Pass identification, replacement for typeid - DeadInstElimination() : BasicBlockPass(&ID) {} + DeadInstElimination() : BasicBlockPass(ID) {} virtual bool runOnBasicBlock(BasicBlock &BB) { bool Changed = false; for (BasicBlock::iterator DI = BB.begin(); DI != BB.end(); ) { @@ -56,8 +56,8 @@ namespace { } char DeadInstElimination::ID = 0; -static RegisterPass -X("die", "Dead Instruction Elimination"); +INITIALIZE_PASS(DeadInstElimination, "die", + "Dead Instruction Elimination", false, false); Pass *llvm::createDeadInstEliminationPass() { return new DeadInstElimination(); @@ -70,7 +70,7 @@ namespace { // struct DCE : public FunctionPass { static char ID; // Pass identification, replacement for typeid - DCE() : FunctionPass(&ID) {} + DCE() : FunctionPass(ID) {} virtual bool runOnFunction(Function &F); @@ -81,7 +81,7 @@ namespace { } char DCE::ID = 0; -static RegisterPass Y("dce", "Dead Code Elimination"); +INITIALIZE_PASS(DCE, "dce", "Dead Code Elimination", false, false); bool DCE::runOnFunction(Function &F) { // Start out with all of the instructions in the worklist... diff --git a/lib/Transforms/Scalar/DeadStoreElimination.cpp b/lib/Transforms/Scalar/DeadStoreElimination.cpp index e047e4f..c8fd9d9 100644 --- a/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -40,7 +40,7 @@ namespace { TargetData *TD; static char ID; // Pass identification, replacement for typeid - DSE() : FunctionPass(&ID) {} + DSE() : FunctionPass(ID) {} virtual bool runOnFunction(Function &F) { bool Changed = false; @@ -82,7 +82,7 @@ namespace { } char DSE::ID = 0; -static RegisterPass X("dse", "Dead Store Elimination"); +INITIALIZE_PASS(DSE, "dse", "Dead Store Elimination", false, false); FunctionPass *llvm::createDeadStoreEliminationPass() { return new DSE(); } @@ -401,10 +401,9 @@ bool DSE::handleEndBlock(BasicBlock &BB) { } continue; - } else if (CallSite::get(BBI).getInstruction() != 0) { + } else if (CallSite CS = cast(BBI)) { // If this call does not access memory, it can't // be undeadifying any of our pointers. - CallSite CS = CallSite::get(BBI); if (AA.doesNotAccessMemory(CS)) continue; diff --git a/lib/Transforms/Scalar/GEPSplitter.cpp b/lib/Transforms/Scalar/GEPSplitter.cpp index 610a41d..53dd06d 100644 --- a/lib/Transforms/Scalar/GEPSplitter.cpp +++ b/lib/Transforms/Scalar/GEPSplitter.cpp @@ -27,13 +27,13 @@ namespace { virtual void getAnalysisUsage(AnalysisUsage &AU) const; public: static char ID; // Pass identification, replacement for typeid - explicit GEPSplitter() : FunctionPass(&ID) {} + explicit GEPSplitter() : FunctionPass(ID) {} }; } char GEPSplitter::ID = 0; -static RegisterPass X("split-geps", - "split complex GEPs into simple GEPs"); +INITIALIZE_PASS(GEPSplitter, "split-geps", + "split complex GEPs into simple GEPs", false, false); FunctionPass *llvm::createGEPSplitterPass() { return new GEPSplitter(); diff --git a/lib/Transforms/Scalar/GVN.cpp b/lib/Transforms/Scalar/GVN.cpp index 88b6776..c62ce1f 100644 --- a/lib/Transforms/Scalar/GVN.cpp +++ b/lib/Transforms/Scalar/GVN.cpp @@ -165,7 +165,6 @@ namespace { Expression create_expression(CastInst* C); Expression create_expression(GetElementPtrInst* G); Expression create_expression(CallInst* C); - Expression create_expression(Constant* C); Expression create_expression(ExtractValueInst* C); Expression create_expression(InsertValueInst* C); @@ -665,7 +664,7 @@ namespace { public: static char ID; // Pass identification, replacement for typeid explicit GVN(bool noloads = false) - : FunctionPass(&ID), NoLoads(noloads), MD(0) { } + : FunctionPass(ID), NoLoads(noloads), MD(0) { } private: bool NoLoads; @@ -716,8 +715,7 @@ FunctionPass *llvm::createGVNPass(bool NoLoads) { return new GVN(NoLoads); } -static RegisterPass X("gvn", - "Global Value Numbering"); +INITIALIZE_PASS(GVN, "gvn", "Global Value Numbering", false, false); void GVN::dump(DenseMap& d) { errs() << "{\n"; @@ -735,7 +733,7 @@ static bool isSafeReplacement(PHINode* p, Instruction *inst) { for (Instruction::use_iterator UI = p->use_begin(), E = p->use_end(); UI != E; ++UI) - if (PHINode* use_phi = dyn_cast(UI)) + if (PHINode* use_phi = dyn_cast(*UI)) if (use_phi->getParent() == inst->getParent()) return false; @@ -1312,7 +1310,7 @@ static Value *ConstructSSAForLoadSet(LoadInst *LI, // Otherwise, we have to construct SSA form. SmallVector NewPHIs; SSAUpdater SSAUpdate(&NewPHIs); - SSAUpdate.Initialize(LI); + SSAUpdate.Initialize(LI->getType(), LI->getName()); const Type *LoadTy = LI->getType(); @@ -2112,6 +2110,11 @@ bool GVN::performPRE(Function &F) { CurInst->mayReadFromMemory() || CurInst->mayHaveSideEffects() || isa(CurInst)) continue; + + // We don't currently value number ANY inline asm calls. + if (CallInst *CallI = dyn_cast(CurInst)) + if (CallI->isInlineAsm()) + continue; uint32_t ValNo = VN.lookup(CurInst); diff --git a/lib/Transforms/Scalar/IndVarSimplify.cpp b/lib/Transforms/Scalar/IndVarSimplify.cpp index b5c9dd8..af2eafc 100644 --- a/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -77,7 +77,7 @@ namespace { public: static char ID; // Pass identification, replacement for typeid - IndVarSimplify() : LoopPass(&ID) {} + IndVarSimplify() : LoopPass(ID) {} virtual bool runOnLoop(Loop *L, LPPassManager &LPM); @@ -102,7 +102,7 @@ namespace { void RewriteNonIntegerIVs(Loop *L); ICmpInst *LinearFunctionTestReplace(Loop *L, const SCEV *BackedgeTakenCount, - Value *IndVar, + PHINode *IndVar, BasicBlock *ExitingBlock, BranchInst *BI, SCEVExpander &Rewriter); @@ -117,8 +117,8 @@ namespace { } char IndVarSimplify::ID = 0; -static RegisterPass -X("indvars", "Canonicalize Induction Variables"); +INITIALIZE_PASS(IndVarSimplify, "indvars", + "Canonicalize Induction Variables", false, false); Pass *llvm::createIndVarSimplifyPass() { return new IndVarSimplify(); @@ -131,7 +131,7 @@ Pass *llvm::createIndVarSimplifyPass() { /// is actually a much broader range than just linear tests. ICmpInst *IndVarSimplify::LinearFunctionTestReplace(Loop *L, const SCEV *BackedgeTakenCount, - Value *IndVar, + PHINode *IndVar, BasicBlock *ExitingBlock, BranchInst *BI, SCEVExpander &Rewriter) { @@ -181,7 +181,7 @@ ICmpInst *IndVarSimplify::LinearFunctionTestReplace(Loop *L, // The BackedgeTaken expression contains the number of times that the // backedge branches to the loop header. This is one less than the // number of times the loop executes, so use the incremented indvar. - CmpIndVar = L->getCanonicalInductionVariableIncrement(); + CmpIndVar = IndVar->getIncomingValueForBlock(ExitingBlock); } else { // We have to use the preincremented value... RHS = SE->getTruncateOrZeroExtend(BackedgeTakenCount, @@ -534,7 +534,7 @@ bool IndVarSimplify::runOnLoop(Loop *L, LPPassManager &LPM) { // Now that we know the largest of the induction variable expressions // in this loop, insert a canonical induction variable of the largest size. - Value *IndVar = 0; + PHINode *IndVar = 0; if (NeedCannIV) { // Check to see if the loop already has any canonical-looking induction // variables. If any are present and wider than the planned canonical @@ -862,9 +862,9 @@ void IndVarSimplify::HandleFloatingPointIV(Loop *L, PHINode *PN) { // Check Incr uses. One user is PN and the other user is an exit condition // used by the conditional terminator. Value::use_iterator IncrUse = Incr->use_begin(); - Instruction *U1 = cast(IncrUse++); + Instruction *U1 = cast(*IncrUse++); if (IncrUse == Incr->use_end()) return; - Instruction *U2 = cast(IncrUse++); + Instruction *U2 = cast(*IncrUse++); if (IncrUse != Incr->use_end()) return; // Find exit condition, which is an fcmp. If it doesn't exist, or if it isn't diff --git a/lib/Transforms/Scalar/JumpThreading.cpp b/lib/Transforms/Scalar/JumpThreading.cpp index edce14c..104d5ae 100644 --- a/lib/Transforms/Scalar/JumpThreading.cpp +++ b/lib/Transforms/Scalar/JumpThreading.cpp @@ -24,6 +24,7 @@ #include "llvm/Transforms/Utils/SSAUpdater.h" #include "llvm/Target/TargetData.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" @@ -45,7 +46,10 @@ Threshold("jump-threading-threshold", // Turn on use of LazyValueInfo. static cl::opt -EnableLVI("enable-jump-threading-lvi", cl::ReallyHidden); +EnableLVI("enable-jump-threading-lvi", + cl::desc("Use LVI for jump threading"), + cl::init(true), + cl::ReallyHidden); @@ -74,15 +78,32 @@ namespace { #else SmallSet, 16> LoopHeaders; #endif + DenseSet > RecursionSet; + + // RAII helper for updating the recursion stack. + struct RecursionSetRemover { + DenseSet > &TheSet; + std::pair ThePair; + + RecursionSetRemover(DenseSet > &S, + std::pair P) + : TheSet(S), ThePair(P) { } + + ~RecursionSetRemover() { + TheSet.erase(ThePair); + } + }; public: static char ID; // Pass identification - JumpThreading() : FunctionPass(&ID) {} + JumpThreading() : FunctionPass(ID) {} bool runOnFunction(Function &F); virtual void getAnalysisUsage(AnalysisUsage &AU) const { - if (EnableLVI) + if (EnableLVI) { AU.addRequired(); + AU.addPreserved(); + } } void FindLoopHeaders(Function &F); @@ -111,8 +132,8 @@ namespace { } char JumpThreading::ID = 0; -static RegisterPass -X("jump-threading", "Jump Threading"); +INITIALIZE_PASS(JumpThreading, "jump-threading", + "Jump Threading", false, false); // Public interface to the Jump Threading pass FunctionPass *llvm::createJumpThreadingPass() { return new JumpThreading(); } @@ -144,6 +165,7 @@ bool JumpThreading::runOnFunction(Function &F) { DEBUG(dbgs() << " JT: Deleting dead block '" << BB->getName() << "' with terminator: " << *BB->getTerminator() << '\n'); LoopHeaders.erase(BB); + if (LVI) LVI->eraseBlock(BB); DeleteDeadBlock(BB); Changed = true; } else if (BranchInst *BI = dyn_cast(BB->getTerminator())) { @@ -164,6 +186,11 @@ bool JumpThreading::runOnFunction(Function &F) { bool ErasedFromLoopHeaders = LoopHeaders.erase(BB); BasicBlock *Succ = BI->getSuccessor(0); + // FIXME: It is always conservatively correct to drop the info + // for a block even if it doesn't get erased. This isn't totally + // awesome, but it allows us to use AssertingVH to prevent nasty + // dangling pointer issues within LazyValueInfo. + if (LVI) LVI->eraseBlock(BB); if (TryToSimplifyUncondBranchFromEmptyBlock(BB)) { Changed = true; // If we deleted BB and BB was the header of a loop, then the @@ -251,6 +278,17 @@ void JumpThreading::FindLoopHeaders(Function &F) { LoopHeaders.insert(const_cast(Edges[i].second)); } +// Helper method for ComputeValueKnownInPredecessors. If Value is a +// ConstantInt, push it. If it's an undef, push 0. Otherwise, do nothing. +static void PushConstantIntOrUndef(SmallVectorImpl > &Result, + Constant *Value, BasicBlock* BB){ + if (ConstantInt *FoldedCInt = dyn_cast(Value)) + Result.push_back(std::make_pair(FoldedCInt, BB)); + else if (isa(Value)) + Result.push_back(std::make_pair((ConstantInt*)0, BB)); +} + /// ComputeValueKnownInPredecessors - Given a basic block BB and a value V, see /// if we can infer that the value is a known ConstantInt in any of our /// predecessors. If so, return the known list of value and pred BB in the @@ -260,12 +298,24 @@ void JumpThreading::FindLoopHeaders(Function &F) { /// bool JumpThreading:: ComputeValueKnownInPredecessors(Value *V, BasicBlock *BB,PredValueInfo &Result){ + // This method walks up use-def chains recursively. Because of this, we could + // get into an infinite loop going around loops in the use-def chain. To + // prevent this, keep track of what (value, block) pairs we've already visited + // and terminate the search if we loop back to them + if (!RecursionSet.insert(std::make_pair(V, BB)).second) + return false; + + // An RAII help to remove this pair from the recursion set once the recursion + // stack pops back out again. + RecursionSetRemover remover(RecursionSet, std::make_pair(V, BB)); + // If V is a constantint, then it is known in all predecessors. if (isa(V) || isa(V)) { ConstantInt *CI = dyn_cast(V); for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) Result.push_back(std::make_pair(CI, *PI)); + return true; } @@ -313,8 +363,15 @@ ComputeValueKnownInPredecessors(Value *V, BasicBlock *BB,PredValueInfo &Result){ if (isa(InVal) || isa(InVal)) { ConstantInt *CI = dyn_cast(InVal); Result.push_back(std::make_pair(CI, PN->getIncomingBlock(i))); + } else if (LVI) { + Constant *CI = LVI->getConstantOnEdge(InVal, + PN->getIncomingBlock(i), BB); + // LVI returns null is no value could be determined. + if (!CI) continue; + PushConstantIntOrUndef(Result, CI, PN->getIncomingBlock(i)); } } + return !Result.empty(); } @@ -338,29 +395,26 @@ ComputeValueKnownInPredecessors(Value *V, BasicBlock *BB,PredValueInfo &Result){ else InterestingVal = ConstantInt::getFalse(I->getContext()); + SmallPtrSet LHSKnownBBs; + // Scan for the sentinel. If we find an undef, force it to the // interesting value: x|undef -> true and x&undef -> false. for (unsigned i = 0, e = LHSVals.size(); i != e; ++i) if (LHSVals[i].first == InterestingVal || LHSVals[i].first == 0) { Result.push_back(LHSVals[i]); Result.back().first = InterestingVal; + LHSKnownBBs.insert(LHSVals[i].second); } for (unsigned i = 0, e = RHSVals.size(); i != e; ++i) if (RHSVals[i].first == InterestingVal || RHSVals[i].first == 0) { // If we already inferred a value for this block on the LHS, don't // re-add it. - bool HasValue = false; - for (unsigned r = 0, e = Result.size(); r != e; ++r) - if (Result[r].second == RHSVals[i].second) { - HasValue = true; - break; - } - - if (!HasValue) { + if (!LHSKnownBBs.count(RHSVals[i].second)) { Result.push_back(RHSVals[i]); Result.back().first = InterestingVal; } } + return !Result.empty(); } @@ -377,8 +431,27 @@ ComputeValueKnownInPredecessors(Value *V, BasicBlock *BB,PredValueInfo &Result){ if (Result[i].first) Result[i].first = cast(ConstantExpr::getNot(Result[i].first)); + return true; } + + // Try to simplify some other binary operator values. + } else if (BinaryOperator *BO = dyn_cast(I)) { + if (ConstantInt *CI = dyn_cast(BO->getOperand(1))) { + SmallVector, 8> LHSVals; + ComputeValueKnownInPredecessors(BO->getOperand(0), BB, LHSVals); + + // Try to use constant folding to simplify the binary operator. + for (unsigned i = 0, e = LHSVals.size(); i != e; ++i) { + Constant *V = LHSVals[i].first ? LHSVals[i].first : + cast(UndefValue::get(BO->getType())); + Constant *Folded = ConstantExpr::get(BO->getOpcode(), V, CI); + + PushConstantIntOrUndef(Result, Folded, LHSVals[i].second); + } + } + + return !Result.empty(); } // Handle compare with phi operand, where the PHI is defined in this block. @@ -405,10 +478,8 @@ ComputeValueKnownInPredecessors(Value *V, BasicBlock *BB,PredValueInfo &Result){ Res = ConstantInt::get(Type::getInt1Ty(LHS->getContext()), ResT); } - if (isa(Res)) - Result.push_back(std::make_pair((ConstantInt*)0, PredBB)); - else if (ConstantInt *CI = dyn_cast(Res)) - Result.push_back(std::make_pair(CI, PredBB)); + if (Constant *ConstRes = dyn_cast(Res)) + PushConstantIntOrUndef(Result, ConstRes, PredBB); } return !Result.empty(); @@ -418,28 +489,59 @@ ComputeValueKnownInPredecessors(Value *V, BasicBlock *BB,PredValueInfo &Result){ // If comparing a live-in value against a constant, see if we know the // live-in value on any predecessors. if (LVI && isa(Cmp->getOperand(1)) && - Cmp->getType()->isIntegerTy() && // Not vector compare. - (!isa(Cmp->getOperand(0)) || - cast(Cmp->getOperand(0))->getParent() != BB)) { - Constant *RHSCst = cast(Cmp->getOperand(1)); + Cmp->getType()->isIntegerTy()) { + if (!isa(Cmp->getOperand(0)) || + cast(Cmp->getOperand(0))->getParent() != BB) { + Constant *RHSCst = cast(Cmp->getOperand(1)); + + for (pred_iterator PI = pred_begin(BB), E = pred_end(BB);PI != E; ++PI){ + BasicBlock *P = *PI; + // If the value is known by LazyValueInfo to be a constant in a + // predecessor, use that information to try to thread this block. + LazyValueInfo::Tristate Res = + LVI->getPredicateOnEdge(Cmp->getPredicate(), Cmp->getOperand(0), + RHSCst, P, BB); + if (Res == LazyValueInfo::Unknown) + continue; - for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { - BasicBlock *P = *PI; - // If the value is known by LazyValueInfo to be a constant in a - // predecessor, use that information to try to thread this block. - LazyValueInfo::Tristate - Res = LVI->getPredicateOnEdge(Cmp->getPredicate(), Cmp->getOperand(0), - RHSCst, P, BB); - if (Res == LazyValueInfo::Unknown) - continue; + Constant *ResC = ConstantInt::get(Cmp->getType(), Res); + Result.push_back(std::make_pair(cast(ResC), P)); + } - Constant *ResC = ConstantInt::get(Cmp->getType(), Res); - Result.push_back(std::make_pair(cast(ResC), P)); + return !Result.empty(); } - - return !Result.empty(); + + // Try to find a constant value for the LHS of a comparison, + // and evaluate it statically if we can. + if (Constant *CmpConst = dyn_cast(Cmp->getOperand(1))) { + SmallVector, 8> LHSVals; + ComputeValueKnownInPredecessors(I->getOperand(0), BB, LHSVals); + + for (unsigned i = 0, e = LHSVals.size(); i != e; ++i) { + Constant *V = LHSVals[i].first ? LHSVals[i].first : + cast(UndefValue::get(CmpConst->getType())); + Constant *Folded = ConstantExpr::getCompare(Cmp->getPredicate(), + V, CmpConst); + PushConstantIntOrUndef(Result, Folded, LHSVals[i].second); + } + + return !Result.empty(); + } + } + } + + if (LVI) { + // If all else fails, see if LVI can figure out a constant value for us. + Constant *CI = LVI->getConstant(V, BB); + ConstantInt *CInt = dyn_cast_or_null(CI); + if (CInt) { + for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) + Result.push_back(std::make_pair(CInt, *PI)); } + + return !Result.empty(); } + return false; } @@ -490,6 +592,7 @@ bool JumpThreading::ProcessBlock(BasicBlock *BB) { // Remember if SinglePred was the entry block of the function. If so, we // will need to move BB back to the entry position. bool isEntry = SinglePred == &SinglePred->getParent()->getEntryBlock(); + if (LVI) LVI->eraseBlock(SinglePred); MergeBasicBlockIntoOnlyPred(BB); if (isEntry && BB != &BB->getParent()->getEntryBlock()) @@ -603,6 +706,44 @@ bool JumpThreading::ProcessBlock(BasicBlock *BB) { } } } + + // For a comparison where the LHS is outside this block, it's possible + // that we've branched on it before. Used LVI to see if we can simplify + // the branch based on that. + BranchInst *CondBr = dyn_cast(BB->getTerminator()); + Constant *CondConst = dyn_cast(CondCmp->getOperand(1)); + pred_iterator PI = pred_begin(BB), PE = pred_end(BB); + if (LVI && CondBr && CondConst && CondBr->isConditional() && PI != PE && + (!isa(CondCmp->getOperand(0)) || + cast(CondCmp->getOperand(0))->getParent() != BB)) { + // For predecessor edge, determine if the comparison is true or false + // on that edge. If they're all true or all false, we can simplify the + // branch. + // FIXME: We could handle mixed true/false by duplicating code. + LazyValueInfo::Tristate Baseline = + LVI->getPredicateOnEdge(CondCmp->getPredicate(), CondCmp->getOperand(0), + CondConst, *PI, BB); + if (Baseline != LazyValueInfo::Unknown) { + // Check that all remaining incoming values match the first one. + while (++PI != PE) { + LazyValueInfo::Tristate Ret = LVI->getPredicateOnEdge( + CondCmp->getPredicate(), + CondCmp->getOperand(0), + CondConst, *PI, BB); + if (Ret != Baseline) break; + } + + // If we terminated early, then one of the values didn't match. + if (PI == PE) { + unsigned ToRemove = Baseline == LazyValueInfo::True ? 1 : 0; + unsigned ToKeep = Baseline == LazyValueInfo::True ? 0 : 1; + RemovePredecessorAndSimplify(CondBr->getSuccessor(ToRemove), BB, TD); + BranchInst::Create(CondBr->getSuccessor(ToKeep), CondBr); + CondBr->eraseFromParent(); + return true; + } + } + } } // Check for some cases that are worth simplifying. Right now we want to look @@ -1020,6 +1161,7 @@ bool JumpThreading::ProcessThreadableEdges(Value *Cond, BasicBlock *BB) { SmallVector, 8> PredValues; if (!ComputeValueKnownInPredecessors(Cond, BB, PredValues)) return false; + assert(!PredValues.empty() && "ComputeValueKnownInPredecessors returned true with no values"); @@ -1314,6 +1456,9 @@ bool JumpThreading::ThreadEdge(BasicBlock *BB, << ", across block:\n " << *BB << "\n"); + if (LVI) + LVI->threadEdge(PredBB, BB, SuccBB); + // We are going to have to map operands from the original BB block to the new // copy of the block 'NewBB'. If there are PHI nodes in BB, evaluate them to // account for entry from PredBB. @@ -1383,7 +1528,7 @@ bool JumpThreading::ThreadEdge(BasicBlock *BB, // We found a use of I outside of BB. Rename all uses of I that are outside // its block to be uses of the appropriate PHI node etc. See ValuesInBlocks // with the two values we know. - SSAUpdate.Initialize(I); + SSAUpdate.Initialize(I->getType(), I->getName()); SSAUpdate.AddAvailableValue(BB, I); SSAUpdate.AddAvailableValue(NewBB, ValueMapping[I]); @@ -1538,7 +1683,7 @@ bool JumpThreading::DuplicateCondBranchOnPHIIntoPred(BasicBlock *BB, // We found a use of I outside of BB. Rename all uses of I that are outside // its block to be uses of the appropriate PHI node etc. See ValuesInBlocks // with the two values we know. - SSAUpdate.Initialize(I); + SSAUpdate.Initialize(I->getType(), I->getName()); SSAUpdate.AddAvailableValue(BB, I); SSAUpdate.AddAvailableValue(PredBB, ValueMapping[I]); diff --git a/lib/Transforms/Scalar/LICM.cpp b/lib/Transforms/Scalar/LICM.cpp index 7347395..2ef8544 100644 --- a/lib/Transforms/Scalar/LICM.cpp +++ b/lib/Transforms/Scalar/LICM.cpp @@ -26,8 +26,7 @@ // pointer. There are no calls in the loop which mod/ref the pointer. // If these conditions are true, we can promote the loads and stores in the // loop of the pointer to use a temporary alloca'd variable. We then use -// the mem2reg functionality to construct the appropriate SSA form for the -// variable. +// the SSAUpdater to construct the appropriate SSA form for the value. // //===----------------------------------------------------------------------===// @@ -37,14 +36,15 @@ #include "llvm/DerivedTypes.h" #include "llvm/IntrinsicInst.h" #include "llvm/Instructions.h" -#include "llvm/Target/TargetData.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AliasSetTracker.h" +#include "llvm/Analysis/ConstantFolding.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/Dominators.h" #include "llvm/Analysis/ScalarEvolution.h" -#include "llvm/Transforms/Utils/PromoteMemToReg.h" +#include "llvm/Transforms/Utils/Local.h" +#include "llvm/Transforms/Utils/SSAUpdater.h" #include "llvm/Support/CFG.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" @@ -66,7 +66,7 @@ DisablePromotion("disable-licm-promotion", cl::Hidden, namespace { struct LICM : public LoopPass { static char ID; // Pass identification, replacement for typeid - LICM() : LoopPass(&ID) {} + LICM() : LoopPass(ID) {} virtual bool runOnLoop(Loop *L, LPPassManager &LPM); @@ -75,39 +75,31 @@ namespace { /// virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); - AU.addRequiredID(LoopSimplifyID); - AU.addRequired(); AU.addRequired(); - AU.addRequired(); // For scalar promotion (mem2reg) + AU.addRequired(); + AU.addRequiredID(LoopSimplifyID); AU.addRequired(); + AU.addPreserved(); AU.addPreserved(); - AU.addPreserved(); AU.addPreservedID(LoopSimplifyID); } bool doFinalization() { - // Free the values stored in the map - for (std::map::iterator - I = LoopToAliasMap.begin(), E = LoopToAliasMap.end(); I != E; ++I) - delete I->second; - - LoopToAliasMap.clear(); + assert(LoopToAliasSetMap.empty() && "Didn't free loop alias sets"); return false; } private: - // Various analyses that we use... AliasAnalysis *AA; // Current AliasAnalysis information LoopInfo *LI; // Current LoopInfo - DominatorTree *DT; // Dominator Tree for the current Loop... - DominanceFrontier *DF; // Current Dominance Frontier + DominatorTree *DT; // Dominator Tree for the current Loop. - // State that is updated as we process loops + // State that is updated as we process loops. bool Changed; // Set to true when we change anything. BasicBlock *Preheader; // The preheader block of the current loop... Loop *CurLoop; // The current loop we are working on... AliasSetTracker *CurAST; // AliasSet information for the current loop... - std::map LoopToAliasMap; + DenseMap LoopToAliasSetMap; /// cloneBasicBlockAnalysis - Simple Analysis hook. Clone alias set info. void cloneBasicBlockAnalysis(BasicBlock *From, BasicBlock *To, Loop *L); @@ -204,25 +196,12 @@ namespace { bool isLoopInvariantInst(Instruction &I); bool isNotUsedInLoop(Instruction &I); - /// PromoteValuesInLoop - Look at the stores in the loop and promote as many - /// to scalars as we can. - /// - void PromoteValuesInLoop(); - - /// FindPromotableValuesInLoop - Check the current loop for stores to - /// definite pointers, which are not loaded and stored through may aliases. - /// If these are found, create an alloca for the value, add it to the - /// PromotedValues list, and keep track of the mapping from value to - /// alloca... - /// - void FindPromotableValuesInLoop( - std::vector > &PromotedValues, - std::map &Val2AlMap); + void PromoteAliasSet(AliasSet &AS); }; } char LICM::ID = 0; -static RegisterPass X("licm", "Loop Invariant Code Motion"); +INITIALIZE_PASS(LICM, "licm", "Loop Invariant Code Motion", false, false); Pass *llvm::createLICMPass() { return new LICM(); } @@ -236,19 +215,23 @@ bool LICM::runOnLoop(Loop *L, LPPassManager &LPM) { // Get our Loop and Alias Analysis information... LI = &getAnalysis(); AA = &getAnalysis(); - DF = &getAnalysis(); DT = &getAnalysis(); CurAST = new AliasSetTracker(*AA); - // Collect Alias info from subloops + // Collect Alias info from subloops. for (Loop::iterator LoopItr = L->begin(), LoopItrE = L->end(); LoopItr != LoopItrE; ++LoopItr) { Loop *InnerL = *LoopItr; - AliasSetTracker *InnerAST = LoopToAliasMap[InnerL]; - assert (InnerAST && "Where is my AST?"); + AliasSetTracker *InnerAST = LoopToAliasSetMap[InnerL]; + assert(InnerAST && "Where is my AST?"); // What if InnerLoop was modified by other passes ? CurAST->add(*InnerAST); + + // Once we've incorporated the inner loop's AST into ours, we don't need the + // subloop's anymore. + delete InnerAST; + LoopToAliasSetMap.erase(InnerL); } CurLoop = L; @@ -263,7 +246,7 @@ bool LICM::runOnLoop(Loop *L, LPPassManager &LPM) { for (Loop::block_iterator I = L->block_begin(), E = L->block_end(); I != E; ++I) { BasicBlock *BB = *I; - if (LI->getLoopFor(BB) == L) // Ignore blocks in subloops... + if (LI->getLoopFor(BB) == L) // Ignore blocks in subloops. CurAST->add(*BB); // Incorporate the specified basic block } @@ -283,15 +266,24 @@ bool LICM::runOnLoop(Loop *L, LPPassManager &LPM) { HoistRegion(DT->getNode(L->getHeader())); // Now that all loop invariants have been removed from the loop, promote any - // memory references to scalars that we can... - if (!DisablePromotion && Preheader && L->hasDedicatedExits()) - PromoteValuesInLoop(); - + // memory references to scalars that we can. + if (!DisablePromotion && Preheader && L->hasDedicatedExits()) { + // Loop over all of the alias sets in the tracker object. + for (AliasSetTracker::iterator I = CurAST->begin(), E = CurAST->end(); + I != E; ++I) + PromoteAliasSet(*I); + } + // Clear out loops state information for the next iteration CurLoop = 0; Preheader = 0; - LoopToAliasMap[L] = CurAST; + // If this loop is nested inside of another one, save the alias information + // for when we process the outer loop. + if (L->getParentLoop()) + LoopToAliasSetMap[L] = CurAST; + else + delete CurAST; return Changed; } @@ -308,7 +300,7 @@ void LICM::SinkRegion(DomTreeNode *N) { // If this subregion is not in the top level loop at all, exit. if (!CurLoop->contains(BB)) return; - // We are processing blocks in reverse dfo, so process children first... + // We are processing blocks in reverse dfo, so process children first. const std::vector &Children = N->getChildren(); for (unsigned i = 0, e = Children.size(); i != e; ++i) SinkRegion(Children[i]); @@ -319,6 +311,17 @@ void LICM::SinkRegion(DomTreeNode *N) { for (BasicBlock::iterator II = BB->end(); II != BB->begin(); ) { Instruction &I = *--II; + + // If the instruction is dead, we would try to sink it because it isn't used + // in the loop, instead, just delete it. + if (isInstructionTriviallyDead(&I)) { + DEBUG(dbgs() << "LICM deleting dead inst: " << I << '\n'); + ++II; + CurAST->deleteValue(&I); + I.eraseFromParent(); + Changed = true; + continue; + } // Check to see if we can sink this instruction to the exit blocks // of the loop. We can do this if the all users of the instruction are @@ -350,6 +353,18 @@ void LICM::HoistRegion(DomTreeNode *N) { for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E; ) { Instruction &I = *II++; + // Try constant folding this instruction. If all the operands are + // constants, it is technically hoistable, but it would be better to just + // fold it. + if (Constant *C = ConstantFoldInstruction(&I)) { + DEBUG(dbgs() << "LICM folding inst: " << I << " --> " << *C << '\n'); + CurAST->copyValue(&I, C); + CurAST->deleteValue(&I); + I.replaceAllUsesWith(C); + I.eraseFromParent(); + continue; + } + // Try hoisting the instruction out to the preheader. We can only do this // if all of the operands of the instruction are loop invariant and if it // is safe to hoist the instruction. @@ -357,7 +372,7 @@ void LICM::HoistRegion(DomTreeNode *N) { if (isLoopInvariantInst(I) && canSinkOrHoistInst(I) && isSafeToExecuteUnconditionally(I)) hoist(I); - } + } const std::vector &Children = N->getChildren(); for (unsigned i = 0, e = Children.size(); i != e; ++i) @@ -457,10 +472,10 @@ bool LICM::isLoopInvariantInst(Instruction &I) { /// position, and may either delete it or move it to outside of the loop. /// void LICM::sink(Instruction &I) { - DEBUG(dbgs() << "LICM sinking instruction: " << I); + DEBUG(dbgs() << "LICM sinking instruction: " << I << "\n"); SmallVector ExitBlocks; - CurLoop->getExitBlocks(ExitBlocks); + CurLoop->getUniqueExitBlocks(ExitBlocks); if (isa(I)) ++NumMovedLoads; else if (isa(I)) ++NumMovedCalls; @@ -477,122 +492,101 @@ void LICM::sink(Instruction &I) { // If I has users in unreachable blocks, eliminate. // If I is not void type then replaceAllUsesWith undef. // This allows ValueHandlers and custom metadata to adjust itself. - if (!I.getType()->isVoidTy()) + if (!I.use_empty()) I.replaceAllUsesWith(UndefValue::get(I.getType())); I.eraseFromParent(); } else { // Move the instruction to the start of the exit block, after any PHI // nodes in it. - I.removeFromParent(); - BasicBlock::iterator InsertPt = ExitBlocks[0]->getFirstNonPHI(); - ExitBlocks[0]->getInstList().insert(InsertPt, &I); + I.moveBefore(ExitBlocks[0]->getFirstNonPHI()); + + // This instruction is no longer in the AST for the current loop, because + // we just sunk it out of the loop. If we just sunk it into an outer + // loop, we will rediscover the operation when we process it. + CurAST->deleteValue(&I); } - } else if (ExitBlocks.empty()) { + return; + } + + if (ExitBlocks.empty()) { // The instruction is actually dead if there ARE NO exit blocks. CurAST->deleteValue(&I); // If I has users in unreachable blocks, eliminate. // If I is not void type then replaceAllUsesWith undef. // This allows ValueHandlers and custom metadata to adjust itself. - if (!I.getType()->isVoidTy()) + if (!I.use_empty()) I.replaceAllUsesWith(UndefValue::get(I.getType())); I.eraseFromParent(); - } else { - // Otherwise, if we have multiple exits, use the PromoteMem2Reg function to - // do all of the hard work of inserting PHI nodes as necessary. We convert - // the value into a stack object to get it to do this. - - // Firstly, we create a stack object to hold the value... - AllocaInst *AI = 0; - - if (!I.getType()->isVoidTy()) { - AI = new AllocaInst(I.getType(), 0, I.getName(), - I.getParent()->getParent()->getEntryBlock().begin()); - CurAST->add(AI); - } - - // Secondly, insert load instructions for each use of the instruction - // outside of the loop. - while (!I.use_empty()) { - Instruction *U = cast(I.use_back()); - - // If the user is a PHI Node, we actually have to insert load instructions - // in all predecessor blocks, not in the PHI block itself! - if (PHINode *UPN = dyn_cast(U)) { - // Only insert into each predecessor once, so that we don't have - // different incoming values from the same block! - std::map InsertedBlocks; - for (unsigned i = 0, e = UPN->getNumIncomingValues(); i != e; ++i) - if (UPN->getIncomingValue(i) == &I) { - BasicBlock *Pred = UPN->getIncomingBlock(i); - Value *&PredVal = InsertedBlocks[Pred]; - if (!PredVal) { - // Insert a new load instruction right before the terminator in - // the predecessor block. - PredVal = new LoadInst(AI, "", Pred->getTerminator()); - CurAST->add(cast(PredVal)); - } - - UPN->setIncomingValue(i, PredVal); - } - - } else { - LoadInst *L = new LoadInst(AI, "", U); - U->replaceUsesOfWith(&I, L); - CurAST->add(L); - } - } - - // Thirdly, insert a copy of the instruction in each exit block of the loop - // that is dominated by the instruction, storing the result into the memory - // location. Be careful not to insert the instruction into any particular - // basic block more than once. - std::set InsertedBlocks; - BasicBlock *InstOrigBB = I.getParent(); - - for (unsigned i = 0, e = ExitBlocks.size(); i != e; ++i) { - BasicBlock *ExitBlock = ExitBlocks[i]; - - if (isExitBlockDominatedByBlockInLoop(ExitBlock, InstOrigBB)) { - // If we haven't already processed this exit block, do so now. - if (InsertedBlocks.insert(ExitBlock).second) { - // Insert the code after the last PHI node... - BasicBlock::iterator InsertPt = ExitBlock->getFirstNonPHI(); - - // If this is the first exit block processed, just move the original - // instruction, otherwise clone the original instruction and insert - // the copy. - Instruction *New; - if (InsertedBlocks.size() == 1) { - I.removeFromParent(); - ExitBlock->getInstList().insert(InsertPt, &I); - New = &I; - } else { - New = I.clone(); - CurAST->copyValue(&I, New); - if (!I.getName().empty()) - New->setName(I.getName()+".le"); - ExitBlock->getInstList().insert(InsertPt, New); - } - - // Now that we have inserted the instruction, store it into the alloca - if (AI) new StoreInst(New, AI, InsertPt); - } - } - } - - // If the instruction doesn't dominate any exit blocks, it must be dead. - if (InsertedBlocks.empty()) { - CurAST->deleteValue(&I); - I.eraseFromParent(); - } - - // Finally, promote the fine value to SSA form. - if (AI) { - std::vector Allocas; - Allocas.push_back(AI); - PromoteMemToReg(Allocas, *DT, *DF, CurAST); + return; + } + + // Otherwise, if we have multiple exits, use the SSAUpdater to do all of the + // hard work of inserting PHI nodes as necessary. + SmallVector NewPHIs; + SSAUpdater SSA(&NewPHIs); + + if (!I.use_empty()) + SSA.Initialize(I.getType(), I.getName()); + + // Insert a copy of the instruction in each exit block of the loop that is + // dominated by the instruction. Each exit block is known to only be in the + // ExitBlocks list once. + BasicBlock *InstOrigBB = I.getParent(); + unsigned NumInserted = 0; + + for (unsigned i = 0, e = ExitBlocks.size(); i != e; ++i) { + BasicBlock *ExitBlock = ExitBlocks[i]; + + if (!isExitBlockDominatedByBlockInLoop(ExitBlock, InstOrigBB)) + continue; + + // Insert the code after the last PHI node. + BasicBlock::iterator InsertPt = ExitBlock->getFirstNonPHI(); + + // If this is the first exit block processed, just move the original + // instruction, otherwise clone the original instruction and insert + // the copy. + Instruction *New; + if (NumInserted++ == 0) { + I.moveBefore(InsertPt); + New = &I; + } else { + New = I.clone(); + if (!I.getName().empty()) + New->setName(I.getName()+".le"); + ExitBlock->getInstList().insert(InsertPt, New); } + + // Now that we have inserted the instruction, inform SSAUpdater. + if (!I.use_empty()) + SSA.AddAvailableValue(ExitBlock, New); } + + // If the instruction doesn't dominate any exit blocks, it must be dead. + if (NumInserted == 0) { + CurAST->deleteValue(&I); + if (!I.use_empty()) + I.replaceAllUsesWith(UndefValue::get(I.getType())); + I.eraseFromParent(); + return; + } + + // Next, rewrite uses of the instruction, inserting PHI nodes as needed. + for (Value::use_iterator UI = I.use_begin(), UE = I.use_end(); UI != UE; ) { + // Grab the use before incrementing the iterator. + Use &U = UI.getUse(); + // Increment the iterator before removing the use from the list. + ++UI; + SSA.RewriteUseAfterInsertions(U); + } + + // Update CurAST for NewPHIs if I had pointer type. + if (I.getType()->isPointerTy()) + for (unsigned i = 0, e = NewPHIs.size(); i != e; ++i) + CurAST->copyValue(&I, NewPHIs[i]); + + // Finally, remove the instruction from CurAST. It is no longer in the loop. + CurAST->deleteValue(&I); } /// hoist - When an instruction is found to only use loop invariant operands @@ -602,12 +596,8 @@ void LICM::hoist(Instruction &I) { DEBUG(dbgs() << "LICM hoisting to " << Preheader->getName() << ": " << I << "\n"); - // Remove the instruction from its current basic block... but don't delete the - // instruction. - I.removeFromParent(); - - // Insert the new node in Preheader, before the terminator. - Preheader->getInstList().insert(Preheader->getTerminator(), &I); + // Move the new node to the Preheader, before its terminator. + I.moveBefore(Preheader->getTerminator()); if (isa(I)) ++NumMovedLoads; else if (isa(I)) ++NumMovedCalls; @@ -647,223 +637,269 @@ bool LICM::isSafeToExecuteUnconditionally(Instruction &Inst) { return true; } - -/// PromoteValuesInLoop - Try to promote memory values to scalars by sinking +/// PromoteAliasSet - Try to promote memory values to scalars by sinking /// stores out of the loop and moving loads to before the loop. We do this by /// looping over the stores in the loop, looking for stores to Must pointers -/// which are loop invariant. We promote these memory locations to use allocas -/// instead. These allocas can easily be raised to register values by the -/// PromoteMem2Reg functionality. +/// which are loop invariant. /// -void LICM::PromoteValuesInLoop() { - // PromotedValues - List of values that are promoted out of the loop. Each - // value has an alloca instruction for it, and a canonical version of the - // pointer. - std::vector > PromotedValues; - std::map ValueToAllocaMap; // Map of ptr to alloca - - FindPromotableValuesInLoop(PromotedValues, ValueToAllocaMap); - if (ValueToAllocaMap.empty()) return; // If there are values to promote. - - Changed = true; - NumPromoted += PromotedValues.size(); - - std::vector PointerValueNumbers; - - // Emit a copy from the value into the alloca'd value in the loop preheader - TerminatorInst *LoopPredInst = Preheader->getTerminator(); - for (unsigned i = 0, e = PromotedValues.size(); i != e; ++i) { - Value *Ptr = PromotedValues[i].second; - - // If we are promoting a pointer value, update alias information for the - // inserted load. - Value *LoadValue = 0; - if (cast(Ptr->getType())->getElementType()->isPointerTy()) { - // Locate a load or store through the pointer, and assign the same value - // to LI as we are loading or storing. Since we know that the value is - // stored in this loop, this will always succeed. - for (Value::use_iterator UI = Ptr->use_begin(), E = Ptr->use_end(); - UI != E; ++UI) { - User *U = *UI; - if (LoadInst *LI = dyn_cast(U)) { - LoadValue = LI; - break; - } else if (StoreInst *SI = dyn_cast(U)) { - if (SI->getOperand(1) == Ptr) { - LoadValue = SI->getOperand(0); - break; - } - } - } - assert(LoadValue && "No store through the pointer found!"); - PointerValueNumbers.push_back(LoadValue); // Remember this for later. - } - - // Load from the memory we are promoting. - LoadInst *LI = new LoadInst(Ptr, Ptr->getName()+".promoted", LoopPredInst); - - if (LoadValue) CurAST->copyValue(LoadValue, LI); - - // Store into the temporary alloca. - new StoreInst(LI, PromotedValues[i].first, LoopPredInst); - } +void LICM::PromoteAliasSet(AliasSet &AS) { + // We can promote this alias set if it has a store, if it is a "Must" alias + // set, if the pointer is loop invariant, and if we are not eliminating any + // volatile loads or stores. + if (AS.isForwardingAliasSet() || !AS.isMod() || !AS.isMustAlias() || + AS.isVolatile() || !CurLoop->isLoopInvariant(AS.begin()->getValue())) + return; + + assert(!AS.empty() && + "Must alias set should have at least one pointer element in it!"); + Value *SomePtr = AS.begin()->getValue(); - // Scan the basic blocks in the loop, replacing uses of our pointers with - // uses of the allocas in question. + // It isn't safe to promote a load/store from the loop if the load/store is + // conditional. For example, turning: // - for (Loop::block_iterator I = CurLoop->block_begin(), - E = CurLoop->block_end(); I != E; ++I) { - BasicBlock *BB = *I; - // Rewrite all loads and stores in the block of the pointer... - for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E; ++II) { - if (LoadInst *L = dyn_cast(II)) { - std::map::iterator - I = ValueToAllocaMap.find(L->getOperand(0)); - if (I != ValueToAllocaMap.end()) - L->setOperand(0, I->second); // Rewrite load instruction... - } else if (StoreInst *S = dyn_cast(II)) { - std::map::iterator - I = ValueToAllocaMap.find(S->getOperand(1)); - if (I != ValueToAllocaMap.end()) - S->setOperand(1, I->second); // Rewrite store instruction... - } - } - } - - // Now that the body of the loop uses the allocas instead of the original - // memory locations, insert code to copy the alloca value back into the - // original memory location on all exits from the loop. Note that we only - // want to insert one copy of the code in each exit block, though the loop may - // exit to the same block more than once. + // for () { if (c) *P += 1; } // - SmallPtrSet ProcessedBlocks; - - SmallVector ExitBlocks; - CurLoop->getExitBlocks(ExitBlocks); - for (unsigned i = 0, e = ExitBlocks.size(); i != e; ++i) { - if (!ProcessedBlocks.insert(ExitBlocks[i])) - continue; - - // Copy all of the allocas into their memory locations. - BasicBlock::iterator BI = ExitBlocks[i]->getFirstNonPHI(); - Instruction *InsertPos = BI; - unsigned PVN = 0; - for (unsigned i = 0, e = PromotedValues.size(); i != e; ++i) { - // Load from the alloca. - LoadInst *LI = new LoadInst(PromotedValues[i].first, "", InsertPos); - - // If this is a pointer type, update alias info appropriately. - if (LI->getType()->isPointerTy()) - CurAST->copyValue(PointerValueNumbers[PVN++], LI); - - // Store into the memory we promoted. - new StoreInst(LI, PromotedValues[i].second, InsertPos); - } - } - - // Now that we have done the deed, use the mem2reg functionality to promote - // all of the new allocas we just created into real SSA registers. + // into: // - std::vector PromotedAllocas; - PromotedAllocas.reserve(PromotedValues.size()); - for (unsigned i = 0, e = PromotedValues.size(); i != e; ++i) - PromotedAllocas.push_back(PromotedValues[i].first); - PromoteMemToReg(PromotedAllocas, *DT, *DF, CurAST); -} - -/// FindPromotableValuesInLoop - Check the current loop for stores to definite -/// pointers, which are not loaded and stored through may aliases and are safe -/// for promotion. If these are found, create an alloca for the value, add it -/// to the PromotedValues list, and keep track of the mapping from value to -/// alloca. -void LICM::FindPromotableValuesInLoop( - std::vector > &PromotedValues, - std::map &ValueToAllocaMap) { - Instruction *FnStart = CurLoop->getHeader()->getParent()->begin()->begin(); - - // Loop over all of the alias sets in the tracker object. - for (AliasSetTracker::iterator I = CurAST->begin(), E = CurAST->end(); - I != E; ++I) { - AliasSet &AS = *I; - // We can promote this alias set if it has a store, if it is a "Must" alias - // set, if the pointer is loop invariant, and if we are not eliminating any - // volatile loads or stores. - if (AS.isForwardingAliasSet() || !AS.isMod() || !AS.isMustAlias() || - AS.isVolatile() || !CurLoop->isLoopInvariant(AS.begin()->getValue())) - continue; + // tmp = *P; for () { if (c) tmp +=1; } *P = tmp; + // + // is not safe, because *P may only be valid to access if 'c' is true. + // + // It is safe to promote P if all uses are direct load/stores and if at + // least one is guaranteed to be executed. + bool GuaranteedToExecute = false; + + SmallVector LoopUses; + SmallPtrSet PointerMustAliases; + + // Check that all of the pointers in the alias set have the same type. We + // cannot (yet) promote a memory location that is loaded and stored in + // different sizes. + for (AliasSet::iterator ASI = AS.begin(), E = AS.end(); ASI != E; ++ASI) { + Value *ASIV = ASI->getValue(); + PointerMustAliases.insert(ASIV); - assert(!AS.empty() && - "Must alias set should have at least one pointer element in it!"); - Value *V = AS.begin()->getValue(); - // Check that all of the pointers in the alias set have the same type. We // cannot (yet) promote a memory location that is loaded and stored in // different sizes. - { - bool PointerOk = true; - for (AliasSet::iterator I = AS.begin(), E = AS.end(); I != E; ++I) - if (V->getType() != I->getValue()->getType()) { - PointerOk = false; - break; - } - if (!PointerOk) - continue; - } - - // It isn't safe to promote a load/store from the loop if the load/store is - // conditional. For example, turning: - // - // for () { if (c) *P += 1; } - // - // into: - // - // tmp = *P; for () { if (c) tmp +=1; } *P = tmp; - // - // is not safe, because *P may only be valid to access if 'c' is true. - // - // It is safe to promote P if all uses are direct load/stores and if at - // least one is guaranteed to be executed. - bool GuaranteedToExecute = false; - bool InvalidInst = false; - for (Value::use_iterator UI = V->use_begin(), UE = V->use_end(); + if (SomePtr->getType() != ASIV->getType()) + return; + + for (Value::use_iterator UI = ASIV->use_begin(), UE = ASIV->use_end(); UI != UE; ++UI) { - // Ignore instructions not in this loop. + // Ignore instructions that are outside the loop. Instruction *Use = dyn_cast(*UI); if (!Use || !CurLoop->contains(Use)) continue; - - if (!isa(Use) && !isa(Use)) { - InvalidInst = true; - break; - } + + // If there is an non-load/store instruction in the loop, we can't promote + // it. + if (isa(Use)) + assert(!cast(Use)->isVolatile() && "AST broken"); + else if (isa(Use)) { + assert(!cast(Use)->isVolatile() && "AST broken"); + if (Use->getOperand(0) == ASIV) return; + } else + return; // Not a load or store. if (!GuaranteedToExecute) GuaranteedToExecute = isSafeToExecuteUnconditionally(*Use); + + LoopUses.push_back(Use); } + } + + // If there isn't a guaranteed-to-execute instruction, we can't promote. + if (!GuaranteedToExecute) + return; + + // Otherwise, this is safe to promote, lets do it! + DEBUG(dbgs() << "LICM: Promoting value stored to in loop: " <<*SomePtr<<'\n'); + Changed = true; + ++NumPromoted; - // If there is an non-load/store instruction in the loop, we can't promote - // it. If there isn't a guaranteed-to-execute instruction, we can't - // promote. - if (InvalidInst || !GuaranteedToExecute) + // We use the SSAUpdater interface to insert phi nodes as required. + SmallVector NewPHIs; + SSAUpdater SSA(&NewPHIs); + + // It wants to know some value of the same type as what we'll be inserting. + Value *SomeValue; + if (isa(LoopUses[0])) + SomeValue = LoopUses[0]; + else + SomeValue = cast(LoopUses[0])->getOperand(0); + SSA.Initialize(SomeValue->getType(), SomeValue->getName()); + + // First step: bucket up uses of the pointers by the block they occur in. + // This is important because we have to handle multiple defs/uses in a block + // ourselves: SSAUpdater is purely for cross-block references. + // FIXME: Want a TinyVector since there is usually 0/1 element. + DenseMap > UsesByBlock; + for (unsigned i = 0, e = LoopUses.size(); i != e; ++i) { + Instruction *User = LoopUses[i]; + UsesByBlock[User->getParent()].push_back(User); + } + + // Okay, now we can iterate over all the blocks in the loop with uses, + // processing them. Keep track of which loads are loading a live-in value. + SmallVector LiveInLoads; + DenseMap ReplacedLoads; + + for (unsigned LoopUse = 0, e = LoopUses.size(); LoopUse != e; ++LoopUse) { + Instruction *User = LoopUses[LoopUse]; + std::vector &BlockUses = UsesByBlock[User->getParent()]; + + // If this block has already been processed, ignore this repeat use. + if (BlockUses.empty()) continue; + + // Okay, this is the first use in the block. If this block just has a + // single user in it, we can rewrite it trivially. + if (BlockUses.size() == 1) { + // If it is a store, it is a trivial def of the value in the block. + if (isa(User)) { + SSA.AddAvailableValue(User->getParent(), + cast(User)->getOperand(0)); + } else { + // Otherwise it is a load, queue it to rewrite as a live-in load. + LiveInLoads.push_back(cast(User)); + } + BlockUses.clear(); continue; + } - const Type *Ty = cast(V->getType())->getElementType(); - AllocaInst *AI = new AllocaInst(Ty, 0, V->getName()+".tmp", FnStart); - PromotedValues.push_back(std::make_pair(AI, V)); + // Otherwise, check to see if this block is all loads. If so, we can queue + // them all as live in loads. + bool HasStore = false; + for (unsigned i = 0, e = BlockUses.size(); i != e; ++i) { + if (isa(BlockUses[i])) { + HasStore = true; + break; + } + } + + if (!HasStore) { + for (unsigned i = 0, e = BlockUses.size(); i != e; ++i) + LiveInLoads.push_back(cast(BlockUses[i])); + BlockUses.clear(); + continue; + } - // Update the AST and alias analysis. - CurAST->copyValue(V, AI); + // Otherwise, we have mixed loads and stores (or just a bunch of stores). + // Since SSAUpdater is purely for cross-block values, we need to determine + // the order of these instructions in the block. If the first use in the + // block is a load, then it uses the live in value. The last store defines + // the live out value. We handle this by doing a linear scan of the block. + BasicBlock *BB = User->getParent(); + Value *StoredValue = 0; + for (BasicBlock::iterator II = BB->begin(), E = BB->end(); II != E; ++II) { + if (LoadInst *L = dyn_cast(II)) { + // If this is a load from an unrelated pointer, ignore it. + if (!PointerMustAliases.count(L->getOperand(0))) continue; + + // If we haven't seen a store yet, this is a live in use, otherwise + // use the stored value. + if (StoredValue) { + L->replaceAllUsesWith(StoredValue); + ReplacedLoads[L] = StoredValue; + } else { + LiveInLoads.push_back(L); + } + continue; + } + + if (StoreInst *S = dyn_cast(II)) { + // If this is a store to an unrelated pointer, ignore it. + if (!PointerMustAliases.count(S->getOperand(1))) continue; - for (AliasSet::iterator I = AS.begin(), E = AS.end(); I != E; ++I) - ValueToAllocaMap.insert(std::make_pair(I->getValue(), AI)); + // Remember that this is the active value in the block. + StoredValue = S->getOperand(0); + } + } + + // The last stored value that happened is the live-out for the block. + assert(StoredValue && "Already checked that there is a store in block"); + SSA.AddAvailableValue(BB, StoredValue); + BlockUses.clear(); + } + + // Now that all the intra-loop values are classified, set up the preheader. + // It gets a load of the pointer we're promoting, and it is the live-out value + // from the preheader. + LoadInst *PreheaderLoad = new LoadInst(SomePtr,SomePtr->getName()+".promoted", + Preheader->getTerminator()); + SSA.AddAvailableValue(Preheader, PreheaderLoad); + + // Now that the preheader is good to go, set up the exit blocks. Each exit + // block gets a store of the live-out values that feed them. Since we've + // already told the SSA updater about the defs in the loop and the preheader + // definition, it is all set and we can start using it. + SmallVector ExitBlocks; + CurLoop->getUniqueExitBlocks(ExitBlocks); + for (unsigned i = 0, e = ExitBlocks.size(); i != e; ++i) { + BasicBlock *ExitBlock = ExitBlocks[i]; + Value *LiveInValue = SSA.GetValueInMiddleOfBlock(ExitBlock); + Instruction *InsertPos = ExitBlock->getFirstNonPHI(); + new StoreInst(LiveInValue, SomePtr, InsertPos); + } - DEBUG(dbgs() << "LICM: Promoting value: " << *V << "\n"); + // Okay, now we rewrite all loads that use live-in values in the loop, + // inserting PHI nodes as necessary. + for (unsigned i = 0, e = LiveInLoads.size(); i != e; ++i) { + LoadInst *ALoad = LiveInLoads[i]; + Value *NewVal = SSA.GetValueInMiddleOfBlock(ALoad->getParent()); + ALoad->replaceAllUsesWith(NewVal); + CurAST->copyValue(ALoad, NewVal); + ReplacedLoads[ALoad] = NewVal; + } + + // If the preheader load is itself a pointer, we need to tell alias analysis + // about the new pointer we created in the preheader block and about any PHI + // nodes that just got inserted. + if (PreheaderLoad->getType()->isPointerTy()) { + // Copy any value stored to or loaded from a must-alias of the pointer. + CurAST->copyValue(SomeValue, PreheaderLoad); + + for (unsigned i = 0, e = NewPHIs.size(); i != e; ++i) + CurAST->copyValue(SomeValue, NewPHIs[i]); } + + // Now that everything is rewritten, delete the old instructions from the body + // of the loop. They should all be dead now. + for (unsigned i = 0, e = LoopUses.size(); i != e; ++i) { + Instruction *User = LoopUses[i]; + + // If this is a load that still has uses, then the load must have been added + // as a live value in the SSAUpdate data structure for a block (e.g. because + // the loaded value was stored later). In this case, we need to recursively + // propagate the updates until we get to the real value. + if (!User->use_empty()) { + Value *NewVal = ReplacedLoads[User]; + assert(NewVal && "not a replaced load?"); + + // Propagate down to the ultimate replacee. The intermediately loads + // could theoretically already have been deleted, so we don't want to + // dereference the Value*'s. + DenseMap::iterator RLI = ReplacedLoads.find(NewVal); + while (RLI != ReplacedLoads.end()) { + NewVal = RLI->second; + RLI = ReplacedLoads.find(NewVal); + } + + User->replaceAllUsesWith(NewVal); + CurAST->copyValue(User, NewVal); + } + + CurAST->deleteValue(User); + User->eraseFromParent(); + } + + // fwew, we're done! } + /// cloneBasicBlockAnalysis - Simple Analysis hook. Clone alias set info. void LICM::cloneBasicBlockAnalysis(BasicBlock *From, BasicBlock *To, Loop *L) { - AliasSetTracker *AST = LoopToAliasMap[L]; + AliasSetTracker *AST = LoopToAliasSetMap.lookup(L); if (!AST) return; @@ -873,7 +909,7 @@ void LICM::cloneBasicBlockAnalysis(BasicBlock *From, BasicBlock *To, Loop *L) { /// deleteAnalysisValue - Simple Analysis hook. Delete value V from alias /// set. void LICM::deleteAnalysisValue(Value *V, Loop *L) { - AliasSetTracker *AST = LoopToAliasMap[L]; + AliasSetTracker *AST = LoopToAliasSetMap.lookup(L); if (!AST) return; diff --git a/lib/Transforms/Scalar/LoopDeletion.cpp b/lib/Transforms/Scalar/LoopDeletion.cpp index e4894e9..543dfc1 100644 --- a/lib/Transforms/Scalar/LoopDeletion.cpp +++ b/lib/Transforms/Scalar/LoopDeletion.cpp @@ -28,7 +28,7 @@ namespace { class LoopDeletion : public LoopPass { public: static char ID; // Pass ID, replacement for typeid - LoopDeletion() : LoopPass(&ID) {} + LoopDeletion() : LoopPass(ID) {} // Possibly eliminate loop L if it is dead. bool runOnLoop(Loop* L, LPPassManager& LPM); @@ -38,9 +38,9 @@ namespace { bool &Changed, BasicBlock *Preheader); virtual void getAnalysisUsage(AnalysisUsage& AU) const { - AU.addRequired(); AU.addRequired(); AU.addRequired(); + AU.addRequired(); AU.addRequiredID(LoopSimplifyID); AU.addRequiredID(LCSSAID); @@ -55,7 +55,8 @@ namespace { } char LoopDeletion::ID = 0; -static RegisterPass X("loop-deletion", "Delete dead loops"); +INITIALIZE_PASS(LoopDeletion, "loop-deletion", + "Delete dead loops", false, false); Pass* llvm::createLoopDeletionPass() { return new LoopDeletion(); diff --git a/lib/Transforms/Scalar/LoopIndexSplit.cpp b/lib/Transforms/Scalar/LoopIndexSplit.cpp index 31058e5..a433674 100644 --- a/lib/Transforms/Scalar/LoopIndexSplit.cpp +++ b/lib/Transforms/Scalar/LoopIndexSplit.cpp @@ -74,7 +74,7 @@ namespace { class LoopIndexSplit : public LoopPass { public: static char ID; // Pass ID, replacement for typeid - LoopIndexSplit() : LoopPass(&ID) {} + LoopIndexSplit() : LoopPass(ID) {} // Index split Loop L. Return true if loop is split. bool runOnLoop(Loop *L, LPPassManager &LPM); @@ -197,8 +197,8 @@ namespace { } char LoopIndexSplit::ID = 0; -static RegisterPass -X("loop-index-split", "Index Split Loops"); +INITIALIZE_PASS(LoopIndexSplit, "loop-index-split", + "Index Split Loops", false, false); Pass *llvm::createLoopIndexSplitPass() { return new LoopIndexSplit(); @@ -677,7 +677,7 @@ void LoopIndexSplit::removeBlocks(BasicBlock *DeadBB, Loop *LP, for(pred_iterator PI = pred_begin(FrontierBB), PE = pred_end(FrontierBB); PI != PE; ++PI) { BasicBlock *P = *PI; - if (P == DeadBB || DT->dominates(DeadBB, P)) + if (DT->dominates(DeadBB, P)) PredBlocks.push_back(P); } @@ -799,7 +799,7 @@ void LoopIndexSplit::moveExitCondition(BasicBlock *CondBB, BasicBlock *ActiveBB, // the dominance frontiers. for (Loop::block_iterator I = LP->block_begin(), E = LP->block_end(); I != E; ++I) { - if (*I == CondBB || !DT->dominates(CondBB, *I)) continue; + if (!DT->properlyDominates(CondBB, *I)) continue; DominanceFrontier::iterator BBDF = DF->find(*I); DominanceFrontier::DomSetType::iterator DomSetI = BBDF->second.begin(); DominanceFrontier::DomSetType::iterator DomSetE = BBDF->second.end(); @@ -1183,7 +1183,7 @@ bool LoopIndexSplit::cleanBlock(BasicBlock *BB) { bool usedOutsideBB = false; for (Value::use_iterator UI = I->use_begin(), UE = I->use_end(); UI != UE; ++UI) { - Instruction *U = cast(UI); + Instruction *U = cast(*UI); if (U->getParent() != BB) usedOutsideBB = true; } diff --git a/lib/Transforms/Scalar/LoopRotation.cpp b/lib/Transforms/Scalar/LoopRotation.cpp index 16c4a15..65acc1d 100644 --- a/lib/Transforms/Scalar/LoopRotation.cpp +++ b/lib/Transforms/Scalar/LoopRotation.cpp @@ -35,7 +35,7 @@ namespace { class LoopRotate : public LoopPass { public: static char ID; // Pass ID, replacement for typeid - LoopRotate() : LoopPass(&ID) {} + LoopRotate() : LoopPass(ID) {} // Rotate Loop L as many times as possible. Return true if // loop is rotated at least once. @@ -43,15 +43,15 @@ namespace { // LCSSA form makes instruction renaming easier. virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addPreserved(); + AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); AU.addRequiredID(LoopSimplifyID); AU.addPreservedID(LoopSimplifyID); AU.addRequiredID(LCSSAID); AU.addPreservedID(LCSSAID); AU.addPreserved(); - AU.addRequired(); - AU.addPreserved(); - AU.addPreserved(); - AU.addPreserved(); } // Helper functions @@ -79,7 +79,7 @@ namespace { } char LoopRotate::ID = 0; -static RegisterPass X("loop-rotate", "Rotate Loops"); +INITIALIZE_PASS(LoopRotate, "loop-rotate", "Rotate Loops", false, false); Pass *llvm::createLoopRotatePass() { return new LoopRotate(); } @@ -221,7 +221,7 @@ bool LoopRotate::rotateLoop(Loop *Lp, LPPassManager &LPM) { // The value now exits in two versions: the initial value in the preheader // and the loop "next" value in the original header. - SSA.Initialize(OrigHeaderVal); + SSA.Initialize(OrigHeaderVal->getType(), OrigHeaderVal->getName()); SSA.AddAvailableValue(OrigHeader, OrigHeaderVal); SSA.AddAvailableValue(OrigPreHeader, OrigPreHeaderVal); @@ -261,6 +261,26 @@ bool LoopRotate::rotateLoop(Loop *Lp, LPPassManager &LPM) { // NewHeader is now the header of the loop. L->moveToHeader(NewHeader); + // Move the original header to the bottom of the loop, where it now more + // naturally belongs. This isn't necessary for correctness, and CodeGen can + // usually reorder blocks on its own to fix things like this up, but it's + // still nice to keep the IR readable. + // + // The original header should have only one predecessor at this point, since + // we checked that the loop had a proper preheader and unique backedge before + // we started. + assert(OrigHeader->getSinglePredecessor() && + "Original loop header has too many predecessors after loop rotation!"); + OrigHeader->moveAfter(OrigHeader->getSinglePredecessor()); + + // Also, since this original header only has one predecessor, zap its + // PHI nodes, which are now trivial. + FoldSingleEntryPHINodes(OrigHeader); + + // TODO: We could just go ahead and merge OrigHeader into its predecessor + // at this point, if we don't mind updating dominator info. + + // Establish a new preheader, update dominators, etc. preserveCanonicalLoopForm(LPM); ++NumRotated; diff --git a/lib/Transforms/Scalar/LoopStrengthReduce.cpp b/lib/Transforms/Scalar/LoopStrengthReduce.cpp index 1f9b415..e8dc5d3 100644 --- a/lib/Transforms/Scalar/LoopStrengthReduce.cpp +++ b/lib/Transforms/Scalar/LoopStrengthReduce.cpp @@ -161,9 +161,10 @@ RegUseTracker::DropUse(size_t LUIdx) { bool RegUseTracker::isRegUsedByUsesOtherThan(const SCEV *Reg, size_t LUIdx) const { - if (!RegUsesMap.count(Reg)) return false; - const SmallBitVector &UsedByIndices = - RegUsesMap.find(Reg)->second.UsedByIndices; + RegUsesTy::const_iterator I = RegUsesMap.find(Reg); + if (I == RegUsesMap.end()) + return false; + const SmallBitVector &UsedByIndices = I->second.UsedByIndices; int i = UsedByIndices.find_first(); if (i == -1) return false; if ((size_t)i != LUIdx) return true; @@ -441,12 +442,12 @@ static const SCEV *getExactSDiv(const SCEV *LHS, const SCEV *RHS, // Distribute the sdiv over addrec operands, if the addrec doesn't overflow. if (const SCEVAddRecExpr *AR = dyn_cast(LHS)) { if (IgnoreSignificantBits || isAddRecSExtable(AR, SE)) { - const SCEV *Start = getExactSDiv(AR->getStart(), RHS, SE, - IgnoreSignificantBits); - if (!Start) return 0; const SCEV *Step = getExactSDiv(AR->getStepRecurrence(SE), RHS, SE, IgnoreSignificantBits); if (!Step) return 0; + const SCEV *Start = getExactSDiv(AR->getStart(), RHS, SE, + IgnoreSignificantBits); + if (!Start) return 0; return SE.getAddRecExpr(Start, Step, AR->getLoop()); } return 0; @@ -505,12 +506,14 @@ static int64_t ExtractImmediate(const SCEV *&S, ScalarEvolution &SE) { } else if (const SCEVAddExpr *Add = dyn_cast(S)) { SmallVector NewOps(Add->op_begin(), Add->op_end()); int64_t Result = ExtractImmediate(NewOps.front(), SE); - S = SE.getAddExpr(NewOps); + if (Result != 0) + S = SE.getAddExpr(NewOps); return Result; } else if (const SCEVAddRecExpr *AR = dyn_cast(S)) { SmallVector NewOps(AR->op_begin(), AR->op_end()); int64_t Result = ExtractImmediate(NewOps.front(), SE); - S = SE.getAddRecExpr(NewOps, AR->getLoop()); + if (Result != 0) + S = SE.getAddRecExpr(NewOps, AR->getLoop()); return Result; } return 0; @@ -528,12 +531,14 @@ static GlobalValue *ExtractSymbol(const SCEV *&S, ScalarEvolution &SE) { } else if (const SCEVAddExpr *Add = dyn_cast(S)) { SmallVector NewOps(Add->op_begin(), Add->op_end()); GlobalValue *Result = ExtractSymbol(NewOps.back(), SE); - S = SE.getAddExpr(NewOps); + if (Result) + S = SE.getAddExpr(NewOps); return Result; } else if (const SCEVAddRecExpr *AR = dyn_cast(S)) { SmallVector NewOps(AR->op_begin(), AR->op_end()); GlobalValue *Result = ExtractSymbol(NewOps.front(), SE); - S = SE.getAddRecExpr(NewOps, AR->getLoop()); + if (Result) + S = SE.getAddRecExpr(NewOps, AR->getLoop()); return Result; } return 0; @@ -965,6 +970,12 @@ public: /// may be used. bool AllFixupsOutsideLoop; + /// WidestFixupType - This records the widest use type for any fixup using + /// this LSRUse. FindUseWithSimilarFormula can't consider uses with different + /// max fixup widths to be equivalent, because the narrower one may be relying + /// on the implicit truncation to truncate away bogus bits. + const Type *WidestFixupType; + /// Formulae - A list of ways to build a value that can satisfy this user. /// After the list is populated, one of these is selected heuristically and /// used to formulate a replacement for OperandValToReplace in UserInst. @@ -976,15 +987,14 @@ public: LSRUse(KindType K, const Type *T) : Kind(K), AccessTy(T), MinOffset(INT64_MAX), MaxOffset(INT64_MIN), - AllFixupsOutsideLoop(true) {} + AllFixupsOutsideLoop(true), + WidestFixupType(0) {} bool HasFormulaWithSameRegs(const Formula &F) const; bool InsertFormula(const Formula &F); void DeleteFormula(Formula &F); void RecomputeRegs(size_t LUIdx, RegUseTracker &Reguses); - void check() const; - void print(raw_ostream &OS) const; void dump() const; }; @@ -1076,13 +1086,16 @@ void LSRUse::print(raw_ostream &OS) const { for (SmallVectorImpl::const_iterator I = Offsets.begin(), E = Offsets.end(); I != E; ++I) { OS << *I; - if (next(I) != E) + if (llvm::next(I) != E) OS << ','; } OS << '}'; if (AllFixupsOutsideLoop) OS << ", all-fixups-outside-loop"; + + if (WidestFixupType) + OS << ", widest fixup type: " << *WidestFixupType; } void LSRUse::dump() const { @@ -1354,6 +1367,10 @@ public: void FilterOutUndesirableDedicatedRegisters(); size_t EstimateSearchSpaceComplexity() const; + void NarrowSearchSpaceByDetectingSupersets(); + void NarrowSearchSpaceByCollapsingUnrolledCode(); + void NarrowSearchSpaceByRefilteringUndesirableDedicatedRegisters(); + void NarrowSearchSpaceByPickingWinnerRegs(); void NarrowSearchSpaceUsingHeuristics(); void SolveRecurse(SmallVectorImpl &Solution, @@ -1587,7 +1604,7 @@ ICmpInst *LSRInstance::OptimizeMax(ICmpInst *Cond, IVStrideUse* &CondUse) { const SCEV *One = SE.getConstant(BackedgeTakenCount->getType(), 1); // Add one to the backedge-taken count to get the trip count. - const SCEV *IterationCount = SE.getAddExpr(BackedgeTakenCount, One); + const SCEV *IterationCount = SE.getAddExpr(One, BackedgeTakenCount); if (IterationCount != SE.getSCEV(Sel)) return Cond; // Check for a max calculation that matches the pattern. There's no check @@ -1919,32 +1936,41 @@ void LSRInstance::DeleteUse(LSRUse &LU) { LSRUse * LSRInstance::FindUseWithSimilarFormula(const Formula &OrigF, const LSRUse &OrigLU) { - // Search all uses for the formula. This could be more clever. Ignore - // ICmpZero uses because they may contain formulae generated by - // GenerateICmpZeroScales, in which case adding fixup offsets may - // be invalid. + // Search all uses for the formula. This could be more clever. for (size_t LUIdx = 0, NumUses = Uses.size(); LUIdx != NumUses; ++LUIdx) { LSRUse &LU = Uses[LUIdx]; + // Check whether this use is close enough to OrigLU, to see whether it's + // worthwhile looking through its formulae. + // Ignore ICmpZero uses because they may contain formulae generated by + // GenerateICmpZeroScales, in which case adding fixup offsets may + // be invalid. if (&LU != &OrigLU && LU.Kind != LSRUse::ICmpZero && LU.Kind == OrigLU.Kind && OrigLU.AccessTy == LU.AccessTy && + LU.WidestFixupType == OrigLU.WidestFixupType && LU.HasFormulaWithSameRegs(OrigF)) { + // Scan through this use's formulae. for (SmallVectorImpl::const_iterator I = LU.Formulae.begin(), E = LU.Formulae.end(); I != E; ++I) { const Formula &F = *I; + // Check to see if this formula has the same registers and symbols + // as OrigF. if (F.BaseRegs == OrigF.BaseRegs && F.ScaledReg == OrigF.ScaledReg && F.AM.BaseGV == OrigF.AM.BaseGV && - F.AM.Scale == OrigF.AM.Scale && - LU.Kind) { + F.AM.Scale == OrigF.AM.Scale) { if (F.AM.BaseOffs == 0) return &LU; + // This is the formula where all the registers and symbols matched; + // there aren't going to be any others. Since we declined it, we + // can skip the rest of the formulae and procede to the next LSRUse. break; } } } } + // Nothing looked good. return 0; } @@ -1976,7 +2002,7 @@ void LSRInstance::CollectInterestingTypesAndFactors() { for (SmallSetVector::const_iterator I = Strides.begin(), E = Strides.end(); I != E; ++I) for (SmallSetVector::const_iterator NewStrideIter = - next(I); NewStrideIter != E; ++NewStrideIter) { + llvm::next(I); NewStrideIter != E; ++NewStrideIter) { const SCEV *OldStride = *I; const SCEV *NewStride = *NewStrideIter; @@ -2066,6 +2092,10 @@ void LSRInstance::CollectFixupsAndInitialFormulae() { LF.Offset = P.second; LSRUse &LU = Uses[LF.LUIdx]; LU.AllFixupsOutsideLoop &= LF.isUseFullyOutsideLoop(L); + if (!LU.WidestFixupType || + SE.getTypeSizeInBits(LU.WidestFixupType) < + SE.getTypeSizeInBits(LF.OperandValToReplace->getType())) + LU.WidestFixupType = LF.OperandValToReplace->getType(); // If this is the first use of this LSRUse, give it a formula. if (LU.Formulae.empty()) { @@ -2195,6 +2225,10 @@ LSRInstance::CollectLoopInvariantFixupsAndFormulae() { LF.Offset = P.second; LSRUse &LU = Uses[LF.LUIdx]; LU.AllFixupsOutsideLoop &= LF.isUseFullyOutsideLoop(L); + if (!LU.WidestFixupType || + SE.getTypeSizeInBits(LU.WidestFixupType) < + SE.getTypeSizeInBits(LF.OperandValToReplace->getType())) + LU.WidestFixupType = LF.OperandValToReplace->getType(); InsertSupplementalFormula(U, LU, LF.LUIdx); CountRegisters(LU.Formulae.back(), Uses.size() - 1); break; @@ -2207,14 +2241,13 @@ LSRInstance::CollectLoopInvariantFixupsAndFormulae() { /// separate registers. If C is non-null, multiply each subexpression by C. static void CollectSubexprs(const SCEV *S, const SCEVConstant *C, SmallVectorImpl &Ops, - SmallVectorImpl &UninterestingOps, const Loop *L, ScalarEvolution &SE) { if (const SCEVAddExpr *Add = dyn_cast(S)) { // Break out add operands. for (SCEVAddExpr::op_iterator I = Add->op_begin(), E = Add->op_end(); I != E; ++I) - CollectSubexprs(*I, C, Ops, UninterestingOps, L, SE); + CollectSubexprs(*I, C, Ops, L, SE); return; } else if (const SCEVAddRecExpr *AR = dyn_cast(S)) { // Split a non-zero base out of an addrec. @@ -2222,8 +2255,8 @@ static void CollectSubexprs(const SCEV *S, const SCEVConstant *C, CollectSubexprs(SE.getAddRecExpr(SE.getConstant(AR->getType(), 0), AR->getStepRecurrence(SE), AR->getLoop()), - C, Ops, UninterestingOps, L, SE); - CollectSubexprs(AR->getStart(), C, Ops, UninterestingOps, L, SE); + C, Ops, L, SE); + CollectSubexprs(AR->getStart(), C, Ops, L, SE); return; } } else if (const SCEVMulExpr *Mul = dyn_cast(S)) { @@ -2233,17 +2266,13 @@ static void CollectSubexprs(const SCEV *S, const SCEVConstant *C, dyn_cast(Mul->getOperand(0))) { CollectSubexprs(Mul->getOperand(1), C ? cast(SE.getMulExpr(C, Op0)) : Op0, - Ops, UninterestingOps, L, SE); + Ops, L, SE); return; } } - // Otherwise use the value itself. Loop-variant "unknown" values are - // uninteresting; we won't be able to do anything meaningful with them. - if (!C && isa(S) && !S->isLoopInvariant(L)) - UninterestingOps.push_back(S); - else - Ops.push_back(C ? SE.getMulExpr(C, S) : S); + // Otherwise use the value itself, optionally with a scale applied. + Ops.push_back(C ? SE.getMulExpr(C, S) : S); } /// GenerateReassociations - Split out subexpressions from adds and the bases of @@ -2257,19 +2286,19 @@ void LSRInstance::GenerateReassociations(LSRUse &LU, unsigned LUIdx, for (size_t i = 0, e = Base.BaseRegs.size(); i != e; ++i) { const SCEV *BaseReg = Base.BaseRegs[i]; - SmallVector AddOps, UninterestingAddOps; - CollectSubexprs(BaseReg, 0, AddOps, UninterestingAddOps, L, SE); - - // Add any uninteresting values as one register, as we won't be able to - // form any interesting reassociation opportunities with them. They'll - // just have to be added inside the loop no matter what we do. - if (!UninterestingAddOps.empty()) - AddOps.push_back(SE.getAddExpr(UninterestingAddOps)); + SmallVector AddOps; + CollectSubexprs(BaseReg, 0, AddOps, L, SE); if (AddOps.size() == 1) continue; for (SmallVectorImpl::const_iterator J = AddOps.begin(), JE = AddOps.end(); J != JE; ++J) { + + // Loop-variant "unknown" values are uninteresting; we won't be able to + // do anything meaningful with them. + if (isa(*J) && !(*J)->isLoopInvariant(L)) + continue; + // Don't pull a constant into a register if the constant could be folded // into an immediate field. if (isAlwaysFoldable(*J, LU.MinOffset, LU.MaxOffset, @@ -2279,9 +2308,9 @@ void LSRInstance::GenerateReassociations(LSRUse &LU, unsigned LUIdx, // Collect all operands except *J. SmallVector InnerAddOps - ( ((const SmallVector &)AddOps).begin(), J); + (((const SmallVector &)AddOps).begin(), J); InnerAddOps.append - (next(J), ((const SmallVector &)AddOps).end()); + (llvm::next(J), ((const SmallVector &)AddOps).end()); // Don't leave just a constant behind in a register if the constant could // be folded into an immediate field. @@ -2377,7 +2406,7 @@ void LSRInstance::GenerateConstantOffsets(LSRUse &LU, unsigned LUIdx, if (isLegalUse(F.AM, LU.MinOffset - *I, LU.MaxOffset - *I, LU.Kind, LU.AccessTy, TLI)) { // Add the offset to the base register. - const SCEV *NewG = SE.getAddExpr(G, SE.getConstant(G->getType(), *I)); + const SCEV *NewG = SE.getAddExpr(SE.getConstant(G->getType(), *I), G); // If it cancelled out, drop the base register, otherwise update it. if (NewG->isZero()) { std::swap(F.BaseRegs[i], F.BaseRegs.back()); @@ -2778,6 +2807,10 @@ LSRInstance::GenerateAllReuseFormulae() { } GenerateCrossUseConstantOffsets(); + + DEBUG(dbgs() << "\n" + "After generating reuse formulae:\n"; + print_uses(dbgs())); } /// If their are multiple formulae with the same set of registers used @@ -2876,11 +2909,11 @@ size_t LSRInstance::EstimateSearchSpaceComplexity() const { return Power; } -/// NarrowSearchSpaceUsingHeuristics - If there are an extraordinary number of -/// formulae to choose from, use some rough heuristics to prune down the number -/// of formulae. This keeps the main solver from taking an extraordinary amount -/// of time in some worst-case scenarios. -void LSRInstance::NarrowSearchSpaceUsingHeuristics() { +/// NarrowSearchSpaceByDetectingSupersets - When one formula uses a superset +/// of the registers of another formula, it won't help reduce register +/// pressure (though it may not necessarily hurt register pressure); remove +/// it to simplify the system. +void LSRInstance::NarrowSearchSpaceByDetectingSupersets() { if (EstimateSearchSpaceComplexity() >= ComplexityLimit) { DEBUG(dbgs() << "The search space is too complex.\n"); @@ -2938,7 +2971,12 @@ void LSRInstance::NarrowSearchSpaceUsingHeuristics() { DEBUG(dbgs() << "After pre-selection:\n"; print_uses(dbgs())); } +} +/// NarrowSearchSpaceByCollapsingUnrolledCode - When there are many registers +/// for expressions like A, A+1, A+2, etc., allocate a single register for +/// them. +void LSRInstance::NarrowSearchSpaceByCollapsingUnrolledCode() { if (EstimateSearchSpaceComplexity() >= ComplexityLimit) { DEBUG(dbgs() << "The search space is too complex.\n"); @@ -2988,7 +3026,7 @@ void LSRInstance::NarrowSearchSpaceUsingHeuristics() { if (Fixup.LUIdx == LUIdx) { Fixup.LUIdx = LUThatHas - &Uses.front(); Fixup.Offset += F.AM.BaseOffs; - DEBUG(errs() << "New fixup has offset " + DEBUG(dbgs() << "New fixup has offset " << Fixup.Offset << '\n'); } if (Fixup.LUIdx == NumUses-1) @@ -3009,7 +3047,30 @@ void LSRInstance::NarrowSearchSpaceUsingHeuristics() { DEBUG(dbgs() << "After pre-selection:\n"; print_uses(dbgs())); } +} + +/// NarrowSearchSpaceByRefilteringUndesirableDedicatedRegisters - Call +/// FilterOutUndesirableDedicatedRegisters again, if necessary, now that +/// we've done more filtering, as it may be able to find more formulae to +/// eliminate. +void LSRInstance::NarrowSearchSpaceByRefilteringUndesirableDedicatedRegisters(){ + if (EstimateSearchSpaceComplexity() >= ComplexityLimit) { + DEBUG(dbgs() << "The search space is too complex.\n"); + + DEBUG(dbgs() << "Narrowing the search space by re-filtering out " + "undesirable dedicated registers.\n"); + + FilterOutUndesirableDedicatedRegisters(); + + DEBUG(dbgs() << "After pre-selection:\n"; + print_uses(dbgs())); + } +} +/// NarrowSearchSpaceByPickingWinnerRegs - Pick a register which seems likely +/// to be profitable, and then in any use which has any reference to that +/// register, delete all formulae which do not reference that register. +void LSRInstance::NarrowSearchSpaceByPickingWinnerRegs() { // With all other options exhausted, loop until the system is simple // enough to handle. SmallPtrSet Taken; @@ -3071,6 +3132,17 @@ void LSRInstance::NarrowSearchSpaceUsingHeuristics() { } } +/// NarrowSearchSpaceUsingHeuristics - If there are an extraordinary number of +/// formulae to choose from, use some rough heuristics to prune down the number +/// of formulae. This keeps the main solver from taking an extraordinary amount +/// of time in some worst-case scenarios. +void LSRInstance::NarrowSearchSpaceUsingHeuristics() { + NarrowSearchSpaceByDetectingSupersets(); + NarrowSearchSpaceByCollapsingUnrolledCode(); + NarrowSearchSpaceByRefilteringUndesirableDedicatedRegisters(); + NarrowSearchSpaceByPickingWinnerRegs(); +} + /// SolveRecurse - This is the recursive solver. void LSRInstance::SolveRecurse(SmallVectorImpl &Solution, Cost &SolutionCost, @@ -3614,10 +3686,6 @@ LSRInstance::LSRInstance(const TargetLowering *tli, Loop *l, Pass *P) // to formulate the values needed for the uses. GenerateAllReuseFormulae(); - DEBUG(dbgs() << "\n" - "After generating reuse formulae:\n"; - print_uses(dbgs())); - FilterOutUndesirableDedicatedRegisters(); NarrowSearchSpaceUsingHeuristics(); @@ -3724,15 +3792,15 @@ private: } char LoopStrengthReduce::ID = 0; -static RegisterPass -X("loop-reduce", "Loop Strength Reduction"); +INITIALIZE_PASS(LoopStrengthReduce, "loop-reduce", + "Loop Strength Reduction", false, false); Pass *llvm::createLoopStrengthReducePass(const TargetLowering *TLI) { return new LoopStrengthReduce(TLI); } LoopStrengthReduce::LoopStrengthReduce(const TargetLowering *tli) - : LoopPass(&ID), TLI(tli) {} + : LoopPass(ID), TLI(tli) {} void LoopStrengthReduce::getAnalysisUsage(AnalysisUsage &AU) const { // We split critical edges, so we change the CFG. However, we do update diff --git a/lib/Transforms/Scalar/LoopUnrollPass.cpp b/lib/Transforms/Scalar/LoopUnrollPass.cpp index 4ad41ae..d0edfa2 100644 --- a/lib/Transforms/Scalar/LoopUnrollPass.cpp +++ b/lib/Transforms/Scalar/LoopUnrollPass.cpp @@ -17,6 +17,7 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/InlineCost.h" +#include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -26,7 +27,7 @@ using namespace llvm; static cl::opt -UnrollThreshold("unroll-threshold", cl::init(100), cl::Hidden, +UnrollThreshold("unroll-threshold", cl::init(200), cl::Hidden, cl::desc("The cut-off point for automatic loop unrolling")); static cl::opt @@ -42,7 +43,7 @@ namespace { class LoopUnroll : public LoopPass { public: static char ID; // Pass ID, replacement for typeid - LoopUnroll() : LoopPass(&ID) {} + LoopUnroll() : LoopPass(ID) {} /// A magic value for use with the Threshold parameter to indicate /// that the loop unroll should be performed regardless of how much @@ -55,23 +56,24 @@ namespace { /// loop preheaders be inserted into the CFG... /// virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + AU.addPreserved(); AU.addRequiredID(LoopSimplifyID); + AU.addPreservedID(LoopSimplifyID); AU.addRequiredID(LCSSAID); - AU.addRequired(); AU.addPreservedID(LCSSAID); - AU.addPreserved(); + AU.addPreserved(); // FIXME: Loop unroll requires LCSSA. And LCSSA requires dom info. // If loop unroll does not preserve dom info then LCSSA pass on next // loop will receive invalid dom info. // For now, recreate dom info, if loop is unrolled. AU.addPreserved(); - AU.addPreserved(); } }; } char LoopUnroll::ID = 0; -static RegisterPass X("loop-unroll", "Unroll loops"); +INITIALIZE_PASS(LoopUnroll, "loop-unroll", "Unroll loops", false, false); Pass *llvm::createLoopUnrollPass() { return new LoopUnroll(); } @@ -145,12 +147,7 @@ bool LoopUnroll::runOnLoop(Loop *L, LPPassManager &LPM) { return false; // FIXME: Reconstruct dom info, because it is not preserved properly. - DominatorTree *DT = getAnalysisIfAvailable(); - if (DT) { + if (DominatorTree *DT = getAnalysisIfAvailable()) DT->runOnFunction(*F); - DominanceFrontier *DF = getAnalysisIfAvailable(); - if (DF) - DF->runOnFunction(*F); - } return true; } diff --git a/lib/Transforms/Scalar/LoopUnswitch.cpp b/lib/Transforms/Scalar/LoopUnswitch.cpp index 0c900ff..9afe428 100644 --- a/lib/Transforms/Scalar/LoopUnswitch.cpp +++ b/lib/Transforms/Scalar/LoopUnswitch.cpp @@ -77,7 +77,6 @@ namespace { bool redoLoop; Loop *currentLoop; - DominanceFrontier *DF; DominatorTree *DT; BasicBlock *loopHeader; BasicBlock *loopPreheader; @@ -92,15 +91,15 @@ namespace { public: static char ID; // Pass ID, replacement for typeid explicit LoopUnswitch(bool Os = false) : - LoopPass(&ID), OptimizeForSize(Os), redoLoop(false), - currentLoop(NULL), DF(NULL), DT(NULL), loopHeader(NULL), + LoopPass(ID), OptimizeForSize(Os), redoLoop(false), + currentLoop(NULL), DT(NULL), loopHeader(NULL), loopPreheader(NULL) {} bool runOnLoop(Loop *L, LPPassManager &LPM); bool processCurrentLoop(); /// This transformation requires natural loop information & requires that - /// loop preheaders be inserted into the CFG... + /// loop preheaders be inserted into the CFG. /// virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequiredID(LoopSimplifyID); @@ -110,7 +109,6 @@ namespace { AU.addRequiredID(LCSSAID); AU.addPreservedID(LCSSAID); AU.addPreserved(); - AU.addPreserved(); } private: @@ -160,7 +158,7 @@ namespace { }; } char LoopUnswitch::ID = 0; -static RegisterPass X("loop-unswitch", "Unswitch loops"); +INITIALIZE_PASS(LoopUnswitch, "loop-unswitch", "Unswitch loops", false, false); Pass *llvm::createLoopUnswitchPass(bool Os) { return new LoopUnswitch(Os); @@ -201,7 +199,6 @@ static Value *FindLIVLoopCondition(Value *Cond, Loop *L, bool &Changed) { bool LoopUnswitch::runOnLoop(Loop *L, LPPassManager &LPM_Ref) { LI = &getAnalysis(); LPM = &LPM_Ref; - DF = getAnalysisIfAvailable(); DT = getAnalysisIfAvailable(); currentLoop = L; Function *F = currentLoop->getHeader()->getParent(); @@ -216,8 +213,6 @@ bool LoopUnswitch::runOnLoop(Loop *L, LPPassManager &LPM_Ref) { // FIXME: Reconstruct dom info, because it is not preserved properly. if (DT) DT->runOnFunction(*F); - if (DF) - DF->runOnFunction(*F); } return Changed; } @@ -282,19 +277,18 @@ bool LoopUnswitch::processCurrentLoop() { return Changed; } -/// isTrivialLoopExitBlock - Check to see if all paths from BB either: -/// 1. Exit the loop with no side effects. -/// 2. Branch to the latch block with no side-effects. +/// isTrivialLoopExitBlock - Check to see if all paths from BB exit the +/// loop with no side effects (including infinite loops). /// -/// If these conditions are true, we return true and set ExitBB to the block we +/// If true, we return true and set ExitBB to the block we /// exit through. /// static bool isTrivialLoopExitBlockHelper(Loop *L, BasicBlock *BB, BasicBlock *&ExitBB, std::set &Visited) { if (!Visited.insert(BB).second) { - // Already visited and Ok, end of recursion. - return true; + // Already visited. Without more analysis, this could indicate an infinte loop. + return false; } else if (!L->contains(BB)) { // Otherwise, this is a loop exit, this is fine so long as this is the // first exit. @@ -324,7 +318,7 @@ static bool isTrivialLoopExitBlockHelper(Loop *L, BasicBlock *BB, /// process. If so, return the block that is exited to, otherwise return null. static BasicBlock *isTrivialLoopExitBlock(Loop *L, BasicBlock *BB) { std::set Visited; - Visited.insert(L->getHeader()); // Branches to header are ok. + Visited.insert(L->getHeader()); // Branches to header make infinite loops. BasicBlock *ExitBB = 0; if (isTrivialLoopExitBlockHelper(L, BB, ExitBB, Visited)) return ExitBB; @@ -356,8 +350,8 @@ bool LoopUnswitch::IsTrivialUnswitchCondition(Value *Cond, Constant **Val, if (!BI->isConditional() || BI->getCondition() != Cond) return false; - // Check to see if a successor of the branch is guaranteed to go to the - // latch block or exit through a one exit block without having any + // Check to see if a successor of the branch is guaranteed to + // exit through a unique exit block without having any // side-effects. If so, determine the value of Cond that causes it to do // this. if ((LoopExitBB = isTrivialLoopExitBlock(currentLoop, diff --git a/lib/Transforms/Scalar/LowerAtomic.cpp b/lib/Transforms/Scalar/LowerAtomic.cpp new file mode 100644 index 0000000..973ffe7 --- /dev/null +++ b/lib/Transforms/Scalar/LowerAtomic.cpp @@ -0,0 +1,161 @@ +//===- LowerAtomic.cpp - Lower atomic intrinsics --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass lowers atomic intrinsics to non-atomic form for use in a known +// non-preemptible environment. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "loweratomic" +#include "llvm/Transforms/Scalar.h" +#include "llvm/BasicBlock.h" +#include "llvm/Function.h" +#include "llvm/Instruction.h" +#include "llvm/Instructions.h" +#include "llvm/Intrinsics.h" +#include "llvm/Pass.h" +#include "llvm/Support/IRBuilder.h" + +using namespace llvm; + +namespace { + +bool LowerAtomicIntrinsic(CallInst *CI) { + IRBuilder<> Builder(CI->getParent(), CI); + + Function *Callee = CI->getCalledFunction(); + if (!Callee) + return false; + + unsigned IID = Callee->getIntrinsicID(); + switch (IID) { + case Intrinsic::memory_barrier: + break; + + case Intrinsic::atomic_load_add: + case Intrinsic::atomic_load_sub: + case Intrinsic::atomic_load_and: + case Intrinsic::atomic_load_nand: + case Intrinsic::atomic_load_or: + case Intrinsic::atomic_load_xor: + case Intrinsic::atomic_load_max: + case Intrinsic::atomic_load_min: + case Intrinsic::atomic_load_umax: + case Intrinsic::atomic_load_umin: { + Value *Ptr = CI->getArgOperand(0); + Value *Delta = CI->getArgOperand(1); + + LoadInst *Orig = Builder.CreateLoad(Ptr); + Value *Res = NULL; + switch (IID) { + default: assert(0 && "Unrecognized atomic modify operation"); + case Intrinsic::atomic_load_add: + Res = Builder.CreateAdd(Orig, Delta); + break; + case Intrinsic::atomic_load_sub: + Res = Builder.CreateSub(Orig, Delta); + break; + case Intrinsic::atomic_load_and: + Res = Builder.CreateAnd(Orig, Delta); + break; + case Intrinsic::atomic_load_nand: + Res = Builder.CreateNot(Builder.CreateAnd(Orig, Delta)); + break; + case Intrinsic::atomic_load_or: + Res = Builder.CreateOr(Orig, Delta); + break; + case Intrinsic::atomic_load_xor: + Res = Builder.CreateXor(Orig, Delta); + break; + case Intrinsic::atomic_load_max: + Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta), + Delta, + Orig); + break; + case Intrinsic::atomic_load_min: + Res = Builder.CreateSelect(Builder.CreateICmpSLT(Orig, Delta), + Orig, + Delta); + break; + case Intrinsic::atomic_load_umax: + Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta), + Delta, + Orig); + break; + case Intrinsic::atomic_load_umin: + Res = Builder.CreateSelect(Builder.CreateICmpULT(Orig, Delta), + Orig, + Delta); + break; + } + Builder.CreateStore(Res, Ptr); + + CI->replaceAllUsesWith(Orig); + break; + } + + case Intrinsic::atomic_swap: { + Value *Ptr = CI->getArgOperand(0); + Value *Val = CI->getArgOperand(1); + + LoadInst *Orig = Builder.CreateLoad(Ptr); + Builder.CreateStore(Val, Ptr); + + CI->replaceAllUsesWith(Orig); + break; + } + + case Intrinsic::atomic_cmp_swap: { + Value *Ptr = CI->getArgOperand(0); + Value *Cmp = CI->getArgOperand(1); + Value *Val = CI->getArgOperand(2); + + LoadInst *Orig = Builder.CreateLoad(Ptr); + Value *Equal = Builder.CreateICmpEQ(Orig, Cmp); + Value *Res = Builder.CreateSelect(Equal, Val, Orig); + Builder.CreateStore(Res, Ptr); + + CI->replaceAllUsesWith(Orig); + break; + } + + default: + return false; + } + + assert(CI->use_empty() && + "Lowering should have eliminated any uses of the intrinsic call!"); + CI->eraseFromParent(); + + return true; +} + +struct LowerAtomic : public BasicBlockPass { + static char ID; + LowerAtomic() : BasicBlockPass(ID) {} + bool runOnBasicBlock(BasicBlock &BB) { + bool Changed = false; + for (BasicBlock::iterator DI = BB.begin(), DE = BB.end(); DI != DE; ) { + Instruction *Inst = DI++; + if (CallInst *CI = dyn_cast(Inst)) + Changed |= LowerAtomicIntrinsic(CI); + } + return Changed; + } + +}; + +} + +char LowerAtomic::ID = 0; +INITIALIZE_PASS(LowerAtomic, "loweratomic", + "Lower atomic intrinsics to non-atomic form", + false, false); + +Pass *llvm::createLowerAtomicPass() { return new LowerAtomic(); } diff --git a/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/lib/Transforms/Scalar/MemCpyOptimizer.cpp index 0e566c5..24fae42 100644 --- a/lib/Transforms/Scalar/MemCpyOptimizer.cpp +++ b/lib/Transforms/Scalar/MemCpyOptimizer.cpp @@ -304,7 +304,7 @@ namespace { bool runOnFunction(Function &F); public: static char ID; // Pass identification, replacement for typeid - MemCpyOpt() : FunctionPass(&ID) {} + MemCpyOpt() : FunctionPass(ID) {} private: // This transformation requires dominator postdominator info @@ -331,8 +331,7 @@ namespace { // createMemCpyOptPass - The public interface to this file... FunctionPass *llvm::createMemCpyOptPass() { return new MemCpyOpt(); } -static RegisterPass X("memcpyopt", - "MemCpy Optimization"); +INITIALIZE_PASS(MemCpyOpt, "memcpyopt", "MemCpy Optimization", false, false); @@ -374,7 +373,7 @@ bool MemCpyOpt::processStore(StoreInst *SI, BasicBlock::iterator &BBI) { // If the call is readnone, ignore it, otherwise bail out. We don't even // allow readonly here because we don't want something like: // A[1] = 2; strlen(A); A[2] = 2; -> memcpy(A, ...); strlen(A). - if (AA.getModRefBehavior(CallSite::get(BI)) == + if (AA.getModRefBehavior(CallSite(BI)) == AliasAnalysis::DoesNotAccessMemory) continue; @@ -509,7 +508,7 @@ bool MemCpyOpt::performCallSlotOptzn(MemCpyInst *cpy, CallInst *C) { // because we'll need to do type comparisons based on the underlying type. Value *cpyDest = cpy->getDest(); Value *cpySrc = cpy->getSource(); - CallSite CS = CallSite::get(C); + CallSite CS(C); // We need to be able to reason about the size of the memcpy, so we require // that it be a constant. @@ -637,10 +636,11 @@ bool MemCpyOpt::performCallSlotOptzn(MemCpyInst *cpy, CallInst *C) { return true; } -/// processMemCpy - perform simplication of memcpy's. If we have memcpy A which -/// copies X to Y, and memcpy B which copies Y to Z, then we can rewrite B to be -/// a memcpy from X to Z (or potentially a memmove, depending on circumstances). -/// This allows later passes to remove the first memcpy altogether. +/// processMemCpy - perform simplification of memcpy's. If we have memcpy A +/// which copies X to Y, and memcpy B which copies Y to Z, then we can rewrite +/// B to be a memcpy from X to Z (or potentially a memmove, depending on +/// circumstances). This allows later passes to remove the first memcpy +/// altogether. bool MemCpyOpt::processMemCpy(MemCpyInst *M) { MemoryDependenceAnalysis &MD = getAnalysis(); @@ -744,7 +744,8 @@ bool MemCpyOpt::processMemMove(MemMoveInst *M) { const Type *ArgTys[3] = { M->getRawDest()->getType(), M->getRawSource()->getType(), M->getLength()->getType() }; - M->setCalledFunction(Intrinsic::getDeclaration(Mod, Intrinsic::memcpy, ArgTys, 3)); + M->setCalledFunction(Intrinsic::getDeclaration(Mod, Intrinsic::memcpy, + ArgTys, 3)); // MemDep may have over conservative information about this instruction, just // conservatively flush it from the cache. diff --git a/lib/Transforms/Scalar/Reassociate.cpp b/lib/Transforms/Scalar/Reassociate.cpp index 98452f5..b8afcc1 100644 --- a/lib/Transforms/Scalar/Reassociate.cpp +++ b/lib/Transforms/Scalar/Reassociate.cpp @@ -77,7 +77,7 @@ namespace { bool MadeChange; public: static char ID; // Pass identification, replacement for typeid - Reassociate() : FunctionPass(&ID) {} + Reassociate() : FunctionPass(ID) {} bool runOnFunction(Function &F); @@ -103,7 +103,8 @@ namespace { } char Reassociate::ID = 0; -static RegisterPass X("reassociate", "Reassociate expressions"); +INITIALIZE_PASS(Reassociate, "reassociate", + "Reassociate expressions", false, false); // Public interface to the Reassociate pass FunctionPass *llvm::createReassociatePass() { return new Reassociate(); } diff --git a/lib/Transforms/Scalar/Reg2Mem.cpp b/lib/Transforms/Scalar/Reg2Mem.cpp index 13222ac..506b72a 100644 --- a/lib/Transforms/Scalar/Reg2Mem.cpp +++ b/lib/Transforms/Scalar/Reg2Mem.cpp @@ -36,7 +36,7 @@ STATISTIC(NumPhisDemoted, "Number of phi-nodes demoted"); namespace { struct RegToMem : public FunctionPass { static char ID; // Pass identification, replacement for typeid - RegToMem() : FunctionPass(&ID) {} + RegToMem() : FunctionPass(ID) {} virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequiredID(BreakCriticalEdgesID); @@ -59,8 +59,8 @@ namespace { } char RegToMem::ID = 0; -static RegisterPass -X("reg2mem", "Demote all values to stack slots"); +INITIALIZE_PASS(RegToMem, "reg2mem", "Demote all values to stack slots", + false, false); bool RegToMem::runOnFunction(Function &F) { @@ -124,7 +124,7 @@ bool RegToMem::runOnFunction(Function &F) { // createDemoteRegisterToMemory - Provide an entry point to create this pass. // -const PassInfo *const llvm::DemoteRegisterToMemoryID = &X; +char &llvm::DemoteRegisterToMemoryID = RegToMem::ID; FunctionPass *llvm::createDemoteRegisterToMemoryPass() { return new RegToMem(); } diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp index 907ece8..6115c05 100644 --- a/lib/Transforms/Scalar/SCCP.cpp +++ b/lib/Transforms/Scalar/SCCP.cpp @@ -275,12 +275,12 @@ public: return I->second; } - LatticeVal getStructLatticeValueFor(Value *V, unsigned i) const { + /*LatticeVal getStructLatticeValueFor(Value *V, unsigned i) const { DenseMap, LatticeVal>::const_iterator I = StructValueState.find(std::make_pair(V, i)); assert(I != StructValueState.end() && "V is not in valuemap!"); return I->second; - } + }*/ /// getTrackedRetVals - Get the inferred return value map. /// @@ -508,17 +508,16 @@ private: void visitLoadInst (LoadInst &I); void visitGetElementPtrInst(GetElementPtrInst &I); void visitCallInst (CallInst &I) { - visitCallSite(CallSite::get(&I)); + visitCallSite(&I); } void visitInvokeInst (InvokeInst &II) { - visitCallSite(CallSite::get(&II)); + visitCallSite(&II); visitTerminatorInst(II); } void visitCallSite (CallSite CS); void visitUnwindInst (TerminatorInst &I) { /*returns void*/ } void visitUnreachableInst(TerminatorInst &I) { /*returns void*/ } void visitAllocaInst (Instruction &I) { markOverdefined(&I); } - void visitVANextInst (Instruction &I) { markOverdefined(&I); } void visitVAArgInst (Instruction &I) { markAnythingOverdefined(&I); } void visitInstruction(Instruction &I) { @@ -1586,7 +1585,7 @@ namespace { /// struct SCCP : public FunctionPass { static char ID; // Pass identification, replacement for typeid - SCCP() : FunctionPass(&ID) {} + SCCP() : FunctionPass(ID) {} // runOnFunction - Run the Sparse Conditional Constant Propagation // algorithm, and return true if the function was modified. @@ -1600,8 +1599,8 @@ namespace { } // end anonymous namespace char SCCP::ID = 0; -static RegisterPass -X("sccp", "Sparse Conditional Constant Propagation"); +INITIALIZE_PASS(SCCP, "sccp", + "Sparse Conditional Constant Propagation", false, false); // createSCCPPass - This is the public interface to this file. FunctionPass *llvm::createSCCPPass() { @@ -1702,14 +1701,15 @@ namespace { /// struct IPSCCP : public ModulePass { static char ID; - IPSCCP() : ModulePass(&ID) {} + IPSCCP() : ModulePass(ID) {} bool runOnModule(Module &M); }; } // end anonymous namespace char IPSCCP::ID = 0; -static RegisterPass -Y("ipsccp", "Interprocedural Sparse Conditional Constant Propagation"); +INITIALIZE_PASS(IPSCCP, "ipsccp", + "Interprocedural Sparse Conditional Constant Propagation", + false, false); // createIPSCCPPass - This is the public interface to this file. ModulePass *llvm::createIPSCCPPass() { @@ -1748,6 +1748,13 @@ static bool AddressIsTaken(const GlobalValue *GV) { bool IPSCCP::runOnModule(Module &M) { SCCPSolver Solver(getAnalysisIfAvailable()); + // AddressTakenFunctions - This set keeps track of the address-taken functions + // that are in the input. As IPSCCP runs through and simplifies code, + // functions that were address taken can end up losing their + // address-taken-ness. Because of this, we keep track of their addresses from + // the first pass so we can use them for the later simplification pass. + SmallPtrSet AddressTakenFunctions; + // Loop over all functions, marking arguments to those with their addresses // taken or that are external as overdefined. // @@ -1763,9 +1770,13 @@ bool IPSCCP::runOnModule(Module &M) { // If this function only has direct calls that we can see, we can track its // arguments and return value aggressively, and can assume it is not called // unless we see evidence to the contrary. - if (F->hasLocalLinkage() && !AddressIsTaken(F)) { - Solver.AddArgumentTrackedFunction(F); - continue; + if (F->hasLocalLinkage()) { + if (AddressIsTaken(F)) + AddressTakenFunctions.insert(F); + else { + Solver.AddArgumentTrackedFunction(F); + continue; + } } // Assume the function is called. @@ -1950,7 +1961,7 @@ bool IPSCCP::runOnModule(Module &M) { continue; // We can only do this if we know that nothing else can call the function. - if (!F->hasLocalLinkage() || AddressIsTaken(F)) + if (!F->hasLocalLinkage() || AddressTakenFunctions.count(F)) continue; for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) diff --git a/lib/Transforms/Scalar/ScalarReplAggregates.cpp b/lib/Transforms/Scalar/ScalarReplAggregates.cpp index dd445f6..fee317d 100644 --- a/lib/Transforms/Scalar/ScalarReplAggregates.cpp +++ b/lib/Transforms/Scalar/ScalarReplAggregates.cpp @@ -28,6 +28,7 @@ #include "llvm/Instructions.h" #include "llvm/IntrinsicInst.h" #include "llvm/LLVMContext.h" +#include "llvm/Module.h" #include "llvm/Pass.h" #include "llvm/Analysis/Dominators.h" #include "llvm/Target/TargetData.h" @@ -51,7 +52,7 @@ STATISTIC(NumGlobals, "Number of allocas copied from constant global"); namespace { struct SROA : public FunctionPass { static char ID; // Pass identification, replacement for typeid - explicit SROA(signed T = -1) : FunctionPass(&ID) { + explicit SROA(signed T = -1) : FunctionPass(ID) { if (T == -1) SRThreshold = 128; else @@ -114,8 +115,7 @@ namespace { void DoScalarReplacement(AllocaInst *AI, std::vector &WorkList); void DeleteDeadInstructions(); - AllocaInst *AddNewAlloca(Function &F, const Type *Ty, AllocaInst *Base); - + void RewriteForScalarRepl(Instruction *I, AllocaInst *AI, uint64_t Offset, SmallVector &NewElts); void RewriteBitCast(BitCastInst *BC, AllocaInst *AI, uint64_t Offset, @@ -135,7 +135,8 @@ namespace { } char SROA::ID = 0; -static RegisterPass X("scalarrepl", "Scalar Replacement of Aggregates"); +INITIALIZE_PASS(SROA, "scalarrepl", + "Scalar Replacement of Aggregates", false, false); // Public interface to the ScalarReplAggregates pass FunctionPass *llvm::createScalarReplAggregatesPass(signed int Threshold) { @@ -193,6 +194,27 @@ private: }; } // end anonymous namespace. + +/// IsVerbotenVectorType - Return true if this is a vector type ScalarRepl isn't +/// allowed to form. We do this to avoid MMX types, which is a complete hack, +/// but is required until the backend is fixed. +static bool IsVerbotenVectorType(const VectorType *VTy, const Instruction *I) { + StringRef Triple(I->getParent()->getParent()->getParent()->getTargetTriple()); + if (!Triple.startswith("i386") && + !Triple.startswith("x86_64")) + return false; + + // Reject all the MMX vector types. + switch (VTy->getNumElements()) { + default: return false; + case 1: return VTy->getElementType()->isIntegerTy(64); + case 2: return VTy->getElementType()->isIntegerTy(32); + case 4: return VTy->getElementType()->isIntegerTy(16); + case 8: return VTy->getElementType()->isIntegerTy(8); + } +} + + /// TryConvert - Analyze the specified alloca, and if it is safe to do so, /// rewrite it to be a new alloca which is mem2reg'able. This returns the new /// alloca if possible or null if not. @@ -209,7 +231,8 @@ AllocaInst *ConvertToScalarInfo::TryConvert(AllocaInst *AI) { // we just get a lot of insert/extracts. If at least one vector is // involved, then we probably really do have a union of vector/array. const Type *NewTy; - if (VectorTy && VectorTy->isVectorTy() && HadAVector) { + if (VectorTy && VectorTy->isVectorTy() && HadAVector && + !IsVerbotenVectorType(cast(VectorTy), AI)) { DEBUG(dbgs() << "CONVERT TO VECTOR: " << *AI << "\n TYPE = " << *VectorTy << '\n'); NewTy = VectorTy; // Use the vector type. @@ -969,7 +992,7 @@ void SROA::isSafeForScalarRepl(Instruction *I, AllocaInst *AI, uint64_t Offset, ConstantInt *Length = dyn_cast(MI->getLength()); if (Length) isSafeMemAccess(AI, Offset, Length->getZExtValue(), 0, - UI.getOperandNo() == CallInst::ArgOffset, Info); + UI.getOperandNo() == 0, Info); else MarkUnsafe(Info); } else if (LoadInst *LI = dyn_cast(User)) { @@ -1662,6 +1685,12 @@ void SROA::RewriteLoadUserOfWholeAlloca(LoadInst *LI, AllocaInst *AI, /// HasPadding - Return true if the specified type has any structure or /// alignment padding, false otherwise. static bool HasPadding(const Type *Ty, const TargetData &TD) { + if (const ArrayType *ATy = dyn_cast(Ty)) + return HasPadding(ATy->getElementType(), TD); + + if (const VectorType *VTy = dyn_cast(Ty)) + return HasPadding(VTy->getElementType(), TD); + if (const StructType *STy = dyn_cast(Ty)) { const StructLayout *SL = TD.getStructLayout(STy); unsigned PrevFieldBitOffset = 0; @@ -1691,12 +1720,8 @@ static bool HasPadding(const Type *Ty, const TargetData &TD) { if (PrevFieldEnd < SL->getSizeInBits()) return true; } - - } else if (const ArrayType *ATy = dyn_cast(Ty)) { - return HasPadding(ATy->getElementType(), TD); - } else if (const VectorType *VTy = dyn_cast(Ty)) { - return HasPadding(VTy->getElementType(), TD); } + return TD.getTypeSizeInBits(Ty) != TD.getTypeAllocSizeInBits(Ty); } @@ -1787,7 +1812,7 @@ static bool isOnlyCopiedFromConstantGlobal(Value *V, MemTransferInst *&TheCopy, if (isOffset) return false; // If the memintrinsic isn't using the alloca as the dest, reject it. - if (UI.getOperandNo() != CallInst::ArgOffset) return false; + if (UI.getOperandNo() != 0) return false; // If the source of the memcpy/move is not a constant global, reject it. if (!PointsToConstantGlobal(MI->getSource())) diff --git a/lib/Transforms/Scalar/SimplifyCFGPass.cpp b/lib/Transforms/Scalar/SimplifyCFGPass.cpp index 49d93a2..360749c 100644 --- a/lib/Transforms/Scalar/SimplifyCFGPass.cpp +++ b/lib/Transforms/Scalar/SimplifyCFGPass.cpp @@ -42,14 +42,15 @@ STATISTIC(NumSimpl, "Number of blocks simplified"); namespace { struct CFGSimplifyPass : public FunctionPass { static char ID; // Pass identification, replacement for typeid - CFGSimplifyPass() : FunctionPass(&ID) {} + CFGSimplifyPass() : FunctionPass(ID) {} virtual bool runOnFunction(Function &F); }; } char CFGSimplifyPass::ID = 0; -static RegisterPass X("simplifycfg", "Simplify the CFG"); +INITIALIZE_PASS(CFGSimplifyPass, "simplifycfg", + "Simplify the CFG", false, false); // Public interface to the CFGSimplification pass FunctionPass *llvm::createCFGSimplificationPass() { @@ -284,10 +285,9 @@ static bool IterativeSimplifyCFG(Function &F, const TargetData *TD) { while (LocalChange) { LocalChange = false; - // Loop over all of the basic blocks (except the first one) and remove them - // if they are unneeded... + // Loop over all of the basic blocks and remove them if they are unneeded... // - for (Function::iterator BBIt = ++F.begin(); BBIt != F.end(); ) { + for (Function::iterator BBIt = F.begin(); BBIt != F.end(); ) { if (SimplifyCFG(BBIt++, TD)) { LocalChange = true; ++NumSimpl; diff --git a/lib/Transforms/Scalar/SimplifyHalfPowrLibCalls.cpp b/lib/Transforms/Scalar/SimplifyHalfPowrLibCalls.cpp index c3408e7..3ec70ec 100644 --- a/lib/Transforms/Scalar/SimplifyHalfPowrLibCalls.cpp +++ b/lib/Transforms/Scalar/SimplifyHalfPowrLibCalls.cpp @@ -32,7 +32,7 @@ namespace { const TargetData *TD; public: static char ID; // Pass identification - SimplifyHalfPowrLibCalls() : FunctionPass(&ID) {} + SimplifyHalfPowrLibCalls() : FunctionPass(ID) {} bool runOnFunction(Function &F); @@ -46,8 +46,8 @@ namespace { char SimplifyHalfPowrLibCalls::ID = 0; } // end anonymous namespace. -static RegisterPass -X("simplify-libcalls-halfpowr", "Simplify half_powr library calls"); +INITIALIZE_PASS(SimplifyHalfPowrLibCalls, "simplify-libcalls-halfpowr", + "Simplify half_powr library calls", false, false); // Public interface to the Simplify HalfPowr LibCalls pass. FunctionPass *llvm::createSimplifyHalfPowrLibCallsPass() { diff --git a/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/lib/Transforms/Scalar/SimplifyLibCalls.cpp index b1c6191..d7ce53f 100644 --- a/lib/Transforms/Scalar/SimplifyLibCalls.cpp +++ b/lib/Transforms/Scalar/SimplifyLibCalls.cpp @@ -532,7 +532,7 @@ struct StrStrOpt : public LibCallOptimization { StrLen, B, TD); for (Value::use_iterator UI = CI->use_begin(), UE = CI->use_end(); UI != UE; ) { - ICmpInst *Old = cast(UI++); + ICmpInst *Old = cast(*UI++); Value *Cmp = B.CreateICmp(Old->getPredicate(), StrNCmp, ConstantInt::getNullValue(StrNCmp->getType()), "cmp"); @@ -566,8 +566,8 @@ struct StrStrOpt : public LibCallOptimization { // fold strstr(x, "y") -> strchr(x, 'y'). if (HasStr2 && ToFindStr.size() == 1) - return B.CreateBitCast(EmitStrChr(CI->getArgOperand(0), ToFindStr[0], B, TD), - CI->getType()); + return B.CreateBitCast(EmitStrChr(CI->getArgOperand(0), + ToFindStr[0], B, TD), CI->getType()); return 0; } }; @@ -681,8 +681,8 @@ struct MemSetOpt : public LibCallOptimization { return 0; // memset(p, v, n) -> llvm.memset(p, v, n, 1) - Value *Val = B.CreateIntCast(CI->getArgOperand(1), Type::getInt8Ty(*Context), - false); + Value *Val = B.CreateIntCast(CI->getArgOperand(1), + Type::getInt8Ty(*Context), false); EmitMemSet(CI->getArgOperand(0), Val, CI->getArgOperand(2), false, B, TD); return CI->getArgOperand(0); } @@ -1042,9 +1042,9 @@ struct SPrintFOpt : public LibCallOptimization { if (!TD) return 0; // sprintf(str, fmt) -> llvm.memcpy(str, fmt, strlen(fmt)+1, 1) - EmitMemCpy(CI->getArgOperand(0), CI->getArgOperand(1), // Copy the nul byte. - ConstantInt::get(TD->getIntPtrType(*Context), - FormatStr.size()+1), 1, false, B, TD); + EmitMemCpy(CI->getArgOperand(0), CI->getArgOperand(1), // Copy the + ConstantInt::get(TD->getIntPtrType(*Context), // nul byte. + FormatStr.size() + 1), 1, false, B, TD); return ConstantInt::get(CI->getType(), FormatStr.size()); } @@ -1080,7 +1080,8 @@ struct SPrintFOpt : public LibCallOptimization { Value *IncLen = B.CreateAdd(Len, ConstantInt::get(Len->getType(), 1), "leninc"); - EmitMemCpy(CI->getArgOperand(0), CI->getArgOperand(2), IncLen, 1, false, B, TD); + EmitMemCpy(CI->getArgOperand(0), CI->getArgOperand(2), + IncLen, 1, false, B, TD); // The sprintf result is the unincremented number of bytes in the string. return B.CreateIntCast(Len, CI->getType(), false); @@ -1236,7 +1237,7 @@ namespace { bool Modified; // This is only used by doInitialization. public: static char ID; // Pass identification - SimplifyLibCalls() : FunctionPass(&ID), StrCpy(false), StrCpyChk(true) {} + SimplifyLibCalls() : FunctionPass(ID), StrCpy(false), StrCpyChk(true) {} void InitOptimizations(); bool runOnFunction(Function &F); @@ -1253,8 +1254,8 @@ namespace { char SimplifyLibCalls::ID = 0; } // end anonymous namespace. -static RegisterPass -X("simplify-libcalls", "Simplify well-known library calls"); +INITIALIZE_PASS(SimplifyLibCalls, "simplify-libcalls", + "Simplify well-known library calls", false, false); // Public interface to the Simplify LibCalls pass. FunctionPass *llvm::createSimplifyLibCallsPass() { @@ -2155,7 +2156,7 @@ bool SimplifyLibCalls::doInitialization(Module &M) { // * pow(pow(x,y),z)-> pow(x,y*z) // // puts: -// * puts("") -> putchar("\n") +// * puts("") -> putchar('\n') // // round, roundf, roundl: // * round(cnst) -> cnst' diff --git a/lib/Transforms/Scalar/Sink.cpp b/lib/Transforms/Scalar/Sink.cpp index b88ba48..95d3ded 100644 --- a/lib/Transforms/Scalar/Sink.cpp +++ b/lib/Transforms/Scalar/Sink.cpp @@ -35,7 +35,7 @@ namespace { public: static char ID; // Pass identification - Sinking() : FunctionPass(&ID) {} + Sinking() : FunctionPass(ID) {} virtual bool runOnFunction(Function &F); @@ -56,8 +56,7 @@ namespace { } // end anonymous namespace char Sinking::ID = 0; -static RegisterPass -X("sink", "Code sinking"); +INITIALIZE_PASS(Sinking, "sink", "Code sinking", false, false); FunctionPass *llvm::createSinkingPass() { return new Sinking(); } diff --git a/lib/Transforms/Scalar/TailDuplication.cpp b/lib/Transforms/Scalar/TailDuplication.cpp index 9208238..2e437ac 100644 --- a/lib/Transforms/Scalar/TailDuplication.cpp +++ b/lib/Transforms/Scalar/TailDuplication.cpp @@ -49,7 +49,7 @@ namespace { bool runOnFunction(Function &F); public: static char ID; // Pass identification, replacement for typeid - TailDup() : FunctionPass(&ID) {} + TailDup() : FunctionPass(ID) {} private: inline bool shouldEliminateUnconditionalBranch(TerminatorInst *, unsigned); @@ -59,7 +59,7 @@ namespace { } char TailDup::ID = 0; -static RegisterPass X("tailduplicate", "Tail Duplication"); +INITIALIZE_PASS(TailDup, "tailduplicate", "Tail Duplication", false, false); // Public interface to the Tail Duplication pass FunctionPass *llvm::createTailDuplicationPass() { return new TailDup(); } diff --git a/lib/Transforms/Scalar/TailRecursionElimination.cpp b/lib/Transforms/Scalar/TailRecursionElimination.cpp index 01c8e5d..3717254 100644 --- a/lib/Transforms/Scalar/TailRecursionElimination.cpp +++ b/lib/Transforms/Scalar/TailRecursionElimination.cpp @@ -72,7 +72,7 @@ STATISTIC(NumAccumAdded, "Number of accumulators introduced"); namespace { struct TailCallElim : public FunctionPass { static char ID; // Pass identification, replacement for typeid - TailCallElim() : FunctionPass(&ID) {} + TailCallElim() : FunctionPass(ID) {} virtual bool runOnFunction(Function &F); @@ -87,7 +87,8 @@ namespace { } char TailCallElim::ID = 0; -static RegisterPass X("tailcallelim", "Tail Call Elimination"); +INITIALIZE_PASS(TailCallElim, "tailcallelim", + "Tail Call Elimination", false, false); // Public interface to the TailCallElimination pass FunctionPass *llvm::createTailCallEliminationPass() { @@ -277,22 +278,22 @@ static Value *getCommonReturnValue(ReturnInst *IgnoreRI, CallInst *CI) { Function *F = CI->getParent()->getParent(); Value *ReturnedValue = 0; - for (Function::iterator BBI = F->begin(), E = F->end(); BBI != E; ++BBI) - if (ReturnInst *RI = dyn_cast(BBI->getTerminator())) - if (RI != IgnoreRI) { - Value *RetOp = RI->getOperand(0); - - // We can only perform this transformation if the value returned is - // evaluatable at the start of the initial invocation of the function, - // instead of at the end of the evaluation. - // - if (!isDynamicConstant(RetOp, CI, RI)) - return 0; - - if (ReturnedValue && RetOp != ReturnedValue) - return 0; // Cannot transform if differing values are returned. - ReturnedValue = RetOp; - } + for (Function::iterator BBI = F->begin(), E = F->end(); BBI != E; ++BBI) { + ReturnInst *RI = dyn_cast(BBI->getTerminator()); + if (RI == 0 || RI == IgnoreRI) continue; + + // We can only perform this transformation if the value returned is + // evaluatable at the start of the initial invocation of the function, + // instead of at the end of the evaluation. + // + Value *RetOp = RI->getOperand(0); + if (!isDynamicConstant(RetOp, CI, RI)) + return 0; + + if (ReturnedValue && RetOp != ReturnedValue) + return 0; // Cannot transform if differing values are returned. + ReturnedValue = RetOp; + } return ReturnedValue; } @@ -306,7 +307,7 @@ Value *TailCallElim::CanTransformAccumulatorRecursion(Instruction *I, assert(I->getNumOperands() == 2 && "Associative/commutative operations should have 2 args!"); - // Exactly one operand should be the result of the call instruction... + // Exactly one operand should be the result of the call instruction. if ((I->getOperand(0) == CI && I->getOperand(1) == CI) || (I->getOperand(0) != CI && I->getOperand(1) != CI)) return 0; @@ -386,21 +387,22 @@ bool TailCallElim::ProcessReturningBlock(ReturnInst *Ret, BasicBlock *&OldEntry, // tail call if all of the instructions between the call and the return are // movable to above the call itself, leaving the call next to the return. // Check that this is the case now. - for (BBI = CI, ++BBI; &*BBI != Ret; ++BBI) - if (!CanMoveAboveCall(BBI, CI)) { - // If we can't move the instruction above the call, it might be because it - // is an associative and commutative operation that could be tranformed - // using accumulator recursion elimination. Check to see if this is the - // case, and if so, remember the initial accumulator value for later. - if ((AccumulatorRecursionEliminationInitVal = - CanTransformAccumulatorRecursion(BBI, CI))) { - // Yes, this is accumulator recursion. Remember which instruction - // accumulates. - AccumulatorRecursionInstr = BBI; - } else { - return false; // Otherwise, we cannot eliminate the tail recursion! - } + for (BBI = CI, ++BBI; &*BBI != Ret; ++BBI) { + if (CanMoveAboveCall(BBI, CI)) continue; + + // If we can't move the instruction above the call, it might be because it + // is an associative and commutative operation that could be tranformed + // using accumulator recursion elimination. Check to see if this is the + // case, and if so, remember the initial accumulator value for later. + if ((AccumulatorRecursionEliminationInitVal = + CanTransformAccumulatorRecursion(BBI, CI))) { + // Yes, this is accumulator recursion. Remember which instruction + // accumulates. + AccumulatorRecursionInstr = BBI; + } else { + return false; // Otherwise, we cannot eliminate the tail recursion! } + } // We can only transform call/return pairs that either ignore the return value // of the call and return void, ignore the value of the call and return a diff --git a/lib/Transforms/Utils/BasicBlockUtils.cpp b/lib/Transforms/Utils/BasicBlockUtils.cpp index ec625b4..093083a 100644 --- a/lib/Transforms/Utils/BasicBlockUtils.cpp +++ b/lib/Transforms/Utils/BasicBlockUtils.cpp @@ -97,23 +97,13 @@ bool llvm::DeleteDeadPHIs(BasicBlock *BB) { /// MergeBlockIntoPredecessor - Attempts to merge a block into its predecessor, /// if possible. The return value indicates success or failure. bool llvm::MergeBlockIntoPredecessor(BasicBlock *BB, Pass *P) { - pred_iterator PI(pred_begin(BB)), PE(pred_end(BB)); - // Can't merge the entry block. Don't merge away blocks who have their - // address taken: this is a bug if the predecessor block is the entry node - // (because we'd end up taking the address of the entry) and undesirable in - // any case. - if (pred_begin(BB) == pred_end(BB) || - BB->hasAddressTaken()) return false; + // Don't merge away blocks who have their address taken. + if (BB->hasAddressTaken()) return false; - BasicBlock *PredBB = *PI++; - for (; PI != PE; ++PI) // Search all predecessors, see if they are all same - if (*PI != PredBB) { - PredBB = 0; // There are multiple different predecessors... - break; - } - - // Can't merge if there are multiple predecessors. + // Can't merge if there are multiple predecessors, or no predecessors. + BasicBlock *PredBB = BB->getUniquePredecessor(); if (!PredBB) return false; + // Don't break self-loops. if (PredBB == BB) return false; // Don't break invokes. @@ -267,7 +257,7 @@ void llvm::RemoveSuccessor(TerminatorInst *TI, unsigned SuccNum) { case Instruction::Switch: // Should remove entry default: case Instruction::Ret: // Cannot happen, has no successors! - llvm_unreachable("Unhandled terminator instruction type in RemoveSuccessor!"); + llvm_unreachable("Unhandled terminator inst type in RemoveSuccessor!"); } if (NewTI) // If it's a different instruction, replace. @@ -421,7 +411,8 @@ BasicBlock *llvm::SplitBlockPredecessors(BasicBlock *BB, DominatorTree *DT = P ? P->getAnalysisIfAvailable() : 0; if (DT) DT->splitBlock(NewBB); - if (DominanceFrontier *DF = P ? P->getAnalysisIfAvailable():0) + if (DominanceFrontier *DF = + P ? P->getAnalysisIfAvailable() : 0) DF->splitBlock(NewBB); // Insert a new PHI node into NewBB for every PHI node in BB and that new PHI diff --git a/lib/Transforms/Utils/BasicInliner.cpp b/lib/Transforms/Utils/BasicInliner.cpp index f0e31ef..23a30cc5 100644 --- a/lib/Transforms/Utils/BasicInliner.cpp +++ b/lib/Transforms/Utils/BasicInliner.cpp @@ -82,8 +82,8 @@ void BasicInlinerImpl::inlineFunctions() { Function *F = *FI; for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) for (BasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) { - CallSite CS = CallSite::get(I); - if (CS.getInstruction() && CS.getCalledFunction() + CallSite CS(cast(I)); + if (CS && CS.getCalledFunction() && !CS.getCalledFunction()->isDeclaration()) CallSites.push_back(CS); } diff --git a/lib/Transforms/Utils/BreakCriticalEdges.cpp b/lib/Transforms/Utils/BreakCriticalEdges.cpp index 26f53c0..f75ffe6 100644 --- a/lib/Transforms/Utils/BreakCriticalEdges.cpp +++ b/lib/Transforms/Utils/BreakCriticalEdges.cpp @@ -36,7 +36,7 @@ STATISTIC(NumBroken, "Number of blocks inserted"); namespace { struct BreakCriticalEdges : public FunctionPass { static char ID; // Pass identification, replacement for typeid - BreakCriticalEdges() : FunctionPass(&ID) {} + BreakCriticalEdges() : FunctionPass(ID) {} virtual bool runOnFunction(Function &F); @@ -53,11 +53,11 @@ namespace { } char BreakCriticalEdges::ID = 0; -static RegisterPass -X("break-crit-edges", "Break critical edges in CFG"); +INITIALIZE_PASS(BreakCriticalEdges, "break-crit-edges", + "Break critical edges in CFG", false, false); // Publically exposed interface to pass... -const PassInfo *const llvm::BreakCriticalEdgesID = &X; +char &llvm::BreakCriticalEdgesID = BreakCriticalEdges::ID; FunctionPass *llvm::createBreakCriticalEdgesPass() { return new BreakCriticalEdges(); } @@ -225,7 +225,7 @@ BasicBlock *llvm::SplitCriticalEdge(TerminatorInst *TI, unsigned SuccNum, for (Value::use_iterator UI = TIBB->use_begin(), E = TIBB->use_end(); UI != E; ) { Value::use_iterator Use = UI++; - if (PHINode *PN = dyn_cast(Use)) { + if (PHINode *PN = dyn_cast(*Use)) { // Remove one entry from each PHI. if (PN->getParent() == DestBB && UpdatedPHIs.insert(PN)) PN->setOperand(Use.getOperandNo(), NewBB); diff --git a/lib/Transforms/Utils/BuildLibCalls.cpp b/lib/Transforms/Utils/BuildLibCalls.cpp index 7a9d007..c313949 100644 --- a/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/lib/Transforms/Utils/BuildLibCalls.cpp @@ -421,9 +421,9 @@ bool SimplifyFortifiedLibCalls::fold(CallInst *CI, const TargetData *TD) { FT->getParamType(3) != TD->getIntPtrType(Context)) return false; - if (isFoldable(3 + CallInst::ArgOffset, 2 + CallInst::ArgOffset, false)) { - EmitMemCpy(CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2), - 1, false, B, TD); + if (isFoldable(3, 2, false)) { + EmitMemCpy(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(2), 1, false, B, TD); replaceCall(CI->getArgOperand(0)); return true; } @@ -444,9 +444,9 @@ bool SimplifyFortifiedLibCalls::fold(CallInst *CI, const TargetData *TD) { FT->getParamType(3) != TD->getIntPtrType(Context)) return false; - if (isFoldable(3 + CallInst::ArgOffset, 2 + CallInst::ArgOffset, false)) { - EmitMemMove(CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2), - 1, false, B, TD); + if (isFoldable(3, 2, false)) { + EmitMemMove(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(2), 1, false, B, TD); replaceCall(CI->getArgOperand(0)); return true; } @@ -462,10 +462,11 @@ bool SimplifyFortifiedLibCalls::fold(CallInst *CI, const TargetData *TD) { FT->getParamType(3) != TD->getIntPtrType(Context)) return false; - if (isFoldable(3 + CallInst::ArgOffset, 2 + CallInst::ArgOffset, false)) { + if (isFoldable(3, 2, false)) { Value *Val = B.CreateIntCast(CI->getArgOperand(1), B.getInt8Ty(), false); - EmitMemSet(CI->getArgOperand(0), Val, CI->getArgOperand(2), false, B, TD); + EmitMemSet(CI->getArgOperand(0), Val, CI->getArgOperand(2), + false, B, TD); replaceCall(CI->getArgOperand(0)); return true; } @@ -487,7 +488,7 @@ bool SimplifyFortifiedLibCalls::fold(CallInst *CI, const TargetData *TD) { // st[rp]cpy_chk call which may fail at runtime if the size is too long. // TODO: It might be nice to get a maximum length out of the possible // string lengths for varying. - if (isFoldable(2 + CallInst::ArgOffset, 1 + CallInst::ArgOffset, true)) { + if (isFoldable(2, 1, true)) { Value *Ret = EmitStrCpy(CI->getArgOperand(0), CI->getArgOperand(1), B, TD, Name.substr(2, 6)); replaceCall(Ret); @@ -505,7 +506,7 @@ bool SimplifyFortifiedLibCalls::fold(CallInst *CI, const TargetData *TD) { FT->getParamType(3) != TD->getIntPtrType(Context)) return false; - if (isFoldable(3 + CallInst::ArgOffset, 2 + CallInst::ArgOffset, false)) { + if (isFoldable(3, 2, false)) { Value *Ret = EmitStrNCpy(CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(2), B, TD, Name.substr(2, 7)); replaceCall(Ret); diff --git a/lib/Transforms/Utils/CMakeLists.txt b/lib/Transforms/Utils/CMakeLists.txt index dec227a..61cbeb2 100644 --- a/lib/Transforms/Utils/CMakeLists.txt +++ b/lib/Transforms/Utils/CMakeLists.txt @@ -20,7 +20,6 @@ add_llvm_library(LLVMTransformUtils Mem2Reg.cpp PromoteMemoryToRegister.cpp SSAUpdater.cpp - SSI.cpp SimplifyCFG.cpp UnifyFunctionExitNodes.cpp ValueMapper.cpp diff --git a/lib/Transforms/Utils/CloneFunction.cpp b/lib/Transforms/Utils/CloneFunction.cpp index 1dcfd57..f43186e 100644 --- a/lib/Transforms/Utils/CloneFunction.cpp +++ b/lib/Transforms/Utils/CloneFunction.cpp @@ -23,7 +23,7 @@ #include "llvm/LLVMContext.h" #include "llvm/Metadata.h" #include "llvm/Support/CFG.h" -#include "ValueMapper.h" +#include "llvm/Transforms/Utils/ValueMapper.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/DebugInfo.h" #include "llvm/ADT/SmallVector.h" @@ -69,10 +69,11 @@ BasicBlock *llvm::CloneBasicBlock(const BasicBlock *BB, } // Clone OldFunc into NewFunc, transforming the old arguments into references to -// ArgMap values. +// VMap values. // void llvm::CloneFunctionInto(Function *NewFunc, const Function *OldFunc, ValueToValueMapTy &VMap, + bool ModuleLevelChanges, SmallVectorImpl &Returns, const char *NameSuffix, ClonedCodeInfo *CodeInfo) { assert(NameSuffix && "NameSuffix cannot be null!"); @@ -126,7 +127,7 @@ void llvm::CloneFunctionInto(Function *NewFunc, const Function *OldFunc, BE = NewFunc->end(); BB != BE; ++BB) // Loop over all instructions, fixing each one as we find it... for (BasicBlock::iterator II = BB->begin(); II != BB->end(); ++II) - RemapInstruction(II, VMap); + RemapInstruction(II, VMap, ModuleLevelChanges); } /// CloneFunction - Return a copy of the specified function, but without @@ -139,6 +140,7 @@ void llvm::CloneFunctionInto(Function *NewFunc, const Function *OldFunc, /// Function *llvm::CloneFunction(const Function *F, ValueToValueMapTy &VMap, + bool ModuleLevelChanges, ClonedCodeInfo *CodeInfo) { std::vector ArgTypes; @@ -167,7 +169,7 @@ Function *llvm::CloneFunction(const Function *F, } SmallVector Returns; // Ignore returns cloned. - CloneFunctionInto(NewF, F, VMap, Returns, "", CodeInfo); + CloneFunctionInto(NewF, F, VMap, ModuleLevelChanges, Returns, "", CodeInfo); return NewF; } @@ -180,6 +182,7 @@ namespace { Function *NewFunc; const Function *OldFunc; ValueToValueMapTy &VMap; + bool ModuleLevelChanges; SmallVectorImpl &Returns; const char *NameSuffix; ClonedCodeInfo *CodeInfo; @@ -187,12 +190,14 @@ namespace { public: PruningFunctionCloner(Function *newFunc, const Function *oldFunc, ValueToValueMapTy &valueMap, + bool moduleLevelChanges, SmallVectorImpl &returns, const char *nameSuffix, ClonedCodeInfo *codeInfo, const TargetData *td) - : NewFunc(newFunc), OldFunc(oldFunc), VMap(valueMap), Returns(returns), - NameSuffix(nameSuffix), CodeInfo(codeInfo), TD(td) { + : NewFunc(newFunc), OldFunc(oldFunc), + VMap(valueMap), ModuleLevelChanges(moduleLevelChanges), + Returns(returns), NameSuffix(nameSuffix), CodeInfo(codeInfo), TD(td) { } /// CloneBlock - The specified block is found to be reachable, clone it and @@ -313,7 +318,7 @@ ConstantFoldMappedInstruction(const Instruction *I) { SmallVector Ops; for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) if (Constant *Op = dyn_cast_or_null(MapValue(I->getOperand(i), - VMap))) + VMap, ModuleLevelChanges))) Ops.push_back(Op); else return 0; // All operands not constant! @@ -334,25 +339,16 @@ ConstantFoldMappedInstruction(const Instruction *I) { Ops.size(), TD); } -static MDNode *UpdateInlinedAtInfo(MDNode *InsnMD, MDNode *TheCallMD) { - DILocation ILoc(InsnMD); - if (!ILoc.Verify()) return InsnMD; +static DebugLoc +UpdateInlinedAtInfo(const DebugLoc &InsnDL, const DebugLoc &TheCallDL, + LLVMContext &Ctx) { + DebugLoc NewLoc = TheCallDL; + if (MDNode *IA = InsnDL.getInlinedAt(Ctx)) + NewLoc = UpdateInlinedAtInfo(DebugLoc::getFromDILocation(IA), TheCallDL, + Ctx); - DILocation CallLoc(TheCallMD); - if (!CallLoc.Verify()) return InsnMD; - - DILocation OrigLocation = ILoc.getOrigLocation(); - MDNode *NewLoc = TheCallMD; - if (OrigLocation.Verify()) - NewLoc = UpdateInlinedAtInfo(OrigLocation, TheCallMD); - - Value *MDVs[] = { - InsnMD->getOperand(0), // Line - InsnMD->getOperand(1), // Col - InsnMD->getOperand(2), // Scope - NewLoc - }; - return MDNode::get(InsnMD->getContext(), MDVs, 4); + return DebugLoc::get(InsnDL.getLine(), InsnDL.getCol(), + InsnDL.getScope(Ctx), NewLoc.getAsMDNode(Ctx)); } /// CloneAndPruneFunctionInto - This works exactly like CloneFunctionInto, @@ -364,6 +360,7 @@ static MDNode *UpdateInlinedAtInfo(MDNode *InsnMD, MDNode *TheCallMD) { /// used for things like CloneFunction or CloneModule. void llvm::CloneAndPruneFunctionInto(Function *NewFunc, const Function *OldFunc, ValueToValueMapTy &VMap, + bool ModuleLevelChanges, SmallVectorImpl &Returns, const char *NameSuffix, ClonedCodeInfo *CodeInfo, @@ -377,8 +374,8 @@ void llvm::CloneAndPruneFunctionInto(Function *NewFunc, const Function *OldFunc, assert(VMap.count(II) && "No mapping from source argument specified!"); #endif - PruningFunctionCloner PFC(NewFunc, OldFunc, VMap, Returns, - NameSuffix, CodeInfo, TD); + PruningFunctionCloner PFC(NewFunc, OldFunc, VMap, ModuleLevelChanges, + Returns, NameSuffix, CodeInfo, TD); // Clone the entry block, and anything recursively reachable from it. std::vector CloneWorklist; @@ -408,10 +405,9 @@ void llvm::CloneAndPruneFunctionInto(Function *NewFunc, const Function *OldFunc, // BasicBlock::iterator I = NewBB->begin(); - unsigned DbgKind = OldFunc->getContext().getMDKindID("dbg"); - MDNode *TheCallMD = NULL; - if (TheCall && TheCall->hasMetadata()) - TheCallMD = TheCall->getMetadata(DbgKind); + DebugLoc TheCallDL; + if (TheCall) + TheCallDL = TheCall->getDebugLoc(); // Handle PHI nodes specially, as we have to remove references to dead // blocks. @@ -420,15 +416,17 @@ void llvm::CloneAndPruneFunctionInto(Function *NewFunc, const Function *OldFunc, BasicBlock::const_iterator OldI = BI->begin(); for (; (PN = dyn_cast(I)); ++I, ++OldI) { if (I->hasMetadata()) { - if (TheCallMD) { - if (MDNode *IMD = I->getMetadata(DbgKind)) { - MDNode *NewMD = UpdateInlinedAtInfo(IMD, TheCallMD); - I->setMetadata(DbgKind, NewMD); + if (!TheCallDL.isUnknown()) { + DebugLoc IDL = I->getDebugLoc(); + if (!IDL.isUnknown()) { + DebugLoc NewDL = UpdateInlinedAtInfo(IDL, TheCallDL, + I->getContext()); + I->setDebugLoc(NewDL); } } else { // The cloned instruction has dbg info but the call instruction // does not have dbg info. Remove dbg info from cloned instruction. - I->setMetadata(DbgKind, 0); + I->setDebugLoc(DebugLoc()); } } PHIToResolve.push_back(cast(OldI)); @@ -444,18 +442,20 @@ void llvm::CloneAndPruneFunctionInto(Function *NewFunc, const Function *OldFunc, // Otherwise, remap the rest of the instructions normally. for (; I != NewBB->end(); ++I) { if (I->hasMetadata()) { - if (TheCallMD) { - if (MDNode *IMD = I->getMetadata(DbgKind)) { - MDNode *NewMD = UpdateInlinedAtInfo(IMD, TheCallMD); - I->setMetadata(DbgKind, NewMD); + if (!TheCallDL.isUnknown()) { + DebugLoc IDL = I->getDebugLoc(); + if (!IDL.isUnknown()) { + DebugLoc NewDL = UpdateInlinedAtInfo(IDL, TheCallDL, + I->getContext()); + I->setDebugLoc(NewDL); } } else { // The cloned instruction has dbg info but the call instruction // does not have dbg info. Remove dbg info from cloned instruction. - I->setMetadata(DbgKind, 0); + I->setDebugLoc(DebugLoc()); } } - RemapInstruction(I, VMap); + RemapInstruction(I, VMap, ModuleLevelChanges); } } @@ -477,7 +477,7 @@ void llvm::CloneAndPruneFunctionInto(Function *NewFunc, const Function *OldFunc, if (BasicBlock *MappedBlock = cast_or_null(VMap[PN->getIncomingBlock(pred)])) { Value *InVal = MapValue(PN->getIncomingValue(pred), - VMap); + VMap, ModuleLevelChanges); assert(InVal && "Unknown input value?"); PN->setIncomingValue(pred, InVal); PN->setIncomingBlock(pred, MappedBlock); diff --git a/lib/Transforms/Utils/CloneModule.cpp b/lib/Transforms/Utils/CloneModule.cpp index fc603d2..b347bf5 100644 --- a/lib/Transforms/Utils/CloneModule.cpp +++ b/lib/Transforms/Utils/CloneModule.cpp @@ -17,7 +17,7 @@ #include "llvm/DerivedTypes.h" #include "llvm/TypeSymbolTable.h" #include "llvm/Constant.h" -#include "ValueMapper.h" +#include "llvm/Transforms/Utils/ValueMapper.h" using namespace llvm; /// CloneModule - Return an exact copy of the specified module. This is not as @@ -89,7 +89,8 @@ Module *llvm::CloneModule(const Module *M, GlobalVariable *GV = cast(VMap[I]); if (I->hasInitializer()) GV->setInitializer(cast(MapValue(I->getInitializer(), - VMap))); + VMap, + true))); GV->setLinkage(I->getLinkage()); GV->setThreadLocal(I->isThreadLocal()); GV->setConstant(I->isConstant()); @@ -108,7 +109,7 @@ Module *llvm::CloneModule(const Module *M, } SmallVector Returns; // Ignore returns cloned. - CloneFunctionInto(F, I, VMap, Returns); + CloneFunctionInto(F, I, VMap, /*ModuleLevelChanges=*/true, Returns); } F->setLinkage(I->getLinkage()); @@ -120,34 +121,17 @@ Module *llvm::CloneModule(const Module *M, GlobalAlias *GA = cast(VMap[I]); GA->setLinkage(I->getLinkage()); if (const Constant* C = I->getAliasee()) - GA->setAliasee(cast(MapValue(C, VMap))); + GA->setAliasee(cast(MapValue(C, VMap, true))); } // And named metadata.... for (Module::const_named_metadata_iterator I = M->named_metadata_begin(), E = M->named_metadata_end(); I != E; ++I) { const NamedMDNode &NMD = *I; - SmallVector MDs; + NamedMDNode *NewNMD = New->getOrInsertNamedMetadata(NMD.getName()); for (unsigned i = 0, e = NMD.getNumOperands(); i != e; ++i) - MDs.push_back(cast(MapValue(NMD.getOperand(i), VMap))); - NamedMDNode::Create(New->getContext(), NMD.getName(), - MDs.data(), MDs.size(), New); + NewNMD->addOperand(cast(MapValue(NMD.getOperand(i), VMap, true))); } - // Update metadata attach with instructions. - for (Module::iterator MI = New->begin(), ME = New->end(); MI != ME; ++MI) - for (Function::iterator FI = MI->begin(), FE = MI->end(); - FI != FE; ++FI) - for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); - BI != BE; ++BI) { - SmallVector, 4 > MDs; - BI->getAllMetadata(MDs); - for (SmallVector, 4>::iterator - MDI = MDs.begin(), MDE = MDs.end(); MDI != MDE; ++MDI) { - Value *MappedValue = MapValue(MDI->second, VMap); - if (MDI->second != MappedValue && MappedValue) - BI->setMetadata(MDI->first, cast(MappedValue)); - } - } return New; } diff --git a/lib/Transforms/Utils/InlineFunction.cpp b/lib/Transforms/Utils/InlineFunction.cpp index 598e7d2..88979e86 100644 --- a/lib/Transforms/Utils/InlineFunction.cpp +++ b/lib/Transforms/Utils/InlineFunction.cpp @@ -215,12 +215,12 @@ static void UpdateCallGraphAfterInlining(CallSite CS, if (I->second->getFunction() == 0) if (Function *F = CallSite(NewCall).getCalledFunction()) { // Indirect call site resolved to direct call. - CallerNode->addCalledFunction(CallSite::get(NewCall), CG[F]); - + CallerNode->addCalledFunction(CallSite(NewCall), CG[F]); + continue; } - - CallerNode->addCalledFunction(CallSite::get(NewCall), I->second); + + CallerNode->addCalledFunction(CallSite(NewCall), I->second); } // Update the call graph by deleting the edge from Callee to Caller. We must @@ -365,7 +365,8 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI) { // have no dead or constant instructions leftover after inlining occurs // (which can happen, e.g., because an argument was constant), but we'll be // happy with whatever the cloner can do. - CloneAndPruneFunctionInto(Caller, CalledFunc, VMap, Returns, ".i", + CloneAndPruneFunctionInto(Caller, CalledFunc, VMap, + /*ModuleLevelChanges=*/false, Returns, ".i", &InlinedFunctionInfo, IFI.TD, TheCall); // Remember the first block that is newly cloned over. diff --git a/lib/Transforms/Utils/InstructionNamer.cpp b/lib/Transforms/Utils/InstructionNamer.cpp index 090af95..5ca8299 100644 --- a/lib/Transforms/Utils/InstructionNamer.cpp +++ b/lib/Transforms/Utils/InstructionNamer.cpp @@ -23,7 +23,7 @@ using namespace llvm; namespace { struct InstNamer : public FunctionPass { static char ID; // Pass identification, replacement for typeid - InstNamer() : FunctionPass(&ID) {} + InstNamer() : FunctionPass(ID) {} void getAnalysisUsage(AnalysisUsage &Info) const { Info.setPreservesAll(); @@ -48,12 +48,12 @@ namespace { }; char InstNamer::ID = 0; - static RegisterPass X("instnamer", - "Assign names to anonymous instructions"); + INITIALIZE_PASS(InstNamer, "instnamer", + "Assign names to anonymous instructions", false, false); } -const PassInfo *const llvm::InstructionNamerID = &X; +char &llvm::InstructionNamerID = InstNamer::ID; //===----------------------------------------------------------------------===// // // InstructionNamer - Give any unnamed non-void instructions "tmp" names. diff --git a/lib/Transforms/Utils/LCSSA.cpp b/lib/Transforms/Utils/LCSSA.cpp index e90c30b..275b265 100644 --- a/lib/Transforms/Utils/LCSSA.cpp +++ b/lib/Transforms/Utils/LCSSA.cpp @@ -47,7 +47,7 @@ STATISTIC(NumLCSSA, "Number of live out of a loop variables"); namespace { struct LCSSA : public LoopPass { static char ID; // Pass identification, replacement for typeid - LCSSA() : LoopPass(&ID) {} + LCSSA() : LoopPass(ID) {} // Cached analysis information for the current function. DominatorTree *DT; @@ -64,22 +64,13 @@ namespace { virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); - // LCSSA doesn't actually require LoopSimplify, but the PassManager - // doesn't know how to schedule LoopSimplify by itself. - AU.addRequiredID(LoopSimplifyID); - AU.addPreservedID(LoopSimplifyID); - AU.addRequiredTransitive(); - AU.addPreserved(); - AU.addRequiredTransitive(); - AU.addPreserved(); + AU.addRequired(); AU.addPreserved(); - - // Request DominanceFrontier now, even though LCSSA does - // not use it. This allows Pass Manager to schedule Dominance - // Frontier early enough such that one LPPassManager can handle - // multiple loop transformation passes. - AU.addRequired(); AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + AU.addPreservedID(LoopSimplifyID); + AU.addPreserved(); } private: bool ProcessInstruction(Instruction *Inst, @@ -99,10 +90,10 @@ namespace { } char LCSSA::ID = 0; -static RegisterPass X("lcssa", "Loop-Closed SSA Form Pass"); +INITIALIZE_PASS(LCSSA, "lcssa", "Loop-Closed SSA Form Pass", false, false); Pass *llvm::createLCSSAPass() { return new LCSSA(); } -const PassInfo *const llvm::LCSSAID = &X; +char &llvm::LCSSAID = LCSSA::ID; /// BlockDominatesAnExit - Return true if the specified block dominates at least @@ -215,7 +206,7 @@ bool LCSSA::ProcessInstruction(Instruction *Inst, DomTreeNode *DomNode = DT->getNode(DomBB); SSAUpdater SSAUpdate; - SSAUpdate.Initialize(Inst); + SSAUpdate.Initialize(Inst->getType(), Inst->getName()); // Insert the LCSSA phi's into all of the exit blocks dominated by the // value, and add them to the Phi's map. diff --git a/lib/Transforms/Utils/Local.cpp b/lib/Transforms/Utils/Local.cpp index 8e91138..52f0499 100644 --- a/lib/Transforms/Utils/Local.cpp +++ b/lib/Transforms/Utils/Local.cpp @@ -490,6 +490,9 @@ static bool CanPropagatePredecessorsForPHIs(BasicBlock *BB, BasicBlock *Succ) { /// rewriting all the predecessors to branch to the successor block and return /// true. If we can't transform, return false. bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB) { + assert(BB != &BB->getParent()->getEntryBlock() && + "TryToSimplifyUncondBranchFromEmptyBlock called on entry block!"); + // We can't eliminate infinite loops. BasicBlock *Succ = cast(BB->getTerminator())->getSuccessor(0); if (BB == Succ) return false; diff --git a/lib/Transforms/Utils/LoopSimplify.cpp b/lib/Transforms/Utils/LoopSimplify.cpp index 4f4edf3..b3c4801 100644 --- a/lib/Transforms/Utils/LoopSimplify.cpp +++ b/lib/Transforms/Utils/LoopSimplify.cpp @@ -46,9 +46,9 @@ #include "llvm/LLVMContext.h" #include "llvm/Type.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/Dominators.h" #include "llvm/Analysis/LoopPass.h" -#include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Support/CFG.h" @@ -65,27 +65,30 @@ STATISTIC(NumNested , "Number of nested loops split out"); namespace { struct LoopSimplify : public LoopPass { static char ID; // Pass identification, replacement for typeid - LoopSimplify() : LoopPass(&ID) {} + LoopSimplify() : LoopPass(ID) {} // AA - If we have an alias analysis object to update, this is it, otherwise // this is null. AliasAnalysis *AA; LoopInfo *LI; DominatorTree *DT; + ScalarEvolution *SE; Loop *L; virtual bool runOnLoop(Loop *L, LPPassManager &LPM); virtual void getAnalysisUsage(AnalysisUsage &AU) const { // We need loop information to identify the loops... - AU.addRequiredTransitive(); - AU.addRequiredTransitive(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); AU.addPreserved(); - AU.addPreserved(); - AU.addPreserved(); + AU.addPreserved(); AU.addPreserved(); AU.addPreservedID(BreakCriticalEdgesID); // No critical edges added. + AU.addPreserved(); + AU.addPreservedID(LCSSAID); } /// verifyAnalysis() - Verify LoopSimplifyForm's guarantees. @@ -104,11 +107,11 @@ namespace { } char LoopSimplify::ID = 0; -static RegisterPass -X("loopsimplify", "Canonicalize natural loops", true); +INITIALIZE_PASS(LoopSimplify, "loopsimplify", + "Canonicalize natural loops", true, false); // Publically exposed interface to pass... -const PassInfo *const llvm::LoopSimplifyID = &X; +char &llvm::LoopSimplifyID = LoopSimplify::ID; Pass *llvm::createLoopSimplifyPass() { return new LoopSimplify(); } /// runOnLoop - Run down all loops in the CFG (recursively, but we could do @@ -120,6 +123,7 @@ bool LoopSimplify::runOnLoop(Loop *l, LPPassManager &LPM) { LI = &getAnalysis(); AA = getAnalysisIfAvailable(); DT = &getAnalysis(); + SE = getAnalysisIfAvailable(); Changed |= ProcessLoop(L, LPM); @@ -141,15 +145,16 @@ ReprocessLoop: BB != E; ++BB) { if (*BB == L->getHeader()) continue; - SmallPtrSet BadPreds; - for (pred_iterator PI = pred_begin(*BB), PE = pred_end(*BB); PI != PE; ++PI){ + SmallPtrSet BadPreds; + for (pred_iterator PI = pred_begin(*BB), + PE = pred_end(*BB); PI != PE; ++PI) { BasicBlock *P = *PI; if (!L->contains(P)) BadPreds.insert(P); } // Delete each unique out-of-loop (and thus dead) predecessor. - for (SmallPtrSet::iterator I = BadPreds.begin(), + for (SmallPtrSet::iterator I = BadPreds.begin(), E = BadPreds.end(); I != E; ++I) { DEBUG(dbgs() << "LoopSimplify: Deleting edge from dead predecessor "; @@ -530,6 +535,12 @@ Loop *LoopSimplify::SeparateNestedLoop(Loop *L, LPPassManager &LPM) { DEBUG(dbgs() << "LoopSimplify: Splitting out a new outer loop\n"); + // If ScalarEvolution is around and knows anything about values in + // this loop, tell it to forget them, because we're about to + // substantially change it. + if (SE) + SE->forgetLoop(L); + BasicBlock *Header = L->getHeader(); BasicBlock *NewBB = SplitBlockPredecessors(Header, &OuterLoopPreds[0], OuterLoopPreds.size(), @@ -619,6 +630,11 @@ LoopSimplify::InsertUniqueBackedgeBlock(Loop *L, BasicBlock *Preheader) { std::vector BackedgeBlocks; for (pred_iterator I = pred_begin(Header), E = pred_end(Header); I != E; ++I){ BasicBlock *P = *I; + + // Indirectbr edges cannot be split, so we must fail if we find one. + if (isa(P->getTerminator())) + return 0; + if (P != Preheader) BackedgeBlocks.push_back(P); } diff --git a/lib/Transforms/Utils/LoopUnroll.cpp b/lib/Transforms/Utils/LoopUnroll.cpp index e0e07e7..236bbe9 100644 --- a/lib/Transforms/Utils/LoopUnroll.cpp +++ b/lib/Transforms/Utils/LoopUnroll.cpp @@ -24,6 +24,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/LoopPass.h" +#include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -127,6 +128,11 @@ bool llvm::UnrollLoop(Loop *L, unsigned Count, LoopInfo* LI, LPPassManager* LPM) return false; } + // Notify ScalarEvolution that the loop will be substantially changed, + // if not outright eliminated. + if (ScalarEvolution *SE = LPM->getAnalysisIfAvailable()) + SE->forgetLoop(L); + // Find trip count unsigned TripCount = L->getSmallConstantTripCount(); // Find trip multiple if count is not available diff --git a/lib/Transforms/Utils/LowerInvoke.cpp b/lib/Transforms/Utils/LowerInvoke.cpp index 2696e69..a46dd84 100644 --- a/lib/Transforms/Utils/LowerInvoke.cpp +++ b/lib/Transforms/Utils/LowerInvoke.cpp @@ -78,14 +78,14 @@ namespace { static char ID; // Pass identification, replacement for typeid explicit LowerInvoke(const TargetLowering *tli = NULL, bool useExpensiveEHSupport = ExpensiveEHSupport) - : FunctionPass(&ID), useExpensiveEHSupport(useExpensiveEHSupport), + : FunctionPass(ID), useExpensiveEHSupport(useExpensiveEHSupport), TLI(tli) { } bool doInitialization(Module &M); bool runOnFunction(Function &F); virtual void getAnalysisUsage(AnalysisUsage &AU) const { // This is a cluster of orthogonal Transforms - AU.addPreservedID(PromoteMemoryToRegisterID); + AU.addPreserved("mem2reg"); AU.addPreservedID(LowerSwitchID); } @@ -100,10 +100,11 @@ namespace { } char LowerInvoke::ID = 0; -static RegisterPass -X("lowerinvoke", "Lower invoke and unwind, for unwindless code generators"); +INITIALIZE_PASS(LowerInvoke, "lowerinvoke", + "Lower invoke and unwind, for unwindless code generators", + false, false); -const PassInfo *const llvm::LowerInvokePassID = &X; +char &llvm::LowerInvokePassID = LowerInvoke::ID; // Public Interface To the LowerInvoke pass. FunctionPass *llvm::createLowerInvokePass(const TargetLowering *TLI) { diff --git a/lib/Transforms/Utils/LowerSwitch.cpp b/lib/Transforms/Utils/LowerSwitch.cpp index 468a5fe..5530b47 100644 --- a/lib/Transforms/Utils/LowerSwitch.cpp +++ b/lib/Transforms/Utils/LowerSwitch.cpp @@ -29,19 +29,18 @@ using namespace llvm; namespace { /// LowerSwitch Pass - Replace all SwitchInst instructions with chained branch - /// instructions. Note that this cannot be a BasicBlock pass because it - /// modifies the CFG! + /// instructions. class LowerSwitch : public FunctionPass { public: static char ID; // Pass identification, replacement for typeid - LowerSwitch() : FunctionPass(&ID) {} + LowerSwitch() : FunctionPass(ID) {} virtual bool runOnFunction(Function &F); virtual void getAnalysisUsage(AnalysisUsage &AU) const { // This is a cluster of orthogonal Transforms AU.addPreserved(); - AU.addPreservedID(PromoteMemoryToRegisterID); + AU.addPreserved("mem2reg"); AU.addPreservedID(LowerInvokePassID); } @@ -50,8 +49,7 @@ namespace { Constant* High; BasicBlock* BB; - CaseRange() : Low(0), High(0), BB(0) { } - CaseRange(Constant* low, Constant* high, BasicBlock* bb) : + CaseRange(Constant *low = 0, Constant *high = 0, BasicBlock *bb = 0) : Low(low), High(high), BB(bb) { } }; @@ -81,11 +79,11 @@ namespace { } char LowerSwitch::ID = 0; -static RegisterPass -X("lowerswitch", "Lower SwitchInst's to branches"); +INITIALIZE_PASS(LowerSwitch, "lowerswitch", + "Lower SwitchInst's to branches", false, false); // Publically exposed interface to pass... -const PassInfo *const llvm::LowerSwitchID = &X; +char &llvm::LowerSwitchID = LowerSwitch::ID; // createLowerSwitchPass - Interface to this file... FunctionPass *llvm::createLowerSwitchPass() { return new LowerSwitch(); diff --git a/lib/Transforms/Utils/Mem2Reg.cpp b/lib/Transforms/Utils/Mem2Reg.cpp index 99203b6..101645b 100644 --- a/lib/Transforms/Utils/Mem2Reg.cpp +++ b/lib/Transforms/Utils/Mem2Reg.cpp @@ -27,7 +27,7 @@ STATISTIC(NumPromoted, "Number of alloca's promoted"); namespace { struct PromotePass : public FunctionPass { static char ID; // Pass identification, replacement for typeid - PromotePass() : FunctionPass(&ID) {} + PromotePass() : FunctionPass(ID) {} // runOnFunction - To run this pass, first we calculate the alloca // instructions that are safe for promotion, then we promote each one. @@ -49,7 +49,8 @@ namespace { } // end of anonymous namespace char PromotePass::ID = 0; -static RegisterPass X("mem2reg", "Promote Memory to Register"); +INITIALIZE_PASS(PromotePass, "mem2reg", "Promote Memory to Register", + false, false); bool PromotePass::runOnFunction(Function &F) { std::vector Allocas; @@ -81,8 +82,6 @@ bool PromotePass::runOnFunction(Function &F) { return Changed; } -// Publically exposed interface to pass... -const PassInfo *const llvm::PromoteMemoryToRegisterID = &X; // createPromoteMemoryToRegister - Provide an entry point to create this pass. // FunctionPass *llvm::createPromoteMemoryToRegisterPass() { diff --git a/lib/Transforms/Utils/PromoteMemoryToRegister.cpp b/lib/Transforms/Utils/PromoteMemoryToRegister.cpp index c0de193..a4e3029 100644 --- a/lib/Transforms/Utils/PromoteMemoryToRegister.cpp +++ b/lib/Transforms/Utils/PromoteMemoryToRegister.cpp @@ -228,14 +228,6 @@ namespace { void run(); - /// properlyDominates - Return true if I1 properly dominates I2. - /// - bool properlyDominates(Instruction *I1, Instruction *I2) const { - if (InvokeInst *II = dyn_cast(I1)) - I1 = II->getNormalDest()->begin(); - return DT.properlyDominates(I1->getParent(), I2->getParent()); - } - /// dominates - Return true if BB1 dominates BB2 using the DominatorTree. /// bool dominates(BasicBlock *BB1, BasicBlock *BB2) const { @@ -896,11 +888,12 @@ void PromoteMem2Reg::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI, DIVar, SI); // Propagate any debug metadata from the store onto the dbg.value. - if (MDNode *SIMD = SI->getMetadata("dbg")) - DbgVal->setMetadata("dbg", SIMD); + DebugLoc SIDL = SI->getDebugLoc(); + if (!SIDL.isUnknown()) + DbgVal->setDebugLoc(SIDL); // Otherwise propagate debug metadata from dbg.declare. - else if (MDNode *MD = DDI->getMetadata("dbg")) - DbgVal->setMetadata("dbg", MD); + else + DbgVal->setDebugLoc(DDI->getDebugLoc()); } // QueuePhiNode - queues a phi-node to be added to a basic-block for a specific diff --git a/lib/Transforms/Utils/SSAUpdater.cpp b/lib/Transforms/Utils/SSAUpdater.cpp index f4bdb527..c855988 100644 --- a/lib/Transforms/Utils/SSAUpdater.cpp +++ b/lib/Transforms/Utils/SSAUpdater.cpp @@ -29,20 +29,21 @@ static AvailableValsTy &getAvailableVals(void *AV) { } SSAUpdater::SSAUpdater(SmallVectorImpl *NewPHI) - : AV(0), PrototypeValue(0), InsertedPHIs(NewPHI) {} + : AV(0), ProtoType(0), ProtoName(), InsertedPHIs(NewPHI) {} SSAUpdater::~SSAUpdater() { delete &getAvailableVals(AV); } /// Initialize - Reset this object to get ready for a new set of SSA -/// updates. ProtoValue is the value used to name PHI nodes. -void SSAUpdater::Initialize(Value *ProtoValue) { +/// updates with type 'Ty'. PHI nodes get a name based on 'Name'. +void SSAUpdater::Initialize(const Type *Ty, StringRef Name) { if (AV == 0) AV = new AvailableValsTy(); else getAvailableVals(AV).clear(); - PrototypeValue = ProtoValue; + ProtoType = Ty; + ProtoName = Name; } /// HasValueForBlock - Return true if the SSAUpdater already has a value for @@ -54,8 +55,8 @@ bool SSAUpdater::HasValueForBlock(BasicBlock *BB) const { /// AddAvailableValue - Indicate that a rewritten value is available in the /// specified block with the specified value. void SSAUpdater::AddAvailableValue(BasicBlock *BB, Value *V) { - assert(PrototypeValue != 0 && "Need to initialize SSAUpdater"); - assert(PrototypeValue->getType() == V->getType() && + assert(ProtoType != 0 && "Need to initialize SSAUpdater"); + assert(ProtoType == V->getType() && "All rewritten values must have the same type"); getAvailableVals(AV)[BB] = V; } @@ -148,7 +149,7 @@ Value *SSAUpdater::GetValueInMiddleOfBlock(BasicBlock *BB) { // If there are no predecessors, just return undef. if (PredValues.empty()) - return UndefValue::get(PrototypeValue->getType()); + return UndefValue::get(ProtoType); // Otherwise, if all the merged values are the same, just use it. if (SingularValue != 0) @@ -168,9 +169,7 @@ Value *SSAUpdater::GetValueInMiddleOfBlock(BasicBlock *BB) { } // Ok, we have no way out, insert a new one now. - PHINode *InsertedPHI = PHINode::Create(PrototypeValue->getType(), - PrototypeValue->getName(), - &BB->front()); + PHINode *InsertedPHI = PHINode::Create(ProtoType, ProtoName, &BB->front()); InsertedPHI->reserveOperandSpace(PredValues.size()); // Fill in all the predecessors of the PHI. @@ -205,6 +204,22 @@ void SSAUpdater::RewriteUse(Use &U) { U.set(V); } +/// RewriteUseAfterInsertions - Rewrite a use, just like RewriteUse. However, +/// this version of the method can rewrite uses in the same block as a +/// definition, because it assumes that all uses of a value are below any +/// inserted values. +void SSAUpdater::RewriteUseAfterInsertions(Use &U) { + Instruction *User = cast(U.getUser()); + + Value *V; + if (PHINode *UserPN = dyn_cast(User)) + V = GetValueAtEndOfBlock(UserPN->getIncomingBlock(U)); + else + V = GetValueAtEndOfBlock(User->getParent()); + + U.set(V); +} + /// PHIiter - Iterator for PHI operands. This is used for the PHI_iterator /// in the SSAUpdaterImpl template. namespace { @@ -266,15 +281,14 @@ public: /// GetUndefVal - Get an undefined value of the same type as the value /// being handled. static Value *GetUndefVal(BasicBlock *BB, SSAUpdater *Updater) { - return UndefValue::get(Updater->PrototypeValue->getType()); + return UndefValue::get(Updater->ProtoType); } /// CreateEmptyPHI - Create a new PHI instruction in the specified block. /// Reserve space for the operands but do not fill them in yet. static Value *CreateEmptyPHI(BasicBlock *BB, unsigned NumPreds, SSAUpdater *Updater) { - PHINode *PHI = PHINode::Create(Updater->PrototypeValue->getType(), - Updater->PrototypeValue->getName(), + PHINode *PHI = PHINode::Create(Updater->ProtoType, Updater->ProtoName, &BB->front()); PHI->reserveOperandSpace(NumPreds); return PHI; diff --git a/lib/Transforms/Utils/SSI.cpp b/lib/Transforms/Utils/SSI.cpp deleted file mode 100644 index 4e813dd..0000000 --- a/lib/Transforms/Utils/SSI.cpp +++ /dev/null @@ -1,432 +0,0 @@ -//===------------------- SSI.cpp - Creates SSI Representation -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This pass converts a list of variables to the Static Single Information -// form. This is a program representation described by Scott Ananian in his -// Master Thesis: "The Static Single Information Form (1999)". -// We are building an on-demand representation, that is, we do not convert -// every single variable in the target function to SSI form. Rather, we receive -// a list of target variables that must be converted. We also do not -// completely convert a target variable to the SSI format. Instead, we only -// change the variable in the points where new information can be attached -// to its live range, that is, at branch points. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "ssi" - -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Utils/SSI.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/Dominators.h" - -using namespace llvm; - -static const std::string SSI_PHI = "SSI_phi"; -static const std::string SSI_SIG = "SSI_sigma"; - -STATISTIC(NumSigmaInserted, "Number of sigma functions inserted"); -STATISTIC(NumPhiInserted, "Number of phi functions inserted"); - -void SSI::getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredTransitive(); - AU.addRequiredTransitive(); - AU.setPreservesAll(); -} - -bool SSI::runOnFunction(Function &F) { - DT_ = &getAnalysis(); - return false; -} - -/// This methods creates the SSI representation for the list of values -/// received. It will only create SSI representation if a value is used -/// to decide a branch. Repeated values are created only once. -/// -void SSI::createSSI(SmallVectorImpl &value) { - init(value); - - SmallPtrSet needConstruction; - for (SmallVectorImpl::iterator I = value.begin(), - E = value.end(); I != E; ++I) - if (created.insert(*I)) - needConstruction.insert(*I); - - insertSigmaFunctions(needConstruction); - - // Test if there is a need to transform to SSI - if (!needConstruction.empty()) { - insertPhiFunctions(needConstruction); - renameInit(needConstruction); - rename(DT_->getRoot()); - fixPhis(); - } - - clean(); -} - -/// Insert sigma functions (a sigma function is a phi function with one -/// operator) -/// -void SSI::insertSigmaFunctions(SmallPtrSet &value) { - for (SmallPtrSet::iterator I = value.begin(), - E = value.end(); I != E; ++I) { - for (Value::use_iterator begin = (*I)->use_begin(), - end = (*I)->use_end(); begin != end; ++begin) { - // Test if the Use of the Value is in a comparator - if (CmpInst *CI = dyn_cast(begin)) { - // Iterates through all uses of CmpInst - for (Value::use_iterator begin_ci = CI->use_begin(), - end_ci = CI->use_end(); begin_ci != end_ci; ++begin_ci) { - // Test if any use of CmpInst is in a Terminator - if (TerminatorInst *TI = dyn_cast(begin_ci)) { - insertSigma(TI, *I); - } - } - } - } - } -} - -/// Inserts Sigma Functions in every BasicBlock successor to Terminator -/// Instruction TI. All inserted Sigma Function are related to Instruction I. -/// -void SSI::insertSigma(TerminatorInst *TI, Instruction *I) { - // Basic Block of the Terminator Instruction - BasicBlock *BB = TI->getParent(); - for (unsigned i = 0, e = TI->getNumSuccessors(); i < e; ++i) { - // Next Basic Block - BasicBlock *BB_next = TI->getSuccessor(i); - if (BB_next != BB && - BB_next->getSinglePredecessor() != NULL && - dominateAny(BB_next, I)) { - PHINode *PN = PHINode::Create(I->getType(), SSI_SIG, BB_next->begin()); - PN->addIncoming(I, BB); - sigmas[PN] = I; - created.insert(PN); - defsites[I].push_back(BB_next); - ++NumSigmaInserted; - } - } -} - -/// Insert phi functions when necessary -/// -void SSI::insertPhiFunctions(SmallPtrSet &value) { - DominanceFrontier *DF = &getAnalysis(); - for (SmallPtrSet::iterator I = value.begin(), - E = value.end(); I != E; ++I) { - // Test if there were any sigmas for this variable - SmallPtrSet BB_visited; - - // Insert phi functions if there is any sigma function - while (!defsites[*I].empty()) { - - BasicBlock *BB = defsites[*I].back(); - - defsites[*I].pop_back(); - DominanceFrontier::iterator DF_BB = DF->find(BB); - - // The BB is unreachable. Skip it. - if (DF_BB == DF->end()) - continue; - - // Iterates through all the dominance frontier of BB - for (std::set::iterator DF_BB_begin = - DF_BB->second.begin(), DF_BB_end = DF_BB->second.end(); - DF_BB_begin != DF_BB_end; ++DF_BB_begin) { - BasicBlock *BB_dominated = *DF_BB_begin; - - // Test if has not yet visited this node and if the - // original definition dominates this node - if (BB_visited.insert(BB_dominated) && - DT_->properlyDominates(value_original[*I], BB_dominated) && - dominateAny(BB_dominated, *I)) { - PHINode *PN = PHINode::Create( - (*I)->getType(), SSI_PHI, BB_dominated->begin()); - phis.insert(std::make_pair(PN, *I)); - created.insert(PN); - - defsites[*I].push_back(BB_dominated); - ++NumPhiInserted; - } - } - } - BB_visited.clear(); - } -} - -/// Some initialization for the rename part -/// -void SSI::renameInit(SmallPtrSet &value) { - for (SmallPtrSet::iterator I = value.begin(), - E = value.end(); I != E; ++I) - value_stack[*I].push_back(*I); -} - -/// Renames all variables in the specified BasicBlock. -/// Only variables that need to be rename will be. -/// -void SSI::rename(BasicBlock *BB) { - SmallPtrSet defined; - - // Iterate through instructions and make appropriate renaming. - // For SSI_PHI (b = PHI()), store b at value_stack as a new - // definition of the variable it represents. - // For SSI_SIG (b = PHI(a)), substitute a with the current - // value of a, present in the value_stack. - // Then store bin the value_stack as the new definition of a. - // For all other instructions (b = OP(a, c, d, ...)), we need to substitute - // all operands with its current value, present in value_stack. - for (BasicBlock::iterator begin = BB->begin(), end = BB->end(); - begin != end; ++begin) { - Instruction *I = begin; - if (PHINode *PN = dyn_cast(I)) { // Treat PHI functions - Instruction* position; - - // Treat SSI_PHI - if ((position = getPositionPhi(PN))) { - value_stack[position].push_back(PN); - defined.insert(position); - // Treat SSI_SIG - } else if ((position = getPositionSigma(PN))) { - substituteUse(I); - value_stack[position].push_back(PN); - defined.insert(position); - } - - // Treat all other PHI functions - else { - substituteUse(I); - } - } - - // Treat all other functions - else { - substituteUse(I); - } - } - - // This loop iterates in all BasicBlocks that are successors of the current - // BasicBlock. For each SSI_PHI instruction found, insert an operand. - // This operand is the current operand in value_stack for the variable - // in "position". And the BasicBlock this operand represents is the current - // BasicBlock. - for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI) { - BasicBlock *BB_succ = *SI; - - for (BasicBlock::iterator begin = BB_succ->begin(), - notPhi = BB_succ->getFirstNonPHI(); begin != *notPhi; ++begin) { - Instruction *I = begin; - PHINode *PN = dyn_cast(I); - Instruction* position; - if (PN && ((position = getPositionPhi(PN)))) { - PN->addIncoming(value_stack[position].back(), BB); - } - } - } - - // This loop calls rename on all children from this block. This time children - // refers to a successor block in the dominance tree. - DomTreeNode *DTN = DT_->getNode(BB); - for (DomTreeNode::iterator begin = DTN->begin(), end = DTN->end(); - begin != end; ++begin) { - DomTreeNodeBase *DTN_children = *begin; - BasicBlock *BB_children = DTN_children->getBlock(); - rename(BB_children); - } - - // Now we remove all inserted definitions of a variable from the top of - // the stack leaving the previous one as the top. - for (SmallPtrSet::iterator DI = defined.begin(), - DE = defined.end(); DI != DE; ++DI) - value_stack[*DI].pop_back(); -} - -/// Substitute any use in this instruction for the last definition of -/// the variable -/// -void SSI::substituteUse(Instruction *I) { - for (unsigned i = 0, e = I->getNumOperands(); i < e; ++i) { - Value *operand = I->getOperand(i); - for (DenseMap >::iterator - VI = value_stack.begin(), VE = value_stack.end(); VI != VE; ++VI) { - if (operand == VI->second.front() && - I != VI->second.back()) { - PHINode *PN_I = dyn_cast(I); - PHINode *PN_vs = dyn_cast(VI->second.back()); - - // If a phi created in a BasicBlock is used as an operand of another - // created in the same BasicBlock, this step marks this second phi, - // to fix this issue later. It cannot be fixed now, because the - // operands of the first phi are not final yet. - if (PN_I && PN_vs && - VI->second.back()->getParent() == I->getParent()) { - - phisToFix.insert(PN_I); - } - - I->setOperand(i, VI->second.back()); - break; - } - } - } -} - -/// Test if the BasicBlock BB dominates any use or definition of value. -/// If it dominates a phi instruction that is on the same BasicBlock, -/// that does not count. -/// -bool SSI::dominateAny(BasicBlock *BB, Instruction *value) { - for (Value::use_iterator begin = value->use_begin(), - end = value->use_end(); begin != end; ++begin) { - Instruction *I = cast(*begin); - BasicBlock *BB_father = I->getParent(); - if (BB == BB_father && isa(I)) - continue; - if (DT_->dominates(BB, BB_father)) { - return true; - } - } - return false; -} - -/// When there is a phi node that is created in a BasicBlock and it is used -/// as an operand of another phi function used in the same BasicBlock, -/// LLVM looks this as an error. So on the second phi, the first phi is called -/// P and the BasicBlock it incomes is B. This P will be replaced by the value -/// it has for BasicBlock B. It also includes undef values for predecessors -/// that were not included in the phi. -/// -void SSI::fixPhis() { - for (SmallPtrSet::iterator begin = phisToFix.begin(), - end = phisToFix.end(); begin != end; ++begin) { - PHINode *PN = *begin; - for (unsigned i = 0, e = PN->getNumIncomingValues(); i < e; ++i) { - PHINode *PN_father = dyn_cast(PN->getIncomingValue(i)); - if (PN_father && PN->getParent() == PN_father->getParent() && - !DT_->dominates(PN->getParent(), PN->getIncomingBlock(i))) { - BasicBlock *BB = PN->getIncomingBlock(i); - int pos = PN_father->getBasicBlockIndex(BB); - PN->setIncomingValue(i, PN_father->getIncomingValue(pos)); - } - } - } - - for (DenseMapIterator begin = phis.begin(), - end = phis.end(); begin != end; ++begin) { - PHINode *PN = begin->first; - BasicBlock *BB = PN->getParent(); - pred_iterator PI = pred_begin(BB), PE = pred_end(BB); - SmallVector Preds(PI, PE); - for (unsigned size = Preds.size(); - PI != PE && PN->getNumIncomingValues() != size; ++PI) { - bool found = false; - for (unsigned i = 0, pn_end = PN->getNumIncomingValues(); - i < pn_end; ++i) { - if (PN->getIncomingBlock(i) == *PI) { - found = true; - break; - } - } - if (!found) { - PN->addIncoming(UndefValue::get(PN->getType()), *PI); - } - } - } -} - -/// Return which variable (position on the vector of variables) this phi -/// represents on the phis list. -/// -Instruction* SSI::getPositionPhi(PHINode *PN) { - DenseMap::iterator val = phis.find(PN); - if (val == phis.end()) - return 0; - else - return val->second; -} - -/// Return which variable (position on the vector of variables) this phi -/// represents on the sigmas list. -/// -Instruction* SSI::getPositionSigma(PHINode *PN) { - DenseMap::iterator val = sigmas.find(PN); - if (val == sigmas.end()) - return 0; - else - return val->second; -} - -/// Initializes -/// -void SSI::init(SmallVectorImpl &value) { - for (SmallVectorImpl::iterator I = value.begin(), - E = value.end(); I != E; ++I) { - value_original[*I] = (*I)->getParent(); - defsites[*I].push_back((*I)->getParent()); - } -} - -/// Clean all used resources in this creation of SSI -/// -void SSI::clean() { - phis.clear(); - sigmas.clear(); - phisToFix.clear(); - - defsites.clear(); - value_stack.clear(); - value_original.clear(); -} - -/// createSSIPass - The public interface to this file... -/// -FunctionPass *llvm::createSSIPass() { return new SSI(); } - -char SSI::ID = 0; -static RegisterPass X("ssi", "Static Single Information Construction"); - -/// SSIEverything - A pass that runs createSSI on every non-void variable, -/// intended for debugging. -namespace { - struct SSIEverything : public FunctionPass { - static char ID; // Pass identification, replacement for typeid - SSIEverything() : FunctionPass(&ID) {} - - bool runOnFunction(Function &F); - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired(); - } - }; -} - -bool SSIEverything::runOnFunction(Function &F) { - SmallVector Insts; - SSI &ssi = getAnalysis(); - - if (F.isDeclaration() || F.isIntrinsic()) return false; - - for (Function::iterator B = F.begin(), BE = F.end(); B != BE; ++B) - for (BasicBlock::iterator I = B->begin(), E = B->end(); I != E; ++I) - if (!I->getType()->isVoidTy()) - Insts.push_back(I); - - ssi.createSSI(Insts); - return true; -} - -/// createSSIEverythingPass - The public interface to this file... -/// -FunctionPass *llvm::createSSIEverythingPass() { return new SSIEverything(); } - -char SSIEverything::ID = 0; -static RegisterPass -Y("ssi-everything", "Static Single Information Construction"); diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp index 27b07d9..28d7afb 100644 --- a/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/lib/Transforms/Utils/SimplifyCFG.cpp @@ -949,7 +949,7 @@ static bool SpeculativelyExecuteBB(BranchInst *BI, BasicBlock *BB1) { UI != E; ++UI) { // Ignore any user that is not a PHI node in BB2. These can only occur in // unreachable blocks, because they would not be dominated by the instr. - PHINode *PN = dyn_cast(UI); + PHINode *PN = dyn_cast(*UI); if (!PN || PN->getParent() != BB2) return false; PHIUses.push_back(PN); @@ -1724,12 +1724,12 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) { assert(BB && BB->getParent() && "Block not embedded in function!"); assert(BB->getTerminator() && "Degenerate basic block encountered!"); - assert(&BB->getParent()->getEntryBlock() != BB && - "Can't Simplify entry block!"); - // Remove basic blocks that have no predecessors... or that just have themself - // as a predecessor. These are unreachable. - if (pred_begin(BB) == pred_end(BB) || BB->getSinglePredecessor() == BB) { + // Remove basic blocks that have no predecessors (except the entry block)... + // or that just have themself as a predecessor. These are unreachable. + if ((pred_begin(BB) == pred_end(BB) && + &BB->getParent()->getEntryBlock() != BB) || + BB->getSinglePredecessor() == BB) { DEBUG(dbgs() << "Removing BB: \n" << *BB); DeleteDeadBlock(BB); return true; @@ -1880,8 +1880,9 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) { while (isa(BBI)) ++BBI; if (BBI->isTerminator()) // Terminator is the only non-phi instruction! - if (TryToSimplifyUncondBranchFromEmptyBlock(BB)) - return true; + if (BB != &BB->getParent()->getEntryBlock()) + if (TryToSimplifyUncondBranchFromEmptyBlock(BB)) + return true; } else { // Conditional branch if (isValueEqualityComparison(BI)) { @@ -2049,12 +2050,38 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) { } // If this block is now dead, remove it. - if (pred_begin(BB) == pred_end(BB)) { + if (pred_begin(BB) == pred_end(BB) && + BB != &BB->getParent()->getEntryBlock()) { // We know there are no successors, so just nuke the block. M->getBasicBlockList().erase(BB); return true; } } + } else if (IndirectBrInst *IBI = + dyn_cast(BB->getTerminator())) { + // Eliminate redundant destinations. + SmallPtrSet Succs; + for (unsigned i = 0, e = IBI->getNumDestinations(); i != e; ++i) { + BasicBlock *Dest = IBI->getDestination(i); + if (!Dest->hasAddressTaken() || !Succs.insert(Dest)) { + Dest->removePredecessor(BB); + IBI->removeDestination(i); + --i; --e; + Changed = true; + } + } + + if (IBI->getNumDestinations() == 0) { + // If the indirectbr has no successors, change it to unreachable. + new UnreachableInst(IBI->getContext(), IBI); + IBI->eraseFromParent(); + Changed = true; + } else if (IBI->getNumDestinations() == 1) { + // If the indirectbr has one successor, change it to a direct branch. + BranchInst::Create(IBI->getDestination(0), IBI); + IBI->eraseFromParent(); + Changed = true; + } } // Merge basic blocks into their predecessor if there is only one distinct @@ -2068,12 +2095,15 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) { // is a conditional branch, see if we can hoist any code from this block up // into our predecessor. pred_iterator PI(pred_begin(BB)), PE(pred_end(BB)); - BasicBlock *OnlyPred = *PI++; - for (; PI != PE; ++PI) // Search all predecessors, see if they are all same - if (*PI != OnlyPred) { + BasicBlock *OnlyPred = 0; + for (; PI != PE; ++PI) { // Search all predecessors, see if they are all same + if (!OnlyPred) + OnlyPred = *PI; + else if (*PI != OnlyPred) { OnlyPred = 0; // There are multiple different predecessors... break; } + } if (OnlyPred) if (BranchInst *BI = dyn_cast(OnlyPred->getTerminator())) @@ -2172,8 +2202,6 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) { /// eliminates unreachable basic blocks, and does other "peephole" optimization /// of the CFG. It returns true if a modification was made. /// -/// WARNING: The entry node of a function may not be simplified. -/// bool llvm::SimplifyCFG(BasicBlock *BB, const TargetData *TD) { return SimplifyCFGOpt(TD).run(BB); } diff --git a/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp b/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp index 3fa8b70..a51f1e1 100644 --- a/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp +++ b/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp @@ -24,8 +24,8 @@ using namespace llvm; char UnifyFunctionExitNodes::ID = 0; -static RegisterPass -X("mergereturn", "Unify function exit nodes"); +INITIALIZE_PASS(UnifyFunctionExitNodes, "mergereturn", + "Unify function exit nodes", false, false); Pass *llvm::createUnifyFunctionExitNodesPass() { return new UnifyFunctionExitNodes(); @@ -35,7 +35,7 @@ void UnifyFunctionExitNodes::getAnalysisUsage(AnalysisUsage &AU) const{ // We preserve the non-critical-edgeness property AU.addPreservedID(BreakCriticalEdgesID); // This is a cluster of orthogonal Transforms - AU.addPreservedID(PromoteMemoryToRegisterID); + AU.addPreserved("mem2reg"); AU.addPreservedID(LowerSwitchID); } diff --git a/lib/Transforms/Utils/ValueMapper.cpp b/lib/Transforms/Utils/ValueMapper.cpp index 3f6a90c..fc4bde7 100644 --- a/lib/Transforms/Utils/ValueMapper.cpp +++ b/lib/Transforms/Utils/ValueMapper.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "ValueMapper.h" +#include "llvm/Transforms/Utils/ValueMapper.h" #include "llvm/Type.h" #include "llvm/Constants.h" #include "llvm/Function.h" @@ -20,28 +20,51 @@ #include "llvm/ADT/SmallVector.h" using namespace llvm; -Value *llvm::MapValue(const Value *V, ValueToValueMapTy &VM) { +Value *llvm::MapValue(const Value *V, ValueToValueMapTy &VM, + bool ModuleLevelChanges) { Value *&VMSlot = VM[V]; if (VMSlot) return VMSlot; // Does it exist in the map yet? // NOTE: VMSlot can be invalidated by any reference to VM, which can grow the // DenseMap. This includes any recursive calls to MapValue. - // Global values and non-function-local metadata do not need to be seeded into - // the VM if they are using the identity mapping. + // Global values do not need to be seeded into the VM if they + // are using the identity mapping. if (isa(V) || isa(V) || isa(V) || - (isa(V) && !cast(V)->isFunctionLocal())) + (isa(V) && !cast(V)->isFunctionLocal() && + !ModuleLevelChanges)) return VMSlot = const_cast(V); if (const MDNode *MD = dyn_cast(V)) { - SmallVector Elts; - for (unsigned i = 0, e = MD->getNumOperands(); i != e; ++i) - Elts.push_back(MD->getOperand(i) ? MapValue(MD->getOperand(i), VM) : 0); - return VM[V] = MDNode::get(V->getContext(), Elts.data(), Elts.size()); + // Start by assuming that we'll use the identity mapping. + VMSlot = const_cast(V); + + // Check all operands to see if any need to be remapped. + for (unsigned i = 0, e = MD->getNumOperands(); i != e; ++i) { + Value *OP = MD->getOperand(i); + if (!OP || MapValue(OP, VM, ModuleLevelChanges) == OP) continue; + + // Ok, at least one operand needs remapping. + MDNode *Dummy = MDNode::getTemporary(V->getContext(), 0, 0); + VM[V] = Dummy; + SmallVector Elts; + Elts.reserve(MD->getNumOperands()); + for (i = 0; i != e; ++i) + Elts.push_back(MD->getOperand(i) ? + MapValue(MD->getOperand(i), VM, ModuleLevelChanges) : 0); + MDNode *NewMD = MDNode::get(V->getContext(), Elts.data(), Elts.size()); + Dummy->replaceAllUsesWith(NewMD); + MDNode::deleteTemporary(Dummy); + return VM[V] = NewMD; + } + + // No operands needed remapping; keep the identity map. + return const_cast(V); } Constant *C = const_cast(dyn_cast(V)); - if (C == 0) return 0; + if (C == 0) + return 0; if (isa(C) || isa(C) || isa(C) || isa(C) || @@ -51,7 +74,7 @@ Value *llvm::MapValue(const Value *V, ValueToValueMapTy &VM) { if (ConstantArray *CA = dyn_cast(C)) { for (User::op_iterator b = CA->op_begin(), i = b, e = CA->op_end(); i != e; ++i) { - Value *MV = MapValue(*i, VM); + Value *MV = MapValue(*i, VM, ModuleLevelChanges); if (MV != *i) { // This array must contain a reference to a global, make a new array // and return it. @@ -62,7 +85,8 @@ Value *llvm::MapValue(const Value *V, ValueToValueMapTy &VM) { Values.push_back(cast(*j)); Values.push_back(cast(MV)); for (++i; i != e; ++i) - Values.push_back(cast(MapValue(*i, VM))); + Values.push_back(cast(MapValue(*i, VM, + ModuleLevelChanges))); return VM[V] = ConstantArray::get(CA->getType(), Values); } } @@ -72,7 +96,7 @@ Value *llvm::MapValue(const Value *V, ValueToValueMapTy &VM) { if (ConstantStruct *CS = dyn_cast(C)) { for (User::op_iterator b = CS->op_begin(), i = b, e = CS->op_end(); i != e; ++i) { - Value *MV = MapValue(*i, VM); + Value *MV = MapValue(*i, VM, ModuleLevelChanges); if (MV != *i) { // This struct must contain a reference to a global, make a new struct // and return it. @@ -83,7 +107,8 @@ Value *llvm::MapValue(const Value *V, ValueToValueMapTy &VM) { Values.push_back(cast(*j)); Values.push_back(cast(MV)); for (++i; i != e; ++i) - Values.push_back(cast(MapValue(*i, VM))); + Values.push_back(cast(MapValue(*i, VM, + ModuleLevelChanges))); return VM[V] = ConstantStruct::get(CS->getType(), Values); } } @@ -93,14 +118,14 @@ Value *llvm::MapValue(const Value *V, ValueToValueMapTy &VM) { if (ConstantExpr *CE = dyn_cast(C)) { std::vector Ops; for (User::op_iterator i = CE->op_begin(), e = CE->op_end(); i != e; ++i) - Ops.push_back(cast(MapValue(*i, VM))); + Ops.push_back(cast(MapValue(*i, VM, ModuleLevelChanges))); return VM[V] = CE->getWithOperands(Ops); } if (ConstantVector *CV = dyn_cast(C)) { for (User::op_iterator b = CV->op_begin(), i = b, e = CV->op_end(); i != e; ++i) { - Value *MV = MapValue(*i, VM); + Value *MV = MapValue(*i, VM, ModuleLevelChanges); if (MV != *i) { // This vector value must contain a reference to a global, make a new // vector constant and return it. @@ -111,7 +136,8 @@ Value *llvm::MapValue(const Value *V, ValueToValueMapTy &VM) { Values.push_back(cast(*j)); Values.push_back(cast(MV)); for (++i; i != e; ++i) - Values.push_back(cast(MapValue(*i, VM))); + Values.push_back(cast(MapValue(*i, VM, + ModuleLevelChanges))); return VM[V] = ConstantVector::get(Values); } } @@ -119,19 +145,33 @@ Value *llvm::MapValue(const Value *V, ValueToValueMapTy &VM) { } BlockAddress *BA = cast(C); - Function *F = cast(MapValue(BA->getFunction(), VM)); - BasicBlock *BB = cast_or_null(MapValue(BA->getBasicBlock(),VM)); + Function *F = cast(MapValue(BA->getFunction(), VM, + ModuleLevelChanges)); + BasicBlock *BB = cast_or_null(MapValue(BA->getBasicBlock(),VM, + ModuleLevelChanges)); return VM[V] = BlockAddress::get(F, BB ? BB : BA->getBasicBlock()); } /// RemapInstruction - Convert the instruction operands from referencing the /// current values into those specified by VMap. /// -void llvm::RemapInstruction(Instruction *I, ValueToValueMapTy &VMap) { +void llvm::RemapInstruction(Instruction *I, ValueToValueMapTy &VMap, + bool ModuleLevelChanges) { + // Remap operands. for (User::op_iterator op = I->op_begin(), E = I->op_end(); op != E; ++op) { - Value *V = MapValue(*op, VMap); + Value *V = MapValue(*op, VMap, ModuleLevelChanges); assert(V && "Referenced value not in value map!"); *op = V; } -} + // Remap attached metadata. + SmallVector, 4> MDs; + I->getAllMetadata(MDs); + for (SmallVectorImpl >::iterator + MI = MDs.begin(), ME = MDs.end(); MI != ME; ++MI) { + Value *Old = MI->second; + Value *New = MapValue(Old, VMap, ModuleLevelChanges); + if (New != Old) + I->setMetadata(MI->first, cast(New)); + } +} diff --git a/lib/Transforms/Utils/ValueMapper.h b/lib/Transforms/Utils/ValueMapper.h deleted file mode 100644 index f4ff643..0000000 --- a/lib/Transforms/Utils/ValueMapper.h +++ /dev/null @@ -1,29 +0,0 @@ -//===- ValueMapper.h - Interface shared by lib/Transforms/Utils -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the MapValue interface which is used by various parts of -// the Transforms/Utils library to implement cloning and linking facilities. -// -//===----------------------------------------------------------------------===// - -#ifndef VALUEMAPPER_H -#define VALUEMAPPER_H - -#include "llvm/ADT/ValueMap.h" - -namespace llvm { - class Value; - class Instruction; - typedef ValueMap ValueToValueMapTy; - - Value *MapValue(const Value *V, ValueToValueMapTy &VM); - void RemapInstruction(Instruction *I, ValueToValueMapTy &VM); -} // End llvm namespace - -#endif diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp index 09b8aa5..831a996 100644 --- a/lib/VMCore/AsmWriter.cpp +++ b/lib/VMCore/AsmWriter.cpp @@ -16,7 +16,7 @@ #include "llvm/Assembly/Writer.h" #include "llvm/Assembly/PrintModulePass.h" -#include "llvm/Assembly/AsmAnnotationWriter.h" +#include "llvm/Assembly/AssemblyAnnotationWriter.h" #include "llvm/LLVMContext.h" #include "llvm/CallingConv.h" #include "llvm/Constants.h" @@ -63,8 +63,6 @@ static const Module *getModuleFromVal(const Value *V) { if (const GlobalValue *GV = dyn_cast(V)) return GV->getParent(); - if (const NamedMDNode *NMD = dyn_cast(V)) - return NMD->getParent(); return 0; } @@ -230,7 +228,7 @@ void TypePrinting::CalcTypeName(const Type *Ty, E = STy->element_end(); I != E; ++I) { OS << ' '; CalcTypeName(*I, TypeStack, OS); - if (next(I) == STy->element_end()) + if (llvm::next(I) == STy->element_end()) OS << ' '; else OS << ','; @@ -240,21 +238,6 @@ void TypePrinting::CalcTypeName(const Type *Ty, OS << '>'; break; } - case Type::UnionTyID: { - const UnionType *UTy = cast(Ty); - OS << "union {"; - for (StructType::element_iterator I = UTy->element_begin(), - E = UTy->element_end(); I != E; ++I) { - OS << ' '; - CalcTypeName(*I, TypeStack, OS); - if (next(I) == UTy->element_end()) - OS << ' '; - else - OS << ','; - } - OS << '}'; - break; - } case Type::PointerTyID: { const PointerType *PTy = cast(Ty); CalcTypeName(PTy->getElementType(), TypeStack, OS); @@ -581,8 +564,12 @@ static SlotTracker *createSlotTracker(const Value *V) { if (const Function *Func = dyn_cast(V)) return new SlotTracker(Func); - if (isa(V)) + if (const MDNode *MD = dyn_cast(V)) { + if (!MD->isFunctionLocal()) + return new SlotTracker(MD->getFunction()); + return new SlotTracker((Function *)0); + } return 0; } @@ -634,10 +621,8 @@ void SlotTracker::processModule() { I = TheModule->named_metadata_begin(), E = TheModule->named_metadata_end(); I != E; ++I) { const NamedMDNode *NMD = I; - for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { - if (MDNode *MD = NMD->getOperand(i)) - CreateMetadataSlot(MD); - } + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) + CreateMetadataSlot(NMD->getOperand(i)); } // Add all the unnamed functions to the table. @@ -778,15 +763,14 @@ void SlotTracker::CreateMetadataSlot(const MDNode *N) { // Don't insert if N is a function-local metadata, these are always printed // inline. - if (N->isFunctionLocal()) - return; - - mdn_iterator I = mdnMap.find(N); - if (I != mdnMap.end()) - return; + if (!N->isFunctionLocal()) { + mdn_iterator I = mdnMap.find(N); + if (I != mdnMap.end()) + return; - unsigned DestSlot = mdnNext++; - mdnMap[N] = DestSlot; + unsigned DestSlot = mdnNext++; + mdnMap[N] = DestSlot; + } // Recursively add any MDNodes referenced by operands. for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) @@ -800,7 +784,8 @@ void SlotTracker::CreateMetadataSlot(const MDNode *N) { static void WriteAsOperandInternal(raw_ostream &Out, const Value *V, TypePrinting *TypePrinter, - SlotTracker *Machine); + SlotTracker *Machine, + const Module *Context); @@ -856,7 +841,8 @@ static void WriteOptimizationInfo(raw_ostream &Out, const User *U) { static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, TypePrinting &TypePrinter, - SlotTracker *Machine) { + SlotTracker *Machine, + const Module *Context) { if (const ConstantInt *CI = dyn_cast(CV)) { if (CI->getType()->isIntegerTy(1)) { Out << (CI->getZExtValue() ? "true" : "false"); @@ -972,9 +958,11 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, if (const BlockAddress *BA = dyn_cast(CV)) { Out << "blockaddress("; - WriteAsOperandInternal(Out, BA->getFunction(), &TypePrinter, Machine); + WriteAsOperandInternal(Out, BA->getFunction(), &TypePrinter, Machine, + Context); Out << ", "; - WriteAsOperandInternal(Out, BA->getBasicBlock(), &TypePrinter, Machine); + WriteAsOperandInternal(Out, BA->getBasicBlock(), &TypePrinter, Machine, + Context); Out << ")"; return; } @@ -994,12 +982,14 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, TypePrinter.print(ETy, Out); Out << ' '; WriteAsOperandInternal(Out, CA->getOperand(0), - &TypePrinter, Machine); + &TypePrinter, Machine, + Context); for (unsigned i = 1, e = CA->getNumOperands(); i != e; ++i) { Out << ", "; TypePrinter.print(ETy, Out); Out << ' '; - WriteAsOperandInternal(Out, CA->getOperand(i), &TypePrinter, Machine); + WriteAsOperandInternal(Out, CA->getOperand(i), &TypePrinter, Machine, + Context); } } Out << ']'; @@ -1017,14 +1007,16 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, TypePrinter.print(CS->getOperand(0)->getType(), Out); Out << ' '; - WriteAsOperandInternal(Out, CS->getOperand(0), &TypePrinter, Machine); + WriteAsOperandInternal(Out, CS->getOperand(0), &TypePrinter, Machine, + Context); for (unsigned i = 1; i < N; i++) { Out << ", "; TypePrinter.print(CS->getOperand(i)->getType(), Out); Out << ' '; - WriteAsOperandInternal(Out, CS->getOperand(i), &TypePrinter, Machine); + WriteAsOperandInternal(Out, CS->getOperand(i), &TypePrinter, Machine, + Context); } Out << ' '; } @@ -1035,15 +1027,6 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, return; } - if (const ConstantUnion *CU = dyn_cast(CV)) { - Out << "{ "; - TypePrinter.print(CU->getOperand(0)->getType(), Out); - Out << ' '; - WriteAsOperandInternal(Out, CU->getOperand(0), &TypePrinter, Machine); - Out << " }"; - return; - } - if (const ConstantVector *CP = dyn_cast(CV)) { const Type *ETy = CP->getType()->getElementType(); assert(CP->getNumOperands() > 0 && @@ -1051,12 +1034,14 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, Out << '<'; TypePrinter.print(ETy, Out); Out << ' '; - WriteAsOperandInternal(Out, CP->getOperand(0), &TypePrinter, Machine); + WriteAsOperandInternal(Out, CP->getOperand(0), &TypePrinter, Machine, + Context); for (unsigned i = 1, e = CP->getNumOperands(); i != e; ++i) { Out << ", "; TypePrinter.print(ETy, Out); Out << ' '; - WriteAsOperandInternal(Out, CP->getOperand(i), &TypePrinter, Machine); + WriteAsOperandInternal(Out, CP->getOperand(i), &TypePrinter, Machine, + Context); } Out << '>'; return; @@ -1087,7 +1072,7 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, for (User::const_op_iterator OI=CE->op_begin(); OI != CE->op_end(); ++OI) { TypePrinter.print((*OI)->getType(), Out); Out << ' '; - WriteAsOperandInternal(Out, *OI, &TypePrinter, Machine); + WriteAsOperandInternal(Out, *OI, &TypePrinter, Machine, Context); if (OI+1 != CE->op_end()) Out << ", "; } @@ -1112,7 +1097,8 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, static void WriteMDNodeBodyInternal(raw_ostream &Out, const MDNode *Node, TypePrinting *TypePrinter, - SlotTracker *Machine) { + SlotTracker *Machine, + const Module *Context) { Out << "!{"; for (unsigned mi = 0, me = Node->getNumOperands(); mi != me; ++mi) { const Value *V = Node->getOperand(mi); @@ -1122,7 +1108,7 @@ static void WriteMDNodeBodyInternal(raw_ostream &Out, const MDNode *Node, TypePrinter->print(V->getType(), Out); Out << ' '; WriteAsOperandInternal(Out, Node->getOperand(mi), - TypePrinter, Machine); + TypePrinter, Machine, Context); } if (mi + 1 != me) Out << ", "; @@ -1138,7 +1124,8 @@ static void WriteMDNodeBodyInternal(raw_ostream &Out, const MDNode *Node, /// static void WriteAsOperandInternal(raw_ostream &Out, const Value *V, TypePrinting *TypePrinter, - SlotTracker *Machine) { + SlotTracker *Machine, + const Module *Context) { if (V->hasName()) { PrintLLVMName(Out, V); return; @@ -1147,7 +1134,7 @@ static void WriteAsOperandInternal(raw_ostream &Out, const Value *V, const Constant *CV = dyn_cast(V); if (CV && !isa(CV)) { assert(TypePrinter && "Constants require TypePrinting!"); - WriteConstantInternal(Out, CV, *TypePrinter, Machine); + WriteConstantInternal(Out, CV, *TypePrinter, Machine, Context); return; } @@ -1168,12 +1155,16 @@ static void WriteAsOperandInternal(raw_ostream &Out, const Value *V, if (const MDNode *N = dyn_cast(V)) { if (N->isFunctionLocal()) { // Print metadata inline, not via slot reference number. - WriteMDNodeBodyInternal(Out, N, TypePrinter, Machine); + WriteMDNodeBodyInternal(Out, N, TypePrinter, Machine, Context); return; } - if (!Machine) - Machine = createSlotTracker(V); + if (!Machine) { + if (N->isFunctionLocal()) + Machine = new SlotTracker(N->getFunction()); + else + Machine = new SlotTracker(Context); + } Out << '!' << Machine->getMetadataSlot(N); return; } @@ -1227,8 +1218,9 @@ void llvm::WriteAsOperand(raw_ostream &Out, const Value *V, // Fast path: Don't construct and populate a TypePrinting object if we // won't be needing any types printed. if (!PrintType && - (!isa(V) || V->hasName() || isa(V))) { - WriteAsOperandInternal(Out, V, 0, 0); + ((!isa(V) && !isa(V)) || + V->hasName() || isa(V))) { + WriteAsOperandInternal(Out, V, 0, 0, Context); return; } @@ -1242,7 +1234,7 @@ void llvm::WriteAsOperand(raw_ostream &Out, const Value *V, Out << ' '; } - WriteAsOperandInternal(Out, V, &TypePrinter, 0); + WriteAsOperandInternal(Out, V, &TypePrinter, 0, Context); } namespace { @@ -1297,7 +1289,7 @@ void AssemblyWriter::writeOperand(const Value *Operand, bool PrintType) { TypePrinter.print(Operand->getType(), Out); Out << ' '; } - WriteAsOperandInternal(Out, Operand, &TypePrinter, &Machine); + WriteAsOperandInternal(Out, Operand, &TypePrinter, &Machine, TheModule); } void AssemblyWriter::writeParamOperand(const Value *Operand, @@ -1314,7 +1306,7 @@ void AssemblyWriter::writeParamOperand(const Value *Operand, Out << ' ' << Attribute::getAsString(Attrs); Out << ' '; // Print the operand - WriteAsOperandInternal(Out, Operand, &TypePrinter, &Machine); + WriteAsOperandInternal(Out, Operand, &TypePrinter, &Machine, TheModule); } void AssemblyWriter::printModule(const Module *M) { @@ -1403,10 +1395,7 @@ void AssemblyWriter::printNamedMDNode(const NamedMDNode *NMD) { Out << "!" << NMD->getName() << " = !{"; for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { if (i) Out << ", "; - if (MDNode *MD = NMD->getOperand(i)) - Out << '!' << Machine.getMetadataSlot(MD); - else - Out << "null"; + Out << '!' << Machine.getMetadataSlot(NMD->getOperand(i)); } Out << "}\n"; } @@ -1421,6 +1410,9 @@ static void PrintLinkage(GlobalValue::LinkageTypes LT, case GlobalValue::LinkerPrivateWeakLinkage: Out << "linker_private_weak "; break; + case GlobalValue::LinkerPrivateWeakDefAutoLinkage: + Out << "linker_private_weak_def_auto "; + break; case GlobalValue::InternalLinkage: Out << "internal "; break; case GlobalValue::LinkOnceAnyLinkage: Out << "linkonce "; break; case GlobalValue::LinkOnceODRLinkage: Out << "linkonce_odr "; break; @@ -1451,7 +1443,7 @@ void AssemblyWriter::printGlobal(const GlobalVariable *GV) { if (GV->isMaterializable()) Out << "; Materializable\n"; - WriteAsOperandInternal(Out, GV, &TypePrinter, &Machine); + WriteAsOperandInternal(Out, GV, &TypePrinter, &Machine, GV->getParent()); Out << " = "; if (!GV->hasInitializer() && GV->hasExternalLinkage()) @@ -1510,7 +1502,7 @@ void AssemblyWriter::printAlias(const GlobalAlias *GA) { TypePrinter.print(F->getFunctionType(), Out); Out << "* "; - WriteAsOperandInternal(Out, F, &TypePrinter, &Machine); + WriteAsOperandInternal(Out, F, &TypePrinter, &Machine, F->getParent()); } else if (const GlobalAlias *GA = dyn_cast(Aliasee)) { TypePrinter.print(GA->getType(), Out); Out << ' '; @@ -1593,7 +1585,7 @@ void AssemblyWriter::printFunction(const Function *F) { Out << Attribute::getAsString(Attrs.getRetAttributes()) << ' '; TypePrinter.print(F->getReturnType(), Out); Out << ' '; - WriteAsOperandInternal(Out, F, &TypePrinter, &Machine); + WriteAsOperandInternal(Out, F, &TypePrinter, &Machine, F->getParent()); Out << '('; Machine.incorporateFunction(F); @@ -1643,11 +1635,10 @@ void AssemblyWriter::printFunction(const Function *F) { if (F->hasGC()) Out << " gc \"" << F->getGC() << '"'; if (F->isDeclaration()) { - Out << "\n"; + Out << '\n'; } else { Out << " {"; - - // Output all of its basic blocks... for the function + // Output all of the function's basic blocks. for (Function::const_iterator I = F->begin(), E = F->end(); I != E; ++I) printBasicBlock(I); @@ -1696,7 +1687,7 @@ void AssemblyWriter::printBasicBlock(const BasicBlock *BB) { Out.PadToColumn(50); Out << "; Error: Block without parent!"; } else if (BB != &BB->getParent()->getEntryBlock()) { // Not the entry block? - // Output predecessors for the block... + // Output predecessors for the block. Out.PadToColumn(50); Out << ";"; const_pred_iterator PI = pred_begin(BB), PE = pred_end(BB); @@ -1734,13 +1725,6 @@ void AssemblyWriter::printInfoComment(const Value &V) { AnnotationWriter->printInfoComment(V, Out); return; } - - if (V.getType()->isVoidTy()) return; - - Out.PadToColumn(50); - Out << "; <"; - TypePrinter.print(V.getType(), Out); - Out << "> [#uses=" << V.getNumUses() << ']'; // Output # uses } // This member is called for each Instruction in a function.. @@ -2029,7 +2013,9 @@ void AssemblyWriter::printInstruction(const Instruction &I) { } else { Out << ", !"; } - Out << " !" << Machine.getMetadataSlot(InstMD[i].second); + Out << ' '; + WriteAsOperandInternal(Out, InstMD[i].second, &TypePrinter, &Machine, + TheModule); } } printInfoComment(I); @@ -2077,7 +2063,7 @@ void AssemblyWriter::writeAllMDNodes() { } void AssemblyWriter::printMDNodeBody(const MDNode *Node) { - WriteMDNodeBodyInternal(Out, Node, &TypePrinter, &Machine); + WriteMDNodeBodyInternal(Out, Node, &TypePrinter, &Machine, TheModule); WriteMDNodeComment(Node, Out); Out << "\n"; } @@ -2093,6 +2079,13 @@ void Module::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW) const { W.printModule(this); } +void NamedMDNode::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW) const { + SlotTracker SlotTable(getParent()); + formatted_raw_ostream OS(ROS); + AssemblyWriter W(OS, SlotTable, getParent(), AAW); + W.printNamedMDNode(this); +} + void Type::print(raw_ostream &OS) const { if (this == 0) { OS << ""; @@ -2130,15 +2123,11 @@ void Value::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW) const { SlotTracker SlotTable(F); AssemblyWriter W(OS, SlotTable, F ? F->getParent() : 0, AAW); W.printMDNodeBody(N); - } else if (const NamedMDNode *N = dyn_cast(this)) { - SlotTracker SlotTable(N->getParent()); - AssemblyWriter W(OS, SlotTable, N->getParent(), AAW); - W.printNamedMDNode(N); } else if (const Constant *C = dyn_cast(this)) { TypePrinting TypePrinter; TypePrinter.print(C->getType(), OS); OS << ' '; - WriteConstantInternal(OS, C, TypePrinter, 0); + WriteConstantInternal(OS, C, TypePrinter, 0, 0); } else if (isa(this) || isa(this) || isa(this)) { WriteAsOperand(OS, this, true, 0); diff --git a/lib/VMCore/AutoUpgrade.cpp b/lib/VMCore/AutoUpgrade.cpp index dc39024..9330e14 100644 --- a/lib/VMCore/AutoUpgrade.cpp +++ b/lib/VMCore/AutoUpgrade.cpp @@ -78,6 +78,63 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) { NewFn = F; return true; } + } else if (Name.compare(5, 9, "arm.neon.", 9) == 0) { + if (((Name.compare(14, 5, "vmovl", 5) == 0 || + Name.compare(14, 5, "vaddl", 5) == 0 || + Name.compare(14, 5, "vsubl", 5) == 0 || + Name.compare(14, 5, "vaddw", 5) == 0 || + Name.compare(14, 5, "vsubw", 5) == 0 || + Name.compare(14, 5, "vmull", 5) == 0 || + Name.compare(14, 5, "vmlal", 5) == 0 || + Name.compare(14, 5, "vmlsl", 5) == 0 || + Name.compare(14, 5, "vabdl", 5) == 0 || + Name.compare(14, 5, "vabal", 5) == 0) && + (Name.compare(19, 2, "s.", 2) == 0 || + Name.compare(19, 2, "u.", 2) == 0)) || + + (Name.compare(14, 4, "vaba", 4) == 0 && + (Name.compare(18, 2, "s.", 2) == 0 || + Name.compare(18, 2, "u.", 2) == 0)) || + + (Name.compare(14, 6, "vmovn.", 6) == 0)) { + + // Calls to these are transformed into IR without intrinsics. + NewFn = 0; + return true; + } + // Old versions of NEON ld/st intrinsics are missing alignment arguments. + bool isVLd = (Name.compare(14, 3, "vld", 3) == 0); + bool isVSt = (Name.compare(14, 3, "vst", 3) == 0); + if (isVLd || isVSt) { + unsigned NumVecs = Name.at(17) - '0'; + if (NumVecs == 0 || NumVecs > 4) + return false; + bool isLaneOp = (Name.compare(18, 5, "lane.", 5) == 0); + if (!isLaneOp && Name.at(18) != '.') + return false; + unsigned ExpectedArgs = 2; // for the address and alignment + if (isVSt || isLaneOp) + ExpectedArgs += NumVecs; + if (isLaneOp) + ExpectedArgs += 1; // for the lane number + unsigned NumP = FTy->getNumParams(); + if (NumP != ExpectedArgs - 1) + return false; + + // Change the name of the old (bad) intrinsic, because + // its type is incorrect, but we cannot overload that name. + F->setName(""); + + // One argument is missing: add the alignment argument. + std::vector NewParams; + for (unsigned p = 0; p < NumP; ++p) + NewParams.push_back(FTy->getParamType(p)); + NewParams.push_back(Type::getInt32Ty(F->getContext())); + FunctionType *NewFTy = FunctionType::get(FTy->getReturnType(), + NewParams, false); + NewFn = cast(M->getOrInsertFunction(Name, NewFTy)); + return true; + } } break; case 'b': @@ -182,7 +239,6 @@ static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) { NewFnName = "llvm.memset.p0i8.i64"; } if (NewFnName) { - const FunctionType *FTy = F->getFunctionType(); NewFn = cast(M->getOrInsertFunction(NewFnName, FTy->getReturnType(), FTy->getParamType(0), @@ -309,6 +365,73 @@ bool llvm::UpgradeIntrinsicFunction(Function *F, Function *&NewFn) { return Upgraded; } +bool llvm::UpgradeGlobalVariable(GlobalVariable *GV) { + StringRef Name(GV->getName()); + + // We are only upgrading one symbol here. + if (Name == ".llvm.eh.catch.all.value") { + GV->setName("llvm.eh.catch.all.value"); + return true; + } + + return false; +} + +/// ExtendNEONArgs - For NEON "long" and "wide" operations, where the results +/// have vector elements twice as big as one or both source operands, do the +/// sign- or zero-extension that used to be handled by intrinsics. The +/// extended values are returned via V0 and V1. +static void ExtendNEONArgs(CallInst *CI, Value *Arg0, Value *Arg1, + Value *&V0, Value *&V1) { + Function *F = CI->getCalledFunction(); + const std::string& Name = F->getName(); + bool isLong = (Name.at(18) == 'l'); + bool isSigned = (Name.at(19) == 's'); + + if (isSigned) { + if (isLong) + V0 = new SExtInst(Arg0, CI->getType(), "", CI); + else + V0 = Arg0; + V1 = new SExtInst(Arg1, CI->getType(), "", CI); + } else { + if (isLong) + V0 = new ZExtInst(Arg0, CI->getType(), "", CI); + else + V0 = Arg0; + V1 = new ZExtInst(Arg1, CI->getType(), "", CI); + } +} + +/// CallVABD - As part of expanding a call to one of the old NEON vabdl, vaba, +/// or vabal intrinsics, construct a call to a vabd intrinsic. Examine the +/// name of the old intrinsic to determine whether to use a signed or unsigned +/// vabd intrinsic. Get the type from the old call instruction, adjusted for +/// half-size vector elements if the old intrinsic was vabdl or vabal. +static Instruction *CallVABD(CallInst *CI, Value *Arg0, Value *Arg1) { + Function *F = CI->getCalledFunction(); + const std::string& Name = F->getName(); + bool isLong = (Name.at(18) == 'l'); + bool isSigned = (Name.at(isLong ? 19 : 18) == 's'); + + Intrinsic::ID intID; + if (isSigned) + intID = Intrinsic::arm_neon_vabds; + else + intID = Intrinsic::arm_neon_vabdu; + + const Type *Ty = CI->getType(); + if (isLong) + Ty = VectorType::getTruncatedElementVectorType(cast(Ty)); + + Function *VABD = Intrinsic::getDeclaration(F->getParent(), intID, &Ty, 1); + Value *Operands[2]; + Operands[0] = Arg0; + Operands[1] = Arg1; + return CallInst::Create(VABD, Operands, Operands+2, + "upgraded."+CI->getName(), CI); +} + // UpgradeIntrinsicCall - Upgrade a call to an old intrinsic to be a call the // upgraded intrinsic. All argument and return casting must be provided in // order to seamlessly integrate with existing context. @@ -320,6 +443,60 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { assert(F && "CallInst has no function associated with it."); if (!NewFn) { + // Get the Function's name. + const std::string& Name = F->getName(); + + // Upgrade ARM NEON intrinsics. + if (Name.compare(5, 9, "arm.neon.", 9) == 0) { + Instruction *NewI; + Value *V0, *V1; + if (Name.compare(14, 7, "vmovls.", 7) == 0) { + NewI = new SExtInst(CI->getArgOperand(0), CI->getType(), + "upgraded." + CI->getName(), CI); + } else if (Name.compare(14, 7, "vmovlu.", 7) == 0) { + NewI = new ZExtInst(CI->getArgOperand(0), CI->getType(), + "upgraded." + CI->getName(), CI); + } else if (Name.compare(14, 4, "vadd", 4) == 0) { + ExtendNEONArgs(CI, CI->getArgOperand(0), CI->getArgOperand(1), V0, V1); + NewI = BinaryOperator::CreateAdd(V0, V1, "upgraded."+CI->getName(), CI); + } else if (Name.compare(14, 4, "vsub", 4) == 0) { + ExtendNEONArgs(CI, CI->getArgOperand(0), CI->getArgOperand(1), V0, V1); + NewI = BinaryOperator::CreateSub(V0, V1,"upgraded."+CI->getName(),CI); + } else if (Name.compare(14, 4, "vmul", 4) == 0) { + ExtendNEONArgs(CI, CI->getArgOperand(0), CI->getArgOperand(1), V0, V1); + NewI = BinaryOperator::CreateMul(V0, V1,"upgraded."+CI->getName(),CI); + } else if (Name.compare(14, 4, "vmla", 4) == 0) { + ExtendNEONArgs(CI, CI->getArgOperand(1), CI->getArgOperand(2), V0, V1); + Instruction *MulI = BinaryOperator::CreateMul(V0, V1, "", CI); + NewI = BinaryOperator::CreateAdd(CI->getArgOperand(0), MulI, + "upgraded."+CI->getName(), CI); + } else if (Name.compare(14, 4, "vmls", 4) == 0) { + ExtendNEONArgs(CI, CI->getArgOperand(1), CI->getArgOperand(2), V0, V1); + Instruction *MulI = BinaryOperator::CreateMul(V0, V1, "", CI); + NewI = BinaryOperator::CreateSub(CI->getArgOperand(0), MulI, + "upgraded."+CI->getName(), CI); + } else if (Name.compare(14, 4, "vabd", 4) == 0) { + NewI = CallVABD(CI, CI->getArgOperand(0), CI->getArgOperand(1)); + NewI = new ZExtInst(NewI, CI->getType(), "upgraded."+CI->getName(), CI); + } else if (Name.compare(14, 4, "vaba", 4) == 0) { + NewI = CallVABD(CI, CI->getArgOperand(1), CI->getArgOperand(2)); + if (Name.at(18) == 'l') + NewI = new ZExtInst(NewI, CI->getType(), "", CI); + NewI = BinaryOperator::CreateAdd(CI->getArgOperand(0), NewI, + "upgraded."+CI->getName(), CI); + } else if (Name.compare(14, 6, "vmovn.", 6) == 0) { + NewI = new TruncInst(CI->getArgOperand(0), CI->getType(), + "upgraded." + CI->getName(), CI); + } else { + llvm_unreachable("Unknown arm.neon function for CallInst upgrade."); + } + // Replace any uses of the old CallInst. + if (!CI->use_empty()) + CI->replaceAllUsesWith(NewI); + CI->eraseFromParent(); + return; + } + bool isLoadH = false, isLoadL = false, isMovL = false; bool isMovSD = false, isShufPD = false; bool isUnpckhPD = false, isUnpcklPD = false; @@ -398,7 +575,8 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { SI = new ShuffleVectorInst(Op0, Op1, Mask, "upgraded.", CI); } else if (isShufPD) { Value *Op1 = CI->getArgOperand(1); - unsigned MaskVal = cast(CI->getArgOperand(2))->getZExtValue(); + unsigned MaskVal = + cast(CI->getArgOperand(2))->getZExtValue(); Idxs.push_back(ConstantInt::get(Type::getInt32Ty(C), MaskVal & 1)); Idxs.push_back(ConstantInt::get(Type::getInt32Ty(C), ((MaskVal >> 1) & 1)+2)); @@ -547,7 +725,40 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { } switch (NewFn->getIntrinsicID()) { - default: llvm_unreachable("Unknown function for CallInst upgrade."); + default: llvm_unreachable("Unknown function for CallInst upgrade."); + case Intrinsic::arm_neon_vld1: + case Intrinsic::arm_neon_vld2: + case Intrinsic::arm_neon_vld3: + case Intrinsic::arm_neon_vld4: + case Intrinsic::arm_neon_vst1: + case Intrinsic::arm_neon_vst2: + case Intrinsic::arm_neon_vst3: + case Intrinsic::arm_neon_vst4: + case Intrinsic::arm_neon_vld2lane: + case Intrinsic::arm_neon_vld3lane: + case Intrinsic::arm_neon_vld4lane: + case Intrinsic::arm_neon_vst2lane: + case Intrinsic::arm_neon_vst3lane: + case Intrinsic::arm_neon_vst4lane: { + // Add a default alignment argument of 1. + SmallVector Operands(CS.arg_begin(), CS.arg_end()); + Operands.push_back(ConstantInt::get(Type::getInt32Ty(C), 1)); + CallInst *NewCI = CallInst::Create(NewFn, Operands.begin(), Operands.end(), + CI->getName(), CI); + NewCI->setTailCall(CI->isTailCall()); + NewCI->setCallingConv(CI->getCallingConv()); + + // Handle any uses of the old CallInst. + if (!CI->use_empty()) + // Replace all uses of the old call with the new cast which has the + // correct type. + CI->replaceAllUsesWith(NewCI); + + // Clean up the old call now that it has been completely upgraded. + CI->eraseFromParent(); + break; + } + case Intrinsic::x86_mmx_psll_d: case Intrinsic::x86_mmx_psll_q: case Intrinsic::x86_mmx_psll_w: diff --git a/lib/VMCore/CMakeLists.txt b/lib/VMCore/CMakeLists.txt index c64564b..1388c93 100644 --- a/lib/VMCore/CMakeLists.txt +++ b/lib/VMCore/CMakeLists.txt @@ -23,6 +23,7 @@ add_llvm_library(LLVMCore Module.cpp Pass.cpp PassManager.cpp + PassRegistry.cpp PrintModulePass.cpp Type.cpp TypeSymbolTable.cpp diff --git a/lib/VMCore/ConstantFold.cpp b/lib/VMCore/ConstantFold.cpp index 3567266..9a91daf 100644 --- a/lib/VMCore/ConstantFold.cpp +++ b/lib/VMCore/ConstantFold.cpp @@ -357,22 +357,6 @@ static Constant *getFoldedSizeOf(const Type *Ty, const Type *DestTy, } } - if (const UnionType *UTy = dyn_cast(Ty)) { - unsigned NumElems = UTy->getNumElements(); - // Check for a union with all members having the same size. - Constant *MemberSize = - getFoldedSizeOf(UTy->getElementType(0), DestTy, true); - bool AllSame = true; - for (unsigned i = 1; i != NumElems; ++i) - if (MemberSize != - getFoldedSizeOf(UTy->getElementType(i), DestTy, true)) { - AllSame = false; - break; - } - if (AllSame) - return MemberSize; - } - // Pointer size doesn't depend on the pointee type, so canonicalize them // to an arbitrary pointee. if (const PointerType *PTy = dyn_cast(Ty)) @@ -438,24 +422,6 @@ static Constant *getFoldedAlignOf(const Type *Ty, const Type *DestTy, return MemberAlign; } - if (const UnionType *UTy = dyn_cast(Ty)) { - // Union alignment is the maximum alignment of any member. - // Without target data, we can't compare much, but we can check to see - // if all the members have the same alignment. - unsigned NumElems = UTy->getNumElements(); - // Check for a union with all members having the same alignment. - Constant *MemberAlign = - getFoldedAlignOf(UTy->getElementType(0), DestTy, true); - bool AllSame = true; - for (unsigned i = 1; i != NumElems; ++i) - if (MemberAlign != getFoldedAlignOf(UTy->getElementType(i), DestTy, true)) { - AllSame = false; - break; - } - if (AllSame) - return MemberAlign; - } - // Pointer alignment doesn't depend on the pointee type, so canonicalize them // to an arbitrary pointee. if (const PointerType *PTy = dyn_cast(Ty)) @@ -909,8 +875,6 @@ Constant *llvm::ConstantFoldInsertValueInstruction(Constant *Agg, unsigned numOps; if (const ArrayType *AR = dyn_cast(AggTy)) numOps = AR->getNumElements(); - else if (AggTy->isUnionTy()) - numOps = 1; else numOps = cast(AggTy)->getNumElements(); @@ -927,10 +891,6 @@ Constant *llvm::ConstantFoldInsertValueInstruction(Constant *Agg, if (const StructType* ST = dyn_cast(AggTy)) return ConstantStruct::get(ST->getContext(), Ops, ST->isPacked()); - if (const UnionType* UT = dyn_cast(AggTy)) { - assert(Ops.size() == 1 && "Union can only contain a single value!"); - return ConstantUnion::get(UT, Ops[0]); - } return ConstantArray::get(cast(AggTy), Ops); } diff --git a/lib/VMCore/Constants.cpp b/lib/VMCore/Constants.cpp index 00b0094..16eaca8 100644 --- a/lib/VMCore/Constants.cpp +++ b/lib/VMCore/Constants.cpp @@ -59,7 +59,6 @@ Constant *Constant::getNullValue(const Type *Ty) { case Type::PointerTyID: return ConstantPointerNull::get(cast(Ty)); case Type::StructTyID: - case Type::UnionTyID: case Type::ArrayTyID: case Type::VectorTyID: return ConstantAggregateZero::get(Ty); @@ -526,6 +525,7 @@ Constant* ConstantArray::get(const ArrayType* T, Constant* const* Vals, Constant* ConstantArray::get(LLVMContext &Context, StringRef Str, bool AddNull) { std::vector ElementVals; + ElementVals.reserve(Str.size() + size_t(AddNull)); for (unsigned i = 0; i < Str.size(); ++i) ElementVals.push_back(ConstantInt::get(Type::getInt8Ty(Context), Str[i])); @@ -586,27 +586,6 @@ Constant* ConstantStruct::get(LLVMContext &Context, return get(Context, std::vector(Vals, Vals+NumVals), Packed); } -ConstantUnion::ConstantUnion(const UnionType *T, Constant* V) - : Constant(T, ConstantUnionVal, - OperandTraits::op_end(this) - 1, 1) { - Use *OL = OperandList; - assert(T->getElementTypeIndex(V->getType()) >= 0 && - "Initializer for union element isn't a member of union type!"); - *OL = V; -} - -// ConstantUnion accessors. -Constant* ConstantUnion::get(const UnionType* T, Constant* V) { - LLVMContextImpl* pImpl = T->getContext().pImpl; - - // Create a ConstantAggregateZero value if all elements are zeros... - if (!V->isNullValue()) - return pImpl->UnionConstants.getOrCreate(T, V); - - return ConstantAggregateZero::get(T); -} - - ConstantVector::ConstantVector(const VectorType *T, const std::vector &V) : Constant(T, ConstantVectorVal, @@ -723,7 +702,7 @@ bool ConstantExpr::isGEPWithNoNotionalOverIndexing() const { if (getOpcode() != Instruction::GetElementPtr) return false; gep_type_iterator GEPI = gep_type_begin(this), E = gep_type_end(this); - User::const_op_iterator OI = next(this->op_begin()); + User::const_op_iterator OI = llvm::next(this->op_begin()); // Skip the first index, as it has no static limit. ++GEPI; @@ -945,8 +924,7 @@ bool ConstantFP::isValueValidForType(const Type *Ty, const APFloat& Val) { // Factory Function Implementation ConstantAggregateZero* ConstantAggregateZero::get(const Type* Ty) { - assert((Ty->isStructTy() || Ty->isUnionTy() - || Ty->isArrayTy() || Ty->isVectorTy()) && + assert((Ty->isStructTy() || Ty->isArrayTy() || Ty->isVectorTy()) && "Cannot create an aggregate zero of non-aggregate type!"); LLVMContextImpl *pImpl = Ty->getContext().pImpl; @@ -956,14 +934,14 @@ ConstantAggregateZero* ConstantAggregateZero::get(const Type* Ty) { /// destroyConstant - Remove the constant from the constant table... /// void ConstantAggregateZero::destroyConstant() { - getType()->getContext().pImpl->AggZeroConstants.remove(this); + getRawType()->getContext().pImpl->AggZeroConstants.remove(this); destroyConstantImpl(); } /// destroyConstant - Remove the constant from the constant table... /// void ConstantArray::destroyConstant() { - getType()->getContext().pImpl->ArrayConstants.remove(this); + getRawType()->getContext().pImpl->ArrayConstants.remove(this); destroyConstantImpl(); } @@ -1027,21 +1005,14 @@ namespace llvm { // destroyConstant - Remove the constant from the constant table... // void ConstantStruct::destroyConstant() { - getType()->getContext().pImpl->StructConstants.remove(this); - destroyConstantImpl(); -} - -// destroyConstant - Remove the constant from the constant table... -// -void ConstantUnion::destroyConstant() { - getType()->getContext().pImpl->UnionConstants.remove(this); + getRawType()->getContext().pImpl->StructConstants.remove(this); destroyConstantImpl(); } // destroyConstant - Remove the constant from the constant table... // void ConstantVector::destroyConstant() { - getType()->getContext().pImpl->VectorConstants.remove(this); + getRawType()->getContext().pImpl->VectorConstants.remove(this); destroyConstantImpl(); } @@ -1082,7 +1053,7 @@ ConstantPointerNull *ConstantPointerNull::get(const PointerType *Ty) { // destroyConstant - Remove the constant from the constant table... // void ConstantPointerNull::destroyConstant() { - getType()->getContext().pImpl->NullPtrConstants.remove(this); + getRawType()->getContext().pImpl->NullPtrConstants.remove(this); destroyConstantImpl(); } @@ -1097,7 +1068,7 @@ UndefValue *UndefValue::get(const Type *Ty) { // destroyConstant - Remove the constant from the constant table. // void UndefValue::destroyConstant() { - getType()->getContext().pImpl->UndefValueConstants.remove(this); + getRawType()->getContext().pImpl->UndefValueConstants.remove(this); destroyConstantImpl(); } @@ -1131,7 +1102,7 @@ BlockAddress::BlockAddress(Function *F, BasicBlock *BB) // destroyConstant - Remove the constant from the constant table. // void BlockAddress::destroyConstant() { - getFunction()->getType()->getContext().pImpl + getFunction()->getRawType()->getContext().pImpl ->BlockAddresses.erase(std::make_pair(getFunction(), getBasicBlock())); getBasicBlock()->AdjustBlockAddressRefCount(-1); destroyConstantImpl(); @@ -1930,7 +1901,7 @@ Constant* ConstantExpr::getAShr(Constant* C1, Constant* C2) { // destroyConstant - Remove the constant from the constant table... // void ConstantExpr::destroyConstant() { - getType()->getContext().pImpl->ExprConstants.remove(this); + getRawType()->getContext().pImpl->ExprConstants.remove(this); destroyConstantImpl(); } @@ -1971,11 +1942,10 @@ void ConstantArray::replaceUsesOfWithOnConstant(Value *From, Value *To, assert(isa(To) && "Cannot make Constant refer to non-constant!"); Constant *ToC = cast(To); - LLVMContext &Context = getType()->getContext(); - LLVMContextImpl *pImpl = Context.pImpl; + LLVMContextImpl *pImpl = getRawType()->getContext().pImpl; std::pair Lookup; - Lookup.first.first = getType(); + Lookup.first.first = cast(getRawType()); Lookup.second = this; std::vector &Values = Lookup.first.second; @@ -2009,7 +1979,7 @@ void ConstantArray::replaceUsesOfWithOnConstant(Value *From, Value *To, Constant *Replacement = 0; if (isAllZeros) { - Replacement = ConstantAggregateZero::get(getType()); + Replacement = ConstantAggregateZero::get(getRawType()); } else { // Check to see if we have this array type already. bool Exists; @@ -2060,7 +2030,7 @@ void ConstantStruct::replaceUsesOfWithOnConstant(Value *From, Value *To, assert(getOperand(OperandToUpdate) == From && "ReplaceAllUsesWith broken!"); std::pair Lookup; - Lookup.first.first = getType(); + Lookup.first.first = cast(getRawType()); Lookup.second = this; std::vector &Values = Lookup.first.second; Values.reserve(getNumOperands()); // Build replacement struct. @@ -2082,14 +2052,13 @@ void ConstantStruct::replaceUsesOfWithOnConstant(Value *From, Value *To, } Values[OperandToUpdate] = ToC; - LLVMContext &Context = getType()->getContext(); - LLVMContextImpl *pImpl = Context.pImpl; + LLVMContextImpl *pImpl = getRawType()->getContext().pImpl; Constant *Replacement = 0; if (isAllZeros) { - Replacement = ConstantAggregateZero::get(getType()); + Replacement = ConstantAggregateZero::get(getRawType()); } else { - // Check to see if we have this array type already. + // Check to see if we have this struct type already. bool Exists; LLVMContextImpl::StructConstantsTy::MapTy::iterator I = pImpl->StructConstants.InsertOrGetItem(Lookup, Exists); @@ -2118,56 +2087,6 @@ void ConstantStruct::replaceUsesOfWithOnConstant(Value *From, Value *To, destroyConstant(); } -void ConstantUnion::replaceUsesOfWithOnConstant(Value *From, Value *To, - Use *U) { - assert(isa(To) && "Cannot make Constant refer to non-constant!"); - Constant *ToC = cast(To); - - assert(U == OperandList && "Union constants can only have one use!"); - assert(getNumOperands() == 1 && "Union constants can only have one use!"); - assert(getOperand(0) == From && "ReplaceAllUsesWith broken!"); - - std::pair Lookup; - Lookup.first.first = getType(); - Lookup.second = this; - Lookup.first.second = ToC; - - LLVMContext &Context = getType()->getContext(); - LLVMContextImpl *pImpl = Context.pImpl; - - Constant *Replacement = 0; - if (ToC->isNullValue()) { - Replacement = ConstantAggregateZero::get(getType()); - } else { - // Check to see if we have this union type already. - bool Exists; - LLVMContextImpl::UnionConstantsTy::MapTy::iterator I = - pImpl->UnionConstants.InsertOrGetItem(Lookup, Exists); - - if (Exists) { - Replacement = I->second; - } else { - // Okay, the new shape doesn't exist in the system yet. Instead of - // creating a new constant union, inserting it, replaceallusesof'ing the - // old with the new, then deleting the old... just update the current one - // in place! - pImpl->UnionConstants.MoveConstantToNewSlot(this, I); - - // Update to the new value. - setOperand(0, ToC); - return; - } - } - - assert(Replacement != this && "I didn't contain From!"); - - // Everyone using this now uses the replacement. - uncheckedReplaceAllUsesWith(Replacement); - - // Delete the old constant! - destroyConstant(); -} - void ConstantVector::replaceUsesOfWithOnConstant(Value *From, Value *To, Use *U) { assert(isa(To) && "Cannot make Constant refer to non-constant!"); @@ -2180,7 +2099,7 @@ void ConstantVector::replaceUsesOfWithOnConstant(Value *From, Value *To, Values.push_back(Val); } - Constant *Replacement = get(getType(), Values); + Constant *Replacement = get(cast(getRawType()), Values); assert(Replacement != this && "I didn't contain From!"); // Everyone using this now uses the replacement. @@ -2227,7 +2146,7 @@ void ConstantExpr::replaceUsesOfWithOnConstant(Value *From, Value *ToV, &Indices[0], Indices.size()); } else if (isCast()) { assert(getOperand(0) == From && "Cast only has one use!"); - Replacement = ConstantExpr::getCast(getOpcode(), To, getType()); + Replacement = ConstantExpr::getCast(getOpcode(), To, getRawType()); } else if (getOpcode() == Instruction::Select) { Constant *C1 = getOperand(0); Constant *C2 = getOperand(1); diff --git a/lib/VMCore/ConstantsContext.h b/lib/VMCore/ConstantsContext.h index 2f2fac5..1c04c3e 100644 --- a/lib/VMCore/ConstantsContext.h +++ b/lib/VMCore/ConstantsContext.h @@ -511,14 +511,6 @@ struct ConstantKeyData { } }; -template<> -struct ConstantKeyData { - typedef Constant* ValType; - static ValType getValType(ConstantUnion *CU) { - return cast(CU->getOperand(0)); - } -}; - // ConstantPointerNull does not take extra "value" argument... template struct ConstantCreator { @@ -757,9 +749,13 @@ public: // If this constant is the representative element for its abstract type, // update the AbstractTypeMap so that the representative element is I. - if (C->getType()->isAbstract()) { + // + // This must use getRawType() because if the type is under refinement, we + // will get the refineAbstractType callback below, and we don't want to + // kick union find in on the constant. + if (C->getRawType()->isAbstract()) { typename AbstractTypeMapTy::iterator ATI = - AbstractTypeMap.find(C->getType()); + AbstractTypeMap.find(cast(C->getRawType())); assert(ATI != AbstractTypeMap.end() && "Abstract type not in AbstractTypeMap?"); if (ATI->second == OldI) diff --git a/lib/VMCore/Core.cpp b/lib/VMCore/Core.cpp index ca1a399..5aad19d 100644 --- a/lib/VMCore/Core.cpp +++ b/lib/VMCore/Core.cpp @@ -22,6 +22,7 @@ #include "llvm/TypeSymbolTable.h" #include "llvm/InlineAsm.h" #include "llvm/IntrinsicInst.h" +#include "llvm/PassManager.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -155,8 +156,6 @@ LLVMTypeKind LLVMGetTypeKind(LLVMTypeRef Ty) { return LLVMFunctionTypeKind; case Type::StructTyID: return LLVMStructTypeKind; - case Type::UnionTyID: - return LLVMUnionTypeKind; case Type::ArrayTyID: return LLVMArrayTypeKind; case Type::PointerTyID: @@ -315,34 +314,6 @@ LLVMBool LLVMIsPackedStruct(LLVMTypeRef StructTy) { return unwrap(StructTy)->isPacked(); } -/*--.. Operations on union types ..........................................--*/ - -LLVMTypeRef LLVMUnionTypeInContext(LLVMContextRef C, LLVMTypeRef *ElementTypes, - unsigned ElementCount) { - SmallVector Tys; - for (LLVMTypeRef *I = ElementTypes, - *E = ElementTypes + ElementCount; I != E; ++I) - Tys.push_back(unwrap(*I)); - - return wrap(UnionType::get(&Tys[0], Tys.size())); -} - -LLVMTypeRef LLVMUnionType(LLVMTypeRef *ElementTypes, unsigned ElementCount) { - return LLVMUnionTypeInContext(LLVMGetGlobalContext(), ElementTypes, - ElementCount); -} - -unsigned LLVMCountUnionElementTypes(LLVMTypeRef UnionTy) { - return unwrap(UnionTy)->getNumElements(); -} - -void LLVMGetUnionElementTypes(LLVMTypeRef UnionTy, LLVMTypeRef *Dest) { - UnionType *Ty = unwrap(UnionTy); - for (FunctionType::param_iterator I = Ty->element_begin(), - E = Ty->element_end(); I != E; ++I) - *Dest++ = wrap(*I); -} - /*--.. Operations on array, pointer, and vector types (sequence types) .....--*/ LLVMTypeRef LLVMArrayType(LLVMTypeRef ElementType, unsigned ElementCount) { @@ -488,6 +459,14 @@ LLVMValueRef LLVMGetOperand(LLVMValueRef Val, unsigned Index) { return wrap(unwrap(Val)->getOperand(Index)); } +void LLVMSetOperand(LLVMValueRef Val, unsigned Index, LLVMValueRef Op) { + unwrap(Val)->setOperand(Index, unwrap(Op)); +} + +int LLVMGetNumOperands(LLVMValueRef Val) { + return unwrap(Val)->getNumOperands(); +} + /*--.. Operations on constants of any type .................................--*/ LLVMValueRef LLVMConstNull(LLVMTypeRef Ty) { @@ -619,10 +598,6 @@ LLVMValueRef LLVMConstVector(LLVMValueRef *ScalarConstantVals, unsigned Size) { return wrap(ConstantVector::get( unwrap(ScalarConstantVals, Size), Size)); } -LLVMValueRef LLVMConstUnion(LLVMTypeRef Ty, LLVMValueRef Val) { - return wrap(ConstantUnion::get(unwrap(Ty), unwrap(Val))); -} - /*--.. Constant expressions ................................................--*/ LLVMOpcode LLVMGetConstOpcode(LLVMValueRef ConstantVal) { @@ -1060,6 +1035,8 @@ LLVMLinkage LLVMGetLinkage(LLVMValueRef Global) { return LLVMLinkerPrivateLinkage; case GlobalValue::LinkerPrivateWeakLinkage: return LLVMLinkerPrivateWeakLinkage; + case GlobalValue::LinkerPrivateWeakDefAutoLinkage: + return LLVMLinkerPrivateWeakDefAutoLinkage; case GlobalValue::DLLImportLinkage: return LLVMDLLImportLinkage; case GlobalValue::DLLExportLinkage: @@ -1113,6 +1090,9 @@ void LLVMSetLinkage(LLVMValueRef Global, LLVMLinkage Linkage) { case LLVMLinkerPrivateWeakLinkage: GV->setLinkage(GlobalValue::LinkerPrivateWeakLinkage); break; + case LLVMLinkerPrivateWeakDefAutoLinkage: + GV->setLinkage(GlobalValue::LinkerPrivateWeakDefAutoLinkage); + break; case LLVMDLLImportLinkage: GV->setLinkage(GlobalValue::DLLImportLinkage); break; @@ -1515,6 +1495,14 @@ void LLVMDeleteBasicBlock(LLVMBasicBlockRef BBRef) { unwrap(BBRef)->eraseFromParent(); } +void LLVMMoveBasicBlockBefore(LLVMBasicBlockRef BB, LLVMBasicBlockRef MovePos) { + unwrap(BB)->moveBefore(unwrap(MovePos)); +} + +void LLVMMoveBasicBlockAfter(LLVMBasicBlockRef BB, LLVMBasicBlockRef MovePos) { + unwrap(BB)->moveAfter(unwrap(MovePos)); +} + /*--.. Operations on instructions ..........................................--*/ LLVMBasicBlockRef LLVMGetInstructionParent(LLVMValueRef Inst) { @@ -2223,3 +2211,39 @@ LLVMBool LLVMCreateMemoryBufferWithSTDIN(LLVMMemoryBufferRef *OutMemBuf, void LLVMDisposeMemoryBuffer(LLVMMemoryBufferRef MemBuf) { delete unwrap(MemBuf); } + + +/*===-- Pass Manager ------------------------------------------------------===*/ + +LLVMPassManagerRef LLVMCreatePassManager() { + return wrap(new PassManager()); +} + +LLVMPassManagerRef LLVMCreateFunctionPassManagerForModule(LLVMModuleRef M) { + return wrap(new FunctionPassManager(unwrap(M))); +} + +LLVMPassManagerRef LLVMCreateFunctionPassManager(LLVMModuleProviderRef P) { + return LLVMCreateFunctionPassManagerForModule( + reinterpret_cast(P)); +} + +LLVMBool LLVMRunPassManager(LLVMPassManagerRef PM, LLVMModuleRef M) { + return unwrap(PM)->run(*unwrap(M)); +} + +LLVMBool LLVMInitializeFunctionPassManager(LLVMPassManagerRef FPM) { + return unwrap(FPM)->doInitialization(); +} + +LLVMBool LLVMRunFunctionPassManager(LLVMPassManagerRef FPM, LLVMValueRef F) { + return unwrap(FPM)->run(*unwrap(F)); +} + +LLVMBool LLVMFinalizeFunctionPassManager(LLVMPassManagerRef FPM) { + return unwrap(FPM)->doFinalization(); +} + +void LLVMDisposePassManager(LLVMPassManagerRef PM) { + delete unwrap(PM); +} diff --git a/lib/VMCore/Dominators.cpp b/lib/VMCore/Dominators.cpp index 10a866f..f3dad82 100644 --- a/lib/VMCore/Dominators.cpp +++ b/lib/VMCore/Dominators.cpp @@ -17,6 +17,7 @@ #include "llvm/Analysis/Dominators.h" #include "llvm/Support/CFG.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/SetOperations.h" #include "llvm/ADT/SmallPtrSet.h" @@ -51,8 +52,8 @@ TEMPLATE_INSTANTIATION(class llvm::DomTreeNodeBase); TEMPLATE_INSTANTIATION(class llvm::DominatorTreeBase); char DominatorTree::ID = 0; -static RegisterPass -E("domtree", "Dominator Tree Construction", true, true); +INITIALIZE_PASS(DominatorTree, "domtree", + "Dominator Tree Construction", true, true); bool DominatorTree::runOnFunction(Function &F) { DT->recalculate(F); @@ -105,8 +106,8 @@ bool DominatorTree::dominates(const Instruction *A, const Instruction *B) const{ //===----------------------------------------------------------------------===// char DominanceFrontier::ID = 0; -static RegisterPass -G("domfrontier", "Dominance Frontier Construction", true, true); +INITIALIZE_PASS(DominanceFrontier, "domfrontier", + "Dominance Frontier Construction", true, true); void DominanceFrontier::verifyAnalysis() const { if (!VerifyDomInfo) return; @@ -122,36 +123,23 @@ void DominanceFrontier::verifyAnalysis() const { // NewBB is split and now it has one successor. Update dominance frontier to // reflect this change. void DominanceFrontier::splitBlock(BasicBlock *NewBB) { - assert(NewBB->getTerminator()->getNumSuccessors() == 1 - && "NewBB should have a single successor!"); + assert(NewBB->getTerminator()->getNumSuccessors() == 1 && + "NewBB should have a single successor!"); BasicBlock *NewBBSucc = NewBB->getTerminator()->getSuccessor(0); - SmallVector PredBlocks; - for (pred_iterator PI = pred_begin(NewBB), PE = pred_end(NewBB); - PI != PE; ++PI) - PredBlocks.push_back(*PI); - - if (PredBlocks.empty()) - // If NewBB does not have any predecessors then it is a entry block. - // In this case, NewBB and its successor NewBBSucc dominates all - // other blocks. - return; - // NewBBSucc inherits original NewBB frontier. DominanceFrontier::iterator NewBBI = find(NewBB); - if (NewBBI != end()) { - DominanceFrontier::DomSetType NewBBSet = NewBBI->second; - DominanceFrontier::DomSetType NewBBSuccSet; - NewBBSuccSet.insert(NewBBSet.begin(), NewBBSet.end()); - addBasicBlock(NewBBSucc, NewBBSuccSet); - } + if (NewBBI != end()) + addBasicBlock(NewBBSucc, NewBBI->second); // If NewBB dominates NewBBSucc, then DF(NewBB) is now going to be the - // DF(PredBlocks[0]) without the stuff that the new block does not dominate + // DF(NewBBSucc) without the stuff that the new block does not dominate // a predecessor of. DominatorTree &DT = getAnalysis(); - if (DT.dominates(NewBB, NewBBSucc)) { - DominanceFrontier::iterator DFI = find(PredBlocks[0]); + DomTreeNode *NewBBNode = DT.getNode(NewBB); + DomTreeNode *NewBBSuccNode = DT.getNode(NewBBSucc); + if (DT.dominates(NewBBNode, NewBBSuccNode)) { + DominanceFrontier::iterator DFI = find(NewBBSucc); if (DFI != end()) { DominanceFrontier::DomSetType Set = DFI->second; // Filter out stuff in Set that we do not dominate a predecessor of. @@ -160,8 +148,10 @@ void DominanceFrontier::splitBlock(BasicBlock *NewBB) { bool DominatesPred = false; for (pred_iterator PI = pred_begin(*SetI), E = pred_end(*SetI); PI != E; ++PI) - if (DT.dominates(NewBB, *PI)) + if (DT.dominates(NewBBNode, DT.getNode(*PI))) { DominatesPred = true; + break; + } if (!DominatesPred) Set.erase(SetI++); else @@ -186,50 +176,71 @@ void DominanceFrontier::splitBlock(BasicBlock *NewBB) { NewDFSet.insert(NewBBSucc); addBasicBlock(NewBB, NewDFSet); } - - // Now we must loop over all of the dominance frontiers in the function, - // replacing occurrences of NewBBSucc with NewBB in some cases. All - // blocks that dominate a block in PredBlocks and contained NewBBSucc in - // their dominance frontier must be updated to contain NewBB instead. - // - for (Function::iterator FI = NewBB->getParent()->begin(), - FE = NewBB->getParent()->end(); FI != FE; ++FI) { - DominanceFrontier::iterator DFI = find(FI); - if (DFI == end()) continue; // unreachable block. - - // Only consider nodes that have NewBBSucc in their dominator frontier. - if (!DFI->second.count(NewBBSucc)) continue; - - // Verify whether this block dominates a block in predblocks. If not, do - // not update it. - bool BlockDominatesAny = false; - for (SmallVectorImpl::const_iterator BI = PredBlocks.begin(), - BE = PredBlocks.end(); BI != BE; ++BI) { - if (DT.dominates(FI, *BI)) { - BlockDominatesAny = true; + + // Now update dominance frontiers which either used to contain NewBBSucc + // or which now need to include NewBB. + + // Collect the set of blocks which dominate a predecessor of NewBB or + // NewSuccBB and which don't dominate both. This is an initial + // approximation of the blocks whose dominance frontiers will need updates. + SmallVector AllPredDoms; + + // Compute the block which dominates both NewBBSucc and NewBB. This is + // the immediate dominator of NewBBSucc unless NewBB dominates NewBBSucc. + // The code below which climbs dominator trees will stop at this point, + // because from this point up, dominance frontiers are unaffected. + DomTreeNode *DominatesBoth = 0; + if (NewBBSuccNode) { + DominatesBoth = NewBBSuccNode->getIDom(); + if (DominatesBoth == NewBBNode) + DominatesBoth = NewBBNode->getIDom(); + } + + // Collect the set of all blocks which dominate a predecessor of NewBB. + SmallPtrSet NewBBPredDoms; + for (pred_iterator PI = pred_begin(NewBB), E = pred_end(NewBB); PI != E; ++PI) + for (DomTreeNode *DTN = DT.getNode(*PI); DTN; DTN = DTN->getIDom()) { + if (DTN == DominatesBoth) break; - } + if (!NewBBPredDoms.insert(DTN)) + break; + AllPredDoms.push_back(DTN); } - // If NewBBSucc should not stay in our dominator frontier, remove it. - // We remove it unless there is a predecessor of NewBBSucc that we - // dominate, but we don't strictly dominate NewBBSucc. - bool ShouldRemove = true; - if ((BasicBlock*)FI == NewBBSucc || !DT.dominates(FI, NewBBSucc)) { - // Okay, we know that PredDom does not strictly dominate NewBBSucc. - // Check to see if it dominates any predecessors of NewBBSucc. - for (pred_iterator PI = pred_begin(NewBBSucc), - E = pred_end(NewBBSucc); PI != E; ++PI) - if (DT.dominates(FI, *PI)) { - ShouldRemove = false; - break; - } + // Collect the set of all blocks which dominate a predecessor of NewSuccBB. + SmallPtrSet NewBBSuccPredDoms; + for (pred_iterator PI = pred_begin(NewBBSucc), + E = pred_end(NewBBSucc); PI != E; ++PI) + for (DomTreeNode *DTN = DT.getNode(*PI); DTN; DTN = DTN->getIDom()) { + if (DTN == DominatesBoth) + break; + if (!NewBBSuccPredDoms.insert(DTN)) + break; + if (!NewBBPredDoms.count(DTN)) + AllPredDoms.push_back(DTN); } - - if (ShouldRemove) - removeFromFrontier(DFI, NewBBSucc); - if (BlockDominatesAny && (&*FI == NewBB || !DT.dominates(FI, NewBB))) + + // Visit all relevant dominance frontiers and make any needed updates. + for (SmallVectorImpl::const_iterator I = AllPredDoms.begin(), + E = AllPredDoms.end(); I != E; ++I) { + DomTreeNode *DTN = *I; + iterator DFI = find((*I)->getBlock()); + + // Only consider nodes that have NewBBSucc in their dominator frontier. + if (DFI == end() || !DFI->second.count(NewBBSucc)) continue; + + // If the block dominates a predecessor of NewBB but does not properly + // dominate NewBB itself, add NewBB to its dominance frontier. + if (NewBBPredDoms.count(DTN) && + !DT.properlyDominates(DTN, NewBBNode)) addToFrontier(DFI, NewBB); + + // If the block does not dominate a predecessor of NewBBSucc or + // properly dominates NewBBSucc itself, remove NewBBSucc from its + // dominance frontier. + if (!NewBBSuccPredDoms.count(DTN) || + DT.properlyDominates(DTN, NewBBSuccNode)) + removeFromFrontier(DFI, NewBBSucc); } } @@ -343,3 +354,7 @@ void DominanceFrontierBase::print(raw_ostream &OS, const Module* ) const { } } +void DominanceFrontierBase::dump() const { + print(dbgs()); +} + diff --git a/lib/VMCore/Globals.cpp b/lib/VMCore/Globals.cpp index b758eb8..96716ee 100644 --- a/lib/VMCore/Globals.cpp +++ b/lib/VMCore/Globals.cpp @@ -102,7 +102,14 @@ void GlobalValue::copyAttributesFrom(const GlobalValue *Src) { setVisibility(Src->getVisibility()); } - +void GlobalValue::setAlignment(unsigned Align) { + assert((Align & (Align-1)) == 0 && "Alignment is not a power of 2!"); + assert(Align <= MaximumAlignment && + "Alignment is greater than MaximumAlignment!"); + Alignment = Log2_32(Align) + 1; + assert(getAlignment() == Align && "Alignment representation error!"); +} + //===----------------------------------------------------------------------===// // GlobalVariable Implementation //===----------------------------------------------------------------------===// diff --git a/lib/VMCore/InlineAsm.cpp b/lib/VMCore/InlineAsm.cpp index 0d2eca9..69f713b 100644 --- a/lib/VMCore/InlineAsm.cpp +++ b/lib/VMCore/InlineAsm.cpp @@ -164,7 +164,7 @@ InlineAsm::ParseConstraints(StringRef Constraints) { StringRef::iterator ConstraintEnd = std::find(I, E, ','); if (ConstraintEnd == I || // Empty constraint like ",," - Info.Parse(std::string(I, ConstraintEnd), Result)) { + Info.Parse(StringRef(I, ConstraintEnd-I), Result)) { Result.clear(); // Erroneous constraint? break; } diff --git a/lib/VMCore/Instruction.cpp b/lib/VMCore/Instruction.cpp index 9792ada..05bed4c 100644 --- a/lib/VMCore/Instruction.cpp +++ b/lib/VMCore/Instruction.cpp @@ -49,8 +49,8 @@ Instruction::Instruction(const Type *ty, unsigned it, Use *Ops, unsigned NumOps, // Out of line virtual method, so the vtable, etc has a home. Instruction::~Instruction() { assert(Parent == 0 && "Instruction still linked in the program!"); - if (hasMetadata()) - removeAllMetadata(); + if (hasMetadataHashEntry()) + clearMetadataHashEntries(); } diff --git a/lib/VMCore/Instructions.cpp b/lib/VMCore/Instructions.cpp index c13696f..401802e 100644 --- a/lib/VMCore/Instructions.cpp +++ b/lib/VMCore/Instructions.cpp @@ -33,10 +33,8 @@ using namespace llvm; User::op_iterator CallSite::getCallee() const { Instruction *II(getInstruction()); return isCall() - ? (CallInst::ArgOffset - ? cast(II)->op_begin() - : cast(II)->op_end() - 1) - : cast(II)->op_end() - 3; // Skip BB, BB, Function + ? cast(II)->op_end() - 1 // Skip Callee + : cast(II)->op_end() - 3; // Skip BB, BB, Callee } //===----------------------------------------------------------------------===// @@ -233,7 +231,7 @@ CallInst::~CallInst() { void CallInst::init(Value *Func, Value* const *Params, unsigned NumParams) { assert(NumOperands == NumParams+1 && "NumOperands not set up?"); - Op() = Func; + Op<-1>() = Func; const FunctionType *FTy = cast(cast(Func->getType())->getElementType()); @@ -246,15 +244,15 @@ void CallInst::init(Value *Func, Value* const *Params, unsigned NumParams) { assert((i >= FTy->getNumParams() || FTy->getParamType(i) == Params[i]->getType()) && "Calling a function with a bad signature!"); - OperandList[i + ArgOffset] = Params[i]; + OperandList[i] = Params[i]; } } void CallInst::init(Value *Func, Value *Actual1, Value *Actual2) { assert(NumOperands == 3 && "NumOperands not set up?"); - Op() = Func; - Op() = Actual1; - Op() = Actual2; + Op<-1>() = Func; + Op<0>() = Actual1; + Op<1>() = Actual2; const FunctionType *FTy = cast(cast(Func->getType())->getElementType()); @@ -273,8 +271,8 @@ void CallInst::init(Value *Func, Value *Actual1, Value *Actual2) { void CallInst::init(Value *Func, Value *Actual) { assert(NumOperands == 2 && "NumOperands not set up?"); - Op() = Func; - Op() = Actual; + Op<-1>() = Func; + Op<0>() = Actual; const FunctionType *FTy = cast(cast(Func->getType())->getElementType()); @@ -290,7 +288,7 @@ void CallInst::init(Value *Func, Value *Actual) { void CallInst::init(Value *Func) { assert(NumOperands == 1 && "NumOperands not set up?"); - Op() = Func; + Op<-1>() = Func; const FunctionType *FTy = cast(cast(Func->getType())->getElementType()); @@ -893,6 +891,8 @@ AllocaInst::~AllocaInst() { void AllocaInst::setAlignment(unsigned Align) { assert((Align & (Align-1)) == 0 && "Alignment is not a power of 2!"); + assert(Align <= MaximumAlignment && + "Alignment is greater than MaximumAlignment!"); setInstructionSubclassData(Log2_32(Align) + 1); assert(getAlignment() == Align && "Alignment representation error!"); } @@ -1028,8 +1028,11 @@ LoadInst::LoadInst(Value *Ptr, const char *Name, bool isVolatile, void LoadInst::setAlignment(unsigned Align) { assert((Align & (Align-1)) == 0 && "Alignment is not a power of 2!"); + assert(Align <= MaximumAlignment && + "Alignment is greater than MaximumAlignment!"); setInstructionSubclassData((getSubclassDataFromInstruction() & 1) | ((Log2_32(Align)+1)<<1)); + assert(getAlignment() == Align && "Alignment representation error!"); } //===----------------------------------------------------------------------===// @@ -1124,8 +1127,11 @@ StoreInst::StoreInst(Value *val, Value *addr, bool isVolatile, void StoreInst::setAlignment(unsigned Align) { assert((Align & (Align-1)) == 0 && "Alignment is not a power of 2!"); + assert(Align <= MaximumAlignment && + "Alignment is greater than MaximumAlignment!"); setInstructionSubclassData((getSubclassDataFromInstruction() & 1) | ((Log2_32(Align)+1) << 1)); + assert(getAlignment() == Align && "Alignment representation error!"); } //===----------------------------------------------------------------------===// @@ -1424,9 +1430,24 @@ bool ShuffleVectorInst::isValidOperands(const Value *V1, const Value *V2, return false; const VectorType *MaskTy = dyn_cast(Mask->getType()); - if (!isa(Mask) || MaskTy == 0 || - !MaskTy->getElementType()->isIntegerTy(32)) + if (MaskTy == 0 || !MaskTy->getElementType()->isIntegerTy(32)) + return false; + + // Check to see if Mask is valid. + if (const ConstantVector *MV = dyn_cast(Mask)) { + const VectorType *VTy = cast(V1->getType()); + for (unsigned i = 0, e = MV->getNumOperands(); i != e; ++i) { + if (ConstantInt* CI = dyn_cast(MV->getOperand(i))) { + if (CI->uge(VTy->getNumElements()*2)) + return false; + } else if (!isa(MV->getOperand(i))) { + return false; + } + } + } + else if (!isa(Mask) && !isa(Mask)) return false; + return true; } diff --git a/lib/VMCore/LLVMContext.cpp b/lib/VMCore/LLVMContext.cpp index 4d61363..563c651 100644 --- a/lib/VMCore/LLVMContext.cpp +++ b/lib/VMCore/LLVMContext.cpp @@ -110,21 +110,18 @@ static bool isValidName(StringRef MDName) { /// getMDKindID - Return a unique non-zero ID for the specified metadata kind. unsigned LLVMContext::getMDKindID(StringRef Name) const { assert(isValidName(Name) && "Invalid MDNode name"); - - unsigned &Entry = pImpl->CustomMDKindNames[Name]; - + // If this is new, assign it its ID. - if (Entry == 0) Entry = pImpl->CustomMDKindNames.size(); - return Entry; + return + pImpl->CustomMDKindNames.GetOrCreateValue( + Name, pImpl->CustomMDKindNames.size()).second; } /// getHandlerNames - Populate client supplied smallvector using custome /// metadata name and ID. void LLVMContext::getMDKindNames(SmallVectorImpl &Names) const { - Names.resize(pImpl->CustomMDKindNames.size()+1); - Names[0] = ""; + Names.resize(pImpl->CustomMDKindNames.size()); for (StringMap::const_iterator I = pImpl->CustomMDKindNames.begin(), E = pImpl->CustomMDKindNames.end(); I != E; ++I) - // MD Handlers are numbered from 1. Names[I->second] = I->first(); } diff --git a/lib/VMCore/LLVMContextImpl.cpp b/lib/VMCore/LLVMContextImpl.cpp index 9e41a08..93a075f 100644 --- a/lib/VMCore/LLVMContextImpl.cpp +++ b/lib/VMCore/LLVMContextImpl.cpp @@ -57,14 +57,11 @@ LLVMContextImpl::~LLVMContextImpl() { DropReferences()); std::for_each(StructConstants.map_begin(), StructConstants.map_end(), DropReferences()); - std::for_each(UnionConstants.map_begin(), UnionConstants.map_end(), - DropReferences()); std::for_each(VectorConstants.map_begin(), VectorConstants.map_end(), DropReferences()); ExprConstants.freeConstants(); ArrayConstants.freeConstants(); StructConstants.freeConstants(); - UnionConstants.freeConstants(); VectorConstants.freeConstants(); AggZeroConstants.freeConstants(); NullPtrConstants.freeConstants(); diff --git a/lib/VMCore/LLVMContextImpl.h b/lib/VMCore/LLVMContextImpl.h index 4876f5d..51b2992 100644 --- a/lib/VMCore/LLVMContextImpl.h +++ b/lib/VMCore/LLVMContextImpl.h @@ -144,10 +144,6 @@ public: ConstantStruct, true /*largekey*/> StructConstantsTy; StructConstantsTy StructConstants; - typedef ConstantUniqueMap - UnionConstantsTy; - UnionConstantsTy UnionConstants; - typedef ConstantUniqueMap, VectorType, ConstantVector> VectorConstantsTy; VectorConstantsTy VectorConstants; @@ -192,7 +188,6 @@ public: TypeMap PointerTypes; TypeMap FunctionTypes; TypeMap StructTypes; - TypeMap UnionTypes; TypeMap IntegerTypes; // Opaque types are not structurally uniqued, so don't use TypeMap. diff --git a/lib/VMCore/Metadata.cpp b/lib/VMCore/Metadata.cpp index 3100d4a..da69c43 100644 --- a/lib/VMCore/Metadata.cpp +++ b/lib/VMCore/Metadata.cpp @@ -20,6 +20,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/SmallString.h" #include "SymbolTableListTraitsImpl.h" +#include "llvm/Support/LeakDetector.h" #include "llvm/Support/ValueHandle.h" using namespace llvm; @@ -186,6 +187,21 @@ MDNode *MDNode::getMDNode(LLVMContext &Context, Value *const *Vals, unsigned NumVals, FunctionLocalness FL, bool Insert) { LLVMContextImpl *pImpl = Context.pImpl; + + // Add all the operand pointers. Note that we don't have to add the + // isFunctionLocal bit because that's implied by the operands. + // Note that if the operands are later nulled out, the node will be + // removed from the uniquing map. + FoldingSetNodeID ID; + for (unsigned i = 0; i != NumVals; ++i) + ID.AddPointer(Vals[i]); + + void *InsertPoint; + MDNode *N = NULL; + + if ((N = pImpl->MDNodeSet.FindNodeOrInsertPos(ID, InsertPoint))) + return N; + bool isFunctionLocal = false; switch (FL) { case FL_Unknown: @@ -206,20 +222,6 @@ MDNode *MDNode::getMDNode(LLVMContext &Context, Value *const *Vals, break; } - FoldingSetNodeID ID; - for (unsigned i = 0; i != NumVals; ++i) - ID.AddPointer(Vals[i]); - ID.AddBoolean(isFunctionLocal); - - void *InsertPoint; - MDNode *N = NULL; - - if ((N = pImpl->MDNodeSet.FindNodeOrInsertPos(ID, InsertPoint))) - return N; - - if (!Insert) - return NULL; - // Coallocate space for the node and Operands together, then placement new. void *Ptr = malloc(sizeof(MDNode)+NumVals*sizeof(MDNodeOperand)); N = new (Ptr) MDNode(Context, Vals, NumVals, isFunctionLocal); @@ -244,15 +246,42 @@ MDNode *MDNode::getIfExists(LLVMContext &Context, Value *const *Vals, return getMDNode(Context, Vals, NumVals, FL_Unknown, false); } +MDNode *MDNode::getTemporary(LLVMContext &Context, Value *const *Vals, + unsigned NumVals) { + MDNode *N = (MDNode *)malloc(sizeof(MDNode)+NumVals*sizeof(MDNodeOperand)); + N = new (N) MDNode(Context, Vals, NumVals, FL_No); + N->setValueSubclassData(N->getSubclassDataFromValue() | + NotUniquedBit); + LeakDetector::addGarbageObject(N); + return N; +} + +void MDNode::deleteTemporary(MDNode *N) { + assert(N->use_empty() && "Temporary MDNode has uses!"); + assert(!N->getContext().pImpl->MDNodeSet.RemoveNode(N) && + "Deleting a non-temporary uniqued node!"); + assert(!N->getContext().pImpl->NonUniquedMDNodes.erase(N) && + "Deleting a non-temporary non-uniqued node!"); + assert((N->getSubclassDataFromValue() & NotUniquedBit) && + "Temporary MDNode does not have NotUniquedBit set!"); + assert((N->getSubclassDataFromValue() & DestroyFlag) == 0 && + "Temporary MDNode has DestroyFlag set!"); + LeakDetector::removeGarbageObject(N); + N->destroy(); +} + /// getOperand - Return specified operand. Value *MDNode::getOperand(unsigned i) const { return *getOperandPtr(const_cast(this), i); } void MDNode::Profile(FoldingSetNodeID &ID) const { + // Add all the operand pointers. Note that we don't have to add the + // isFunctionLocal bit because that's implied by the operands. + // Note that if the operands are later nulled out, the node will be + // removed from the uniquing map. for (unsigned i = 0, e = getNumOperands(); i != e; ++i) ID.AddPointer(getOperand(i)); - ID.AddBoolean(isFunctionLocal()); } void MDNode::setIsNotUniqued() { @@ -301,7 +330,8 @@ void MDNode::replaceOperand(MDNodeOperand *Op, Value *To) { // If we are dropping an argument to null, we choose to not unique the MDNode // anymore. This commonly occurs during destruction, and uniquing these - // brings little reuse. + // brings little reuse. Also, this means we don't need to include + // isFunctionLocal bits in FoldingSetNodeIDs for MDNodes. if (To == 0) { setIsNotUniqued(); return; @@ -324,59 +354,35 @@ void MDNode::replaceOperand(MDNodeOperand *Op, Value *To) { // InsertPoint will have been set by the FindNodeOrInsertPos call. pImpl->MDNodeSet.InsertNode(this, InsertPoint); + + // If this MDValue was previously function-local but no longer is, clear + // its function-local flag. + if (isFunctionLocal() && !isFunctionLocalValue(To)) { + bool isStillFunctionLocal = false; + for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { + Value *V = getOperand(i); + if (!V) continue; + if (isFunctionLocalValue(V)) { + isStillFunctionLocal = true; + break; + } + } + if (!isStillFunctionLocal) + setValueSubclassData(getSubclassDataFromValue() & ~FunctionLocalBit); + } } //===----------------------------------------------------------------------===// // NamedMDNode implementation. // -namespace llvm { -// SymbolTableListTraits specialization for MDSymbolTable. -void ilist_traits -::addNodeToList(NamedMDNode *N) { - assert(N->getParent() == 0 && "Value already in a container!!"); - Module *Owner = getListOwner(); - N->setParent(Owner); - MDSymbolTable &ST = Owner->getMDSymbolTable(); - ST.insert(N->getName(), N); -} - -void ilist_traits::removeNodeFromList(NamedMDNode *N) { - N->setParent(0); - Module *Owner = getListOwner(); - MDSymbolTable &ST = Owner->getMDSymbolTable(); - ST.remove(N->getName()); -} -} - -static SmallVector &getNMDOps(void *Operands) { - return *(SmallVector*)Operands; -} - -NamedMDNode::NamedMDNode(LLVMContext &C, const Twine &N, - MDNode *const *MDs, - unsigned NumMDs, Module *ParentModule) - : Value(Type::getMetadataTy(C), Value::NamedMDNodeVal), Parent(0) { - setName(N); - Operands = new SmallVector(); - - SmallVector &Node = getNMDOps(Operands); - for (unsigned i = 0; i != NumMDs; ++i) - Node.push_back(WeakVH(MDs[i])); - - if (ParentModule) - ParentModule->getNamedMDList().push_back(this); +static SmallVector, 4> &getNMDOps(void *Operands) { + return *(SmallVector, 4>*)Operands; } -NamedMDNode *NamedMDNode::Create(const NamedMDNode *NMD, Module *M) { - assert(NMD && "Invalid source NamedMDNode!"); - SmallVector Elems; - Elems.reserve(NMD->getNumOperands()); - - for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) - Elems.push_back(NMD->getOperand(i)); - return new NamedMDNode(NMD->getContext(), NMD->getName().data(), - Elems.data(), Elems.size(), M); +NamedMDNode::NamedMDNode(const Twine &N) + : Name(N.str()), Parent(0), + Operands(new SmallVector, 4>()) { } NamedMDNode::~NamedMDNode() { @@ -392,18 +398,20 @@ unsigned NamedMDNode::getNumOperands() const { /// getOperand - Return specified operand. MDNode *NamedMDNode::getOperand(unsigned i) const { assert(i < getNumOperands() && "Invalid Operand number!"); - return dyn_cast_or_null(getNMDOps(Operands)[i]); + return dyn_cast(&*getNMDOps(Operands)[i]); } /// addOperand - Add metadata Operand. void NamedMDNode::addOperand(MDNode *M) { - getNMDOps(Operands).push_back(WeakVH(M)); + assert(!M->isFunctionLocal() && + "NamedMDNode operands must not be function-local!"); + getNMDOps(Operands).push_back(TrackingVH(M)); } /// eraseFromParent - Drop all references and remove the node from parent /// module. void NamedMDNode::eraseFromParent() { - getParent()->getNamedMDList().erase(this); + getParent()->eraseNamedMetadata(this); } /// dropAllReferences - Remove all uses and clear node vector. @@ -411,22 +419,6 @@ void NamedMDNode::dropAllReferences() { getNMDOps(Operands).clear(); } -/// setName - Set the name of this named metadata. -void NamedMDNode::setName(const Twine &NewName) { - assert (!NewName.isTriviallyEmpty() && "Invalid named metadata name!"); - - SmallString<256> NameData; - StringRef NameRef = NewName.toStringRef(NameData); - - // Name isn't changing? - if (getName() == NameRef) - return; - - Name = NameRef.str(); - if (Parent) - Parent->getMDSymbolTable().insert(NameRef, this); -} - /// getName - Return a constant reference to this named metadata's name. StringRef NamedMDNode::getName() const { return StringRef(Name); @@ -445,10 +437,6 @@ MDNode *Instruction::getMetadataImpl(const char *Kind) const { return getMetadataImpl(getContext().getMDKindID(Kind)); } -void Instruction::setDbgMetadata(MDNode *Node) { - DbgLoc = DebugLoc::getFromDILocation(Node); -} - /// setMetadata - Set the metadata of of the specified kind to the specified /// node. This updates/replaces metadata if already present, or removes it if /// Node is null. @@ -567,13 +555,11 @@ getAllMetadataOtherThanDebugLocImpl(SmallVectorImplMetadataStore.erase(this); - setHasMetadataHashEntry(false); - } +/// clearMetadataHashEntries - Clear all hashtable-based metadata from +/// this instruction. +void Instruction::clearMetadataHashEntries() { + assert(hasMetadataHashEntry() && "Caller should check"); + getContext().pImpl->MetadataStore.erase(this); + setHasMetadataHashEntry(false); } diff --git a/lib/VMCore/Module.cpp b/lib/VMCore/Module.cpp index 38a51df..d7ddf96 100644 --- a/lib/VMCore/Module.cpp +++ b/lib/VMCore/Module.cpp @@ -58,10 +58,10 @@ template class llvm::SymbolTableListTraits; // Module::Module(StringRef MID, LLVMContext& C) - : Context(C), Materializer(NULL), ModuleID(MID), DataLayout("") { + : Context(C), Materializer(NULL), ModuleID(MID) { ValSymTab = new ValueSymbolTable(); TypeSymTab = new TypeSymbolTable(); - NamedMDSymTab = new MDSymbolTable(); + NamedMDSymTab = new StringMap(); } Module::~Module() { @@ -73,7 +73,7 @@ Module::~Module() { NamedMDList.clear(); delete ValSymTab; delete TypeSymTab; - delete NamedMDSymTab; + delete static_cast *>(NamedMDSymTab); } /// Target endian information... @@ -316,19 +316,28 @@ GlobalAlias *Module::getNamedAlias(StringRef Name) const { NamedMDNode *Module::getNamedMetadata(const Twine &Name) const { SmallString<256> NameData; StringRef NameRef = Name.toStringRef(NameData); - return NamedMDSymTab->lookup(NameRef); + return static_cast *>(NamedMDSymTab)->lookup(NameRef); } /// getOrInsertNamedMetadata - Return the first named MDNode in the module /// with the specified name. This method returns a new NamedMDNode if a /// NamedMDNode with the specified name is not found. NamedMDNode *Module::getOrInsertNamedMetadata(StringRef Name) { - NamedMDNode *NMD = NamedMDSymTab->lookup(Name); - if (!NMD) - NMD = NamedMDNode::Create(getContext(), Name, NULL, 0, this); + NamedMDNode *&NMD = + (*static_cast *>(NamedMDSymTab))[Name]; + if (!NMD) { + NMD = new NamedMDNode(Name); + NMD->setParent(this); + NamedMDList.push_back(NMD); + } return NMD; } +void Module::eraseNamedMetadata(NamedMDNode *NMD) { + static_cast *>(NamedMDSymTab)->erase(NMD->getName()); + NamedMDList.erase(NMD); +} + //===----------------------------------------------------------------------===// // Methods for easy access to the types in the module. // diff --git a/lib/VMCore/Pass.cpp b/lib/VMCore/Pass.cpp index efd98af..a7d7f61 100644 --- a/lib/VMCore/Pass.cpp +++ b/lib/VMCore/Pass.cpp @@ -14,35 +14,18 @@ //===----------------------------------------------------------------------===// #include "llvm/Pass.h" -#include "llvm/PassManager.h" -#include "llvm/Module.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringMap.h" +#include "llvm/PassRegistry.h" #include "llvm/Assembly/PrintModulePass.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PassNameParser.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Atomic.h" -#include "llvm/System/Mutex.h" -#include "llvm/System/Threading.h" -#include -#include -#include using namespace llvm; //===----------------------------------------------------------------------===// // Pass Implementation // -Pass::Pass(PassKind K, intptr_t pid) : Resolver(0), PassID(pid), Kind(K) { - assert(pid && "pid cannot be 0"); -} - -Pass::Pass(PassKind K, const void *pid) - : Resolver(0), PassID((intptr_t)pid), Kind(K) { - assert(pid && "pid cannot be 0"); -} +Pass::Pass(PassKind K, char &pid) : Resolver(0), PassID(&pid), Kind(K) { } // Force out-of-line virtual method. Pass::~Pass() { @@ -61,8 +44,8 @@ PassManagerType ModulePass::getPotentialPassManagerType() const { return PMT_ModulePassManager; } -bool Pass::mustPreserveAnalysisID(const PassInfo *AnalysisID) const { - return Resolver->getAnalysisIfAvailable(AnalysisID, true) != 0; +bool Pass::mustPreserveAnalysisID(char &AID) const { + return Resolver->getAnalysisIfAvailable(&AID, true) != 0; } // dumpPassStructure - Implement the -debug-passes=Structure option @@ -75,7 +58,9 @@ void Pass::dumpPassStructure(unsigned Offset) { /// Registration templates, but can be overloaded directly. /// const char *Pass::getPassName() const { - if (const PassInfo *PI = getPassInfo()) + AnalysisID AID = getPassID(); + const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(AID); + if (PI) return PI->getPassName(); return "Unnamed pass: implement Pass::getPassName()"; } @@ -101,7 +86,7 @@ void Pass::verifyAnalysis() const { // By default, don't do anything. } -void *Pass::getAdjustedAnalysisPointer(const PassInfo *) { +void *Pass::getAdjustedAnalysisPointer(AnalysisID AID) { return this; } @@ -150,30 +135,6 @@ Pass *FunctionPass::createPrinterPass(raw_ostream &O, return createPrintFunctionPass(Banner, &O); } -// run - On a module, we run this pass by initializing, runOnFunction'ing once -// for every function in the module, then by finalizing. -// -bool FunctionPass::runOnModule(Module &M) { - bool Changed = doInitialization(M); - - for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) - if (!I->isDeclaration()) // Passes are not run on external functions! - Changed |= runOnFunction(*I); - - return Changed | doFinalization(M); -} - -// run - On a function, we simply initialize, run the function, then finalize. -// -bool FunctionPass::run(Function &F) { - // Passes are not run on external functions! - if (F.isDeclaration()) return false; - - bool Changed = doInitialization(*F.getParent()); - Changed |= runOnFunction(F); - return Changed | doFinalization(*F.getParent()); -} - bool FunctionPass::doInitialization(Module &) { // By default, don't do anything. return false; @@ -199,16 +160,6 @@ Pass *BasicBlockPass::createPrinterPass(raw_ostream &O, return 0; } -// To run this pass on a function, we simply call runOnBasicBlock once for each -// function. -// -bool BasicBlockPass::runOnFunction(Function &F) { - bool Changed = doInitialization(F); - for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) - Changed |= runOnBasicBlock(*I); - return Changed | doFinalization(F); -} - bool BasicBlockPass::doInitialization(Module &) { // By default, don't do anything. return false; @@ -233,161 +184,12 @@ PassManagerType BasicBlockPass::getPotentialPassManagerType() const { return PMT_BasicBlockPassManager; } -//===----------------------------------------------------------------------===// -// Pass Registration mechanism -// -namespace { -class PassRegistrar { - /// Guards the contents of this class. - mutable sys::SmartMutex Lock; - - /// PassInfoMap - Keep track of the passinfo object for each registered llvm - /// pass. - typedef std::map MapType; - MapType PassInfoMap; - - typedef StringMap StringMapType; - StringMapType PassInfoStringMap; - - /// AnalysisGroupInfo - Keep track of information for each analysis group. - struct AnalysisGroupInfo { - std::set Implementations; - }; - - /// AnalysisGroupInfoMap - Information for each analysis group. - std::map AnalysisGroupInfoMap; - -public: - - const PassInfo *GetPassInfo(intptr_t TI) const { - sys::SmartScopedLock Guard(Lock); - MapType::const_iterator I = PassInfoMap.find(TI); - return I != PassInfoMap.end() ? I->second : 0; - } - - const PassInfo *GetPassInfo(StringRef Arg) const { - sys::SmartScopedLock Guard(Lock); - StringMapType::const_iterator I = PassInfoStringMap.find(Arg); - return I != PassInfoStringMap.end() ? I->second : 0; - } - - void RegisterPass(const PassInfo &PI) { - sys::SmartScopedLock Guard(Lock); - bool Inserted = - PassInfoMap.insert(std::make_pair(PI.getTypeInfo(),&PI)).second; - assert(Inserted && "Pass registered multiple times!"); Inserted=Inserted; - PassInfoStringMap[PI.getPassArgument()] = &PI; - } - - void UnregisterPass(const PassInfo &PI) { - sys::SmartScopedLock Guard(Lock); - MapType::iterator I = PassInfoMap.find(PI.getTypeInfo()); - assert(I != PassInfoMap.end() && "Pass registered but not in map!"); - - // Remove pass from the map. - PassInfoMap.erase(I); - PassInfoStringMap.erase(PI.getPassArgument()); - } - - void EnumerateWith(PassRegistrationListener *L) { - sys::SmartScopedLock Guard(Lock); - for (MapType::const_iterator I = PassInfoMap.begin(), - E = PassInfoMap.end(); I != E; ++I) - L->passEnumerate(I->second); - } - - - /// Analysis Group Mechanisms. - void RegisterAnalysisGroup(PassInfo *InterfaceInfo, - const PassInfo *ImplementationInfo, - bool isDefault) { - sys::SmartScopedLock Guard(Lock); - AnalysisGroupInfo &AGI = AnalysisGroupInfoMap[InterfaceInfo]; - assert(AGI.Implementations.count(ImplementationInfo) == 0 && - "Cannot add a pass to the same analysis group more than once!"); - AGI.Implementations.insert(ImplementationInfo); - if (isDefault) { - assert(InterfaceInfo->getNormalCtor() == 0 && - "Default implementation for analysis group already specified!"); - assert(ImplementationInfo->getNormalCtor() && - "Cannot specify pass as default if it does not have a default ctor"); - InterfaceInfo->setNormalCtor(ImplementationInfo->getNormalCtor()); - } - } -}; -} - -static std::vector *Listeners = 0; -static sys::SmartMutex ListenersLock; - -static PassRegistrar *PassRegistrarObj = 0; -static PassRegistrar *getPassRegistrar() { - // Use double-checked locking to safely initialize the registrar when - // we're running in multithreaded mode. - PassRegistrar* tmp = PassRegistrarObj; - if (llvm_is_multithreaded()) { - sys::MemoryFence(); - if (!tmp) { - llvm_acquire_global_lock(); - tmp = PassRegistrarObj; - if (!tmp) { - tmp = new PassRegistrar(); - sys::MemoryFence(); - PassRegistrarObj = tmp; - } - llvm_release_global_lock(); - } - } else if (!tmp) { - PassRegistrarObj = new PassRegistrar(); - } - - return PassRegistrarObj; -} - -namespace { - -// FIXME: We use ManagedCleanup to erase the pass registrar on shutdown. -// Unfortunately, passes are registered with static ctors, and having -// llvm_shutdown clear this map prevents successful ressurection after -// llvm_shutdown is run. Ideally we should find a solution so that we don't -// leak the map, AND can still resurrect after shutdown. -void cleanupPassRegistrar(void*) { - if (PassRegistrarObj) { - delete PassRegistrarObj; - PassRegistrarObj = 0; - } -} -ManagedCleanup<&cleanupPassRegistrar> registrarCleanup ATTRIBUTE_USED; - -} - -// getPassInfo - Return the PassInfo data structure that corresponds to this -// pass... -const PassInfo *Pass::getPassInfo() const { - return lookupPassInfo(PassID); -} - -const PassInfo *Pass::lookupPassInfo(intptr_t TI) { - return getPassRegistrar()->GetPassInfo(TI); +const PassInfo *Pass::lookupPassInfo(const void *TI) { + return PassRegistry::getPassRegistry()->getPassInfo(TI); } const PassInfo *Pass::lookupPassInfo(StringRef Arg) { - return getPassRegistrar()->GetPassInfo(Arg); -} - -void PassInfo::registerPass() { - getPassRegistrar()->RegisterPass(*this); - - // Notify any listeners. - sys::SmartScopedLock Lock(ListenersLock); - if (Listeners) - for (std::vector::iterator - I = Listeners->begin(), E = Listeners->end(); I != E; ++I) - (*I)->passRegistered(this); -} - -void PassInfo::unregisterPass() { - getPassRegistrar()->UnregisterPass(*this); + return PassRegistry::getPassRegistry()->getPassInfo(Arg); } Pass *PassInfo::createPass() const { @@ -404,32 +206,11 @@ Pass *PassInfo::createPass() const { // RegisterAGBase implementation // -RegisterAGBase::RegisterAGBase(const char *Name, intptr_t InterfaceID, - intptr_t PassID, bool isDefault) - : PassInfo(Name, InterfaceID) { - - PassInfo *InterfaceInfo = - const_cast(Pass::lookupPassInfo(InterfaceID)); - if (InterfaceInfo == 0) { - // First reference to Interface, register it now. - registerPass(); - InterfaceInfo = this; - } - assert(isAnalysisGroup() && - "Trying to join an analysis group that is a normal pass!"); - - if (PassID) { - const PassInfo *ImplementationInfo = Pass::lookupPassInfo(PassID); - assert(ImplementationInfo && - "Must register pass before adding to AnalysisGroup!"); - - // Make sure we keep track of the fact that the implementation implements - // the interface. - PassInfo *IIPI = const_cast(ImplementationInfo); - IIPI->addInterfaceImplemented(InterfaceInfo); - - getPassRegistrar()->RegisterAnalysisGroup(InterfaceInfo, IIPI, isDefault); - } +RegisterAGBase::RegisterAGBase(const char *Name, const void *InterfaceID, + const void *PassID, bool isDefault) + : PassInfo(Name, InterfaceID) { + PassRegistry::getPassRegistry()->registerAnalysisGroup(InterfaceID, PassID, + *this, isDefault); } @@ -440,31 +221,19 @@ RegisterAGBase::RegisterAGBase(const char *Name, intptr_t InterfaceID, // PassRegistrationListener ctor - Add the current object to the list of // PassRegistrationListeners... PassRegistrationListener::PassRegistrationListener() { - sys::SmartScopedLock Lock(ListenersLock); - if (!Listeners) Listeners = new std::vector(); - Listeners->push_back(this); + PassRegistry::getPassRegistry()->addRegistrationListener(this); } // dtor - Remove object from list of listeners... PassRegistrationListener::~PassRegistrationListener() { - sys::SmartScopedLock Lock(ListenersLock); - std::vector::iterator I = - std::find(Listeners->begin(), Listeners->end(), this); - assert(Listeners && I != Listeners->end() && - "PassRegistrationListener not registered!"); - Listeners->erase(I); - - if (Listeners->empty()) { - delete Listeners; - Listeners = 0; - } + PassRegistry::getPassRegistry()->removeRegistrationListener(this); } // enumeratePasses - Iterate over the registered passes, calling the // passEnumerate callback on each PassInfo object. // void PassRegistrationListener::enumeratePasses() { - getPassRegistrar()->EnumerateWith(this); + PassRegistry::getPassRegistry()->enumerateWith(this); } PassNameParser::~PassNameParser() {} @@ -481,7 +250,7 @@ namespace { void passEnumerate(const PassInfo *P) { if (P->isCFGOnlyPass()) - CFGOnlyList.push_back(P); + CFGOnlyList.push_back(P->getTypeInfo()); } }; } @@ -501,15 +270,25 @@ void AnalysisUsage::setPreservesCFG() { GetCFGOnlyPasses(Preserved).enumeratePasses(); } -AnalysisUsage &AnalysisUsage::addRequiredID(AnalysisID ID) { - assert(ID && "Pass class not registered!"); - Required.push_back(ID); +AnalysisUsage &AnalysisUsage::addPreserved(StringRef Arg) { + const PassInfo *PI = Pass::lookupPassInfo(Arg); + // If the pass exists, preserve it. Otherwise silently do nothing. + if (PI) Preserved.push_back(PI->getTypeInfo()); return *this; } -AnalysisUsage &AnalysisUsage::addRequiredTransitiveID(AnalysisID ID) { - assert(ID && "Pass class not registered!"); +AnalysisUsage &AnalysisUsage::addRequiredID(const void *ID) { Required.push_back(ID); - RequiredTransitive.push_back(ID); + return *this; +} + +AnalysisUsage &AnalysisUsage::addRequiredID(char &ID) { + Required.push_back(&ID); + return *this; +} + +AnalysisUsage &AnalysisUsage::addRequiredTransitiveID(char &ID) { + Required.push_back(&ID); + RequiredTransitive.push_back(&ID); return *this; } diff --git a/lib/VMCore/PassManager.cpp b/lib/VMCore/PassManager.cpp index 296b0d1..ab4d4e5 100644 --- a/lib/VMCore/PassManager.cpp +++ b/lib/VMCore/PassManager.cpp @@ -7,12 +7,13 @@ // //===----------------------------------------------------------------------===// // -// This file implements the LLVM Pass Manager infrastructure. +// This file implements the LLVM Pass Manager infrastructure. // //===----------------------------------------------------------------------===// #include "llvm/PassManagers.h" +#include "llvm/PassManager.h" #include "llvm/Assembly/PrintModulePass.h" #include "llvm/Assembly/Writer.h" #include "llvm/Support/CommandLine.h" @@ -24,8 +25,6 @@ #include "llvm/Support/PassNameParser.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Mutex.h" -#include "llvm/System/Threading.h" -#include "llvm-c/Core.h" #include #include #include @@ -82,30 +81,32 @@ PrintAfterAll("print-after-all", /// This is a helper to determine whether to print IR before or /// after a pass. -static bool ShouldPrintBeforeOrAfterPass(Pass *P, +static bool ShouldPrintBeforeOrAfterPass(const void *PassID, PassOptionList &PassesToPrint) { - for (unsigned i = 0, ie = PassesToPrint.size(); i < ie; ++i) { - const llvm::PassInfo *PassInf = PassesToPrint[i]; - if (PassInf && P->getPassInfo()) - if (PassInf->getPassArgument() == - P->getPassInfo()->getPassArgument()) { - return true; - } + if (const llvm::PassInfo *PI = + PassRegistry::getPassRegistry()->getPassInfo(PassID)) { + for (unsigned i = 0, ie = PassesToPrint.size(); i < ie; ++i) { + const llvm::PassInfo *PassInf = PassesToPrint[i]; + if (PassInf) + if (PassInf->getPassArgument() == PI->getPassArgument()) { + return true; + } + } } return false; } - + /// This is a utility to check whether a pass should have IR dumped /// before it. -static bool ShouldPrintBeforePass(Pass *P) { - return PrintBeforeAll || ShouldPrintBeforeOrAfterPass(P, PrintBefore); +static bool ShouldPrintBeforePass(const void *PassID) { + return PrintBeforeAll || ShouldPrintBeforeOrAfterPass(PassID, PrintBefore); } /// This is a utility to check whether a pass should have IR dumped /// after it. -static bool ShouldPrintAfterPass(Pass *P) { - return PrintAfterAll || ShouldPrintBeforeOrAfterPass(P, PrintAfter); +static bool ShouldPrintAfterPass(const void *PassID) { + return PrintAfterAll || ShouldPrintBeforeOrAfterPass(PassID, PrintAfter); } } // End of llvm namespace @@ -124,9 +125,9 @@ void PassManagerPrettyStackEntry::print(raw_ostream &OS) const { OS << "Releasing pass '"; else OS << "Running pass '"; - + OS << P->getPassName() << "'"; - + if (M) { OS << " on module '" << M->getModuleIdentifier() << "'.\n"; return; @@ -162,8 +163,8 @@ class BBPassManager : public PMDataManager, public FunctionPass { public: static char ID; - explicit BBPassManager(int Depth) - : PMDataManager(Depth), FunctionPass(&ID) {} + explicit BBPassManager(int Depth) + : PMDataManager(Depth), FunctionPass(ID) {} /// Execute all of the passes scheduled for execution. Keep track of /// whether any of the passes modifies the function, and if so, return true. @@ -202,8 +203,8 @@ public: return BP; } - virtual PassManagerType getPassManagerType() const { - return PMT_BasicBlockPassManager; + virtual PassManagerType getPassManagerType() const { + return PMT_BasicBlockPassManager; } }; @@ -223,9 +224,9 @@ private: bool wasRun; public: static char ID; - explicit FunctionPassManagerImpl(int Depth) : - Pass(PT_PassManager, &ID), PMDataManager(Depth), - PMTopLevelManager(TLM_Function), wasRun(false) { } + explicit FunctionPassManagerImpl(int Depth) : + Pass(PT_PassManager, ID), PMDataManager(Depth), + PMTopLevelManager(new FPPassManager(1)), wasRun(false) {} /// add - Add a pass to the queue of passes to run. This passes ownership of /// the Pass to the PassManager. When the PassManager is destroyed, the pass @@ -234,8 +235,8 @@ public: void add(Pass *P) { schedulePass(P); } - - /// createPrinterPass - Get a function printer pass. + + /// createPrinterPass - Get a function printer pass. Pass *createPrinterPass(raw_ostream &O, const std::string &Banner) const { return createPrintFunctionPass(Banner, &O); } @@ -251,12 +252,12 @@ public: /// doInitialization - Run all of the initializers for the function passes. /// bool doInitialization(Module &M); - + /// doFinalization - Run all of the finalizers for the function passes. /// bool doFinalization(Module &M); - + virtual PMDataManager *getAsPMDataManager() { return this; } virtual Pass *getAsPass() { return this; } @@ -265,7 +266,7 @@ public: Info.setPreservesAll(); } - inline void addTopLevelPass(Pass *P) { + void addTopLevelPass(Pass *P) { if (ImmutablePass *IP = P->getAsImmutablePass()) { // P is a immutable pass and it will be managed by this // top level manager. Set up analysis resolver to connect them. @@ -288,6 +289,7 @@ public: }; char FunctionPassManagerImpl::ID = 0; + //===----------------------------------------------------------------------===// // MPPassManager // @@ -298,11 +300,11 @@ class MPPassManager : public Pass, public PMDataManager { public: static char ID; explicit MPPassManager(int Depth) : - Pass(PT_PassManager, &ID), PMDataManager(Depth) { } + Pass(PT_PassManager, ID), PMDataManager(Depth) { } // Delete on the fly managers. virtual ~MPPassManager() { - for (std::map::iterator + for (std::map::iterator I = OnTheFlyManagers.begin(), E = OnTheFlyManagers.end(); I != E; ++I) { FunctionPassManagerImpl *FPP = I->second; @@ -310,7 +312,7 @@ public: } } - /// createPrinterPass - Get a module printer pass. + /// createPrinterPass - Get a module printer pass. Pass *createPrinterPass(raw_ostream &O, const std::string &Banner) const { return createPrintModulePass(&O, false, Banner); } @@ -329,10 +331,10 @@ public: /// through getAnalysis interface. virtual void addLowerLevelRequiredPass(Pass *P, Pass *RequiredPass); - /// Return function pass corresponding to PassInfo PI, that is + /// Return function pass corresponding to PassInfo PI, that is /// required by module pass MP. Instantiate analysis pass, by using /// its runOnFunction() for function F. - virtual Pass* getOnTheFlyPass(Pass *MP, const PassInfo *PI, Function &F); + virtual Pass* getOnTheFlyPass(Pass *MP, AnalysisID PI, Function &F); virtual const char *getPassName() const { return "Module Pass Manager"; @@ -360,8 +362,8 @@ public: return static_cast(PassVector[N]); } - virtual PassManagerType getPassManagerType() const { - return PMT_ModulePassManager; + virtual PassManagerType getPassManagerType() const { + return PMT_ModulePassManager; } private: @@ -383,8 +385,8 @@ class PassManagerImpl : public Pass, public: static char ID; explicit PassManagerImpl(int Depth) : - Pass(PT_PassManager, &ID), PMDataManager(Depth), - PMTopLevelManager(TLM_Pass) { } + Pass(PT_PassManager, ID), PMDataManager(Depth), + PMTopLevelManager(new MPPassManager(1)) {} /// add - Add a pass to the queue of passes to run. This passes ownership of /// the Pass to the PassManager. When the PassManager is destroyed, the pass @@ -393,8 +395,8 @@ public: void add(Pass *P) { schedulePass(P); } - - /// createPrinterPass - Get a module printer pass. + + /// createPrinterPass - Get a module printer pass. Pass *createPrinterPass(raw_ostream &O, const std::string &Banner) const { return createPrintModulePass(&O, false, Banner); } @@ -408,7 +410,7 @@ public: Info.setPreservesAll(); } - inline void addTopLevelPass(Pass *P) { + void addTopLevelPass(Pass *P) { if (ImmutablePass *IP = P->getAsImmutablePass()) { // P is a immutable pass and it will be managed by this // top level manager. Set up analysis resolver to connect them. @@ -451,7 +453,7 @@ class TimingInfo { public: // Use 'create' member to get this. TimingInfo() : TG("... Pass execution timing report ...") {} - + // TimingDtor - Print out information about timing information ~TimingInfo() { // Delete all of the timers, which accumulate their info into the @@ -469,7 +471,7 @@ public: /// getPassTimer - Return the timer for the specified pass if it exists. Timer *getPassTimer(Pass *P) { - if (P->getAsPMDataManager()) + if (P->getAsPMDataManager()) return 0; sys::SmartScopedLock Lock(*TimingInfoMutex); @@ -488,28 +490,20 @@ static TimingInfo *TheTimeInfo; // PMTopLevelManager implementation /// Initialize top level manager. Create first pass manager. -PMTopLevelManager::PMTopLevelManager(enum TopLevelManagerType t) { - if (t == TLM_Pass) { - MPPassManager *MPP = new MPPassManager(1); - MPP->setTopLevelManager(this); - addPassManager(MPP); - activeStack.push(MPP); - } else if (t == TLM_Function) { - FPPassManager *FPP = new FPPassManager(1); - FPP->setTopLevelManager(this); - addPassManager(FPP); - activeStack.push(FPP); - } +PMTopLevelManager::PMTopLevelManager(PMDataManager *PMDM) { + PMDM->setTopLevelManager(this); + addPassManager(PMDM); + activeStack.push(PMDM); } /// Set pass P as the last user of the given analysis passes. -void PMTopLevelManager::setLastUser(SmallVector &AnalysisPasses, +void PMTopLevelManager::setLastUser(SmallVector &AnalysisPasses, Pass *P) { for (SmallVector::iterator I = AnalysisPasses.begin(), E = AnalysisPasses.end(); I != E; ++I) { Pass *AP = *I; LastUser[AP] = P; - + if (P == AP) continue; @@ -528,7 +522,7 @@ void PMTopLevelManager::setLastUser(SmallVector &AnalysisPasses, /// Collect passes whose last user is P void PMTopLevelManager::collectLastUses(SmallVector &LastUses, Pass *P) { - DenseMap >::iterator DMI = + DenseMap >::iterator DMI = InversedLastUser.find(P); if (DMI == InversedLastUser.end()) return; @@ -544,7 +538,7 @@ void PMTopLevelManager::collectLastUses(SmallVector &LastUses, AnalysisUsage *PMTopLevelManager::findAnalysisUsage(Pass *P) { AnalysisUsage *AnUsage = NULL; DenseMap::iterator DMI = AnUsageMap.find(P); - if (DMI != AnUsageMap.end()) + if (DMI != AnUsageMap.end()) AnUsage = DMI->second; else { AnUsage = new AnalysisUsage(); @@ -568,8 +562,9 @@ void PMTopLevelManager::schedulePass(Pass *P) { // If P is an analysis pass and it is available then do not // generate the analysis again. Stale analysis info should not be // available at this point. - if (P->getPassInfo() && - P->getPassInfo()->isAnalysis() && findAnalysisPass(P->getPassInfo())) { + const PassInfo *PI = + PassRegistry::getPassRegistry()->getPassInfo(P->getPassID()); + if (PI && PI->isAnalysis() && findAnalysisPass(P->getPassID())) { delete P; return; } @@ -579,14 +574,15 @@ void PMTopLevelManager::schedulePass(Pass *P) { bool checkAnalysis = true; while (checkAnalysis) { checkAnalysis = false; - + const AnalysisUsage::VectorType &RequiredSet = AnUsage->getRequiredSet(); for (AnalysisUsage::VectorType::const_iterator I = RequiredSet.begin(), E = RequiredSet.end(); I != E; ++I) { - + Pass *AnalysisPass = findAnalysisPass(*I); if (!AnalysisPass) { - AnalysisPass = (*I)->createPass(); + const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(*I); + AnalysisPass = PI->createPass(); if (P->getPotentialPassManagerType () == AnalysisPass->getPotentialPassManagerType()) // Schedule analysis pass that is managed by the same pass manager. @@ -595,12 +591,12 @@ void PMTopLevelManager::schedulePass(Pass *P) { AnalysisPass->getPotentialPassManagerType()) { // Schedule analysis pass that is managed by a new manager. schedulePass(AnalysisPass); - // Recheck analysis passes to ensure that required analysises that + // Recheck analysis passes to ensure that required analyses that // are already checked are still available. checkAnalysis = true; } else - // Do not schedule this analysis. Lower level analsyis + // Do not schedule this analysis. Lower level analsyis // passes are run on the fly. delete AnalysisPass; } @@ -632,16 +628,21 @@ Pass *PMTopLevelManager::findAnalysisPass(AnalysisID AID) { for (SmallVector::iterator I = ImmutablePasses.begin(), E = ImmutablePasses.end(); P == NULL && I != E; ++I) { - const PassInfo *PI = (*I)->getPassInfo(); + AnalysisID PI = (*I)->getPassID(); if (PI == AID) P = *I; // If Pass not found then check the interfaces implemented by Immutable Pass if (!P) { + const PassInfo *PassInf = + PassRegistry::getPassRegistry()->getPassInfo(PI); const std::vector &ImmPI = - PI->getInterfacesImplemented(); - if (std::find(ImmPI.begin(), ImmPI.end(), AID) != ImmPI.end()) - P = *I; + PassInf->getInterfacesImplemented(); + for (std::vector::const_iterator II = ImmPI.begin(), + EE = ImmPI.end(); II != EE; ++II) { + if ((*II)->getTypeInfo() == AID) + P = *I; + } } } @@ -658,7 +659,7 @@ void PMTopLevelManager::dumpPasses() const { for (unsigned i = 0, e = ImmutablePasses.size(); i != e; ++i) { ImmutablePasses[i]->dumpPassStructure(0); } - + // Every class that derives from PMDataManager also derives from Pass // (sometimes indirectly), but there's no inheritance relationship // between PMDataManager and Pass, so we have to getAsPass to get @@ -684,15 +685,16 @@ void PMTopLevelManager::initializeAllAnalysisInfo() { for (SmallVector::iterator I = PassManagers.begin(), E = PassManagers.end(); I != E; ++I) (*I)->initializeAnalysisInfo(); - + // Initailize other pass managers - for (SmallVector::iterator I = IndirectPassManagers.begin(), - E = IndirectPassManagers.end(); I != E; ++I) + for (SmallVector::iterator + I = IndirectPassManagers.begin(), E = IndirectPassManagers.end(); + I != E; ++I) (*I)->initializeAnalysisInfo(); for (DenseMap::iterator DMI = LastUser.begin(), DME = LastUser.end(); DMI != DME; ++DMI) { - DenseMap >::iterator InvDMI = + DenseMap >::iterator InvDMI = InversedLastUser.find(DMI->second); if (InvDMI != InversedLastUser.end()) { SmallPtrSet &L = InvDMI->second; @@ -709,7 +711,7 @@ PMTopLevelManager::~PMTopLevelManager() { for (SmallVector::iterator I = PassManagers.begin(), E = PassManagers.end(); I != E; ++I) delete *I; - + for (SmallVector::iterator I = ImmutablePasses.begin(), E = ImmutablePasses.end(); I != E; ++I) delete *I; @@ -724,16 +726,19 @@ PMTopLevelManager::~PMTopLevelManager() { /// Augement AvailableAnalysis by adding analysis made available by pass P. void PMDataManager::recordAvailableAnalysis(Pass *P) { - const PassInfo *PI = P->getPassInfo(); - if (PI == 0) return; - + AnalysisID PI = P->getPassID(); + AvailableAnalysis[PI] = P; - //This pass is the current implementation of all of the interfaces it - //implements as well. - const std::vector &II = PI->getInterfacesImplemented(); + assert(!AvailableAnalysis.empty()); + + // This pass is the current implementation of all of the interfaces it + // implements as well. + const PassInfo *PInf = PassRegistry::getPassRegistry()->getPassInfo(PI); + if (PInf == 0) return; + const std::vector &II = PInf->getInterfacesImplemented(); for (unsigned i = 0, e = II.size(); i != e; ++i) - AvailableAnalysis[II[i]] = P; + AvailableAnalysis[II[i]->getTypeInfo()] = P; } // Return true if P preserves high level analysis used by other @@ -742,18 +747,18 @@ bool PMDataManager::preserveHigherLevelAnalysis(Pass *P) { AnalysisUsage *AnUsage = TPM->findAnalysisUsage(P); if (AnUsage->getPreservesAll()) return true; - + const AnalysisUsage::VectorType &PreservedSet = AnUsage->getPreservedSet(); for (SmallVector::iterator I = HigherLevelAnalysis.begin(), E = HigherLevelAnalysis.end(); I != E; ++I) { Pass *P1 = *I; if (P1->getAsImmutablePass() == 0 && std::find(PreservedSet.begin(), PreservedSet.end(), - P1->getPassInfo()) == + P1->getPassID()) == PreservedSet.end()) return false; } - + return true; } @@ -788,7 +793,7 @@ void PMDataManager::removeNotPreservedAnalysis(Pass *P) { E = AvailableAnalysis.end(); I != E; ) { std::map::iterator Info = I++; if (Info->second->getAsImmutablePass() == 0 && - std::find(PreservedSet.begin(), PreservedSet.end(), Info->first) == + std::find(PreservedSet.begin(), PreservedSet.end(), Info->first) == PreservedSet.end()) { // Remove this analysis if (PassDebugging >= Details) { @@ -807,12 +812,12 @@ void PMDataManager::removeNotPreservedAnalysis(Pass *P) { if (!InheritedAnalysis[Index]) continue; - for (std::map::iterator + for (std::map::iterator I = InheritedAnalysis[Index]->begin(), E = InheritedAnalysis[Index]->end(); I != E; ) { std::map::iterator Info = I++; if (Info->second->getAsImmutablePass() == 0 && - std::find(PreservedSet.begin(), PreservedSet.end(), Info->first) == + std::find(PreservedSet.begin(), PreservedSet.end(), Info->first) == PreservedSet.end()) { // Remove this analysis if (PassDebugging >= Details) { @@ -861,23 +866,24 @@ void PMDataManager::freePass(Pass *P, StringRef Msg, P->releaseMemory(); } - if (const PassInfo *PI = P->getPassInfo()) { + AnalysisID PI = P->getPassID(); + if (const PassInfo *PInf = PassRegistry::getPassRegistry()->getPassInfo(PI)) { // Remove the pass itself (if it is not already removed). AvailableAnalysis.erase(PI); // Remove all interfaces this pass implements, for which it is also // listed as the available implementation. - const std::vector &II = PI->getInterfacesImplemented(); + const std::vector &II = PInf->getInterfacesImplemented(); for (unsigned i = 0, e = II.size(); i != e; ++i) { std::map::iterator Pos = - AvailableAnalysis.find(II[i]); + AvailableAnalysis.find(II[i]->getTypeInfo()); if (Pos != AvailableAnalysis.end() && Pos->second == P) AvailableAnalysis.erase(Pos); } } } -/// Add pass P into the PassVector. Update +/// Add pass P into the PassVector. Update /// AvailableAnalysis appropriately if ProcessAnalysis is true. void PMDataManager::add(Pass *P, bool ProcessAnalysis) { // This manager is going to manage pass P. Set up analysis resolver @@ -902,7 +908,7 @@ void PMDataManager::add(Pass *P, bool ProcessAnalysis) { unsigned PDepth = this->getDepth(); - collectRequiredAnalysis(RequiredPasses, + collectRequiredAnalysis(RequiredPasses, ReqAnalysisNotAvailable, P); for (SmallVector::iterator I = RequiredPasses.begin(), E = RequiredPasses.end(); I != E; ++I) { @@ -920,7 +926,7 @@ void PMDataManager::add(Pass *P, bool ProcessAnalysis) { TransferLastUses.push_back(PRequired); // Keep track of higher level analysis used by this manager. HigherLevelAnalysis.push_back(PRequired); - } else + } else llvm_unreachable("Unable to accomodate Required Pass"); } @@ -937,11 +943,12 @@ void PMDataManager::add(Pass *P, bool ProcessAnalysis) { TransferLastUses.clear(); } - // Now, take care of required analysises that are not available. - for (SmallVector::iterator - I = ReqAnalysisNotAvailable.begin(), + // Now, take care of required analyses that are not available. + for (SmallVector::iterator + I = ReqAnalysisNotAvailable.begin(), E = ReqAnalysisNotAvailable.end() ;I != E; ++I) { - Pass *AnalysisPass = (*I)->createPass(); + const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(*I); + Pass *AnalysisPass = PI->createPass(); this->addLowerLevelRequiredPass(P, AnalysisPass); } @@ -963,10 +970,10 @@ void PMDataManager::collectRequiredAnalysis(SmallVector&RP, Pass *P) { AnalysisUsage *AnUsage = TPM->findAnalysisUsage(P); const AnalysisUsage::VectorType &RequiredSet = AnUsage->getRequiredSet(); - for (AnalysisUsage::VectorType::const_iterator + for (AnalysisUsage::VectorType::const_iterator I = RequiredSet.begin(), E = RequiredSet.end(); I != E; ++I) { if (Pass *AnalysisPass = findAnalysisPass(*I, true)) - RP.push_back(AnalysisPass); + RP.push_back(AnalysisPass); else RP_NotAvail.push_back(*I); } @@ -975,7 +982,7 @@ void PMDataManager::collectRequiredAnalysis(SmallVector&RP, for (AnalysisUsage::VectorType::const_iterator I = IDs.begin(), E = IDs.end(); I != E; ++I) { if (Pass *AnalysisPass = findAnalysisPass(*I, true)) - RP.push_back(AnalysisPass); + RP.push_back(AnalysisPass); else RP_NotAvail.push_back(*I); } @@ -1016,7 +1023,7 @@ Pass *PMDataManager::findAnalysisPass(AnalysisID AID, bool SearchParent) { // Search Parents through TopLevelManager if (SearchParent) return TPM->findAnalysisPass(AID); - + return NULL; } @@ -1030,7 +1037,7 @@ void PMDataManager::dumpLastUses(Pass *P, unsigned Offset) const{ return; TPM->collectLastUses(LUses, P); - + for (SmallVector::iterator I = LUses.begin(), E = LUses.end(); I != E; ++I) { llvm::dbgs() << "--" << std::string(Offset*2, ' '); @@ -1044,7 +1051,8 @@ void PMDataManager::dumpPassArguments() const { if (PMDataManager *PMD = (*I)->getAsPMDataManager()) PMD->dumpPassArguments(); else - if (const PassInfo *PI = (*I)->getPassInfo()) + if (const PassInfo *PI = + PassRegistry::getPassRegistry()->getPassInfo((*I)->getPassID())) if (!PI->isAnalysisGroup()) dbgs() << " -" << PI->getPassArgument(); } @@ -1093,7 +1101,7 @@ void PMDataManager::dumpPassInfo(Pass *P, enum PassDebuggingString S1, void PMDataManager::dumpRequiredSet(const Pass *P) const { if (PassDebugging < Details) return; - + AnalysisUsage analysisUsage; P->getAnalysisUsage(analysisUsage); dumpAnalysisUsage("Required", P, analysisUsage.getRequiredSet()); @@ -1102,7 +1110,7 @@ void PMDataManager::dumpRequiredSet(const Pass *P) const { void PMDataManager::dumpPreservedSet(const Pass *P) const { if (PassDebugging < Details) return; - + AnalysisUsage analysisUsage; P->getAnalysisUsage(analysisUsage); dumpAnalysisUsage("Preserved", P, analysisUsage.getPreservedSet()); @@ -1116,7 +1124,8 @@ void PMDataManager::dumpAnalysisUsage(StringRef Msg, const Pass *P, dbgs() << (void*)P << std::string(getDepth()*2+3, ' ') << Msg << " Analyses:"; for (unsigned i = 0; i != Set.size(); ++i) { if (i) dbgs() << ','; - dbgs() << ' ' << Set[i]->getPassName(); + const PassInfo *PInf = PassRegistry::getPassRegistry()->getPassInfo(Set[i]); + dbgs() << ' ' << PInf->getPassName(); } dbgs() << '\n'; } @@ -1131,14 +1140,14 @@ void PMDataManager::addLowerLevelRequiredPass(Pass *P, Pass *RequiredPass) { TPM->dumpPasses(); } - // Module Level pass may required Function Level analysis info - // (e.g. dominator info). Pass manager uses on the fly function pass manager - // to provide this on demand. In that case, in Pass manager terminology, + // Module Level pass may required Function Level analysis info + // (e.g. dominator info). Pass manager uses on the fly function pass manager + // to provide this on demand. In that case, in Pass manager terminology, // module level pass is requiring lower level analysis info managed by // lower level pass manager. // When Pass manager is not able to order required analysis info, Pass manager - // checks whether any lower level manager will be able to provide this + // checks whether any lower level manager will be able to provide this // analysis info on demand or not. #ifndef NDEBUG dbgs() << "Unable to schedule '" << RequiredPass->getPassName(); @@ -1147,7 +1156,7 @@ void PMDataManager::addLowerLevelRequiredPass(Pass *P, Pass *RequiredPass) { llvm_unreachable("Unable to schedule pass"); } -Pass *PMDataManager::getOnTheFlyPass(Pass *P, const PassInfo *PI, Function &F) { +Pass *PMDataManager::getOnTheFlyPass(Pass *P, AnalysisID PI, Function &F) { assert(0 && "Unable to find on the fly pass"); return NULL; } @@ -1166,7 +1175,7 @@ Pass *AnalysisResolver::getAnalysisIfAvailable(AnalysisID ID, bool dir) const { return PM.findAnalysisPass(ID, dir); } -Pass *AnalysisResolver::findImplPass(Pass *P, const PassInfo *AnalysisPI, +Pass *AnalysisResolver::findImplPass(Pass *P, AnalysisID AnalysisPI, Function &F) { return PM.getOnTheFlyPass(P, AnalysisPI, F); } @@ -1174,8 +1183,8 @@ Pass *AnalysisResolver::findImplPass(Pass *P, const PassInfo *AnalysisPI, //===----------------------------------------------------------------------===// // BBPassManager implementation -/// Execute all of the passes scheduled for execution by invoking -/// runOnBasicBlock method. Keep track of whether any of the passes modifies +/// Execute all of the passes scheduled for execution by invoking +/// runOnBasicBlock method. Keep track of whether any of the passes modifies /// the function, and if so, return true. bool BBPassManager::runOnFunction(Function &F) { if (F.isDeclaration()) @@ -1202,7 +1211,7 @@ bool BBPassManager::runOnFunction(Function &F) { } Changed |= LocalChanged; - if (LocalChanged) + if (LocalChanged) dumpPassInfo(BP, MODIFICATION_MSG, ON_BASICBLOCK_MSG, I->getName()); dumpPreservedSet(BP); @@ -1286,17 +1295,18 @@ void FunctionPassManager::addImpl(Pass *P) { /// PassManager_X is destroyed, the pass will be destroyed as well, so /// there is no need to delete the pass. (TODO delete passes.) /// This implies that all passes MUST be allocated with 'new'. -void FunctionPassManager::add(Pass *P) { +void FunctionPassManager::add(Pass *P) { // If this is a not a function pass, don't add a printer for it. + const void *PassID = P->getPassID(); if (P->getPassKind() == PT_Function) - if (ShouldPrintBeforePass(P)) + if (ShouldPrintBeforePass(PassID)) addImpl(P->createPrinterPass(dbgs(), std::string("*** IR Dump Before ") + P->getPassName() + " ***")); addImpl(P); if (P->getPassKind() == PT_Function) - if (ShouldPrintAfterPass(P)) + if (ShouldPrintAfterPass(PassID)) addImpl(P->createPrinterPass(dbgs(), std::string("*** IR Dump After ") + P->getPassName() + " ***")); } @@ -1405,8 +1415,8 @@ void FPPassManager::dumpPassStructure(unsigned Offset) { } -/// Execute all of the passes scheduled for execution by invoking -/// runOnFunction method. Keep track of whether any of the passes modifies +/// Execute all of the passes scheduled for execution by invoking +/// runOnFunction method. Keep track of whether any of the passes modifies /// the function, and if so, return true. bool FPPassManager::runOnFunction(Function &F) { if (F.isDeclaration()) @@ -1476,8 +1486,8 @@ bool FPPassManager::doFinalization(Module &M) { //===----------------------------------------------------------------------===// // MPPassManager implementation -/// Execute all of the passes scheduled for execution by invoking -/// runOnModule method. Keep track of whether any of the passes modifies +/// Execute all of the passes scheduled for execution by invoking +/// runOnModule method. Keep track of whether any of the passes modifies /// the module, and if so, return true. bool MPPassManager::runOnModule(Module &M) { @@ -1512,7 +1522,7 @@ MPPassManager::runOnModule(Module &M) { dumpPassInfo(MP, MODIFICATION_MSG, ON_MODULE_MSG, M.getModuleIdentifier()); dumpPreservedSet(MP); - + verifyPreservedAnalysis(MP); removeNotPreservedAnalysis(MP); recordAvailableAnalysis(MP); @@ -1538,7 +1548,7 @@ MPPassManager::runOnModule(Module &M) { void MPPassManager::addLowerLevelRequiredPass(Pass *P, Pass *RequiredPass) { assert(P->getPotentialPassManagerType() == PMT_ModulePassManager && "Unable to handle Pass that requires lower level Analysis pass"); - assert((P->getPotentialPassManagerType() < + assert((P->getPotentialPassManagerType() < RequiredPass->getPotentialPassManagerType()) && "Unable to handle Pass that requires lower level Analysis pass"); @@ -1558,13 +1568,13 @@ void MPPassManager::addLowerLevelRequiredPass(Pass *P, Pass *RequiredPass) { FPP->setLastUser(LU, P); } -/// Return function pass corresponding to PassInfo PI, that is +/// Return function pass corresponding to PassInfo PI, that is /// required by module pass MP. Instantiate analysis pass, by using /// its runOnFunction() for function F. -Pass* MPPassManager::getOnTheFlyPass(Pass *MP, const PassInfo *PI, Function &F){ +Pass* MPPassManager::getOnTheFlyPass(Pass *MP, AnalysisID PI, Function &F){ FunctionPassManagerImpl *FPP = OnTheFlyManagers[MP]; assert(FPP && "Unable to find on the fly pass"); - + FPP->releaseMemoryOnTheFly(); FPP->run(F); return ((PMTopLevelManager*)FPP)->findAnalysisPass(PI); @@ -1614,13 +1624,14 @@ void PassManager::addImpl(Pass *P) { /// will be destroyed as well, so there is no need to delete the pass. This /// implies that all passes MUST be allocated with 'new'. void PassManager::add(Pass *P) { - if (ShouldPrintBeforePass(P)) + const void* PassID = P->getPassID(); + if (ShouldPrintBeforePass(PassID)) addImpl(P->createPrinterPass(dbgs(), std::string("*** IR Dump Before ") + P->getPassName() + " ***")); addImpl(P); - if (ShouldPrintAfterPass(P)) + if (ShouldPrintAfterPass(PassID)) addImpl(P->createPrinterPass(dbgs(), std::string("*** IR Dump After ") + P->getPassName() + " ***")); } @@ -1656,7 +1667,7 @@ void TimingInfo::createTheTimeInfo() { /// If TimingInfo is enabled then start pass timer. Timer *llvm::getPassTimer(Pass *P) { - if (TheTimeInfo) + if (TheTimeInfo) return TheTimeInfo->getPassTimer(P); return 0; } @@ -1690,8 +1701,8 @@ void PMStack::push(PMDataManager *PM) { } // Dump content of the pass manager stack. -void PMStack::dump() { - for (std::deque::iterator I = S.begin(), +void PMStack::dump() const { + for (std::vector::const_iterator I = S.begin(), E = S.end(); I != E; ++I) printf("%s ", (*I)->getAsPass()->getPassName()); @@ -1700,11 +1711,11 @@ void PMStack::dump() { } /// Find appropriate Module Pass Manager in the PM Stack and -/// add self into that manager. -void ModulePass::assignPassManager(PMStack &PMS, +/// add self into that manager. +void ModulePass::assignPassManager(PMStack &PMS, PassManagerType PreferredType) { // Find Module Pass Manager - while(!PMS.empty()) { + while (!PMS.empty()) { PassManagerType TopPMType = PMS.top()->getPassManagerType(); if (TopPMType == PreferredType) break; // We found desired pass manager @@ -1718,7 +1729,7 @@ void ModulePass::assignPassManager(PMStack &PMS, } /// Find appropriate Function Pass Manager or Call Graph Pass Manager -/// in the PM Stack and add self into that manager. +/// in the PM Stack and add self into that manager. void FunctionPass::assignPassManager(PMStack &PMS, PassManagerType PreferredType) { @@ -1727,7 +1738,7 @@ void FunctionPass::assignPassManager(PMStack &PMS, if (PMS.top()->getPassManagerType() > PMT_FunctionPassManager) PMS.pop(); else - break; + break; } // Create new Function Pass Manager if needed. @@ -1759,14 +1770,14 @@ void FunctionPass::assignPassManager(PMStack &PMS, } /// Find appropriate Basic Pass Manager or Call Graph Pass Manager -/// in the PM Stack and add self into that manager. +/// in the PM Stack and add self into that manager. void BasicBlockPass::assignPassManager(PMStack &PMS, PassManagerType PreferredType) { BBPassManager *BBP; // Basic Pass Manager is a leaf pass manager. It does not handle // any other pass manager. - if (!PMS.empty() && + if (!PMS.empty() && PMS.top()->getPassManagerType() == PMT_BasicBlockPassManager) { BBP = (BBPassManager *)PMS.top(); } else { @@ -1796,38 +1807,3 @@ void BasicBlockPass::assignPassManager(PMStack &PMS, } PassManagerBase::~PassManagerBase() {} - -/*===-- C Bindings --------------------------------------------------------===*/ - -LLVMPassManagerRef LLVMCreatePassManager() { - return wrap(new PassManager()); -} - -LLVMPassManagerRef LLVMCreateFunctionPassManagerForModule(LLVMModuleRef M) { - return wrap(new FunctionPassManager(unwrap(M))); -} - -LLVMPassManagerRef LLVMCreateFunctionPassManager(LLVMModuleProviderRef P) { - return LLVMCreateFunctionPassManagerForModule( - reinterpret_cast(P)); -} - -LLVMBool LLVMRunPassManager(LLVMPassManagerRef PM, LLVMModuleRef M) { - return unwrap(PM)->run(*unwrap(M)); -} - -LLVMBool LLVMInitializeFunctionPassManager(LLVMPassManagerRef FPM) { - return unwrap(FPM)->doInitialization(); -} - -LLVMBool LLVMRunFunctionPassManager(LLVMPassManagerRef FPM, LLVMValueRef F) { - return unwrap(FPM)->run(*unwrap(F)); -} - -LLVMBool LLVMFinalizeFunctionPassManager(LLVMPassManagerRef FPM) { - return unwrap(FPM)->doFinalization(); -} - -void LLVMDisposePassManager(LLVMPassManagerRef PM) { - delete unwrap(PM); -} diff --git a/lib/VMCore/PassRegistry.cpp b/lib/VMCore/PassRegistry.cpp new file mode 100644 index 0000000..21dba56 --- /dev/null +++ b/lib/VMCore/PassRegistry.cpp @@ -0,0 +1,159 @@ +//===- PassRegistry.cpp - Pass Registration Implementation ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the PassRegistry, with which passes are registered on +// initialization, and supports the PassManager in dependency resolution. +// +//===----------------------------------------------------------------------===// + +#include "llvm/PassRegistry.h" +#include "llvm/PassSupport.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; + +static PassRegistry *PassRegistryObj = 0; +PassRegistry *PassRegistry::getPassRegistry() { + // Use double-checked locking to safely initialize the registrar when + // we're running in multithreaded mode. + PassRegistry* tmp = PassRegistryObj; + if (llvm_is_multithreaded()) { + sys::MemoryFence(); + if (!tmp) { + llvm_acquire_global_lock(); + tmp = PassRegistryObj; + if (!tmp) { + tmp = new PassRegistry(); + sys::MemoryFence(); + PassRegistryObj = tmp; + } + llvm_release_global_lock(); + } + } else if (!tmp) { + PassRegistryObj = new PassRegistry(); + } + + return PassRegistryObj; +} + +namespace { + +// FIXME: We use ManagedCleanup to erase the pass registrar on shutdown. +// Unfortunately, passes are registered with static ctors, and having +// llvm_shutdown clear this map prevents successful ressurection after +// llvm_shutdown is run. Ideally we should find a solution so that we don't +// leak the map, AND can still resurrect after shutdown. +void cleanupPassRegistry(void*) { + if (PassRegistryObj) { + delete PassRegistryObj; + PassRegistryObj = 0; + } +} +ManagedCleanup<&cleanupPassRegistry> registryCleanup ATTRIBUTE_USED; + +} + +const PassInfo *PassRegistry::getPassInfo(const void *TI) const { + sys::SmartScopedLock Guard(Lock); + MapType::const_iterator I = PassInfoMap.find(TI); + return I != PassInfoMap.end() ? I->second : 0; +} + +const PassInfo *PassRegistry::getPassInfo(StringRef Arg) const { + sys::SmartScopedLock Guard(Lock); + StringMapType::const_iterator I = PassInfoStringMap.find(Arg); + return I != PassInfoStringMap.end() ? I->second : 0; +} + +//===----------------------------------------------------------------------===// +// Pass Registration mechanism +// + +void PassRegistry::registerPass(const PassInfo &PI) { + sys::SmartScopedLock Guard(Lock); + bool Inserted = + PassInfoMap.insert(std::make_pair(PI.getTypeInfo(),&PI)).second; + assert(Inserted && "Pass registered multiple times!"); Inserted=Inserted; + PassInfoStringMap[PI.getPassArgument()] = &PI; + + // Notify any listeners. + for (std::vector::iterator + I = Listeners.begin(), E = Listeners.end(); I != E; ++I) + (*I)->passRegistered(&PI); +} + +void PassRegistry::unregisterPass(const PassInfo &PI) { + sys::SmartScopedLock Guard(Lock); + MapType::iterator I = PassInfoMap.find(PI.getTypeInfo()); + assert(I != PassInfoMap.end() && "Pass registered but not in map!"); + + // Remove pass from the map. + PassInfoMap.erase(I); + PassInfoStringMap.erase(PI.getPassArgument()); +} + +void PassRegistry::enumerateWith(PassRegistrationListener *L) { + sys::SmartScopedLock Guard(Lock); + for (MapType::const_iterator I = PassInfoMap.begin(), + E = PassInfoMap.end(); I != E; ++I) + L->passEnumerate(I->second); +} + + +/// Analysis Group Mechanisms. +void PassRegistry::registerAnalysisGroup(const void *InterfaceID, + const void *PassID, + PassInfo& Registeree, + bool isDefault) { + PassInfo *InterfaceInfo = const_cast(getPassInfo(InterfaceID)); + if (InterfaceInfo == 0) { + // First reference to Interface, register it now. + registerPass(Registeree); + InterfaceInfo = &Registeree; + } + assert(Registeree.isAnalysisGroup() && + "Trying to join an analysis group that is a normal pass!"); + + if (PassID) { + PassInfo *ImplementationInfo = const_cast(getPassInfo(PassID)); + assert(ImplementationInfo && + "Must register pass before adding to AnalysisGroup!"); + + // Make sure we keep track of the fact that the implementation implements + // the interface. + ImplementationInfo->addInterfaceImplemented(InterfaceInfo); + + sys::SmartScopedLock Guard(Lock); + AnalysisGroupInfo &AGI = AnalysisGroupInfoMap[InterfaceInfo]; + assert(AGI.Implementations.count(ImplementationInfo) == 0 && + "Cannot add a pass to the same analysis group more than once!"); + AGI.Implementations.insert(ImplementationInfo); + if (isDefault) { + assert(InterfaceInfo->getNormalCtor() == 0 && + "Default implementation for analysis group already specified!"); + assert(ImplementationInfo->getNormalCtor() && + "Cannot specify pass as default if it does not have a default ctor"); + InterfaceInfo->setNormalCtor(ImplementationInfo->getNormalCtor()); + } + } +} + +void PassRegistry::addRegistrationListener(PassRegistrationListener *L) { + sys::SmartScopedLock Guard(Lock); + Listeners.push_back(L); +} + +void PassRegistry::removeRegistrationListener(PassRegistrationListener *L) { + sys::SmartScopedLock Guard(Lock); + std::vector::iterator I = + std::find(Listeners.begin(), Listeners.end(), L); + assert(I != Listeners.end() && "PassRegistrationListener not registered!"); + Listeners.erase(I); +} diff --git a/lib/VMCore/PrintModulePass.cpp b/lib/VMCore/PrintModulePass.cpp index 2d69dce..2ee49d2 100644 --- a/lib/VMCore/PrintModulePass.cpp +++ b/lib/VMCore/PrintModulePass.cpp @@ -28,10 +28,10 @@ namespace { bool DeleteStream; // Delete the ostream in our dtor? public: static char ID; - PrintModulePass() : ModulePass(&ID), Out(&dbgs()), + PrintModulePass() : ModulePass(ID), Out(&dbgs()), DeleteStream(false) {} PrintModulePass(const std::string &B, raw_ostream *o, bool DS) - : ModulePass(&ID), Banner(B), Out(o), DeleteStream(DS) {} + : ModulePass(ID), Banner(B), Out(o), DeleteStream(DS) {} ~PrintModulePass() { if (DeleteStream) delete Out; @@ -53,12 +53,12 @@ namespace { bool DeleteStream; // Delete the ostream in our dtor? public: static char ID; - PrintFunctionPass() : FunctionPass(&ID), Banner(""), Out(&dbgs()), + PrintFunctionPass() : FunctionPass(ID), Banner(""), Out(&dbgs()), DeleteStream(false) {} PrintFunctionPass(const std::string &B, raw_ostream *o, bool DS) - : FunctionPass(&ID), Banner(B), Out(o), DeleteStream(DS) {} + : FunctionPass(ID), Banner(B), Out(o), DeleteStream(DS) {} - inline ~PrintFunctionPass() { + ~PrintFunctionPass() { if (DeleteStream) delete Out; } @@ -77,11 +77,11 @@ namespace { } char PrintModulePass::ID = 0; -static RegisterPass -X("print-module", "Print module to stderr"); +INITIALIZE_PASS(PrintModulePass, "print-module", + "Print module to stderr", false, false); char PrintFunctionPass::ID = 0; -static RegisterPass -Y("print-function","Print function to stderr"); +INITIALIZE_PASS(PrintFunctionPass, "print-function", + "Print function to stderr", false, false); /// createPrintModulePass - Create and return a pass that writes the /// module to the specified raw_ostream. diff --git a/lib/VMCore/Type.cpp b/lib/VMCore/Type.cpp index 845b523..c55e626 100644 --- a/lib/VMCore/Type.cpp +++ b/lib/VMCore/Type.cpp @@ -50,7 +50,7 @@ void AbstractTypeUser::setType(Value *V, const Type *NewTy) { /// Because of the way Type subclasses are allocated, this function is necessary /// to use the correct kind of "delete" operator to deallocate the Type object. -/// Some type objects (FunctionTy, StructTy, UnionTy) allocate additional space +/// Some type objects (FunctionTy, StructTy) allocate additional space /// after the space for their derived type to hold the contained types array of /// PATypeHandles. Using this allocation scheme means all the PATypeHandles are /// allocated with the type object, decreasing allocations and eliminating the @@ -66,8 +66,7 @@ void Type::destroy() const { // Structures and Functions allocate their contained types past the end of // the type object itself. These need to be destroyed differently than the // other types. - if (this->isFunctionTy() || this->isStructTy() || - this->isUnionTy()) { + if (this->isFunctionTy() || this->isStructTy()) { // First, make sure we destruct any PATypeHandles allocated by these // subclasses. They must be manually destructed. for (unsigned i = 0; i < NumContainedTys; ++i) @@ -77,10 +76,10 @@ void Type::destroy() const { // to delete this as an array of char. if (this->isFunctionTy()) static_cast(this)->FunctionType::~FunctionType(); - else if (this->isStructTy()) + else { + assert(isStructTy()); static_cast(this)->StructType::~StructType(); - else - static_cast(this)->UnionType::~UnionType(); + } // Finally, remove the memory as an array deallocation of the chars it was // constructed from. @@ -234,7 +233,7 @@ bool Type::isSizedDerivedType() const { if (const VectorType *PTy = dyn_cast(this)) return PTy->getElementType()->isSized(); - if (!this->isStructTy() && !this->isUnionTy()) + if (!this->isStructTy()) return false; // Okay, our struct is sized if all of the elements are... @@ -319,31 +318,6 @@ const Type *StructType::getTypeAtIndex(unsigned Idx) const { } -bool UnionType::indexValid(const Value *V) const { - // Union indexes require 32-bit integer constants. - if (V->getType()->isIntegerTy(32)) - if (const ConstantInt *CU = dyn_cast(V)) - return indexValid(CU->getZExtValue()); - return false; -} - -bool UnionType::indexValid(unsigned V) const { - return V < NumContainedTys; -} - -// getTypeAtIndex - Given an index value into the type, return the type of the -// element. For a structure type, this must be a constant value... -// -const Type *UnionType::getTypeAtIndex(const Value *V) const { - unsigned Idx = (unsigned)cast(V)->getZExtValue(); - return getTypeAtIndex(Idx); -} - -const Type *UnionType::getTypeAtIndex(unsigned Idx) const { - assert(indexValid(Idx) && "Invalid structure index!"); - return ContainedTys[Idx]; -} - //===----------------------------------------------------------------------===// // Primitive 'Type' data //===----------------------------------------------------------------------===// @@ -455,8 +429,8 @@ const PointerType *Type::getInt64PtrTy(LLVMContext &C, unsigned AS) { /// isValidReturnType - Return true if the specified type is valid as a return /// type. bool FunctionType::isValidReturnType(const Type *RetTy) { - return RetTy->getTypeID() != LabelTyID && - RetTy->getTypeID() != MetadataTyID; + return !RetTy->isFunctionTy() && !RetTy->isLabelTy() && + !RetTy->isMetadataTy(); } /// isValidArgumentType - Return true if the specified type is valid as an @@ -507,23 +481,6 @@ StructType::StructType(LLVMContext &C, setAbstract(isAbstract); } -UnionType::UnionType(LLVMContext &C,const Type* const* Types, unsigned NumTypes) - : CompositeType(C, UnionTyID) { - ContainedTys = reinterpret_cast(this + 1); - NumContainedTys = NumTypes; - bool isAbstract = false; - for (unsigned i = 0; i < NumTypes; ++i) { - assert(Types[i] && " type for union field!"); - assert(isValidElementType(Types[i]) && - "Invalid type for union element!"); - new (&ContainedTys[i]) PATypeHandle(Types[i], this); - isAbstract |= Types[i]->isAbstract(); - } - - // Calculate whether or not this type is abstract - setAbstract(isAbstract); -} - ArrayType::ArrayType(const Type *ElType, uint64_t NumEl) : SequentialType(ArrayTyID, ElType) { NumElements = NumEl; @@ -603,8 +560,8 @@ namespace llvm { static inline ChildIteratorType child_begin(NodeType *N) { if (N->isAbstract()) return N->subtype_begin(); - else // No need to process children of concrete types. - return N->subtype_end(); + // No need to process children of concrete types. + return N->subtype_end(); } static inline ChildIteratorType child_end(NodeType *N) { return N->subtype_end(); @@ -627,35 +584,35 @@ void Type::PromoteAbstractToConcrete() { // Concrete types are leaves in the tree. Since an SCC will either be all // abstract or all concrete, we only need to check one type. - if (SCC[0]->isAbstract()) { - if (SCC[0]->isOpaqueTy()) - return; // Not going to be concrete, sorry. - - // If all of the children of all of the types in this SCC are concrete, - // then this SCC is now concrete as well. If not, neither this SCC, nor - // any parent SCCs will be concrete, so we might as well just exit. - for (unsigned i = 0, e = SCC.size(); i != e; ++i) - for (Type::subtype_iterator CI = SCC[i]->subtype_begin(), - E = SCC[i]->subtype_end(); CI != E; ++CI) - if ((*CI)->isAbstract()) - // If the child type is in our SCC, it doesn't make the entire SCC - // abstract unless there is a non-SCC abstract type. - if (std::find(SCC.begin(), SCC.end(), *CI) == SCC.end()) - return; // Not going to be concrete, sorry. - - // Okay, we just discovered this whole SCC is now concrete, mark it as - // such! - for (unsigned i = 0, e = SCC.size(); i != e; ++i) { - assert(SCC[i]->isAbstract() && "Why are we processing concrete types?"); - - SCC[i]->setAbstract(false); - } - - for (unsigned i = 0, e = SCC.size(); i != e; ++i) { - assert(!SCC[i]->isAbstract() && "Concrete type became abstract?"); - // The type just became concrete, notify all users! - cast(SCC[i])->notifyUsesThatTypeBecameConcrete(); - } + if (!SCC[0]->isAbstract()) continue; + + if (SCC[0]->isOpaqueTy()) + return; // Not going to be concrete, sorry. + + // If all of the children of all of the types in this SCC are concrete, + // then this SCC is now concrete as well. If not, neither this SCC, nor + // any parent SCCs will be concrete, so we might as well just exit. + for (unsigned i = 0, e = SCC.size(); i != e; ++i) + for (Type::subtype_iterator CI = SCC[i]->subtype_begin(), + E = SCC[i]->subtype_end(); CI != E; ++CI) + if ((*CI)->isAbstract()) + // If the child type is in our SCC, it doesn't make the entire SCC + // abstract unless there is a non-SCC abstract type. + if (std::find(SCC.begin(), SCC.end(), *CI) == SCC.end()) + return; // Not going to be concrete, sorry. + + // Okay, we just discovered this whole SCC is now concrete, mark it as + // such! + for (unsigned i = 0, e = SCC.size(); i != e; ++i) { + assert(SCC[i]->isAbstract() && "Why are we processing concrete types?"); + + SCC[i]->setAbstract(false); + } + + for (unsigned i = 0, e = SCC.size(); i != e; ++i) { + assert(!SCC[i]->isAbstract() && "Concrete type became abstract?"); + // The type just became concrete, notify all users! + cast(SCC[i])->notifyUsesThatTypeBecameConcrete(); } } } @@ -693,11 +650,15 @@ static bool TypesEqual(const Type *Ty, const Type *Ty2, if (const IntegerType *ITy = dyn_cast(Ty)) { const IntegerType *ITy2 = cast(Ty2); return ITy->getBitWidth() == ITy2->getBitWidth(); - } else if (const PointerType *PTy = dyn_cast(Ty)) { + } + + if (const PointerType *PTy = dyn_cast(Ty)) { const PointerType *PTy2 = cast(Ty2); return PTy->getAddressSpace() == PTy2->getAddressSpace() && TypesEqual(PTy->getElementType(), PTy2->getElementType(), EqTypes); - } else if (const StructType *STy = dyn_cast(Ty)) { + } + + if (const StructType *STy = dyn_cast(Ty)) { const StructType *STy2 = cast(Ty2); if (STy->getNumElements() != STy2->getNumElements()) return false; if (STy->isPacked() != STy2->isPacked()) return false; @@ -705,22 +666,21 @@ static bool TypesEqual(const Type *Ty, const Type *Ty2, if (!TypesEqual(STy->getElementType(i), STy2->getElementType(i), EqTypes)) return false; return true; - } else if (const UnionType *UTy = dyn_cast(Ty)) { - const UnionType *UTy2 = cast(Ty2); - if (UTy->getNumElements() != UTy2->getNumElements()) return false; - for (unsigned i = 0, e = UTy2->getNumElements(); i != e; ++i) - if (!TypesEqual(UTy->getElementType(i), UTy2->getElementType(i), EqTypes)) - return false; - return true; - } else if (const ArrayType *ATy = dyn_cast(Ty)) { + } + + if (const ArrayType *ATy = dyn_cast(Ty)) { const ArrayType *ATy2 = cast(Ty2); return ATy->getNumElements() == ATy2->getNumElements() && TypesEqual(ATy->getElementType(), ATy2->getElementType(), EqTypes); - } else if (const VectorType *PTy = dyn_cast(Ty)) { + } + + if (const VectorType *PTy = dyn_cast(Ty)) { const VectorType *PTy2 = cast(Ty2); return PTy->getNumElements() == PTy2->getNumElements() && TypesEqual(PTy->getElementType(), PTy2->getElementType(), EqTypes); - } else if (const FunctionType *FTy = dyn_cast(Ty)) { + } + + if (const FunctionType *FTy = dyn_cast(Ty)) { const FunctionType *FTy2 = cast(Ty2); if (FTy->isVarArg() != FTy2->isVarArg() || FTy->getNumParams() != FTy2->getNumParams() || @@ -731,10 +691,10 @@ static bool TypesEqual(const Type *Ty, const Type *Ty2, return false; } return true; - } else { - llvm_unreachable("Unknown derived type!"); - return false; } + + llvm_unreachable("Unknown derived type!"); + return false; } namespace llvm { // in namespace llvm so findable by ADL @@ -808,13 +768,13 @@ const IntegerType *IntegerType::get(LLVMContext &C, unsigned NumBits) { // Check for the built-in integer types switch (NumBits) { - case 1: return cast(Type::getInt1Ty(C)); - case 8: return cast(Type::getInt8Ty(C)); - case 16: return cast(Type::getInt16Ty(C)); - case 32: return cast(Type::getInt32Ty(C)); - case 64: return cast(Type::getInt64Ty(C)); - default: - break; + case 1: return cast(Type::getInt1Ty(C)); + case 8: return cast(Type::getInt8Ty(C)); + case 16: return cast(Type::getInt16Ty(C)); + case 32: return cast(Type::getInt32Ty(C)); + case 64: return cast(Type::getInt64Ty(C)); + default: + break; } LLVMContextImpl *pImpl = C.pImpl; @@ -902,8 +862,8 @@ ArrayType *ArrayType::get(const Type *ElementType, uint64_t NumElements) { } bool ArrayType::isValidElementType(const Type *ElemTy) { - return ElemTy->getTypeID() != VoidTyID && ElemTy->getTypeID() != LabelTyID && - ElemTy->getTypeID() != MetadataTyID && !ElemTy->isFunctionTy(); + return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() && + !ElemTy->isMetadataTy() && !ElemTy->isFunctionTy(); } VectorType *VectorType::get(const Type *ElementType, unsigned NumElements) { @@ -975,60 +935,6 @@ bool StructType::isValidElementType(const Type *ElemTy) { //===----------------------------------------------------------------------===// -// Union Type Factory... -// - -UnionType *UnionType::get(const Type* const* Types, unsigned NumTypes) { - assert(NumTypes > 0 && "union must have at least one member type!"); - UnionValType UTV(Types, NumTypes); - UnionType *UT = 0; - - LLVMContextImpl *pImpl = Types[0]->getContext().pImpl; - - UT = pImpl->UnionTypes.get(UTV); - - if (!UT) { - // Value not found. Derive a new type! - UT = (UnionType*) operator new(sizeof(UnionType) + - sizeof(PATypeHandle) * NumTypes); - new (UT) UnionType(Types[0]->getContext(), Types, NumTypes); - pImpl->UnionTypes.add(UTV, UT); - } -#ifdef DEBUG_MERGE_TYPES - DEBUG(dbgs() << "Derived new type: " << *UT << "\n"); -#endif - return UT; -} - -UnionType *UnionType::get(const Type *type, ...) { - va_list ap; - SmallVector UnionFields; - va_start(ap, type); - while (type) { - UnionFields.push_back(type); - type = va_arg(ap, llvm::Type*); - } - unsigned NumTypes = UnionFields.size(); - assert(NumTypes > 0 && "union must have at least one member type!"); - return llvm::UnionType::get(&UnionFields[0], NumTypes); -} - -bool UnionType::isValidElementType(const Type *ElemTy) { - return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() && - !ElemTy->isMetadataTy() && !ElemTy->isFunctionTy(); -} - -int UnionType::getElementTypeIndex(const Type *ElemTy) const { - int index = 0; - for (UnionType::element_iterator I = element_begin(), E = element_end(); - I != E; ++I, ++index) { - if (ElemTy == *I) return index; - } - - return -1; -} - -//===----------------------------------------------------------------------===// // Pointer Type Factory... // @@ -1060,9 +966,8 @@ const PointerType *Type::getPointerTo(unsigned addrs) const { } bool PointerType::isValidElementType(const Type *ElemTy) { - return ElemTy->getTypeID() != VoidTyID && - ElemTy->getTypeID() != LabelTyID && - ElemTy->getTypeID() != MetadataTyID; + return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() && + !ElemTy->isMetadataTy(); } @@ -1071,8 +976,7 @@ bool PointerType::isValidElementType(const Type *ElemTy) { // OpaqueType *OpaqueType::get(LLVMContext &C) { - OpaqueType *OT = new OpaqueType(C); // All opaque types are distinct - + OpaqueType *OT = new OpaqueType(C); // All opaque types are distinct. LLVMContextImpl *pImpl = C.pImpl; pImpl->OpaqueTypes.insert(OT); return OT; @@ -1123,18 +1027,17 @@ void Type::removeAbstractTypeUser(AbstractTypeUser *U) const { << ">[" << (void*)this << "]" << "\n"); #endif - this->destroy(); + this->destroy(); } - } -// unlockedRefineAbstractTypeTo - This function is used when it is discovered +// refineAbstractTypeTo - This function is used when it is discovered // that the 'this' abstract type is actually equivalent to the NewType // specified. This causes all users of 'this' to switch to reference the more // concrete type NewType and for 'this' to be deleted. Only used for internal // callers. // -void DerivedType::unlockedRefineAbstractTypeTo(const Type *NewType) { +void DerivedType::refineAbstractTypeTo(const Type *NewType) { assert(isAbstract() && "refineAbstractTypeTo: Current type is not abstract!"); assert(this != NewType && "Can't refine to myself!"); assert(ForwardType == 0 && "This type has already been refined!"); @@ -1199,15 +1102,6 @@ void DerivedType::unlockedRefineAbstractTypeTo(const Type *NewType) { // destroyed. } -// refineAbstractTypeTo - This function is used by external callers to notify -// us that this abstract type is equivalent to another type. -// -void DerivedType::refineAbstractTypeTo(const Type *NewType) { - // All recursive calls will go through unlockedRefineAbstractTypeTo, - // to avoid deadlock problems. - unlockedRefineAbstractTypeTo(NewType); -} - // notifyUsesThatTypeBecameConcrete - Notify AbstractTypeUsers of this type that // the current type has transitioned from being abstract to being concrete. // @@ -1291,21 +1185,6 @@ void StructType::typeBecameConcrete(const DerivedType *AbsTy) { // concrete - this could potentially change us from an abstract type to a // concrete type. // -void UnionType::refineAbstractType(const DerivedType *OldType, - const Type *NewType) { - LLVMContextImpl *pImpl = OldType->getContext().pImpl; - pImpl->UnionTypes.RefineAbstractType(this, OldType, NewType); -} - -void UnionType::typeBecameConcrete(const DerivedType *AbsTy) { - LLVMContextImpl *pImpl = AbsTy->getContext().pImpl; - pImpl->UnionTypes.TypeBecameConcrete(this, AbsTy); -} - -// refineAbstractType - Called when a contained type is found to be more -// concrete - this could potentially change us from an abstract type to a -// concrete type. -// void PointerType::refineAbstractType(const DerivedType *OldType, const Type *NewType) { LLVMContextImpl *pImpl = OldType->getContext().pImpl; diff --git a/lib/VMCore/TypesContext.h b/lib/VMCore/TypesContext.h index 02ab113..5a90917 100644 --- a/lib/VMCore/TypesContext.h +++ b/lib/VMCore/TypesContext.h @@ -180,32 +180,6 @@ public: } }; -// UnionValType - Define a class to hold the key that goes into the TypeMap -// -class UnionValType { - std::vector ElTypes; -public: - UnionValType(const Type* const* Types, unsigned NumTypes) - : ElTypes(&Types[0], &Types[NumTypes]) {} - - static UnionValType get(const UnionType *UT) { - std::vector ElTypes; - ElTypes.reserve(UT->getNumElements()); - for (unsigned i = 0, e = UT->getNumElements(); i != e; ++i) - ElTypes.push_back(UT->getElementType(i)); - - return UnionValType(&ElTypes[0], ElTypes.size()); - } - - static unsigned hashTypeStructure(const UnionType *UT) { - return UT->getNumElements(); - } - - inline bool operator<(const UnionValType &UTV) const { - return (ElTypes < UTV.ElTypes); - } -}; - // FunctionValType - Define a class to hold the key that goes into the TypeMap // class FunctionValType { @@ -370,7 +344,7 @@ public: // We already have this type in the table. Get rid of the newly refined // type. TypeClass *NewTy = cast((Type*)I->second.get()); - Ty->unlockedRefineAbstractTypeTo(NewTy); + Ty->refineAbstractTypeTo(NewTy); return; } } else { @@ -385,31 +359,33 @@ public: if (I->second == Ty) { // Remember the position of the old type if we see it in our scan. Entry = I; + continue; + } + + if (!TypesEqual(Ty, I->second)) + continue; + + TypeClass *NewTy = cast((Type*)I->second.get()); + + // Remove the old entry form TypesByHash. If the hash values differ + // now, remove it from the old place. Otherwise, continue scanning + // withing this hashcode to reduce work. + if (NewTypeHash != OldTypeHash) { + RemoveFromTypesByHash(OldTypeHash, Ty); } else { - if (TypesEqual(Ty, I->second)) { - TypeClass *NewTy = cast((Type*)I->second.get()); - - // Remove the old entry form TypesByHash. If the hash values differ - // now, remove it from the old place. Otherwise, continue scanning - // withing this hashcode to reduce work. - if (NewTypeHash != OldTypeHash) { - RemoveFromTypesByHash(OldTypeHash, Ty); - } else { - if (Entry == E) { - // Find the location of Ty in the TypesByHash structure if we - // haven't seen it already. - while (I->second != Ty) { - ++I; - assert(I != E && "Structure doesn't contain type??"); - } - Entry = I; - } - TypesByHash.erase(Entry); + if (Entry == E) { + // Find the location of Ty in the TypesByHash structure if we + // haven't seen it already. + while (I->second != Ty) { + ++I; + assert(I != E && "Structure doesn't contain type??"); } - Ty->unlockedRefineAbstractTypeTo(NewTy); - return; + Entry = I; } + TypesByHash.erase(Entry); } + Ty->refineAbstractTypeTo(NewTy); + return; } // If there is no existing type of the same structure, we reinsert an diff --git a/lib/VMCore/Use.cpp b/lib/VMCore/Use.cpp index b7fd92f..fec710b 100644 --- a/lib/VMCore/Use.cpp +++ b/lib/VMCore/Use.cpp @@ -86,14 +86,27 @@ const Use *Use::getImpliedUser() const { //===----------------------------------------------------------------------===// Use *Use::initTags(Use * const Start, Use *Stop, ptrdiff_t Done) { + while (Done < 20) { + if (Start == Stop--) + return Start; + static const PrevPtrTag tags[20] = { fullStopTag, oneDigitTag, stopTag, + oneDigitTag, oneDigitTag, stopTag, + zeroDigitTag, oneDigitTag, oneDigitTag, + stopTag, zeroDigitTag, oneDigitTag, + zeroDigitTag, oneDigitTag, stopTag, + oneDigitTag, oneDigitTag, oneDigitTag, + oneDigitTag, stopTag + }; + Stop->Prev.setFromOpaqueValue(reinterpret_cast(tags[Done++])); + Stop->Val = 0; + } + ptrdiff_t Count = Done; while (Start != Stop) { --Stop; Stop->Val = 0; if (!Count) { - Stop->Prev.setFromOpaqueValue(reinterpret_cast(Done == 0 - ? fullStopTag - : stopTag)); + Stop->Prev.setFromOpaqueValue(reinterpret_cast(stopTag)); ++Done; Count = Done; } else { diff --git a/lib/VMCore/Value.cpp b/lib/VMCore/Value.cpp index 585edf0..b8c6775 100644 --- a/lib/VMCore/Value.cpp +++ b/lib/VMCore/Value.cpp @@ -139,10 +139,6 @@ static bool getSymTab(Value *V, ValueSymbolTable *&ST) { } else if (Argument *A = dyn_cast(V)) { if (Function *P = A->getParent()) ST = &P->getValueSymbolTable(); - } else if (NamedMDNode *N = dyn_cast(V)) { - if (Module *P = N->getParent()) { - ST = &P->getValueSymbolTable(); - } } else if (isa(V)) return true; else { @@ -492,10 +488,15 @@ void ValueHandleBase::ValueIsDeleted(Value *V) { ValueHandleBase *Entry = pImpl->ValueHandles[V]; assert(Entry && "Value bit set but no entries exist"); - // We use a local ValueHandleBase as an iterator so that - // ValueHandles can add and remove themselves from the list without - // breaking our iteration. This is not really an AssertingVH; we - // just have to give ValueHandleBase some kind. + // We use a local ValueHandleBase as an iterator so that ValueHandles can add + // and remove themselves from the list without breaking our iteration. This + // is not really an AssertingVH; we just have to give ValueHandleBase a kind. + // Note that we deliberately do not the support the case when dropping a value + // handle results in a new value handle being permanently added to the list + // (as might occur in theory for CallbackVH's): the new value handle will not + // be processed and the checking code will mete out righteous punishment if + // the handle is still present once we have finished processing all the other + // value handles (it is fine to momentarily add then remove a value handle). for (ValueHandleBase Iterator(Assert, *Entry); Entry; Entry = Iterator.Next) { Iterator.RemoveFromUseList(); Iterator.AddToExistingUseListAfter(Entry); @@ -576,6 +577,24 @@ void ValueHandleBase::ValueIsRAUWd(Value *Old, Value *New) { break; } } + +#ifndef NDEBUG + // If any new tracking or weak value handles were added while processing the + // list, then complain about it now. + if (Old->HasValueHandle) + for (Entry = pImpl->ValueHandles[Old]; Entry; Entry = Entry->Next) + switch (Entry->getKind()) { + case Tracking: + case Weak: + dbgs() << "After RAUW from " << *Old->getType() << " %" + << Old->getNameStr() << " to " << *New->getType() << " %" + << New->getNameStr() << "\n"; + llvm_unreachable("A tracking or weak value handle still pointed to the" + " old value!\n"); + default: + break; + } +#endif } /// ~CallbackVH. Empty, but defined here to avoid emitting the vtable diff --git a/lib/VMCore/ValueSymbolTable.cpp b/lib/VMCore/ValueSymbolTable.cpp index 449d61a..254bf06 100644 --- a/lib/VMCore/ValueSymbolTable.cpp +++ b/lib/VMCore/ValueSymbolTable.cpp @@ -115,5 +115,3 @@ void ValueSymbolTable::dump() const { //DEBUG(dbgs() << "\n"); } } - -MDSymbolTable::~MDSymbolTable() { } diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp index f97699d..e3ecc97 100644 --- a/lib/VMCore/Verifier.cpp +++ b/lib/VMCore/Verifier.cpp @@ -72,7 +72,7 @@ namespace { // Anonymous namespace for class struct PreVerifier : public FunctionPass { static char ID; // Pass ID, replacement for typeid - PreVerifier() : FunctionPass(&ID) { } + PreVerifier() : FunctionPass(ID) { } virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); @@ -102,9 +102,9 @@ namespace { // Anonymous namespace for class } char PreVerifier::ID = 0; -static RegisterPass -PreVer("preverify", "Preliminary module verification"); -static const PassInfo *const PreVerifyID = &PreVer; +INITIALIZE_PASS(PreVerifier, "preverify", "Preliminary module verification", + false, false); +char &PreVerifyID = PreVerifier::ID; namespace { class TypeSet : public AbstractTypeUser { @@ -182,23 +182,13 @@ namespace { SmallPtrSet MDNodes; Verifier() - : FunctionPass(&ID), + : FunctionPass(ID), Broken(false), RealPass(true), action(AbortProcessAction), Mod(0), Context(0), DT(0), MessagesStr(Messages) {} explicit Verifier(VerifierFailureAction ctn) - : FunctionPass(&ID), + : FunctionPass(ID), Broken(false), RealPass(true), action(ctn), Mod(0), Context(0), DT(0), MessagesStr(Messages) {} - explicit Verifier(bool AB) - : FunctionPass(&ID), - Broken(false), RealPass(true), - action( AB ? AbortProcessAction : PrintMessageAction), Mod(0), - Context(0), DT(0), MessagesStr(Messages) {} - explicit Verifier(DominatorTree &dt) - : FunctionPass(&ID), - Broken(false), RealPass(false), action(PrintMessageAction), Mod(0), - Context(0), DT(&dt), MessagesStr(Messages) {} - bool doInitialization(Module &M) { Mod = &M; @@ -331,6 +321,7 @@ namespace { void visitBranchInst(BranchInst &BI); void visitReturnInst(ReturnInst &RI); void visitSwitchInst(SwitchInst &SI); + void visitIndirectBrInst(IndirectBrInst &BI); void visitSelectInst(SelectInst &SI); void visitUserOp1(Instruction &I); void visitUserOp2(Instruction &I) { visitUserOp1(I); } @@ -402,7 +393,7 @@ namespace { } // End anonymous namespace char Verifier::ID = 0; -static RegisterPass X("verify", "Module Verifier"); +INITIALIZE_PASS(Verifier, "verify", "Module Verifier", false, false); // Assert - We know that cond should be true, if not print an error message. #define Assert(C, M) \ @@ -445,6 +436,10 @@ void Verifier::visitGlobalValue(GlobalValue &GV) { Assert1(GVar && GVar->getType()->getElementType()->isArrayTy(), "Only global arrays can have appending linkage!", GVar); } + + Assert1(!GV.hasLinkerPrivateWeakDefAutoLinkage() || GV.hasDefaultVisibility(), + "linker_private_weak_def_auto can only have default visibility!", + &GV); } void Verifier::visitGlobalVariable(GlobalVariable &GV) { @@ -504,8 +499,8 @@ void Verifier::visitNamedMDNode(NamedMDNode &NMD) { if (!MD) continue; - Assert2(!MD->isFunctionLocal(), - "Named metadata operand cannot be function local!", &NMD, MD); + Assert1(!MD->isFunctionLocal(), + "Named metadata operand cannot be function local!", MD); visitMDNode(*MD, 0); } } @@ -520,7 +515,7 @@ void Verifier::visitMDNode(MDNode &MD, Function *F) { Value *Op = MD.getOperand(i); if (!Op) continue; - if (isa(Op) || isa(Op) || isa(Op)) + if (isa(Op) || isa(Op)) continue; if (MDNode *N = dyn_cast(Op)) { Assert2(MD.isFunctionLocal() || !N->isFunctionLocal(), @@ -864,6 +859,16 @@ void Verifier::visitSwitchInst(SwitchInst &SI) { visitTerminatorInst(SI); } +void Verifier::visitIndirectBrInst(IndirectBrInst &BI) { + Assert1(BI.getAddress()->getType()->isPointerTy(), + "Indirectbr operand must have pointer type!", &BI); + for (unsigned i = 0, e = BI.getNumDestinations(); i != e; ++i) + Assert1(BI.getDestination(i)->getType()->isLabelTy(), + "Indirectbr destinations must all have pointer type!", &BI); + + visitTerminatorInst(BI); +} + void Verifier::visitSelectInst(SelectInst &SI) { Assert1(!SelectInst::areInvalidOperands(SI.getOperand(0), SI.getOperand(1), SI.getOperand(2)), @@ -1202,6 +1207,7 @@ void Verifier::visitCallInst(CallInst &CI) { void Verifier::visitInvokeInst(InvokeInst &II) { VerifyCallSite(&II); + visitTerminatorInst(II); } /// visitBinaryOperator - Check that both arguments to the binary operator are @@ -1266,28 +1272,37 @@ void Verifier::visitBinaryOperator(BinaryOperator &B) { visitInstruction(B); } -void Verifier::visitICmpInst(ICmpInst& IC) { +void Verifier::visitICmpInst(ICmpInst &IC) { // Check that the operands are the same type - const Type* Op0Ty = IC.getOperand(0)->getType(); - const Type* Op1Ty = IC.getOperand(1)->getType(); + const Type *Op0Ty = IC.getOperand(0)->getType(); + const Type *Op1Ty = IC.getOperand(1)->getType(); Assert1(Op0Ty == Op1Ty, "Both operands to ICmp instruction are not of the same type!", &IC); // Check that the operands are the right type Assert1(Op0Ty->isIntOrIntVectorTy() || Op0Ty->isPointerTy(), "Invalid operand types for ICmp instruction", &IC); + // Check that the predicate is valid. + Assert1(IC.getPredicate() >= CmpInst::FIRST_ICMP_PREDICATE && + IC.getPredicate() <= CmpInst::LAST_ICMP_PREDICATE, + "Invalid predicate in ICmp instruction!", &IC); visitInstruction(IC); } -void Verifier::visitFCmpInst(FCmpInst& FC) { +void Verifier::visitFCmpInst(FCmpInst &FC) { // Check that the operands are the same type - const Type* Op0Ty = FC.getOperand(0)->getType(); - const Type* Op1Ty = FC.getOperand(1)->getType(); + const Type *Op0Ty = FC.getOperand(0)->getType(); + const Type *Op1Ty = FC.getOperand(1)->getType(); Assert1(Op0Ty == Op1Ty, "Both operands to FCmp instruction are not of the same type!", &FC); // Check that the operands are the right type Assert1(Op0Ty->isFPOrFPVectorTy(), "Invalid operand types for FCmp instruction", &FC); + // Check that the predicate is valid. + Assert1(FC.getPredicate() >= CmpInst::FIRST_FCMP_PREDICATE && + FC.getPredicate() <= CmpInst::LAST_FCMP_PREDICATE, + "Invalid predicate in FCmp instruction!", &FC); + visitInstruction(FC); } @@ -1310,27 +1325,6 @@ void Verifier::visitShuffleVectorInst(ShuffleVectorInst &SV) { Assert1(ShuffleVectorInst::isValidOperands(SV.getOperand(0), SV.getOperand(1), SV.getOperand(2)), "Invalid shufflevector operands!", &SV); - - const VectorType *VTy = dyn_cast(SV.getOperand(0)->getType()); - Assert1(VTy, "Operands are not a vector type", &SV); - - // Check to see if Mask is valid. - if (const ConstantVector *MV = dyn_cast(SV.getOperand(2))) { - for (unsigned i = 0, e = MV->getNumOperands(); i != e; ++i) { - if (ConstantInt* CI = dyn_cast(MV->getOperand(i))) { - Assert1(!CI->uge(VTy->getNumElements()*2), - "Invalid shufflevector shuffle mask!", &SV); - } else { - Assert1(isa(MV->getOperand(i)), - "Invalid shufflevector shuffle mask!", &SV); - } - } - } else { - Assert1(isa(SV.getOperand(2)) || - isa(SV.getOperand(2)), - "Invalid shufflevector shuffle mask!", &SV); - } - visitInstruction(SV); } @@ -1408,10 +1402,6 @@ void Verifier::visitInstruction(Instruction &I) { "Only PHI nodes may reference their own value!", &I); } - // Verify that if this is a terminator that it is at the end of the block. - if (isa(I)) - Assert1(BB->getTerminator() == &I, "Terminator not at end of block!", &I); - // Check that void typed values don't have names Assert1(!I.getType()->isVoidTy() || !I.hasName(), "Instruction has a name, but provides a void value!", &I); @@ -1570,7 +1560,8 @@ void Verifier::VerifyType(const Type *Ty) { "Function type with invalid parameter type", ElTy, FTy); VerifyType(ElTy); } - } break; + break; + } case Type::StructTyID: { const StructType *STy = cast(Ty); for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { @@ -1579,34 +1570,29 @@ void Verifier::VerifyType(const Type *Ty) { "Structure type with invalid element type", ElTy, STy); VerifyType(ElTy); } - } break; - case Type::UnionTyID: { - const UnionType *UTy = cast(Ty); - for (unsigned i = 0, e = UTy->getNumElements(); i != e; ++i) { - const Type *ElTy = UTy->getElementType(i); - Assert2(UnionType::isValidElementType(ElTy), - "Union type with invalid element type", ElTy, UTy); - VerifyType(ElTy); - } - } break; + break; + } case Type::ArrayTyID: { const ArrayType *ATy = cast(Ty); Assert1(ArrayType::isValidElementType(ATy->getElementType()), "Array type with invalid element type", ATy); VerifyType(ATy->getElementType()); - } break; + break; + } case Type::PointerTyID: { const PointerType *PTy = cast(Ty); Assert1(PointerType::isValidElementType(PTy->getElementType()), "Pointer type with invalid element type", PTy); VerifyType(PTy->getElementType()); - } break; + break; + } case Type::VectorTyID: { const VectorType *VTy = cast(Ty); Assert1(VectorType::isValidElementType(VTy->getElementType()), "Vector type with invalid element type", VTy); VerifyType(VTy->getElementType()); - } break; + break; + } default: break; } @@ -1832,8 +1818,13 @@ bool Verifier::PerformTypeCheck(Intrinsic::ID ID, Function *F, const Type *Ty, // and iPTR. In the verifier, we can not distinguish which case we have so // allow either case to be legal. if (const PointerType* PTyp = dyn_cast(Ty)) { - Suffix += ".p" + utostr(PTyp->getAddressSpace()) + - EVT::getEVT(PTyp->getElementType()).getEVTString(); + EVT PointeeVT = EVT::getEVT(PTyp->getElementType(), true); + if (PointeeVT == MVT::Other) { + CheckFailed("Intrinsic has pointer to complex type."); + return false; + } + Suffix += ".p" + utostr(PTyp->getAddressSpace()) + + PointeeVT.getEVTString(); } else { CheckFailed(IntrinsicParam(ArgNo, NumRetVals) + " is not a " "pointer and a pointer is required.", F); -- cgit v1.1 From 36c49e3f258dced101949edabd72e9bc3f1dedc4 Mon Sep 17 00:00:00 2001 From: dim Date: Fri, 17 Sep 2010 15:54:40 +0000 Subject: Vendor import of clang r114020 (from the release_28 branch): http://llvm.org/svn/llvm-project/cfe/branches/release_28@114020 Approved by: rpaulo (mentor) --- lib/AST/ASTConsumer.cpp | 3 + lib/AST/ASTContext.cpp | 595 +- lib/AST/ASTDiagnostic.cpp | 11 +- lib/AST/ASTImporter.cpp | 104 +- lib/AST/AttrImpl.cpp | 196 +- lib/AST/CMakeLists.txt | 4 +- lib/AST/CXXABI.h | 39 + lib/AST/Decl.cpp | 272 +- lib/AST/DeclBase.cpp | 251 +- lib/AST/DeclCXX.cpp | 109 +- lib/AST/DeclGroup.cpp | 6 - lib/AST/DeclObjC.cpp | 183 +- lib/AST/DeclPrinter.cpp | 19 +- lib/AST/DeclTemplate.cpp | 174 +- lib/AST/DeclarationName.cpp | 116 +- lib/AST/Expr.cpp | 589 +- lib/AST/ExprCXX.cpp | 329 +- lib/AST/ExprClassification.cpp | 34 +- lib/AST/ExprConstant.cpp | 505 +- lib/AST/FullExpr.cpp | 13 - lib/AST/ItaniumCXXABI.cpp | 52 + lib/AST/Makefile | 1 - lib/AST/MicrosoftCXXABI.cpp | 48 + lib/AST/NestedNameSpecifier.cpp | 5 - lib/AST/ParentMap.cpp | 2 +- lib/AST/RecordLayout.cpp | 4 +- lib/AST/RecordLayoutBuilder.cpp | 113 +- lib/AST/Stmt.cpp | 94 +- lib/AST/StmtDumper.cpp | 38 +- lib/AST/StmtPrinter.cpp | 92 +- lib/AST/StmtProfile.cpp | 107 +- lib/AST/TemplateBase.cpp | 17 +- lib/AST/Type.cpp | 157 +- lib/AST/TypeLoc.cpp | 14 - lib/AST/TypePrinter.cpp | 9 +- lib/Analysis/AnalysisContext.cpp | 45 +- lib/Analysis/CFG.cpp | 164 +- lib/Analysis/CFGStmtMap.cpp | 88 + lib/Analysis/CMakeLists.txt | 4 + lib/Analysis/FormatString.cpp | 474 ++ lib/Analysis/FormatStringParsing.h | 72 + lib/Analysis/LiveVariables.cpp | 24 +- lib/Analysis/Makefile | 1 - lib/Analysis/PrintfFormatString.cpp | 572 +- lib/Analysis/PseudoConstantAnalysis.cpp | 238 + lib/Analysis/ReachableCode.cpp | 2 +- lib/Analysis/ScanfFormatString.cpp | 221 + lib/Analysis/UninitializedValues.cpp | 4 +- lib/Basic/Builtins.cpp | 20 + lib/Basic/Diagnostic.cpp | 64 +- lib/Basic/FileManager.cpp | 16 + lib/Basic/IdentifierTable.cpp | 12 +- lib/Basic/Makefile | 1 - lib/Basic/SourceManager.cpp | 34 +- lib/Basic/TargetInfo.cpp | 22 +- lib/Basic/Targets.cpp | 84 +- lib/Basic/Version.cpp | 2 +- lib/CMakeLists.txt | 2 + lib/Checker/AdjustedReturnValueChecker.cpp | 3 +- lib/Checker/AggExprVisitor.cpp | 11 +- lib/Checker/AnalysisConsumer.cpp | 12 +- lib/Checker/AnalysisManager.cpp | 31 + lib/Checker/ArrayBoundChecker.cpp | 2 +- lib/Checker/BasicObjCFoundationChecks.cpp | 5 +- lib/Checker/BasicStore.cpp | 63 +- lib/Checker/BasicValueFactory.cpp | 32 +- lib/Checker/BugReporter.cpp | 51 +- lib/Checker/BugReporterVisitors.cpp | 49 +- lib/Checker/CFRefCount.cpp | 202 +- lib/Checker/CMakeLists.txt | 4 +- lib/Checker/CStringChecker.cpp | 594 +- lib/Checker/CallAndMessageChecker.cpp | 2 +- lib/Checker/CallInliner.cpp | 54 - lib/Checker/CastSizeChecker.cpp | 4 + lib/Checker/CheckDeadStores.cpp | 4 +- lib/Checker/CheckSecuritySyntaxOnly.cpp | 16 +- lib/Checker/CheckerHelpers.cpp | 80 + lib/Checker/CocoaConventions.cpp | 5 +- lib/Checker/DivZeroChecker.cpp | 8 +- lib/Checker/Environment.cpp | 41 +- lib/Checker/FixedAddressChecker.cpp | 2 +- lib/Checker/FlatStore.cpp | 82 +- lib/Checker/GRCXXExprEngine.cpp | 34 +- lib/Checker/GRCoreEngine.cpp | 154 +- lib/Checker/GRExprEngine.cpp | 678 +- lib/Checker/GRExprEngineExperimentalChecks.cpp | 16 +- lib/Checker/GRExprEngineExperimentalChecks.h | 5 +- lib/Checker/GRState.cpp | 224 +- lib/Checker/IdempotentOperationChecker.cpp | 673 +- lib/Checker/LLVMConventionsChecker.cpp | 1 - lib/Checker/Makefile | 1 - lib/Checker/MallocChecker.cpp | 251 +- lib/Checker/MemRegion.cpp | 69 +- lib/Checker/OSAtomicChecker.cpp | 8 +- lib/Checker/PointerArithChecker.cpp | 3 +- lib/Checker/PointerSubChecker.cpp | 2 +- lib/Checker/RangeConstraintManager.cpp | 1 - lib/Checker/RegionStore.cpp | 356 +- lib/Checker/ReturnPointerRangeChecker.cpp | 2 +- lib/Checker/ReturnUndefChecker.cpp | 1 + lib/Checker/SVals.cpp | 7 +- lib/Checker/SValuator.cpp | 4 +- lib/Checker/SimpleConstraintManager.cpp | 70 +- lib/Checker/SimpleConstraintManager.h | 4 - lib/Checker/SimpleSValuator.cpp | 284 +- lib/Checker/StackAddrLeakChecker.cpp | 2 +- lib/Checker/Store.cpp | 41 +- lib/Checker/StreamChecker.cpp | 197 +- lib/Checker/SymbolManager.cpp | 139 +- lib/Checker/UndefBranchChecker.cpp | 17 +- lib/Checker/UndefinedAssignmentChecker.cpp | 12 +- lib/Checker/UnixAPIChecker.cpp | 2 +- lib/Checker/UnreachableCodeChecker.cpp | 226 + lib/Checker/VLASizeChecker.cpp | 2 +- lib/Checker/ValueManager.cpp | 17 +- lib/CodeGen/ABIInfo.h | 106 +- lib/CodeGen/CGBlocks.cpp | 197 +- lib/CodeGen/CGBlocks.h | 18 +- lib/CodeGen/CGBuiltin.cpp | 388 +- lib/CodeGen/CGCXX.cpp | 190 +- lib/CodeGen/CGCXXABI.h | 200 +- lib/CodeGen/CGCall.cpp | 481 +- lib/CodeGen/CGClass.cpp | 450 +- lib/CodeGen/CGDebugInfo.cpp | 477 +- lib/CodeGen/CGDebugInfo.h | 51 +- lib/CodeGen/CGDecl.cpp | 164 +- lib/CodeGen/CGDeclCXX.cpp | 72 +- lib/CodeGen/CGException.cpp | 578 +- lib/CodeGen/CGException.h | 313 +- lib/CodeGen/CGExpr.cpp | 501 +- lib/CodeGen/CGExprAgg.cpp | 201 +- lib/CodeGen/CGExprCXX.cpp | 860 ++- lib/CodeGen/CGExprComplex.cpp | 4 +- lib/CodeGen/CGExprConstant.cpp | 125 +- lib/CodeGen/CGExprScalar.cpp | 463 +- lib/CodeGen/CGObjC.cpp | 15 +- lib/CodeGen/CGObjCGNU.cpp | 64 +- lib/CodeGen/CGObjCMac.cpp | 993 ++- lib/CodeGen/CGObjCRuntime.h | 13 +- lib/CodeGen/CGRTTI.cpp | 192 +- lib/CodeGen/CGRecordLayout.h | 28 +- lib/CodeGen/CGRecordLayoutBuilder.cpp | 81 +- lib/CodeGen/CGStmt.cpp | 131 +- lib/CodeGen/CGTemporaries.cpp | 86 +- lib/CodeGen/CGVTT.cpp | 3 +- lib/CodeGen/CGVTables.cpp | 92 +- lib/CodeGen/CGValue.h | 71 +- lib/CodeGen/CodeGenFunction.cpp | 1125 +-- lib/CodeGen/CodeGenFunction.h | 321 +- lib/CodeGen/CodeGenModule.cpp | 454 +- lib/CodeGen/CodeGenModule.h | 77 +- lib/CodeGen/CodeGenTypes.cpp | 39 +- lib/CodeGen/CodeGenTypes.h | 28 +- lib/CodeGen/ItaniumCXXABI.cpp | 992 ++- lib/CodeGen/Makefile | 1 - lib/CodeGen/Mangle.cpp | 120 +- lib/CodeGen/MicrosoftCXXABI.cpp | 37 +- lib/CodeGen/TargetInfo.cpp | 1183 +-- lib/CodeGen/TargetInfo.h | 10 + lib/Driver/Compilation.cpp | 12 - lib/Driver/Driver.cpp | 126 +- lib/Driver/HostInfo.cpp | 177 +- lib/Driver/InputInfo.h | 15 +- lib/Driver/Job.cpp | 12 +- lib/Driver/Makefile | 1 - lib/Driver/OptTable.cpp | 2 + lib/Driver/Option.cpp | 2 +- lib/Driver/ToolChain.cpp | 140 + lib/Driver/ToolChains.cpp | 265 +- lib/Driver/ToolChains.h | 50 +- lib/Driver/Tools.cpp | 500 +- lib/Driver/Tools.h | 95 +- lib/Frontend/ASTConsumers.cpp | 2 +- lib/Frontend/ASTMerge.cpp | 8 +- lib/Frontend/ASTUnit.cpp | 1586 +++- lib/Frontend/CMakeLists.txt | 8 - lib/Frontend/CacheTokens.cpp | 13 +- lib/Frontend/CompilerInstance.cpp | 127 +- lib/Frontend/CompilerInvocation.cpp | 111 +- lib/Frontend/DependencyFile.cpp | 1 - lib/Frontend/DiagChecker.cpp | 2 +- lib/Frontend/FrontendAction.cpp | 36 +- lib/Frontend/FrontendActions.cpp | 88 +- lib/Frontend/GeneratePCH.cpp | 83 - lib/Frontend/InitHeaderSearch.cpp | 42 +- lib/Frontend/InitPreprocessor.cpp | 33 +- lib/Frontend/Makefile | 1 - lib/Frontend/PCHReader.cpp | 3469 --------- lib/Frontend/PCHReaderDecl.cpp | 1484 ---- lib/Frontend/PCHReaderStmt.cpp | 1727 ----- lib/Frontend/PCHWriter.cpp | 2748 ------- lib/Frontend/PCHWriterDecl.cpp | 1172 --- lib/Frontend/PCHWriterStmt.cpp | 1345 ---- lib/Frontend/PrintParserCallbacks.cpp | 852 -- lib/Frontend/PrintPreprocessedOutput.cpp | 59 +- lib/Frontend/StmtXML.cpp | 4 +- lib/Frontend/TextDiagnosticPrinter.cpp | 46 +- lib/Frontend/VerifyDiagnosticsClient.cpp | 14 +- lib/FrontendTool/CMakeLists.txt | 5 + lib/FrontendTool/ExecuteCompilerInvocation.cpp | 155 + lib/FrontendTool/Makefile | 13 + lib/Headers/CMakeLists.txt | 3 + lib/Headers/Makefile | 1 + lib/Headers/altivec.h | 9858 +++++++++++++++++------- lib/Headers/avxintrin.h | 1156 +++ lib/Headers/emmintrin.h | 9 +- lib/Headers/immintrin.h | 59 + lib/Headers/mmintrin.h | 58 + lib/Headers/nmmintrin.h | 44 +- lib/Headers/smmintrin.h | 12 +- lib/Headers/stddef.h | 3 +- lib/Headers/x86intrin.h | 31 + lib/Headers/xmmintrin.h | 51 +- lib/Index/CMakeLists.txt | 1 - lib/Index/Entity.cpp | 4 +- lib/Index/Makefile | 1 - lib/Index/ResolveLocation.cpp | 602 -- lib/Lex/Lexer.cpp | 292 +- lib/Lex/LiteralSupport.cpp | 44 +- lib/Lex/MacroInfo.cpp | 19 + lib/Lex/Makefile | 1 - lib/Lex/PPDirectives.cpp | 51 +- lib/Lex/PPExpressions.cpp | 19 +- lib/Lex/PPMacroExpansion.cpp | 24 +- lib/Lex/PTHLexer.cpp | 30 +- lib/Lex/Pragma.cpp | 270 +- lib/Lex/PreprocessingRecord.cpp | 3 +- lib/Lex/Preprocessor.cpp | 29 +- lib/Lex/TokenLexer.cpp | 18 +- lib/Makefile | 2 +- lib/Parse/AttributeList.cpp | 130 - lib/Parse/CMakeLists.txt | 6 +- lib/Parse/DeclSpec.cpp | 595 -- lib/Parse/Makefile | 1 - lib/Parse/MinimalAction.cpp | 281 - lib/Parse/ParseAST.cpp | 114 + lib/Parse/ParseCXXInlineMethods.cpp | 24 +- lib/Parse/ParseDecl.cpp | 369 +- lib/Parse/ParseDeclCXX.cpp | 308 +- lib/Parse/ParseExpr.cpp | 323 +- lib/Parse/ParseExprCXX.cpp | 180 +- lib/Parse/ParseInit.cpp | 48 +- lib/Parse/ParseObjc.cpp | 420 +- lib/Parse/ParsePragma.cpp | 120 +- lib/Parse/ParsePragma.h | 39 +- lib/Parse/ParseStmt.cpp | 282 +- lib/Parse/ParseTemplate.cpp | 121 +- lib/Parse/ParseTentative.cpp | 37 +- lib/Parse/Parser.cpp | 149 +- lib/Rewrite/CMakeLists.txt | 6 + lib/Rewrite/DeltaTree.cpp | 10 +- lib/Rewrite/FixItRewriter.cpp | 29 +- lib/Rewrite/FrontendActions.cpp | 21 +- lib/Rewrite/HTMLRewrite.cpp | 3 +- lib/Rewrite/Makefile | 1 - lib/Rewrite/RewriteObjC.cpp | 388 +- lib/Sema/AnalysisBasedWarnings.cpp | 39 +- lib/Sema/AnalysisBasedWarnings.h | 55 - lib/Sema/AttributeList.cpp | 136 + lib/Sema/CMakeLists.txt | 3 +- lib/Sema/CXXFieldCollector.h | 79 - lib/Sema/CodeCompleteConsumer.cpp | 233 +- lib/Sema/DeclSpec.cpp | 667 ++ lib/Sema/IdentifierResolver.cpp | 35 +- lib/Sema/IdentifierResolver.h | 203 - lib/Sema/JumpDiagnostics.cpp | 29 +- lib/Sema/Lookup.h | 654 -- lib/Sema/Makefile | 1 - lib/Sema/ParseAST.cpp | 125 - lib/Sema/Sema.cpp | 261 +- lib/Sema/Sema.h | 4655 ----------- lib/Sema/SemaAccess.cpp | 218 +- lib/Sema/SemaAttr.cpp | 135 +- lib/Sema/SemaCXXCast.cpp | 183 +- lib/Sema/SemaCXXScopeSpec.cpp | 42 +- lib/Sema/SemaChecking.cpp | 870 ++- lib/Sema/SemaCodeComplete.cpp | 2077 +++-- lib/Sema/SemaDecl.cpp | 1400 ++-- lib/Sema/SemaDeclAttr.cpp | 453 +- lib/Sema/SemaDeclCXX.cpp | 1068 +-- lib/Sema/SemaDeclObjC.cpp | 442 +- lib/Sema/SemaExceptionSpec.cpp | 10 +- lib/Sema/SemaExpr.cpp | 1704 ++-- lib/Sema/SemaExprCXX.cpp | 604 +- lib/Sema/SemaExprObjC.cpp | 136 +- lib/Sema/SemaInit.cpp | 383 +- lib/Sema/SemaInit.h | 765 -- lib/Sema/SemaLookup.cpp | 168 +- lib/Sema/SemaObjCProperty.cpp | 175 +- lib/Sema/SemaOverload.cpp | 1374 ++-- lib/Sema/SemaOverload.h | 617 -- lib/Sema/SemaStmt.cpp | 382 +- lib/Sema/SemaTemplate.cpp | 550 +- lib/Sema/SemaTemplate.h | 151 - lib/Sema/SemaTemplateDeduction.cpp | 191 +- lib/Sema/SemaTemplateInstantiate.cpp | 87 +- lib/Sema/SemaTemplateInstantiateDecl.cpp | 397 +- lib/Sema/SemaType.cpp | 154 +- lib/Sema/TargetAttributesSema.cpp | 17 +- lib/Sema/TargetAttributesSema.h | 2 +- lib/Sema/TreeTransform.h | 2028 +++-- lib/Serialization/ASTCommon.cpp | 69 + lib/Serialization/ASTCommon.h | 50 + lib/Serialization/ASTReader.cpp | 4147 ++++++++++ lib/Serialization/ASTReaderDecl.cpp | 1462 ++++ lib/Serialization/ASTReaderStmt.cpp | 1766 +++++ lib/Serialization/ASTWriter.cpp | 3119 ++++++++ lib/Serialization/ASTWriterDecl.cpp | 1202 +++ lib/Serialization/ASTWriterStmt.cpp | 1361 ++++ lib/Serialization/CMakeLists.txt | 23 + lib/Serialization/GeneratePCH.cpp | 64 + lib/Serialization/Makefile | 19 + 312 files changed, 52093 insertions(+), 41804 deletions(-) create mode 100644 lib/AST/CXXABI.h create mode 100644 lib/AST/ItaniumCXXABI.cpp create mode 100644 lib/AST/MicrosoftCXXABI.cpp create mode 100644 lib/Analysis/CFGStmtMap.cpp create mode 100644 lib/Analysis/FormatString.cpp create mode 100644 lib/Analysis/FormatStringParsing.h create mode 100644 lib/Analysis/PseudoConstantAnalysis.cpp create mode 100644 lib/Analysis/ScanfFormatString.cpp create mode 100644 lib/Checker/AnalysisManager.cpp delete mode 100644 lib/Checker/CallInliner.cpp create mode 100644 lib/Checker/CheckerHelpers.cpp create mode 100644 lib/Checker/UnreachableCodeChecker.cpp delete mode 100644 lib/Frontend/GeneratePCH.cpp delete mode 100644 lib/Frontend/PCHReader.cpp delete mode 100644 lib/Frontend/PCHReaderDecl.cpp delete mode 100644 lib/Frontend/PCHReaderStmt.cpp delete mode 100644 lib/Frontend/PCHWriter.cpp delete mode 100644 lib/Frontend/PCHWriterDecl.cpp delete mode 100644 lib/Frontend/PCHWriterStmt.cpp delete mode 100644 lib/Frontend/PrintParserCallbacks.cpp create mode 100644 lib/FrontendTool/CMakeLists.txt create mode 100644 lib/FrontendTool/ExecuteCompilerInvocation.cpp create mode 100644 lib/FrontendTool/Makefile create mode 100644 lib/Headers/avxintrin.h create mode 100644 lib/Headers/immintrin.h create mode 100644 lib/Headers/x86intrin.h delete mode 100644 lib/Index/ResolveLocation.cpp delete mode 100644 lib/Parse/AttributeList.cpp delete mode 100644 lib/Parse/DeclSpec.cpp delete mode 100644 lib/Parse/MinimalAction.cpp create mode 100644 lib/Parse/ParseAST.cpp delete mode 100644 lib/Sema/AnalysisBasedWarnings.h create mode 100644 lib/Sema/AttributeList.cpp delete mode 100644 lib/Sema/CXXFieldCollector.h create mode 100644 lib/Sema/DeclSpec.cpp delete mode 100644 lib/Sema/IdentifierResolver.h delete mode 100644 lib/Sema/Lookup.h delete mode 100644 lib/Sema/ParseAST.cpp delete mode 100644 lib/Sema/Sema.h delete mode 100644 lib/Sema/SemaInit.h delete mode 100644 lib/Sema/SemaOverload.h delete mode 100644 lib/Sema/SemaTemplate.h create mode 100644 lib/Serialization/ASTCommon.cpp create mode 100644 lib/Serialization/ASTCommon.h create mode 100644 lib/Serialization/ASTReader.cpp create mode 100644 lib/Serialization/ASTReaderDecl.cpp create mode 100644 lib/Serialization/ASTReaderStmt.cpp create mode 100644 lib/Serialization/ASTWriter.cpp create mode 100644 lib/Serialization/ASTWriterDecl.cpp create mode 100644 lib/Serialization/ASTWriterStmt.cpp create mode 100644 lib/Serialization/CMakeLists.txt create mode 100644 lib/Serialization/GeneratePCH.cpp create mode 100644 lib/Serialization/Makefile (limited to 'lib') diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp index f37cbde..04a084a 100644 --- a/lib/AST/ASTConsumer.cpp +++ b/lib/AST/ASTConsumer.cpp @@ -17,3 +17,6 @@ using namespace clang; void ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) {} +void ASTConsumer::HandleInterestingDecl(DeclGroupRef D) { + HandleTopLevelDecl(D); +} diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index d41051f..4591a0f 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -28,6 +28,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" +#include "CXXABI.h" using namespace clang; @@ -134,11 +135,25 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( return CanonTTP; } +CXXABI *ASTContext::createCXXABI(const TargetInfo &T) { + if (!LangOpts.CPlusPlus) return 0; + + switch (T.getCXXABI()) { + case CXXABI_ARM: + return CreateARMCXXABI(*this); + case CXXABI_Itanium: + return CreateItaniumCXXABI(*this); + case CXXABI_Microsoft: + return CreateMicrosoftCXXABI(*this); + } + return 0; +} + ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, const TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, Builtin::Context &builtins, - bool FreeMem, unsigned size_reserve) : + unsigned size_reserve) : TemplateSpecializationTypes(this_()), DependentTemplateSpecializationTypes(this_()), GlobalNestedNameSpecifier(0), IsInt128Installed(false), @@ -146,7 +161,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), NullTypeSourceInfo(QualType()), - SourceMgr(SM), LangOpts(LOpts), FreeMemory(FreeMem), Target(t), + SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)), Target(t), Idents(idents), Selectors(sels), BuiltinInfo(builtins), DeclarationNames(*this), @@ -155,7 +170,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, UniqueBlockByRefTypeID(0), UniqueBlockParmTypeID(0) { ObjCIdRedefinitionType = QualType(); ObjCClassRedefinitionType = QualType(); - ObjCSelRedefinitionType = QualType(); + ObjCSelRedefinitionType = QualType(); if (size_reserve > 0) Types.reserve(size_reserve); TUDecl = TranslationUnitDecl::Create(*this); InitBuiltinTypes(); @@ -166,11 +181,9 @@ ASTContext::~ASTContext() { // FIXME: Is this the ideal solution? ReleaseDeclContextMaps(); - if (!FreeMemory) { - // Call all of the deallocation functions. - for (unsigned I = 0, N = Deallocations.size(); I != N; ++I) - Deallocations[I].first(Deallocations[I].second); - } + // Call all of the deallocation functions. + for (unsigned I = 0, N = Deallocations.size(); I != N; ++I) + Deallocations[I].first(Deallocations[I].second); // Release all of the memory associated with overridden C++ methods. for (llvm::DenseMap::iterator @@ -178,51 +191,26 @@ ASTContext::~ASTContext() { OM != OMEnd; ++OM) OM->second.Destroy(); - if (FreeMemory) { - // Deallocate all the types. - while (!Types.empty()) { - Types.back()->Destroy(*this); - Types.pop_back(); - } - - for (llvm::FoldingSet::iterator - I = ExtQualNodes.begin(), E = ExtQualNodes.end(); I != E; ) { - // Increment in loop to prevent using deallocated memory. - Deallocate(&*I++); - } - - for (llvm::DenseMap::iterator - I = ObjCLayouts.begin(), E = ObjCLayouts.end(); I != E; ) { - // Increment in loop to prevent using deallocated memory. - if (ASTRecordLayout *R = const_cast((I++)->second)) - R->Destroy(*this); - } - } - // ASTRecordLayout objects in ASTRecordLayouts must always be destroyed - // even when using the BumpPtrAllocator because they can contain - // DenseMaps. - for (llvm::DenseMap::iterator - I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); I != E; ) { + // because they can contain DenseMaps. + for (llvm::DenseMap::iterator + I = ObjCLayouts.begin(), E = ObjCLayouts.end(); I != E; ) // Increment in loop to prevent using deallocated memory. if (ASTRecordLayout *R = const_cast((I++)->second)) R->Destroy(*this); - } - // Destroy nested-name-specifiers. - for (llvm::FoldingSet::iterator - NNS = NestedNameSpecifiers.begin(), - NNSEnd = NestedNameSpecifiers.end(); - NNS != NNSEnd; ) { + for (llvm::DenseMap::iterator + I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); I != E; ) { // Increment in loop to prevent using deallocated memory. - (*NNS++).Destroy(*this); + if (ASTRecordLayout *R = const_cast((I++)->second)) + R->Destroy(*this); } - - if (GlobalNestedNameSpecifier) - GlobalNestedNameSpecifier->Destroy(*this); - - TUDecl->Destroy(*this); + + for (llvm::DenseMap::iterator A = DeclAttrs.begin(), + AEnd = DeclAttrs.end(); + A != AEnd; ++A) + A->second->~AttrVec(); } void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { @@ -275,16 +263,12 @@ void ASTContext::PrintStats() const { fprintf(stderr, " %u/%u implicit destructors created\n", NumImplicitDestructorsDeclared, NumImplicitDestructors); - if (!FreeMemory) - BumpAlloc.PrintStats(); - if (ExternalSource.get()) { fprintf(stderr, "\n"); ExternalSource->PrintStats(); } - if (!FreeMemory) - BumpAlloc.PrintStats(); + BumpAlloc.PrintStats(); } @@ -385,6 +369,26 @@ void ASTContext::InitBuiltinTypes() { InitBuiltinType(NullPtrTy, BuiltinType::NullPtr); } +AttrVec& ASTContext::getDeclAttrs(const Decl *D) { + AttrVec *&Result = DeclAttrs[D]; + if (!Result) { + void *Mem = Allocate(sizeof(AttrVec)); + Result = new (Mem) AttrVec; + } + + return *Result; +} + +/// \brief Erase the attributes corresponding to the given declaration. +void ASTContext::eraseDeclAttrs(const Decl *D) { + llvm::DenseMap::iterator Pos = DeclAttrs.find(D); + if (Pos != DeclAttrs.end()) { + Pos->second->~AttrVec(); + DeclAttrs.erase(Pos); + } +} + + MemberSpecializationInfo * ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) { assert(Var->isStaticDataMember() && "Not a static data member"); @@ -499,20 +503,6 @@ void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method, OverriddenMethods[Method].push_back(Overridden); } -namespace { - class BeforeInTranslationUnit - : std::binary_function { - SourceManager *SourceMgr; - - public: - explicit BeforeInTranslationUnit(SourceManager *SM) : SourceMgr(SM) { } - - bool operator()(SourceRange X, SourceRange Y) { - return SourceMgr->isBeforeInTranslationUnit(X.getBegin(), Y.getBegin()); - } - }; -} - //===----------------------------------------------------------------------===// // Type Sizing and Analysis //===----------------------------------------------------------------------===// @@ -538,8 +528,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) { unsigned Align = Target.getCharWidth(); - if (const AlignedAttr* AA = D->getAttr()) - Align = std::max(Align, AA->getMaxAlignment()); + Align = std::max(Align, D->getMaxAlignment()); if (const ValueDecl *VD = dyn_cast(D)) { QualType T = VD->getType(); @@ -716,6 +705,12 @@ ASTContext::getTypeInfo(const Type *T) { Width = Target.getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t) Align = Target.getPointerAlign(0); // == sizeof(void*) break; + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + Width = Target.getPointerWidth(0); + Align = Target.getPointerAlign(0); + break; } break; case Type::ObjCObjectPointer: @@ -744,12 +739,10 @@ ASTContext::getTypeInfo(const Type *T) { break; } case Type::MemberPointer: { - QualType Pointee = cast(T)->getPointeeType(); + const MemberPointerType *MPT = cast(T); std::pair PtrDiffInfo = getTypeInfo(getPointerDiffType()); - Width = PtrDiffInfo.first; - if (Pointee->isFunctionType()) - Width *= 2; + Width = PtrDiffInfo.first * ABI->getMemberPointerSize(MPT); Align = PtrDiffInfo.second; break; } @@ -797,12 +790,10 @@ ASTContext::getTypeInfo(const Type *T) { case Type::Typedef: { const TypedefDecl *Typedef = cast(T)->getDecl(); - if (const AlignedAttr *Aligned = Typedef->getAttr()) { - Align = std::max(Aligned->getMaxAlignment(), - getTypeAlign(Typedef->getUnderlyingType().getTypePtr())); - Width = getTypeSize(Typedef->getUnderlyingType().getTypePtr()); - } else - return getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); + std::pair Info + = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); + Align = std::max(Typedef->getMaxAlignment(), Info.second); + Width = Info.first; break; } @@ -868,60 +859,37 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) { return ABIAlign; } -static void CollectLocalObjCIvars(ASTContext *Ctx, - const ObjCInterfaceDecl *OI, - llvm::SmallVectorImpl &Fields) { - for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(), - E = OI->ivar_end(); I != E; ++I) { - ObjCIvarDecl *IVDecl = *I; - if (!IVDecl->isInvalidDecl()) - Fields.push_back(cast(IVDecl)); - } -} - -void ASTContext::CollectObjCIvars(const ObjCInterfaceDecl *OI, - llvm::SmallVectorImpl &Fields) { - if (const ObjCInterfaceDecl *SuperClass = OI->getSuperClass()) - CollectObjCIvars(SuperClass, Fields); - CollectLocalObjCIvars(this, OI, Fields); -} - /// ShallowCollectObjCIvars - /// Collect all ivars, including those synthesized, in the current class. /// void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI, llvm::SmallVectorImpl &Ivars) { - for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(), - E = OI->ivar_end(); I != E; ++I) { - Ivars.push_back(*I); - } - - CollectNonClassIvars(OI, Ivars); -} - -/// CollectNonClassIvars - -/// This routine collects all other ivars which are not declared in the class. -/// This includes synthesized ivars (via @synthesize) and those in -// class's @implementation. + // FIXME. This need be removed but there are two many places which + // assume const-ness of ObjCInterfaceDecl + ObjCInterfaceDecl *IDecl = const_cast(OI); + for (ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv; + Iv= Iv->getNextIvar()) + Ivars.push_back(Iv); +} + +/// DeepCollectObjCIvars - +/// This routine first collects all declared, but not synthesized, ivars in +/// super class and then collects all ivars, including those synthesized for +/// current class. This routine is used for implementation of current class +/// when all ivars, declared and synthesized are known. /// -void ASTContext::CollectNonClassIvars(const ObjCInterfaceDecl *OI, +void ASTContext::DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, + bool leafClass, llvm::SmallVectorImpl &Ivars) { - // Find ivars declared in class extension. - for (const ObjCCategoryDecl *CDecl = OI->getFirstClassExtension(); CDecl; - CDecl = CDecl->getNextClassExtension()) { - for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), - E = CDecl->ivar_end(); I != E; ++I) { - Ivars.push_back(*I); - } - } - - // Also add any ivar defined in this class's implementation. This - // includes synthesized ivars. - if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) { - for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(), - E = ImplDecl->ivar_end(); I != E; ++I) + if (const ObjCInterfaceDecl *SuperClass = OI->getSuperClass()) + DeepCollectObjCIvars(SuperClass, false, Ivars); + if (!leafClass) { + for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(), + E = OI->ivar_end(); I != E; ++I) Ivars.push_back(*I); } + else + ShallowCollectObjCIvars(OI, Ivars); } /// CollectInheritedProtocols - Collect all protocols in current class and @@ -929,8 +897,10 @@ void ASTContext::CollectNonClassIvars(const ObjCInterfaceDecl *OI, void ASTContext::CollectInheritedProtocols(const Decl *CDecl, llvm::SmallPtrSet &Protocols) { if (const ObjCInterfaceDecl *OI = dyn_cast(CDecl)) { - for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(), - PE = OI->protocol_end(); P != PE; ++P) { + // We can use protocol_iterator here instead of + // all_referenced_protocol_iterator since we are walking all categories. + for (ObjCInterfaceDecl::all_protocol_iterator P = OI->all_referenced_protocol_begin(), + PE = OI->all_referenced_protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); Protocols.insert(Proto); for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), @@ -950,7 +920,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl, SD = SD->getSuperClass(); } } else if (const ObjCCategoryDecl *OC = dyn_cast(CDecl)) { - for (ObjCInterfaceDecl::protocol_iterator P = OC->protocol_begin(), + for (ObjCCategoryDecl::protocol_iterator P = OC->protocol_begin(), PE = OC->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); Protocols.insert(Proto); @@ -1154,6 +1124,15 @@ static QualType getExtFunctionType(ASTContext& Context, QualType T, return T; ResultType = Context.getBlockPointerType(ResultType); + } else if (const MemberPointerType *MemberPointer + = T->getAs()) { + QualType Pointee = MemberPointer->getPointeeType(); + ResultType = getExtFunctionType(Context, Pointee, Info); + if (ResultType == Pointee) + return T; + + ResultType = Context.getMemberPointerType(ResultType, + MemberPointer->getClass()); } else if (const FunctionType *F = T->getAs()) { if (F->getExtInfo() == Info) return T; @@ -1570,10 +1549,7 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts, // If the element type isn't canonical, this won't be a canonical type either, // so fill in the canonical type field. QualType Canonical; - if (!vecType.isCanonical() || (AltiVecSpec == VectorType::AltiVec)) { - // pass VectorType::NotAltiVec for AltiVecSpec to make AltiVec canonical - // vector type (except 'vector bool ...' and 'vector Pixel') the same as - // the equivalent GCC vector types + if (!vecType.isCanonical()) { Canonical = getVectorType(getCanonicalType(vecType), NumElts, VectorType::NotAltiVec); @@ -2567,21 +2543,31 @@ bool ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) { return false; } -DeclarationName ASTContext::getNameForTemplate(TemplateName Name) { +DeclarationNameInfo ASTContext::getNameForTemplate(TemplateName Name, + SourceLocation NameLoc) { if (TemplateDecl *TD = Name.getAsTemplateDecl()) - return TD->getDeclName(); - + // DNInfo work in progress: CHECKME: what about DNLoc? + return DeclarationNameInfo(TD->getDeclName(), NameLoc); + if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { + DeclarationName DName; if (DTN->isIdentifier()) { - return DeclarationNames.getIdentifier(DTN->getIdentifier()); + DName = DeclarationNames.getIdentifier(DTN->getIdentifier()); + return DeclarationNameInfo(DName, NameLoc); } else { - return DeclarationNames.getCXXOperatorName(DTN->getOperator()); + DName = DeclarationNames.getCXXOperatorName(DTN->getOperator()); + // DNInfo work in progress: FIXME: source locations? + DeclarationNameLoc DNLoc; + DNLoc.CXXOperatorName.BeginOpNameLoc = SourceLocation().getRawEncoding(); + DNLoc.CXXOperatorName.EndOpNameLoc = SourceLocation().getRawEncoding(); + return DeclarationNameInfo(DName, NameLoc, DNLoc); } } OverloadedTemplateStorage *Storage = Name.getAsOverloadedTemplate(); assert(Storage); - return (*Storage->begin())->getDeclName(); + // DNInfo work in progress: CHECKME: what about DNLoc? + return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc); } TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { @@ -3216,14 +3202,14 @@ bool ASTContext::BlockRequiresCopying(QualType Ty) { return false; } -QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { +QualType ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) { // type = struct __Block_byref_1_X { // void *__isa; // struct __Block_byref_1_X *__forwarding; // unsigned int __flags; // unsigned int __size; - // void *__copy_helper; // as needed - // void *__destroy_help // as needed + // void *__copy_helper; // as needed + // void *__destroy_help // as needed // int X; // } * @@ -3249,7 +3235,7 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) { Ty }; - const char *FieldNames[] = { + llvm::StringRef FieldNames[] = { "__isa", "__forwarding", "__flags", @@ -3326,7 +3312,7 @@ QualType ASTContext::getBlockParmType( const ValueDecl *D = BDRE->getDecl(); FieldName = D->getIdentifier(); if (BDRE->isByRef()) - FieldType = BuildByRefType(D->getNameAsCString(), FieldType); + FieldType = BuildByRefType(D->getName(), FieldType); } else { // Padding. assert(isa(FieldType) && @@ -3885,15 +3871,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, const IdentifierInfo *II = OI->getIdentifier(); S += II->getName(); S += '='; - llvm::SmallVector RecFields; - CollectObjCIvars(OI, RecFields); - for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { - if (RecFields[i]->isBitField()) - getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, - RecFields[i]); + llvm::SmallVector Ivars; + DeepCollectObjCIvars(OI, true, Ivars); + for (unsigned i = 0, e = Ivars.size(); i != e; ++i) { + FieldDecl *Field = cast(Ivars[i]); + if (Field->isBitField()) + getObjCEncodingForTypeImpl(Field->getType(), S, false, true, Field); else - getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, - FD); + getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD); } S += '}'; return; @@ -4200,6 +4185,28 @@ static bool areCompatVectorTypes(const VectorType *LHS, LHS->getNumElements() == RHS->getNumElements(); } +bool ASTContext::areCompatibleVectorTypes(QualType FirstVec, + QualType SecondVec) { + assert(FirstVec->isVectorType() && "FirstVec should be a vector type"); + assert(SecondVec->isVectorType() && "SecondVec should be a vector type"); + + if (hasSameUnqualifiedType(FirstVec, SecondVec)) + return true; + + // AltiVec vectors types are identical to equivalent GCC vector types + const VectorType *First = FirstVec->getAs(); + const VectorType *Second = SecondVec->getAs(); + if ((((First->getAltiVecSpecific() == VectorType::AltiVec) && + (Second->getAltiVecSpecific() == VectorType::NotAltiVec)) || + ((First->getAltiVecSpecific() == VectorType::NotAltiVec) && + (Second->getAltiVecSpecific() == VectorType::AltiVec))) && + hasSameType(First->getElementType(), Second->getElementType()) && + (First->getNumElements() == Second->getNumElements())) + return true; + + return false; +} + //===----------------------------------------------------------------------===// // ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's. //===----------------------------------------------------------------------===// @@ -4226,6 +4233,32 @@ bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) { return false; } +/// ObjCQualifiedClassTypesAreCompatible - compare Class and +/// Class. +bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs, + QualType rhs) { + const ObjCObjectPointerType *lhsQID = lhs->getAs(); + const ObjCObjectPointerType *rhsOPT = rhs->getAs(); + assert ((lhsQID && rhsOPT) && "ObjCQualifiedClassTypesAreCompatible"); + + for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->qual_end(); I != E; ++I) { + bool match = false; + ObjCProtocolDecl *lhsProto = *I; + for (ObjCObjectPointerType::qual_iterator J = rhsOPT->qual_begin(), + E = rhsOPT->qual_end(); J != E; ++J) { + ObjCProtocolDecl *rhsProto = *J; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto)) { + match = true; + break; + } + } + if (!match) + return false; + } + return true; +} + /// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an /// ObjCQualifiedIDType. bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, @@ -4308,9 +4341,9 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) { for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(), E = rhsQID->qual_end(); I != E; ++I) { - // when comparing an id

on lhs with a static type on rhs, - // see if static class implements all of id's protocols, directly or - // through its super class and categories. + // when comparing an id

on rhs with a static type on lhs, + // static class must implement all of id's protocols directly or + // indirectly through its super class. if (lhsID->ClassImplementsProtocol(*I, true)) { match = true; break; @@ -4365,7 +4398,11 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), QualType(RHSOPT,0), false); - + + if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass()) + return ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0), + QualType(RHSOPT,0)); + // If we have 2 user-defined types, fall into that path. if (LHS->getInterface() && RHS->getInterface()) return canAssignObjCInterfaces(LHS, RHS); @@ -4541,15 +4578,22 @@ bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) { canAssignObjCInterfaces(RHSOPT, LHSOPT); } +bool ASTContext::canBindObjCObjectType(QualType To, QualType From) { + return canAssignObjCInterfaces( + getObjCObjectPointerType(To)->getAs(), + getObjCObjectPointerType(From)->getAs()); +} + /// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible, /// both shall have the identically qualified version of a compatible type. /// C99 6.2.7p1: Two types have compatible types if their types are the /// same. See 6.7.[2,3,5] for additional rules. -bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) { +bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS, + bool CompareUnqualified) { if (getLangOptions().CPlusPlus) return hasSameType(LHS, RHS); - return !mergeTypes(LHS, RHS).isNull(); + return !mergeTypes(LHS, RHS, false, CompareUnqualified).isNull(); } bool ASTContext::typesAreBlockPointerCompatible(QualType LHS, QualType RHS) { @@ -4557,7 +4601,8 @@ bool ASTContext::typesAreBlockPointerCompatible(QualType LHS, QualType RHS) { } QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, - bool OfBlockPointer) { + bool OfBlockPointer, + bool Unqualified) { const FunctionType *lbase = lhs->getAs(); const FunctionType *rbase = rhs->getAs(); const FunctionProtoType *lproto = dyn_cast(lbase); @@ -4568,13 +4613,26 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, // Check return type QualType retType; if (OfBlockPointer) - retType = mergeTypes(rbase->getResultType(), lbase->getResultType(), true); + retType = mergeTypes(rbase->getResultType(), lbase->getResultType(), true, + Unqualified); else - retType = mergeTypes(lbase->getResultType(), rbase->getResultType()); + retType = mergeTypes(lbase->getResultType(), rbase->getResultType(), + false, Unqualified); if (retType.isNull()) return QualType(); - if (getCanonicalType(retType) != getCanonicalType(lbase->getResultType())) + + if (Unqualified) + retType = retType.getUnqualifiedType(); + + CanQualType LRetType = getCanonicalType(lbase->getResultType()); + CanQualType RRetType = getCanonicalType(rbase->getResultType()); + if (Unqualified) { + LRetType = LRetType.getUnqualifiedType(); + RRetType = RRetType.getUnqualifiedType(); + } + + if (getCanonicalType(retType) != LRetType) allLTypes = false; - if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType())) + if (getCanonicalType(retType) != RRetType) allRTypes = false; // FIXME: double check this // FIXME: should we error if lbase->getRegParmAttr() != 0 && @@ -4619,9 +4677,19 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, for (unsigned i = 0; i < lproto_nargs; i++) { QualType largtype = lproto->getArgType(i).getUnqualifiedType(); QualType rargtype = rproto->getArgType(i).getUnqualifiedType(); - QualType argtype = mergeTypes(largtype, rargtype, OfBlockPointer); + QualType argtype = mergeTypes(largtype, rargtype, OfBlockPointer, + Unqualified); if (argtype.isNull()) return QualType(); + + if (Unqualified) + argtype = argtype.getUnqualifiedType(); + types.push_back(argtype); + if (Unqualified) { + largtype = largtype.getUnqualifiedType(); + rargtype = rargtype.getUnqualifiedType(); + } + if (getCanonicalType(argtype) != getCanonicalType(largtype)) allLTypes = false; if (getCanonicalType(argtype) != getCanonicalType(rargtype)) @@ -4677,7 +4745,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, } QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, - bool OfBlockPointer) { + bool OfBlockPointer, + bool Unqualified) { // C++ [expr]: If an expression initially has the type "reference to T", the // type is adjusted to "T" prior to any further analysis, the expression // designates the object or function denoted by the reference, and the @@ -4685,6 +4754,11 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, // the expression is a function call (possibly inside parentheses). assert(!LHS->getAs() && "LHS is a reference type?"); assert(!RHS->getAs() && "RHS is a reference type?"); + + if (Unqualified) { + LHS = LHS.getUnqualifiedType(); + RHS = RHS.getUnqualifiedType(); + } QualType LHSCan = getCanonicalType(LHS), RHSCan = getCanonicalType(RHS); @@ -4796,7 +4870,12 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, // Merge two pointer types, while trying to preserve typedef info QualType LHSPointee = LHS->getAs()->getPointeeType(); QualType RHSPointee = RHS->getAs()->getPointeeType(); - QualType ResultType = mergeTypes(LHSPointee, RHSPointee); + if (Unqualified) { + LHSPointee = LHSPointee.getUnqualifiedType(); + RHSPointee = RHSPointee.getUnqualifiedType(); + } + QualType ResultType = mergeTypes(LHSPointee, RHSPointee, false, + Unqualified); if (ResultType.isNull()) return QualType(); if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType)) return LHS; @@ -4809,7 +4888,12 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, // Merge two block pointer types, while trying to preserve typedef info QualType LHSPointee = LHS->getAs()->getPointeeType(); QualType RHSPointee = RHS->getAs()->getPointeeType(); - QualType ResultType = mergeTypes(LHSPointee, RHSPointee, OfBlockPointer); + if (Unqualified) { + LHSPointee = LHSPointee.getUnqualifiedType(); + RHSPointee = RHSPointee.getUnqualifiedType(); + } + QualType ResultType = mergeTypes(LHSPointee, RHSPointee, OfBlockPointer, + Unqualified); if (ResultType.isNull()) return QualType(); if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType)) return LHS; @@ -4826,7 +4910,12 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, QualType LHSElem = getAsArrayType(LHS)->getElementType(); QualType RHSElem = getAsArrayType(RHS)->getElementType(); - QualType ResultType = mergeTypes(LHSElem, RHSElem); + if (Unqualified) { + LHSElem = LHSElem.getUnqualifiedType(); + RHSElem = RHSElem.getUnqualifiedType(); + } + + QualType ResultType = mergeTypes(LHSElem, RHSElem, false, Unqualified); if (ResultType.isNull()) return QualType(); if (LCAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType)) return LHS; @@ -4860,7 +4949,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, ArrayType::ArraySizeModifier(), 0); } case Type::FunctionNoProto: - return mergeFunctionTypes(LHS, RHS, OfBlockPointer); + return mergeFunctionTypes(LHS, RHS, OfBlockPointer, Unqualified); case Type::Record: case Type::Enum: return QualType(); @@ -5001,7 +5090,7 @@ unsigned ASTContext::getIntWidth(QualType T) { } QualType ASTContext::getCorrespondingUnsignedType(QualType T) { - assert(T->isSignedIntegerType() && "Unexpected type"); + assert(T->hasSignedIntegerRepresentation() && "Unexpected type"); // Turn <4 x signed int> -> <4 x unsigned int> if (const VectorType *VTy = T->getAs()) @@ -5381,8 +5470,8 @@ ASTContext::UsualArithmeticConversionsType(QualType lhs, QualType rhs) { // Finally, we have two differing integer types. // The rules for this case are in C99 6.3.1.8 int compare = getIntegerTypeOrder(lhs, rhs); - bool lhsSigned = lhs->isSignedIntegerType(), - rhsSigned = rhs->isSignedIntegerType(); + bool lhsSigned = lhs->hasSignedIntegerRepresentation(), + rhsSigned = rhs->hasSignedIntegerRepresentation(); QualType destType; if (lhsSigned == rhsSigned) { // Same signedness; use the higher-ranked type @@ -5405,3 +5494,173 @@ ASTContext::UsualArithmeticConversionsType(QualType lhs, QualType rhs) { } return destType; } + +GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { + GVALinkage External = GVA_StrongExternal; + + Linkage L = FD->getLinkage(); + if (L == ExternalLinkage && getLangOptions().CPlusPlus && + FD->getType()->getLinkage() == UniqueExternalLinkage) + L = UniqueExternalLinkage; + + switch (L) { + case NoLinkage: + case InternalLinkage: + case UniqueExternalLinkage: + return GVA_Internal; + + case ExternalLinkage: + switch (FD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + External = GVA_StrongExternal; + break; + + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ImplicitInstantiation: + External = GVA_TemplateInstantiation; + break; + } + } + + if (!FD->isInlined()) + return External; + + if (!getLangOptions().CPlusPlus || FD->hasAttr()) { + // GNU or C99 inline semantics. Determine whether this symbol should be + // externally visible. + if (FD->isInlineDefinitionExternallyVisible()) + return External; + + // C99 inline semantics, where the symbol is not externally visible. + return GVA_C99Inline; + } + + // C++0x [temp.explicit]p9: + // [ Note: The intent is that an inline function that is the subject of + // an explicit instantiation declaration will still be implicitly + // instantiated when used so that the body can be considered for + // inlining, but that no out-of-line copy of the inline function would be + // generated in the translation unit. -- end note ] + if (FD->getTemplateSpecializationKind() + == TSK_ExplicitInstantiationDeclaration) + return GVA_C99Inline; + + return GVA_CXXInline; +} + +GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) { + // If this is a static data member, compute the kind of template + // specialization. Otherwise, this variable is not part of a + // template. + TemplateSpecializationKind TSK = TSK_Undeclared; + if (VD->isStaticDataMember()) + TSK = VD->getTemplateSpecializationKind(); + + Linkage L = VD->getLinkage(); + if (L == ExternalLinkage && getLangOptions().CPlusPlus && + VD->getType()->getLinkage() == UniqueExternalLinkage) + L = UniqueExternalLinkage; + + switch (L) { + case NoLinkage: + case InternalLinkage: + case UniqueExternalLinkage: + return GVA_Internal; + + case ExternalLinkage: + switch (TSK) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return GVA_StrongExternal; + + case TSK_ExplicitInstantiationDeclaration: + llvm_unreachable("Variable should not be instantiated"); + // Fall through to treat this like any other instantiation. + + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; + + case TSK_ImplicitInstantiation: + return GVA_TemplateInstantiation; + } + } + + return GVA_StrongExternal; +} + +bool ASTContext::DeclMustBeEmitted(const Decl *D) { + if (const VarDecl *VD = dyn_cast(D)) { + if (!VD->isFileVarDecl()) + return false; + } else if (!isa(D)) + return false; + + // Weak references don't produce any output by themselves. + if (D->hasAttr()) + return false; + + // Aliases and used decls are required. + if (D->hasAttr() || D->hasAttr()) + return true; + + if (const FunctionDecl *FD = dyn_cast(D)) { + // Forward declarations aren't required. + if (!FD->isThisDeclarationADefinition()) + return false; + + // Constructors and destructors are required. + if (FD->hasAttr() || FD->hasAttr()) + return true; + + // The key function for a class is required. + if (const CXXMethodDecl *MD = dyn_cast(FD)) { + const CXXRecordDecl *RD = MD->getParent(); + if (MD->isOutOfLine() && RD->isDynamicClass()) { + const CXXMethodDecl *KeyFunc = getKeyFunction(RD); + if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl()) + return true; + } + } + + GVALinkage Linkage = GetGVALinkageForFunction(FD); + + // static, static inline, always_inline, and extern inline functions can + // always be deferred. Normal inline functions can be deferred in C99/C++. + // Implicit template instantiations can also be deferred in C++. + if (Linkage == GVA_Internal || Linkage == GVA_C99Inline || + Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) + return false; + return true; + } + + const VarDecl *VD = cast(D); + assert(VD->isFileVarDecl() && "Expected file scoped var"); + + if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly) + return false; + + // Structs that have non-trivial constructors or destructors are required. + + // FIXME: Handle references. + if (const RecordType *RT = VD->getType()->getAs()) { + if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) { + if (RD->hasDefinition() && + (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor())) + return true; + } + } + + GVALinkage L = GetGVALinkageForVariable(VD); + if (L == GVA_Internal || L == GVA_TemplateInstantiation) { + if (!(VD->getInit() && VD->getInit()->HasSideEffects(*this))) + return false; + } + + return true; +} + +CXXABI::~CXXABI() {} diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 0d609bf..23f323d 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -151,10 +151,13 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, bool ShouldAKA = false; QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA); if (ShouldAKA) { - S = "'"+S+"' (aka '"; - S += DesugaredTy.getAsString(Context.PrintingPolicy); - S += "')"; - return S; + std::string D = DesugaredTy.getAsString(Context.PrintingPolicy); + if (D != S) { + S = "'" + S + "' (aka '"; + S += D; + S += "')"; + return S; + } } } diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 8d347d1..2edd09c 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -19,7 +19,6 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" -#include "clang/AST/TypeLoc.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" @@ -82,6 +81,8 @@ namespace { bool ImportDeclParts(NamedDecl *D, DeclContext *&DC, DeclContext *&LexicalDC, DeclarationName &Name, SourceLocation &Loc); + void ImportDeclarationNameLoc(const DeclarationNameInfo &From, + DeclarationNameInfo& To); void ImportDeclContext(DeclContext *FromDC); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord); bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); @@ -1385,6 +1386,40 @@ bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC, return false; } +void +ASTNodeImporter::ImportDeclarationNameLoc(const DeclarationNameInfo &From, + DeclarationNameInfo& To) { + // NOTE: To.Name and To.Loc are already imported. + // We only have to import To.LocInfo. + switch (To.getName().getNameKind()) { + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXUsingDirective: + return; + + case DeclarationName::CXXOperatorName: { + SourceRange Range = From.getCXXOperatorNameRange(); + To.setCXXOperatorNameRange(Importer.Import(Range)); + return; + } + case DeclarationName::CXXLiteralOperatorName: { + SourceLocation Loc = From.getCXXLiteralOperatorNameLoc(); + To.setCXXLiteralOperatorNameLoc(Importer.Import(Loc)); + return; + } + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: { + TypeSourceInfo *FromTInfo = From.getNamedTypeInfo(); + To.setNamedTypeInfo(Importer.Import(FromTInfo)); + return; + } + assert(0 && "Unknown name kind."); + } +} + void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC) { for (DeclContext::decl_iterator From = FromDC->decls_begin(), FromEnd = FromDC->decls_end(); @@ -1752,7 +1787,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { Base1->isVirtual(), Base1->isBaseOfClass(), Base1->getAccessSpecifierAsWritten(), - T)); + Importer.Import(Base1->getTypeSourceInfo()))); } if (!Bases.empty()) D2CXX->setBases(Bases.data(), Bases.size()); @@ -1822,7 +1857,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { SourceLocation Loc; if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) return 0; - + // Try to find a function in our own ("to") context with the same name, same // type, and in the same context as the function we're importing. if (!LexicalDC->isFunctionOrMethod()) { @@ -1871,6 +1906,10 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } } + DeclarationNameInfo NameInfo(Name, Loc); + // Import additional name location/type info. + ImportDeclarationNameLoc(D->getNameInfo(), NameInfo); + // Import the type. QualType T = Importer.Import(D->getType()); if (T.isNull()) @@ -1893,26 +1932,26 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (CXXConstructorDecl *FromConstructor = dyn_cast(D)) { ToFunction = CXXConstructorDecl::Create(Importer.getToContext(), cast(DC), - Loc, Name, T, TInfo, + NameInfo, T, TInfo, FromConstructor->isExplicit(), D->isInlineSpecified(), D->isImplicit()); } else if (isa(D)) { ToFunction = CXXDestructorDecl::Create(Importer.getToContext(), cast(DC), - Loc, Name, T, + NameInfo, T, D->isInlineSpecified(), D->isImplicit()); } else if (CXXConversionDecl *FromConversion = dyn_cast(D)) { ToFunction = CXXConversionDecl::Create(Importer.getToContext(), cast(DC), - Loc, Name, T, TInfo, + NameInfo, T, TInfo, D->isInlineSpecified(), FromConversion->isExplicit()); } else { - ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, Loc, - Name, T, TInfo, D->getStorageClass(), + ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, + NameInfo, T, TInfo, D->getStorageClass(), D->getStorageClassAsWritten(), D->isInlineSpecified(), D->hasWrittenPrototype()); @@ -2026,7 +2065,7 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { cast(DC), Loc, Name.getAsIdentifierInfo(), T, TInfo, D->getAccessControl(), - BitWidth); + BitWidth, D->getSynthesize()); ToIvar->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToIvar); LexicalDC->addDecl(ToIvar); @@ -2299,6 +2338,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { D->isInstanceMethod(), D->isVariadic(), D->isSynthesized(), + D->isDefined(), D->getImplementationControl()); // FIXME: When we decide to merge method definitions, we'll need to @@ -2513,6 +2553,8 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { llvm::SmallVector ProtocolLocs; ObjCInterfaceDecl::protocol_loc_iterator FromProtoLoc = D->protocol_loc_begin(); + + // FIXME: Should we be usng all_referenced_protocol_begin() here? for (ObjCInterfaceDecl::protocol_iterator FromProto = D->protocol_begin(), FromProtoEnd = D->protocol_end(); FromProto != FromProtoEnd; @@ -2778,8 +2820,9 @@ Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) { if (T.isNull()) return 0; - return new (Importer.getToContext()) - IntegerLiteral(E->getValue(), T, Importer.Import(E->getLocation())); + return IntegerLiteral::Create(Importer.getToContext(), + E->getValue(), T, + Importer.Import(E->getLocation())); } Expr *ASTNodeImporter::VisitCharacterLiteral(CharacterLiteral *E) { @@ -2886,6 +2929,13 @@ Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) { Importer.Import(E->getOperatorLoc())); } +bool ImportCastPath(CastExpr *E, CXXCastPath &Path) { + if (E->path_empty()) return false; + + // TODO: import cast paths + return true; +} + Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) { QualType T = Importer.Import(E->getType()); if (T.isNull()) @@ -2894,13 +2944,13 @@ Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) { Expr *SubExpr = Importer.Import(E->getSubExpr()); if (!SubExpr) return 0; - - // FIXME: Initialize the base path. - assert(E->getBasePath().empty() && "FIXME: Must copy base path!"); - CXXBaseSpecifierArray BasePath; - return new (Importer.getToContext()) ImplicitCastExpr(T, E->getCastKind(), - SubExpr, BasePath, - E->isLvalueCast()); + + CXXCastPath BasePath; + if (ImportCastPath(E, BasePath)) + return 0; + + return ImplicitCastExpr::Create(Importer.getToContext(), T, E->getCastKind(), + SubExpr, &BasePath, E->getValueKind()); } Expr *ASTNodeImporter::VisitCStyleCastExpr(CStyleCastExpr *E) { @@ -2916,13 +2966,14 @@ Expr *ASTNodeImporter::VisitCStyleCastExpr(CStyleCastExpr *E) { if (!TInfo && E->getTypeInfoAsWritten()) return 0; - // FIXME: Initialize the base path. - assert(E->getBasePath().empty() && "FIXME: Must copy base path!"); - CXXBaseSpecifierArray BasePath; - return new (Importer.getToContext()) CStyleCastExpr(T, E->getCastKind(), - SubExpr, BasePath, TInfo, - Importer.Import(E->getLParenLoc()), - Importer.Import(E->getRParenLoc())); + CXXCastPath BasePath; + if (ImportCastPath(E, BasePath)) + return 0; + + return CStyleCastExpr::Create(Importer.getToContext(), T, E->getCastKind(), + SubExpr, &BasePath, TInfo, + Importer.Import(E->getLParenLoc()), + Importer.Import(E->getRParenLoc())); } ASTImporter::ASTImporter(Diagnostic &Diags, @@ -2964,8 +3015,7 @@ TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) { return FromTSI; // FIXME: For now we just create a "trivial" type source info based - // on the type and a seingle location. Implement a real version of - // this. + // on the type and a single location. Implement a real version of this. QualType T = Import(FromTSI->getType()); if (T.isNull()) return 0; diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index b09ba895..3ca7d4d 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -13,198 +13,10 @@ #include "clang/AST/Attr.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" +#include "clang/AST/Expr.h" using namespace clang; -void Attr::Destroy(ASTContext &C) { - if (Next) { - Next->Destroy(C); - Next = 0; - } - this->~Attr(); - C.Deallocate((void*)this); -} +Attr::~Attr() { } -AttrWithString::AttrWithString(attr::Kind AK, ASTContext &C, llvm::StringRef s) - : Attr(AK) { - assert(!s.empty()); - StrLen = s.size(); - Str = new (C) char[StrLen]; - memcpy(const_cast(Str), s.data(), StrLen); -} - -void AttrWithString::Destroy(ASTContext &C) { - C.Deallocate(const_cast(Str)); - Attr::Destroy(C); -} - -void AttrWithString::ReplaceString(ASTContext &C, llvm::StringRef newS) { - if (newS.size() > StrLen) { - C.Deallocate(const_cast(Str)); - Str = new (C) char[newS.size()]; - } - StrLen = newS.size(); - memcpy(const_cast(Str), newS.data(), StrLen); -} - -void FormatAttr::setType(ASTContext &C, llvm::StringRef type) { - ReplaceString(C, type); -} - -NonNullAttr::NonNullAttr(ASTContext &C, unsigned* arg_nums, unsigned size) - : Attr(attr::NonNull), ArgNums(0), Size(0) { - if (size == 0) - return; - assert(arg_nums); - ArgNums = new (C) unsigned[size]; - Size = size; - memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size); -} - -void NonNullAttr::Destroy(ASTContext &C) { - if (ArgNums) - C.Deallocate(ArgNums); - Attr::Destroy(C); -} - -#define DEF_SIMPLE_ATTR_CLONE(ATTR) \ - Attr *ATTR##Attr::clone(ASTContext &C) const { \ - return ::new (C) ATTR##Attr; \ - } - -// FIXME: Can we use variadic macro to define DEF_SIMPLE_ATTR_CLONE for -// "non-simple" classes? - -DEF_SIMPLE_ATTR_CLONE(AlignMac68k) -DEF_SIMPLE_ATTR_CLONE(AlwaysInline) -DEF_SIMPLE_ATTR_CLONE(AnalyzerNoReturn) -DEF_SIMPLE_ATTR_CLONE(BaseCheck) -DEF_SIMPLE_ATTR_CLONE(CDecl) -DEF_SIMPLE_ATTR_CLONE(CFReturnsNotRetained) -DEF_SIMPLE_ATTR_CLONE(CFReturnsRetained) -DEF_SIMPLE_ATTR_CLONE(Const) -DEF_SIMPLE_ATTR_CLONE(DLLExport) -DEF_SIMPLE_ATTR_CLONE(DLLImport) -DEF_SIMPLE_ATTR_CLONE(Deprecated) -DEF_SIMPLE_ATTR_CLONE(FastCall) -DEF_SIMPLE_ATTR_CLONE(Final) -DEF_SIMPLE_ATTR_CLONE(Hiding) -DEF_SIMPLE_ATTR_CLONE(Malloc) -DEF_SIMPLE_ATTR_CLONE(NSReturnsNotRetained) -DEF_SIMPLE_ATTR_CLONE(NSReturnsRetained) -DEF_SIMPLE_ATTR_CLONE(NoDebug) -DEF_SIMPLE_ATTR_CLONE(NoInline) -DEF_SIMPLE_ATTR_CLONE(NoInstrumentFunction) -DEF_SIMPLE_ATTR_CLONE(NoReturn) -DEF_SIMPLE_ATTR_CLONE(NoThrow) -DEF_SIMPLE_ATTR_CLONE(ObjCException) -DEF_SIMPLE_ATTR_CLONE(ObjCNSObject) -DEF_SIMPLE_ATTR_CLONE(Override) -DEF_SIMPLE_ATTR_CLONE(Packed) -DEF_SIMPLE_ATTR_CLONE(Pure) -DEF_SIMPLE_ATTR_CLONE(StdCall) -DEF_SIMPLE_ATTR_CLONE(ThisCall) -DEF_SIMPLE_ATTR_CLONE(TransparentUnion) -DEF_SIMPLE_ATTR_CLONE(Unavailable) -DEF_SIMPLE_ATTR_CLONE(Unused) -DEF_SIMPLE_ATTR_CLONE(Used) -DEF_SIMPLE_ATTR_CLONE(WarnUnusedResult) -DEF_SIMPLE_ATTR_CLONE(Weak) -DEF_SIMPLE_ATTR_CLONE(WeakImport) -DEF_SIMPLE_ATTR_CLONE(WeakRef) -DEF_SIMPLE_ATTR_CLONE(X86ForceAlignArgPointer) - -Attr* MaxFieldAlignmentAttr::clone(ASTContext &C) const { - return ::new (C) MaxFieldAlignmentAttr(Alignment); -} - -Attr* AlignedAttr::clone(ASTContext &C) const { - return ::new (C) AlignedAttr(Alignment); -} - -Attr* AnnotateAttr::clone(ASTContext &C) const { - return ::new (C) AnnotateAttr(C, getAnnotation()); -} - -Attr *AsmLabelAttr::clone(ASTContext &C) const { - return ::new (C) AsmLabelAttr(C, getLabel()); -} - -Attr *AliasAttr::clone(ASTContext &C) const { - return ::new (C) AliasAttr(C, getAliasee()); -} - -Attr *ConstructorAttr::clone(ASTContext &C) const { - return ::new (C) ConstructorAttr(priority); -} - -Attr *DestructorAttr::clone(ASTContext &C) const { - return ::new (C) DestructorAttr(priority); -} - -Attr *IBOutletAttr::clone(ASTContext &C) const { - return ::new (C) IBOutletAttr; -} - -Attr *IBOutletCollectionAttr::clone(ASTContext &C) const { - return ::new (C) IBOutletCollectionAttr(D); -} - -Attr *IBActionAttr::clone(ASTContext &C) const { - return ::new (C) IBActionAttr; -} - -Attr *GNUInlineAttr::clone(ASTContext &C) const { - return ::new (C) GNUInlineAttr; -} - -Attr *SectionAttr::clone(ASTContext &C) const { - return ::new (C) SectionAttr(C, getName()); -} - -Attr *NonNullAttr::clone(ASTContext &C) const { - return ::new (C) NonNullAttr(C, ArgNums, Size); -} - -Attr *FormatAttr::clone(ASTContext &C) const { - return ::new (C) FormatAttr(C, getType(), formatIdx, firstArg); -} - -Attr *FormatArgAttr::clone(ASTContext &C) const { - return ::new (C) FormatArgAttr(formatIdx); -} - -Attr *SentinelAttr::clone(ASTContext &C) const { - return ::new (C) SentinelAttr(sentinel, NullPos); -} - -Attr *VisibilityAttr::clone(ASTContext &C) const { - return ::new (C) VisibilityAttr(VisibilityType); -} - -Attr *OverloadableAttr::clone(ASTContext &C) const { - return ::new (C) OverloadableAttr; -} - -Attr *BlocksAttr::clone(ASTContext &C) const { - return ::new (C) BlocksAttr(BlocksAttrType); -} - -Attr *CleanupAttr::clone(ASTContext &C) const { - return ::new (C) CleanupAttr(FD); -} - -Attr *RegparmAttr::clone(ASTContext &C) const { - return ::new (C) RegparmAttr(NumParams); -} - -Attr *ReqdWorkGroupSizeAttr::clone(ASTContext &C) const { - return ::new (C) ReqdWorkGroupSizeAttr(X, Y, Z); -} - -Attr *InitPriorityAttr::clone(ASTContext &C) const { - return ::new (C) InitPriorityAttr(Priority); -} - -Attr *MSP430InterruptAttr::clone(ASTContext &C) const { - return ::new (C) MSP430InterruptAttr(Number); -} +#include "clang/AST/AttrImpl.inc" diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 407ed95..82a81ec 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -23,6 +23,8 @@ add_clang_library(clangAST ExprCXX.cpp FullExpr.cpp InheritViz.cpp + ItaniumCXXABI.cpp + MicrosoftCXXABI.cpp NestedNameSpecifier.cpp ParentMap.cpp RecordLayout.cpp @@ -41,4 +43,4 @@ add_clang_library(clangAST ) add_dependencies(clangAST ClangARMNeon ClangAttrClasses ClangAttrList - ClangDiagnosticAST ClangDeclNodes ClangStmtNodes) + ClangAttrImpl ClangDiagnosticAST ClangDeclNodes ClangStmtNodes) diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h new file mode 100644 index 0000000..4b38d7a --- /dev/null +++ b/lib/AST/CXXABI.h @@ -0,0 +1,39 @@ +//===----- CXXABI.h - Interface to C++ ABIs ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides an abstract class for C++ AST support. Concrete +// subclasses of this implement AST support for specific C++ ABIs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_CXXABI_H +#define LLVM_CLANG_AST_CXXABI_H + +namespace clang { + +class ASTContext; +class MemberPointerType; + +/// Implements C++ ABI-specific semantic analysis functions. +class CXXABI { +public: + virtual ~CXXABI(); + + /// Returns the size of a member pointer in multiples of the target + /// pointer size. + virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0; +}; + +/// Creates an instance of a C++ ABI class. +CXXABI *CreateARMCXXABI(ASTContext &Ctx); +CXXABI *CreateItaniumCXXABI(ASTContext &Ctx); +CXXABI *CreateMicrosoftCXXABI(ASTContext &Ctx); +} + +#endif diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 149938f..b7be02d 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -97,8 +97,14 @@ static Linkage getLinkageForTemplateArgumentList(const TemplateArgument *Args, return L; } +static Linkage +getLinkageForTemplateArgumentList(const TemplateArgumentList &TArgs) { + return getLinkageForTemplateArgumentList(TArgs.getFlatArgumentList(), + TArgs.flat_size()); +} + static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { - assert(D->getDeclContext()->getLookupContext()->isFileContext() && + assert(D->getDeclContext()->getRedeclContext()->isFileContext() && "Not a name having namespace scope"); ASTContext &Context = D->getASTContext(); @@ -110,7 +116,7 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // (This bullet corresponds to C99 6.2.2p3.) if (const VarDecl *Var = dyn_cast(D)) { // Explicitly declared static. - if (Var->getStorageClass() == VarDecl::Static) + if (Var->getStorageClass() == SC_Static) return InternalLinkage; // - an object or reference that is explicitly declared const @@ -119,8 +125,8 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // (there is no equivalent in C99) if (Context.getLangOptions().CPlusPlus && Var->getType().isConstant(Context) && - Var->getStorageClass() != VarDecl::Extern && - Var->getStorageClass() != VarDecl::PrivateExtern) { + Var->getStorageClass() != SC_Extern && + Var->getStorageClass() != SC_PrivateExtern) { bool FoundExtern = false; for (const VarDecl *PrevVar = Var->getPreviousDeclaration(); PrevVar && !FoundExtern; @@ -143,7 +149,7 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { Function = cast(D); // Explicitly declared static. - if (Function->getStorageClass() == FunctionDecl::Static) + if (Function->getStorageClass() == SC_Static) return InternalLinkage; } else if (const FieldDecl *Field = dyn_cast(D)) { // - a data member of an anonymous union. @@ -159,8 +165,8 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // - an object or reference, unless it has internal linkage; or if (const VarDecl *Var = dyn_cast(D)) { if (!Context.getLangOptions().CPlusPlus && - (Var->getStorageClass() == VarDecl::Extern || - Var->getStorageClass() == VarDecl::PrivateExtern)) { + (Var->getStorageClass() == SC_Extern || + Var->getStorageClass() == SC_PrivateExtern)) { // C99 6.2.2p4: // For an identifier declared with the storage-class specifier // extern in a scope in which a prior declaration of that @@ -194,9 +200,9 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { // as if it were declared with the storage-class specifier // extern. if (!Context.getLangOptions().CPlusPlus && - (Function->getStorageClass() == FunctionDecl::Extern || - Function->getStorageClass() == FunctionDecl::PrivateExtern || - Function->getStorageClass() == FunctionDecl::None)) { + (Function->getStorageClass() == SC_Extern || + Function->getStorageClass() == SC_PrivateExtern || + Function->getStorageClass() == SC_None)) { // C99 6.2.2p4: // For an identifier declared with the storage-class specifier // extern in a scope in which a prior declaration of that @@ -219,10 +225,7 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { = Function->getTemplateSpecializationInfo()) { Linkage L = SpecInfo->getTemplate()->getLinkage(); const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments; - L = minLinkage(L, - getLinkageForTemplateArgumentList( - TemplateArgs.getFlatArgumentList(), - TemplateArgs.flat_size())); + L = minLinkage(L, getLinkageForTemplateArgumentList(TemplateArgs)); return L; } @@ -245,9 +248,7 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { if (const ClassTemplateSpecializationDecl *Spec = dyn_cast(Tag)) { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); - Linkage L = getLinkageForTemplateArgumentList( - TemplateArgs.getFlatArgumentList(), - TemplateArgs.flat_size()); + Linkage L = getLinkageForTemplateArgumentList(TemplateArgs); return minLinkage(L, Spec->getSpecializedTemplate()->getLinkage()); } @@ -279,6 +280,47 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) { return NoLinkage; } +static Linkage getLinkageForClassMember(const NamedDecl *D) { + if (!(isa(D) || + isa(D) || + (isa(D) && + (D->getDeclName() || cast(D)->getTypedefForAnonDecl())))) + return NoLinkage; + + // Class members only have linkage if their class has external linkage. + Linkage L = cast(D->getDeclContext())->getLinkage(); + if (!isExternalLinkage(L)) return NoLinkage; + + // If the class already has unique-external linkage, we can't improve. + if (L == UniqueExternalLinkage) return UniqueExternalLinkage; + + // If this is a method template specialization, use the linkage for + // the template parameters and arguments. + if (const CXXMethodDecl *MD = dyn_cast(D)) { + if (FunctionTemplateSpecializationInfo *SpecInfo + = MD->getTemplateSpecializationInfo()) { + Linkage ArgLinkage = + getLinkageForTemplateArgumentList(*SpecInfo->TemplateArguments); + Linkage ParamLinkage = + getLinkageForTemplateParameterList( + SpecInfo->getTemplate()->getTemplateParameters()); + return minLinkage(ArgLinkage, ParamLinkage); + } + + // Similarly for member class template specializations. + } else if (const ClassTemplateSpecializationDecl *Spec + = dyn_cast(D)) { + Linkage ArgLinkage = + getLinkageForTemplateArgumentList(Spec->getTemplateArgs()); + Linkage ParamLinkage = + getLinkageForTemplateParameterList( + Spec->getSpecializedTemplate()->getTemplateParameters()); + return minLinkage(ArgLinkage, ParamLinkage); + } + + return ExternalLinkage; +} + Linkage NamedDecl::getLinkage() const { // Objective-C: treat all Objective-C declarations as having external @@ -303,7 +345,7 @@ Linkage NamedDecl::getLinkage() const { } // Handle linkage for namespace-scope names. - if (getDeclContext()->getLookupContext()->isFileContext()) + if (getDeclContext()->getRedeclContext()->isFileContext()) if (Linkage L = getLinkageForNamespaceScopeDecl(this)) return L; @@ -314,14 +356,8 @@ Linkage NamedDecl::getLinkage() const { // that the class or enumeration has the typedef name for linkage // purposes (7.1.3), has external linkage if the name of the class // has external linkage. - if (getDeclContext()->isRecord() && - (isa(this) || isa(this) || - (isa(this) && - (getDeclName() || cast(this)->getTypedefForAnonDecl())))) { - Linkage L = cast(getDeclContext())->getLinkage(); - if (isExternalLinkage(L)) - return L; - } + if (getDeclContext()->isRecord()) + return getLinkageForClassMember(this); // C++ [basic.link]p6: // The name of a function declared in block scope and the name of @@ -347,8 +383,8 @@ Linkage NamedDecl::getLinkage() const { } if (const VarDecl *Var = dyn_cast(this)) - if (Var->getStorageClass() == VarDecl::Extern || - Var->getStorageClass() == VarDecl::PrivateExtern) { + if (Var->getStorageClass() == SC_Extern || + Var->getStorageClass() == SC_PrivateExtern) { if (Var->getPreviousDeclaration()) if (Linkage L = Var->getPreviousDeclaration()->getLinkage()) return L; @@ -531,13 +567,6 @@ static SourceLocation getTemplateOrInnerLocStart(const DeclT *decl) { return decl->getInnerLocStart(); } -DeclaratorDecl::~DeclaratorDecl() {} -void DeclaratorDecl::Destroy(ASTContext &C) { - if (hasExtInfo()) - C.Deallocate(getExtInfo()); - ValueDecl::Destroy(C); -} - SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { TypeSourceInfo *TSI = getTypeSourceInfo(); if (TSI) return TSI->getTypeLoc().getBeginLoc(); @@ -602,24 +631,18 @@ QualifierInfo::setTemplateParameterListsInfo(ASTContext &Context, } } -void QualifierInfo::Destroy(ASTContext &Context) { - // FIXME: Deallocate template parameter lists themselves! - if (TemplParamLists) - Context.Deallocate(TemplParamLists); -} - //===----------------------------------------------------------------------===// // VarDecl Implementation //===----------------------------------------------------------------------===// const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { switch (SC) { - case VarDecl::None: break; - case VarDecl::Auto: return "auto"; break; - case VarDecl::Extern: return "extern"; break; - case VarDecl::PrivateExtern: return "__private_extern__"; break; - case VarDecl::Register: return "register"; break; - case VarDecl::Static: return "static"; break; + case SC_None: break; + case SC_Auto: return "auto"; break; + case SC_Extern: return "extern"; break; + case SC_PrivateExtern: return "__private_extern__"; break; + case SC_Register: return "register"; break; + case SC_Static: return "static"; break; } assert(0 && "Invalid storage class"); @@ -632,22 +655,6 @@ VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten); } -void VarDecl::Destroy(ASTContext& C) { - Expr *Init = getInit(); - if (Init) { - Init->Destroy(C); - if (EvaluatedStmt *Eval = this->Init.dyn_cast()) { - Eval->~EvaluatedStmt(); - C.Deallocate(Eval); - } - } - this->~VarDecl(); - DeclaratorDecl::Destroy(C); -} - -VarDecl::~VarDecl() { -} - SourceLocation VarDecl::getInnerLocStart() const { SourceLocation Start = getTypeSpecStartLoc(); if (Start.isInvalid()) @@ -665,14 +672,14 @@ bool VarDecl::isExternC() const { ASTContext &Context = getASTContext(); if (!Context.getLangOptions().CPlusPlus) return (getDeclContext()->isTranslationUnit() && - getStorageClass() != Static) || + getStorageClass() != SC_Static) || (getDeclContext()->isFunctionOrMethod() && hasExternalStorage()); for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); DC = DC->getParent()) { if (const LinkageSpecDecl *Linkage = dyn_cast(DC)) { if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) - return getStorageClass() != Static; + return getStorageClass() != SC_Static; break; } @@ -717,8 +724,8 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition() const { if (hasExternalStorage()) return DeclarationOnly; - if (getStorageClassAsWritten() == Extern || - getStorageClassAsWritten() == PrivateExtern) { + if (getStorageClassAsWritten() == SC_Extern || + getStorageClassAsWritten() == SC_PrivateExtern) { for (const VarDecl *PrevVar = getPreviousDeclaration(); PrevVar; PrevVar = PrevVar->getPreviousDeclaration()) { if (PrevVar->getLinkage() == InternalLinkage && PrevVar->hasInit()) @@ -912,28 +919,6 @@ SourceRange ParmVarDecl::getDefaultArgRange() const { // FunctionDecl Implementation //===----------------------------------------------------------------------===// -void FunctionDecl::Destroy(ASTContext& C) { - if (Body && Body.isOffset()) - Body.get(C.getExternalSource())->Destroy(C); - - for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) - (*I)->Destroy(C); - - FunctionTemplateSpecializationInfo *FTSInfo - = TemplateOrSpecialization.dyn_cast(); - if (FTSInfo) - C.Deallocate(FTSInfo); - - MemberSpecializationInfo *MSInfo - = TemplateOrSpecialization.dyn_cast(); - if (MSInfo) - C.Deallocate(MSInfo); - - C.Deallocate(ParamInfo); - - DeclaratorDecl::Destroy(C); -} - void FunctionDecl::getNameForDiagnostic(std::string &S, const PrintingPolicy &Policy, bool Qualified) const { @@ -984,7 +969,7 @@ void FunctionDecl::setBody(Stmt *B) { bool FunctionDecl::isMain() const { ASTContext &Context = getASTContext(); return !Context.getLangOptions().Freestanding && - getDeclContext()->getLookupContext()->isTranslationUnit() && + getDeclContext()->getRedeclContext()->isTranslationUnit() && getIdentifier() && getIdentifier()->isStr("main"); } @@ -993,17 +978,20 @@ bool FunctionDecl::isExternC() const { // In C, any non-static, non-overloadable function has external // linkage. if (!Context.getLangOptions().CPlusPlus) - return getStorageClass() != Static && !getAttr(); + return getStorageClass() != SC_Static && !getAttr(); for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); DC = DC->getParent()) { if (const LinkageSpecDecl *Linkage = dyn_cast(DC)) { if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) - return getStorageClass() != Static && + return getStorageClass() != SC_Static && !getAttr(); break; } + + if (DC->isRecord()) + break; } return false; @@ -1013,7 +1001,7 @@ bool FunctionDecl::isGlobal() const { if (const CXXMethodDecl *Method = dyn_cast(this)) return Method->isStatic(); - if (getStorageClass() == Static) + if (getStorageClass() == SC_Static) return false; for (const DeclContext *DC = getDeclContext(); @@ -1072,7 +1060,7 @@ unsigned FunctionDecl::getBuiltinID() const { // function or whether it just has the same name. // If this is a static function, it's not a builtin. - if (getStorageClass() == Static) + if (getStorageClass() == SC_Static) return 0; // If this function is at translation-unit scope and we're not in @@ -1206,7 +1194,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end(); Redecl != RedeclEnd; ++Redecl) { - if (Redecl->isInlineSpecified() && Redecl->getStorageClass() != Extern) + if (Redecl->isInlineSpecified() && Redecl->getStorageClass() != SC_Extern) return true; } @@ -1225,7 +1213,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const { if (!Redecl->getLexicalDeclContext()->isTranslationUnit()) continue; - if (!Redecl->isInlineSpecified() || Redecl->getStorageClass() == Extern) + if (!Redecl->isInlineSpecified() || Redecl->getStorageClass() == SC_Extern) return true; // Not an inline definition } @@ -1400,14 +1388,15 @@ FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, if (InsertPos) Template->getSpecializations().InsertNode(Info, InsertPos); else { - // Try to insert the new node. If there is an existing node, remove it - // first. + // Try to insert the new node. If there is an existing node, leave it, the + // set will contain the canonical decls while + // FunctionTemplateDecl::findSpecialization will return + // the most recent redeclarations. FunctionTemplateSpecializationInfo *Existing = Template->getSpecializations().GetOrInsertNode(Info); - if (Existing) { - Template->getSpecializations().RemoveNode(Existing); - Template->getSpecializations().GetOrInsertNode(Info); - } + (void)Existing; + assert((!Existing || Existing->Function->isCanonicalDecl()) && + "Set is supposed to only contain canonical decls"); } } @@ -1564,12 +1553,6 @@ bool FieldDecl::isAnonymousStructOrUnion() const { // TagDecl Implementation //===----------------------------------------------------------------------===// -void TagDecl::Destroy(ASTContext &C) { - if (hasExtInfo()) - C.Deallocate(getExtInfo()); - TypeDecl::Destroy(C); -} - SourceLocation TagDecl::getOuterLocStart() const { return getTemplateOrInnerLocStart(this); } @@ -1590,14 +1573,7 @@ void TagDecl::setTypedefForAnonDecl(TypedefDecl *TDD) { } void TagDecl::startDefinition() { - if (TagType *TagT = const_cast(TypeForDecl->getAs())) { - TagT->decl.setPointer(this); - TagT->decl.setInt(1); - } else if (InjectedClassNameType *Injected - = const_cast( - TypeForDecl->getAs())) { - Injected->Decl = cast(this); - } + IsBeingDefined = true; if (isa(this)) { CXXRecordDecl *D = cast(this); @@ -1614,17 +1590,7 @@ void TagDecl::completeDefinition() { "definition completed but not started"); IsDefinition = true; - if (TagType *TagT = const_cast(TypeForDecl->getAs())) { - assert(TagT->decl.getPointer() == this && - "Attempt to redefine a tag definition?"); - TagT->decl.setInt(0); - } else if (InjectedClassNameType *Injected - = const_cast( - TypeForDecl->getAs())) { - assert(Injected->Decl == this && - "Attempt to redefine a class template definition?"); - (void)Injected; - } + IsBeingDefined = false; } TagDecl* TagDecl::getDefinition() const { @@ -1675,10 +1641,6 @@ EnumDecl *EnumDecl::Create(ASTContext &C, EmptyShell Empty) { return new (C) EnumDecl(0, SourceLocation(), 0, 0, SourceLocation()); } -void EnumDecl::Destroy(ASTContext& C) { - TagDecl::Destroy(C); -} - void EnumDecl::completeDefinition(QualType NewType, QualType NewPromotionType, unsigned NumPositiveBits, @@ -1719,13 +1681,6 @@ RecordDecl *RecordDecl::Create(ASTContext &C, EmptyShell Empty) { SourceLocation()); } -RecordDecl::~RecordDecl() { -} - -void RecordDecl::Destroy(ASTContext& C) { - TagDecl::Destroy(C); -} - bool RecordDecl::isInjectedClassName() const { return isImplicit() && getDeclName() && getDeclContext()->isRecord() && cast(getDeclContext())->getDeclName() == getDeclName(); @@ -1753,20 +1708,6 @@ ValueDecl *RecordDecl::getAnonymousStructOrUnionObject() { // BlockDecl Implementation //===----------------------------------------------------------------------===// -BlockDecl::~BlockDecl() { -} - -void BlockDecl::Destroy(ASTContext& C) { - if (Body) - Body->Destroy(C); - - for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) - (*I)->Destroy(C); - - C.Deallocate(ParamInfo); - Decl::Destroy(C); -} - void BlockDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NParms) { assert(ParamInfo == 0 && "Already has param info!"); @@ -1798,27 +1739,17 @@ NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, return new (C) NamespaceDecl(DC, L, Id); } -void NamespaceDecl::Destroy(ASTContext& C) { - // NamespaceDecl uses "NextDeclarator" to chain namespace declarations - // together. They are all top-level Decls. - - this->~NamespaceDecl(); - Decl::Destroy(C); -} - - ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, QualType T) { return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T); } FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - DeclarationName N, QualType T, - TypeSourceInfo *TInfo, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, StorageClass S, StorageClass SCAsWritten, bool isInline, bool hasWrittenPrototype) { - FunctionDecl *New = new (C) FunctionDecl(Function, DC, L, N, T, TInfo, + FunctionDecl *New = new (C) FunctionDecl(Function, DC, NameInfo, T, TInfo, S, SCAsWritten, isInline); New->HasWrittenPrototype = hasWrittenPrototype; return New; @@ -1835,9 +1766,11 @@ EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, return new (C) EnumConstantDecl(CD, L, Id, T, E, V); } -void EnumConstantDecl::Destroy(ASTContext& C) { - if (Init) Init->Destroy(C); - ValueDecl::Destroy(C); +SourceRange EnumConstantDecl::getSourceRange() const { + SourceLocation End = getLocation(); + if (Init) + End = Init->getLocEnd(); + return SourceRange(getLocation(), End); } TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, @@ -1846,9 +1779,6 @@ TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, return new (C) TypedefDecl(DC, L, Id, TInfo); } -// Anchor TypedefDecl's vtable here. -TypedefDecl::~TypedefDecl() {} - FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, StringLiteral *Str) { diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index d4f997d..0b958fe 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -157,9 +157,7 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { //===----------------------------------------------------------------------===// // Out-of-line virtual method providing a home for Decl. -Decl::~Decl() { - assert(!HasAttrs && "attributes should have been freed by Destroy"); -} +Decl::~Decl() { } void Decl::setDeclContext(DeclContext *DC) { if (isOutOfSemaDC()) @@ -314,35 +312,25 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { return 0; } -void Decl::initAttrs(Attr *attrs) { +void Decl::setAttrs(const AttrVec &attrs) { assert(!HasAttrs && "Decl already contains attrs."); - Attr *&AttrBlank = getASTContext().getDeclAttrs(this); - assert(AttrBlank == 0 && "HasAttrs was wrong?"); + AttrVec &AttrBlank = getASTContext().getDeclAttrs(this); + assert(AttrBlank.empty() && "HasAttrs was wrong?"); AttrBlank = attrs; HasAttrs = true; } -void Decl::addAttr(Attr *NewAttr) { - Attr *&ExistingAttr = getASTContext().getDeclAttrs(this); - - assert(NewAttr->getNext() == 0 && "Chain of attributes will be truncated!"); - NewAttr->setNext(ExistingAttr); - ExistingAttr = NewAttr; - - HasAttrs = true; -} - -void Decl::invalidateAttrs() { +void Decl::dropAttrs() { if (!HasAttrs) return; HasAttrs = false; getASTContext().eraseDeclAttrs(this); } -const Attr *Decl::getAttrsImpl() const { - assert(HasAttrs && "getAttrs() should verify this!"); +const AttrVec &Decl::getAttrs() const { + assert(HasAttrs && "No attrs to get!"); return getASTContext().getDeclAttrs(this); } @@ -372,40 +360,6 @@ void Decl::swapAttrs(Decl *RHS) { RHS->HasAttrs = true; } -void Decl::Destroy(ASTContext &C) { - // Free attributes for this decl. - if (HasAttrs) { - C.getDeclAttrs(this)->Destroy(C); - invalidateAttrs(); - HasAttrs = false; - } - -#if 0 - // FIXME: Once ownership is fully understood, we can enable this code - if (DeclContext *DC = dyn_cast(this)) - DC->decls_begin()->Destroy(C); - - // Observe the unrolled recursion. By setting N->NextDeclInContext = 0x0 - // within the loop, only the Destroy method for the first Decl - // will deallocate all of the Decls in a chain. - - Decl* N = getNextDeclInContext(); - - while (N) { - Decl* Tmp = N->getNextDeclInContext(); - N->NextDeclInContext = 0; - N->Destroy(C); - N = Tmp; - } - - if (isOutOfSemaDC()) - delete (C) getMultipleDC(); - - this->~Decl(); - C.Deallocate((void *)this); -#endif -} - Decl *Decl::castFromDeclContext (const DeclContext *D) { Decl::Kind DK = D->getDeclKind(); switch(DK) { @@ -506,17 +460,7 @@ bool DeclContext::classof(const Decl *D) { } } -DeclContext::~DeclContext() { - // FIXME: Currently ~ASTContext will delete the StoredDeclsMaps because - // ~DeclContext() is not guaranteed to be called when ASTContext uses - // a BumpPtrAllocator. - // delete LookupPtr; -} - -void DeclContext::DestroyDecls(ASTContext &C) { - for (decl_iterator D = decls_begin(); D != decls_end(); ) - (*D++)->Destroy(C); -} +DeclContext::~DeclContext() { } /// \brief Find the parent context of this context that will be /// used for unqualified name lookup. @@ -527,13 +471,18 @@ void DeclContext::DestroyDecls(ASTContext &C) { DeclContext *DeclContext::getLookupParent() { // FIXME: Find a better way to identify friends if (isa(this)) - if (getParent()->getLookupContext()->isFileContext() && - getLexicalParent()->getLookupContext()->isRecord()) + if (getParent()->getRedeclContext()->isFileContext() && + getLexicalParent()->getRedeclContext()->isRecord()) return getLexicalParent(); return getParent(); } +bool DeclContext::isInlineNamespace() const { + return isNamespace() && + cast(this)->isInline(); +} + bool DeclContext::isDependentContext() const { if (isFileContext()) return false; @@ -565,13 +514,11 @@ bool DeclContext::isTransparentContext() const { return true; else if (DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord) return cast(this)->isAnonymousStructOrUnion(); - else if (DeclKind == Decl::Namespace) - return false; // FIXME: Check for C++0x inline namespaces return false; } -bool DeclContext::Encloses(DeclContext *DC) { +bool DeclContext::Encloses(const DeclContext *DC) const { if (getPrimaryContext() != this) return getPrimaryContext()->Encloses(DC); @@ -652,6 +599,9 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const { ExternalASTSource *Source = getParentASTContext().getExternalSource(); assert(hasExternalLexicalStorage() && Source && "No external storage?"); + // Notify that we have a DeclContext that is initializing. + ExternalASTSource::Deserializing ADeclContext(Source); + llvm::SmallVector Decls; if (Source->FindExternalLexicalDecls(this, Decls)) return; @@ -701,19 +651,6 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC, DeclContext::lookup_result ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, - const VisibleDeclaration &VD) { - ASTContext &Context = DC->getParentASTContext(); - StoredDeclsMap *Map; - if (!(Map = DC->LookupPtr)) - Map = DC->CreateStoredDeclsMap(Context); - - StoredDeclsList &List = (*Map)[VD.Name]; - List.setFromDeclIDs(VD.Declarations); - return List.getLookupResult(Context); -} - -DeclContext::lookup_result -ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, DeclarationName Name, llvm::SmallVectorImpl &Decls) { ASTContext &Context = DC->getParentASTContext();; @@ -730,35 +667,34 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, List.AddSubsequentDecl(Decls[I]); } - return List.getLookupResult(Context); + return List.getLookupResult(); } -void ExternalASTSource::SetExternalVisibleDecls(const DeclContext *DC, - const llvm::SmallVectorImpl &Decls) { - // There is no longer any visible storage in this context. - DC->ExternalVisibleStorage = false; - - assert(!DC->LookupPtr && "Have a lookup map before de-serialization?"); - StoredDeclsMap *Map = DC->CreateStoredDeclsMap(DC->getParentASTContext()); - for (unsigned I = 0, N = Decls.size(); I != N; ++I) { - (*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations); +void ExternalASTSource::MaterializeVisibleDeclsForName(const DeclContext *DC, + DeclarationName Name, + llvm::SmallVectorImpl &Decls) { + assert(DC->LookupPtr); + StoredDeclsMap &Map = *DC->LookupPtr; + + // If there's an entry in the table the visible decls for this name have + // already been deserialized. + if (Map.find(Name) == Map.end()) { + StoredDeclsList &List = Map[Name]; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + if (List.isNull()) + List.setOnlyValue(Decls[I]); + else + List.AddSubsequentDecl(Decls[I]); + } } } -void ExternalASTSource::SetExternalVisibleDecls(const DeclContext *DC, - const llvm::SmallVectorImpl &Decls) { - // There is no longer any visible storage in this context. - DC->ExternalVisibleStorage = false; +DeclContext::decl_iterator DeclContext::noload_decls_begin() const { + return decl_iterator(FirstDecl); +} - assert(!DC->LookupPtr && "Have a lookup map before de-serialization?"); - StoredDeclsMap &Map = *DC->CreateStoredDeclsMap(DC->getParentASTContext()); - for (unsigned I = 0, N = Decls.size(); I != N; ++I) { - StoredDeclsList &List = Map[Decls[I]->getDeclName()]; - if (List.isNull()) - List.setOnlyValue(Decls[I]); - else - List.AddSubsequentDecl(Decls[I]); - } +DeclContext::decl_iterator DeclContext::noload_decls_end() const { + return decl_iterator(); } DeclContext::decl_iterator DeclContext::decls_begin() const { @@ -866,10 +802,10 @@ void DeclContext::buildLookup(DeclContext *DCtx) { I != IEnd; ++I) makeDeclVisibleInContextImpl(I->getInterface()); - // If this declaration is itself a transparent declaration context, - // add its members (recursively). + // If this declaration is itself a transparent declaration context or + // inline namespace, add its members (recursively). if (DeclContext *InnerCtx = dyn_cast(*D)) - if (InnerCtx->isTransparentContext()) + if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) buildLookup(InnerCtx->getPrimaryContext()); } } @@ -886,7 +822,7 @@ DeclContext::lookup(DeclarationName Name) { if (LookupPtr) { StoredDeclsMap::iterator I = LookupPtr->find(Name); if (I != LookupPtr->end()) - return I->second.getLookupResult(getParentASTContext()); + return I->second.getLookupResult(); } ExternalASTSource *Source = getParentASTContext().getExternalSource(); @@ -906,7 +842,7 @@ DeclContext::lookup(DeclarationName Name) { StoredDeclsMap::iterator Pos = LookupPtr->find(Name); if (Pos == LookupPtr->end()) return lookup_result(lookup_iterator(0), lookup_iterator(0)); - return Pos->second.getLookupResult(getParentASTContext()); + return Pos->second.getLookupResult(); } DeclContext::lookup_const_result @@ -914,7 +850,7 @@ DeclContext::lookup(DeclarationName Name) const { return const_cast(this)->lookup(Name); } -DeclContext *DeclContext::getLookupContext() { +DeclContext *DeclContext::getRedeclContext() { DeclContext *Ctx = this; // Skip through transparent contexts. while (Ctx->isTransparentContext()) @@ -925,11 +861,29 @@ DeclContext *DeclContext::getLookupContext() { DeclContext *DeclContext::getEnclosingNamespaceContext() { DeclContext *Ctx = this; // Skip through non-namespace, non-translation-unit contexts. - while (!Ctx->isFileContext() || Ctx->isTransparentContext()) + while (!Ctx->isFileContext()) Ctx = Ctx->getParent(); return Ctx->getPrimaryContext(); } +bool DeclContext::InEnclosingNamespaceSetOf(const DeclContext *O) const { + // For non-file contexts, this is equivalent to Equals. + if (!isFileContext()) + return O->Equals(this); + + do { + if (O->Equals(this)) + return true; + + const NamespaceDecl *NS = dyn_cast(O); + if (!NS || !NS->isInline()) + break; + O = NS->getParent(); + } while (O); + + return false; +} + void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) { // FIXME: This feels like a hack. Should DeclarationName support // template-ids, or is there a better way to keep specializations @@ -953,9 +907,9 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) { if (LookupPtr || !Recoverable || hasExternalVisibleStorage()) makeDeclVisibleInContextImpl(D); - // If we are a transparent context, insert into our parent context, - // too. This operation is recursive. - if (isTransparentContext()) + // If we are a transparent context or inline namespace, insert into our + // parent context, too. This operation is recursive. + if (isTransparentContext() || isInlineNamespace()) getParent()->makeDeclVisibleInContext(D, Recoverable); } @@ -970,18 +924,21 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { if (isa(D)) return; - // If there is an external AST source, load any declarations it knows about - // with this declaration's name. - if (ExternalASTSource *Source = getParentASTContext().getExternalSource()) - if (hasExternalVisibleStorage()) - Source->FindExternalVisibleDeclsByName(this, D->getDeclName()); - ASTContext *C = 0; if (!LookupPtr) { C = &getParentASTContext(); CreateStoredDeclsMap(*C); } + // If there is an external AST source, load any declarations it knows about + // with this declaration's name. + // If the lookup table contains an entry about this name it means that we + // have already checked the external source. + if (ExternalASTSource *Source = getParentASTContext().getExternalSource()) + if (hasExternalVisibleStorage() && + LookupPtr->find(D->getDeclName()) == LookupPtr->end()) + Source->FindExternalVisibleDeclsByName(this, D->getDeclName()); + // Insert this declaration into the map. StoredDeclsList &DeclNameEntries = (*LookupPtr)[D->getDeclName()]; if (DeclNameEntries.isNull()) { @@ -992,16 +949,22 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { // If it is possible that this is a redeclaration, check to see if there is // already a decl for which declarationReplaces returns true. If there is // one, just replace it and return. - if (!C) - C = &getParentASTContext(); - - if (DeclNameEntries.HandleRedeclaration(*C, D)) + if (DeclNameEntries.HandleRedeclaration(D)) return; // Put this declaration into the appropriate slot. DeclNameEntries.AddSubsequentDecl(D); } +void DeclContext::MaterializeVisibleDeclsFromExternalStorage() { + ExternalASTSource *Source = getParentASTContext().getExternalSource(); + assert(hasExternalVisibleStorage() && Source && "No external storage?"); + + if (!LookupPtr) + CreateStoredDeclsMap(getParentASTContext()); + Source->MaterializeVisibleDecls(this); +} + /// Returns iterator range [First, Last) of UsingDirectiveDecls stored within /// this context. DeclContext::udir_iterator_range @@ -1011,43 +974,6 @@ DeclContext::getUsingDirectives() const { reinterpret_cast(Result.second)); } -void StoredDeclsList::materializeDecls(ASTContext &Context) { - if (isNull()) - return; - - switch ((DataKind)(Data & 0x03)) { - case DK_Decl: - case DK_Decl_Vector: - break; - - case DK_DeclID: { - // Resolve this declaration ID to an actual declaration by - // querying the external AST source. - unsigned DeclID = Data >> 2; - - ExternalASTSource *Source = Context.getExternalSource(); - assert(Source && "No external AST source available!"); - - Data = reinterpret_cast(Source->GetExternalDecl(DeclID)); - break; - } - - case DK_ID_Vector: { - // We have a vector of declaration IDs. Resolve all of them to - // actual declarations. - VectorTy &Vector = *getAsVector(); - ExternalASTSource *Source = Context.getExternalSource(); - assert(Source && "No external AST source available!"); - - for (unsigned I = 0, N = Vector.size(); I != N; ++I) - Vector[I] = reinterpret_cast(Source->GetExternalDecl(Vector[I])); - - Data = (Data & ~0x03) | DK_Decl_Vector; - break; - } - } -} - //===----------------------------------------------------------------------===// // Creation and Destruction of StoredDeclsMaps. // //===----------------------------------------------------------------------===// @@ -1073,7 +999,6 @@ void ASTContext::ReleaseDeclContextMaps() { // It's okay to delete DependentStoredDeclsMaps via a StoredDeclsMap // pointer because the subclass doesn't add anything that needs to // be deleted. - StoredDeclsMap::DestroyAll(LastSDM.getPointer(), LastSDM.getInt()); } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index dd0fe08..f2f0694 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -65,18 +65,6 @@ CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, EmptyShell Empty) { SourceLocation()); } -CXXRecordDecl::~CXXRecordDecl() { -} - -void CXXRecordDecl::Destroy(ASTContext &C) { - if (data().Definition == this) { - C.Deallocate(data().Bases); - C.Deallocate(data().VBases); - C.Deallocate(&data()); - } - this->RecordDecl::Destroy(C); -} - void CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases) { @@ -133,19 +121,19 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, data().VBases = new (C) CXXBaseSpecifier[VBases.size()]; data().NumVBases = VBases.size(); for (int I = 0, E = VBases.size(); I != E; ++I) { - QualType VBaseType = VBases[I]->getType(); - + TypeSourceInfo *VBaseTypeInfo = VBases[I]->getTypeSourceInfo(); + // Skip dependent types; we can't do any checking on them now. - if (VBaseType->isDependentType()) + if (VBaseTypeInfo->getType()->isDependentType()) continue; - CXXRecordDecl *VBaseClassDecl - = cast(VBaseType->getAs()->getDecl()); + CXXRecordDecl *VBaseClassDecl = cast( + VBaseTypeInfo->getType()->getAs()->getDecl()); data().VBases[I] = CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, VBaseClassDecl->getTagKind() == TTK_Class, - VBases[I]->getAccessSpecifier(), VBaseType); + VBases[I]->getAccessSpecifier(), VBaseTypeInfo); } } @@ -621,7 +609,8 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const { DeclContext::lookup_const_iterator I, E; llvm::tie(I, E) = lookup(Name); - assert(I != E && "Did not find a destructor!"); + if (I == E) + return 0; CXXDestructorDecl *Dtor = cast(*I); assert(++I == E && "Found more than one destructor!"); @@ -631,10 +620,10 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const { CXXMethodDecl * CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation L, DeclarationName N, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isStatic, StorageClass SCAsWritten, bool isInline) { - return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, TInfo, + return new (C) CXXMethodDecl(CXXMethod, RD, NameInfo, T, TInfo, isStatic, SCAsWritten, isInline); } @@ -796,13 +785,6 @@ CXXBaseOrMemberInitializer::Create(ASTContext &Context, L, Init, R, Indices, NumIndices); } -void CXXBaseOrMemberInitializer::Destroy(ASTContext &Context) { - if (Init) - Init->Destroy(Context); - // FIXME: Destroy indices - this->~CXXBaseOrMemberInitializer(); -} - TypeLoc CXXBaseOrMemberInitializer::getBaseClassLoc() const { if (isBaseInitializer()) return BaseOrMember.get()->getTypeLoc(); @@ -837,20 +819,21 @@ SourceRange CXXBaseOrMemberInitializer::getSourceRange() const { CXXConstructorDecl * CXXConstructorDecl::Create(ASTContext &C, EmptyShell Empty) { - return new (C) CXXConstructorDecl(0, SourceLocation(), DeclarationName(), + return new (C) CXXConstructorDecl(0, DeclarationNameInfo(), QualType(), 0, false, false, false); } CXXConstructorDecl * CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation L, DeclarationName N, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isExplicit, bool isInline, bool isImplicitlyDeclared) { - assert(N.getNameKind() == DeclarationName::CXXConstructorName && + assert(NameInfo.getName().getNameKind() + == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); - return new (C) CXXConstructorDecl(RD, L, N, T, TInfo, isExplicit, + return new (C) CXXConstructorDecl(RD, NameInfo, T, TInfo, isExplicit, isInline, isImplicitlyDeclared); } @@ -945,40 +928,38 @@ bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const { CXXDestructorDecl * CXXDestructorDecl::Create(ASTContext &C, EmptyShell Empty) { - return new (C) CXXDestructorDecl(0, SourceLocation(), DeclarationName(), + return new (C) CXXDestructorDecl(0, DeclarationNameInfo(), QualType(), false, false); } CXXDestructorDecl * CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation L, DeclarationName N, + const DeclarationNameInfo &NameInfo, QualType T, bool isInline, bool isImplicitlyDeclared) { - assert(N.getNameKind() == DeclarationName::CXXDestructorName && + assert(NameInfo.getName().getNameKind() + == DeclarationName::CXXDestructorName && "Name must refer to a destructor"); - return new (C) CXXDestructorDecl(RD, L, N, T, isInline, isImplicitlyDeclared); -} - -void -CXXConstructorDecl::Destroy(ASTContext& C) { - C.Deallocate(BaseOrMemberInitializers); - CXXMethodDecl::Destroy(C); + return new (C) CXXDestructorDecl(RD, NameInfo, T, isInline, + isImplicitlyDeclared); } CXXConversionDecl * CXXConversionDecl::Create(ASTContext &C, EmptyShell Empty) { - return new (C) CXXConversionDecl(0, SourceLocation(), DeclarationName(), + return new (C) CXXConversionDecl(0, DeclarationNameInfo(), QualType(), 0, false, false); } CXXConversionDecl * CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation L, DeclarationName N, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isInline, bool isExplicit) { - assert(N.getNameKind() == DeclarationName::CXXConversionFunctionName && + assert(NameInfo.getName().getNameKind() + == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); - return new (C) CXXConversionDecl(RD, L, N, T, TInfo, isInline, isExplicit); + return new (C) CXXConversionDecl(RD, NameInfo, T, TInfo, + isInline, isExplicit); } LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, @@ -1009,14 +990,8 @@ NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() { return cast_or_null(NominatedNamespace); } -void UsingDirectiveDecl::setNominatedNamespace(NamedDecl* ND) { - assert((isa(ND) || isa(ND)) && - "expected a NamespaceDecl or NamespaceAliasDecl"); - NominatedNamespace = ND; -} - NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, + SourceLocation UsingLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, SourceRange QualifierRange, @@ -1025,15 +1000,16 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, NamedDecl *Namespace) { if (NamespaceDecl *NS = dyn_cast_or_null(Namespace)) Namespace = NS->getOriginalNamespace(); - return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange, + return new (C) NamespaceAliasDecl(DC, UsingLoc, AliasLoc, Alias, QualifierRange, Qualifier, IdentLoc, Namespace); } UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, SourceRange NNR, SourceLocation UL, - NestedNameSpecifier* TargetNNS, DeclarationName Name, - bool IsTypeNameArg) { - return new (C) UsingDecl(DC, L, NNR, UL, TargetNNS, Name, IsTypeNameArg); + SourceRange NNR, SourceLocation UL, + NestedNameSpecifier* TargetNNS, + const DeclarationNameInfo &NameInfo, + bool IsTypeNameArg) { + return new (C) UsingDecl(DC, NNR, UL, TargetNNS, NameInfo, IsTypeNameArg); } UnresolvedUsingValueDecl * @@ -1041,11 +1017,9 @@ UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, SourceRange TargetNNR, NestedNameSpecifier *TargetNNS, - SourceLocation TargetNameLoc, - DeclarationName TargetName) { + const DeclarationNameInfo &NameInfo) { return new (C) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc, - TargetNNR, TargetNNS, - TargetNameLoc, TargetName); + TargetNNR, TargetNNS, NameInfo); } UnresolvedUsingTypenameDecl * @@ -1068,15 +1042,6 @@ StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC, return new (C) StaticAssertDecl(DC, L, AssertExpr, Message); } -void StaticAssertDecl::Destroy(ASTContext& C) { - AssertExpr->Destroy(C); - Message->Destroy(C); - Decl::Destroy(C); -} - -StaticAssertDecl::~StaticAssertDecl() { -} - static const char *getAccessName(AccessSpecifier AS) { switch (AS) { default: @@ -1096,5 +1061,3 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, AccessSpecifier AS) { return DB << getAccessName(AS); } - - diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp index 434bf00..036acc2 100644 --- a/lib/AST/DeclGroup.cpp +++ b/lib/AST/DeclGroup.cpp @@ -30,9 +30,3 @@ DeclGroup::DeclGroup(unsigned numdecls, Decl** decls) : NumDecls(numdecls) { assert(decls); memcpy(this+1, decls, numdecls * sizeof(*decls)); } - -void DeclGroup::Destroy(ASTContext& C) { - // Decls are destroyed by the DeclContext. - this->~DeclGroup(); - C.Deallocate((void*) this); -} diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index adb0e7d..d952cc3 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -21,14 +21,8 @@ using namespace clang; // ObjCListBase //===----------------------------------------------------------------------===// -void ObjCListBase::Destroy(ASTContext &Ctx) { - Ctx.Deallocate(List); - NumElts = 0; - List = 0; -} - void ObjCListBase::set(void *const* InList, unsigned Elts, ASTContext &Ctx) { - assert(List == 0 && "Elements already set!"); + List = 0; if (Elts == 0) return; // Setting to an empty list is a noop. @@ -47,12 +41,6 @@ void ObjCProtocolList::set(ObjCProtocolDecl* const* InList, unsigned Elts, set(InList, Elts, Ctx); } -void ObjCProtocolList::Destroy(ASTContext &Ctx) { - Ctx.Deallocate(Locations); - Locations = 0; - ObjCList::Destroy(Ctx); -} - //===----------------------------------------------------------------------===// // ObjCInterfaceDecl //===----------------------------------------------------------------------===// @@ -132,8 +120,9 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { return P; // Look through protocols. - for (ObjCInterfaceDecl::protocol_iterator - I = OID->protocol_begin(), E = OID->protocol_end(); I != E; ++I) + for (ObjCInterfaceDecl::all_protocol_iterator + I = OID->all_referenced_protocol_begin(), + E = OID->all_referenced_protocol_end(); I != E; ++I) if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) return P; @@ -169,8 +158,9 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( return PD; // Look through protocols. - for (ObjCInterfaceDecl::protocol_iterator - I = protocol_begin(), E = protocol_end(); I != E; ++I) + for (ObjCInterfaceDecl::all_protocol_iterator + I = all_referenced_protocol_begin(), + E = all_referenced_protocol_end(); I != E; ++I) if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) return P; @@ -179,23 +169,23 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( void ObjCInterfaceDecl::mergeClassExtensionProtocolList( ObjCProtocolDecl *const* ExtList, unsigned ExtNum, - const SourceLocation *Locs, ASTContext &C) { - if (ReferencedProtocols.empty()) { - ReferencedProtocols.set(ExtList, ExtNum, Locs, C); + if (AllReferencedProtocols.empty() && ReferencedProtocols.empty()) { + AllReferencedProtocols.set(ExtList, ExtNum, C); return; } + // Check for duplicate protocol in class's protocol list. - // This is (O)2. But it is extremely rare and number of protocols in + // This is O(n*m). But it is extremely rare and number of protocols in // class or its extension are very few. llvm::SmallVector ProtocolRefs; - llvm::SmallVector ProtocolLocs; for (unsigned i = 0; i < ExtNum; i++) { bool protocolExists = false; ObjCProtocolDecl *ProtoInExtension = ExtList[i]; - for (protocol_iterator p = protocol_begin(), e = protocol_end(); - p != e; p++) { + for (all_protocol_iterator + p = all_referenced_protocol_begin(), + e = all_referenced_protocol_end(); p != e; ++p) { ObjCProtocolDecl *Proto = (*p); if (C.ProtocolCompatibleWithProtocol(ProtoInExtension, Proto)) { protocolExists = true; @@ -204,23 +194,20 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList( } // Do we want to warn on a protocol in extension class which // already exist in the class? Probably not. - if (!protocolExists) { + if (!protocolExists) ProtocolRefs.push_back(ProtoInExtension); - ProtocolLocs.push_back(Locs[i]); - } } + if (ProtocolRefs.empty()) return; + // Merge ProtocolRefs into class's protocol list; - protocol_loc_iterator pl = protocol_loc_begin(); - for (protocol_iterator p = protocol_begin(), e = protocol_end(); - p != e; ++p, ++pl) { + for (all_protocol_iterator p = all_referenced_protocol_begin(), + e = all_referenced_protocol_end(); p != e; ++p) { ProtocolRefs.push_back(*p); - ProtocolLocs.push_back(*pl); } - ReferencedProtocols.Destroy(C); - unsigned NumProtoRefs = ProtocolRefs.size(); - setProtocolList(ProtocolRefs.data(), NumProtoRefs, ProtocolLocs.data(), C); + + AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(), C); } /// getFirstClassExtension - Find first class extension of the given class. @@ -339,27 +326,17 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, bool isInstance, bool isVariadic, bool isSynthesized, + bool isDefined, ImplementationControl impControl, unsigned numSelectorArgs) { return new (C) ObjCMethodDecl(beginLoc, endLoc, SelInfo, T, ResultTInfo, contextDecl, isInstance, - isVariadic, isSynthesized, impControl, + isVariadic, isSynthesized, isDefined, + impControl, numSelectorArgs); } -void ObjCMethodDecl::Destroy(ASTContext &C) { - if (Body) Body->Destroy(C); - if (SelfDecl) SelfDecl->Destroy(C); - - for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) - if (*I) (*I)->Destroy(C); - - ParamInfo.Destroy(C); - - Decl::Destroy(C); -} - /// \brief A definition will return its interface declaration. /// An interface declaration will return its definition. /// Otherwise it will return itself. @@ -465,22 +442,11 @@ ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, SourceLocation CLoc, bool FD, bool isInternal) : ObjCContainerDecl(ObjCInterface, DC, atLoc, Id), TypeForDecl(0), SuperClass(0), - CategoryList(0), ForwardDecl(FD), InternalInterface(isInternal), + CategoryList(0), IvarList(0), + ForwardDecl(FD), InternalInterface(isInternal), ClassLoc(CLoc) { } -void ObjCInterfaceDecl::Destroy(ASTContext &C) { - for (ivar_iterator I = ivar_begin(), E = ivar_end(); I != E; ++I) - if (*I) (*I)->Destroy(C); - - // FIXME: CategoryList? - - // FIXME: Because there is no clear ownership - // role between ObjCInterfaceDecls and the ObjCPropertyDecls that they - // reference, we destroy ObjCPropertyDecls in ~TranslationUnit. - Decl::Destroy(C); -} - ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const { return getASTContext().getObjCImplementation( const_cast(this)); @@ -490,6 +456,49 @@ void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) { getASTContext().setObjCImplementation(this, ImplD); } +/// all_declared_ivar_begin - return first ivar declared in this class, +/// its extensions and its implementation. Lazily build the list on first +/// access. +ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() { + if (IvarList) + return IvarList; + + ObjCIvarDecl *curIvar = 0; + if (!ivar_empty()) { + ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end(); + IvarList = (*I); ++I; + for (curIvar = IvarList; I != E; curIvar = *I, ++I) + curIvar->setNextIvar(*I); + } + + for (const ObjCCategoryDecl *CDecl = getFirstClassExtension(); CDecl; + CDecl = CDecl->getNextClassExtension()) { + if (!CDecl->ivar_empty()) { + ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), + E = CDecl->ivar_end(); + if (!IvarList) { + IvarList = (*I); ++I; + curIvar = IvarList; + } + for ( ;I != E; curIvar = *I, ++I) + curIvar->setNextIvar(*I); + } + } + + if (ObjCImplementationDecl *ImplDecl = getImplementation()) { + if (!ImplDecl->ivar_empty()) { + ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(), + E = ImplDecl->ivar_end(); + if (!IvarList) { + IvarList = (*I); ++I; + curIvar = IvarList; + } + for ( ;I != E; curIvar = *I, ++I) + curIvar->setNextIvar(*I); + } + } + return IvarList; +} /// FindCategoryDeclaration - Finds category declaration in the list of /// categories for this class and returns it. Name of the category is passed @@ -575,7 +584,8 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto, ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - AccessControl ac, Expr *BW) { + AccessControl ac, Expr *BW, + bool synthesized) { if (DC) { // Ivar's can only appear in interfaces, implementations (via synthesized // properties), and class extensions (via direct declaration, or synthesized @@ -590,9 +600,26 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, assert((isa(DC) || isa(DC) || isa(DC)) && "Invalid ivar decl context!"); + // Once a new ivar is created in any of class/class-extension/implementation + // decl contexts, the previously built IvarList must be rebuilt. + ObjCInterfaceDecl *ID = dyn_cast(DC); + if (!ID) { + if (ObjCImplementationDecl *IM = dyn_cast(DC)) { + ID = IM->getClassInterface(); + if (BW) + IM->setHasSynthBitfield(true); + } + else { + ObjCCategoryDecl *CD = cast(DC); + ID = CD->getClassInterface(); + if (BW) + CD->setHasSynthBitfield(true); + } + } + ID->setIvarList(0); } - return new (C) ObjCIvarDecl(DC, L, Id, T, TInfo, ac, BW); + return new (C) ObjCIvarDecl(DC, L, Id, T, TInfo, ac, BW, synthesized); } const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { @@ -630,11 +657,6 @@ ObjCAtDefsFieldDecl return new (C) ObjCAtDefsFieldDecl(DC, L, Id, T, BW); } -void ObjCAtDefsFieldDecl::Destroy(ASTContext& C) { - this->~ObjCAtDefsFieldDecl(); - C.Deallocate((void *)this); -} - //===----------------------------------------------------------------------===// // ObjCProtocolDecl //===----------------------------------------------------------------------===// @@ -645,11 +667,6 @@ ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCProtocolDecl(DC, L, Id); } -void ObjCProtocolDecl::Destroy(ASTContext &C) { - ReferencedProtocols.Destroy(C); - ObjCContainerDecl::Destroy(C); -} - ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) { ObjCProtocolDecl *PDecl = this; @@ -709,23 +726,6 @@ ObjCClassDecl *ObjCClassDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCClassDecl(DC, L, Elts, Locs, nElts, C); } -void ObjCClassDecl::Destroy(ASTContext &C) { - // ObjCInterfaceDecls registered with a DeclContext will get destroyed - // when the DeclContext is destroyed. For those created only by a forward - // declaration, the first @class that created the ObjCInterfaceDecl gets - // to destroy it. - // FIXME: Note that this ownership role is very brittle; a better - // polict is surely need in the future. - for (iterator I = begin(), E = end(); I !=E ; ++I) { - ObjCInterfaceDecl *ID = I->getInterface(); - if (ID->isForwardDecl() && ID->getLocStart() == getLocStart()) - ID->Destroy(C); - } - - C.Deallocate(ForwardDecls); - Decl::Destroy(C); -} - SourceRange ObjCClassDecl::getSourceRange() const { // FIXME: We should include the semicolon assert(NumDecls); @@ -754,11 +754,6 @@ ObjCForwardProtocolDecl::Create(ASTContext &C, DeclContext *DC, return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, Locs, C); } -void ObjCForwardProtocolDecl::Destroy(ASTContext &C) { - ReferencedProtocols.Destroy(C); - Decl::Destroy(C); -} - //===----------------------------------------------------------------------===// // ObjCCategoryDecl //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 765772d..f18d2f0 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -198,6 +198,12 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { llvm::SmallVector Decls; for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end(); D != DEnd; ++D) { + + // Don't print ObjCIvarDecls, as they are printed when visiting the + // containing ObjCInterfaceDecl. + if (isa(*D)) + continue; + if (!Policy.Dump) { // Skip over implicit declarations in pretty-printing mode. if (D->isImplicit()) continue; @@ -329,10 +335,11 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (!Policy.SuppressSpecifiers) { switch (D->getStorageClass()) { - case FunctionDecl::None: break; - case FunctionDecl::Extern: Out << "extern "; break; - case FunctionDecl::Static: Out << "static "; break; - case FunctionDecl::PrivateExtern: Out << "__private_extern__ "; break; + case SC_None: break; + case SC_Extern: Out << "extern "; break; + case SC_Static: Out << "static "; break; + case SC_PrivateExtern: Out << "__private_extern__ "; break; + case SC_Auto: case SC_Register: llvm_unreachable("invalid for functions"); } if (D->isInlineSpecified()) Out << "inline "; @@ -341,7 +348,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { PrintingPolicy SubPolicy(Policy); SubPolicy.SuppressSpecifiers = false; - std::string Proto = D->getNameAsString(); + std::string Proto = D->getNameInfo().getAsString(); if (isa(D->getType().getTypePtr())) { const FunctionType *AFT = D->getType()->getAs(); @@ -499,7 +506,7 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) { } void DeclPrinter::VisitVarDecl(VarDecl *D) { - if (!Policy.SuppressSpecifiers && D->getStorageClass() != VarDecl::None) + if (!Policy.SuppressSpecifiers && D->getStorageClass() != SC_None) Out << VarDecl::getStorageClassSpecifierString(D->getStorageClass()) << " "; if (!Policy.SuppressSpecifiers && D->isThreadSpecified()) diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 9e1d79d..e69338a 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -84,10 +84,59 @@ unsigned TemplateParameterList::getDepth() const { } //===----------------------------------------------------------------------===// -// TemplateDecl Implementation +// RedeclarableTemplateDecl Implementation //===----------------------------------------------------------------------===// -TemplateDecl::~TemplateDecl() { +RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() { + // Find the first declaration of this function template. + RedeclarableTemplateDecl *First = getCanonicalDecl(); + + if (First->CommonOrPrev.isNull()) { + CommonBase *CommonPtr = First->newCommon(); + First->CommonOrPrev = CommonPtr; + CommonPtr->Latest = First; + } + return First->CommonOrPrev.get(); +} + + +RedeclarableTemplateDecl *RedeclarableTemplateDecl::getCanonicalDeclImpl() { + RedeclarableTemplateDecl *Tmpl = this; + while (Tmpl->getPreviousDeclaration()) + Tmpl = Tmpl->getPreviousDeclaration(); + return Tmpl; +} + +void RedeclarableTemplateDecl::setPreviousDeclarationImpl( + RedeclarableTemplateDecl *Prev) { + if (Prev) { + CommonBase *Common = Prev->getCommonPtr(); + Prev = Common->Latest; + Common->Latest = this; + CommonOrPrev = Prev; + } else { + assert(CommonOrPrev.is() && "Cannot reset TemplateDecl Prev"); + } +} + +RedeclarableTemplateDecl *RedeclarableTemplateDecl::getNextRedeclaration() { + if (CommonOrPrev.is()) + return CommonOrPrev.get(); + CommonBase *Common = CommonOrPrev.get(); + return Common ? Common->Latest : this; +} + +template +typename RedeclarableTemplateDecl::SpecEntryTraits::DeclType* +RedeclarableTemplateDecl::findSpecializationImpl( + llvm::FoldingSet &Specs, + const TemplateArgument *Args, unsigned NumArgs, + void *&InsertPos) { + typedef SpecEntryTraits SETraits; + llvm::FoldingSetNodeID ID; + EntryType::Profile(ID,Args,NumArgs, getASTContext()); + EntryType *Entry = Specs.FindNodeOrInsertPos(ID, InsertPos); + return Entry ? SETraits::getMostRecentDeclaration(Entry) : 0; } //===----------------------------------------------------------------------===// @@ -107,37 +156,16 @@ FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl); } -void FunctionTemplateDecl::Destroy(ASTContext &C) { - if (Common *CommonPtr = CommonOrPrev.dyn_cast()) { - for (llvm::FoldingSet::iterator - Spec = CommonPtr->Specializations.begin(), - SpecEnd = CommonPtr->Specializations.end(); - Spec != SpecEnd; ++Spec) - C.Deallocate(&*Spec); - } - - Decl::Destroy(C); +RedeclarableTemplateDecl::CommonBase *FunctionTemplateDecl::newCommon() { + Common *CommonPtr = new (getASTContext()) Common; + getASTContext().AddDeallocation(DeallocateCommon, CommonPtr); + return CommonPtr; } -FunctionTemplateDecl *FunctionTemplateDecl::getCanonicalDecl() { - FunctionTemplateDecl *FunTmpl = this; - while (FunTmpl->getPreviousDeclaration()) - FunTmpl = FunTmpl->getPreviousDeclaration(); - return FunTmpl; -} - -FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() { - // Find the first declaration of this function template. - FunctionTemplateDecl *First = this; - while (First->getPreviousDeclaration()) - First = First->getPreviousDeclaration(); - - if (First->CommonOrPrev.isNull()) { - Common *CommonPtr = new (getASTContext()) Common; - getASTContext().AddDeallocation(DeallocateCommon, CommonPtr); - First->CommonOrPrev = CommonPtr; - } - return First->CommonOrPrev.get(); +FunctionDecl * +FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args, + unsigned NumArgs, void *&InsertPos) { + return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos); } //===----------------------------------------------------------------------===// @@ -148,13 +176,6 @@ void ClassTemplateDecl::DeallocateCommon(void *Ptr) { static_cast(Ptr)->~Common(); } -ClassTemplateDecl *ClassTemplateDecl::getCanonicalDecl() { - ClassTemplateDecl *Template = this; - while (Template->getPreviousDeclaration()) - Template = Template->getPreviousDeclaration(); - return Template; -} - ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -167,8 +188,24 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, return New; } -void ClassTemplateDecl::Destroy(ASTContext& C) { - Decl::Destroy(C); +RedeclarableTemplateDecl::CommonBase *ClassTemplateDecl::newCommon() { + Common *CommonPtr = new (getASTContext()) Common; + getASTContext().AddDeallocation(DeallocateCommon, CommonPtr); + return CommonPtr; +} + +ClassTemplateSpecializationDecl * +ClassTemplateDecl::findSpecialization(const TemplateArgument *Args, + unsigned NumArgs, void *&InsertPos) { + return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos); +} + +ClassTemplatePartialSpecializationDecl * +ClassTemplateDecl::findPartialSpecialization(const TemplateArgument *Args, + unsigned NumArgs, + void *&InsertPos) { + return findSpecializationImpl(getPartialSpecializations(), Args, NumArgs, + InsertPos); } void ClassTemplateDecl::getPartialSpecializations( @@ -181,7 +218,7 @@ void ClassTemplateDecl::getPartialSpecializations( P = PartialSpecs.begin(), PEnd = PartialSpecs.end(); P != PEnd; ++P) { assert(!PS[P->getSequenceNumber()]); - PS[P->getSequenceNumber()] = &*P; + PS[P->getSequenceNumber()] = P->getMostRecentDeclaration(); } } @@ -194,7 +231,22 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) { PEnd = getPartialSpecializations().end(); P != PEnd; ++P) { if (Context.hasSameType(P->getInjectedSpecializationType(), T)) - return &*P; + return P->getMostRecentDeclaration(); + } + + return 0; +} + +ClassTemplatePartialSpecializationDecl * +ClassTemplateDecl::findPartialSpecInstantiatedFromMember( + ClassTemplatePartialSpecializationDecl *D) { + Decl *DCanon = D->getCanonicalDecl(); + for (llvm::FoldingSet::iterator + P = getPartialSpecializations().begin(), + PEnd = getPartialSpecializations().end(); + P != PEnd; ++P) { + if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) + return P->getMostRecentDeclaration(); } return 0; @@ -239,20 +291,6 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() { return CommonPtr->InjectedClassNameType; } -ClassTemplateDecl::Common *ClassTemplateDecl::getCommonPtr() { - // Find the first declaration of this function template. - ClassTemplateDecl *First = this; - while (First->getPreviousDeclaration()) - First = First->getPreviousDeclaration(); - - if (First->CommonOrPrev.isNull()) { - Common *CommonPtr = new (getASTContext()) Common; - getASTContext().AddDeallocation(DeallocateCommon, CommonPtr); - First->CommonOrPrev = CommonPtr; - } - return First->CommonOrPrev.get(); -} - //===----------------------------------------------------------------------===// // TemplateTypeParm Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// @@ -431,15 +469,6 @@ StructuredArguments.setPointer(NewArgs); StructuredArguments.setInt(0); // Doesn't own the pointer. } -void TemplateArgumentList::Destroy(ASTContext &C) { - if (FlatArguments.getInt()) - C.Deallocate((void*)FlatArguments.getPointer()); - if (StructuredArguments.getInt()) - C.Deallocate((void*)StructuredArguments.getPointer()); -} - -TemplateArgumentList::~TemplateArgumentList() {} - //===----------------------------------------------------------------------===// // ClassTemplateSpecializationDecl Implementation //===----------------------------------------------------------------------===// @@ -487,16 +516,6 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, EmptyShell Empty) { new (Context)ClassTemplateSpecializationDecl(ClassTemplateSpecialization); } -void ClassTemplateSpecializationDecl::Destroy(ASTContext &C) { - delete ExplicitInfo; - - if (SpecializedPartialSpecialization *PartialSpec - = SpecializedTemplate.dyn_cast()) - C.Deallocate(PartialSpec); - - CXXRecordDecl::Destroy(C); -} - void ClassTemplateSpecializationDecl::getNameForDiagnostic(std::string &S, const PrintingPolicy &Policy, @@ -584,3 +603,8 @@ FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context, = new (Context) FriendTemplateDecl(DC, L, NParams, Params, Friend, FLoc); return Result; } + +FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context, + EmptyShell Empty) { + return new (Context) FriendTemplateDecl(Empty); +} diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 343d403..860a0b2 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -15,6 +15,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/DenseMap.h" @@ -404,26 +405,6 @@ DeclarationNameTable::~DeclarationNameTable() { = static_cast*> (CXXLiteralOperatorNames); - if (Ctx.FreeMemory) { - llvm::FoldingSetIterator - SI = SpecialNames->begin(), SE = SpecialNames->end(); - - while (SI != SE) { - CXXSpecialName *n = &*SI++; - Ctx.Deallocate(n); - } - - llvm::FoldingSetIterator - LI = LiteralNames->begin(), LE = LiteralNames->end(); - - while (LI != LE) { - CXXLiteralOperatorIdName *n = &*LI++; - Ctx.Deallocate(n); - } - - Ctx.Deallocate(CXXOperatorNames); - } - delete SpecialNames; delete LiteralNames; } @@ -505,3 +486,98 @@ getHashValue(clang::DeclarationName N) { return DenseMapInfo::getHashValue(N.getAsOpaquePtr()); } +DeclarationNameLoc::DeclarationNameLoc(DeclarationName Name) { + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + NamedType.TInfo = 0; + break; + case DeclarationName::CXXOperatorName: + CXXOperatorName.BeginOpNameLoc = SourceLocation().getRawEncoding(); + CXXOperatorName.EndOpNameLoc = SourceLocation().getRawEncoding(); + break; + case DeclarationName::CXXLiteralOperatorName: + CXXLiteralOperatorName.OpNameLoc = SourceLocation().getRawEncoding(); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + // FIXME: ? + break; + case DeclarationName::CXXUsingDirective: + break; + } +} + +std::string DeclarationNameInfo::getAsString() const { + std::string Result; + llvm::raw_string_ostream OS(Result); + printName(OS); + return OS.str(); +} + +void DeclarationNameInfo::printName(llvm::raw_ostream &OS) const { + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXUsingDirective: + Name.printName(OS); + return; + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo) { + if (Name.getNameKind() == DeclarationName::CXXDestructorName) + OS << '~'; + else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) + OS << "operator "; + OS << TInfo->getType().getAsString(); + } + else + Name.printName(OS); + return; + } + assert(false && "Unexpected declaration name kind"); +} + +SourceLocation DeclarationNameInfo::getEndLoc() const { + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + return NameLoc; + + case DeclarationName::CXXOperatorName: { + unsigned raw = LocInfo.CXXOperatorName.EndOpNameLoc; + return SourceLocation::getFromRawEncoding(raw); + } + + case DeclarationName::CXXLiteralOperatorName: { + unsigned raw = LocInfo.CXXLiteralOperatorName.OpNameLoc; + return SourceLocation::getFromRawEncoding(raw); + } + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo) + return TInfo->getTypeLoc().getEndLoc(); + else + return NameLoc; + + // DNInfo work in progress: FIXME. + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXUsingDirective: + return NameLoc; + } + assert(false && "Unexpected declaration name kind"); + return SourceLocation(); +} diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 6524a31..5feef1c 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -44,8 +44,8 @@ bool Expr::isKnownToHaveBooleanValue() const { if (const UnaryOperator *UO = dyn_cast(this)) { switch (UO->getOpcode()) { - case UnaryOperator::Plus: - case UnaryOperator::Extension: + case UO_Plus: + case UO_Extension: return UO->getSubExpr()->isKnownToHaveBooleanValue(); default: return false; @@ -60,25 +60,25 @@ bool Expr::isKnownToHaveBooleanValue() const { if (const BinaryOperator *BO = dyn_cast(this)) { switch (BO->getOpcode()) { default: return false; - case BinaryOperator::LT: // Relational operators. - case BinaryOperator::GT: - case BinaryOperator::LE: - case BinaryOperator::GE: - case BinaryOperator::EQ: // Equality operators. - case BinaryOperator::NE: - case BinaryOperator::LAnd: // AND operator. - case BinaryOperator::LOr: // Logical OR operator. + case BO_LT: // Relational operators. + case BO_GT: + case BO_LE: + case BO_GE: + case BO_EQ: // Equality operators. + case BO_NE: + case BO_LAnd: // AND operator. + case BO_LOr: // Logical OR operator. return true; - case BinaryOperator::And: // Bitwise AND operator. - case BinaryOperator::Xor: // Bitwise XOR operator. - case BinaryOperator::Or: // Bitwise OR operator. + case BO_And: // Bitwise AND operator. + case BO_Xor: // Bitwise XOR operator. + case BO_Or: // Bitwise OR operator. // Handle things like (x==2)|(y==12). return BO->getLHS()->isKnownToHaveBooleanValue() && BO->getRHS()->isKnownToHaveBooleanValue(); - case BinaryOperator::Comma: - case BinaryOperator::Assign: + case BO_Comma: + case BO_Assign: return BO->getRHS()->isKnownToHaveBooleanValue(); } } @@ -151,7 +151,7 @@ void DeclRefExpr::computeDependence() { ValueDependent = true; } // (TD) - a template-id that is dependent, - else if (hasExplicitTemplateArgumentList() && + else if (hasExplicitTemplateArgs() && TemplateSpecializationType::anyDependentTemplateArguments( getTemplateArgs(), getNumTemplateArgs())) { @@ -204,7 +204,29 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, } if (TemplateArgs) - getExplicitTemplateArgumentList()->initializeFrom(*TemplateArgs); + getExplicitTemplateArgs().initializeFrom(*TemplateArgs); + + computeDependence(); +} + +DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + ValueDecl *D, const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs, + QualType T) + : Expr(DeclRefExprClass, T, false, false), + DecoratedD(D, + (Qualifier? HasQualifierFlag : 0) | + (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)), + Loc(NameInfo.getLoc()), DNLoc(NameInfo.getInfo()) { + if (Qualifier) { + NameQualifier *NQ = getNameQualifier(); + NQ->NNS = Qualifier; + NQ->Range = QualifierRange; + } + + if (TemplateArgs) + getExplicitTemplateArgs().initializeFrom(*TemplateArgs); computeDependence(); } @@ -216,6 +238,18 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, SourceLocation NameLoc, QualType T, const TemplateArgumentListInfo *TemplateArgs) { + return Create(Context, Qualifier, QualifierRange, D, + DeclarationNameInfo(D->getDeclName(), NameLoc), + T, TemplateArgs); +} + +DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, + NestedNameSpecifier *Qualifier, + SourceRange QualifierRange, + ValueDecl *D, + const DeclarationNameInfo &NameInfo, + QualType T, + const TemplateArgumentListInfo *TemplateArgs) { std::size_t Size = sizeof(DeclRefExpr); if (Qualifier != 0) Size += sizeof(NameQualifier); @@ -224,7 +258,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); void *Mem = Context.Allocate(Size, llvm::alignof()); - return new (Mem) DeclRefExpr(Qualifier, QualifierRange, D, NameLoc, + return new (Mem) DeclRefExpr(Qualifier, QualifierRange, D, NameInfo, TemplateArgs, T); } @@ -242,12 +276,10 @@ DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, bool HasQualifier, } SourceRange DeclRefExpr::getSourceRange() const { - // FIXME: Does not handle multi-token names well, e.g., operator[]. - SourceRange R(Loc); - + SourceRange R = getNameInfo().getSourceRange(); if (hasQualifier()) R.setBegin(getQualifierRange().getBegin()); - if (hasExplicitTemplateArgumentList()) + if (hasExplicitTemplateArgs()) R.setEnd(getRAngleLoc()); return R; } @@ -342,6 +374,44 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { return ""; } +void APNumericStorage::setIntValue(ASTContext &C, const llvm::APInt &Val) { + if (hasAllocation()) + C.Deallocate(pVal); + + BitWidth = Val.getBitWidth(); + unsigned NumWords = Val.getNumWords(); + const uint64_t* Words = Val.getRawData(); + if (NumWords > 1) { + pVal = new (C) uint64_t[NumWords]; + std::copy(Words, Words + NumWords, pVal); + } else if (NumWords == 1) + VAL = Words[0]; + else + VAL = 0; +} + +IntegerLiteral * +IntegerLiteral::Create(ASTContext &C, const llvm::APInt &V, + QualType type, SourceLocation l) { + return new (C) IntegerLiteral(C, V, type, l); +} + +IntegerLiteral * +IntegerLiteral::Create(ASTContext &C, EmptyShell Empty) { + return new (C) IntegerLiteral(Empty); +} + +FloatingLiteral * +FloatingLiteral::Create(ASTContext &C, const llvm::APFloat &V, + bool isexact, QualType Type, SourceLocation L) { + return new (C) FloatingLiteral(C, V, isexact, Type, L); +} + +FloatingLiteral * +FloatingLiteral::Create(ASTContext &C, EmptyShell Empty) { + return new (C) FloatingLiteral(Empty); +} + /// getValueAsApproximateDouble - This returns the value as an inaccurate /// double. Note that this may cause loss of precision, but is useful for /// debugging dumps, etc. @@ -390,15 +460,7 @@ StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) { return SL; } -void StringLiteral::DoDestroy(ASTContext &C) { - C.Deallocate(const_cast(StrData)); - Expr::DoDestroy(C); -} - void StringLiteral::setString(ASTContext &C, llvm::StringRef Str) { - if (StrData) - C.Deallocate(const_cast(StrData)); - char *AStrData = new (C, 1) char[Str.size()]; memcpy(AStrData, Str.data(), Str.size()); StrData = AStrData; @@ -410,48 +472,47 @@ void StringLiteral::setString(ASTContext &C, llvm::StringRef Str) { const char *UnaryOperator::getOpcodeStr(Opcode Op) { switch (Op) { default: assert(0 && "Unknown unary operator"); - case PostInc: return "++"; - case PostDec: return "--"; - case PreInc: return "++"; - case PreDec: return "--"; - case AddrOf: return "&"; - case Deref: return "*"; - case Plus: return "+"; - case Minus: return "-"; - case Not: return "~"; - case LNot: return "!"; - case Real: return "__real"; - case Imag: return "__imag"; - case Extension: return "__extension__"; - case OffsetOf: return "__builtin_offsetof"; + case UO_PostInc: return "++"; + case UO_PostDec: return "--"; + case UO_PreInc: return "++"; + case UO_PreDec: return "--"; + case UO_AddrOf: return "&"; + case UO_Deref: return "*"; + case UO_Plus: return "+"; + case UO_Minus: return "-"; + case UO_Not: return "~"; + case UO_LNot: return "!"; + case UO_Real: return "__real"; + case UO_Imag: return "__imag"; + case UO_Extension: return "__extension__"; } } -UnaryOperator::Opcode +UnaryOperatorKind UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) { switch (OO) { default: assert(false && "No unary operator for overloaded function"); - case OO_PlusPlus: return Postfix ? PostInc : PreInc; - case OO_MinusMinus: return Postfix ? PostDec : PreDec; - case OO_Amp: return AddrOf; - case OO_Star: return Deref; - case OO_Plus: return Plus; - case OO_Minus: return Minus; - case OO_Tilde: return Not; - case OO_Exclaim: return LNot; + case OO_PlusPlus: return Postfix ? UO_PostInc : UO_PreInc; + case OO_MinusMinus: return Postfix ? UO_PostDec : UO_PreDec; + case OO_Amp: return UO_AddrOf; + case OO_Star: return UO_Deref; + case OO_Plus: return UO_Plus; + case OO_Minus: return UO_Minus; + case OO_Tilde: return UO_Not; + case OO_Exclaim: return UO_LNot; } } OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { switch (Opc) { - case PostInc: case PreInc: return OO_PlusPlus; - case PostDec: case PreDec: return OO_MinusMinus; - case AddrOf: return OO_Amp; - case Deref: return OO_Star; - case Plus: return OO_Plus; - case Minus: return OO_Minus; - case Not: return OO_Tilde; - case LNot: return OO_Exclaim; + case UO_PostInc: case UO_PreInc: return OO_PlusPlus; + case UO_PostDec: case UO_PreDec: return OO_MinusMinus; + case UO_AddrOf: return OO_Amp; + case UO_Deref: return OO_Star; + case UO_Plus: return OO_Plus; + case UO_Minus: return OO_Minus; + case UO_Not: return OO_Tilde; + case UO_LNot: return OO_Exclaim; default: return OO_None; } } @@ -496,13 +557,6 @@ CallExpr::CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty) SubExprs = new (C) Stmt*[1]; } -void CallExpr::DoDestroy(ASTContext& C) { - DestroyChildren(C); - if (SubExprs) C.Deallocate(SubExprs); - this->~CallExpr(); - C.Deallocate(this); -} - Decl *CallExpr::getCalleeDecl() { Expr *CEE = getCallee()->IgnoreParenCasts(); if (DeclRefExpr *DRE = dyn_cast(CEE)) @@ -526,8 +580,6 @@ void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) { // If shrinking # arguments, just delete the extras and forgot them. if (NumArgs < getNumArgs()) { - for (unsigned i = NumArgs, e = getNumArgs(); i != e; ++i) - getArg(i)->Destroy(C); this->NumArgs = NumArgs; return; } @@ -640,7 +692,7 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, SourceRange qualrange, ValueDecl *memberdecl, DeclAccessPair founddecl, - SourceLocation l, + DeclarationNameInfo nameinfo, const TemplateArgumentListInfo *targs, QualType ty) { std::size_t Size = sizeof(MemberExpr); @@ -655,7 +707,7 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, Size += ExplicitTemplateArgumentList::sizeFor(*targs); void *Mem = C.Allocate(Size, llvm::alignof()); - MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, l, ty); + MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, nameinfo, ty); if (hasQualOrFound) { if (qual && qual->isDependent()) { @@ -672,7 +724,7 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, if (targs) { E->HasExplicitTemplateArgumentList = true; - E->getExplicitTemplateArgumentList()->initializeFrom(*targs); + E->getExplicitTemplateArgs().initializeFrom(*targs); } return E; @@ -680,72 +732,68 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, const char *CastExpr::getCastKindName() const { switch (getCastKind()) { - case CastExpr::CK_Unknown: + case CK_Unknown: return "Unknown"; - case CastExpr::CK_BitCast: + case CK_BitCast: return "BitCast"; - case CastExpr::CK_LValueBitCast: + case CK_LValueBitCast: return "LValueBitCast"; - case CastExpr::CK_NoOp: + case CK_NoOp: return "NoOp"; - case CastExpr::CK_BaseToDerived: + case CK_BaseToDerived: return "BaseToDerived"; - case CastExpr::CK_DerivedToBase: + case CK_DerivedToBase: return "DerivedToBase"; - case CastExpr::CK_UncheckedDerivedToBase: + case CK_UncheckedDerivedToBase: return "UncheckedDerivedToBase"; - case CastExpr::CK_Dynamic: + case CK_Dynamic: return "Dynamic"; - case CastExpr::CK_ToUnion: + case CK_ToUnion: return "ToUnion"; - case CastExpr::CK_ArrayToPointerDecay: + case CK_ArrayToPointerDecay: return "ArrayToPointerDecay"; - case CastExpr::CK_FunctionToPointerDecay: + case CK_FunctionToPointerDecay: return "FunctionToPointerDecay"; - case CastExpr::CK_NullToMemberPointer: + case CK_NullToMemberPointer: return "NullToMemberPointer"; - case CastExpr::CK_BaseToDerivedMemberPointer: + case CK_BaseToDerivedMemberPointer: return "BaseToDerivedMemberPointer"; - case CastExpr::CK_DerivedToBaseMemberPointer: + case CK_DerivedToBaseMemberPointer: return "DerivedToBaseMemberPointer"; - case CastExpr::CK_UserDefinedConversion: + case CK_UserDefinedConversion: return "UserDefinedConversion"; - case CastExpr::CK_ConstructorConversion: + case CK_ConstructorConversion: return "ConstructorConversion"; - case CastExpr::CK_IntegralToPointer: + case CK_IntegralToPointer: return "IntegralToPointer"; - case CastExpr::CK_PointerToIntegral: + case CK_PointerToIntegral: return "PointerToIntegral"; - case CastExpr::CK_ToVoid: + case CK_ToVoid: return "ToVoid"; - case CastExpr::CK_VectorSplat: + case CK_VectorSplat: return "VectorSplat"; - case CastExpr::CK_IntegralCast: + case CK_IntegralCast: return "IntegralCast"; - case CastExpr::CK_IntegralToFloating: + case CK_IntegralToFloating: return "IntegralToFloating"; - case CastExpr::CK_FloatingToIntegral: + case CK_FloatingToIntegral: return "FloatingToIntegral"; - case CastExpr::CK_FloatingCast: + case CK_FloatingCast: return "FloatingCast"; - case CastExpr::CK_MemberPointerToBoolean: + case CK_MemberPointerToBoolean: return "MemberPointerToBoolean"; - case CastExpr::CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToObjCPointerCast: return "AnyPointerToObjCPointerCast"; - case CastExpr::CK_AnyPointerToBlockPointerCast: + case CK_AnyPointerToBlockPointerCast: return "AnyPointerToBlockPointerCast"; + case CK_ObjCObjectLValueCast: + return "ObjCObjectLValueCast"; } assert(0 && "Unhandled cast kind!"); return 0; } -void CastExpr::DoDestroy(ASTContext &C) -{ - BasePath.Destroy(); - Expr::DoDestroy(C); -} - Expr *CastExpr::getSubExprAsWritten() { Expr *SubExpr = 0; CastExpr *E = this; @@ -758,9 +806,9 @@ Expr *CastExpr::getSubExprAsWritten() { // Conversions by constructor and conversion functions have a // subexpression describing the call; strip it off. - if (E->getCastKind() == CastExpr::CK_ConstructorConversion) + if (E->getCastKind() == CK_ConstructorConversion) SubExpr = cast(SubExpr)->getArg(0); - else if (E->getCastKind() == CastExpr::CK_UserDefinedConversion) + else if (E->getCastKind() == CK_UserDefinedConversion) SubExpr = cast(SubExpr)->getImplicitObjectArgument(); // If the subexpression we're left with is an implicit cast, look @@ -770,82 +818,142 @@ Expr *CastExpr::getSubExprAsWritten() { return SubExpr; } +CXXBaseSpecifier **CastExpr::path_buffer() { + switch (getStmtClass()) { +#define ABSTRACT_STMT(x) +#define CASTEXPR(Type, Base) \ + case Stmt::Type##Class: \ + return reinterpret_cast(static_cast(this)+1); +#define STMT(Type, Base) +#include "clang/AST/StmtNodes.inc" + default: + llvm_unreachable("non-cast expressions not possible here"); + return 0; + } +} + +void CastExpr::setCastPath(const CXXCastPath &Path) { + assert(Path.size() == path_size()); + memcpy(path_buffer(), Path.data(), Path.size() * sizeof(CXXBaseSpecifier*)); +} + +ImplicitCastExpr *ImplicitCastExpr::Create(ASTContext &C, QualType T, + CastKind Kind, Expr *Operand, + const CXXCastPath *BasePath, + ExprValueKind VK) { + unsigned PathSize = (BasePath ? BasePath->size() : 0); + void *Buffer = + C.Allocate(sizeof(ImplicitCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + ImplicitCastExpr *E = + new (Buffer) ImplicitCastExpr(T, Kind, Operand, PathSize, VK); + if (PathSize) E->setCastPath(*BasePath); + return E; +} + +ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C, + unsigned PathSize) { + void *Buffer = + C.Allocate(sizeof(ImplicitCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + return new (Buffer) ImplicitCastExpr(EmptyShell(), PathSize); +} + + +CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T, + CastKind K, Expr *Op, + const CXXCastPath *BasePath, + TypeSourceInfo *WrittenTy, + SourceLocation L, SourceLocation R) { + unsigned PathSize = (BasePath ? BasePath->size() : 0); + void *Buffer = + C.Allocate(sizeof(CStyleCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + CStyleCastExpr *E = + new (Buffer) CStyleCastExpr(T, K, Op, PathSize, WrittenTy, L, R); + if (PathSize) E->setCastPath(*BasePath); + return E; +} + +CStyleCastExpr *CStyleCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { + void *Buffer = + C.Allocate(sizeof(CStyleCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + return new (Buffer) CStyleCastExpr(EmptyShell(), PathSize); +} + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "<<=". const char *BinaryOperator::getOpcodeStr(Opcode Op) { switch (Op) { - case PtrMemD: return ".*"; - case PtrMemI: return "->*"; - case Mul: return "*"; - case Div: return "/"; - case Rem: return "%"; - case Add: return "+"; - case Sub: return "-"; - case Shl: return "<<"; - case Shr: return ">>"; - case LT: return "<"; - case GT: return ">"; - case LE: return "<="; - case GE: return ">="; - case EQ: return "=="; - case NE: return "!="; - case And: return "&"; - case Xor: return "^"; - case Or: return "|"; - case LAnd: return "&&"; - case LOr: return "||"; - case Assign: return "="; - case MulAssign: return "*="; - case DivAssign: return "/="; - case RemAssign: return "%="; - case AddAssign: return "+="; - case SubAssign: return "-="; - case ShlAssign: return "<<="; - case ShrAssign: return ">>="; - case AndAssign: return "&="; - case XorAssign: return "^="; - case OrAssign: return "|="; - case Comma: return ","; + case BO_PtrMemD: return ".*"; + case BO_PtrMemI: return "->*"; + case BO_Mul: return "*"; + case BO_Div: return "/"; + case BO_Rem: return "%"; + case BO_Add: return "+"; + case BO_Sub: return "-"; + case BO_Shl: return "<<"; + case BO_Shr: return ">>"; + case BO_LT: return "<"; + case BO_GT: return ">"; + case BO_LE: return "<="; + case BO_GE: return ">="; + case BO_EQ: return "=="; + case BO_NE: return "!="; + case BO_And: return "&"; + case BO_Xor: return "^"; + case BO_Or: return "|"; + case BO_LAnd: return "&&"; + case BO_LOr: return "||"; + case BO_Assign: return "="; + case BO_MulAssign: return "*="; + case BO_DivAssign: return "/="; + case BO_RemAssign: return "%="; + case BO_AddAssign: return "+="; + case BO_SubAssign: return "-="; + case BO_ShlAssign: return "<<="; + case BO_ShrAssign: return ">>="; + case BO_AndAssign: return "&="; + case BO_XorAssign: return "^="; + case BO_OrAssign: return "|="; + case BO_Comma: return ","; } return ""; } -BinaryOperator::Opcode +BinaryOperatorKind BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) { switch (OO) { default: assert(false && "Not an overloadable binary operator"); - case OO_Plus: return Add; - case OO_Minus: return Sub; - case OO_Star: return Mul; - case OO_Slash: return Div; - case OO_Percent: return Rem; - case OO_Caret: return Xor; - case OO_Amp: return And; - case OO_Pipe: return Or; - case OO_Equal: return Assign; - case OO_Less: return LT; - case OO_Greater: return GT; - case OO_PlusEqual: return AddAssign; - case OO_MinusEqual: return SubAssign; - case OO_StarEqual: return MulAssign; - case OO_SlashEqual: return DivAssign; - case OO_PercentEqual: return RemAssign; - case OO_CaretEqual: return XorAssign; - case OO_AmpEqual: return AndAssign; - case OO_PipeEqual: return OrAssign; - case OO_LessLess: return Shl; - case OO_GreaterGreater: return Shr; - case OO_LessLessEqual: return ShlAssign; - case OO_GreaterGreaterEqual: return ShrAssign; - case OO_EqualEqual: return EQ; - case OO_ExclaimEqual: return NE; - case OO_LessEqual: return LE; - case OO_GreaterEqual: return GE; - case OO_AmpAmp: return LAnd; - case OO_PipePipe: return LOr; - case OO_Comma: return Comma; - case OO_ArrowStar: return PtrMemI; + case OO_Plus: return BO_Add; + case OO_Minus: return BO_Sub; + case OO_Star: return BO_Mul; + case OO_Slash: return BO_Div; + case OO_Percent: return BO_Rem; + case OO_Caret: return BO_Xor; + case OO_Amp: return BO_And; + case OO_Pipe: return BO_Or; + case OO_Equal: return BO_Assign; + case OO_Less: return BO_LT; + case OO_Greater: return BO_GT; + case OO_PlusEqual: return BO_AddAssign; + case OO_MinusEqual: return BO_SubAssign; + case OO_StarEqual: return BO_MulAssign; + case OO_SlashEqual: return BO_DivAssign; + case OO_PercentEqual: return BO_RemAssign; + case OO_CaretEqual: return BO_XorAssign; + case OO_AmpEqual: return BO_AndAssign; + case OO_PipeEqual: return BO_OrAssign; + case OO_LessLess: return BO_Shl; + case OO_GreaterGreater: return BO_Shr; + case OO_LessLessEqual: return BO_ShlAssign; + case OO_GreaterGreaterEqual: return BO_ShrAssign; + case OO_EqualEqual: return BO_EQ; + case OO_ExclaimEqual: return BO_NE; + case OO_LessEqual: return BO_LE; + case OO_GreaterEqual: return BO_GE; + case OO_AmpAmp: return BO_LAnd; + case OO_PipePipe: return BO_LOr; + case OO_Comma: return BO_Comma; + case OO_ArrowStar: return BO_PtrMemI; } } @@ -897,9 +1005,6 @@ void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) { } void InitListExpr::resizeInits(ASTContext &C, unsigned NumInits) { - for (unsigned Idx = NumInits, LastIdx = InitExprs.size(); - Idx < LastIdx; ++Idx) - InitExprs[Idx]->Destroy(C); InitExprs.resize(C, NumInits, 0); } @@ -963,24 +1068,24 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, switch (UO->getOpcode()) { default: break; - case UnaryOperator::PostInc: - case UnaryOperator::PostDec: - case UnaryOperator::PreInc: - case UnaryOperator::PreDec: // ++/-- + case UO_PostInc: + case UO_PostDec: + case UO_PreInc: + case UO_PreDec: // ++/-- return false; // Not a warning. - case UnaryOperator::Deref: + case UO_Deref: // Dereferencing a volatile pointer is a side-effect. if (Ctx.getCanonicalType(getType()).isVolatileQualified()) return false; break; - case UnaryOperator::Real: - case UnaryOperator::Imag: + case UO_Real: + case UO_Imag: // accessing a piece of a volatile complex is a side-effect. if (Ctx.getCanonicalType(UO->getSubExpr()->getType()) .isVolatileQualified()) return false; break; - case UnaryOperator::Extension: + case UO_Extension: return UO->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx); } Loc = UO->getOperatorLoc(); @@ -994,7 +1099,7 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, break; // Consider the RHS of comma for side effects. LHS was checked by // Sema::CheckCommaOperands. - case BinaryOperator::Comma: + case BO_Comma: // ((foo = ), 0) is an idiom for hiding the result (and // lvalue-ness) of an assignment written in a macro. if (IntegerLiteral *IE = @@ -1003,8 +1108,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, return false; return BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx); // Consider '||', '&&' to have side effects if the LHS or RHS does. - case BinaryOperator::LAnd: - case BinaryOperator::LOr: + case BO_LAnd: + case BO_LOr: if (!BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || !BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)) return false; @@ -1137,8 +1242,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, // If this is a cast to void or a constructor conversion, check the operand. // Otherwise, the result of the cast is unused. - if (CE->getCastKind() == CastExpr::CK_ToVoid || - CE->getCastKind() == CastExpr::CK_ConstructorConversion) + if (CE->getCastKind() == CK_ToVoid || + CE->getCastKind() == CK_ConstructorConversion) return (cast(this)->getSubExpr() ->isUnusedResultAWarning(Loc, R1, R2, Ctx)); Loc = cast(this)->getTypeBeginLoc(); @@ -1287,7 +1392,7 @@ bool Expr::isDefaultArgument() const { /// expressions. static const Expr *skipTemporaryBindingsAndNoOpCasts(const Expr *E) { while (const ImplicitCastExpr *ICE = dyn_cast(E)) { - if (ICE->getCastKind() == CastExpr::CK_NoOp) + if (ICE->getCastKind() == CK_NoOp) E = ICE->getSubExpr(); else break; @@ -1297,7 +1402,7 @@ static const Expr *skipTemporaryBindingsAndNoOpCasts(const Expr *E) { E = BE->getSubExpr(); while (const ImplicitCastExpr *ICE = dyn_cast(E)) { - if (ICE->getCastKind() == CastExpr::CK_NoOp) + if (ICE->getCastKind() == CK_NoOp) E = ICE->getSubExpr(); else break; @@ -1314,8 +1419,8 @@ const Expr *Expr::getTemporaryObject() const { if (const CastExpr *Cast = dyn_cast(E)) { // Only user-defined and constructor conversions can produce // temporary objects. - if (Cast->getCastKind() != CastExpr::CK_ConstructorConversion && - Cast->getCastKind() != CastExpr::CK_UserDefinedConversion) + if (Cast->getCastKind() != CK_ConstructorConversion && + Cast->getCastKind() != CK_UserDefinedConversion) return 0; // Strip off temporary bindings and no-op casts. @@ -1323,12 +1428,12 @@ const Expr *Expr::getTemporaryObject() const { // If this is a constructor conversion, see if we have an object // construction. - if (Cast->getCastKind() == CastExpr::CK_ConstructorConversion) + if (Cast->getCastKind() == CK_ConstructorConversion) return dyn_cast(Sub); // If this is a user-defined conversion, see if we have a call to // a function that itself returns a temporary object. - if (Cast->getCastKind() == CastExpr::CK_UserDefinedConversion) + if (Cast->getCastKind() == CK_UserDefinedConversion) if (const CallExpr *CE = dyn_cast(Sub)) if (CE->getCallReturnType()->isRecordType()) return CE; @@ -1368,15 +1473,20 @@ bool Expr::hasAnyValueDependentArguments(Expr** Exprs, unsigned NumExprs) { return false; } -bool Expr::isConstantInitializer(ASTContext &Ctx) const { +bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { // This function is attempting whether an expression is an initializer // which can be evaluated at compile-time. isEvaluatable handles most // of the cases, but it can't deal with some initializer-specific // expressions, and it can't deal with aggregates; we deal with those here, // and fall back to isEvaluatable for the other cases. - // FIXME: This function assumes the variable being assigned to - // isn't a reference type! + // If we ever capture reference-binding directly in the AST, we can + // kill the second parameter. + + if (IsForRef) { + EvalResult Result; + return EvaluateAsLValue(Result, Ctx) && !Result.HasSideEffects; + } switch (getStmtClass()) { default: break; @@ -1384,12 +1494,27 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { case ObjCStringLiteralClass: case ObjCEncodeExprClass: return true; + case CXXTemporaryObjectExprClass: + case CXXConstructExprClass: { + const CXXConstructExpr *CE = cast(this); + + // Only if it's + // 1) an application of the trivial default constructor or + if (!CE->getConstructor()->isTrivial()) return false; + if (!CE->getNumArgs()) return true; + + // 2) an elidable trivial copy construction of an operand which is + // itself a constant initializer. Note that we consider the + // operand on its own, *not* as a reference binding. + return CE->isElidable() && + CE->getArg(0)->isConstantInitializer(Ctx, false); + } case CompoundLiteralExprClass: { // This handles gcc's extension that allows global initializers like // "struct x {int x;} x = (struct x) {};". // FIXME: This accepts other cases it shouldn't! const Expr *Exp = cast(this)->getInitializer(); - return Exp->isConstantInitializer(Ctx); + return Exp->isConstantInitializer(Ctx, false); } case InitListExprClass: { // FIXME: This doesn't deal with fields with reference types correctly. @@ -1398,7 +1523,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { const InitListExpr *Exp = cast(this); unsigned numInits = Exp->getNumInits(); for (unsigned i = 0; i < numInits; i++) { - if (!Exp->getInit(i)->isConstantInitializer(Ctx)) + if (!Exp->getInit(i)->isConstantInitializer(Ctx, false)) return false; } return true; @@ -1406,36 +1531,41 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { case ImplicitValueInitExprClass: return true; case ParenExprClass: - return cast(this)->getSubExpr()->isConstantInitializer(Ctx); + return cast(this)->getSubExpr() + ->isConstantInitializer(Ctx, IsForRef); case UnaryOperatorClass: { const UnaryOperator* Exp = cast(this); - if (Exp->getOpcode() == UnaryOperator::Extension) - return Exp->getSubExpr()->isConstantInitializer(Ctx); + if (Exp->getOpcode() == UO_Extension) + return Exp->getSubExpr()->isConstantInitializer(Ctx, false); break; } case BinaryOperatorClass: { // Special case &&foo - &&bar. It would be nice to generalize this somehow // but this handles the common case. const BinaryOperator *Exp = cast(this); - if (Exp->getOpcode() == BinaryOperator::Sub && + if (Exp->getOpcode() == BO_Sub && isa(Exp->getLHS()->IgnoreParenNoopCasts(Ctx)) && isa(Exp->getRHS()->IgnoreParenNoopCasts(Ctx))) return true; break; } + case CXXFunctionalCastExprClass: + case CXXStaticCastExprClass: case ImplicitCastExprClass: case CStyleCastExprClass: // Handle casts with a destination that's a struct or union; this // deals with both the gcc no-op struct cast extension and the // cast-to-union extension. if (getType()->isRecordType()) - return cast(this)->getSubExpr()->isConstantInitializer(Ctx); + return cast(this)->getSubExpr() + ->isConstantInitializer(Ctx, false); // Integer->integer casts can be handled here, which is important for // things like (int)(&&x-&&y). Scary but true. if (getType()->isIntegerType() && cast(this)->getSubExpr()->getType()->isIntegerType()) - return cast(this)->getSubExpr()->isConstantInitializer(Ctx); + return cast(this)->getSubExpr() + ->isConstantInitializer(Ctx, false); break; } @@ -1508,7 +1638,8 @@ FieldDecl *Expr::getBitField() { Expr *E = this->IgnoreParens(); while (ImplicitCastExpr *ICE = dyn_cast(E)) { - if (ICE->isLvalueCast() && ICE->getCastKind() == CastExpr::CK_NoOp) + if (ICE->getValueKind() != VK_RValue && + ICE->getCastKind() == CK_NoOp) E = ICE->getSubExpr()->IgnoreParens(); else break; @@ -1530,7 +1661,8 @@ bool Expr::refersToVectorElement() const { const Expr *E = this->IgnoreParens(); while (const ImplicitCastExpr *ICE = dyn_cast(E)) { - if (ICE->isLvalueCast() && ICE->getCastKind() == CastExpr::CK_NoOp) + if (ICE->getValueKind() != VK_RValue && + ICE->getCastKind() == CK_NoOp) E = ICE->getSubExpr()->IgnoreParens(); else break; @@ -1773,27 +1905,6 @@ void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs, memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs); } -void ShuffleVectorExpr::DoDestroy(ASTContext& C) { - DestroyChildren(C); - if (SubExprs) C.Deallocate(SubExprs); - this->~ShuffleVectorExpr(); - C.Deallocate(this); -} - -void SizeOfAlignOfExpr::DoDestroy(ASTContext& C) { - // Override default behavior of traversing children. If this has a type - // operand and the type is a variable-length array, the child iteration - // will iterate over the size expression. However, this expression belongs - // to the type, not to this, so we don't want to delete it. - // We still want to delete this expression. - if (isArgumentType()) { - this->~SizeOfAlignOfExpr(); - C.Deallocate(this); - } - else - Expr::DoDestroy(C); -} - //===----------------------------------------------------------------------===// // DesignatedInitExpr //===----------------------------------------------------------------------===// @@ -1878,8 +1989,6 @@ DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C, void DesignatedInitExpr::setDesignators(ASTContext &C, const Designator *Desigs, unsigned NumDesigs) { - DestroyDesignators(C); - Designators = new (C) Designator[NumDesigs]; NumDesignators = NumDesigs; for (unsigned I = 0; I != NumDesigs; ++I) @@ -1950,23 +2059,10 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx, std::copy(First, Last, NewDesignators + Idx); std::copy(Designators + Idx + 1, Designators + NumDesignators, NewDesignators + Idx + NumNewDesignators); - DestroyDesignators(C); Designators = NewDesignators; NumDesignators = NumDesignators - 1 + NumNewDesignators; } -void DesignatedInitExpr::DoDestroy(ASTContext &C) { - DestroyDesignators(C); - Expr::DoDestroy(C); -} - -void DesignatedInitExpr::DestroyDesignators(ASTContext &C) { - for (unsigned I = 0; I != NumDesignators; ++I) - Designators[I].~Designator(); - C.Deallocate(Designators); - Designators = 0; -} - ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs, unsigned nexprs, SourceLocation rparenloc) @@ -1980,13 +2076,6 @@ ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, Exprs[i] = exprs[i]; } -void ParenListExpr::DoDestroy(ASTContext& C) { - DestroyChildren(C); - if (Exprs) C.Deallocate(Exprs); - this->~ParenListExpr(); - C.Deallocate(this); -} - //===----------------------------------------------------------------------===// // ExprIterator. //===----------------------------------------------------------------------===// diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index c2548ec..0a10130 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -118,14 +118,6 @@ void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray, } -void CXXNewExpr::DoDestroy(ASTContext &C) { - DestroyChildren(C); - if (SubExprs) - C.Deallocate(SubExprs); - this->~CXXNewExpr(); - C.Deallocate((void*)this); -} - Stmt::child_iterator CXXNewExpr::child_begin() { return &SubExprs[0]; } Stmt::child_iterator CXXNewExpr::child_end() { return &SubExprs[0] + Array + getNumPlacementArgs() + getNumConstructorArgs(); @@ -167,8 +159,9 @@ UnresolvedLookupExpr * UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, CXXRecordDecl *NamingClass, NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, DeclarationName Name, - SourceLocation NameLoc, bool ADL, + SourceRange QualifierRange, + const DeclarationNameInfo &NameInfo, + bool ADL, const TemplateArgumentListInfo &Args, UnresolvedSetIterator Begin, UnresolvedSetIterator End) @@ -179,8 +172,8 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent, = new (Mem) UnresolvedLookupExpr(C, Dependent ? C.DependentTy : C.OverloadTy, Dependent, NamingClass, - Qualifier, QualifierRange, - Name, NameLoc, ADL, + Qualifier, QualifierRange, NameInfo, + ADL, /*Overload*/ true, /*ExplicitTemplateArgs*/ true, Begin, End); @@ -204,14 +197,14 @@ UnresolvedLookupExpr::CreateEmpty(ASTContext &C, unsigned NumTemplateArgs) { OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, QualType T, bool Dependent, NestedNameSpecifier *Qualifier, - SourceRange QRange, DeclarationName Name, - SourceLocation NameLoc, bool HasTemplateArgs, + SourceRange QRange, + const DeclarationNameInfo &NameInfo, + bool HasTemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End) : Expr(K, T, Dependent, Dependent), - Results(0), NumResults(0), Name(Name), Qualifier(Qualifier), - QualifierRange(QRange), NameLoc(NameLoc), - HasExplicitTemplateArgs(HasTemplateArgs) + Results(0), NumResults(0), NameInfo(NameInfo), Qualifier(Qualifier), + QualifierRange(QRange), HasExplicitTemplateArgs(HasTemplateArgs) { initializeResults(C, Begin, End); } @@ -270,8 +263,7 @@ DependentScopeDeclRefExpr * DependentScopeDeclRefExpr::Create(ASTContext &C, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - DeclarationName Name, - SourceLocation NameLoc, + const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *Args) { std::size_t size = sizeof(DependentScopeDeclRefExpr); if (Args) size += ExplicitTemplateArgumentList::sizeFor(*Args); @@ -280,8 +272,7 @@ DependentScopeDeclRefExpr::Create(ASTContext &C, DependentScopeDeclRefExpr *DRE = new (Mem) DependentScopeDeclRefExpr(C.DependentTy, Qualifier, QualifierRange, - Name, NameLoc, - Args != 0); + NameInfo, Args != 0); if (Args) reinterpret_cast(DRE+1) @@ -299,7 +290,7 @@ DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C, void *Mem = C.Allocate(size); return new (Mem) DependentScopeDeclRefExpr(QualType(), 0, SourceRange(), - DeclarationName(),SourceLocation(), + DeclarationNameInfo(), NumTemplateArgs != 0); } @@ -395,6 +386,118 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const { C.getBaseElementType(QueriedType)->getAs()) return cast(RT->getDecl())->hasTrivialDestructor(); return false; + // TODO: Propagate nothrowness for implicitly declared special members. + case UTT_HasNothrowAssign: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If type is const qualified or is a reference type then the + // trait is false. Otherwise if __has_trivial_assign (type) + // is true then the trait is true, else if type is a cv class + // or union type with copy assignment operators that are known + // not to throw an exception then the trait is true, else it is + // false. + if (C.getBaseElementType(QueriedType).isConstQualified()) + return false; + if (QueriedType->isReferenceType()) + return false; + if (QueriedType->isPODType()) + return true; + if (const RecordType *RT = QueriedType->getAs()) { + CXXRecordDecl* RD = cast(RT->getDecl()); + if (RD->hasTrivialCopyAssignment()) + return true; + + bool FoundAssign = false; + bool AllNoThrow = true; + DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal); + DeclContext::lookup_const_iterator Op, OpEnd; + for (llvm::tie(Op, OpEnd) = RD->lookup(Name); + Op != OpEnd; ++Op) { + CXXMethodDecl *Operator = cast(*Op); + if (Operator->isCopyAssignmentOperator()) { + FoundAssign = true; + const FunctionProtoType *CPT + = Operator->getType()->getAs(); + if (!CPT->hasEmptyExceptionSpec()) { + AllNoThrow = false; + break; + } + } + } + + return FoundAssign && AllNoThrow; + } + return false; + case UTT_HasNothrowCopy: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __has_trivial_copy (type) is true then the trait is true, else + // if type is a cv class or union type with copy constructors that are + // known not to throw an exception then the trait is true, else it is + // false. + if (QueriedType->isPODType() || QueriedType->isReferenceType()) + return true; + if (const RecordType *RT = QueriedType->getAs()) { + CXXRecordDecl *RD = cast(RT->getDecl()); + if (RD->hasTrivialCopyConstructor()) + return true; + + bool FoundConstructor = false; + bool AllNoThrow = true; + unsigned FoundTQs; + DeclarationName ConstructorName + = C.DeclarationNames.getCXXConstructorName( + C.getCanonicalType(QueriedType)); + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = RD->lookup(ConstructorName); + Con != ConEnd; ++Con) { + CXXConstructorDecl *Constructor = cast(*Con); + if (Constructor->isCopyConstructor(FoundTQs)) { + FoundConstructor = true; + const FunctionProtoType *CPT + = Constructor->getType()->getAs(); + if (!CPT->hasEmptyExceptionSpec()) { + AllNoThrow = false; + break; + } + } + } + + return FoundConstructor && AllNoThrow; + } + return false; + case UTT_HasNothrowConstructor: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __has_trivial_constructor (type) is true then the trait is + // true, else if type is a cv class or union type (or array + // thereof) with a default constructor that is known not to + // throw an exception then the trait is true, else it is false. + if (QueriedType->isPODType()) + return true; + if (const RecordType *RT = + C.getBaseElementType(QueriedType)->getAs()) { + CXXRecordDecl *RD = cast(RT->getDecl()); + if (RD->hasTrivialConstructor()) + return true; + + if (CXXConstructorDecl *Constructor = RD->getDefaultConstructor()) { + const FunctionProtoType *CPT + = Constructor->getType()->getAs(); + // TODO: check whether evaluating default arguments can throw. + // For now, we'll be conservative and assume that they can throw. + if (CPT->hasEmptyExceptionSpec() && CPT->getNumArgs() == 0) + return true; + } + } + return false; + case UTT_HasVirtualDestructor: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If type is a class type with a virtual destructor ([class.dtor]) + // then the trait is true, else it is false. + if (const RecordType *Record = QueriedType->getAs()) { + CXXRecordDecl *RD = cast(Record->getDecl()); + if (CXXDestructorDecl *Destructor = RD->getDestructor()) + return Destructor->isVirtual(); + } + return false; } } @@ -468,6 +571,100 @@ const char *CXXNamedCastExpr::getCastName() const { } } +CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T, + CastKind K, Expr *Op, + const CXXCastPath *BasePath, + TypeSourceInfo *WrittenTy, + SourceLocation L) { + unsigned PathSize = (BasePath ? BasePath->size() : 0); + void *Buffer = C.Allocate(sizeof(CXXStaticCastExpr) + + PathSize * sizeof(CXXBaseSpecifier*)); + CXXStaticCastExpr *E = + new (Buffer) CXXStaticCastExpr(T, K, Op, PathSize, WrittenTy, L); + if (PathSize) E->setCastPath(*BasePath); + return E; +} + +CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(ASTContext &C, + unsigned PathSize) { + void *Buffer = + C.Allocate(sizeof(CXXStaticCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + return new (Buffer) CXXStaticCastExpr(EmptyShell(), PathSize); +} + +CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T, + CastKind K, Expr *Op, + const CXXCastPath *BasePath, + TypeSourceInfo *WrittenTy, + SourceLocation L) { + unsigned PathSize = (BasePath ? BasePath->size() : 0); + void *Buffer = C.Allocate(sizeof(CXXDynamicCastExpr) + + PathSize * sizeof(CXXBaseSpecifier*)); + CXXDynamicCastExpr *E = + new (Buffer) CXXDynamicCastExpr(T, K, Op, PathSize, WrittenTy, L); + if (PathSize) E->setCastPath(*BasePath); + return E; +} + +CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(ASTContext &C, + unsigned PathSize) { + void *Buffer = + C.Allocate(sizeof(CXXDynamicCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + return new (Buffer) CXXDynamicCastExpr(EmptyShell(), PathSize); +} + +CXXReinterpretCastExpr * +CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, CastKind K, Expr *Op, + const CXXCastPath *BasePath, + TypeSourceInfo *WrittenTy, SourceLocation L) { + unsigned PathSize = (BasePath ? BasePath->size() : 0); + void *Buffer = + C.Allocate(sizeof(CXXReinterpretCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + CXXReinterpretCastExpr *E = + new (Buffer) CXXReinterpretCastExpr(T, K, Op, PathSize, WrittenTy, L); + if (PathSize) E->setCastPath(*BasePath); + return E; +} + +CXXReinterpretCastExpr * +CXXReinterpretCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { + void *Buffer = C.Allocate(sizeof(CXXReinterpretCastExpr) + + PathSize * sizeof(CXXBaseSpecifier*)); + return new (Buffer) CXXReinterpretCastExpr(EmptyShell(), PathSize); +} + +CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T, Expr *Op, + TypeSourceInfo *WrittenTy, + SourceLocation L) { + return new (C) CXXConstCastExpr(T, Op, WrittenTy, L); +} + +CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) { + return new (C) CXXConstCastExpr(EmptyShell()); +} + +CXXFunctionalCastExpr * +CXXFunctionalCastExpr::Create(ASTContext &C, QualType T, + TypeSourceInfo *Written, SourceLocation L, + CastKind K, Expr *Op, const CXXCastPath *BasePath, + SourceLocation R) { + unsigned PathSize = (BasePath ? BasePath->size() : 0); + void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr) + + PathSize * sizeof(CXXBaseSpecifier*)); + CXXFunctionalCastExpr *E = + new (Buffer) CXXFunctionalCastExpr(T, Written, L, K, Op, PathSize, R); + if (PathSize) E->setCastPath(*BasePath); + return E; +} + +CXXFunctionalCastExpr * +CXXFunctionalCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { + void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr) + + PathSize * sizeof(CXXBaseSpecifier*)); + return new (Buffer) CXXFunctionalCastExpr(EmptyShell(), PathSize); +} + + CXXDefaultArgExpr * CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc, ParmVarDecl *Param, Expr *SubExpr) { @@ -476,23 +673,11 @@ CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc, SubExpr); } -void CXXDefaultArgExpr::DoDestroy(ASTContext &C) { - if (Param.getInt()) - getExpr()->Destroy(C); - this->~CXXDefaultArgExpr(); - C.Deallocate(this); -} - CXXTemporary *CXXTemporary::Create(ASTContext &C, const CXXDestructorDecl *Destructor) { return new (C) CXXTemporary(Destructor); } -void CXXTemporary::Destroy(ASTContext &Ctx) { - this->~CXXTemporary(); - Ctx.Deallocate(this); -} - CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, CXXTemporary *Temp, Expr* SubExpr) { @@ -502,25 +687,6 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, return new (C) CXXBindTemporaryExpr(Temp, SubExpr); } -void CXXBindTemporaryExpr::DoDestroy(ASTContext &C) { - Temp->Destroy(C); - this->~CXXBindTemporaryExpr(); - C.Deallocate(this); -} - -CXXBindReferenceExpr *CXXBindReferenceExpr::Create(ASTContext &C, Expr *SubExpr, - bool ExtendsLifetime, - bool RequiresTemporaryCopy) { - return new (C) CXXBindReferenceExpr(SubExpr, - ExtendsLifetime, - RequiresTemporaryCopy); -} - -void CXXBindReferenceExpr::DoDestroy(ASTContext &C) { - this->~CXXBindReferenceExpr(); - C.Deallocate(this); -} - CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, QualType writtenTy, @@ -569,14 +735,6 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, } } -void CXXConstructExpr::DoDestroy(ASTContext &C) { - DestroyChildren(C); - if (Args) - C.Deallocate(Args); - this->~CXXConstructExpr(); - C.Deallocate(this); -} - CXXExprWithTemporaries::CXXExprWithTemporaries(ASTContext &C, Expr *subexpr, CXXTemporary **temps, @@ -605,16 +763,6 @@ CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C, return new (C) CXXExprWithTemporaries(C, SubExpr, Temps, NumTemps); } -void CXXExprWithTemporaries::DoDestroy(ASTContext &C) { - DestroyChildren(C); - if (Temps) - C.Deallocate(Temps); - this->~CXXExprWithTemporaries(); - C.Deallocate(this); -} - -CXXExprWithTemporaries::~CXXExprWithTemporaries() {} - // CXXBindTemporaryExpr Stmt::child_iterator CXXBindTemporaryExpr::child_begin() { return &SubExpr; @@ -624,15 +772,6 @@ Stmt::child_iterator CXXBindTemporaryExpr::child_end() { return &SubExpr + 1; } -// CXXBindReferenceExpr -Stmt::child_iterator CXXBindReferenceExpr::child_begin() { - return &SubExpr; -} - -Stmt::child_iterator CXXBindReferenceExpr::child_end() { - return &SubExpr + 1; -} - // CXXConstructExpr Stmt::child_iterator CXXConstructExpr::child_begin() { return &Args[0]; @@ -705,8 +844,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, NamedDecl *FirstQualifierFoundInScope, - DeclarationName Member, - SourceLocation MemberLoc, + DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs) : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true), Base(Base), BaseType(BaseType), IsArrow(IsArrow), @@ -714,9 +852,9 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, OperatorLoc(OperatorLoc), Qualifier(Qualifier), QualifierRange(QualifierRange), FirstQualifierFoundInScope(FirstQualifierFoundInScope), - Member(Member), MemberLoc(MemberLoc) { + MemberNameInfo(MemberNameInfo) { if (TemplateArgs) - getExplicitTemplateArgumentList()->initializeFrom(*TemplateArgs); + getExplicitTemplateArgs().initializeFrom(*TemplateArgs); } CXXDependentScopeMemberExpr * @@ -726,15 +864,14 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, NamedDecl *FirstQualifierFoundInScope, - DeclarationName Member, - SourceLocation MemberLoc, + DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs) { if (!TemplateArgs) return new (C) CXXDependentScopeMemberExpr(C, Base, BaseType, IsArrow, OperatorLoc, Qualifier, QualifierRange, FirstQualifierFoundInScope, - Member, MemberLoc); + MemberNameInfo); std::size_t size = sizeof(CXXDependentScopeMemberExpr); if (TemplateArgs) @@ -745,7 +882,7 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C, IsArrow, OperatorLoc, Qualifier, QualifierRange, FirstQualifierFoundInScope, - Member, MemberLoc, TemplateArgs); + MemberNameInfo, TemplateArgs); } CXXDependentScopeMemberExpr * @@ -755,8 +892,7 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C, return new (C) CXXDependentScopeMemberExpr(C, 0, QualType(), 0, SourceLocation(), 0, SourceRange(), 0, - DeclarationName(), - SourceLocation()); + DeclarationNameInfo()); std::size_t size = sizeof(CXXDependentScopeMemberExpr) + ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); @@ -765,8 +901,7 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C, = new (Mem) CXXDependentScopeMemberExpr(C, 0, QualType(), 0, SourceLocation(), 0, SourceRange(), 0, - DeclarationName(), - SourceLocation(), 0); + DeclarationNameInfo(), 0); E->HasExplicitTemplateArgs = true; return E; } @@ -789,13 +924,12 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, QualType T, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - DeclarationName MemberName, - SourceLocation MemberLoc, + const DeclarationNameInfo &MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End) : OverloadExpr(UnresolvedMemberExprClass, C, T, Dependent, - Qualifier, QualifierRange, MemberName, MemberLoc, + Qualifier, QualifierRange, MemberNameInfo, TemplateArgs != 0, Begin, End), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) { @@ -810,8 +944,7 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, SourceLocation OperatorLoc, NestedNameSpecifier *Qualifier, SourceRange QualifierRange, - DeclarationName Member, - SourceLocation MemberLoc, + const DeclarationNameInfo &MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End) { @@ -824,7 +957,7 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent, Dependent ? C.DependentTy : C.OverloadTy, Dependent, HasUnresolvedUsing, Base, BaseType, IsArrow, OperatorLoc, Qualifier, QualifierRange, - Member, MemberLoc, TemplateArgs, Begin, End); + MemberNameInfo, TemplateArgs, Begin, End); } UnresolvedMemberExpr * diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 60ac347..d7e38eb 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -111,20 +111,20 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // C++ [expr.unary.op]p1: The unary * operator performs indirection: // [...] the result is an lvalue referring to the object or function // to which the expression points. - case UnaryOperator::Deref: + case UO_Deref: return Cl::CL_LValue; // GNU extensions, simply look through them. - case UnaryOperator::Real: - case UnaryOperator::Imag: - case UnaryOperator::Extension: + case UO_Real: + case UO_Imag: + case UO_Extension: return ClassifyInternal(Ctx, cast(E)->getSubExpr()); // C++ [expr.pre.incr]p1: The result is the updated operand; it is an // lvalue, [...] // Not so in C. - case UnaryOperator::PreInc: - case UnaryOperator::PreDec: + case UO_PreInc: + case UO_PreDec: return Lang.CPlusPlus ? Cl::CL_LValue : Cl::CL_PRValue; default: @@ -134,10 +134,16 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // Implicit casts are lvalues if they're lvalue casts. Other than that, we // only specifically record class temporaries. case Expr::ImplicitCastExprClass: - if (cast(E)->isLvalueCast()) + switch (cast(E)->getValueKind()) { + case VK_RValue: + return Lang.CPlusPlus && E->getType()->isRecordType() ? + Cl::CL_ClassTemporary : Cl::CL_PRValue; + case VK_LValue: return Cl::CL_LValue; - return Lang.CPlusPlus && E->getType()->isRecordType() ? - Cl::CL_ClassTemporary : Cl::CL_PRValue; + case VK_XValue: + return Cl::CL_XValue; + } + llvm_unreachable("Invalid value category of implicit cast."); // C++ [expr.prim.general]p4: The presence of parentheses does not affect // whether the expression is an lvalue. @@ -223,6 +229,10 @@ static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) { // In addition, NonTypeTemplateParmDecl derives from VarDecl but isn't an // lvalue unless it's a reference type (C++ [temp.param]p6), so we need to // special-case this. + + if (isa(D) && cast(D)->isInstance()) + return Cl::CL_MemberFunction; + bool islvalue; if (const NonTypeTemplateParmDecl *NTTParm = dyn_cast(D)) @@ -315,19 +325,19 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) { // C++ [expr.comma]p1: the result is of the same value category as its right // operand, [...]. - if (E->getOpcode() == BinaryOperator::Comma) + if (E->getOpcode() == BO_Comma) return ClassifyInternal(Ctx, E->getRHS()); // C++ [expr.mptr.oper]p6: The result of a .* expression whose second operand // is a pointer to a data member is of the same value category as its first // operand. - if (E->getOpcode() == BinaryOperator::PtrMemD) + if (E->getOpcode() == BO_PtrMemD) return E->getType()->isFunctionType() ? Cl::CL_MemberFunction : ClassifyInternal(Ctx, E->getLHS()); // C++ [expr.mptr.oper]p6: The result of an ->* expression is an lvalue if its // second operand is a pointer to data member and a prvalue otherwise. - if (E->getOpcode() == BinaryOperator::PtrMemI) + if (E->getOpcode() == BO_PtrMemI) return E->getType()->isFunctionType() ? Cl::CL_MemberFunction : Cl::CL_LValue; diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 3c97420..7347f5a 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -337,7 +337,7 @@ public: default: return false; - case CastExpr::CK_NoOp: + case CK_NoOp: return Visit(E->getSubExpr()); } } @@ -481,8 +481,8 @@ static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) { } bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { - if (E->getOpcode() != BinaryOperator::Add && - E->getOpcode() != BinaryOperator::Sub) + if (E->getOpcode() != BO_Add && + E->getOpcode() != BO_Sub) return false; const Expr *PExp = E->getLHS(); @@ -512,7 +512,7 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { else SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType); - if (E->getOpcode() == BinaryOperator::Add) + if (E->getOpcode() == BO_Add) Result.Offset += AdditionalOffset * SizeOfPointee; else Result.Offset -= AdditionalOffset * SizeOfPointee; @@ -532,7 +532,7 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) { default: break; - case CastExpr::CK_Unknown: { + case CK_Unknown: { // FIXME: The handling for CK_Unknown is ugly/shouldn't be necessary! // Check for pointer->pointer cast @@ -561,14 +561,14 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) { break; } - case CastExpr::CK_NoOp: - case CastExpr::CK_BitCast: - case CastExpr::CK_LValueBitCast: - case CastExpr::CK_AnyPointerToObjCPointerCast: - case CastExpr::CK_AnyPointerToBlockPointerCast: + case CK_NoOp: + case CK_BitCast: + case CK_LValueBitCast: + case CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: return Visit(SubExpr); - case CastExpr::CK_IntegralToPointer: { + case CK_IntegralToPointer: { APValue Value; if (!EvaluateIntegerOrLValue(SubExpr, Value, Info)) break; @@ -585,8 +585,8 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) { return true; } } - case CastExpr::CK_ArrayToPointerDecay: - case CastExpr::CK_FunctionToPointerDecay: + case CK_ArrayToPointerDecay: + case CK_FunctionToPointerDecay: return EvaluateLValue(SubExpr, Result, Info); } @@ -1008,8 +1008,11 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { VD->setEvaluatingValue(); - if (Visit(const_cast(Init))) { + Expr::EvalResult EResult; + if (Init->Evaluate(EResult, Info.Ctx) && !EResult.HasSideEffects && + EResult.Val.isInt()) { // Cache the evaluated value in the variable declaration. + Result = EResult.Val; VD->setEvaluatedValue(Result); return true; } @@ -1106,7 +1109,7 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(CallExpr *E) { QualType T = GetObjectType(LVBase); if (T.isNull() || T->isIncompleteType() || - !T->isObjectType() || + T->isFunctionType() || T->isVariablyModifiedType() || T->isDependentType()) return false; @@ -1161,7 +1164,7 @@ bool IntExprEvaluator::VisitCallExpr(CallExpr *E) { } bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { - if (E->getOpcode() == BinaryOperator::Comma) { + if (E->getOpcode() == BO_Comma) { if (!Visit(E->getRHS())) return false; @@ -1181,11 +1184,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (HandleConversionToBool(E->getLHS(), lhsResult, Info)) { // We were able to evaluate the LHS, see if we can get away with not // evaluating the RHS: 0 && X -> 0, 1 || X -> 1 - if (lhsResult == (E->getOpcode() == BinaryOperator::LOr)) + if (lhsResult == (E->getOpcode() == BO_LOr)) return Success(lhsResult, E); if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) { - if (E->getOpcode() == BinaryOperator::LOr) + if (E->getOpcode() == BO_LOr) return Success(lhsResult || rhsResult, E); else return Success(lhsResult && rhsResult, E); @@ -1194,8 +1197,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) { // We can't evaluate the LHS; however, sometimes the result // is determined by the RHS: X && 0 -> 0, X || 1 -> 1. - if (rhsResult == (E->getOpcode() == BinaryOperator::LOr) || - !rhsResult == (E->getOpcode() == BinaryOperator::LAnd)) { + if (rhsResult == (E->getOpcode() == BO_LOr) || + !rhsResult == (E->getOpcode() == BO_LAnd)) { // Since we weren't able to evaluate the left hand side, it // must have had side effects. Info.EvalResult.HasSideEffects = true; @@ -1227,11 +1230,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { APFloat::cmpResult CR_i = LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag()); - if (E->getOpcode() == BinaryOperator::EQ) + if (E->getOpcode() == BO_EQ) return Success((CR_r == APFloat::cmpEqual && CR_i == APFloat::cmpEqual), E); else { - assert(E->getOpcode() == BinaryOperator::NE && + assert(E->getOpcode() == BO_NE && "Invalid complex comparison."); return Success(((CR_r == APFloat::cmpGreaterThan || CR_r == APFloat::cmpLessThan || @@ -1241,11 +1244,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { CR_i == APFloat::cmpUnordered)), E); } } else { - if (E->getOpcode() == BinaryOperator::EQ) + if (E->getOpcode() == BO_EQ) return Success((LHS.getComplexIntReal() == RHS.getComplexIntReal() && LHS.getComplexIntImag() == RHS.getComplexIntImag()), E); else { - assert(E->getOpcode() == BinaryOperator::NE && + assert(E->getOpcode() == BO_NE && "Invalid compex comparison."); return Success((LHS.getComplexIntReal() != RHS.getComplexIntReal() || LHS.getComplexIntImag() != RHS.getComplexIntImag()), E); @@ -1268,18 +1271,18 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { switch (E->getOpcode()) { default: assert(0 && "Invalid binary operator!"); - case BinaryOperator::LT: + case BO_LT: return Success(CR == APFloat::cmpLessThan, E); - case BinaryOperator::GT: + case BO_GT: return Success(CR == APFloat::cmpGreaterThan, E); - case BinaryOperator::LE: + case BO_LE: return Success(CR == APFloat::cmpLessThan || CR == APFloat::cmpEqual, E); - case BinaryOperator::GE: + case BO_GE: return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpEqual, E); - case BinaryOperator::EQ: + case BO_EQ: return Success(CR == APFloat::cmpEqual, E); - case BinaryOperator::NE: + case BO_NE: return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpLessThan || CR == APFloat::cmpUnordered, E); @@ -1287,7 +1290,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } if (LHSTy->isPointerType() && RHSTy->isPointerType()) { - if (E->getOpcode() == BinaryOperator::Sub || E->isEqualityOp()) { + if (E->getOpcode() == BO_Sub || E->isEqualityOp()) { LValue LHSValue; if (!EvaluatePointer(E->getLHS(), LHSValue, Info)) return false; @@ -1306,7 +1309,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { bool bres; if (!EvalPointerValueAsBool(LHSValue, bres)) return false; - return Success(bres ^ (E->getOpcode() == BinaryOperator::EQ), E); + return Success(bres ^ (E->getOpcode() == BO_EQ), E); } else if (RHSValue.getLValueBase()) { if (!E->isEqualityOp()) return false; @@ -1315,10 +1318,10 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { bool bres; if (!EvalPointerValueAsBool(RHSValue, bres)) return false; - return Success(bres ^ (E->getOpcode() == BinaryOperator::EQ), E); + return Success(bres ^ (E->getOpcode() == BO_EQ), E); } - if (E->getOpcode() == BinaryOperator::Sub) { + if (E->getOpcode() == BO_Sub) { QualType Type = E->getLHS()->getType(); QualType ElementType = Type->getAs()->getPointeeType(); @@ -1331,7 +1334,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return Success(Diff / ElementSize, E); } bool Result; - if (E->getOpcode() == BinaryOperator::EQ) { + if (E->getOpcode() == BO_EQ) { Result = LHSValue.getLValueOffset() == RHSValue.getLValueOffset(); } else { Result = LHSValue.getLValueOffset() != RHSValue.getLValueOffset(); @@ -1359,7 +1362,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { CharUnits Offset = Result.getLValueOffset(); CharUnits AdditionalOffset = CharUnits::fromQuantity( RHSVal.getInt().getZExtValue()); - if (E->getOpcode() == BinaryOperator::Add) + if (E->getOpcode() == BO_Add) Offset += AdditionalOffset; else Offset -= AdditionalOffset; @@ -1368,7 +1371,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { } // Handle cases like 4 + (unsigned long)&a - if (E->getOpcode() == BinaryOperator::Add && + if (E->getOpcode() == BO_Add && RHSVal.isLValue() && Result.isInt()) { CharUnits Offset = RHSVal.getLValueOffset(); Offset += CharUnits::fromQuantity(Result.getInt().getZExtValue()); @@ -1385,38 +1388,38 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { switch (E->getOpcode()) { default: return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E); - case BinaryOperator::Mul: return Success(Result.getInt() * RHS, E); - case BinaryOperator::Add: return Success(Result.getInt() + RHS, E); - case BinaryOperator::Sub: return Success(Result.getInt() - RHS, E); - case BinaryOperator::And: return Success(Result.getInt() & RHS, E); - case BinaryOperator::Xor: return Success(Result.getInt() ^ RHS, E); - case BinaryOperator::Or: return Success(Result.getInt() | RHS, E); - case BinaryOperator::Div: + case BO_Mul: return Success(Result.getInt() * RHS, E); + case BO_Add: return Success(Result.getInt() + RHS, E); + case BO_Sub: return Success(Result.getInt() - RHS, E); + case BO_And: return Success(Result.getInt() & RHS, E); + case BO_Xor: return Success(Result.getInt() ^ RHS, E); + case BO_Or: return Success(Result.getInt() | RHS, E); + case BO_Div: if (RHS == 0) return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E); return Success(Result.getInt() / RHS, E); - case BinaryOperator::Rem: + case BO_Rem: if (RHS == 0) return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E); return Success(Result.getInt() % RHS, E); - case BinaryOperator::Shl: { + case BO_Shl: { // FIXME: Warn about out of range shift amounts! unsigned SA = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); return Success(Result.getInt() << SA, E); } - case BinaryOperator::Shr: { + case BO_Shr: { unsigned SA = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); return Success(Result.getInt() >> SA, E); } - case BinaryOperator::LT: return Success(Result.getInt() < RHS, E); - case BinaryOperator::GT: return Success(Result.getInt() > RHS, E); - case BinaryOperator::LE: return Success(Result.getInt() <= RHS, E); - case BinaryOperator::GE: return Success(Result.getInt() >= RHS, E); - case BinaryOperator::EQ: return Success(Result.getInt() == RHS, E); - case BinaryOperator::NE: return Success(Result.getInt() != RHS, E); + case BO_LT: return Success(Result.getInt() < RHS, E); + case BO_GT: return Success(Result.getInt() > RHS, E); + case BO_LE: return Success(Result.getInt() <= RHS, E); + case BO_GE: return Success(Result.getInt() >= RHS, E); + case BO_EQ: return Success(Result.getInt() == RHS, E); + case BO_NE: return Success(Result.getInt() != RHS, E); } } @@ -1573,20 +1576,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) { } bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { - // Special case unary operators that do not need their subexpression - // evaluated. offsetof/sizeof/alignof are all special. - if (E->isOffsetOfOp()) { - // The AST for offsetof is defined in such a way that we can just - // directly Evaluate it as an l-value. - LValue LV; - if (!EvaluateLValue(E->getSubExpr(), LV, Info)) - return false; - if (LV.getLValueBase()) - return false; - return Success(LV.getLValueOffset().getQuantity(), E); - } - - if (E->getOpcode() == UnaryOperator::LNot) { + if (E->getOpcode() == UO_LNot) { // LNot's operand isn't necessarily an integer, so we handle it specially. bool bres; if (!HandleConversionToBool(E->getSubExpr(), bres, Info)) @@ -1607,17 +1597,17 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { // Address, indirect, pre/post inc/dec, etc are not valid constant exprs. // See C99 6.6p3. return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E); - case UnaryOperator::Extension: + case UO_Extension: // FIXME: Should extension allow i-c-e extension expressions in its scope? // If so, we could clear the diagnostic ID. return true; - case UnaryOperator::Plus: + case UO_Plus: // The result is always just the subexpr. return true; - case UnaryOperator::Minus: + case UO_Minus: if (!Result.isInt()) return false; return Success(-Result.getInt(), E); - case UnaryOperator::Not: + case UO_Not: if (!Result.isInt()) return false; return Success(~Result.getInt(), E); } @@ -1855,23 +1845,35 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { } bool FloatExprEvaluator::VisitUnaryReal(const UnaryOperator *E) { - ComplexValue CV; - if (!EvaluateComplex(E->getSubExpr(), CV, Info)) - return false; - Result = CV.FloatReal; - return true; + if (E->getSubExpr()->getType()->isAnyComplexType()) { + ComplexValue CV; + if (!EvaluateComplex(E->getSubExpr(), CV, Info)) + return false; + Result = CV.FloatReal; + return true; + } + + return Visit(E->getSubExpr()); } bool FloatExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { - ComplexValue CV; - if (!EvaluateComplex(E->getSubExpr(), CV, Info)) - return false; - Result = CV.FloatImag; + if (E->getSubExpr()->getType()->isAnyComplexType()) { + ComplexValue CV; + if (!EvaluateComplex(E->getSubExpr(), CV, Info)) + return false; + Result = CV.FloatImag; + return true; + } + + if (!E->getSubExpr()->isEvaluatable(Info.Ctx)) + Info.EvalResult.HasSideEffects = true; + const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(E->getType()); + Result = llvm::APFloat::getZero(Sem); return true; } bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { - if (E->getOpcode() == UnaryOperator::Deref) + if (E->getOpcode() == UO_Deref) return false; if (!EvaluateFloat(E->getSubExpr(), Result, Info)) @@ -1879,16 +1881,16 @@ bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { switch (E->getOpcode()) { default: return false; - case UnaryOperator::Plus: + case UO_Plus: return true; - case UnaryOperator::Minus: + case UO_Minus: Result.changeSign(); return true; } } bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { - if (E->getOpcode() == BinaryOperator::Comma) { + if (E->getOpcode() == BO_Comma) { if (!EvaluateFloat(E->getRHS(), Result, Info)) return false; @@ -1910,16 +1912,16 @@ bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { switch (E->getOpcode()) { default: return false; - case BinaryOperator::Mul: + case BO_Mul: Result.multiply(RHS, APFloat::rmNearestTiesToEven); return true; - case BinaryOperator::Add: + case BO_Add: Result.add(RHS, APFloat::rmNearestTiesToEven); return true; - case BinaryOperator::Sub: + case BO_Sub: Result.subtract(RHS, APFloat::rmNearestTiesToEven); return true; - case BinaryOperator::Div: + case BO_Div: Result.divide(RHS, APFloat::rmNearestTiesToEven); return true; } @@ -1990,138 +1992,142 @@ public: bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } - bool VisitImaginaryLiteral(ImaginaryLiteral *E) { - Expr* SubExpr = E->getSubExpr(); + bool VisitImaginaryLiteral(ImaginaryLiteral *E); - if (SubExpr->getType()->isRealFloatingType()) { - Result.makeComplexFloat(); - APFloat &Imag = Result.FloatImag; - if (!EvaluateFloat(SubExpr, Imag, Info)) - return false; + bool VisitCastExpr(CastExpr *E); + + bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitChooseExpr(const ChooseExpr *E) + { return Visit(E->getChosenSubExpr(Info.Ctx)); } + bool VisitUnaryExtension(const UnaryOperator *E) + { return Visit(E->getSubExpr()); } + // FIXME Missing: unary +/-/~, binary div, ImplicitValueInitExpr, + // conditional ?:, comma +}; +} // end anonymous namespace + +static bool EvaluateComplex(const Expr *E, ComplexValue &Result, + EvalInfo &Info) { + assert(E->getType()->isAnyComplexType()); + return ComplexExprEvaluator(Info, Result).Visit(const_cast(E)); +} + +bool ComplexExprEvaluator::VisitImaginaryLiteral(ImaginaryLiteral *E) { + Expr* SubExpr = E->getSubExpr(); + + if (SubExpr->getType()->isRealFloatingType()) { + Result.makeComplexFloat(); + APFloat &Imag = Result.FloatImag; + if (!EvaluateFloat(SubExpr, Imag, Info)) + return false; - Result.FloatReal = APFloat(Imag.getSemantics()); + Result.FloatReal = APFloat(Imag.getSemantics()); + return true; + } else { + assert(SubExpr->getType()->isIntegerType() && + "Unexpected imaginary literal."); + + Result.makeComplexInt(); + APSInt &Imag = Result.IntImag; + if (!EvaluateInteger(SubExpr, Imag, Info)) + return false; + + Result.IntReal = APSInt(Imag.getBitWidth(), !Imag.isSigned()); + return true; + } +} + +bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) { + Expr* SubExpr = E->getSubExpr(); + QualType EltType = E->getType()->getAs()->getElementType(); + QualType SubType = SubExpr->getType(); + + if (SubType->isRealFloatingType()) { + APFloat &Real = Result.FloatReal; + if (!EvaluateFloat(SubExpr, Real, Info)) + return false; + + if (EltType->isRealFloatingType()) { + Result.makeComplexFloat(); + Real = HandleFloatToFloatCast(EltType, SubType, Real, Info.Ctx); + Result.FloatImag = APFloat(Real.getSemantics()); return true; } else { - assert(SubExpr->getType()->isIntegerType() && - "Unexpected imaginary literal."); - Result.makeComplexInt(); - APSInt &Imag = Result.IntImag; - if (!EvaluateInteger(SubExpr, Imag, Info)) - return false; - - Result.IntReal = APSInt(Imag.getBitWidth(), !Imag.isSigned()); + Result.IntReal = HandleFloatToIntCast(EltType, SubType, Real, Info.Ctx); + Result.IntImag = APSInt(Result.IntReal.getBitWidth(), + !Result.IntReal.isSigned()); return true; } - } + } else if (SubType->isIntegerType()) { + APSInt &Real = Result.IntReal; + if (!EvaluateInteger(SubExpr, Real, Info)) + return false; - bool VisitCastExpr(CastExpr *E) { - Expr* SubExpr = E->getSubExpr(); - QualType EltType = E->getType()->getAs()->getElementType(); - QualType SubType = SubExpr->getType(); + if (EltType->isRealFloatingType()) { + Result.makeComplexFloat(); + Result.FloatReal + = HandleIntToFloatCast(EltType, SubType, Real, Info.Ctx); + Result.FloatImag = APFloat(Result.FloatReal.getSemantics()); + return true; + } else { + Result.makeComplexInt(); + Real = HandleIntToIntCast(EltType, SubType, Real, Info.Ctx); + Result.IntImag = APSInt(Real.getBitWidth(), !Real.isSigned()); + return true; + } + } else if (const ComplexType *CT = SubType->getAs()) { + if (!Visit(SubExpr)) + return false; - if (SubType->isRealFloatingType()) { - APFloat &Real = Result.FloatReal; - if (!EvaluateFloat(SubExpr, Real, Info)) - return false; + QualType SrcType = CT->getElementType(); + if (Result.isComplexFloat()) { if (EltType->isRealFloatingType()) { Result.makeComplexFloat(); - Real = HandleFloatToFloatCast(EltType, SubType, Real, Info.Ctx); - Result.FloatImag = APFloat(Real.getSemantics()); + Result.FloatReal = HandleFloatToFloatCast(EltType, SrcType, + Result.FloatReal, + Info.Ctx); + Result.FloatImag = HandleFloatToFloatCast(EltType, SrcType, + Result.FloatImag, + Info.Ctx); return true; } else { Result.makeComplexInt(); - Result.IntReal = HandleFloatToIntCast(EltType, SubType, Real, Info.Ctx); - Result.IntImag = APSInt(Result.IntReal.getBitWidth(), - !Result.IntReal.isSigned()); + Result.IntReal = HandleFloatToIntCast(EltType, SrcType, + Result.FloatReal, + Info.Ctx); + Result.IntImag = HandleFloatToIntCast(EltType, SrcType, + Result.FloatImag, + Info.Ctx); return true; } - } else if (SubType->isIntegerType()) { - APSInt &Real = Result.IntReal; - if (!EvaluateInteger(SubExpr, Real, Info)) - return false; - + } else { + assert(Result.isComplexInt() && "Invalid evaluate result."); if (EltType->isRealFloatingType()) { Result.makeComplexFloat(); - Result.FloatReal - = HandleIntToFloatCast(EltType, SubType, Real, Info.Ctx); - Result.FloatImag = APFloat(Result.FloatReal.getSemantics()); + Result.FloatReal = HandleIntToFloatCast(EltType, SrcType, + Result.IntReal, + Info.Ctx); + Result.FloatImag = HandleIntToFloatCast(EltType, SrcType, + Result.IntImag, + Info.Ctx); return true; } else { Result.makeComplexInt(); - Real = HandleIntToIntCast(EltType, SubType, Real, Info.Ctx); - Result.IntImag = APSInt(Real.getBitWidth(), !Real.isSigned()); + Result.IntReal = HandleIntToIntCast(EltType, SrcType, + Result.IntReal, + Info.Ctx); + Result.IntImag = HandleIntToIntCast(EltType, SrcType, + Result.IntImag, + Info.Ctx); return true; } - } else if (const ComplexType *CT = SubType->getAs()) { - if (!Visit(SubExpr)) - return false; - - QualType SrcType = CT->getElementType(); - - if (Result.isComplexFloat()) { - if (EltType->isRealFloatingType()) { - Result.makeComplexFloat(); - Result.FloatReal = HandleFloatToFloatCast(EltType, SrcType, - Result.FloatReal, - Info.Ctx); - Result.FloatImag = HandleFloatToFloatCast(EltType, SrcType, - Result.FloatImag, - Info.Ctx); - return true; - } else { - Result.makeComplexInt(); - Result.IntReal = HandleFloatToIntCast(EltType, SrcType, - Result.FloatReal, - Info.Ctx); - Result.IntImag = HandleFloatToIntCast(EltType, SrcType, - Result.FloatImag, - Info.Ctx); - return true; - } - } else { - assert(Result.isComplexInt() && "Invalid evaluate result."); - if (EltType->isRealFloatingType()) { - Result.makeComplexFloat(); - Result.FloatReal = HandleIntToFloatCast(EltType, SrcType, - Result.IntReal, - Info.Ctx); - Result.FloatImag = HandleIntToFloatCast(EltType, SrcType, - Result.IntImag, - Info.Ctx); - return true; - } else { - Result.makeComplexInt(); - Result.IntReal = HandleIntToIntCast(EltType, SrcType, - Result.IntReal, - Info.Ctx); - Result.IntImag = HandleIntToIntCast(EltType, SrcType, - Result.IntImag, - Info.Ctx); - return true; - } - } } - - // FIXME: Handle more casts. - return false; } - bool VisitBinaryOperator(const BinaryOperator *E); - bool VisitChooseExpr(const ChooseExpr *E) - { return Visit(E->getChosenSubExpr(Info.Ctx)); } - bool VisitUnaryExtension(const UnaryOperator *E) - { return Visit(E->getSubExpr()); } - // FIXME Missing: unary +/-/~, binary div, ImplicitValueInitExpr, - // conditional ?:, comma -}; -} // end anonymous namespace - -static bool EvaluateComplex(const Expr *E, ComplexValue &Result, - EvalInfo &Info) { - assert(E->getType()->isAnyComplexType()); - return ComplexExprEvaluator(Info, Result).Visit(const_cast(E)); + // FIXME: Handle more casts. + return false; } bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { @@ -2136,7 +2142,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { "Invalid operands to binary operator."); switch (E->getOpcode()) { default: return false; - case BinaryOperator::Add: + case BO_Add: if (Result.isComplexFloat()) { Result.getComplexFloatReal().add(RHS.getComplexFloatReal(), APFloat::rmNearestTiesToEven); @@ -2147,7 +2153,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { Result.getComplexIntImag() += RHS.getComplexIntImag(); } break; - case BinaryOperator::Sub: + case BO_Sub: if (Result.isComplexFloat()) { Result.getComplexFloatReal().subtract(RHS.getComplexFloatReal(), APFloat::rmNearestTiesToEven); @@ -2158,7 +2164,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { Result.getComplexIntImag() -= RHS.getComplexIntImag(); } break; - case BinaryOperator::Mul: + case BO_Mul: if (Result.isComplexFloat()) { ComplexValue LHS = Result; APFloat &LHS_r = LHS.getComplexFloatReal(); @@ -2321,6 +2327,8 @@ APSInt Expr::EvaluateAsInt(ASTContext &Ctx) const { // the comma operator in C99 mode. // 2: This expression is not an ICE, and is not a legal subexpression for one. +namespace { + struct ICEDiag { unsigned Val; SourceLocation Loc; @@ -2330,7 +2338,9 @@ struct ICEDiag { ICEDiag() : Val(0) {} }; -ICEDiag NoDiag() { return ICEDiag(); } +} + +static ICEDiag NoDiag() { return ICEDiag(); } static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) { Expr::EvalResult EVResult; @@ -2380,7 +2390,6 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::DependentScopeDeclRefExprClass: case Expr::CXXConstructExprClass: case Expr::CXXBindTemporaryExprClass: - case Expr::CXXBindReferenceExprClass: case Expr::CXXExprWithTemporariesClass: case Expr::CXXTemporaryObjectExprClass: case Expr::CXXUnresolvedConstructExprClass: @@ -2476,23 +2485,21 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::UnaryOperatorClass: { const UnaryOperator *Exp = cast(E); switch (Exp->getOpcode()) { - case UnaryOperator::PostInc: - case UnaryOperator::PostDec: - case UnaryOperator::PreInc: - case UnaryOperator::PreDec: - case UnaryOperator::AddrOf: - case UnaryOperator::Deref: + case UO_PostInc: + case UO_PostDec: + case UO_PreInc: + case UO_PreDec: + case UO_AddrOf: + case UO_Deref: return ICEDiag(2, E->getLocStart()); - case UnaryOperator::Extension: - case UnaryOperator::LNot: - case UnaryOperator::Plus: - case UnaryOperator::Minus: - case UnaryOperator::Not: - case UnaryOperator::Real: - case UnaryOperator::Imag: + case UO_Extension: + case UO_LNot: + case UO_Plus: + case UO_Minus: + case UO_Not: + case UO_Real: + case UO_Imag: return CheckICE(Exp->getSubExpr(), Ctx); - case UnaryOperator::OffsetOf: - break; } // OffsetOf falls through here. @@ -2515,42 +2522,42 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::BinaryOperatorClass: { const BinaryOperator *Exp = cast(E); switch (Exp->getOpcode()) { - case BinaryOperator::PtrMemD: - case BinaryOperator::PtrMemI: - case BinaryOperator::Assign: - case BinaryOperator::MulAssign: - case BinaryOperator::DivAssign: - case BinaryOperator::RemAssign: - case BinaryOperator::AddAssign: - case BinaryOperator::SubAssign: - case BinaryOperator::ShlAssign: - case BinaryOperator::ShrAssign: - case BinaryOperator::AndAssign: - case BinaryOperator::XorAssign: - case BinaryOperator::OrAssign: + case BO_PtrMemD: + case BO_PtrMemI: + case BO_Assign: + case BO_MulAssign: + case BO_DivAssign: + case BO_RemAssign: + case BO_AddAssign: + case BO_SubAssign: + case BO_ShlAssign: + case BO_ShrAssign: + case BO_AndAssign: + case BO_XorAssign: + case BO_OrAssign: return ICEDiag(2, E->getLocStart()); - case BinaryOperator::Mul: - case BinaryOperator::Div: - case BinaryOperator::Rem: - case BinaryOperator::Add: - case BinaryOperator::Sub: - case BinaryOperator::Shl: - case BinaryOperator::Shr: - case BinaryOperator::LT: - case BinaryOperator::GT: - case BinaryOperator::LE: - case BinaryOperator::GE: - case BinaryOperator::EQ: - case BinaryOperator::NE: - case BinaryOperator::And: - case BinaryOperator::Xor: - case BinaryOperator::Or: - case BinaryOperator::Comma: { + case BO_Mul: + case BO_Div: + case BO_Rem: + case BO_Add: + case BO_Sub: + case BO_Shl: + case BO_Shr: + case BO_LT: + case BO_GT: + case BO_LE: + case BO_GE: + case BO_EQ: + case BO_NE: + case BO_And: + case BO_Xor: + case BO_Or: + case BO_Comma: { ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); - if (Exp->getOpcode() == BinaryOperator::Div || - Exp->getOpcode() == BinaryOperator::Rem) { + if (Exp->getOpcode() == BO_Div || + Exp->getOpcode() == BO_Rem) { // Evaluate gives an error for undefined Div/Rem, so make sure // we don't evaluate one. if (LHSResult.Val != 2 && RHSResult.Val != 2) { @@ -2564,7 +2571,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { } } } - if (Exp->getOpcode() == BinaryOperator::Comma) { + if (Exp->getOpcode() == BO_Comma) { if (Ctx.getLangOptions().C99) { // C99 6.6p3 introduces a strange edge case: comma can be in an ICE // if it isn't evaluated. @@ -2579,15 +2586,15 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { return LHSResult; return RHSResult; } - case BinaryOperator::LAnd: - case BinaryOperator::LOr: { + case BO_LAnd: + case BO_LOr: { ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); if (LHSResult.Val == 0 && RHSResult.Val == 1) { // Rare case where the RHS has a comma "side-effect"; we need // to actually check the condition to see whether the side // with the comma is evaluated. - if ((Exp->getOpcode() == BinaryOperator::LAnd) != + if ((Exp->getOpcode() == BO_LAnd) != (Exp->getLHS()->EvaluateAsInt(Ctx) == 0)) return RHSResult; return NoDiag(); diff --git a/lib/AST/FullExpr.cpp b/lib/AST/FullExpr.cpp index f47284f..93ee8d1 100644 --- a/lib/AST/FullExpr.cpp +++ b/lib/AST/FullExpr.cpp @@ -43,16 +43,3 @@ FullExpr FullExpr::Create(ASTContext &Context, Expr *SubExpr, return E; } -void FullExpr::Destroy(ASTContext &Context) { - if (Expr *E = SubExpr.dyn_cast()) { - E->Destroy(Context); - return; - } - - ExprAndTemporaries *ET = SubExpr.get(); - for (ExprAndTemporaries::temps_iterator i = ET->temps_begin(), - e = ET->temps_end(); i != e; ++i) - (*i)->Destroy(Context); - - Context.Deallocate(ET); -} diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp new file mode 100644 index 0000000..c3fa466 --- /dev/null +++ b/lib/AST/ItaniumCXXABI.cpp @@ -0,0 +1,52 @@ +//===------- ItaniumCXXABI.cpp - AST support for the Itanium C++ ABI ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides C++ AST support targetting the Itanium C++ ABI, which is +// documented at: +// http://www.codesourcery.com/public/cxx-abi/abi.html +// http://www.codesourcery.com/public/cxx-abi/abi-eh.html +// +// It also supports the closely-related ARM C++ ABI, documented at: +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf +// +//===----------------------------------------------------------------------===// + +#include "CXXABI.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" + +using namespace clang; + +namespace { +class ItaniumCXXABI : public CXXABI { +protected: + ASTContext &Context; +public: + ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { } + + unsigned getMemberPointerSize(const MemberPointerType *MPT) const { + QualType Pointee = MPT->getPointeeType(); + if (Pointee->isFunctionType()) return 2; + return 1; + } +}; + +class ARMCXXABI : public ItaniumCXXABI { +public: + ARMCXXABI(ASTContext &Ctx) : ItaniumCXXABI(Ctx) { } +}; +} + +CXXABI *clang::CreateItaniumCXXABI(ASTContext &Ctx) { + return new ItaniumCXXABI(Ctx); +} + +CXXABI *clang::CreateARMCXXABI(ASTContext &Ctx) { + return new ARMCXXABI(Ctx); +} diff --git a/lib/AST/Makefile b/lib/AST/Makefile index 7a1672b..65383c5 100644 --- a/lib/AST/Makefile +++ b/lib/AST/Makefile @@ -13,7 +13,6 @@ CLANG_LEVEL := ../.. LIBRARYNAME := clangAST -BUILD_ARCHIVE = 1 include $(CLANG_LEVEL)/Makefile diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp new file mode 100644 index 0000000..87b7767 --- /dev/null +++ b/lib/AST/MicrosoftCXXABI.cpp @@ -0,0 +1,48 @@ +//===------- MicrosoftCXXABI.cpp - AST support for the Microsoft C++ ABI --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides C++ AST support targetting the Microsoft Visual C++ +// ABI. +// +//===----------------------------------------------------------------------===// + +#include "CXXABI.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" +#include "clang/AST/DeclCXX.h" + +using namespace clang; + +namespace { +class MicrosoftCXXABI : public CXXABI { + ASTContext &Context; +public: + MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { } + + unsigned getMemberPointerSize(const MemberPointerType *MPT) const; +}; +} + +unsigned MicrosoftCXXABI::getMemberPointerSize(const MemberPointerType *MPT) const { + QualType Pointee = MPT->getPointeeType(); + CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + if (RD->getNumVBases() > 0) { + if (Pointee->isFunctionType()) + return 3; + else + return 2; + } else if (RD->getNumBases() > 1 && Pointee->isFunctionType()) + return 2; + return 1; +} + +CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) { + return new MicrosoftCXXABI(Ctx); +} + diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index d6594cd..212def8 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -176,11 +176,6 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS, OS << "::"; } -void NestedNameSpecifier::Destroy(ASTContext &Context) { - this->~NestedNameSpecifier(); - Context.Deallocate((void *)this); -} - void NestedNameSpecifier::dump(const LangOptions &LO) { print(llvm::errs(), PrintingPolicy(LO)); } diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp index 48251d5..5fe873a 100644 --- a/lib/AST/ParentMap.cpp +++ b/lib/AST/ParentMap.cpp @@ -73,7 +73,7 @@ bool ParentMap::isConsumedExpr(Expr* E) const { BinaryOperator *BE = cast(P); // If it is a comma, only the right side is consumed. // If it isn't a comma, both sides are consumed. - return BE->getOpcode()!=BinaryOperator::Comma ||DirectChild==BE->getRHS(); + return BE->getOpcode()!=BO_Comma ||DirectChild==BE->getRHS(); } case Stmt::ForStmtClass: return DirectChild == cast(P)->getCond(); diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp index 262c459..4d9c516 100644 --- a/lib/AST/RecordLayout.cpp +++ b/lib/AST/RecordLayout.cpp @@ -19,8 +19,10 @@ using namespace clang; void ASTRecordLayout::Destroy(ASTContext &Ctx) { if (FieldOffsets) Ctx.Deallocate(FieldOffsets); - if (CXXInfo) + if (CXXInfo) { Ctx.Deallocate(CXXInfo); + CXXInfo->~CXXRecordLayoutInfo(); + } this->~ASTRecordLayout(); Ctx.Deallocate(this); } diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 88d71ce..13fae29 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -73,22 +73,11 @@ class EmptySubobjectMap { /// member subobject that is empty. void ComputeEmptySubobjectSizes(); - bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, - uint64_t Offset) const; - void AddSubobjectAtOffset(const CXXRecordDecl *RD, uint64_t Offset); - bool CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, - uint64_t Offset); void UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info, uint64_t Offset, bool PlacingEmptyBase); - bool CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, - const CXXRecordDecl *Class, - uint64_t Offset) const; - bool CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, - uint64_t Offset) const; - void UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, const CXXRecordDecl *Class, uint64_t Offset); @@ -100,6 +89,19 @@ class EmptySubobjectMap { return Offset <= MaxEmptyClassOffset; } +protected: + bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, + uint64_t Offset) const; + + bool CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, + uint64_t Offset); + + bool CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *Class, + uint64_t Offset) const; + bool CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, + uint64_t Offset) const; + public: /// This holds the size of the largest empty subobject (either a base /// or a member). Will be zero if the record being built doesn't contain @@ -513,6 +515,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD, } class RecordLayoutBuilder { +protected: // FIXME: Remove this and make the appropriate fields public. friend class clang::ASTContext; @@ -623,12 +626,14 @@ class RecordLayoutBuilder { void SelectPrimaryVBase(const CXXRecordDecl *RD); + virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const; + /// IdentifyPrimaryBases - Identify all virtual base classes, direct or /// indirect, that are primary base classes for some other direct or indirect /// base class. void IdentifyPrimaryBases(const CXXRecordDecl *RD); - bool IsNearlyEmpty(const CXXRecordDecl *RD) const; + virtual bool IsNearlyEmpty(const CXXRecordDecl *RD) const; /// LayoutNonVirtualBases - Determines the primary base class (if any) and /// lays it out. Will then proceed to lay out all non-virtual base clasess. @@ -638,7 +643,7 @@ class RecordLayoutBuilder { void LayoutNonVirtualBase(const BaseSubobjectInfo *Base); void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info, - uint64_t Offset); + uint64_t Offset); /// LayoutVirtualBases - Lays out all the virtual bases. void LayoutVirtualBases(const CXXRecordDecl *RD, @@ -664,6 +669,8 @@ class RecordLayoutBuilder { void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT public: static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD); + + virtual ~RecordLayoutBuilder() { } }; } // end anonymous namespace @@ -734,6 +741,11 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { } } +uint64_t +RecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const { + return Context.Target.getPointerWidth(0); +} + /// DeterminePrimaryBase - Determine the primary base of the given class. void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { // If the class isn't dynamic, it won't have a primary base. @@ -794,7 +806,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { assert(DataSize == 0 && "Vtable pointer must be at offset zero!"); // Update the size. - Size += Context.Target.getPointerWidth(0); + Size += GetVirtualPointersSize(RD); DataSize = Size; // Update the alignment. @@ -1123,8 +1135,8 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) { if (const MaxFieldAlignmentAttr *MFAA = D->getAttr()) MaxFieldAlignment = MFAA->getAlignment(); - if (const AlignedAttr *AA = D->getAttr()) - UpdateAlignment(AA->getMaxAlignment()); + if (unsigned MaxAlign = D->getMaxAlignment()) + UpdateAlignment(MaxAlign); } } @@ -1287,8 +1299,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { if (FieldPacked || !Context.Target.useBitFieldTypeAlignment()) FieldAlign = 1; - if (const AlignedAttr *AA = D->getAttr()) - FieldAlign = std::max(FieldAlign, AA->getMaxAlignment()); + FieldAlign = std::max(FieldAlign, D->getMaxAlignment()); // The maximum field alignment overrides the aligned attribute. if (MaxFieldAlignment) @@ -1357,8 +1368,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { if (FieldPacked) FieldAlign = 8; - if (const AlignedAttr *AA = D->getAttr()) - FieldAlign = std::max(FieldAlign, AA->getMaxAlignment()); + FieldAlign = std::max(FieldAlign, D->getMaxAlignment()); // The maximum field alignment overrides the aligned attribute. if (MaxFieldAlignment) @@ -1453,6 +1463,37 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { return 0; } +// This class implements layout specific to the Microsoft ABI. +class MSRecordLayoutBuilder: public RecordLayoutBuilder { +public: + MSRecordLayoutBuilder(ASTContext& Ctx, EmptySubobjectMap *EmptySubobjects): + RecordLayoutBuilder(Ctx, EmptySubobjects) {} + + virtual bool IsNearlyEmpty(const CXXRecordDecl *RD) const; + virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const; +}; + +bool MSRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const { + // FIXME: Audit the corners + if (!RD->isDynamicClass()) + return false; + const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD); + // In the Microsoft ABI, classes can have one or two vtable pointers. + if (BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0) || + BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0) * 2) + return true; + return false; +} + +uint64_t +MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const { + // We should reserve space for two pointers if the class has both + // virtual functions and virtual bases. + if (RD->isPolymorphic() && RD->getNumVBases() > 0) + return 2 * Context.Target.getPointerWidth(0); + return Context.Target.getPointerWidth(0); +} + /// getASTRecordLayout - Get or compute information about the layout of the /// specified record (struct/union/class), which indicates its size and field /// position information. @@ -1471,8 +1512,16 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { if (const CXXRecordDecl *RD = dyn_cast(D)) { EmptySubobjectMap EmptySubobjects(*this, RD); - RecordLayoutBuilder Builder(*this, &EmptySubobjects); - Builder.Layout(RD); + // When compiling for Microsoft, use the special MS builder. + llvm::OwningPtr Builder; + switch (Target.getCXXABI()) { + default: + Builder.reset(new RecordLayoutBuilder(*this, &EmptySubobjects)); + break; + case CXXABI_Microsoft: + Builder.reset(new MSRecordLayoutBuilder(*this, &EmptySubobjects)); + } + Builder->Layout(RD); // FIXME: This is not always correct. See the part about bitfields at // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info. @@ -1481,20 +1530,20 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { // FIXME: This should be done in FinalizeLayout. uint64_t DataSize = - IsPODForThePurposeOfLayout ? Builder.Size : Builder.DataSize; + IsPODForThePurposeOfLayout ? Builder->Size : Builder->DataSize; uint64_t NonVirtualSize = - IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize; + IsPODForThePurposeOfLayout ? DataSize : Builder->NonVirtualSize; NewEntry = - new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment, - DataSize, Builder.FieldOffsets.data(), - Builder.FieldOffsets.size(), + new (*this) ASTRecordLayout(*this, Builder->Size, Builder->Alignment, + DataSize, Builder->FieldOffsets.data(), + Builder->FieldOffsets.size(), NonVirtualSize, - Builder.NonVirtualAlignment, + Builder->NonVirtualAlignment, EmptySubobjects.SizeOfLargestEmptySubobject, - Builder.PrimaryBase, - Builder.PrimaryBaseIsVirtual, - Builder.Bases, Builder.VBases); + Builder->PrimaryBase, + Builder->PrimaryBaseIsVirtual, + Builder->Bases, Builder->VBases); } else { RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); Builder.Layout(D); @@ -1630,7 +1679,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS, if (const RecordType *RT = Field->getType()->getAs()) { if (const CXXRecordDecl *D = dyn_cast(RT->getDecl())) { DumpCXXRecordLayout(OS, D, C, FieldOffset, IndentLevel, - Field->getNameAsCString(), + Field->getName().data(), /*IncludeVirtualBases=*/true); continue; } diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 6dbe8f4..fc88981 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -119,7 +119,7 @@ bool Stmt::hasImplicitControlFlow() const { case Stmt::BinaryOperatorClass: { const BinaryOperator* B = cast(this); - if (B->isLogicalOp() || B->getOpcode() == BinaryOperator::Comma) + if (B->isLogicalOp() || B->getOpcode() == BO_Comma) return true; else return false; @@ -215,8 +215,9 @@ int AsmStmt::getNamedOperand(llvm::StringRef SymbolicName) const { /// true, otherwise return false. unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl&Pieces, ASTContext &C, unsigned &DiagOffs) const { - const char *StrStart = getAsmString()->getStrData(); - const char *StrEnd = StrStart + getAsmString()->getByteLength(); + llvm::StringRef Str = getAsmString()->getString(); + const char *StrStart = Str.begin(); + const char *StrEnd = Str.end(); const char *CurPtr = StrStart; // "Simple" inline asms have no constraints or operands, just convert the asm @@ -451,6 +452,15 @@ CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc, return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers); } +CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty, + unsigned numHandlers) { + std::size_t Size = sizeof(CXXTryStmt); + Size += ((numHandlers + 1) * sizeof(Stmt)); + + void *Mem = C.Allocate(Size, llvm::alignof()); + return new (Mem) CXXTryStmt(Empty, numHandlers); +} + CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, Stmt **handlers, unsigned numHandlers) : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(numHandlers) { @@ -459,46 +469,6 @@ CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, std::copy(handlers, handlers + NumHandlers, Stmts + 1); } -//===----------------------------------------------------------------------===// -// AST Destruction. -//===----------------------------------------------------------------------===// - -void Stmt::DestroyChildren(ASTContext &C) { - for (child_iterator I = child_begin(), E = child_end(); I !=E; ) - if (Stmt* Child = *I++) Child->Destroy(C); -} - -static void BranchDestroy(ASTContext &C, Stmt *S, Stmt **SubExprs, - unsigned NumExprs) { - // We do not use child_iterator here because that will include - // the expressions referenced by the condition variable. - for (Stmt **I = SubExprs, **E = SubExprs + NumExprs; I != E; ++I) - if (Stmt *Child = *I) Child->Destroy(C); - - S->~Stmt(); - C.Deallocate((void *) S); -} - -void Stmt::DoDestroy(ASTContext &C) { - DestroyChildren(C); - this->~Stmt(); - C.Deallocate((void *)this); -} - -void CXXCatchStmt::DoDestroy(ASTContext& C) { - if (ExceptionDecl) - ExceptionDecl->Destroy(C); - Stmt::DoDestroy(C); -} - -void DeclStmt::DoDestroy(ASTContext &C) { - // Don't use StmtIterator to iterate over the Decls, as that can recurse - // into VLA size expressions (which are owned by the VLA). Further, Decls - // are owned by the DeclContext, and will be destroyed with them. - if (DG.isDeclGroup()) - DG.getDeclGroup().Destroy(C); -} - IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, Stmt *then, SourceLocation EL, Stmt *elsev) : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) @@ -528,10 +498,6 @@ void IfStmt::setConditionVariable(ASTContext &C, VarDecl *V) { V->getSourceRange().getEnd()); } -void IfStmt::DoDestroy(ASTContext &C) { - BranchDestroy(C, this, SubExprs, END_EXPR); -} - ForStmt::ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP) @@ -563,10 +529,6 @@ void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) { V->getSourceRange().getEnd()); } -void ForStmt::DoDestroy(ASTContext &C) { - BranchDestroy(C, this, SubExprs, END_EXPR); -} - SwitchStmt::SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond) : Stmt(SwitchStmtClass), FirstCase(0) { @@ -594,20 +556,6 @@ void SwitchStmt::setConditionVariable(ASTContext &C, VarDecl *V) { V->getSourceRange().getEnd()); } -void SwitchStmt::DoDestroy(ASTContext &C) { - // Destroy the SwitchCase statements in this switch. In the normal - // case, this loop will merely decrement the reference counts from - // the Retain() calls in addSwitchCase(); - SwitchCase *SC = FirstCase; - while (SC) { - SwitchCase *Next = SC->getNextSwitchCase(); - SC->Destroy(C); - SC = Next; - } - - BranchDestroy(C, this, SubExprs, END_EXPR); -} - WhileStmt::WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, SourceLocation WL) : Stmt(WhileStmtClass) @@ -637,22 +585,6 @@ void WhileStmt::setConditionVariable(ASTContext &C, VarDecl *V) { V->getSourceRange().getEnd()); } -void WhileStmt::DoDestroy(ASTContext &C) { - BranchDestroy(C, this, SubExprs, END_EXPR); -} - -void AsmStmt::DoDestroy(ASTContext &C) { - DestroyChildren(C); - - C.Deallocate(Names); - C.Deallocate(Constraints); - C.Deallocate(Exprs); - C.Deallocate(Clobbers); - - this->~AsmStmt(); - C.Deallocate((void *)this); -} - //===----------------------------------------------------------------------===// // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index b388a3b1..5c236a4 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -65,6 +65,13 @@ namespace { OS << '\n'; DumpSubTree(*CI++); } + if (const ConditionalOperator *CO = + dyn_cast(S)) { + if (CO->getSAVE()) { + OS << '\n'; + DumpSubTree(CO->getSAVE()); + } + } } } OS << ')'; @@ -225,7 +232,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { OS << "\""; // Emit storage class for vardecls. if (VarDecl *V = dyn_cast(VD)) { - if (V->getStorageClass() != VarDecl::None) + if (V->getStorageClass() != SC_None) OS << VarDecl::getStorageClassSpecifierString(V->getStorageClass()) << " "; } @@ -308,13 +315,13 @@ void StmtDumper::VisitExpr(Expr *Node) { } static void DumpBasePath(llvm::raw_ostream &OS, CastExpr *Node) { - if (Node->getBasePath().empty()) + if (Node->path_empty()) return; OS << " ("; bool First = true; - for (CXXBaseSpecifierArray::iterator I = Node->getBasePath().begin(), - E = Node->getBasePath().end(); I != E; ++I) { + for (CastExpr::path_iterator + I = Node->path_begin(), E = Node->path_end(); I != E; ++I) { const CXXBaseSpecifier *Base = *I; if (!First) OS << " -> "; @@ -340,8 +347,16 @@ void StmtDumper::VisitCastExpr(CastExpr *Node) { void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) { VisitCastExpr(Node); - if (Node->isLvalueCast()) + switch (Node->getValueKind()) { + case VK_LValue: OS << " lvalue"; + break; + case VK_XValue: + OS << " xvalue"; + break; + case VK_RValue: + break; + } } void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { @@ -421,8 +436,7 @@ void StmtDumper::VisitStringLiteral(StringLiteral *Str) { if (Str->isWide()) OS << "L"; OS << '"'; - OS.write_escaped(llvm::StringRef(Str->getStrData(), - Str->getByteLength())); + OS.write_escaped(Str->getString()); OS << '"'; } @@ -511,6 +525,8 @@ void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) { DumpType(Ctor->getType()); if (Node->isElidable()) OS << " elidable"; + if (Node->requiresZeroInitialization()) + OS << " zeroing"; } void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { @@ -623,9 +639,13 @@ void StmtDumper::VisitObjCSuperExpr(ObjCSuperExpr *Node) { /// specified node and a few nodes underneath it, but not the whole subtree. /// This is useful in a debugger. void Stmt::dump(SourceManager &SM) const { - StmtDumper P(&SM, llvm::errs(), 4); + dump(llvm::errs(), SM); +} + +void Stmt::dump(llvm::raw_ostream &OS, SourceManager &SM) const { + StmtDumper P(&SM, OS, 4); P.DumpSubTree(const_cast(this)); - llvm::errs() << "\n"; + OS << "\n"; } /// dump - This does a local dump of the specified AST fragment. It dumps the diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 7043c35..5236a66 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -77,16 +77,21 @@ namespace { return OS; } - bool PrintOffsetOfDesignator(Expr *E); - void VisitUnaryOffsetOf(UnaryOperator *Node); - void Visit(Stmt* S) { if (Helper && Helper->handledStmt(S,OS)) return; else StmtVisitor::Visit(S); } + + void VisitStmt(Stmt *Node) ATTRIBUTE_UNUSED { + Indent() << "<>\n"; + } + void VisitExpr(Expr *Node) ATTRIBUTE_UNUSED { + OS << "<>"; + } + void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); - void VisitStmt(Stmt *Node); +#define ABSTRACT_STMT(CLASS) #define STMT(CLASS, PARENT) \ void Visit##CLASS(CLASS *Node); #include "clang/AST/StmtNodes.inc" @@ -97,10 +102,6 @@ namespace { // Stmt printing methods. //===----------------------------------------------------------------------===// -void StmtPrinter::VisitStmt(Stmt *Node) { - Indent() << "<>\n"; -} - /// PrintRawCompoundStmt - Print a compound stmt without indenting the {, and /// with no newline after the }. void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) { @@ -465,15 +466,11 @@ void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) { // Expr printing methods. //===----------------------------------------------------------------------===// -void StmtPrinter::VisitExpr(Expr *Node) { - OS << "<>"; -} - void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); - OS << Node->getDecl(); - if (Node->hasExplicitTemplateArgumentList()) + OS << Node->getNameInfo(); + if (Node->hasExplicitTemplateArgs()) OS << TemplateSpecializationType::PrintTemplateArgumentList( Node->getTemplateArgs(), Node->getNumTemplateArgs(), @@ -483,7 +480,7 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { void StmtPrinter::VisitDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *Node) { Node->getQualifier()->print(OS, Policy); - OS << Node->getDeclName().getAsString(); + OS << Node->getNameInfo(); if (Node->hasExplicitTemplateArgs()) OS << TemplateSpecializationType::PrintTemplateArgumentList( Node->getTemplateArgs(), @@ -494,7 +491,7 @@ void StmtPrinter::VisitDependentScopeDeclRefExpr( void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { if (Node->getQualifier()) Node->getQualifier()->print(OS, Policy); - OS << Node->getName().getAsString(); + OS << Node->getNameInfo(); if (Node->hasExplicitTemplateArgs()) OS << TemplateSpecializationType::PrintTemplateArgumentList( Node->getTemplateArgs(), @@ -515,7 +512,7 @@ void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { PrintExpr(Node->getBase()); OS << "."; } - OS << Node->getProperty()->getNameAsCString(); + OS << Node->getProperty()->getName(); } void StmtPrinter::VisitObjCImplicitSetterGetterRefExpr( @@ -624,8 +621,10 @@ void StmtPrinter::VisitStringLiteral(StringLiteral *Str) { OS << '"'; // FIXME: this doesn't print wstrings right. - for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { - unsigned char Char = Str->getStrData()[i]; + llvm::StringRef StrData = Str->getString(); + for (llvm::StringRef::iterator I = StrData.begin(), E = StrData.end(); + I != E; ++I) { + unsigned char Char = *I; switch (Char) { default: @@ -661,13 +660,13 @@ void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) { // it might be concatenated incorrectly like '+'. switch (Node->getOpcode()) { default: break; - case UnaryOperator::Real: - case UnaryOperator::Imag: - case UnaryOperator::Extension: + case UO_Real: + case UO_Imag: + case UO_Extension: OS << ' '; break; - case UnaryOperator::Plus: - case UnaryOperator::Minus: + case UO_Plus: + case UO_Minus: if (isa(Node->getSubExpr())) OS << ' '; break; @@ -679,31 +678,6 @@ void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) { OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); } -bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) { - if (isa(E)) { - // Base case, print the type and comma. - OS << E->getType().getAsString(Policy) << ", "; - return true; - } else if (ArraySubscriptExpr *ASE = dyn_cast(E)) { - PrintOffsetOfDesignator(ASE->getLHS()); - OS << "["; - PrintExpr(ASE->getRHS()); - OS << "]"; - return false; - } else { - MemberExpr *ME = cast(E); - bool IsFirst = PrintOffsetOfDesignator(ME->getBase()); - OS << (IsFirst ? "" : ".") << ME->getMemberDecl(); - return false; - } -} - -void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) { - OS << "__builtin_offsetof("; - PrintOffsetOfDesignator(Node->getSubExpr()); - OS << ")"; -} - void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) { OS << "__builtin_offsetof("; OS << Node->getTypeSourceInfo()->getType().getAsString(Policy) << ", "; @@ -777,9 +751,9 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); - OS << Node->getMemberDecl(); + OS << Node->getMemberNameInfo(); - if (Node->hasExplicitTemplateArgumentList()) + if (Node->hasExplicitTemplateArgs()) OS << TemplateSpecializationType::PrintTemplateArgumentList( Node->getTemplateArgs(), Node->getNumTemplateArgs(), @@ -795,12 +769,6 @@ void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { OS << "."; OS << Node->getAccessor().getName(); } -void StmtPrinter::VisitCastExpr(CastExpr *) { - assert(0 && "CastExpr is an abstract class"); -} -void StmtPrinter::VisitExplicitCastExpr(ExplicitCastExpr *) { - assert(0 && "ExplicitCastExpr is an abstract class"); -} void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) { OS << "(" << Node->getType().getAsString(Policy) << ")"; PrintExpr(Node->getSubExpr()); @@ -1069,10 +1037,6 @@ void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { PrintExpr(Node->getSubExpr()); } -void StmtPrinter::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *Node) { - PrintExpr(Node->getSubExpr()); -} - void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) { OS << Node->getType().getAsString(Policy); OS << "("; @@ -1201,7 +1165,7 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr( // FIXME: Track use of "template" keyword explicitly? OS << "template "; - OS << Node->getMember().getAsString(); + OS << Node->getMemberNameInfo(); if (Node->hasExplicitTemplateArgs()) { OS << TemplateSpecializationType::PrintTemplateArgumentList( @@ -1221,7 +1185,7 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { // FIXME: this might originally have been written with 'template' - OS << Node->getMemberName().getAsString(); + OS << Node->getMemberNameInfo(); if (Node->hasExplicitTemplateArgs()) { OS << TemplateSpecializationType::PrintTemplateArgumentList( @@ -1368,7 +1332,7 @@ void Stmt::printPretty(llvm::raw_ostream &OS, ASTContext& Context, } if (Policy.Dump && &Context) { - dump(Context.getSourceManager()); + dump(OS, Context.getSourceManager()); return; } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index cff86a4..78a336d 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -325,7 +325,7 @@ void StmtProfiler::VisitCastExpr(CastExpr *S) { void StmtProfiler::VisitImplicitCastExpr(ImplicitCastExpr *S) { VisitCastExpr(S); - ID.AddBoolean(S->isLvalueCast()); + ID.AddInteger(S->getValueKind()); } void StmtProfiler::VisitExplicitCastExpr(ExplicitCastExpr *S) { @@ -436,8 +436,8 @@ void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) { } static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S, - UnaryOperator::Opcode &UnaryOp, - BinaryOperator::Opcode &BinaryOp) { + UnaryOperatorKind &UnaryOp, + BinaryOperatorKind &BinaryOp) { switch (S->getOperator()) { case OO_None: case OO_New: @@ -453,165 +453,165 @@ static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S, case OO_Plus: if (S->getNumArgs() == 1) { - UnaryOp = UnaryOperator::Plus; + UnaryOp = UO_Plus; return Stmt::UnaryOperatorClass; } - BinaryOp = BinaryOperator::Add; + BinaryOp = BO_Add; return Stmt::BinaryOperatorClass; case OO_Minus: if (S->getNumArgs() == 1) { - UnaryOp = UnaryOperator::Minus; + UnaryOp = UO_Minus; return Stmt::UnaryOperatorClass; } - BinaryOp = BinaryOperator::Sub; + BinaryOp = BO_Sub; return Stmt::BinaryOperatorClass; case OO_Star: if (S->getNumArgs() == 1) { - UnaryOp = UnaryOperator::Minus; + UnaryOp = UO_Minus; return Stmt::UnaryOperatorClass; } - BinaryOp = BinaryOperator::Sub; + BinaryOp = BO_Sub; return Stmt::BinaryOperatorClass; case OO_Slash: - BinaryOp = BinaryOperator::Div; + BinaryOp = BO_Div; return Stmt::BinaryOperatorClass; case OO_Percent: - BinaryOp = BinaryOperator::Rem; + BinaryOp = BO_Rem; return Stmt::BinaryOperatorClass; case OO_Caret: - BinaryOp = BinaryOperator::Xor; + BinaryOp = BO_Xor; return Stmt::BinaryOperatorClass; case OO_Amp: if (S->getNumArgs() == 1) { - UnaryOp = UnaryOperator::AddrOf; + UnaryOp = UO_AddrOf; return Stmt::UnaryOperatorClass; } - BinaryOp = BinaryOperator::And; + BinaryOp = BO_And; return Stmt::BinaryOperatorClass; case OO_Pipe: - BinaryOp = BinaryOperator::Or; + BinaryOp = BO_Or; return Stmt::BinaryOperatorClass; case OO_Tilde: - UnaryOp = UnaryOperator::Not; + UnaryOp = UO_Not; return Stmt::UnaryOperatorClass; case OO_Exclaim: - UnaryOp = UnaryOperator::LNot; + UnaryOp = UO_LNot; return Stmt::UnaryOperatorClass; case OO_Equal: - BinaryOp = BinaryOperator::Assign; + BinaryOp = BO_Assign; return Stmt::BinaryOperatorClass; case OO_Less: - BinaryOp = BinaryOperator::LT; + BinaryOp = BO_LT; return Stmt::BinaryOperatorClass; case OO_Greater: - BinaryOp = BinaryOperator::GT; + BinaryOp = BO_GT; return Stmt::BinaryOperatorClass; case OO_PlusEqual: - BinaryOp = BinaryOperator::AddAssign; + BinaryOp = BO_AddAssign; return Stmt::CompoundAssignOperatorClass; case OO_MinusEqual: - BinaryOp = BinaryOperator::SubAssign; + BinaryOp = BO_SubAssign; return Stmt::CompoundAssignOperatorClass; case OO_StarEqual: - BinaryOp = BinaryOperator::MulAssign; + BinaryOp = BO_MulAssign; return Stmt::CompoundAssignOperatorClass; case OO_SlashEqual: - BinaryOp = BinaryOperator::DivAssign; + BinaryOp = BO_DivAssign; return Stmt::CompoundAssignOperatorClass; case OO_PercentEqual: - BinaryOp = BinaryOperator::RemAssign; + BinaryOp = BO_RemAssign; return Stmt::CompoundAssignOperatorClass; case OO_CaretEqual: - BinaryOp = BinaryOperator::XorAssign; + BinaryOp = BO_XorAssign; return Stmt::CompoundAssignOperatorClass; case OO_AmpEqual: - BinaryOp = BinaryOperator::AndAssign; + BinaryOp = BO_AndAssign; return Stmt::CompoundAssignOperatorClass; case OO_PipeEqual: - BinaryOp = BinaryOperator::OrAssign; + BinaryOp = BO_OrAssign; return Stmt::CompoundAssignOperatorClass; case OO_LessLess: - BinaryOp = BinaryOperator::Shl; + BinaryOp = BO_Shl; return Stmt::BinaryOperatorClass; case OO_GreaterGreater: - BinaryOp = BinaryOperator::Shr; + BinaryOp = BO_Shr; return Stmt::BinaryOperatorClass; case OO_LessLessEqual: - BinaryOp = BinaryOperator::ShlAssign; + BinaryOp = BO_ShlAssign; return Stmt::CompoundAssignOperatorClass; case OO_GreaterGreaterEqual: - BinaryOp = BinaryOperator::ShrAssign; + BinaryOp = BO_ShrAssign; return Stmt::CompoundAssignOperatorClass; case OO_EqualEqual: - BinaryOp = BinaryOperator::EQ; + BinaryOp = BO_EQ; return Stmt::BinaryOperatorClass; case OO_ExclaimEqual: - BinaryOp = BinaryOperator::NE; + BinaryOp = BO_NE; return Stmt::BinaryOperatorClass; case OO_LessEqual: - BinaryOp = BinaryOperator::LE; + BinaryOp = BO_LE; return Stmt::BinaryOperatorClass; case OO_GreaterEqual: - BinaryOp = BinaryOperator::GE; + BinaryOp = BO_GE; return Stmt::BinaryOperatorClass; case OO_AmpAmp: - BinaryOp = BinaryOperator::LAnd; + BinaryOp = BO_LAnd; return Stmt::BinaryOperatorClass; case OO_PipePipe: - BinaryOp = BinaryOperator::LOr; + BinaryOp = BO_LOr; return Stmt::BinaryOperatorClass; case OO_PlusPlus: - UnaryOp = S->getNumArgs() == 1? UnaryOperator::PreInc - : UnaryOperator::PostInc; + UnaryOp = S->getNumArgs() == 1? UO_PreInc + : UO_PostInc; return Stmt::UnaryOperatorClass; case OO_MinusMinus: - UnaryOp = S->getNumArgs() == 1? UnaryOperator::PreDec - : UnaryOperator::PostDec; + UnaryOp = S->getNumArgs() == 1? UO_PreDec + : UO_PostDec; return Stmt::UnaryOperatorClass; case OO_Comma: - BinaryOp = BinaryOperator::Comma; + BinaryOp = BO_Comma; return Stmt::BinaryOperatorClass; case OO_ArrowStar: - BinaryOp = BinaryOperator::PtrMemI; + BinaryOp = BO_PtrMemI; return Stmt::BinaryOperatorClass; case OO_Subscript: @@ -626,8 +626,8 @@ void StmtProfiler::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *S) { if (S->isTypeDependent()) { // Type-dependent operator calls are profiled like their underlying // syntactic operator. - UnaryOperator::Opcode UnaryOp = UnaryOperator::Extension; - BinaryOperator::Opcode BinaryOp = BinaryOperator::Comma; + UnaryOperatorKind UnaryOp = UO_Extension; + BinaryOperatorKind BinaryOp = BO_Comma; Stmt::StmtClass SC = DecodeOperatorCall(S, UnaryOp, BinaryOp); ID.AddInteger(SC); @@ -706,10 +706,6 @@ void StmtProfiler::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *S) { const_cast(S->getTemporary()->getDestructor())); } -void StmtProfiler::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *S) { - VisitExpr(S); -} - void StmtProfiler::VisitCXXConstructExpr(CXXConstructExpr *S) { VisitExpr(S); VisitDecl(S->getConstructor()); @@ -757,14 +753,19 @@ void StmtProfiler::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *S) { VisitType(S->getDestroyedType()); } -void -StmtProfiler::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *S) { +void StmtProfiler::VisitOverloadExpr(OverloadExpr *S) { VisitExpr(S); VisitNestedNameSpecifier(S->getQualifier()); VisitName(S->getName()); ID.AddBoolean(S->hasExplicitTemplateArgs()); if (S->hasExplicitTemplateArgs()) - VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); + VisitTemplateArguments(S->getExplicitTemplateArgs().getTemplateArgs(), + S->getExplicitTemplateArgs().NumTemplateArgs); +} + +void +StmtProfiler::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *S) { + VisitOverloadExpr(S); } void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) { diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index 02e6488..a3bf145 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -125,19 +125,22 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { switch (Argument.getKind()) { case TemplateArgument::Expression: return getSourceExpression()->getSourceRange(); - + case TemplateArgument::Declaration: return getSourceDeclExpression()->getSourceRange(); - + case TemplateArgument::Type: - return getTypeSourceInfo()->getTypeLoc().getSourceRange(); - + if (TypeSourceInfo *TSI = getTypeSourceInfo()) + return TSI->getTypeLoc().getSourceRange(); + else + return SourceRange(); + case TemplateArgument::Template: if (getTemplateQualifierRange().isValid()) return SourceRange(getTemplateQualifierRange().getBegin(), getTemplateNameLoc()); return SourceRange(getTemplateNameLoc()); - + case TemplateArgument::Integral: case TemplateArgument::Pack: case TemplateArgument::Null: @@ -152,7 +155,9 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, const TemplateArgument &Arg) { switch (Arg.getKind()) { case TemplateArgument::Null: - return DB; + // This is bad, but not as bad as crashing because of argument + // count mismatches. + return DB << "(null template argument)"; case TemplateArgument::Type: return DB << Arg.getAsType(); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index d7929304..ca10532 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/Type.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -21,6 +22,7 @@ #include "clang/Basic/Specifiers.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" +#include using namespace clang; bool QualType::isConstant(QualType T, ASTContext &Ctx) { @@ -33,24 +35,32 @@ bool QualType::isConstant(QualType T, ASTContext &Ctx) { return false; } -void Type::Destroy(ASTContext& C) { - this->~Type(); - C.Deallocate(this); -} +Type::~Type() { } + +unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context, + QualType ElementType, + const llvm::APInt &NumElements) { + llvm::APSInt SizeExtended(NumElements, true); + unsigned SizeTypeBits = Context.getTypeSize(Context.getSizeType()); + SizeExtended.extend(std::max(SizeTypeBits, SizeExtended.getBitWidth()) * 2); -void VariableArrayType::Destroy(ASTContext& C) { - if (SizeExpr) - SizeExpr->Destroy(C); - this->~VariableArrayType(); - C.Deallocate(this); + uint64_t ElementSize + = Context.getTypeSizeInChars(ElementType).getQuantity(); + llvm::APSInt TotalSize(llvm::APInt(SizeExtended.getBitWidth(), ElementSize)); + TotalSize *= SizeExtended; + + return TotalSize.getActiveBits(); } -void DependentSizedArrayType::Destroy(ASTContext& C) { - // FIXME: Resource contention like in ConstantArrayWithExprType ? - // May crash, depending on platform or a particular build. - // SizeExpr->Destroy(C); - this->~DependentSizedArrayType(); - C.Deallocate(this); +unsigned ConstantArrayType::getMaxSizeBits(ASTContext &Context) { + unsigned Bits = Context.getTypeSize(Context.getSizeType()); + + // GCC appears to only allow 63 bits worth of address space when compiling + // for 64-bit, so we do the same. + if (Bits == 64) + --Bits; + + return Bits; } void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID, @@ -73,14 +83,6 @@ DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID, SizeExpr->Profile(ID, Context, true); } -void DependentSizedExtVectorType::Destroy(ASTContext& C) { - // FIXME: Deallocate size expression, once we're cloning properly. -// if (SizeExpr) -// SizeExpr->Destroy(C); - this->~DependentSizedExtVectorType(); - C.Deallocate(this); -} - /// getArrayElementTypeNoTypeQual - If this is an array type, return the /// element type of the array, potentially with type qualifiers missing. /// This method should never be used when type qualifiers are meaningful. @@ -192,13 +194,6 @@ bool Type::isVoidType() const { return false; } -bool Type::isObjectType() const { - if (isa(CanonicalType) || isa(CanonicalType) || - isa(CanonicalType) || isVoidType()) - return false; - return true; -} - bool Type::isDerivedType() const { switch (CanonicalType->getTypeClass()) { case Pointer: @@ -348,11 +343,6 @@ const RecordType *Type::getAsUnionType() const { return 0; } -void ObjCInterfaceType::Destroy(ASTContext& C) { - this->~ObjCInterfaceType(); - C.Deallocate(this); -} - ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, ObjCProtocolDecl * const *Protocols, unsigned NumProtocols) @@ -366,11 +356,6 @@ ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, NumProtocols * sizeof(ObjCProtocolDecl*)); } -void ObjCObjectTypeImpl::Destroy(ASTContext& C) { - this->~ObjCObjectTypeImpl(); - C.Deallocate(this); -} - const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const { // There is no sugar for ObjCObjectType's, just return the canonical // type pointer if it is the right class. There is no typedef information to @@ -385,11 +370,6 @@ bool Type::isObjCQualifiedInterfaceType() const { return getAsObjCQualifiedInterfaceType() != 0; } -void ObjCObjectPointerType::Destroy(ASTContext& C) { - this->~ObjCObjectPointerType(); - C.Deallocate(this); -} - const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const { // There is no sugar for ObjCQualifiedIdType's, just return the canonical // type pointer if it is the right class. @@ -434,9 +414,14 @@ bool Type::isIntegerType() const { // FIXME: In C++, enum types are never integer types. if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition()) return true; + return false; +} + +bool Type::hasIntegerRepresentation() const { if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isIntegerType(); - return false; + else + return isIntegerType(); } /// \brief Determine whether this type is an integral type. @@ -475,10 +460,13 @@ bool Type::isIntegralOrEnumerationType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; - - if (isa(CanonicalType)) - return true; - + + // Check for a complete enum type; incomplete enum types are not properly an + // enumeration type in the sense required here. + if (const TagType *TT = dyn_cast(CanonicalType)) + if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition()) + return true; + return false; } @@ -523,8 +511,7 @@ bool Type::isAnyCharacterType() const { /// isSignedIntegerType - Return true if this is an integer type that is /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], -/// an enum decl which has a signed representation, or a vector of signed -/// integer element type. +/// an enum decl which has a signed representation bool Type::isSignedIntegerType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::Char_S && @@ -534,15 +521,19 @@ bool Type::isSignedIntegerType() const { if (const EnumType *ET = dyn_cast(CanonicalType)) return ET->getDecl()->getIntegerType()->isSignedIntegerType(); + return false; +} + +bool Type::hasSignedIntegerRepresentation() const { if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isSignedIntegerType(); - return false; + else + return isSignedIntegerType(); } /// isUnsignedIntegerType - Return true if this is an integer type that is /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum -/// decl which has an unsigned representation, or a vector of unsigned integer -/// element type. +/// decl which has an unsigned representation bool Type::isUnsignedIntegerType() const { if (const BuiltinType *BT = dyn_cast(CanonicalType)) { return BT->getKind() >= BuiltinType::Bool && @@ -552,9 +543,14 @@ bool Type::isUnsignedIntegerType() const { if (const EnumType *ET = dyn_cast(CanonicalType)) return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); + return false; +} + +bool Type::hasUnsignedIntegerRepresentation() const { if (const VectorType *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isUnsignedIntegerType(); - return false; + else + return isUnsignedIntegerType(); } bool Type::isFloatingType() const { @@ -671,10 +667,11 @@ bool Type::isIncompleteType() const { // An array of unknown size is an incomplete type (C99 6.2.5p22). return true; case ObjCObject: - return cast(this)->getBaseType()->isIncompleteType(); + return cast(CanonicalType)->getBaseType() + ->isIncompleteType(); case ObjCInterface: // ObjC interfaces are incomplete if they are @class, not @interface. - return cast(this)->getDecl()->isForwardDecl(); + return cast(CanonicalType)->getDecl()->isForwardDecl(); } } @@ -894,15 +891,6 @@ ElaboratedType::~ElaboratedType() {} DependentNameType::~DependentNameType() {} DependentTemplateSpecializationType::~DependentTemplateSpecializationType() {} -void DependentTemplateSpecializationType::Destroy(ASTContext &C) { - for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { - // FIXME: Not all expressions get cloned, so we can't yet perform - // this destruction. - // if (Expr *E = getArg(Arg).getAsExpr()) - // E->Destroy(C); - } -} - DependentTemplateSpecializationType::DependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, @@ -1017,6 +1005,7 @@ llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) { case CC_X86StdCall: return "stdcall"; case CC_X86FastCall: return "fastcall"; case CC_X86ThisCall: return "thiscall"; + case CC_X86Pascal: return "pascal"; } } @@ -1108,7 +1097,30 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) : Type(TC, can, D->isDependentType()), - decl(const_cast(D), 0) {} + decl(const_cast(D)) {} + +static TagDecl *getInterestingTagDecl(TagDecl *decl) { + for (TagDecl::redecl_iterator I = decl->redecls_begin(), + E = decl->redecls_end(); + I != E; ++I) { + if (I->isDefinition() || I->isBeingDefined()) + return *I; + } + // If there's no definition (not even in progress), return what we have. + return decl; +} + +TagDecl *TagType::getDecl() const { + return getInterestingTagDecl(decl); +} + +bool TagType::isBeingDefined() const { + return getDecl()->isBeingDefined(); +} + +CXXRecordDecl *InjectedClassNameType::getDecl() const { + return cast(getInterestingTagDecl(Decl)); +} bool RecordType::classof(const TagType *TT) { return isa(TT->getDecl()); @@ -1196,15 +1208,6 @@ TemplateSpecializationType(TemplateName T, new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]); } -void TemplateSpecializationType::Destroy(ASTContext& C) { - for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { - // FIXME: Not all expressions get cloned, so we can't yet perform - // this destruction. - // if (Expr *E = getArg(Arg).getAsExpr()) - // E->Destroy(C); - } -} - void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, TemplateName T, diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 4893b38..66578fb 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -74,20 +74,6 @@ TypeLoc TypeLoc::getNextTypeLocImpl(TypeLoc TL) { return NextLoc().Visit(TL); } -namespace { - struct TypeLocInitializer : public TypeLocVisitor { - SourceLocation Loc; - TypeLocInitializer(SourceLocation Loc) : Loc(Loc) {} - -#define ABSTRACT_TYPELOC(CLASS, PARENT) -#define TYPELOC(CLASS, PARENT) \ - void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ - TyLoc.initializeLocal(Loc); \ - } -#include "clang/AST/TypeLocNodes.def" - }; -} - /// \brief Initializes a type location, and all of its children /// recursively, as if the entire tree had been written in the /// given location. diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index a08ee1a..d3a6b64 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -299,6 +299,9 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T, case CC_X86ThisCall: S += " __attribute__((thiscall))"; break; + case CC_X86Pascal: + S += " __attribute__((pascal))"; + break; } if (Info.getNoReturn()) S += " __attribute__((noreturn))"; @@ -430,9 +433,10 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) { Buffer += ' '; } + // Compute the full nested-name-specifier for this type. + // In C, this will always be empty except when the type + // being printed is anonymous within other Record. if (!Policy.SuppressScope) - // Compute the full nested-name-specifier for this type. In C, - // this will always be empty. AppendScope(D->getDeclContext(), Buffer); if (const IdentifierInfo *II = D->getIdentifier()) @@ -463,7 +467,6 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) { } OS << '>'; - OS.flush(); } // If this is a class template specialization, print the template diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 06d8aec..bf9f967 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -18,6 +18,7 @@ #include "clang/AST/ParentMap.h" #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/Support/BumpVector.h" @@ -54,8 +55,11 @@ const ImplicitParamDecl *AnalysisContext::getSelfDecl() const { } CFG *AnalysisContext::getCFG() { + if (UseUnoptimizedCFG) + return getUnoptimizedCFG(); + if (!builtCFG) { - cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), AddEHEdges); + cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), true, AddEHEdges); // Even when the cfg is not successfully built, we don't // want to try building it again. builtCFG = true; @@ -63,12 +67,29 @@ CFG *AnalysisContext::getCFG() { return cfg; } +CFG *AnalysisContext::getUnoptimizedCFG() { + if (!builtCompleteCFG) { + completeCFG = CFG::buildCFG(D, getBody(), &D->getASTContext(), + false, AddEHEdges); + // Even when the cfg is not successfully built, we don't + // want to try building it again. + builtCompleteCFG = true; + } + return completeCFG; +} + ParentMap &AnalysisContext::getParentMap() { if (!PM) PM = new ParentMap(getBody()); return *PM; } +PseudoConstantAnalysis *AnalysisContext::getPseudoConstantAnalysis() { + if (!PCA) + PCA = new PseudoConstantAnalysis(getBody()); + return PCA; +} + LiveVariables *AnalysisContext::getLiveVariables() { if (!liveness) { CFG *c = getCFG(); @@ -83,10 +104,25 @@ LiveVariables *AnalysisContext::getLiveVariables() { return liveness; } -AnalysisContext *AnalysisContextManager::getContext(const Decl *D) { +LiveVariables *AnalysisContext::getRelaxedLiveVariables() { + if (!relaxedLiveness) { + CFG *c = getCFG(); + if (!c) + return 0; + + relaxedLiveness = new LiveVariables(*this, false); + relaxedLiveness->runOnCFG(*c); + relaxedLiveness->runOnAllBlocks(*c, 0, true); + } + + return relaxedLiveness; +} + +AnalysisContext *AnalysisContextManager::getContext(const Decl *D, + idx::TranslationUnit *TU) { AnalysisContext *&AC = Contexts[D]; if (!AC) - AC = new AnalysisContext(D); + AC = new AnalysisContext(D, TU, UseUnoptimizedCFG); return AC; } @@ -296,8 +332,11 @@ AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) { AnalysisContext::~AnalysisContext() { delete cfg; + delete completeCFG; delete liveness; + delete relaxedLiveness; delete PM; + delete PCA; delete ReferencedBlockVars; } diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 08543aa..c97b916 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -35,7 +35,7 @@ static SourceLocation GetEndLoc(Decl* D) { return D->getLocation(); } - + class AddStmtChoice { public: enum Kind { NotAlwaysAdd = 0, @@ -99,7 +99,8 @@ public: TryTerminatedBlock(NULL) {} // buildCFG - Used by external clients to construct the CFG. - CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, bool AddEHEdges, + CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, + bool pruneTriviallyFalseEdges, bool AddEHEdges, bool AddScopes); private: @@ -174,12 +175,12 @@ private: CFGBlock *addStmt(Stmt *S) { return Visit(S, AddStmtChoice::AlwaysAdd); } - + void AppendStmt(CFGBlock *B, Stmt *S, AddStmtChoice asc = AddStmtChoice::AlwaysAdd) { B->appendStmt(S, cfg->getBumpVectorContext(), asc.asLValue()); } - + void AddSuccessor(CFGBlock *B, CFGBlock *S) { B->addSuccessor(S, cfg->getBumpVectorContext()); } @@ -206,6 +207,9 @@ private: /// TryEvaluateBool - Try and evaluate the Stmt and return 0 or 1 /// if we can evaluate to a known value, otherwise return -1. TryResult TryEvaluateBool(Expr *S) { + if (!PruneTriviallyFalseEdges) + return TryResult(); + Expr::EvalResult Result; if (!S->isTypeDependent() && !S->isValueDependent() && S->Evaluate(Result, *Context) && Result.Val.isInt()) @@ -216,6 +220,9 @@ private: bool badCFG; + // True iff trivially false edges should be pruned from the CFG. + bool PruneTriviallyFalseEdges; + // True iff EH edges on CallExprs should be added to the CFG. bool AddEHEdges; @@ -243,8 +250,12 @@ static VariableArrayType* FindVA(Type* t) { /// transferred to the caller. If CFG construction fails, this method returns /// NULL. CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C, + bool pruneTriviallyFalseEdges, bool addehedges, bool AddScopes) { + AddEHEdges = addehedges; + PruneTriviallyFalseEdges = pruneTriviallyFalseEdges; + Context = C; assert(cfg.get()); if (!Statement) @@ -359,6 +370,7 @@ tryAgain: return VisitBreakStmt(cast(S)); case Stmt::CallExprClass: + case Stmt::CXXOperatorCallExprClass: return VisitCallExpr(cast(S), asc); case Stmt::CaseStmtClass: @@ -379,15 +391,21 @@ tryAgain: case Stmt::CXXCatchStmtClass: return VisitCXXCatchStmt(cast(S)); + case Stmt::CXXExprWithTemporariesClass: { + // FIXME: Handle temporaries. For now, just visit the subexpression + // so we don't artificially create extra blocks. + return Visit(cast(S)->getSubExpr(), asc); + } + case Stmt::CXXMemberCallExprClass: return VisitCXXMemberCallExpr(cast(S), asc); case Stmt::CXXThrowExprClass: return VisitCXXThrowExpr(cast(S)); - + case Stmt::CXXTryStmtClass: return VisitCXXTryStmt(cast(S)); - + case Stmt::DeclStmtClass: return VisitDeclStmt(cast(S)); @@ -515,15 +533,15 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, // See if this is a known constant. TryResult KnownVal = TryEvaluateBool(B->getLHS()); - if (KnownVal.isKnown() && (B->getOpcode() == BinaryOperator::LOr)) + if (KnownVal.isKnown() && (B->getOpcode() == BO_LOr)) KnownVal.negate(); // Now link the LHSBlock with RHSBlock. - if (B->getOpcode() == BinaryOperator::LOr) { + if (B->getOpcode() == BO_LOr) { AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); } else { - assert(B->getOpcode() == BinaryOperator::LAnd); + assert(B->getOpcode() == BO_LAnd); AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock); AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock); } @@ -532,7 +550,7 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, Block = LHSBlock; return addStmt(B->getLHS()); } - else if (B->getOpcode() == BinaryOperator::Comma) { // , + else if (B->getOpcode() == BO_Comma) { // , autoCreateBlock(); AppendStmt(Block, B, asc); addStmt(B->getRHS()); @@ -543,7 +561,7 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, autoCreateBlock(); AppendStmt(Block, B, asc); } - + Visit(B->getRHS()); return Visit(B->getLHS(), AddStmtChoice::AsLValueNotAlwaysAdd); } @@ -586,7 +604,7 @@ static bool CanThrow(Expr *E) { Ty = Ty->getAs()->getPointeeType(); else if (Ty->isBlockPointerType()) Ty = Ty->getAs()->getPointeeType(); - + const FunctionType *FT = Ty->getAs(); if (FT) { if (const FunctionProtoType *Proto = dyn_cast(FT)) @@ -691,7 +709,10 @@ CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) { for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend(); I != E; ++I ) { - LastBlock = addStmt(*I); + // If we hit a segment of code just containing ';' (NullStmts), we can + // get a null block back. In such cases, just use the LastBlock + if (CFGBlock *newBlock = addStmt(*I)) + LastBlock = newBlock; if (badCFG) return NULL; @@ -901,7 +922,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { // new blocks as the condition may contain control-flow. Any newly created // blocks will be pointed to be "Block". Block = addStmt(I->getCond()); - + // Finally, if the IfStmt contains a condition variable, add both the IfStmt // and the condition variable initialization to the CFG. if (VarDecl *VD = I->getConditionVariable()) { @@ -911,7 +932,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { addStmt(Init); } } - + return Block; } @@ -1029,7 +1050,7 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { assert(Block == EntryConditionBlock); } } - + if (Block) { if (!FinishBlock(EntryConditionBlock)) return 0; @@ -1277,7 +1298,7 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { Block = ExitConditionBlock; EntryConditionBlock = addStmt(C); assert(Block == EntryConditionBlock); - + // If this block contains a condition variable, add both the condition // variable and initializer to the CFG. if (VarDecl *VD = W->getConditionVariable()) { @@ -1389,7 +1410,7 @@ CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) { if (TryTerminatedBlock) // The current try statement is the only successor. AddSuccessor(Block, TryTerminatedBlock); - else + else // otherwise the Exit block is the only successor. AddSuccessor(Block, &cfg->getExit()); @@ -1465,18 +1486,22 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) { return 0; } - // Add an intermediate block between the BodyBlock and the - // ExitConditionBlock to represent the "loop back" transition. Create an - // empty block to represent the transition block for looping back to the - // head of the loop. - // FIXME: Can we do this more efficiently without adding another block? - Block = NULL; - Succ = BodyBlock; - CFGBlock *LoopBackBlock = createBlock(); - LoopBackBlock->setLoopTarget(D); - - // Add the loop body entry as a successor to the condition. - AddSuccessor(ExitConditionBlock, KnownVal.isFalse() ? NULL : LoopBackBlock); + if (!KnownVal.isFalse()) { + // Add an intermediate block between the BodyBlock and the + // ExitConditionBlock to represent the "loop back" transition. Create an + // empty block to represent the transition block for looping back to the + // head of the loop. + // FIXME: Can we do this more efficiently without adding another block? + Block = NULL; + Succ = BodyBlock; + CFGBlock *LoopBackBlock = createBlock(); + LoopBackBlock->setLoopTarget(D); + + // Add the loop body entry as a successor to the condition. + AddSuccessor(ExitConditionBlock, LoopBackBlock); + } + else + AddSuccessor(ExitConditionBlock, NULL); } // Link up the condition block with the code that follows the loop. @@ -1589,7 +1614,7 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { assert(Terminator->getCond() && "switch condition must be non-NULL"); Block = SwitchTerminatedBlock; Block = addStmt(Terminator->getCond()); - + // Finally, if the SwitchStmt contains a condition variable, add both the // SwitchStmt and the condition variable initialization to the CFG. if (VarDecl *VD = Terminator->getConditionVariable()) { @@ -1599,16 +1624,37 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { addStmt(Init); } } - + return Block; } CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) { // CaseStmts are essentially labels, so they are the first statement in a // block. + CFGBlock *TopBlock = 0, *LastBlock = 0; + + if (Stmt *Sub = CS->getSubStmt()) { + // For deeply nested chains of CaseStmts, instead of doing a recursion + // (which can blow out the stack), manually unroll and create blocks + // along the way. + while (isa(Sub)) { + CFGBlock *CurrentBlock = createBlock(false); + CurrentBlock->setLabel(CS); + + if (TopBlock) + AddSuccessor(LastBlock, CurrentBlock); + else + TopBlock = CurrentBlock; + + AddSuccessor(SwitchTerminatedBlock, CurrentBlock); + LastBlock = CurrentBlock; + + CS = cast(Sub); + Sub = CS->getSubStmt(); + } - if (CS->getSubStmt()) - addStmt(CS->getSubStmt()); + addStmt(Sub); + } CFGBlock* CaseBlock = Block; if (!CaseBlock) @@ -1629,10 +1675,16 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) { // We set Block to NULL to allow lazy creation of a new block (if necessary) Block = NULL; - // This block is now the implicit successor of other blocks. - Succ = CaseBlock; + if (TopBlock) { + AddSuccessor(LastBlock, CaseBlock); + Succ = TopBlock; + } + else { + // This block is now the implicit successor of other blocks. + Succ = CaseBlock; + } - return CaseBlock; + return Succ; } CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* Terminator) { @@ -1742,9 +1794,9 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) { return CatchBlock; } -CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C, +CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C, AddStmtChoice asc) { - AddStmtChoice::Kind K = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue + AddStmtChoice::Kind K = asc.asLValue() ? AddStmtChoice::AlwaysAddAsLValue : AddStmtChoice::AlwaysAdd; autoCreateBlock(); AppendStmt(Block, C, AddStmtChoice(K)); @@ -1795,9 +1847,11 @@ CFGBlock* CFG::createBlock() { /// buildCFG - Constructs a CFG from an AST. Ownership of the returned /// CFG is returned to the caller. CFG* CFG::buildCFG(const Decl *D, Stmt* Statement, ASTContext *C, + bool PruneTriviallyFalse, bool AddEHEdges, bool AddScopes) { CFGBuilder Builder; - return Builder.buildCFG(D, Statement, C, AddEHEdges, AddScopes); + return Builder.buildCFG(D, Statement, C, PruneTriviallyFalse, + AddEHEdges, AddScopes); } //===----------------------------------------------------------------------===// @@ -1814,10 +1868,10 @@ static void FindSubExprAssignments(Stmt *S, return; for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) { - Stmt *child = *I; + Stmt *child = *I; if (!child) continue; - + if (BinaryOperator* B = dyn_cast(child)) if (B->isAssignmentOp()) Set.insert(B); @@ -2037,10 +2091,10 @@ public: B->getLHS()->printPretty(OS, Helper, Policy); switch (B->getOpcode()) { - case BinaryOperator::LOr: + case BO_LOr: OS << " || ..."; return; - case BinaryOperator::LAnd: + case BO_LAnd: OS << " && ..."; return; default: @@ -2057,7 +2111,6 @@ public: static void print_stmt(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, const CFGElement &E) { - Stmt *Terminator = E; if (E.asStartScope()) { OS << "start scope\n"; @@ -2068,9 +2121,11 @@ static void print_stmt(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, return; } + Stmt *S = E; + if (Helper) { // special printing for statement-expressions. - if (StmtExpr* SE = dyn_cast(Terminator)) { + if (StmtExpr* SE = dyn_cast(S)) { CompoundStmt* Sub = SE->getSubStmt(); if (Sub->child_begin() != Sub->child_end()) { @@ -2082,8 +2137,8 @@ static void print_stmt(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, } // special printing for comma expressions. - if (BinaryOperator* B = dyn_cast(Terminator)) { - if (B->getOpcode() == BinaryOperator::Comma) { + if (BinaryOperator* B = dyn_cast(S)) { + if (B->getOpcode() == BO_Comma) { OS << "... , "; Helper->handledStmt(B->getRHS(),OS); OS << '\n'; @@ -2092,10 +2147,19 @@ static void print_stmt(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, } } - Terminator->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts())); + S->printPretty(OS, Helper, PrintingPolicy(Helper->getLangOpts())); + + if (isa(S)) { + OS << " (OperatorCall)"; + } + else if (isa(S)) { + OS << " (BindTemporary)"; + } + // Expressions need a newline. - if (isa(Terminator)) OS << '\n'; + if (isa(S)) + OS << '\n'; } static void print_block(llvm::raw_ostream& OS, const CFG* cfg, diff --git a/lib/Analysis/CFGStmtMap.cpp b/lib/Analysis/CFGStmtMap.cpp new file mode 100644 index 0000000..965eca1 --- /dev/null +++ b/lib/Analysis/CFGStmtMap.cpp @@ -0,0 +1,88 @@ +//===--- CFGStmtMap.h - Map from Stmt* to CFGBlock* -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CFGStmtMap class, which defines a mapping from +// Stmt* to CFGBlock* +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/DenseMap.h" +#include "clang/AST/ParentMap.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/CFGStmtMap.h" + +using namespace clang; + +typedef llvm::DenseMap SMap; +static SMap *AsMap(void *m) { return (SMap*) m; } + +CFGStmtMap::~CFGStmtMap() { delete AsMap(M); } + +CFGBlock *CFGStmtMap::getBlock(Stmt *S) { + SMap *SM = AsMap(M); + Stmt *X = S; + + // If 'S' isn't in the map, walk the ParentMap to see if one of its ancestors + // is in the map. + while (X) { + SMap::iterator I = SM->find(X); + if (I != SM->end()) { + CFGBlock *B = I->second; + // Memoize this lookup. + if (X != S) + (*SM)[X] = B; + return B; + } + + X = PM->getParentIgnoreParens(X); + } + + return 0; +} + +static void Accumulate(SMap &SM, CFGBlock *B) { + // First walk the block-level expressions. + for (CFGBlock::iterator I = B->begin(), E = B->end(); I != E; ++I) { + const CFGElement &CE = *I; + if (Stmt *S = CE.getStmt()) { + CFGBlock *&Entry = SM[S]; + // If 'Entry' is already initialized (e.g., a terminator was already), + // skip. + if (Entry) + continue; + + Entry = B; + } + } + + // Look at the label of the block. + if (Stmt *Label = B->getLabel()) + SM[Label] = B; + + // Finally, look at the terminator. If the terminator was already added + // because it is a block-level expression in another block, overwrite + // that mapping. + if (Stmt *Term = B->getTerminator()) + SM[Term] = B; +} + +CFGStmtMap *CFGStmtMap::Build(CFG *C, ParentMap *PM) { + if (!C || !PM) + return 0; + + SMap *SM = new SMap(); + + // Walk all blocks, accumulating the block-level expressions, labels, + // and terminators. + for (CFG::iterator I = C->begin(), E = C->end(); I != E; ++I) + Accumulate(*SM, *I); + + return new CFGStmtMap(PM, SM); +} + diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index f2916c2..850e9b4 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -3,9 +3,13 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangAnalysis AnalysisContext.cpp CFG.cpp + CFGStmtMap.cpp + FormatString.cpp LiveVariables.cpp PrintfFormatString.cpp + PseudoConstantAnalysis.cpp ReachableCode.cpp + ScanfFormatString.cpp UninitializedValues.cpp ) diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp new file mode 100644 index 0000000..388b9d3 --- /dev/null +++ b/lib/Analysis/FormatString.cpp @@ -0,0 +1,474 @@ +// FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Shared details for processing format strings of printf and scanf +// (and friends). +// +//===----------------------------------------------------------------------===// + +#include "FormatStringParsing.h" + +using clang::analyze_format_string::ArgTypeResult; +using clang::analyze_format_string::FormatStringHandler; +using clang::analyze_format_string::FormatSpecifier; +using clang::analyze_format_string::LengthModifier; +using clang::analyze_format_string::OptionalAmount; +using clang::analyze_format_string::PositionContext; +using clang::analyze_format_string::ConversionSpecifier; +using namespace clang; + +// Key function to FormatStringHandler. +FormatStringHandler::~FormatStringHandler() {} + +//===----------------------------------------------------------------------===// +// Functions for parsing format strings components in both printf and +// scanf format strings. +//===----------------------------------------------------------------------===// + +OptionalAmount +clang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) { + const char *I = Beg; + UpdateOnReturn UpdateBeg(Beg, I); + + unsigned accumulator = 0; + bool hasDigits = false; + + for ( ; I != E; ++I) { + char c = *I; + if (c >= '0' && c <= '9') { + hasDigits = true; + accumulator = (accumulator * 10) + (c - '0'); + continue; + } + + if (hasDigits) + return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg, + false); + + break; + } + + return OptionalAmount(); +} + +OptionalAmount +clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg, + const char *E, + unsigned &argIndex) { + if (*Beg == '*') { + ++Beg; + return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false); + } + + return ParseAmount(Beg, E); +} + +OptionalAmount +clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H, + const char *Start, + const char *&Beg, + const char *E, + PositionContext p) { + if (*Beg == '*') { + const char *I = Beg + 1; + const OptionalAmount &Amt = ParseAmount(I, E); + + if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) { + H.HandleInvalidPosition(Beg, I - Beg, p); + return OptionalAmount(false); + } + + if (I == E) { + // No more characters left? + H.HandleIncompleteSpecifier(Start, E - Start); + return OptionalAmount(false); + } + + assert(Amt.getHowSpecified() == OptionalAmount::Constant); + + if (*I == '$') { + // Handle positional arguments + + // Special case: '*0$', since this is an easy mistake. + if (Amt.getConstantAmount() == 0) { + H.HandleZeroPosition(Beg, I - Beg + 1); + return OptionalAmount(false); + } + + const char *Tmp = Beg; + Beg = ++I; + + return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1, + Tmp, 0, true); + } + + H.HandleInvalidPosition(Beg, I - Beg, p); + return OptionalAmount(false); + } + + return ParseAmount(Beg, E); +} + + +bool +clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H, + FormatSpecifier &CS, + const char *Start, + const char *&Beg, const char *E, + unsigned *argIndex) { + // FIXME: Support negative field widths. + if (argIndex) { + CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex)); + } + else { + const OptionalAmount Amt = + ParsePositionAmount(H, Start, Beg, E, + analyze_format_string::FieldWidthPos); + + if (Amt.isInvalid()) + return true; + CS.setFieldWidth(Amt); + } + return false; +} + +bool +clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H, + FormatSpecifier &FS, + const char *Start, + const char *&Beg, + const char *E) { + const char *I = Beg; + + const OptionalAmount &Amt = ParseAmount(I, E); + + if (I == E) { + // No more characters left? + H.HandleIncompleteSpecifier(Start, E - Start); + return true; + } + + if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') { + // Special case: '%0$', since this is an easy mistake. + if (Amt.getConstantAmount() == 0) { + H.HandleZeroPosition(Start, I - Start); + return true; + } + + FS.setArgIndex(Amt.getConstantAmount() - 1); + FS.setUsesPositionalArg(); + // Update the caller's pointer if we decided to consume + // these characters. + Beg = I; + return false; + } + + return false; +} + +bool +clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, + const char *&I, + const char *E) { + LengthModifier::Kind lmKind = LengthModifier::None; + const char *lmPosition = I; + switch (*I) { + default: + return false; + case 'h': + ++I; + lmKind = (I != E && *I == 'h') ? + ++I, LengthModifier::AsChar : LengthModifier::AsShort; + break; + case 'l': + ++I; + lmKind = (I != E && *I == 'l') ? + ++I, LengthModifier::AsLongLong : LengthModifier::AsLong; + break; + case 'j': lmKind = LengthModifier::AsIntMax; ++I; break; + case 'z': lmKind = LengthModifier::AsSizeT; ++I; break; + case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break; + case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break; + case 'q': lmKind = LengthModifier::AsLongLong; ++I; break; + } + LengthModifier lm(lmPosition, lmKind); + FS.setLengthModifier(lm); + return true; +} + +//===----------------------------------------------------------------------===// +// Methods on ArgTypeResult. +//===----------------------------------------------------------------------===// + +bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const { + switch (K) { + case InvalidTy: + assert(false && "ArgTypeResult must be valid"); + return true; + + case UnknownTy: + return true; + + case SpecificTy: { + argTy = C.getCanonicalType(argTy).getUnqualifiedType(); + if (T == argTy) + return true; + if (const BuiltinType *BT = argTy->getAs()) + switch (BT->getKind()) { + default: + break; + case BuiltinType::Char_S: + case BuiltinType::SChar: + return T == C.UnsignedCharTy; + case BuiltinType::Char_U: + case BuiltinType::UChar: + return T == C.SignedCharTy; + case BuiltinType::Short: + return T == C.UnsignedShortTy; + case BuiltinType::UShort: + return T == C.ShortTy; + case BuiltinType::Int: + return T == C.UnsignedIntTy; + case BuiltinType::UInt: + return T == C.IntTy; + case BuiltinType::Long: + return T == C.UnsignedLongTy; + case BuiltinType::ULong: + return T == C.LongTy; + case BuiltinType::LongLong: + return T == C.UnsignedLongLongTy; + case BuiltinType::ULongLong: + return T == C.LongLongTy; + } + return false; + } + + case CStrTy: { + const PointerType *PT = argTy->getAs(); + if (!PT) + return false; + QualType pointeeTy = PT->getPointeeType(); + if (const BuiltinType *BT = pointeeTy->getAs()) + switch (BT->getKind()) { + case BuiltinType::Void: + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::Char_S: + case BuiltinType::SChar: + return true; + default: + break; + } + + return false; + } + + case WCStrTy: { + const PointerType *PT = argTy->getAs(); + if (!PT) + return false; + QualType pointeeTy = + C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType(); + return pointeeTy == C.getWCharType(); + } + + case WIntTy: { + // Instead of doing a lookup for the definition of 'wint_t' (which + // is defined by the system headers) instead see if wchar_t and + // the argument type promote to the same type. + QualType PromoWChar = + C.getWCharType()->isPromotableIntegerType() + ? C.getPromotedIntegerType(C.getWCharType()) : C.getWCharType(); + QualType PromoArg = + argTy->isPromotableIntegerType() + ? C.getPromotedIntegerType(argTy) : argTy; + + PromoWChar = C.getCanonicalType(PromoWChar).getUnqualifiedType(); + PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType(); + + return PromoWChar == PromoArg; + } + + case CPointerTy: + return argTy->getAs() != NULL || + argTy->getAs() != NULL; + + case ObjCPointerTy: + return argTy->getAs() != NULL; + } + + // FIXME: Should be unreachable, but Clang is currently emitting + // a warning. + return false; +} + +QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const { + switch (K) { + case InvalidTy: + assert(false && "No representative type for Invalid ArgTypeResult"); + // Fall-through. + case UnknownTy: + return QualType(); + case SpecificTy: + return T; + case CStrTy: + return C.getPointerType(C.CharTy); + case WCStrTy: + return C.getPointerType(C.getWCharType()); + case ObjCPointerTy: + return C.ObjCBuiltinIdTy; + case CPointerTy: + return C.VoidPtrTy; + case WIntTy: { + QualType WC = C.getWCharType(); + return WC->isPromotableIntegerType() ? C.getPromotedIntegerType(WC) : WC; + } + } + + // FIXME: Should be unreachable, but Clang is currently emitting + // a warning. + return QualType(); +} + +//===----------------------------------------------------------------------===// +// Methods on OptionalAmount. +//===----------------------------------------------------------------------===// + +ArgTypeResult +analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const { + return Ctx.IntTy; +} + +//===----------------------------------------------------------------------===// +// Methods on LengthModifier. +//===----------------------------------------------------------------------===// + +const char * +analyze_format_string::LengthModifier::toString() const { + switch (kind) { + case AsChar: + return "hh"; + case AsShort: + return "h"; + case AsLong: // or AsWideChar + return "l"; + case AsLongLong: + return "ll"; + case AsIntMax: + return "j"; + case AsSizeT: + return "z"; + case AsPtrDiff: + return "t"; + case AsLongDouble: + return "L"; + case None: + return ""; + } + return NULL; +} + +//===----------------------------------------------------------------------===// +// Methods on OptionalAmount. +//===----------------------------------------------------------------------===// + +void OptionalAmount::toString(llvm::raw_ostream &os) const { + switch (hs) { + case Invalid: + case NotSpecified: + return; + case Arg: + if (UsesDotPrefix) + os << "."; + if (usesPositionalArg()) + os << "*" << getPositionalArgIndex() << "$"; + else + os << "*"; + break; + case Constant: + if (UsesDotPrefix) + os << "."; + os << amt; + break; + } +} + +//===----------------------------------------------------------------------===// +// Methods on ConversionSpecifier. +//===----------------------------------------------------------------------===// + +bool FormatSpecifier::hasValidLengthModifier() const { + switch (LM.getKind()) { + case LengthModifier::None: + return true; + + // Handle most integer flags + case LengthModifier::AsChar: + case LengthModifier::AsShort: + case LengthModifier::AsLongLong: + case LengthModifier::AsIntMax: + case LengthModifier::AsSizeT: + case LengthModifier::AsPtrDiff: + switch (CS.getKind()) { + case ConversionSpecifier::dArg: + case ConversionSpecifier::iArg: + case ConversionSpecifier::oArg: + case ConversionSpecifier::uArg: + case ConversionSpecifier::xArg: + case ConversionSpecifier::XArg: + case ConversionSpecifier::nArg: + return true; + default: + return false; + } + + // Handle 'l' flag + case LengthModifier::AsLong: + switch (CS.getKind()) { + case ConversionSpecifier::dArg: + case ConversionSpecifier::iArg: + case ConversionSpecifier::oArg: + case ConversionSpecifier::uArg: + case ConversionSpecifier::xArg: + case ConversionSpecifier::XArg: + case ConversionSpecifier::aArg: + case ConversionSpecifier::AArg: + case ConversionSpecifier::fArg: + case ConversionSpecifier::FArg: + case ConversionSpecifier::eArg: + case ConversionSpecifier::EArg: + case ConversionSpecifier::gArg: + case ConversionSpecifier::GArg: + case ConversionSpecifier::nArg: + case ConversionSpecifier::cArg: + case ConversionSpecifier::sArg: + return true; + default: + return false; + } + + case LengthModifier::AsLongDouble: + switch (CS.getKind()) { + case ConversionSpecifier::aArg: + case ConversionSpecifier::AArg: + case ConversionSpecifier::fArg: + case ConversionSpecifier::FArg: + case ConversionSpecifier::eArg: + case ConversionSpecifier::EArg: + case ConversionSpecifier::gArg: + case ConversionSpecifier::GArg: + return true; + default: + return false; + } + } + return false; +} + + diff --git a/lib/Analysis/FormatStringParsing.h b/lib/Analysis/FormatStringParsing.h new file mode 100644 index 0000000..607e99c --- /dev/null +++ b/lib/Analysis/FormatStringParsing.h @@ -0,0 +1,72 @@ +#ifndef LLVM_CLANG_FORMAT_PARSING_H +#define LLVM_CLANG_FORMAT_PARSING_H + +#include "clang/Analysis/Analyses/FormatString.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + +template +class UpdateOnReturn { + T &ValueToUpdate; + const T &ValueToCopy; +public: + UpdateOnReturn(T &valueToUpdate, const T &valueToCopy) + : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {} + + ~UpdateOnReturn() { + ValueToUpdate = ValueToCopy; + } +}; + +namespace analyze_format_string { + +OptionalAmount ParseAmount(const char *&Beg, const char *E); +OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E, + unsigned &argIndex); + +OptionalAmount ParsePositionAmount(FormatStringHandler &H, + const char *Start, const char *&Beg, + const char *E, PositionContext p); + +bool ParseFieldWidth(FormatStringHandler &H, + FormatSpecifier &CS, + const char *Start, const char *&Beg, const char *E, + unsigned *argIndex); + +bool ParseArgPosition(FormatStringHandler &H, + FormatSpecifier &CS, const char *Start, + const char *&Beg, const char *E); + +/// Returns true if a LengthModifier was parsed and installed in the +/// FormatSpecifier& argument, and false otherwise. +bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E); + +template class SpecifierResult { + T FS; + const char *Start; + bool Stop; +public: + SpecifierResult(bool stop = false) + : Start(0), Stop(stop) {} + SpecifierResult(const char *start, + const T &fs) + : FS(fs), Start(start), Stop(false) {} + + const char *getStart() const { return Start; } + bool shouldStop() const { return Stop; } + bool hasValue() const { return Start != 0; } + const T &getValue() const { + assert(hasValue()); + return FS; + } + const T &getValue() { return FS; } +}; + +} // end analyze_format_string namespace +} // end clang namespace + +#endif + diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index 4efe25e..47b2e3d 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -77,12 +77,13 @@ public: }; } // end anonymous namespace -LiveVariables::LiveVariables(AnalysisContext &AC) { +LiveVariables::LiveVariables(AnalysisContext &AC, bool killAtAssign) { // Register all referenced VarDecls. CFG &cfg = *AC.getCFG(); getAnalysisData().setCFG(cfg); getAnalysisData().setContext(AC.getASTContext()); getAnalysisData().AC = &AC; + getAnalysisData().killAtAssign = killAtAssign; RegisterDecls R(getAnalysisData()); cfg.VisitBlockStmts(R); @@ -229,10 +230,10 @@ void TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { Expr *E = U->getSubExpr(); switch (U->getOpcode()) { - case UnaryOperator::PostInc: - case UnaryOperator::PostDec: - case UnaryOperator::PreInc: - case UnaryOperator::PreDec: + case UO_PostInc: + case UO_PostDec: + case UO_PreInc: + case UO_PreDec: // Walk through the subexpressions, blasting through ParenExprs // until we either find a DeclRefExpr or some non-DeclRefExpr // expression. @@ -260,15 +261,16 @@ void TransferFuncs::VisitAssign(BinaryOperator* B) { if (DR->getDecl()->getType()->isReferenceType()) { VisitDeclRefExpr(DR); } else { - // Update liveness inforamtion. - unsigned bit = AD.getIdx(DR->getDecl()); - LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit); - - if (AD.Observer) { AD.Observer->ObserverKill(DR); } + if (AD.killAtAssign) { + // Update liveness inforamtion. + unsigned bit = AD.getIdx(DR->getDecl()); + LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit); + if (AD.Observer) { AD.Observer->ObserverKill(DR); } + } // Handle things like +=, etc., which also generate "uses" // of a variable. Do this just by visiting the subexpression. - if (B->getOpcode() != BinaryOperator::Assign) + if (B->getOpcode() != BO_Assign) VisitDeclRefExpr(DR); } } diff --git a/lib/Analysis/Makefile b/lib/Analysis/Makefile index 03bf7a6..fbbb83d 100644 --- a/lib/Analysis/Makefile +++ b/lib/Analysis/Makefile @@ -13,7 +13,6 @@ CLANG_LEVEL := ../.. LIBRARYNAME := clangAnalysis -BUILD_ARCHIVE = 1 include $(CLANG_LEVEL)/Makefile diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index 558d38a..b8c327c 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -1,4 +1,4 @@ -//= PrintfFormatStrings.cpp - Analysis of printf format strings --*- C++ -*-==// +//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -12,141 +12,28 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/Analyses/PrintfFormatString.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Type.h" -#include "llvm/Support/raw_ostream.h" +#include "clang/Analysis/Analyses/FormatString.h" +#include "FormatStringParsing.h" -using clang::analyze_printf::ArgTypeResult; -using clang::analyze_printf::FormatSpecifier; -using clang::analyze_printf::FormatStringHandler; -using clang::analyze_printf::OptionalAmount; -using clang::analyze_printf::PositionContext; -using clang::analyze_printf::ConversionSpecifier; -using clang::analyze_printf::LengthModifier; +using clang::analyze_format_string::ArgTypeResult; +using clang::analyze_format_string::FormatStringHandler; +using clang::analyze_format_string::LengthModifier; +using clang::analyze_format_string::OptionalAmount; +using clang::analyze_format_string::ConversionSpecifier; +using clang::analyze_printf::PrintfSpecifier; using namespace clang; -namespace { -class FormatSpecifierResult { - FormatSpecifier FS; - const char *Start; - bool Stop; -public: - FormatSpecifierResult(bool stop = false) - : Start(0), Stop(stop) {} - FormatSpecifierResult(const char *start, - const FormatSpecifier &fs) - : FS(fs), Start(start), Stop(false) {} - - const char *getStart() const { return Start; } - bool shouldStop() const { return Stop; } - bool hasValue() const { return Start != 0; } - const FormatSpecifier &getValue() const { - assert(hasValue()); - return FS; - } - const FormatSpecifier &getValue() { return FS; } -}; -} // end anonymous namespace - -template -class UpdateOnReturn { - T &ValueToUpdate; - const T &ValueToCopy; -public: - UpdateOnReturn(T &valueToUpdate, const T &valueToCopy) - : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {} - - ~UpdateOnReturn() { - ValueToUpdate = ValueToCopy; - } -}; +typedef clang::analyze_format_string::SpecifierResult + PrintfSpecifierResult; //===----------------------------------------------------------------------===// // Methods for parsing format strings. //===----------------------------------------------------------------------===// -static OptionalAmount ParseAmount(const char *&Beg, const char *E) { - const char *I = Beg; - UpdateOnReturn UpdateBeg(Beg, I); - - unsigned accumulator = 0; - bool hasDigits = false; - - for ( ; I != E; ++I) { - char c = *I; - if (c >= '0' && c <= '9') { - hasDigits = true; - accumulator = (accumulator * 10) + (c - '0'); - continue; - } - - if (hasDigits) - return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg, - false); - - break; - } - - return OptionalAmount(); -} - -static OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E, - unsigned &argIndex) { - if (*Beg == '*') { - ++Beg; - return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false); - } - - return ParseAmount(Beg, E); -} - -static OptionalAmount ParsePositionAmount(FormatStringHandler &H, - const char *Start, - const char *&Beg, const char *E, - PositionContext p) { - if (*Beg == '*') { - const char *I = Beg + 1; - const OptionalAmount &Amt = ParseAmount(I, E); - - if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) { - H.HandleInvalidPosition(Beg, I - Beg, p); - return OptionalAmount(false); - } - - if (I== E) { - // No more characters left? - H.HandleIncompleteFormatSpecifier(Start, E - Start); - return OptionalAmount(false); - } - - assert(Amt.getHowSpecified() == OptionalAmount::Constant); - - if (*I == '$') { - // Handle positional arguments - - // Special case: '*0$', since this is an easy mistake. - if (Amt.getConstantAmount() == 0) { - H.HandleZeroPosition(Beg, I - Beg + 1); - return OptionalAmount(false); - } - - const char *Tmp = Beg; - Beg = ++I; - - return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1, - Tmp, 0, true); - } - - H.HandleInvalidPosition(Beg, I - Beg, p); - return OptionalAmount(false); - } - - return ParseAmount(Beg, E); -} +using analyze_format_string::ParseNonPositionAmount; -static bool ParsePrecision(FormatStringHandler &H, FormatSpecifier &FS, +static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS, const char *Start, const char *&Beg, const char *E, unsigned *argIndex) { if (argIndex) { @@ -154,7 +41,7 @@ static bool ParsePrecision(FormatStringHandler &H, FormatSpecifier &FS, } else { const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, - analyze_printf::PrecisionPos); + analyze_format_string::PrecisionPos); if (Amt.isInvalid()) return true; FS.setPrecision(Amt); @@ -162,61 +49,12 @@ static bool ParsePrecision(FormatStringHandler &H, FormatSpecifier &FS, return false; } -static bool ParseFieldWidth(FormatStringHandler &H, FormatSpecifier &FS, - const char *Start, const char *&Beg, const char *E, - unsigned *argIndex) { - // FIXME: Support negative field widths. - if (argIndex) { - FS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex)); - } - else { - const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E, - analyze_printf::FieldWidthPos); - if (Amt.isInvalid()) - return true; - FS.setFieldWidth(Amt); - } - return false; -} - -static bool ParseArgPosition(FormatStringHandler &H, - FormatSpecifier &FS, const char *Start, - const char *&Beg, const char *E) { - - using namespace clang::analyze_printf; - const char *I = Beg; - - const OptionalAmount &Amt = ParseAmount(I, E); - - if (I == E) { - // No more characters left? - H.HandleIncompleteFormatSpecifier(Start, E - Start); - return true; - } - - if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') { - // Special case: '%0$', since this is an easy mistake. - if (Amt.getConstantAmount() == 0) { - H.HandleZeroPosition(Start, I - Start); - return true; - } - - FS.setArgIndex(Amt.getConstantAmount() - 1); - FS.setUsesPositionalArg(); - // Update the caller's pointer if we decided to consume - // these characters. - Beg = I; - return false; - } - - return false; -} - -static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, +static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, unsigned &argIndex) { + using namespace clang::analyze_format_string; using namespace clang::analyze_printf; const char *I = Beg; @@ -243,17 +81,17 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, if (I == E) { // No more characters left? - H.HandleIncompleteFormatSpecifier(Start, E - Start); + H.HandleIncompleteSpecifier(Start, E - Start); return true; } - FormatSpecifier FS; + PrintfSpecifier FS; if (ParseArgPosition(H, FS, Start, I, E)) return true; if (I == E) { // No more characters left? - H.HandleIncompleteFormatSpecifier(Start, E - Start); + H.HandleIncompleteSpecifier(Start, E - Start); return true; } @@ -274,7 +112,7 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, if (I == E) { // No more characters left? - H.HandleIncompleteFormatSpecifier(Start, E - Start); + H.HandleIncompleteSpecifier(Start, E - Start); return true; } @@ -285,7 +123,7 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, if (I == E) { // No more characters left? - H.HandleIncompleteFormatSpecifier(Start, E - Start); + H.HandleIncompleteSpecifier(Start, E - Start); return true; } @@ -293,7 +131,7 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, if (*I == '.') { ++I; if (I == E) { - H.HandleIncompleteFormatSpecifier(Start, E - Start); + H.HandleIncompleteSpecifier(Start, E - Start); return true; } @@ -303,39 +141,15 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, if (I == E) { // No more characters left? - H.HandleIncompleteFormatSpecifier(Start, E - Start); + H.HandleIncompleteSpecifier(Start, E - Start); return true; } } // Look for the length modifier. - LengthModifier::Kind lmKind = LengthModifier::None; - const char *lmPosition = I; - switch (*I) { - default: - break; - case 'h': - ++I; - lmKind = (I != E && *I == 'h') ? - ++I, LengthModifier::AsChar : LengthModifier::AsShort; - break; - case 'l': - ++I; - lmKind = (I != E && *I == 'l') ? - ++I, LengthModifier::AsLongLong : LengthModifier::AsLong; - break; - case 'j': lmKind = LengthModifier::AsIntMax; ++I; break; - case 'z': lmKind = LengthModifier::AsSizeT; ++I; break; - case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break; - case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break; - case 'q': lmKind = LengthModifier::AsLongLong; ++I; break; - } - LengthModifier lm(lmPosition, lmKind); - FS.setLengthModifier(lm); - - if (I == E) { + if (ParseLengthModifier(FS, I, E) && I == E) { // No more characters left? - H.HandleIncompleteFormatSpecifier(Start, E - Start); + H.HandleIncompleteSpecifier(Start, E - Start); return true; } @@ -359,46 +173,47 @@ static FormatSpecifierResult ParseFormatSpecifier(FormatStringHandler &H, case 'G': k = ConversionSpecifier::GArg; break; case 'X': k = ConversionSpecifier::XArg; break; case 'a': k = ConversionSpecifier::aArg; break; - case 'c': k = ConversionSpecifier::IntAsCharArg; break; + case 'c': k = ConversionSpecifier::cArg; break; case 'd': k = ConversionSpecifier::dArg; break; case 'e': k = ConversionSpecifier::eArg; break; case 'f': k = ConversionSpecifier::fArg; break; case 'g': k = ConversionSpecifier::gArg; break; case 'i': k = ConversionSpecifier::iArg; break; - case 'n': k = ConversionSpecifier::OutIntPtrArg; break; + case 'n': k = ConversionSpecifier::nArg; break; case 'o': k = ConversionSpecifier::oArg; break; - case 'p': k = ConversionSpecifier::VoidPtrArg; break; - case 's': k = ConversionSpecifier::CStrArg; break; + case 'p': k = ConversionSpecifier::pArg; break; + case 's': k = ConversionSpecifier::sArg; break; case 'u': k = ConversionSpecifier::uArg; break; case 'x': k = ConversionSpecifier::xArg; break; // Mac OS X (unicode) specific case 'C': k = ConversionSpecifier::CArg; break; - case 'S': k = ConversionSpecifier::UnicodeStrArg; break; + case 'S': k = ConversionSpecifier::SArg; break; // Objective-C. case '@': k = ConversionSpecifier::ObjCObjArg; break; // Glibc specific. case 'm': k = ConversionSpecifier::PrintErrno; break; } - ConversionSpecifier CS(conversionPosition, k); + PrintfConversionSpecifier CS(conversionPosition, k); FS.setConversionSpecifier(CS); if (CS.consumesDataArgument() && !FS.usesPositionalArg()) FS.setArgIndex(argIndex++); if (k == ConversionSpecifier::InvalidSpecifier) { // Assume the conversion takes one argument. - return !H.HandleInvalidConversionSpecifier(FS, Beg, I - Beg); + return !H.HandleInvalidPrintfConversionSpecifier(FS, Beg, I - Beg); } - return FormatSpecifierResult(Start, FS); + return PrintfSpecifierResult(Start, FS); } -bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H, - const char *I, const char *E) { +bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, + const char *I, + const char *E) { unsigned argIndex = 0; // Keep looking for a format specifier until we have exhausted the string. while (I != E) { - const FormatSpecifierResult &FSR = ParseFormatSpecifier(H, I, E, argIndex); + const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex); // Did a fail-stop error of any kind occur when parsing the specifier? // If so, don't do any more processing. if (FSR.shouldStop()) @@ -408,7 +223,7 @@ bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H, if (!FSR.hasValue()) continue; // We have a format specifier. Pass it to the callback. - if (!H.HandleFormatSpecifier(FSR.getValue(), FSR.getStart(), + if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(), I - FSR.getStart())) return true; } @@ -416,129 +231,6 @@ bool clang::analyze_printf::ParseFormatString(FormatStringHandler &H, return false; } -FormatStringHandler::~FormatStringHandler() {} - -//===----------------------------------------------------------------------===// -// Methods on ArgTypeResult. -//===----------------------------------------------------------------------===// - -bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const { - switch (K) { - case InvalidTy: - assert(false && "ArgTypeResult must be valid"); - return true; - - case UnknownTy: - return true; - - case SpecificTy: { - argTy = C.getCanonicalType(argTy).getUnqualifiedType(); - if (T == argTy) - return true; - if (const BuiltinType *BT = argTy->getAs()) - switch (BT->getKind()) { - default: - break; - case BuiltinType::Char_S: - case BuiltinType::SChar: - return T == C.UnsignedCharTy; - case BuiltinType::Char_U: - case BuiltinType::UChar: - return T == C.SignedCharTy; - case BuiltinType::Short: - return T == C.UnsignedShortTy; - case BuiltinType::UShort: - return T == C.ShortTy; - case BuiltinType::Int: - return T == C.UnsignedIntTy; - case BuiltinType::UInt: - return T == C.IntTy; - case BuiltinType::Long: - return T == C.UnsignedLongTy; - case BuiltinType::ULong: - return T == C.LongTy; - case BuiltinType::LongLong: - return T == C.UnsignedLongLongTy; - case BuiltinType::ULongLong: - return T == C.LongLongTy; - } - return false; - } - - case CStrTy: { - const PointerType *PT = argTy->getAs(); - if (!PT) - return false; - QualType pointeeTy = PT->getPointeeType(); - if (const BuiltinType *BT = pointeeTy->getAs()) - switch (BT->getKind()) { - case BuiltinType::Void: - case BuiltinType::Char_U: - case BuiltinType::UChar: - case BuiltinType::Char_S: - case BuiltinType::SChar: - return true; - default: - break; - } - - return false; - } - - case WCStrTy: { - const PointerType *PT = argTy->getAs(); - if (!PT) - return false; - QualType pointeeTy = - C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType(); - return pointeeTy == C.getWCharType(); - } - - case CPointerTy: - return argTy->getAs() != NULL || - argTy->getAs() != NULL; - - case ObjCPointerTy: - return argTy->getAs() != NULL; - } - - // FIXME: Should be unreachable, but Clang is currently emitting - // a warning. - return false; -} - -QualType ArgTypeResult::getRepresentativeType(ASTContext &C) const { - switch (K) { - case InvalidTy: - assert(false && "No representative type for Invalid ArgTypeResult"); - // Fall-through. - case UnknownTy: - return QualType(); - case SpecificTy: - return T; - case CStrTy: - return C.getPointerType(C.CharTy); - case WCStrTy: - return C.getPointerType(C.getWCharType()); - case ObjCPointerTy: - return C.ObjCBuiltinIdTy; - case CPointerTy: - return C.VoidPtrTy; - } - - // FIXME: Should be unreachable, but Clang is currently emitting - // a warning. - return QualType(); -} - -//===----------------------------------------------------------------------===// -// Methods on OptionalAmount. -//===----------------------------------------------------------------------===// - -ArgTypeResult OptionalAmount::getArgType(ASTContext &Ctx) const { - return Ctx.IntTy; -} - //===----------------------------------------------------------------------===// // Methods on ConversionSpecifier. //===----------------------------------------------------------------------===// @@ -558,16 +250,17 @@ const char *ConversionSpecifier::toString() const { case GArg: return "G"; case aArg: return "a"; case AArg: return "A"; - case IntAsCharArg: return "c"; - case CStrArg: return "s"; - case VoidPtrArg: return "p"; - case OutIntPtrArg: return "n"; - case PercentArg: return "%"; + case cArg: return "c"; + case sArg: return "s"; + case pArg: return "p"; + case nArg: return "n"; + case PercentArg: return "%"; + case ScanListArg: return "["; case InvalidSpecifier: return NULL; // MacOS X unicode extensions. - case CArg: return "C"; - case UnicodeStrArg: return "S"; + case CArg: return "C"; + case SArg: return "S"; // Objective-C specific specifiers. case ObjCObjArg: return "@"; @@ -579,66 +272,23 @@ const char *ConversionSpecifier::toString() const { } //===----------------------------------------------------------------------===// -// Methods on LengthModifier. -//===----------------------------------------------------------------------===// - -const char *LengthModifier::toString() const { - switch (kind) { - case AsChar: - return "hh"; - case AsShort: - return "h"; - case AsLong: // or AsWideChar - return "l"; - case AsLongLong: - return "ll"; - case AsIntMax: - return "j"; - case AsSizeT: - return "z"; - case AsPtrDiff: - return "t"; - case AsLongDouble: - return "L"; - case None: - return ""; - } - return NULL; -} - -//===----------------------------------------------------------------------===// -// Methods on OptionalAmount. +// Methods on PrintfSpecifier. //===----------------------------------------------------------------------===// -void OptionalAmount::toString(llvm::raw_ostream &os) const { - switch (hs) { - case Invalid: - case NotSpecified: - return; - case Arg: - if (UsesDotPrefix) - os << "."; - if (usesPositionalArg()) - os << "*" << getPositionalArgIndex() << "$"; - else - os << "*"; - break; - case Constant: - if (UsesDotPrefix) - os << "."; - os << amt; - break; - } -} - -//===----------------------------------------------------------------------===// -// Methods on FormatSpecifier. -//===----------------------------------------------------------------------===// - -ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const { +ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const { + const PrintfConversionSpecifier &CS = getConversionSpecifier(); + if (!CS.consumesDataArgument()) return ArgTypeResult::Invalid(); + if (CS.getKind() == ConversionSpecifier::cArg) + switch (LM.getKind()) { + case LengthModifier::None: return Ctx.IntTy; + case LengthModifier::AsLong: return ArgTypeResult::WIntTy; + default: + return ArgTypeResult::Invalid(); + } + if (CS.isIntArg()) switch (LM.getKind()) { case LengthModifier::AsLongDouble: @@ -684,15 +334,15 @@ ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const { } switch (CS.getKind()) { - case ConversionSpecifier::CStrArg: + case ConversionSpecifier::sArg: return ArgTypeResult(LM.getKind() == LengthModifier::AsWideChar ? ArgTypeResult::WCStrTy : ArgTypeResult::CStrTy); - case ConversionSpecifier::UnicodeStrArg: + case ConversionSpecifier::SArg: // FIXME: This appears to be Mac OS X specific. return ArgTypeResult::WCStrTy; case ConversionSpecifier::CArg: return Ctx.WCharTy; - case ConversionSpecifier::VoidPtrArg: + case ConversionSpecifier::pArg: return ArgTypeResult::CPointerTy; default: break; @@ -702,10 +352,10 @@ ArgTypeResult FormatSpecifier::getArgType(ASTContext &Ctx) const { return ArgTypeResult(); } -bool FormatSpecifier::fixType(QualType QT) { +bool PrintfSpecifier::fixType(QualType QT) { // Handle strings first (char *, wchar_t *) if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { - CS.setKind(ConversionSpecifier::CStrArg); + CS.setKind(ConversionSpecifier::sArg); // Disable irrelevant flags HasAlternativeForm = 0; @@ -750,7 +400,7 @@ bool FormatSpecifier::fixType(QualType QT) { // Set conversion specifier and disable any flags which do not apply to it. if (QT->isAnyCharacterType()) { - CS.setKind(ConversionSpecifier::IntAsCharArg); + CS.setKind(ConversionSpecifier::cArg); Precision.setHowSpecified(OptionalAmount::NotSpecified); HasAlternativeForm = 0; HasLeadingZeroes = 0; @@ -761,7 +411,7 @@ bool FormatSpecifier::fixType(QualType QT) { CS.setKind(ConversionSpecifier::fArg); } else if (QT->isPointerType()) { - CS.setKind(ConversionSpecifier::VoidPtrArg); + CS.setKind(ConversionSpecifier::pArg); Precision.setHowSpecified(OptionalAmount::NotSpecified); HasAlternativeForm = 0; HasLeadingZeroes = 0; @@ -783,9 +433,9 @@ bool FormatSpecifier::fixType(QualType QT) { return true; } -void FormatSpecifier::toString(llvm::raw_ostream &os) const { +void PrintfSpecifier::toString(llvm::raw_ostream &os) const { // Whilst some features have no defined order, we are using the order - // appearing in the C99 standard (ISO/IEC 9899:1999 (E) ¤7.19.6.1) + // appearing in the C99 standard (ISO/IEC 9899:1999 (E) ¤7.19.6.1) os << "%"; // Positional args @@ -810,7 +460,7 @@ void FormatSpecifier::toString(llvm::raw_ostream &os) const { os << CS.toString(); } -bool FormatSpecifier::hasValidPlusPrefix() const { +bool PrintfSpecifier::hasValidPlusPrefix() const { if (!HasPlusPrefix) return true; @@ -833,7 +483,7 @@ bool FormatSpecifier::hasValidPlusPrefix() const { } } -bool FormatSpecifier::hasValidAlternativeForm() const { +bool PrintfSpecifier::hasValidAlternativeForm() const { if (!HasAlternativeForm) return true; @@ -856,7 +506,7 @@ bool FormatSpecifier::hasValidAlternativeForm() const { } } -bool FormatSpecifier::hasValidLeadingZeros() const { +bool PrintfSpecifier::hasValidLeadingZeros() const { if (!HasLeadingZeroes) return true; @@ -883,7 +533,7 @@ bool FormatSpecifier::hasValidLeadingZeros() const { } } -bool FormatSpecifier::hasValidSpacePrefix() const { +bool PrintfSpecifier::hasValidSpacePrefix() const { if (!HasSpacePrefix) return true; @@ -906,13 +556,13 @@ bool FormatSpecifier::hasValidSpacePrefix() const { } } -bool FormatSpecifier::hasValidLeftJustified() const { +bool PrintfSpecifier::hasValidLeftJustified() const { if (!IsLeftJustified) return true; // The left justified flag is valid for all conversions except n switch (CS.getKind()) { - case ConversionSpecifier::OutIntPtrArg: + case ConversionSpecifier::nArg: return false; default: @@ -920,75 +570,7 @@ bool FormatSpecifier::hasValidLeftJustified() const { } } -bool FormatSpecifier::hasValidLengthModifier() const { - switch (LM.getKind()) { - case LengthModifier::None: - return true; - - // Handle most integer flags - case LengthModifier::AsChar: - case LengthModifier::AsShort: - case LengthModifier::AsLongLong: - case LengthModifier::AsIntMax: - case LengthModifier::AsSizeT: - case LengthModifier::AsPtrDiff: - switch (CS.getKind()) { - case ConversionSpecifier::dArg: - case ConversionSpecifier::iArg: - case ConversionSpecifier::oArg: - case ConversionSpecifier::uArg: - case ConversionSpecifier::xArg: - case ConversionSpecifier::XArg: - case ConversionSpecifier::OutIntPtrArg: - return true; - default: - return false; - } - - // Handle 'l' flag - case LengthModifier::AsLong: - switch (CS.getKind()) { - case ConversionSpecifier::dArg: - case ConversionSpecifier::iArg: - case ConversionSpecifier::oArg: - case ConversionSpecifier::uArg: - case ConversionSpecifier::xArg: - case ConversionSpecifier::XArg: - case ConversionSpecifier::aArg: - case ConversionSpecifier::AArg: - case ConversionSpecifier::fArg: - case ConversionSpecifier::FArg: - case ConversionSpecifier::eArg: - case ConversionSpecifier::EArg: - case ConversionSpecifier::gArg: - case ConversionSpecifier::GArg: - case ConversionSpecifier::OutIntPtrArg: - case ConversionSpecifier::IntAsCharArg: - case ConversionSpecifier::CStrArg: - return true; - default: - return false; - } - - case LengthModifier::AsLongDouble: - switch (CS.getKind()) { - case ConversionSpecifier::aArg: - case ConversionSpecifier::AArg: - case ConversionSpecifier::fArg: - case ConversionSpecifier::FArg: - case ConversionSpecifier::eArg: - case ConversionSpecifier::EArg: - case ConversionSpecifier::gArg: - case ConversionSpecifier::GArg: - return true; - default: - return false; - } - } - return false; -} - -bool FormatSpecifier::hasValidPrecision() const { +bool PrintfSpecifier::hasValidPrecision() const { if (Precision.getHowSpecified() == OptionalAmount::NotSpecified) return true; @@ -1008,20 +590,20 @@ bool FormatSpecifier::hasValidPrecision() const { case ConversionSpecifier::FArg: case ConversionSpecifier::gArg: case ConversionSpecifier::GArg: - case ConversionSpecifier::CStrArg: + case ConversionSpecifier::sArg: return true; default: return false; } } -bool FormatSpecifier::hasValidFieldWidth() const { +bool PrintfSpecifier::hasValidFieldWidth() const { if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified) return true; // The field width is valid for all conversions except n switch (CS.getKind()) { - case ConversionSpecifier::OutIntPtrArg: + case ConversionSpecifier::nArg: return false; default: diff --git a/lib/Analysis/PseudoConstantAnalysis.cpp b/lib/Analysis/PseudoConstantAnalysis.cpp new file mode 100644 index 0000000..ff43fc2 --- /dev/null +++ b/lib/Analysis/PseudoConstantAnalysis.cpp @@ -0,0 +1,238 @@ +//== PseudoConstantAnalysis.cpp - Find Pseudoconstants in the AST-*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file tracks the usage of variables in a Decl body to see if they are +// never written to, implying that they constant. This is useful in static +// analysis to see if a developer might have intended a variable to be const. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Stmt.h" +#include + +using namespace clang; + +// The number of ValueDecls we want to keep track of by default (per-function) +#define VARDECL_SET_SIZE 256 +typedef llvm::SmallPtrSet VarDeclSet; + +PseudoConstantAnalysis::PseudoConstantAnalysis(const Stmt *DeclBody) : + DeclBody(DeclBody), Analyzed(false) { + NonConstantsImpl = new VarDeclSet; + UsedVarsImpl = new VarDeclSet; +} + +PseudoConstantAnalysis::~PseudoConstantAnalysis() { + delete (VarDeclSet*)NonConstantsImpl; + delete (VarDeclSet*)UsedVarsImpl; +} + +// Returns true if the given ValueDecl is never written to in the given DeclBody +bool PseudoConstantAnalysis::isPseudoConstant(const VarDecl *VD) { + // Only local and static variables can be pseudoconstants + if (!VD->hasLocalStorage() && !VD->isStaticLocal()) + return false; + + if (!Analyzed) { + RunAnalysis(); + Analyzed = true; + } + + VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl; + + return !NonConstants->count(VD); +} + +// Returns true if the variable was used (self assignments don't count) +bool PseudoConstantAnalysis::wasReferenced(const VarDecl *VD) { + if (!Analyzed) { + RunAnalysis(); + Analyzed = true; + } + + VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl; + + return UsedVars->count(VD); +} + +// Returns a Decl from a (Block)DeclRefExpr (if any) +const Decl *PseudoConstantAnalysis::getDecl(const Expr *E) { + if (const DeclRefExpr *DR = dyn_cast(E)) + return DR->getDecl(); + else if (const BlockDeclRefExpr *BDR = dyn_cast(E)) + return BDR->getDecl(); + else + return 0; +} + +void PseudoConstantAnalysis::RunAnalysis() { + std::deque WorkList; + VarDeclSet *NonConstants = (VarDeclSet*)NonConstantsImpl; + VarDeclSet *UsedVars = (VarDeclSet*)UsedVarsImpl; + + // Start with the top level statement of the function + WorkList.push_back(DeclBody); + + while (!WorkList.empty()) { + const Stmt* Head = WorkList.front(); + WorkList.pop_front(); + + switch (Head->getStmtClass()) { + // Case 1: Assignment operators modifying VarDecls + case Stmt::BinaryOperatorClass: { + const BinaryOperator *BO = cast(Head); + // Look for a Decl on the LHS + const Decl *LHSDecl = getDecl(BO->getLHS()->IgnoreParenCasts()); + if (!LHSDecl) + break; + + // We found a binary operator with a DeclRefExpr on the LHS. We now check + // for any of the assignment operators, implying that this Decl is being + // written to. + switch (BO->getOpcode()) { + // Self-assignments don't count as use of a variable + case BO_Assign: { + // Look for a DeclRef on the RHS + const Decl *RHSDecl = getDecl(BO->getRHS()->IgnoreParenCasts()); + + // If the Decls match, we have self-assignment + if (LHSDecl == RHSDecl) + // Do not visit the children + continue; + + } + case BO_AddAssign: + case BO_SubAssign: + case BO_MulAssign: + case BO_DivAssign: + case BO_AndAssign: + case BO_OrAssign: + case BO_XorAssign: + case BO_ShlAssign: + case BO_ShrAssign: { + const VarDecl *VD = dyn_cast(LHSDecl); + // The DeclRefExpr is being assigned to - mark it as non-constant + if (VD) + NonConstants->insert(VD); + break; + } + + default: + break; + } + break; + } + + // Case 2: Pre/post increment/decrement and address of + case Stmt::UnaryOperatorClass: { + const UnaryOperator *UO = cast(Head); + + // Look for a DeclRef in the subexpression + const Decl *D = getDecl(UO->getSubExpr()->IgnoreParenCasts()); + if (!D) + break; + + // We found a unary operator with a DeclRef as a subexpression. We now + // check for any of the increment/decrement operators, as well as + // addressOf. + switch (UO->getOpcode()) { + case UO_PostDec: + case UO_PostInc: + case UO_PreDec: + case UO_PreInc: + // The DeclRef is being changed - mark it as non-constant + case UO_AddrOf: { + // If we are taking the address of the DeclRefExpr, assume it is + // non-constant. + const VarDecl *VD = dyn_cast(D); + if (VD) + NonConstants->insert(VD); + break; + } + + default: + break; + } + break; + } + + // Case 3: Reference Declarations + case Stmt::DeclStmtClass: { + const DeclStmt *DS = cast(Head); + // Iterate over each decl and see if any of them contain reference decls + for (DeclStmt::const_decl_iterator I = DS->decl_begin(), + E = DS->decl_end(); I != E; ++I) { + // We only care about VarDecls + const VarDecl *VD = dyn_cast(*I); + if (!VD) + continue; + + // We found a VarDecl; make sure it is a reference type + if (!VD->getType().getTypePtr()->isReferenceType()) + continue; + + // Try to find a Decl in the initializer + const Decl *D = getDecl(VD->getInit()->IgnoreParenCasts()); + if (!D) + break; + + // If the reference is to another var, add the var to the non-constant + // list + if (const VarDecl *RefVD = dyn_cast(D)) { + NonConstants->insert(RefVD); + continue; + } + } + break; + } + + // Case 4: Block variable references + case Stmt::BlockDeclRefExprClass: { + const BlockDeclRefExpr *BDR = cast(Head); + if (const VarDecl *VD = dyn_cast(BDR->getDecl())) { + // Add the Decl to the used list + UsedVars->insert(VD); + continue; + } + break; + } + + // Case 5: Variable references + case Stmt::DeclRefExprClass: { + const DeclRefExpr *DR = cast(Head); + if (const VarDecl *VD = dyn_cast(DR->getDecl())) { + // Add the Decl to the used list + UsedVars->insert(VD); + continue; + } + break; + } + + // Case 6: Block expressions + case Stmt::BlockExprClass: { + const BlockExpr *B = cast(Head); + // Add the body of the block to the list + WorkList.push_back(B->getBody()); + continue; + } + + default: + break; + } // switch (head->getStmtClass()) + + // Add all substatements to the worklist + for (Stmt::const_child_iterator I = Head->child_begin(), + E = Head->child_end(); I != E; ++I) + if (*I) + WorkList.push_back(*I); + } // while (!WorkList.empty()) +} diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp index f959e5c..0543939 100644 --- a/lib/Analysis/ReachableCode.cpp +++ b/lib/Analysis/ReachableCode.cpp @@ -41,7 +41,7 @@ top: switch (S->getStmtClass()) { case Expr::BinaryOperatorClass: { const BinaryOperator *BO = cast(S); - if (BO->getOpcode() == BinaryOperator::Comma) { + if (BO->getOpcode() == BO_Comma) { if (sn+1 < b.size()) return b[sn+1].getStmt()->getLocStart(); const CFGBlock *n = &b; diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp new file mode 100644 index 0000000..6a8673a --- /dev/null +++ b/lib/Analysis/ScanfFormatString.cpp @@ -0,0 +1,221 @@ +//= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Handling of format string in scanf and friends. The structure of format +// strings for fscanf() are described in C99 7.19.6.2. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/Analyses/FormatString.h" +#include "FormatStringParsing.h" + +using clang::analyze_format_string::ArgTypeResult; +using clang::analyze_format_string::FormatStringHandler; +using clang::analyze_format_string::LengthModifier; +using clang::analyze_format_string::OptionalAmount; +using clang::analyze_format_string::ConversionSpecifier; +using clang::analyze_scanf::ScanfConversionSpecifier; +using clang::analyze_scanf::ScanfSpecifier; +using clang::UpdateOnReturn; + +typedef clang::analyze_format_string::SpecifierResult + ScanfSpecifierResult; + +static bool ParseScanList(FormatStringHandler &H, + ScanfConversionSpecifier &CS, + const char *&Beg, const char *E) { + const char *I = Beg; + const char *start = I - 1; + UpdateOnReturn UpdateBeg(Beg, I); + + // No more characters? + if (I == E) { + H.HandleIncompleteScanList(start, I); + return true; + } + + // Special case: ']' is the first character. + if (*I == ']') { + if (++I == E) { + H.HandleIncompleteScanList(start, I - 1); + return true; + } + } + + // Look for a ']' character which denotes the end of the scan list. + while (*I != ']') { + if (++I == E) { + H.HandleIncompleteScanList(start, I - 1); + return true; + } + } + + CS.setEndScanList(I); + return false; +} + +// FIXME: Much of this is copy-paste from ParsePrintfSpecifier. +// We can possibly refactor. +static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, + const char *&Beg, + const char *E, + unsigned &argIndex) { + + using namespace clang::analyze_scanf; + const char *I = Beg; + const char *Start = 0; + UpdateOnReturn UpdateBeg(Beg, I); + + // Look for a '%' character that indicates the start of a format specifier. + for ( ; I != E ; ++I) { + char c = *I; + if (c == '\0') { + // Detect spurious null characters, which are likely errors. + H.HandleNullChar(I); + return true; + } + if (c == '%') { + Start = I++; // Record the start of the format specifier. + break; + } + } + + // No format specifier found? + if (!Start) + return false; + + if (I == E) { + // No more characters left? + H.HandleIncompleteSpecifier(Start, E - Start); + return true; + } + + ScanfSpecifier FS; + if (ParseArgPosition(H, FS, Start, I, E)) + return true; + + if (I == E) { + // No more characters left? + H.HandleIncompleteSpecifier(Start, E - Start); + return true; + } + + // Look for '*' flag if it is present. + if (*I == '*') { + FS.setSuppressAssignment(I); + if (++I == E) { + H.HandleIncompleteSpecifier(Start, E - Start); + return true; + } + } + + // Look for the field width (if any). Unlike printf, this is either + // a fixed integer or isn't present. + const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E); + if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) { + assert(Amt.getHowSpecified() == OptionalAmount::Constant); + FS.setFieldWidth(Amt); + + if (I == E) { + // No more characters left? + H.HandleIncompleteSpecifier(Start, E - Start); + return true; + } + } + + // Look for the length modifier. + if (ParseLengthModifier(FS, I, E) && I == E) { + // No more characters left? + H.HandleIncompleteSpecifier(Start, E - Start); + return true; + } + + // Detect spurious null characters, which are likely errors. + if (*I == '\0') { + H.HandleNullChar(I); + return true; + } + + // Finally, look for the conversion specifier. + const char *conversionPosition = I++; + ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier; + switch (*conversionPosition) { + default: + break; + case '%': k = ConversionSpecifier::PercentArg; break; + case 'A': k = ConversionSpecifier::AArg; break; + case 'E': k = ConversionSpecifier::EArg; break; + case 'F': k = ConversionSpecifier::FArg; break; + case 'G': k = ConversionSpecifier::GArg; break; + case 'X': k = ConversionSpecifier::XArg; break; + case 'a': k = ConversionSpecifier::aArg; break; + case 'd': k = ConversionSpecifier::dArg; break; + case 'e': k = ConversionSpecifier::eArg; break; + case 'f': k = ConversionSpecifier::fArg; break; + case 'g': k = ConversionSpecifier::gArg; break; + case 'i': k = ConversionSpecifier::iArg; break; + case 'n': k = ConversionSpecifier::nArg; break; + case 'c': k = ConversionSpecifier::cArg; break; + case 'C': k = ConversionSpecifier::CArg; break; + case 'S': k = ConversionSpecifier::SArg; break; + case '[': k = ConversionSpecifier::ScanListArg; break; + case 'u': k = ConversionSpecifier::uArg; break; + case 'x': k = ConversionSpecifier::xArg; break; + case 'o': k = ConversionSpecifier::oArg; break; + case 's': k = ConversionSpecifier::sArg; break; + case 'p': k = ConversionSpecifier::pArg; break; + } + ScanfConversionSpecifier CS(conversionPosition, k); + if (k == ScanfConversionSpecifier::ScanListArg) { + if (!ParseScanList(H, CS, I, E)) + return true; + } + FS.setConversionSpecifier(CS); + if (CS.consumesDataArgument() && !FS.getSuppressAssignment() + && !FS.usesPositionalArg()) + FS.setArgIndex(argIndex++); + + // FIXME: '%' and '*' doesn't make sense. Issue a warning. + // FIXME: 'ConsumedSoFar' and '*' doesn't make sense. + + if (k == ScanfConversionSpecifier::InvalidSpecifier) { + // Assume the conversion takes one argument. + return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, I - Beg); + } + return ScanfSpecifierResult(Start, FS); +} + +bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H, + const char *I, + const char *E) { + + unsigned argIndex = 0; + + // Keep looking for a format specifier until we have exhausted the string. + while (I != E) { + const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex); + // Did a fail-stop error of any kind occur when parsing the specifier? + // If so, don't do any more processing. + if (FSR.shouldStop()) + return true;; + // Did we exhaust the string or encounter an error that + // we can recover from? + if (!FSR.hasValue()) + continue; + // We have a format specifier. Pass it to the callback. + if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(), + I - FSR.getStart())) { + return true; + } + } + assert(I == E && "Format string not exhausted"); + return false; +} + + diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index 7a62864..0f43efa 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/lib/Analysis/UninitializedValues.cpp @@ -121,7 +121,7 @@ bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { if (VarDecl* VD = FindBlockVarDecl(B->getLHS())) if (B->isAssignmentOp()) { - if (B->getOpcode() == BinaryOperator::Assign) + if (B->getOpcode() == BO_Assign) return V(VD,AD) = Visit(B->getRHS()); else // Handle +=, -=, *=, etc. We do want '&', not '&&'. return V(VD,AD) = Visit(B->getLHS()) & Visit(B->getRHS()); @@ -168,7 +168,7 @@ bool TransferFuncs::VisitCallExpr(CallExpr* C) { bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { switch (U->getOpcode()) { - case UnaryOperator::AddrOf: { + case UO_AddrOf: { VarDecl* VD = FindBlockVarDecl(U->getSubExpr()); if (VD && VD->isBlockVarDecl()) return V(VD,AD) = Initialized; diff --git a/lib/Basic/Builtins.cpp b/lib/Basic/Builtins.cpp index 1a32937..040cdb5 100644 --- a/lib/Basic/Builtins.cpp +++ b/lib/Basic/Builtins.cpp @@ -93,3 +93,23 @@ Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, return true; } +// FIXME: Refactor with isPrintfLike. +bool +Builtin::Context::isScanfLike(unsigned ID, unsigned &FormatIdx, + bool &HasVAListArg) { + const char *Scanf = strpbrk(GetRecord(ID).Attributes, "sS"); + if (!Scanf) + return false; + + HasVAListArg = (*Scanf == 'S'); + + ++Scanf; + assert(*Scanf == ':' && "s or S specifier must have be followed by a ':'"); + ++Scanf; + + assert(strchr(Scanf, ':') && "printf specifier must end with a ':'"); + FormatIdx = strtol(Scanf, 0, 10); + return true; +} + + diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 641d87b..d8095f4 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -38,6 +38,8 @@ using namespace clang; // Builtin Diagnostic information //===----------------------------------------------------------------------===// +namespace { + // Diagnostic classes. enum { CLASS_NOTE = 0x01, @@ -59,11 +61,10 @@ struct StaticDiagInfoRec { bool operator<(const StaticDiagInfoRec &RHS) const { return DiagID < RHS.DiagID; } - bool operator>(const StaticDiagInfoRec &RHS) const { - return DiagID > RHS.DiagID; - } }; +} + static const StaticDiagInfoRec StaticDiagInfo[] = { #define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE, CATEGORY) \ { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, CATEGORY, DESC, GROUP }, @@ -244,6 +245,9 @@ static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT, Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { + ArgToStringFn = DummyArgToStringFn; + ArgToStringCookie = 0; + AllExtensionsSilenced = 0; IgnoreAllWarnings = false; WarningsAsErrors = false; @@ -253,26 +257,15 @@ Diagnostic::Diagnostic(DiagnosticClient *client) : Client(client) { ShowOverloads = Ovl_All; ExtBehavior = Ext_Ignore; - ErrorOccurred = false; - FatalErrorOccurred = false; ErrorLimit = 0; TemplateBacktraceLimit = 0; - - NumWarnings = 0; - NumErrors = 0; - NumErrorsSuppressed = 0; CustomDiagInfo = 0; - CurDiagID = ~0U; - LastDiagLevel = Ignored; - - ArgToStringFn = DummyArgToStringFn; - ArgToStringCookie = 0; - - DelayedDiagID = 0; // Set all mappings to 'unset'. - DiagMappings BlankDiags(diag::DIAG_UPPER_LIMIT/2, 0); - DiagMappingsStack.push_back(BlankDiags); + DiagMappingsStack.clear(); + DiagMappingsStack.push_back(DiagMappings()); + + Reset(); } Diagnostic::~Diagnostic() { @@ -331,10 +324,21 @@ bool Diagnostic::isBuiltinExtensionDiag(unsigned DiagID, getBuiltinDiagClass(DiagID) != CLASS_EXTENSION) return false; - EnabledByDefault = StaticDiagInfo[DiagID].Mapping != diag::MAP_IGNORE; + EnabledByDefault = GetDefaultDiagMapping(DiagID) != diag::MAP_IGNORE; return true; } +void Diagnostic::Reset() { + ErrorOccurred = false; + FatalErrorOccurred = false; + + NumWarnings = 0; + NumErrors = 0; + NumErrorsSuppressed = 0; + CurDiagID = ~0U; + LastDiagLevel = Ignored; + DelayedDiagID = 0; +} /// getDescription - Given a diagnostic ID, return a description of the /// issue. @@ -572,11 +576,11 @@ bool Diagnostic::ProcessDiag() { // If a fatal error has already been emitted, silence all subsequent // diagnostics. if (FatalErrorOccurred) { - if (DiagLevel >= Diagnostic::Error) { + if (DiagLevel >= Diagnostic::Error && Client->IncludeInDiagnosticCounts()) { ++NumErrors; ++NumErrorsSuppressed; } - + return false; } @@ -597,9 +601,11 @@ bool Diagnostic::ProcessDiag() { } if (DiagLevel >= Diagnostic::Error) { - ErrorOccurred = true; - ++NumErrors; - + if (Client->IncludeInDiagnosticCounts()) { + ErrorOccurred = true; + ++NumErrors; + } + // If we've emitted a lot of errors, emit a fatal error after it to stop a // flood of bogus errors. if (ErrorLimit && NumErrors >= ErrorLimit && @@ -1146,11 +1152,6 @@ void StoredDiagnostic::Serialize(llvm::raw_ostream &OS) const { break; } - if (F->InsertionLoc.isValid() && F->InsertionLoc.isMacroID()) { - NumFixIts = 0; - break; - } - ++NumFixIts; } @@ -1160,7 +1161,6 @@ void StoredDiagnostic::Serialize(llvm::raw_ostream &OS) const { WriteSourceLocation(OS, SM, F->RemoveRange.getBegin()); WriteSourceLocation(OS, SM, F->RemoveRange.getEnd()); WriteUnsigned(OS, F->RemoveRange.isTokenRange()); - WriteSourceLocation(OS, SM, F->InsertionLoc); WriteString(OS, F->CodeToInsert); } } @@ -1288,12 +1288,11 @@ StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM, if (ReadUnsigned(Memory, MemoryEnd, NumFixIts)) return Diag; for (unsigned I = 0; I != NumFixIts; ++I) { - SourceLocation RemoveBegin, RemoveEnd, InsertionLoc; + SourceLocation RemoveBegin, RemoveEnd; unsigned InsertLen = 0, RemoveIsTokenRange; if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveBegin) || ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveEnd) || ReadUnsigned(Memory, MemoryEnd, RemoveIsTokenRange) || - ReadSourceLocation(FM, SM, Memory, MemoryEnd, InsertionLoc) || ReadUnsigned(Memory, MemoryEnd, InsertLen) || Memory + InsertLen > MemoryEnd) { Diag.FixIts.clear(); @@ -1303,7 +1302,6 @@ StoredDiagnostic::Deserialize(FileManager &FM, SourceManager &SM, FixItHint Hint; Hint.RemoveRange = CharSourceRange(SourceRange(RemoveBegin, RemoveEnd), RemoveIsTokenRange); - Hint.InsertionLoc = InsertionLoc; Hint.CodeToInsert.assign(Memory, Memory + InsertLen); Memory += InsertLen; Diag.FixIts.push_back(Hint); diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index 3c91a0f..565f8a6 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -19,6 +19,7 @@ #include "clang/Basic/FileManager.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" #include "llvm/Config/config.h" @@ -83,6 +84,9 @@ class FileManager::UniqueFileContainer { public: FileEntry &getFile(const char *Name, struct stat &StatBuf) { std::string FullPath(GetFullPath(Name)); + + // LowercaseString because Windows filesystem is case insensitive. + FullPath = llvm::LowercaseString(FullPath); return UniqueFiles.GetOrCreateValue( FullPath.c_str(), FullPath.c_str() + FullPath.size() @@ -365,6 +369,18 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size, UFE->ModTime = ModificationTime; UFE->Dir = DirInfo; UFE->UID = NextFileUID++; + + // If this virtual file resolves to a file, also map that file to the + // newly-created file entry. + const char *InterndFileName = NamedFileEnt.getKeyData(); + struct stat StatBuf; + if (!stat_cached(InterndFileName, &StatBuf) && + !S_ISDIR(StatBuf.st_mode)) { + llvm::sys::Path FilePath(InterndFileName); + FilePath.makeAbsolute(); + FileEntries[FilePath.str()] = UFE; + } + return UFE; } diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 8993e67..6b673e3 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -34,6 +34,8 @@ IdentifierInfo::IdentifierInfo() { IsPoisoned = false; IsCPPOperatorKeyword = false; NeedsHandleIdentifier = false; + IsFromAST = false; + RevertedTokenID = false; FETokenInfo = 0; Entry = 0; } @@ -71,7 +73,8 @@ namespace { KEYMS = 32, BOOLSUPPORT = 64, KEYALTIVEC = 128, - KEYNOMS = 256 + KEYNOMS = 256, + KEYBORLAND = 512 }; } @@ -93,6 +96,7 @@ static void AddKeyword(llvm::StringRef Keyword, else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2; else if (LangOpts.GNUKeywords && (Flags & KEYGNU)) AddResult = 1; else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1; + else if (LangOpts.Borland && (Flags & KEYBORLAND)) AddResult = 1; else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2; else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2; else if (!LangOpts.Microsoft && (Flags & KEYNOMS)) AddResult = 2; @@ -100,8 +104,7 @@ static void AddKeyword(llvm::StringRef Keyword, // Don't add this keyword if disabled in this language. if (AddResult == 0) return; - IdentifierInfo &Info = Table.get(Keyword); - Info.setTokenID(TokenCode); + IdentifierInfo &Info = Table.get(Keyword, TokenCode); Info.setIsExtensionToken(AddResult == 1); } @@ -110,8 +113,7 @@ static void AddKeyword(llvm::StringRef Keyword, static void AddCXXOperatorKeyword(llvm::StringRef Keyword, tok::TokenKind TokenCode, IdentifierTable &Table) { - IdentifierInfo &Info = Table.get(Keyword); - Info.setTokenID(TokenCode); + IdentifierInfo &Info = Table.get(Keyword, TokenCode); Info.setIsCPlusPlusOperatorKeyword(); } diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile index 51b8ac1..c156304 100644 --- a/lib/Basic/Makefile +++ b/lib/Basic/Makefile @@ -13,7 +13,6 @@ CLANG_LEVEL := ../.. LIBRARYNAME := clangBasic -BUILD_ARCHIVE = 1 include $(CLANG_LEVEL)/Makefile diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index e6d9785..633d86c 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -32,7 +32,8 @@ using llvm::MemoryBuffer; //===----------------------------------------------------------------------===// ContentCache::~ContentCache() { - delete Buffer.getPointer(); + if (shouldFreeBuffer()) + delete Buffer.getPointer(); } /// getSizeBytesMapped - Returns the number of bytes actually mapped for @@ -51,12 +52,14 @@ unsigned ContentCache::getSize() const { : (unsigned) Entry->getSize(); } -void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) { +void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B, + bool DoNotFree) { assert(B != Buffer.getPointer()); - delete Buffer.getPointer(); + if (shouldFreeBuffer()) + delete Buffer.getPointer(); Buffer.setPointer(B); - Buffer.setInt(false); + Buffer.setInt(DoNotFree? DoNotFreeFlag : 0); } const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, @@ -72,7 +75,6 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, struct stat FileInfo; Buffer.setPointer(MemoryBuffer::getFile(Entry->getName(), &ErrorStr, Entry->getSize(), &FileInfo)); - Buffer.setInt(false); // If we were unable to open the file, then we are in an inconsistent // situation where the content cache referenced a file which no longer @@ -99,7 +101,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, Diag.Report(FullSourceLoc(Loc, SM), diag::err_cannot_open_file) << Entry->getName() << ErrorStr; - Buffer.setInt(true); + Buffer.setInt(Buffer.getInt() | InvalidFlag); // FIXME: This conditionalization is horrible, but we see spurious failures // in the test suite due to this warning and no one has had time to hunt it @@ -119,14 +121,14 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, Diag.Report(FullSourceLoc(Loc, SM), diag::err_file_modified) << Entry->getName(); - Buffer.setInt(true); + Buffer.setInt(Buffer.getInt() | InvalidFlag); #endif } // If the buffer is valid, check to see if it has a UTF Byte Order Mark // (BOM). We only support UTF-8 without a BOM right now. See // http://en.wikipedia.org/wiki/Byte_order_mark for more information. - if (!Buffer.getInt()) { + if (!isBufferInvalid()) { llvm::StringRef BufStr = Buffer.getPointer()->getBuffer(); const char *BOM = 0; if (BufStr.startswith("\xFE\xBB\xBF")) @@ -161,7 +163,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, } if (Invalid) - *Invalid = Buffer.getInt(); + *Invalid = isBufferInvalid(); return Buffer.getPointer(); } @@ -422,9 +424,12 @@ void SourceManager::PreallocateSLocEntries(ExternalSLocEntrySource *Source, unsigned NextOffset) { ExternalSLocEntries = Source; this->NextOffset = NextOffset; + unsigned CurPrealloc = SLocEntryLoaded.size(); + // If we've ever preallocated, we must not count the dummy entry. + if (CurPrealloc) --CurPrealloc; SLocEntryLoaded.resize(NumSLocEntries + 1); SLocEntryLoaded[0] = true; - SLocEntryTable.resize(SLocEntryTable.size() + NumSLocEntries); + SLocEntryTable.resize(SLocEntryTable.size() + NumSLocEntries - CurPrealloc); } void SourceManager::ClearPreallocatedSLocEntries() { @@ -448,7 +453,7 @@ void SourceManager::ClearPreallocatedSLocEntries() { // Methods to create new FileID's and instantiations. //===----------------------------------------------------------------------===// -/// createFileID - Create a new fileID for the specified ContentCache and +/// createFileID - Create a new FileID for the specified ContentCache and /// include position. This works regardless of whether the ContentCache /// corresponds to a file or some other input source. FileID SourceManager::createFileID(const ContentCache *File, @@ -521,12 +526,13 @@ SourceManager::getMemoryBufferForFile(const FileEntry *File, } bool SourceManager::overrideFileContents(const FileEntry *SourceFile, - const llvm::MemoryBuffer *Buffer) { + const llvm::MemoryBuffer *Buffer, + bool DoNotFree) { const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile); if (IR == 0) return true; - const_cast(IR)->replaceBuffer(Buffer); + const_cast(IR)->replaceBuffer(Buffer, DoNotFree); return false; } @@ -1241,7 +1247,7 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, } // There is no common ancestor, most probably because one location is in the - // predefines buffer or a PCH file. + // predefines buffer or an AST file. // FIXME: We should rearrange the external interface so this simply never // happens; it can't conceptually happen. Also see PR5662. IsBeforeInTUCache.setQueryFIDs(FileID(), FileID()); // Don't try caching. diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 7fcf372..6d42883 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -58,6 +58,9 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { // Default to no types using fpret. RealTypeUsesObjCFPRet = 0; + + // Default to using the Itanium ABI. + CXXABI = CXXABI_Itanium; } // Out of line virtual dtor for TargetInfo. @@ -287,8 +290,15 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { Info.setAllowsRegister(); Info.setAllowsMemory(); break; - case ',': // FIXME: Until we handle multiple alternative constraints, - return true; // ignore everything after the first comma. + case ',': // multiple alternative constraint. Pass it. + Name++; + // Handle additional optional '=' or '+' modifiers. + if (*Name == '=' || *Name == '+') + Name++; + break; + case '?': // Disparage slightly code. + case '!': // Disparage severly. + break; // Pass them. } Name++; @@ -352,6 +362,7 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, if (!resolveSymbolicName(Name, OutputConstraints, NumOutputs, Index)) return false; + Info.setTiedOperand(Index, OutputConstraints[Index]); break; } case '%': // commutative @@ -382,8 +393,11 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, Info.setAllowsRegister(); Info.setAllowsMemory(); break; - case ',': // FIXME: Until we handle multiple alternative constraints, - return true; // ignore everything after the first comma. + case ',': // multiple alternative constraint. Ignore comma. + break; + case '?': // Disparage slightly code. + case '!': // Disparage severly. + break; // Pass them. } Name++; diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index fdf63e7..df20def 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -502,7 +502,7 @@ public: // is therefore only safe to use `m' in an asm statement // if that asm statement accesses the operand exactly once. // The asm statement must also use `%U' as a - // placeholder for the “update” flag in the corresponding + // placeholder for the "update" flag in the corresponding // load or store instruction. For example: // asm ("st%U0 %1,%0" : "=m" (mem) : "r" (val)); // is correct but: @@ -512,7 +512,7 @@ public: case 'e': if (Name[1] != 's') return false; - // es: A “stable” memory operand; that is, one which does not + // es: A "stable" memory operand; that is, one which does not // include any automodification of the base register. Unlike // `m', this constraint can be used in asm statements that // might access the operand several times, or that might not @@ -912,11 +912,12 @@ class X86TargetInfo : public TargetInfo { } AMD3DNowLevel; bool HasAES; - + bool HasAVX; + public: X86TargetInfo(const std::string& triple) : TargetInfo(triple), SSELevel(NoMMXSSE), AMD3DNowLevel(NoAMD3DNow), - HasAES(false) { + HasAES(false), HasAVX(false) { LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; } virtual void getTargetBuiltins(const Builtin::Info *&Records, @@ -963,6 +964,7 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU, Features["sse41"] = false; Features["sse42"] = false; Features["aes"] = false; + Features["avx"] = false; // LLVM does not currently recognize this. // Features["sse4a"] = false; @@ -1046,6 +1048,8 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap &Features, Features["3dnow"] = Features["3dnowa"] = true; else if (Name == "aes") Features["aes"] = true; + else if (Name == "avx") + Features["avx"] = true; } else { if (Name == "mmx") Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = @@ -1073,6 +1077,8 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap &Features, Features["3dnowa"] = false; else if (Name == "aes") Features["aes"] = false; + else if (Name == "avx") + Features["avx"] = false; } return true; @@ -1092,6 +1098,13 @@ void X86TargetInfo::HandleTargetFeatures(std::vector &Features) { continue; } + // FIXME: Not sure yet how to treat AVX in regard to SSE levels. + // For now let it be enabled together with other SSE levels. + if (Features[i].substr(1) == "avx") { + HasAVX = true; + continue; + } + assert(Features[i][0] == '+' && "Invalid target feature!"); X86SSEEnum Level = llvm::StringSwitch(Features[i].substr(1)) .Case("sse42", SSE42) @@ -1133,6 +1146,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasAES) Builder.defineMacro("__AES__"); + if (HasAVX) + Builder.defineMacro("__AVX__"); + // Target properties. Builder.defineMacro("__LITTLE_ENDIAN__"); @@ -1186,6 +1202,15 @@ X86TargetInfo::validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const { switch (*Name) { default: return false; + case 'Y': // first letter of a pair: + switch (*(Name+1)) { + default: return false; + case '0': // First SSE register. + case 't': // Any SSE register, when SSE2 is enabled. + case 'i': // Any SSE register, when SSE2 and inter-unit moves enabled. + case 'm': // any MMX register, when inter-unit moves enabled. + break; // falls through to setAllowsRegister. + } case 'a': // eax. case 'b': // ebx. case 'c': // ecx. @@ -1193,22 +1218,27 @@ X86TargetInfo::validateAsmConstraint(const char *&Name, case 'S': // esi. case 'D': // edi. case 'A': // edx:eax. + case 'f': // any x87 floating point stack register. case 't': // top of floating point stack. case 'u': // second from top of floating point stack. case 'q': // Any register accessible as [r]l: a, b, c, and d. case 'y': // Any MMX register. case 'x': // Any SSE register. case 'Q': // Any register accessible as [r]h: a, b, c, and d. + case 'R': // "Legacy" registers: ax, bx, cx, dx, di, si, sp, bp. + case 'l': // "Index" registers: any general register that can be used as an + // index in a base+index memory access. + Info.setAllowsRegister(); + return true; + case 'C': // SSE floating point constant. + case 'G': // x87 floating point constant. case 'e': // 32-bit signed integer constant for use with zero-extending // x86_64 instructions. case 'Z': // 32-bit unsigned integer constant for use with zero-extending // x86_64 instructions. - case 'N': // unsigned 8-bit integer constant for use with in and out - // instructions. - case 'R': // "legacy" registers: ax, bx, cx, dx, di, si, sp, bp. - Info.setAllowsRegister(); return true; } + return false; } std::string @@ -1333,6 +1363,8 @@ public: // 300=386, 400=486, 500=Pentium, 600=Blend (default) // We lost the original triple, so we use the default. Builder.defineMacro("_M_IX86", "600"); + Builder.defineMacro("_INTEGRAL_MAX_BITS", "64"); + Builder.defineMacro("_STDCALL_SUPPORTED"); } }; } // end anonymous namespace @@ -1388,7 +1420,7 @@ public: SizeType = UnsignedLong; IntPtrType = SignedLong; PtrDiffType = SignedLong; - } + } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { X86_32TargetInfo::getTargetDefines(Opts, Builder); @@ -1447,7 +1479,10 @@ public: TLSSupported = false; WCharType = UnsignedShort; LongWidth = LongAlign = 32; - DoubleAlign = LongLongAlign = 64; + DoubleAlign = LongLongAlign = 64; + IntMaxType = SignedLongLong; + UIntMaxType = UnsignedLongLong; + Int64Type = SignedLongLong; } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { @@ -1469,9 +1504,10 @@ public: MacroBuilder &Builder) const { WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("_M_X64"); + Builder.defineMacro("_INTEGRAL_MAX_BITS", "64"); } virtual const char *getVAListDeclaration() const { - return "typedef char* va_list;"; + return "typedef char* __builtin_va_list;"; } }; } // end anonymous namespace @@ -1566,6 +1602,9 @@ public: "i64:64:64-f32:32:32-f64:64:64-" "v64:64:64-v128:128:128-a0:0:64-n32"); } + + // ARM targets default to using the ARM C++ ABI. + CXXABI = CXXABI_ARM; } virtual const char *getABI() const { return ABI.c_str(); } virtual bool setABI(const std::string &Name) { @@ -1769,18 +1808,27 @@ public: }; const char * const ARMTargetInfo::GCCRegNames[] = { + // Integer registers "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" + "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", + + // Float registers + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", + "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", + "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31" + + // FIXME: Need double and NEON registers, but we need support for aliasing + // multiple registers for that. }; void ARMTargetInfo::getGCCRegNames(const char * const *&Names, - unsigned &NumNames) const { + unsigned &NumNames) const { Names = GCCRegNames; NumNames = llvm::array_lengthof(GCCRegNames); } const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = { - { { "a1" }, "r0" }, { { "a2" }, "r1" }, { { "a3" }, "r2" }, @@ -1794,9 +1842,9 @@ const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = { { { "sl" }, "r10" }, { { "fp" }, "r11" }, { { "ip" }, "r12" }, - { { "sp" }, "r13" }, - { { "lr" }, "r14" }, - { { "pc" }, "r15" }, + { { "r13" }, "sp" }, + { { "r14" }, "lr" }, + { { "r15" }, "pc" }, }; void ARMTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, @@ -2603,7 +2651,7 @@ TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags, } // Set the target C++ ABI. - if (!Target->setCXXABI(Opts.CXXABI)) { + if (!Opts.CXXABI.empty() && !Target->setCXXABI(Opts.CXXABI)) { Diags.Report(diag::err_target_unknown_cxxabi) << Opts.CXXABI; return 0; } diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index e0c2336..3e6d222 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -21,7 +21,7 @@ using namespace std; namespace clang { llvm::StringRef getClangRepositoryPath() { - static const char URL[] = "$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $"; + static const char URL[] = "$URL: http://llvm.org/svn/llvm-project/cfe/branches/release_28/lib/Basic/Version.cpp $"; const char *URLEnd = URL + strlen(URL); const char *End = strstr(URL, "/lib/Basic"); diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index bc2cd46..bd5e342 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -8,6 +8,8 @@ add_subdirectory(CodeGen) add_subdirectory(Analysis) add_subdirectory(Rewrite) add_subdirectory(Driver) +add_subdirectory(Serialization) add_subdirectory(Frontend) +add_subdirectory(FrontendTool) add_subdirectory(Index) add_subdirectory(Checker) diff --git a/lib/Checker/AdjustedReturnValueChecker.cpp b/lib/Checker/AdjustedReturnValueChecker.cpp index b92f2e7..0ed04fb 100644 --- a/lib/Checker/AdjustedReturnValueChecker.cpp +++ b/lib/Checker/AdjustedReturnValueChecker.cpp @@ -70,8 +70,7 @@ void AdjustedReturnValueChecker::PostVisitCallExpr(CheckerContext &C, } else if (const BlockDataRegion *BD = dyn_cast(callee)) { const BlockTextRegion *BR = BD->getCodeRegion(); - const BlockPointerType *BT = - BR->getLocationType(C.getASTContext())->getAs(); + const BlockPointerType *BT=BR->getLocationType()->getAs(); const FunctionType *FT = BT->getPointeeType()->getAs(); actualResultTy = FT->getResultType(); } diff --git a/lib/Checker/AggExprVisitor.cpp b/lib/Checker/AggExprVisitor.cpp index 343afec..6d472f4 100644 --- a/lib/Checker/AggExprVisitor.cpp +++ b/lib/Checker/AggExprVisitor.cpp @@ -18,6 +18,13 @@ using namespace clang; namespace { +/// AggExprVisitor is designed after AggExprEmitter of the CodeGen module. It +/// is used for evaluating exprs of C++ object type. Evaluating such exprs +/// requires a destination pointer pointing to the object being evaluated +/// into. Passing such a pointer around would pollute the Visit* interface of +/// GRExprEngine. AggExprVisitor encapsulates code that goes through various +/// cast and construct exprs (and others), and at the final point, dispatches +/// back to the GRExprEngine to let the real evaluation logic happen. class AggExprVisitor : public StmtVisitor { SVal DestPtr; ExplodedNode *Pred; @@ -38,8 +45,8 @@ void AggExprVisitor::VisitCastExpr(CastExpr *E) { switch (E->getCastKind()) { default: assert(0 && "Unhandled cast kind"); - case CastExpr::CK_NoOp: - case CastExpr::CK_ConstructorConversion: + case CK_NoOp: + case CK_ConstructorConversion: Visit(E->getSubExpr()); break; } diff --git a/lib/Checker/AnalysisConsumer.cpp b/lib/Checker/AnalysisConsumer.cpp index 524f37e..ad5ccb50 100644 --- a/lib/Checker/AnalysisConsumer.cpp +++ b/lib/Checker/AnalysisConsumer.cpp @@ -29,6 +29,7 @@ #include "clang/Checker/PathSensitive/GRTransferFuncs.h" #include "clang/Checker/PathDiagnosticClients.h" #include "GRExprEngineExperimentalChecks.h" +#include "GRExprEngineInternalChecks.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/AnalyzerOptions.h" @@ -173,10 +174,12 @@ public: Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), PP.getLangOptions(), PD, CreateStoreMgr, CreateConstraintMgr, + /* Indexer */ 0, Opts.MaxNodes, Opts.MaxLoop, Opts.VisualizeEGDot, Opts.VisualizeEGUbi, Opts.PurgeDead, Opts.EagerlyAssume, - Opts.TrimGraph, Opts.InlineCall)); + Opts.TrimGraph, Opts.InlineCall, + Opts.UnoptimizedCFG)); } virtual void HandleTranslationUnit(ASTContext &C); @@ -341,7 +344,10 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, if (C.Opts.EnableExperimentalChecks) RegisterExperimentalChecks(Eng); - if (C.Opts.EnableIdempotentOperationChecker) + // Enable idempotent operation checking if it was explicitly turned on, or if + // we are running experimental checks (i.e. everything) + if (C.Opts.IdempotentOps || C.Opts.EnableExperimentalChecks + || C.Opts.EnableExperimentalInternalChecks) RegisterIdempotentOperationChecker(Eng); // Set the graph auditor. @@ -352,7 +358,7 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, } // Execute the worklist algorithm. - Eng.ExecuteWorkList(mgr.getStackFrame(D), mgr.getMaxNodes()); + Eng.ExecuteWorkList(mgr.getStackFrame(D, 0), mgr.getMaxNodes()); // Release the auditor (if any) so that it doesn't monitor the graph // created BugReporter. diff --git a/lib/Checker/AnalysisManager.cpp b/lib/Checker/AnalysisManager.cpp new file mode 100644 index 0000000..339cdab --- /dev/null +++ b/lib/Checker/AnalysisManager.cpp @@ -0,0 +1,31 @@ +//===-- AnalysisManager.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Checker/PathSensitive/AnalysisManager.h" +#include "clang/Index/Entity.h" +#include "clang/Index/Indexer.h" + +using namespace clang; + +const AnalysisContext * +AnalysisManager::getAnalysisContextInAnotherTU(const Decl *D) { + idx::Entity Ent = idx::Entity::get(const_cast(D), + Idxer->getProgram()); + FunctionDecl *FuncDef; + idx::TranslationUnit *TU; + llvm::tie(FuncDef, TU) = Idxer->getDefinitionFor(Ent); + + if (FuncDef == 0) + return 0; + + // This AnalysisContext wraps function definition in another translation unit. + // But it is still owned by the AnalysisManager associated with the current + // translation unit. + return AnaCtxMgr.getContext(FuncDef, TU); +} diff --git a/lib/Checker/ArrayBoundChecker.cpp b/lib/Checker/ArrayBoundChecker.cpp index 746b3f9..98345bd 100644 --- a/lib/Checker/ArrayBoundChecker.cpp +++ b/lib/Checker/ArrayBoundChecker.cpp @@ -58,7 +58,7 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){ // Get the size of the array. DefinedOrUnknownSVal NumElements = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), - ER->getValueType(C.getASTContext())); + ER->getValueType()); const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp index ecb2d1c..3c1a6d1 100644 --- a/lib/Checker/BasicObjCFoundationChecks.cpp +++ b/lib/Checker/BasicObjCFoundationChecks.cpp @@ -73,9 +73,6 @@ class BasicObjCFoundationChecks : public GRSimpleAPICheck { bool isNSString(const ObjCInterfaceType *T, llvm::StringRef suffix); bool AuditNSString(ExplodedNode* N, const ObjCMessageExpr* ME); - void Warn(ExplodedNode* N, const Expr* E, const std::string& s); - void WarnNilArg(ExplodedNode* N, const Expr* E); - bool CheckNilArg(ExplodedNode* N, unsigned Arg); public: @@ -358,7 +355,7 @@ bool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){ if (!R) return false; - QualType T = Ctx.getCanonicalType(R->getValueType(Ctx)); + QualType T = Ctx.getCanonicalType(R->getValueType()); // FIXME: If the pointee isn't an integer type, should we flag a warning? // People can do weird stuff with pointers. diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp index 62c8d9c..f82e1b2 100644 --- a/lib/Checker/BasicStore.cpp +++ b/lib/Checker/BasicStore.cpp @@ -52,7 +52,7 @@ public: Store InvalidateRegions(Store store, const MemRegion * const *Begin, const MemRegion * const *End, const Expr *E, unsigned Count, InvalidatedSymbols *IS, - bool invalidateGlobals); + bool invalidateGlobals, InvalidatedRegions *Regions); Store scanForIvars(Stmt *B, const Decl* SelfDecl, const MemRegion *SelfRegion, Store St); @@ -61,11 +61,6 @@ public: Store Remove(Store St, Loc loc); Store getInitialStore(const LocationContext *InitLoc); - // FIXME: Investigate what is using this. This method should be removed. - virtual Loc getLoc(const VarDecl* VD, const LocationContext *LC) { - return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC)); - } - Store BindCompoundLiteral(Store store, const CompoundLiteralExpr*, const LocationContext*, SVal val) { return store; @@ -77,9 +72,8 @@ public: /// RemoveDeadBindings - Scans a BasicStore of 'state' for dead values. /// It updatees the GRState object in place with the values removed. - const GRState *RemoveDeadBindings(GRState &state, - const StackFrameContext *LCtx, - SymbolReaper& SymReaper, + Store RemoveDeadBindings(Store store, const StackFrameContext *LCtx, + SymbolReaper& SymReaper, llvm::SmallVectorImpl& RegionRoots); void iterBindings(Store store, BindingsHandler& f); @@ -103,8 +97,6 @@ public: private: SVal LazyRetrieve(Store store, const TypedRegion *R); - - ASTContext& getContext() { return StateMgr.getContext(); } }; } // end anonymous namespace @@ -228,17 +220,15 @@ Store BasicStoreManager::Bind(Store store, Loc loc, SVal V) { return VBFactory.Add(B, R, V).getRoot(); } - ASTContext &C = StateMgr.getContext(); - // Special case: handle store of pointer values (Loc) to pointers via // a cast to intXX_t*, void*, etc. This is needed to handle // OSCompareAndSwap32Barrier/OSCompareAndSwap64Barrier. if (isa(V) || isa(V)) if (const ElementRegion *ER = dyn_cast(R)) { // FIXME: Should check for index 0. - QualType T = ER->getLocationType(C); + QualType T = ER->getLocationType(); - if (isHigherOrderRawPtr(T, C)) + if (isHigherOrderRawPtr(T, Ctx)) R = ER->getSuperRegion(); } @@ -249,7 +239,7 @@ Store BasicStoreManager::Bind(Store store, Loc loc, SVal V) { // Do not bind to arrays. We need to explicitly check for this so that // we do not encounter any weirdness of trying to load/store from arrays. - if (TyR->isBoundable() && TyR->getValueType(C)->isArrayType()) + if (TyR->isBoundable() && TyR->getValueType()->isArrayType()) return store; if (nonloc::LocAsInteger *X = dyn_cast(&V)) { @@ -259,7 +249,7 @@ Store BasicStoreManager::Bind(Store store, Loc loc, SVal V) { // a pointer. We may wish to flag a type error here if the types // are incompatible. This may also cause lots of breakage // elsewhere. Food for thought. - if (TyR->isBoundable() && Loc::IsLocType(TyR->getValueType(C))) + if (TyR->isBoundable() && Loc::IsLocType(TyR->getValueType())) V = X->getLoc(); } @@ -285,12 +275,11 @@ Store BasicStoreManager::Remove(Store store, Loc loc) { } } -const GRState *BasicStoreManager::RemoveDeadBindings(GRState &state, +Store BasicStoreManager::RemoveDeadBindings(Store store, const StackFrameContext *LCtx, SymbolReaper& SymReaper, llvm::SmallVectorImpl& RegionRoots) { - Store store = state.getStore(); BindingsTy B = GetBindings(store); typedef SVal::symbol_iterator symbol_iterator; @@ -365,8 +354,7 @@ const GRState *BasicStoreManager::RemoveDeadBindings(GRState &state, } } - state.setStore(store); - return StateMgr.getPersistentState(state); + return store; } Store BasicStoreManager::scanForIvars(Stmt *B, const Decl* SelfDecl, @@ -406,10 +394,10 @@ Store BasicStoreManager::getInitialStore(const LocationContext *InitLoc) { Store St = VBFactory.GetEmptyMap().getRoot(); for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) { - NamedDecl* ND = const_cast(I->first); + const NamedDecl* ND = I->first; // Handle implicit parameters. - if (ImplicitParamDecl* PD = dyn_cast(ND)) { + if (const ImplicitParamDecl* PD = dyn_cast(ND)) { const Decl& CD = *InitLoc->getDecl(); if (const ObjCMethodDecl* MD = dyn_cast(&CD)) { if (MD->getSelfDecl() == PD) { @@ -449,11 +437,11 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR, // will not be called more than once. // Static global variables should not be visited here. - assert(!(VD->getStorageClass() == VarDecl::Static && + assert(!(VD->getStorageClass() == SC_Static && VD->isFileVarDecl())); // Process static variables. - if (VD->getStorageClass() == VarDecl::Static) { + if (VD->getStorageClass() == SC_Static) { // C99: 6.7.8 Initialization // If an object that has static storage duration is not initialized // explicitly, then: @@ -465,12 +453,9 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR, if (Loc::IsLocType(T)) store = Bind(store, loc::MemRegionVal(VR), loc::ConcreteInt(BasicVals.getValue(0, T))); - else if (T->isIntegerType()) + else if (T->isIntegerType() && T->isScalarType()) store = Bind(store, loc::MemRegionVal(VR), nonloc::ConcreteInt(BasicVals.getValue(0, T))); - else { - // assert(0 && "ignore other types of variables"); - } } else { store = Bind(store, loc::MemRegionVal(VR), *InitVal); } @@ -478,7 +463,8 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR, } else { // Process local scalar variables. QualType T = VD->getType(); - if (ValMgr.getSymbolManager().canSymbolicate(T)) { + // BasicStore only supports scalars. + if (T->isScalarType() && ValMgr.getSymbolManager().canSymbolicate(T)) { SVal V = InitVal ? *InitVal : UndefinedVal(); store = Bind(store, loc::MemRegionVal(VR), V); } @@ -523,11 +509,12 @@ StoreManager::BindingsHandler::~BindingsHandler() {} Store BasicStoreManager::InvalidateRegions(Store store, - const MemRegion * const *I, - const MemRegion * const *End, - const Expr *E, unsigned Count, - InvalidatedSymbols *IS, - bool invalidateGlobals) { + const MemRegion * const *I, + const MemRegion * const *End, + const Expr *E, unsigned Count, + InvalidatedSymbols *IS, + bool invalidateGlobals, + InvalidatedRegions *Regions) { if (invalidateGlobals) { BindingsTy B = GetBindings(store); for (BindingsTy::iterator I=B.begin(), End=B.end(); I != End; ++I) { @@ -545,6 +532,8 @@ Store BasicStoreManager::InvalidateRegions(Store store, continue; } store = InvalidateRegion(store, *I, E, Count, IS); + if (Regions) + Regions->push_back(R); } // FIXME: This is copy-and-paste from RegionStore.cpp. @@ -558,6 +547,8 @@ Store BasicStoreManager::InvalidateRegions(Store store, Count); store = Bind(store, loc::MemRegionVal(GS), V); + if (Regions) + Regions->push_back(GS); } return store; @@ -582,7 +573,7 @@ Store BasicStoreManager::InvalidateRegion(Store store, } } - QualType T = cast(R)->getValueType(R->getContext()); + QualType T = cast(R)->getValueType(); SVal V = ValMgr.getConjuredSymbolVal(R, E, T, Count); return Bind(store, loc::MemRegionVal(R), V); } diff --git a/lib/Checker/BasicValueFactory.cpp b/lib/Checker/BasicValueFactory.cpp index 246beea..4c9b109 100644 --- a/lib/Checker/BasicValueFactory.cpp +++ b/lib/Checker/BasicValueFactory.cpp @@ -149,22 +149,22 @@ BasicValueFactory::EvaluateAPSInt(BinaryOperator::Opcode Op, default: assert (false && "Invalid Opcode."); - case BinaryOperator::Mul: + case BO_Mul: return &getValue( V1 * V2 ); - case BinaryOperator::Div: + case BO_Div: return &getValue( V1 / V2 ); - case BinaryOperator::Rem: + case BO_Rem: return &getValue( V1 % V2 ); - case BinaryOperator::Add: + case BO_Add: return &getValue( V1 + V2 ); - case BinaryOperator::Sub: + case BO_Sub: return &getValue( V1 - V2 ); - case BinaryOperator::Shl: { + case BO_Shl: { // FIXME: This logic should probably go higher up, where we can // test these conditions symbolically. @@ -182,7 +182,7 @@ BasicValueFactory::EvaluateAPSInt(BinaryOperator::Opcode Op, return &getValue( V1.operator<<( (unsigned) Amt )); } - case BinaryOperator::Shr: { + case BO_Shr: { // FIXME: This logic should probably go higher up, where we can // test these conditions symbolically. @@ -200,33 +200,33 @@ BasicValueFactory::EvaluateAPSInt(BinaryOperator::Opcode Op, return &getValue( V1.operator>>( (unsigned) Amt )); } - case BinaryOperator::LT: + case BO_LT: return &getTruthValue( V1 < V2 ); - case BinaryOperator::GT: + case BO_GT: return &getTruthValue( V1 > V2 ); - case BinaryOperator::LE: + case BO_LE: return &getTruthValue( V1 <= V2 ); - case BinaryOperator::GE: + case BO_GE: return &getTruthValue( V1 >= V2 ); - case BinaryOperator::EQ: + case BO_EQ: return &getTruthValue( V1 == V2 ); - case BinaryOperator::NE: + case BO_NE: return &getTruthValue( V1 != V2 ); // Note: LAnd, LOr, Comma are handled specially by higher-level logic. - case BinaryOperator::And: + case BO_And: return &getValue( V1 & V2 ); - case BinaryOperator::Or: + case BO_Or: return &getValue( V1 | V2 ); - case BinaryOperator::Xor: + case BO_Xor: return &getValue( V1 ^ V2 ); } } diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp index 0422d80..bffbd52 100644 --- a/lib/Checker/BugReporter.cpp +++ b/lib/Checker/BugReporter.cpp @@ -94,8 +94,8 @@ static const Stmt* GetNextStmt(const ExplodedNode* N) { case Stmt::ChooseExprClass: case Stmt::ConditionalOperatorClass: continue; case Stmt::BinaryOperatorClass: { - BinaryOperator::Opcode Op = cast(S)->getOpcode(); - if (Op == BinaryOperator::LAnd || Op == BinaryOperator::LOr) + BinaryOperatorKind Op = cast(S)->getOpcode(); + if (Op == BO_LAnd || Op == BO_LOr) continue; break; } @@ -177,18 +177,9 @@ public: } virtual NodeMapClosure& getNodeResolver() { return NMC; } - BugReport& getReport() { return *R; } PathDiagnosticLocation getEnclosingStmtLocation(const Stmt *S); - PathDiagnosticLocation - getEnclosingStmtLocation(const PathDiagnosticLocation &L) { - if (const Stmt *S = L.asStmt()) - return getEnclosingStmtLocation(S); - - return L; - } - PathDiagnosticClient::PathGenerationScheme getGenerationScheme() const { return PDC ? PDC->getGenerationScheme() : PathDiagnosticClient::Extensive; } @@ -541,9 +532,9 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, ProgramPoint P = N->getLocation(); if (const BlockEdge* BE = dyn_cast(&P)) { - CFGBlock* Src = BE->getSrc(); - CFGBlock* Dst = BE->getDst(); - Stmt* T = Src->getTerminator(); + const CFGBlock* Src = BE->getSrc(); + const CFGBlock* Dst = BE->getDst(); + const Stmt* T = Src->getTerminator(); if (!T) continue; @@ -577,7 +568,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, std::string sbuf; llvm::raw_string_ostream os(sbuf); - if (Stmt* S = Dst->getLabel()) { + if (const Stmt* S = Dst->getLabel()) { PathDiagnosticLocation End(S, SMgr); switch (S->getStmtClass()) { @@ -593,17 +584,17 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, case Stmt::CaseStmtClass: { os << "Control jumps to 'case "; - CaseStmt* Case = cast(S); - Expr* LHS = Case->getLHS()->IgnoreParenCasts(); + const CaseStmt* Case = cast(S); + const Expr* LHS = Case->getLHS()->IgnoreParenCasts(); // Determine if it is an enum. bool GetRawInt = true; - if (DeclRefExpr* DR = dyn_cast(LHS)) { + if (const DeclRefExpr* DR = dyn_cast(LHS)) { // FIXME: Maybe this should be an assertion. Are there cases // were it is not an EnumConstantDecl? - EnumConstantDecl* D = - dyn_cast(DR->getDecl()); + const EnumConstantDecl* D = + dyn_cast(DR->getDecl()); if (D) { GetRawInt = false; @@ -668,12 +659,12 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, if (!PDB.supportsLogicalOpControlFlow()) break; - BinaryOperator *B = cast(T); + const BinaryOperator *B = cast(T); std::string sbuf; llvm::raw_string_ostream os(sbuf); os << "Left side of '"; - if (B->getOpcode() == BinaryOperator::LAnd) { + if (B->getOpcode() == BO_LAnd) { os << "&&" << "' is "; if (*(Src->succ_begin()+1) == Dst) { @@ -692,7 +683,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, } } else { - assert(B->getOpcode() == BinaryOperator::LOr); + assert(B->getOpcode() == BO_LOr); os << "||" << "' is "; if (*(Src->succ_begin()+1) == Dst) { @@ -902,8 +893,6 @@ class EdgeBuilder { CLocs.pop_back(); } - PathDiagnosticLocation IgnoreParens(const PathDiagnosticLocation &L); - public: EdgeBuilder(PathDiagnostic &pd, PathDiagnosticBuilder &pdb) : PD(pd), PDB(pdb) { @@ -935,10 +924,6 @@ public: void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false); - void addEdge(const Stmt *S, bool alwaysAdd = false) { - addEdge(PathDiagnosticLocation(S, PDB.getSourceManager()), alwaysAdd); - } - void rawAddEdge(PathDiagnosticLocation NewLoc); void addContext(const Stmt *S); @@ -1006,14 +991,6 @@ bool EdgeBuilder::containsLocation(const PathDiagnosticLocation &Container, SM.getInstantiationColumnNumber(ContainerREnd))); } -PathDiagnosticLocation -EdgeBuilder::IgnoreParens(const PathDiagnosticLocation &L) { - if (const Expr* E = dyn_cast_or_null(L.asStmt())) - return PathDiagnosticLocation(E->IgnoreParenCasts(), - PDB.getSourceManager()); - return L; -} - void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) { if (!PrevLoc.isValid()) { PrevLoc = NewLoc; diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp index 776e12b..91cf349 100644 --- a/lib/Checker/BugReporterVisitors.cpp +++ b/lib/Checker/BugReporterVisitors.cpp @@ -31,7 +31,7 @@ const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) { const Stmt *S = N->getLocationAs()->getStmt(); if (const UnaryOperator *U = dyn_cast(S)) { - if (U->getOpcode() == UnaryOperator::Deref) + if (U->getOpcode() == UO_Deref) return U->getSubExpr()->IgnoreParenCasts(); } else if (const MemberExpr *ME = dyn_cast(S)) { @@ -143,10 +143,9 @@ public: if (isa(V)) { bool b = false; - ASTContext &C = BRC.getASTContext(); if (R->isBoundable()) { if (const TypedRegion *TR = dyn_cast(R)) { - if (TR->getValueType(C)->isObjCObjectPointerType()) { + if (TR->getValueType()->isObjCObjectPointerType()) { os << "initialized to nil"; b = true; } @@ -174,10 +173,9 @@ public: if (os.str().empty()) { if (isa(V)) { bool b = false; - ASTContext &C = BRC.getASTContext(); if (R->isBoundable()) { if (const TypedRegion *TR = dyn_cast(R)) { - if (TR->getValueType(C)->isObjCObjectPointerType()) { + if (TR->getValueType()->isObjCObjectPointerType()) { os << "nil object reference stored to "; b = true; } @@ -209,7 +207,7 @@ public: ProgramPoint P = N->getLocation(); if (BlockEdge *BE = dyn_cast(&P)) { - CFGBlock *BSrc = BE->getSrc(); + const CFGBlock *BSrc = BE->getSrc(); S = BSrc->getTerminatorCondition(); } else if (PostStmt *PS = dyn_cast(&P)) { @@ -282,7 +280,7 @@ public: ProgramPoint P = N->getLocation(); if (BlockEdge *BE = dyn_cast(&P)) { - CFGBlock *BSrc = BE->getSrc(); + const CFGBlock *BSrc = BE->getSrc(); S = BSrc->getTerminatorCondition(); } else if (PostStmt *PS = dyn_cast(&P)) { @@ -421,3 +419,40 @@ public: void clang::bugreporter::registerNilReceiverVisitor(BugReporterContext &BRC) { BRC.addVisitor(new NilReceiverVisitor()); } + +// Registers every VarDecl inside a Stmt with a last store vistor. +void clang::bugreporter::registerVarDeclsLastStore(BugReporterContext &BRC, + const void *stmt, + const ExplodedNode *N) { + const Stmt *S = static_cast(stmt); + + std::deque WorkList; + + WorkList.push_back(S); + + while (!WorkList.empty()) { + const Stmt *Head = WorkList.front(); + WorkList.pop_front(); + + GRStateManager &StateMgr = BRC.getStateManager(); + const GRState *state = N->getState(); + + if (const DeclRefExpr *DR = dyn_cast(Head)) { + if (const VarDecl *VD = dyn_cast(DR->getDecl())) { + const VarRegion *R = + StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); + + // What did we load? + SVal V = state->getSVal(S); + + if (isa(V) || isa(V)) { + ::registerFindLastStore(BRC, R, V); + } + } + } + + for (Stmt::const_child_iterator I = Head->child_begin(); + I != Head->child_end(); ++I) + WorkList.push_back(*I); + } +} diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp index 3c74cd8..6fa48b2 100644 --- a/lib/Checker/CFRefCount.cpp +++ b/lib/Checker/CFRefCount.cpp @@ -82,8 +82,7 @@ public: static const ObjCMethodDecl* ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { - ObjCInterfaceDecl *ID = - const_cast(MD->getClassInterface()); + const ObjCInterfaceDecl *ID = MD->getClassInterface(); return MD->isInstanceMethod() ? ID->lookupInstanceMethod(MD->getSelector()) @@ -93,11 +92,11 @@ ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) { namespace { class GenericNodeBuilder { GRStmtNodeBuilder *SNB; - Stmt *S; + const Stmt *S; const void *tag; GREndPathNodeBuilder *ENB; public: - GenericNodeBuilder(GRStmtNodeBuilder &snb, Stmt *s, + GenericNodeBuilder(GRStmtNodeBuilder &snb, const Stmt *s, const void *t) : SNB(&snb), S(s), tag(t), ENB(0) {} @@ -195,12 +194,6 @@ public: static RetEffect MakeNoRet() { return RetEffect(NoRet); } - - void Profile(llvm::FoldingSetNodeID& ID) const { - ID.AddInteger((unsigned)K); - ID.AddInteger((unsigned)O); - ID.AddInteger(index); - } }; //===----------------------------------------------------------------------===// @@ -239,9 +232,6 @@ private: RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t) : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {} - RefVal(Kind k, unsigned cnt = 0) - : kind(k), okind(RetEffect::AnyObj), Cnt(cnt), ACnt(0) {} - public: Kind getKind() const { return kind; } @@ -256,12 +246,6 @@ public: QualType getType() const { return T; } - // Useful predicates. - - static bool isError(Kind k) { return k >= ERROR_START; } - - static bool isLeak(Kind k) { return k >= ERROR_LEAK_START; } - bool isOwned() const { return getKind() == Owned; } @@ -278,11 +262,6 @@ public: return getKind() == ReturnedNotOwned; } - bool isNonLeakError() const { - Kind k = getKind(); - return isError(k) && !isLeak(k); - } - static RefVal makeOwned(RetEffect::ObjKind o, QualType t, unsigned Count = 1) { return RefVal(Owned, o, Count, 0, t); @@ -474,11 +453,6 @@ public: DefaultArgEffect = E; } - /// setArg - Set the argument effect on the argument specified by idx. - void setArgEffect(ArgEffects::Factory& AF, unsigned idx, ArgEffect E) { - Args = AF.Add(Args, idx, E); - } - /// getRetEffect - Returns the effect on the return value of the call. RetEffect getRetEffect() const { return Ret; } @@ -492,28 +466,6 @@ public: /// getReceiverEffect - Returns the effect on the receiver of the call. /// This is only meaningful if the summary applies to an ObjCMessageExpr*. ArgEffect getReceiverEffect() const { return Receiver; } - - /// setReceiverEffect - Set the effect on the receiver of the call. - void setReceiverEffect(ArgEffect E) { Receiver = E; } - - typedef ArgEffects::iterator ExprIterator; - - ExprIterator begin_args() const { return Args.begin(); } - ExprIterator end_args() const { return Args.end(); } - - static void Profile(llvm::FoldingSetNodeID& ID, ArgEffects A, - RetEffect RetEff, ArgEffect DefaultEff, - ArgEffect ReceiverEff, bool EndPath) { - ID.Add(A); - ID.Add(RetEff); - ID.AddInteger((unsigned) DefaultEff); - ID.AddInteger((unsigned) ReceiverEff); - ID.AddInteger((unsigned) EndPath); - } - - void Profile(llvm::FoldingSetNodeID& ID) const { - Profile(ID, Args, Ret, DefaultArgEffect, Receiver, EndPath); - } }; } // end anonymous namespace @@ -618,11 +570,6 @@ public: return Summ; } - - RetainSummary* find(Expr* Receiver, Selector S) { - return find(getReceiverDecl(Receiver), S); - } - RetainSummary* find(IdentifierInfo* II, Selector S) { // FIXME: Class method lookup. Right now we dont' have a good way // of going between IdentifierInfo* and the class hierarchy. @@ -634,47 +581,6 @@ public: return I == M.end() ? NULL : I->second; } - const ObjCInterfaceDecl* getReceiverDecl(Expr* E) { - if (const ObjCObjectPointerType* PT = - E->getType()->getAs()) - return PT->getInterfaceDecl(); - - return NULL; - } - - RetainSummary*& operator[](ObjCMessageExpr* ME) { - - Selector S = ME->getSelector(); - - const ObjCInterfaceDecl* OD = 0; - bool IsInstanceMessage = false; - switch (ME->getReceiverKind()) { - case ObjCMessageExpr::Instance: - OD = getReceiverDecl(ME->getInstanceReceiver()); - IsInstanceMessage = true; - break; - - case ObjCMessageExpr::SuperInstance: - IsInstanceMessage = true; - OD = ME->getSuperType()->getAs() - ->getInterfaceDecl(); - break; - - case ObjCMessageExpr::Class: - OD = ME->getClassReceiver()->getAs()->getInterface(); - break; - - case ObjCMessageExpr::SuperClass: - OD = ME->getSuperType()->getAs()->getInterface(); - break; - } - - if (IsInstanceMessage) - return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S]; - - return M[ObjCSummaryKey(OD->getIdentifier(), S)]; - } - RetainSummary*& operator[](ObjCSummaryKey K) { return M[K]; } @@ -696,7 +602,7 @@ class RetainSummaryManager { // Typedefs. //==-----------------------------------------------------------------==// - typedef llvm::DenseMap + typedef llvm::DenseMap FuncSummariesTy; typedef ObjCSummaryCache ObjCMethodSummariesTy; @@ -766,9 +672,10 @@ public: RetainSummary* getUnarySummary(const FunctionType* FT, UnaryFuncKind func); - RetainSummary* getCFSummaryCreateRule(FunctionDecl* FD); - RetainSummary* getCFSummaryGetRule(FunctionDecl* FD); - RetainSummary* getCFCreateGetRuleSummary(FunctionDecl* FD, StringRef FName); + RetainSummary* getCFSummaryCreateRule(const FunctionDecl* FD); + RetainSummary* getCFSummaryGetRule(const FunctionDecl* FD); + RetainSummary* getCFCreateGetRuleSummary(const FunctionDecl* FD, + StringRef FName); RetainSummary* getPersistentSummary(ArgEffects AE, RetEffect RetEff, ArgEffect ReceiverEff = DoNothing, @@ -796,12 +703,6 @@ public: void InitializeClassMethodSummaries(); void InitializeMethodSummaries(); private: - - void addClsMethSummary(IdentifierInfo* ClsII, Selector S, - RetainSummary* Summ) { - ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; - } - void addNSObjectClsMethSummary(Selector S, RetainSummary *Summ) { ObjCClassMethodSummaries[S] = Summ; } @@ -892,7 +793,7 @@ public: ~RetainSummaryManager(); - RetainSummary* getSummary(FunctionDecl* FD); + RetainSummary* getSummary(const FunctionDecl* FD); RetainSummary *getInstanceMethodSummary(const ObjCMessageExpr *ME, const GRState *state, @@ -999,15 +900,15 @@ RetainSummaryManager::getPersistentSummary(ArgEffects AE, RetEffect RetEff, // Summary creation for functions (largely uses of Core Foundation). //===----------------------------------------------------------------------===// -static bool isRetain(FunctionDecl* FD, StringRef FName) { +static bool isRetain(const FunctionDecl* FD, StringRef FName) { return FName.endswith("Retain"); } -static bool isRelease(FunctionDecl* FD, StringRef FName) { +static bool isRelease(const FunctionDecl* FD, StringRef FName) { return FName.endswith("Release"); } -RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { +RetainSummary* RetainSummaryManager::getSummary(const FunctionDecl* FD) { // Look up a summary in our cache of FunctionDecls -> Summaries. FuncSummariesTy::iterator I = FuncSummaries.find(FD); if (I != FuncSummaries.end()) @@ -1201,7 +1102,7 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) { } RetainSummary* -RetainSummaryManager::getCFCreateGetRuleSummary(FunctionDecl* FD, +RetainSummaryManager::getCFCreateGetRuleSummary(const FunctionDecl* FD, StringRef FName) { if (FName.find("Create") != StringRef::npos || @@ -1250,7 +1151,8 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT, } } -RetainSummary* RetainSummaryManager::getCFSummaryCreateRule(FunctionDecl* FD) { +RetainSummary* +RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl* FD) { assert (ScratchArgs.isEmpty()); if (FD->getIdentifier() == CFDictionaryCreateII) { @@ -1261,7 +1163,8 @@ RetainSummary* RetainSummaryManager::getCFSummaryCreateRule(FunctionDecl* FD) { return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); } -RetainSummary* RetainSummaryManager::getCFSummaryGetRule(FunctionDecl* FD) { +RetainSummary* +RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl* FD) { assert (ScratchArgs.isEmpty()); return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF), DoNothing, DoNothing); @@ -1767,7 +1670,7 @@ private: void ProcessNonLeakError(ExplodedNodeSet& Dst, GRStmtNodeBuilder& Builder, - Expr* NodeExpr, SourceRange ErrorRange, + const Expr* NodeExpr, SourceRange ErrorRange, ExplodedNode* Pred, const GRState* St, RefVal::Kind hasErr, SymbolRef Sym); @@ -1810,33 +1713,26 @@ public: void EvalSummary(ExplodedNodeSet& Dst, GRExprEngine& Eng, GRStmtNodeBuilder& Builder, - Expr* Ex, + const Expr* Ex, InstanceReceiver Receiver, const RetainSummary& Summ, const MemRegion *Callee, - ExprIterator arg_beg, ExprIterator arg_end, + ConstExprIterator arg_beg, ConstExprIterator arg_end, ExplodedNode* Pred, const GRState *state); virtual void EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Eng, GRStmtNodeBuilder& Builder, - CallExpr* CE, SVal L, + const CallExpr* CE, SVal L, ExplodedNode* Pred); virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Engine, GRStmtNodeBuilder& Builder, - ObjCMessageExpr* ME, + const ObjCMessageExpr* ME, ExplodedNode* Pred, const GRState *state); - - bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst, - GRExprEngine& Engine, - GRStmtNodeBuilder& Builder, - ObjCMessageExpr* ME, - ExplodedNode* Pred); - // Stores. virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val); @@ -1861,7 +1757,7 @@ public: virtual void EvalReturn(ExplodedNodeSet& Dst, GRExprEngine& Engine, GRStmtNodeBuilder& Builder, - ReturnStmt* S, + const ReturnStmt* S, ExplodedNode* Pred); // Assumptions. @@ -1934,7 +1830,6 @@ namespace { public: CFRefCount& getTF() { return TF; } - const CFRefCount& getTF() const { return TF; } // FIXME: Eventually remove. virtual const char* getDescription() const = 0; @@ -2049,9 +1944,6 @@ namespace { CFRefBug& getBugType() { return (CFRefBug&) RangedBugReport::getBugType(); } - const CFRefBug& getBugType() const { - return (const CFRefBug&) RangedBugReport::getBugType(); - } virtual void getRanges(const SourceRange*& beg, const SourceRange*& end) { if (!getBugType().isLeak()) @@ -2605,11 +2497,12 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) { void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, GRExprEngine& Eng, GRStmtNodeBuilder& Builder, - Expr* Ex, + const Expr* Ex, InstanceReceiver Receiver, const RetainSummary& Summ, const MemRegion *Callee, - ExprIterator arg_beg, ExprIterator arg_end, + ConstExprIterator arg_beg, + ConstExprIterator arg_end, ExplodedNode* Pred, const GRState *state) { // Evaluate the effect of the arguments. @@ -2620,19 +2513,25 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, llvm::SmallVector RegionsToInvalidate; - for (ExprIterator I = arg_beg; I != arg_end; ++I, ++idx) { + // HACK: Symbols that have ref-count state that are referenced directly + // (not as structure or array elements, or via bindings) by an argument + // should not have their ref-count state stripped after we have + // done an invalidation pass. + llvm::DenseSet WhitelistedSymbols; + + for (ConstExprIterator I = arg_beg; I != arg_end; ++I, ++idx) { SVal V = state->getSValAsScalarOrLoc(*I); SymbolRef Sym = V.getAsLocSymbol(); if (Sym) if (RefBindings::data_type* T = state->get(Sym)) { + WhitelistedSymbols.insert(Sym); state = Update(state, Sym, *T, Summ.getArg(idx), hasErr); if (hasErr) { ErrorRange = (*I)->getSourceRange(); ErrorSym = Sym; break; } - continue; } tryAgain: @@ -2703,22 +2602,22 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, // expression (the context) and the expression itself. This should // disambiguate conjured symbols. unsigned Count = Builder.getCurrentBlockCount(); - StoreManager& StoreMgr = Eng.getStateManager().getStoreManager(); StoreManager::InvalidatedSymbols IS; - Store store = state->getStore(); // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate // global variables. - store = StoreMgr.InvalidateRegions(store, RegionsToInvalidate.data(), - RegionsToInvalidate.data() + - RegionsToInvalidate.size(), - Ex, Count, &IS, - /* invalidateGlobals = */ true); + state = state->InvalidateRegions(RegionsToInvalidate.data(), + RegionsToInvalidate.data() + + RegionsToInvalidate.size(), + Ex, Count, &IS, + /* invalidateGlobals = */ true); - state = state->makeWithStore(store); for (StoreManager::InvalidatedSymbols::iterator I = IS.begin(), E = IS.end(); I!=E; ++I) { - // Remove any existing reference-count binding. + SymbolRef sym = *I; + if (WhitelistedSymbols.count(sym)) + continue; + // Remove any existing reference-count binding. state = state->remove(*I); } @@ -2860,7 +2759,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst, void CFRefCount::EvalCall(ExplodedNodeSet& Dst, GRExprEngine& Eng, GRStmtNodeBuilder& Builder, - CallExpr* CE, SVal L, + const CallExpr* CE, SVal L, ExplodedNode* Pred) { RetainSummary *Summ = 0; @@ -2874,7 +2773,7 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst, else { const FunctionDecl* FD = L.getAsFunctionDecl(); Summ = !FD ? Summaries.getDefaultSummary() : - Summaries.getSummary(const_cast(FD)); + Summaries.getSummary(FD); } assert(Summ); @@ -2885,7 +2784,7 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst, void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst, GRExprEngine& Eng, GRStmtNodeBuilder& Builder, - ObjCMessageExpr* ME, + const ObjCMessageExpr* ME, ExplodedNode* Pred, const GRState *state) { RetainSummary *Summ = @@ -2956,10 +2855,10 @@ void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, GRExprEngine& Eng, GRStmtNodeBuilder& Builder, - ReturnStmt* S, + const ReturnStmt* S, ExplodedNode* Pred) { - Expr* RetE = S->getRetValue(); + const Expr* RetE = S->getRetValue(); if (!RetE) return; @@ -3404,7 +3303,7 @@ void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst, ExplodedNode* Pred, const GRState* state, SymbolReaper& SymReaper) { - Stmt *S = Builder.getStmt(); + const Stmt *S = Builder.getStmt(); RefBindings B = state->get(); // Update counts from autorelease pools @@ -3454,7 +3353,8 @@ void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst, void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, GRStmtNodeBuilder& Builder, - Expr* NodeExpr, SourceRange ErrorRange, + const Expr* NodeExpr, + SourceRange ErrorRange, ExplodedNode* Pred, const GRState* St, RefVal::Kind hasErr, SymbolRef Sym) { diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt index 259346a..5b54f0d 100644 --- a/lib/Checker/CMakeLists.txt +++ b/lib/Checker/CMakeLists.txt @@ -4,6 +4,7 @@ add_clang_library(clangChecker AdjustedReturnValueChecker.cpp AggExprVisitor.cpp AnalysisConsumer.cpp + AnalysisManager.cpp ArrayBoundChecker.cpp AttrNonNullChecker.cpp BasicConstraintManager.cpp @@ -15,7 +16,6 @@ add_clang_library(clangChecker BuiltinFunctionChecker.cpp CFRefCount.cpp CallAndMessageChecker.cpp - CallInliner.cpp CastSizeChecker.cpp CastToStructChecker.cpp CheckDeadStores.cpp @@ -24,6 +24,7 @@ add_clang_library(clangChecker CheckSecuritySyntaxOnly.cpp CheckSizeofPointer.cpp Checker.cpp + CheckerHelpers.cpp CocoaConventions.cpp CStringChecker.cpp DereferenceChecker.cpp @@ -74,6 +75,7 @@ add_clang_library(clangChecker UndefinedArraySubscriptChecker.cpp UndefinedAssignmentChecker.cpp UnixAPIChecker.cpp + UnreachableCodeChecker.cpp VLASizeChecker.cpp ValueManager.cpp ) diff --git a/lib/Checker/CStringChecker.cpp b/lib/Checker/CStringChecker.cpp index a92d409..9ea572f 100644 --- a/lib/Checker/CStringChecker.cpp +++ b/lib/Checker/CStringChecker.cpp @@ -15,19 +15,30 @@ #include "GRExprEngineExperimentalChecks.h" #include "clang/Checker/BugReporter/BugType.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRStateTrait.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; namespace { class CStringChecker : public CheckerVisitor { - BugType *BT_Null, *BT_Bounds, *BT_Overlap; + BugType *BT_Null, *BT_Bounds, *BT_BoundsWrite, *BT_Overlap, *BT_NotCString; public: CStringChecker() - : BT_Null(0), BT_Bounds(0), BT_Overlap(0) {} + : BT_Null(0), BT_Bounds(0), BT_BoundsWrite(0), BT_Overlap(0), BT_NotCString(0) + {} static void *getTag() { static int tag; return &tag; } bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); + void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS); + void MarkLiveSymbols(const GRState *state, SymbolReaper &SR); + void EvalDeadSymbols(CheckerContext &C, SymbolReaper &SR); + bool WantsRegionChangeUpdate(const GRState *state); + + const GRState *EvalRegionChanges(const GRState *state, + const MemRegion * const *Begin, + const MemRegion * const *End, + bool*); typedef void (CStringChecker::*FnCheck)(CheckerContext &, const CallExpr *); @@ -40,26 +51,61 @@ public: void EvalMemcmp(CheckerContext &C, const CallExpr *CE); + void EvalStrlen(CheckerContext &C, const CallExpr *CE); + + void EvalStrcpy(CheckerContext &C, const CallExpr *CE); + void EvalStpcpy(CheckerContext &C, const CallExpr *CE); + void EvalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool ReturnEnd); + // Utility methods std::pair AssumeZero(CheckerContext &C, const GRState *state, SVal V, QualType Ty); + const GRState *SetCStringLength(const GRState *state, const MemRegion *MR, + SVal StrLen); + SVal GetCStringLengthForRegion(CheckerContext &C, const GRState *&state, + const Expr *Ex, const MemRegion *MR); + SVal GetCStringLength(CheckerContext &C, const GRState *&state, + const Expr *Ex, SVal Buf); + + const GRState *InvalidateBuffer(CheckerContext &C, const GRState *state, + const Expr *Ex, SVal V); + + bool SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx, + const MemRegion *MR); + + // Re-usable checks const GRState *CheckNonNull(CheckerContext &C, const GRState *state, const Expr *S, SVal l); const GRState *CheckLocation(CheckerContext &C, const GRState *state, - const Expr *S, SVal l); + const Expr *S, SVal l, + bool IsDestination = false); const GRState *CheckBufferAccess(CheckerContext &C, const GRState *state, const Expr *Size, const Expr *FirstBuf, - const Expr *SecondBuf = NULL); + const Expr *SecondBuf = NULL, + bool FirstIsDestination = false); const GRState *CheckOverlap(CheckerContext &C, const GRState *state, const Expr *Size, const Expr *First, const Expr *Second); void EmitOverlapBug(CheckerContext &C, const GRState *state, const Stmt *First, const Stmt *Second); }; + +class CStringLength { +public: + typedef llvm::ImmutableMap EntryMap; +}; } //end anonymous namespace +namespace clang { + template <> + struct GRStateTrait + : public GRStatePartialTrait { + static void *GDMIndex() { return CStringChecker::getTag(); } + }; +} + void clang::RegisterCStringChecker(GRExprEngine &Eng) { Eng.registerCheck(new CStringChecker()); } @@ -122,7 +168,8 @@ const GRState *CStringChecker::CheckNonNull(CheckerContext &C, // FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor? const GRState *CStringChecker::CheckLocation(CheckerContext &C, const GRState *state, - const Expr *S, SVal l) { + const Expr *S, SVal l, + bool IsDestination) { // If a previous check has failed, propagate the failure. if (!state) return NULL; @@ -136,7 +183,7 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C, if (!ER) return state; - assert(ER->getValueType(C.getASTContext()) == C.getASTContext().CharTy && + assert(ER->getValueType() == C.getASTContext().CharTy && "CheckLocation should only be called with char* ElementRegions"); // Get the size of the array. @@ -155,17 +202,26 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C, if (!N) return NULL; - if (!BT_Bounds) - BT_Bounds = new BuiltinBug("Out-of-bound array access", - "Byte string function accesses out-of-bound array element " - "(buffer overflow)"); + BuiltinBug *BT; + if (IsDestination) { + if (!BT_BoundsWrite) { + BT_BoundsWrite = new BuiltinBug("Out-of-bound array access", + "Byte string function overflows destination buffer"); + } + BT = static_cast(BT_BoundsWrite); + } else { + if (!BT_Bounds) { + BT_Bounds = new BuiltinBug("Out-of-bound array access", + "Byte string function accesses out-of-bound array element"); + } + BT = static_cast(BT_Bounds); + } // FIXME: It would be nice to eventually make this diagnostic more clear, // e.g., by referencing the original declaration or by saying *why* this // reference is outside the range. // Generate a report for this bug. - BuiltinBug *BT = static_cast(BT_Bounds); RangedBugReport *report = new RangedBugReport(*BT, BT->getDescription(), N); report->addRange(S->getSourceRange()); @@ -182,7 +238,8 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C, const GRState *state, const Expr *Size, const Expr *FirstBuf, - const Expr *SecondBuf) { + const Expr *SecondBuf, + bool FirstIsDestination) { // If a previous check has failed, propagate the failure. if (!state) return NULL; @@ -191,7 +248,7 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C, SValuator &SV = VM.getSValuator(); ASTContext &Ctx = C.getASTContext(); - QualType SizeTy = Ctx.getSizeType(); + QualType SizeTy = Size->getType(); QualType PtrTy = Ctx.getPointerType(Ctx.CharTy); // Check that the first buffer is non-null. @@ -208,18 +265,20 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C, // Compute the offset of the last element to be accessed: size-1. NonLoc One = cast(VM.makeIntVal(1, SizeTy)); - NonLoc LastOffset = cast(SV.EvalBinOpNN(state, BinaryOperator::Sub, + NonLoc LastOffset = cast(SV.EvalBinOpNN(state, BO_Sub, *Length, One, SizeTy)); // Check that the first buffer is sufficently long. - Loc BufStart = cast(SV.EvalCast(BufVal, PtrTy, FirstBuf->getType())); - SVal BufEnd - = SV.EvalBinOpLN(state, BinaryOperator::Add, BufStart, LastOffset, PtrTy); - state = CheckLocation(C, state, FirstBuf, BufEnd); + SVal BufStart = SV.EvalCast(BufVal, PtrTy, FirstBuf->getType()); + if (Loc *BufLoc = dyn_cast(&BufStart)) { + SVal BufEnd = SV.EvalBinOpLN(state, BO_Add, *BufLoc, + LastOffset, PtrTy); + state = CheckLocation(C, state, FirstBuf, BufEnd, FirstIsDestination); - // If the buffer isn't large enough, abort. - if (!state) - return NULL; + // If the buffer isn't large enough, abort. + if (!state) + return NULL; + } // If there's a second buffer, check it as well. if (SecondBuf) { @@ -228,10 +287,12 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C, if (!state) return NULL; - BufStart = cast(SV.EvalCast(BufVal, PtrTy, SecondBuf->getType())); - BufEnd - = SV.EvalBinOpLN(state, BinaryOperator::Add, BufStart, LastOffset, PtrTy); - state = CheckLocation(C, state, SecondBuf, BufEnd); + BufStart = SV.EvalCast(BufVal, PtrTy, SecondBuf->getType()); + if (Loc *BufLoc = dyn_cast(&BufStart)) { + SVal BufEnd = SV.EvalBinOpLN(state, BO_Add, *BufLoc, + LastOffset, PtrTy); + state = CheckLocation(C, state, SecondBuf, BufEnd); + } } // Large enough or not, return this state! @@ -284,7 +345,7 @@ const GRState *CStringChecker::CheckOverlap(CheckerContext &C, // Which value comes first? QualType CmpTy = Ctx.IntTy; - SVal Reverse = SV.EvalBinOpLL(state, BinaryOperator::GT, + SVal Reverse = SV.EvalBinOpLL(state, BO_GT, *FirstLoc, *SecondLoc, CmpTy); DefinedOrUnknownSVal *ReverseTest = dyn_cast(&Reverse); if (!ReverseTest) @@ -324,14 +385,14 @@ const GRState *CStringChecker::CheckOverlap(CheckerContext &C, return state; // Compute the end of the first buffer. Bail out if THAT fails. - SVal FirstEnd = SV.EvalBinOpLN(state, BinaryOperator::Add, + SVal FirstEnd = SV.EvalBinOpLN(state, BO_Add, *FirstStartLoc, *Length, CharPtrTy); Loc *FirstEndLoc = dyn_cast(&FirstEnd); if (!FirstEndLoc) return state; // Is the end of the first buffer past the start of the second buffer? - SVal Overlap = SV.EvalBinOpLL(state, BinaryOperator::GT, + SVal Overlap = SV.EvalBinOpLL(state, BO_GT, *FirstEndLoc, *SecondLoc, CmpTy); DefinedOrUnknownSVal *OverlapTest = dyn_cast(&Overlap); if (!OverlapTest) @@ -369,6 +430,222 @@ void CStringChecker::EmitOverlapBug(CheckerContext &C, const GRState *state, C.EmitReport(report); } +const GRState *CStringChecker::SetCStringLength(const GRState *state, + const MemRegion *MR, + SVal StrLen) { + assert(!StrLen.isUndef() && "Attempt to set an undefined string length"); + if (StrLen.isUnknown()) + return state; + + MR = MR->StripCasts(); + + switch (MR->getKind()) { + case MemRegion::StringRegionKind: + // FIXME: This can happen if we strcpy() into a string region. This is + // undefined [C99 6.4.5p6], but we should still warn about it. + return state; + + case MemRegion::SymbolicRegionKind: + case MemRegion::AllocaRegionKind: + case MemRegion::VarRegionKind: + case MemRegion::FieldRegionKind: + case MemRegion::ObjCIvarRegionKind: + return state->set(MR, StrLen); + + case MemRegion::ElementRegionKind: + // FIXME: Handle element regions by upper-bounding the parent region's + // string length. + return state; + + default: + // Other regions (mostly non-data) can't have a reliable C string length. + // For now, just ignore the change. + // FIXME: These are rare but not impossible. We should output some kind of + // warning for things like strcpy((char[]){'a', 0}, "b"); + return state; + } +} + +SVal CStringChecker::GetCStringLengthForRegion(CheckerContext &C, + const GRState *&state, + const Expr *Ex, + const MemRegion *MR) { + // If there's a recorded length, go ahead and return it. + const SVal *Recorded = state->get(MR); + if (Recorded) + return *Recorded; + + // Otherwise, get a new symbol and update the state. + unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + ValueManager &ValMgr = C.getValueManager(); + QualType SizeTy = ValMgr.getContext().getSizeType(); + SVal Strlen = ValMgr.getMetadataSymbolVal(getTag(), MR, Ex, SizeTy, Count); + + state = state->set(MR, Strlen); + return Strlen; +} + +SVal CStringChecker::GetCStringLength(CheckerContext &C, const GRState *&state, + const Expr *Ex, SVal Buf) { + const MemRegion *MR = Buf.getAsRegion(); + if (!MR) { + // If we can't get a region, see if it's something we /know/ isn't a + // C string. In the context of locations, the only time we can issue such + // a warning is for labels. + if (loc::GotoLabel *Label = dyn_cast(&Buf)) { + if (ExplodedNode *N = C.GenerateNode(state)) { + if (!BT_NotCString) + BT_NotCString = new BuiltinBug("API", + "Argument is not a null-terminated string."); + + llvm::SmallString<120> buf; + llvm::raw_svector_ostream os(buf); + os << "Argument to byte string function is the address of the label '" + << Label->getLabel()->getID()->getName() + << "', which is not a null-terminated string"; + + // Generate a report for this bug. + EnhancedBugReport *report = new EnhancedBugReport(*BT_NotCString, + os.str(), N); + + report->addRange(Ex->getSourceRange()); + C.EmitReport(report); + } + + return UndefinedVal(); + } + + // If it's not a region and not a label, give up. + return UnknownVal(); + } + + // If we have a region, strip casts from it and see if we can figure out + // its length. For anything we can't figure out, just return UnknownVal. + MR = MR->StripCasts(); + + switch (MR->getKind()) { + case MemRegion::StringRegionKind: { + // Modifying the contents of string regions is undefined [C99 6.4.5p6], + // so we can assume that the byte length is the correct C string length. + ValueManager &ValMgr = C.getValueManager(); + QualType SizeTy = ValMgr.getContext().getSizeType(); + const StringLiteral *Str = cast(MR)->getStringLiteral(); + return ValMgr.makeIntVal(Str->getByteLength(), SizeTy); + } + case MemRegion::SymbolicRegionKind: + case MemRegion::AllocaRegionKind: + case MemRegion::VarRegionKind: + case MemRegion::FieldRegionKind: + case MemRegion::ObjCIvarRegionKind: + return GetCStringLengthForRegion(C, state, Ex, MR); + case MemRegion::CompoundLiteralRegionKind: + // FIXME: Can we track this? Is it necessary? + return UnknownVal(); + case MemRegion::ElementRegionKind: + // FIXME: How can we handle this? It's not good enough to subtract the + // offset from the base string length; consider "123\x00567" and &a[5]. + return UnknownVal(); + default: + // Other regions (mostly non-data) can't have a reliable C string length. + // In this case, an error is emitted and UndefinedVal is returned. + // The caller should always be prepared to handle this case. + if (ExplodedNode *N = C.GenerateNode(state)) { + if (!BT_NotCString) + BT_NotCString = new BuiltinBug("API", + "Argument is not a null-terminated string."); + + llvm::SmallString<120> buf; + llvm::raw_svector_ostream os(buf); + + os << "Argument to byte string function is "; + + if (SummarizeRegion(os, C.getASTContext(), MR)) + os << ", which is not a null-terminated string"; + else + os << "not a null-terminated string"; + + // Generate a report for this bug. + EnhancedBugReport *report = new EnhancedBugReport(*BT_NotCString, + os.str(), N); + + report->addRange(Ex->getSourceRange()); + C.EmitReport(report); + } + + return UndefinedVal(); + } +} + +const GRState *CStringChecker::InvalidateBuffer(CheckerContext &C, + const GRState *state, + const Expr *E, SVal V) { + Loc *L = dyn_cast(&V); + if (!L) + return state; + + // FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes + // some assumptions about the value that CFRefCount can't. Even so, it should + // probably be refactored. + if (loc::MemRegionVal* MR = dyn_cast(L)) { + const MemRegion *R = MR->getRegion()->StripCasts(); + + // Are we dealing with an ElementRegion? If so, we should be invalidating + // the super-region. + if (const ElementRegion *ER = dyn_cast(R)) { + R = ER->getSuperRegion(); + // FIXME: What about layers of ElementRegions? + } + + // Invalidate this region. + unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + return state->InvalidateRegion(R, E, Count, NULL); + } + + // If we have a non-region value by chance, just remove the binding. + // FIXME: is this necessary or correct? This handles the non-Region + // cases. Is it ever valid to store to these? + return state->unbindLoc(*L); +} + +bool CStringChecker::SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx, + const MemRegion *MR) { + const TypedRegion *TR = dyn_cast(MR); + if (!TR) + return false; + + switch (TR->getKind()) { + case MemRegion::FunctionTextRegionKind: { + const FunctionDecl *FD = cast(TR)->getDecl(); + if (FD) + os << "the address of the function '" << FD << "'"; + else + os << "the address of a function"; + return true; + } + case MemRegion::BlockTextRegionKind: + os << "block text"; + return true; + case MemRegion::BlockDataRegionKind: + os << "a block"; + return true; + case MemRegion::CXXThisRegionKind: + case MemRegion::CXXObjectRegionKind: + os << "a C++ object of type " << TR->getValueType().getAsString(); + return true; + case MemRegion::VarRegionKind: + os << "a variable of type" << TR->getValueType().getAsString(); + return true; + case MemRegion::FieldRegionKind: + os << "a field of type " << TR->getValueType().getAsString(); + return true; + case MemRegion::ObjCIvarRegionKind: + os << "an instance variable of type " << TR->getValueType().getAsString(); + return true; + default: + return false; + } +} + //===----------------------------------------------------------------------===// // Evaluation of individual function calls. //===----------------------------------------------------------------------===// @@ -390,11 +667,20 @@ void CStringChecker::EvalCopyCommon(CheckerContext &C, const GRState *state, // If the size can be nonzero, we have to check the other arguments. if (StNonZeroSize) { state = StNonZeroSize; - state = CheckBufferAccess(C, state, Size, Dest, Source); + state = CheckBufferAccess(C, state, Size, Dest, Source, + /* FirstIsDst = */ true); if (Restricted) state = CheckOverlap(C, state, Size, Dest, Source); - if (state) + + if (state) { + // Invalidate the destination. + // FIXME: Even if we can't perfectly model the copy, we should see if we + // can use LazyCompoundVals to copy the source values into the destination. + // This would probably remove any existing bindings past the end of the + // copied region, but that's still an improvement over blank invalidation. + state = InvalidateBuffer(C, state, Dest, state->getSVal(Dest)); C.addTransition(state); + } } } @@ -481,7 +767,7 @@ void CStringChecker::EvalMemcmp(CheckerContext &C, const CallExpr *CE) { if (state) { // The return value is the comparison result, which we don't know. unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); - SVal CmpV = ValMgr.getConjuredSymbolVal(NULL, CE, CE->getType(), Count); + SVal CmpV = ValMgr.getConjuredSymbolVal(NULL, CE, Count); state = state->BindExpr(CE, CmpV); C.addTransition(state); } @@ -489,8 +775,123 @@ void CStringChecker::EvalMemcmp(CheckerContext &C, const CallExpr *CE) { } } +void CStringChecker::EvalStrlen(CheckerContext &C, const CallExpr *CE) { + // size_t strlen(const char *s); + const GRState *state = C.getState(); + const Expr *Arg = CE->getArg(0); + SVal ArgVal = state->getSVal(Arg); + + // Check that the argument is non-null. + state = CheckNonNull(C, state, Arg, ArgVal); + + if (state) { + SVal StrLen = GetCStringLength(C, state, Arg, ArgVal); + + // If the argument isn't a valid C string, there's no valid state to + // transition to. + if (StrLen.isUndef()) + return; + + // If GetCStringLength couldn't figure out the length, conjure a return + // value, so it can be used in constraints, at least. + if (StrLen.isUnknown()) { + ValueManager &ValMgr = C.getValueManager(); + unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + StrLen = ValMgr.getConjuredSymbolVal(NULL, CE, Count); + } + + // Bind the return value. + state = state->BindExpr(CE, StrLen); + C.addTransition(state); + } +} + +void CStringChecker::EvalStrcpy(CheckerContext &C, const CallExpr *CE) { + // char *strcpy(char *restrict dst, const char *restrict src); + EvalStrcpyCommon(C, CE, /* ReturnEnd = */ false); +} + +void CStringChecker::EvalStpcpy(CheckerContext &C, const CallExpr *CE) { + // char *stpcpy(char *restrict dst, const char *restrict src); + EvalStrcpyCommon(C, CE, /* ReturnEnd = */ true); +} + +void CStringChecker::EvalStrcpyCommon(CheckerContext &C, const CallExpr *CE, + bool ReturnEnd) { + const GRState *state = C.getState(); + + // Check that the destination is non-null + const Expr *Dst = CE->getArg(0); + SVal DstVal = state->getSVal(Dst); + + state = CheckNonNull(C, state, Dst, DstVal); + if (!state) + return; + + // Check that the source is non-null. + const Expr *Src = CE->getArg(1); + SVal SrcVal = state->getSVal(Src); + + state = CheckNonNull(C, state, Src, SrcVal); + if (!state) + return; + + // Get the string length of the source. + SVal StrLen = GetCStringLength(C, state, Src, SrcVal); + + // If the source isn't a valid C string, give up. + if (StrLen.isUndef()) + return; + + SVal Result = (ReturnEnd ? UnknownVal() : DstVal); + + // If the destination is a MemRegion, try to check for a buffer overflow and + // record the new string length. + if (loc::MemRegionVal *DstRegVal = dyn_cast(&DstVal)) { + // If the length is known, we can check for an overflow. + if (NonLoc *KnownStrLen = dyn_cast(&StrLen)) { + SValuator &SV = C.getSValuator(); + + SVal LastElement = SV.EvalBinOpLN(state, BO_Add, + *DstRegVal, *KnownStrLen, + Dst->getType()); + + state = CheckLocation(C, state, Dst, LastElement, /* IsDst = */ true); + if (!state) + return; + + // If this is a stpcpy-style copy, the last element is the return value. + if (ReturnEnd) + Result = LastElement; + } + + // Invalidate the destination. This must happen before we set the C string + // length because invalidation will clear the length. + // FIXME: Even if we can't perfectly model the copy, we should see if we + // can use LazyCompoundVals to copy the source values into the destination. + // This would probably remove any existing bindings past the end of the + // string, but that's still an improvement over blank invalidation. + state = InvalidateBuffer(C, state, Dst, *DstRegVal); + + // Set the C string length of the destination. + state = SetCStringLength(state, DstRegVal->getRegion(), StrLen); + } + + // If this is a stpcpy-style copy, but we were unable to check for a buffer + // overflow, we still need a result. Conjure a return value. + if (ReturnEnd && Result.isUnknown()) { + ValueManager &ValMgr = C.getValueManager(); + unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); + StrLen = ValMgr.getConjuredSymbolVal(NULL, CE, Count); + } + + // Set the return value. + state = state->BindExpr(CE, Result); + C.addTransition(state); +} + //===----------------------------------------------------------------------===// -// The driver method. +// The driver method, and other Checker callbacks. //===----------------------------------------------------------------------===// bool CStringChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { @@ -512,6 +913,9 @@ bool CStringChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { .Cases("memcpy", "__memcpy_chk", &CStringChecker::EvalMemcpy) .Cases("memcmp", "bcmp", &CStringChecker::EvalMemcmp) .Cases("memmove", "__memmove_chk", &CStringChecker::EvalMemmove) + .Cases("strcpy", "__strcpy_chk", &CStringChecker::EvalStrcpy) + .Cases("stpcpy", "__stpcpy_chk", &CStringChecker::EvalStpcpy) + .Case("strlen", &CStringChecker::EvalStrlen) .Case("bcopy", &CStringChecker::EvalBcopy) .Default(NULL); @@ -523,3 +927,129 @@ bool CStringChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { (this->*EvalFunction)(C, CE); return true; } + +void CStringChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { + // Record string length for char a[] = "abc"; + const GRState *state = C.getState(); + + for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end(); + I != E; ++I) { + const VarDecl *D = dyn_cast(*I); + if (!D) + continue; + + // FIXME: Handle array fields of structs. + if (!D->getType()->isArrayType()) + continue; + + const Expr *Init = D->getInit(); + if (!Init) + continue; + if (!isa(Init)) + continue; + + Loc VarLoc = state->getLValue(D, C.getPredecessor()->getLocationContext()); + const MemRegion *MR = VarLoc.getAsRegion(); + if (!MR) + continue; + + SVal StrVal = state->getSVal(Init); + assert(StrVal.isValid() && "Initializer string is unknown or undefined"); + DefinedOrUnknownSVal StrLen + = cast(GetCStringLength(C, state, Init, StrVal)); + + state = state->set(MR, StrLen); + } + + C.addTransition(state); +} + +bool CStringChecker::WantsRegionChangeUpdate(const GRState *state) { + CStringLength::EntryMap Entries = state->get(); + return !Entries.isEmpty(); +} + +const GRState *CStringChecker::EvalRegionChanges(const GRState *state, + const MemRegion * const *Begin, + const MemRegion * const *End, + bool *) { + CStringLength::EntryMap Entries = state->get(); + if (Entries.isEmpty()) + return state; + + llvm::SmallPtrSet Invalidated; + llvm::SmallPtrSet SuperRegions; + + // First build sets for the changed regions and their super-regions. + for ( ; Begin != End; ++Begin) { + const MemRegion *MR = *Begin; + Invalidated.insert(MR); + + SuperRegions.insert(MR); + while (const SubRegion *SR = dyn_cast(MR)) { + MR = SR->getSuperRegion(); + SuperRegions.insert(MR); + } + } + + CStringLength::EntryMap::Factory &F = state->get_context(); + + // Then loop over the entries in the current state. + for (CStringLength::EntryMap::iterator I = Entries.begin(), + E = Entries.end(); I != E; ++I) { + const MemRegion *MR = I.getKey(); + + // Is this entry for a super-region of a changed region? + if (SuperRegions.count(MR)) { + Entries = F.Remove(Entries, MR); + continue; + } + + // Is this entry for a sub-region of a changed region? + const MemRegion *Super = MR; + while (const SubRegion *SR = dyn_cast(Super)) { + Super = SR->getSuperRegion(); + if (Invalidated.count(Super)) { + Entries = F.Remove(Entries, MR); + break; + } + } + } + + return state->set(Entries); +} + +void CStringChecker::MarkLiveSymbols(const GRState *state, SymbolReaper &SR) { + // Mark all symbols in our string length map as valid. + CStringLength::EntryMap Entries = state->get(); + + for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end(); + I != E; ++I) { + SVal Len = I.getData(); + if (SymbolRef Sym = Len.getAsSymbol()) + SR.markInUse(Sym); + } +} + +void CStringChecker::EvalDeadSymbols(CheckerContext &C, SymbolReaper &SR) { + if (!SR.hasDeadSymbols()) + return; + + const GRState *state = C.getState(); + CStringLength::EntryMap Entries = state->get(); + if (Entries.isEmpty()) + return; + + CStringLength::EntryMap::Factory &F = state->get_context(); + for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end(); + I != E; ++I) { + SVal Len = I.getData(); + if (SymbolRef Sym = Len.getAsSymbol()) { + if (SR.isDead(Sym)) + Entries = F.Remove(Entries, I.getKey()); + } + } + + state = state->set(Entries); + C.GenerateNode(state); +} diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp index c619d75..3c9ddce 100644 --- a/lib/Checker/CallAndMessageChecker.cpp +++ b/lib/Checker/CallAndMessageChecker.cpp @@ -114,7 +114,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {} bool Find(const TypedRegion *R) { - QualType T = R->getValueType(C); + QualType T = R->getValueType(); if (const RecordType *RT = T->getAsStructureType()) { const RecordDecl *RD = RT->getDecl()->getDefinition(); assert(RD && "Referred record has no definition"); diff --git a/lib/Checker/CallInliner.cpp b/lib/Checker/CallInliner.cpp deleted file mode 100644 index c47e06c..0000000 --- a/lib/Checker/CallInliner.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===--- CallInliner.cpp - Transfer function that inlines callee ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the callee inlining transfer function. -// -//===----------------------------------------------------------------------===// - -#include "clang/Checker/PathSensitive/CheckerVisitor.h" -#include "clang/Checker/PathSensitive/GRState.h" -#include "clang/Checker/Checkers/LocalCheckers.h" - -using namespace clang; - -namespace { -class CallInliner : public Checker { -public: - static void *getTag() { - static int x; - return &x; - } - - virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); -}; -} - -void clang::RegisterCallInliner(GRExprEngine &Eng) { - Eng.registerCheck(new CallInliner()); -} - -bool CallInliner::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { - const GRState *state = C.getState(); - const Expr *Callee = CE->getCallee(); - SVal L = state->getSVal(Callee); - - const FunctionDecl *FD = L.getAsFunctionDecl(); - if (!FD) - return false; - - if (!FD->hasBody(FD)) - return false; - - // Now we have the definition of the callee, create a CallEnter node. - CallEnter Loc(CE, FD, C.getPredecessor()->getLocationContext()); - C.addTransition(state, Loc); - - return true; -} - diff --git a/lib/Checker/CastSizeChecker.cpp b/lib/Checker/CastSizeChecker.cpp index a502c10..6676fe5 100644 --- a/lib/Checker/CastSizeChecker.cpp +++ b/lib/Checker/CastSizeChecker.cpp @@ -44,6 +44,10 @@ void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) { QualType ToPointeeTy = ToPTy->getPointeeType(); + // Only perform the check if 'ToPointeeTy' is a complete type. + if (ToPointeeTy->isIncompleteType()) + return; + const GRState *state = C.getState(); const MemRegion *R = state->getSVal(E).getAsRegion(); if (R == 0) diff --git a/lib/Checker/CheckDeadStores.cpp b/lib/Checker/CheckDeadStores.cpp index d6ea187..3896100 100644 --- a/lib/Checker/CheckDeadStores.cpp +++ b/lib/Checker/CheckDeadStores.cpp @@ -217,7 +217,7 @@ public: // If x is EVER assigned a new value later, don't issue // a warning. This is because such initialization can be // due to defensive programming. - if (E->isConstantInitializer(Ctx)) + if (E->isConstantInitializer(Ctx, false)) return; if (DeclRefExpr *DRE=dyn_cast(E->IgnoreParenCasts())) @@ -268,7 +268,7 @@ public: // Check for '&'. Any VarDecl whose value has its address-taken we // treat as escaped. Expr* E = U->getSubExpr()->IgnoreParenCasts(); - if (U->getOpcode() == UnaryOperator::AddrOf) + if (U->getOpcode() == UO_AddrOf) if (DeclRefExpr* DR = dyn_cast(E)) if (VarDecl* VD = dyn_cast(DR->getDecl())) { Escaped.insert(VD); diff --git a/lib/Checker/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp index af85c2f..9a2ac45 100644 --- a/lib/Checker/CheckSecuritySyntaxOnly.cpp +++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp @@ -41,8 +41,8 @@ class WalkAST : public StmtVisitor { public: WalkAST(BugReporter &br) : BR(br), - II_gets(0), II_getpw(0), II_mktemp(0), - II_rand(), II_random(0), II_setid(), + II_gets(0), II_getpw(0), II_mktemp(0), + II_rand(), II_random(0), II_setid(), CheckRand(isArc4RandomAvailable(BR.getContext())) {} // Statement visitor methods. @@ -131,7 +131,7 @@ GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) { if (const BinaryOperator *B = dyn_cast(expr)) { if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() || - B->getOpcode() == BinaryOperator::Comma)) + B->getOpcode() == BO_Comma)) return NULL; if (const DeclRefExpr *lhs = GetIncrementedVar(B->getLHS(), x, y)) @@ -217,7 +217,7 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) { llvm::SmallString<256> sbuf; llvm::raw_svector_ostream os(sbuf); - os << "Variable '" << drCond->getDecl()->getNameAsCString() + os << "Variable '" << drCond->getDecl()->getName() << "' with floating point type '" << drCond->getType().getAsString() << "' should not be used as a loop counter"; @@ -332,10 +332,10 @@ void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { // Issue a waring. SourceRange R = CE->getCallee()->getSourceRange(); BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'", - "Security", - "Call to function 'mktemp' is insecure as it always " - "creates or uses insecure temporary file. Use 'mkstemp' instead", - CE->getLocStart(), &R, 1); + "Security", + "Call to function 'mktemp' is insecure as it always " + "creates or uses insecure temporary file. Use 'mkstemp' instead", + CE->getLocStart(), &R, 1); } //===----------------------------------------------------------------------===// diff --git a/lib/Checker/CheckerHelpers.cpp b/lib/Checker/CheckerHelpers.cpp new file mode 100644 index 0000000..ece6943 --- /dev/null +++ b/lib/Checker/CheckerHelpers.cpp @@ -0,0 +1,80 @@ +//===---- CheckerHelpers.cpp - Helper functions for checkers ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines several static functions for use in checkers. +// +//===----------------------------------------------------------------------===// + +#include "clang/Checker/PathSensitive/CheckerHelpers.h" +#include "clang/AST/Expr.h" + +// Recursively find any substatements containing macros +bool clang::containsMacro(const Stmt *S) { + if (S->getLocStart().isMacroID()) + return true; + + if (S->getLocEnd().isMacroID()) + return true; + + for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); + ++I) + if (const Stmt *child = *I) + if (containsMacro(child)) + return true; + + return false; +} + +// Recursively find any substatements containing enum constants +bool clang::containsEnum(const Stmt *S) { + const DeclRefExpr *DR = dyn_cast(S); + + if (DR && isa(DR->getDecl())) + return true; + + for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); + ++I) + if (const Stmt *child = *I) + if (containsEnum(child)) + return true; + + return false; +} + +// Recursively find any substatements containing static vars +bool clang::containsStaticLocal(const Stmt *S) { + const DeclRefExpr *DR = dyn_cast(S); + + if (DR) + if (const VarDecl *VD = dyn_cast(DR->getDecl())) + if (VD->isStaticLocal()) + return true; + + for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); + ++I) + if (const Stmt *child = *I) + if (containsStaticLocal(child)) + return true; + + return false; +} + +// Recursively find any substatements containing __builtin_offsetof +bool clang::containsBuiltinOffsetOf(const Stmt *S) { + if (isa(S)) + return true; + + for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); + ++I) + if (const Stmt *child = *I) + if (containsBuiltinOffsetOf(child)) + return true; + + return false; +} diff --git a/lib/Checker/CocoaConventions.cpp b/lib/Checker/CocoaConventions.cpp index 3ba887c..b446a04 100644 --- a/lib/Checker/CocoaConventions.cpp +++ b/lib/Checker/CocoaConventions.cpp @@ -173,9 +173,10 @@ bool cocoa::isCocoaObjectRef(QualType Ty) { if (!PT) return true; - // We assume that id<..>, id, and "Class" all represent tracked objects. + // We assume that id<..>, id, Class, and Class<..> all represent tracked + // objects. if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() || - PT->isObjCClassType()) + PT->isObjCClassType() || PT->isObjCQualifiedClassType()) return true; // Does the interface subclass NSObject? diff --git a/lib/Checker/DivZeroChecker.cpp b/lib/Checker/DivZeroChecker.cpp index e09a871..32e2a17 100644 --- a/lib/Checker/DivZeroChecker.cpp +++ b/lib/Checker/DivZeroChecker.cpp @@ -40,10 +40,10 @@ void *DivZeroChecker::getTag() { void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B) { BinaryOperator::Opcode Op = B->getOpcode(); - if (Op != BinaryOperator::Div && - Op != BinaryOperator::Rem && - Op != BinaryOperator::DivAssign && - Op != BinaryOperator::RemAssign) + if (Op != BO_Div && + Op != BO_Rem && + Op != BO_DivAssign && + Op != BO_RemAssign) return; if (!B->getRHS()->getType()->isIntegerType() || diff --git a/lib/Checker/Environment.cpp b/lib/Checker/Environment.cpp index 48152ce..02291f4 100644 --- a/lib/Checker/Environment.cpp +++ b/lib/Checker/Environment.cpp @@ -80,7 +80,7 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const { return LookupExpr(E); } -Environment EnvironmentManager::BindExpr(Environment Env, const Stmt *S, +Environment EnvironmentManager::bindExpr(Environment Env, const Stmt *S, SVal V, bool Invalidate) { assert(S); @@ -94,6 +94,16 @@ Environment EnvironmentManager::BindExpr(Environment Env, const Stmt *S, return Environment(F.Add(Env.ExprBindings, S, V)); } +static inline const Stmt *MakeLocation(const Stmt *S) { + return (const Stmt*) (((uintptr_t) S) | 0x1); +} + +Environment EnvironmentManager::bindExprAndLocation(Environment Env, + const Stmt *S, + SVal location, SVal V) { + return Environment(F.Add(F.Add(Env.ExprBindings, MakeLocation(S), V), S, V)); +} + namespace { class MarkLiveCallback : public SymbolVisitor { SymbolReaper &SymReaper; @@ -115,6 +125,12 @@ static bool isBlockExprInCallers(const Stmt *E, const LocationContext *LC) { return false; } +// In addition to mapping from Stmt * - > SVals in the Environment, we also +// maintain a mapping from Stmt * -> SVals (locations) that were used during +// a load and store. +static inline bool IsLocation(const Stmt *S) { + return (bool) (((uintptr_t) S) & 0x1); +} // RemoveDeadBindings: // - Remove subexpression bindings. @@ -123,7 +139,6 @@ static bool isBlockExprInCallers(const Stmt *E, const LocationContext *LC) { // - Mark their reachable symbols live in SymbolReaper, // see ScanReachableSymbols. // - Mark the region in DRoots if the binding is a loc::MemRegionVal. - Environment EnvironmentManager::RemoveDeadBindings(Environment Env, SymbolReaper &SymReaper, @@ -136,12 +151,25 @@ EnvironmentManager::RemoveDeadBindings(Environment Env, // individually removing all the subexpression bindings (which will greatly // outnumber block-level expression bindings). Environment NewEnv = getInitialEnvironment(); + + llvm::SmallVector, 10> deferredLocations; // Iterate over the block-expr bindings. for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { const Stmt *BlkExpr = I.getKey(); + + // For recorded locations (used when evaluating loads and stores), we + // consider them live only when their associated normal expression is + // also live. + // NOTE: This assumes that loads/stores that evaluated to UnknownVal + // still have an entry in the map. + if (IsLocation(BlkExpr)) { + deferredLocations.push_back(std::make_pair(BlkExpr, I.getData())); + continue; + } + const SVal &X = I.getData(); // Block-level expressions in callers are assumed always live. @@ -186,6 +214,15 @@ EnvironmentManager::RemoveDeadBindings(Environment Env, if (X.isUndef() && cast(X).getData()) NewEnv.ExprBindings = F.Add(NewEnv.ExprBindings, BlkExpr, X); } + + // Go through he deferred locations and add them to the new environment if + // the correspond Stmt* is in the map as well. + for (llvm::SmallVectorImpl >::iterator + I = deferredLocations.begin(), E = deferredLocations.end(); I != E; ++I) { + const Stmt *S = (Stmt*) (((uintptr_t) I->first) & (uintptr_t) ~0x1); + if (NewEnv.ExprBindings.lookup(S)) + NewEnv.ExprBindings = F.Add(NewEnv.ExprBindings, I->first, I->second); + } return NewEnv; } diff --git a/lib/Checker/FixedAddressChecker.cpp b/lib/Checker/FixedAddressChecker.cpp index 4fce45b..29a3c3a 100644 --- a/lib/Checker/FixedAddressChecker.cpp +++ b/lib/Checker/FixedAddressChecker.cpp @@ -40,7 +40,7 @@ void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C, // Using a fixed address is not portable because that address will probably // not be valid in all environments or platforms. - if (B->getOpcode() != BinaryOperator::Assign) + if (B->getOpcode() != BO_Assign) return; QualType T = B->getType(); diff --git a/lib/Checker/FlatStore.cpp b/lib/Checker/FlatStore.cpp index 64575b3c9..21fa422 100644 --- a/lib/Checker/FlatStore.cpp +++ b/lib/Checker/FlatStore.cpp @@ -44,11 +44,10 @@ public: } SVal ArrayToPointer(Loc Array); - const GRState *RemoveDeadBindings(GRState &state, - const StackFrameContext *LCtx, + Store RemoveDeadBindings(Store store, const StackFrameContext *LCtx, SymbolReaper& SymReaper, llvm::SmallVectorImpl& RegionRoots){ - return StateMgr.getPersistentState(state); + return store; } Store BindDecl(Store store, const VarRegion *VR, SVal initVal); @@ -57,13 +56,10 @@ public: typedef llvm::DenseSet InvalidatedSymbols; - Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E, - unsigned Count, InvalidatedSymbols *IS); - Store InvalidateRegions(Store store, const MemRegion * const *I, const MemRegion * const *E, const Expr *Ex, unsigned Count, InvalidatedSymbols *IS, - bool invalidateGlobals); + bool invalidateGlobals, InvalidatedRegions *Regions); void print(Store store, llvm::raw_ostream& Out, const char* nl, const char *sep); @@ -74,7 +70,14 @@ private: return RegionBindings(static_cast(store)); } - Interval RegionToInterval(const MemRegion *R); + class RegionInterval { + public: + const MemRegion *R; + Interval I; + RegionInterval(const MemRegion *r, int64_t s, int64_t e) : R(r), I(s, e){} + }; + + RegionInterval RegionToInterval(const MemRegion *R); SVal RetrieveRegionWithNoBinding(const MemRegion *R, QualType T); }; @@ -86,11 +89,15 @@ StoreManager *clang::CreateFlatStoreManager(GRStateManager &StMgr) { SVal FlatStoreManager::Retrieve(Store store, Loc L, QualType T) { const MemRegion *R = cast(L).getRegion(); - Interval I = RegionToInterval(R); + RegionInterval RI = RegionToInterval(R); + // FIXME: FlatStore should handle regions with unknown intervals. + if (!RI.R) + return UnknownVal(); + RegionBindings B = getRegionBindings(store); - const BindingVal *BV = B.lookup(R); + const BindingVal *BV = B.lookup(RI.R); if (BV) { - const SVal *V = BVFactory.Lookup(*BV, I); + const SVal *V = BVFactory.Lookup(*BV, RI.I); if (V) return *V; else @@ -116,9 +123,12 @@ Store FlatStoreManager::Bind(Store store, Loc L, SVal val) { if (V) BV = *V; - Interval I = RegionToInterval(R); - BV = BVFactory.Add(BV, I, val); - B = RBFactory.Add(B, R, BV); + RegionInterval RI = RegionToInterval(R); + // FIXME: FlatStore should handle regions with unknown intervals. + if (!RI.R) + return B.getRoot(); + BV = BVFactory.Add(BV, RI.I, val); + B = RBFactory.Add(B, RI.R, BV); return B.getRoot(); } @@ -139,7 +149,7 @@ SVal FlatStoreManager::ArrayToPointer(Loc Array) { Store FlatStoreManager::BindDecl(Store store, const VarRegion *VR, SVal initVal) { - return store; + return Bind(store, ValMgr.makeLoc(VR), initVal); } Store FlatStoreManager::BindDeclWithNoInit(Store store, const VarRegion *VR) { @@ -147,18 +157,12 @@ Store FlatStoreManager::BindDeclWithNoInit(Store store, const VarRegion *VR) { } Store FlatStoreManager::InvalidateRegions(Store store, - const MemRegion * const *I, - const MemRegion * const *E, - const Expr *Ex, unsigned Count, - InvalidatedSymbols *IS, - bool invalidateGlobals) { - assert(false && "Not implemented"); - return store; -} - -Store FlatStoreManager::InvalidateRegion(Store store, const MemRegion *R, - const Expr *E, unsigned Count, - InvalidatedSymbols *IS) { + const MemRegion * const *I, + const MemRegion * const *E, + const Expr *Ex, unsigned Count, + InvalidatedSymbols *IS, + bool invalidateGlobals, + InvalidatedRegions *Regions) { assert(false && "Not implemented"); return store; } @@ -170,15 +174,29 @@ void FlatStoreManager::print(Store store, llvm::raw_ostream& Out, void FlatStoreManager::iterBindings(Store store, BindingsHandler& f) { } -Interval FlatStoreManager::RegionToInterval(const MemRegion *R) { +FlatStoreManager::RegionInterval +FlatStoreManager::RegionToInterval(const MemRegion *R) { switch (R->getKind()) { case MemRegion::VarRegionKind: { - QualType T = cast(R)->getValueType(Ctx); - uint64_t Size = Ctx.getTypeSize(T); - return Interval(0, Size-1); + QualType T = cast(R)->getValueType(); + int64_t Size = Ctx.getTypeSize(T); + return RegionInterval(R, 0, Size-1); } + + case MemRegion::ElementRegionKind: + case MemRegion::FieldRegionKind: { + RegionOffset Offset = R->getAsOffset(); + // We cannot compute offset for all regions, for example, elements + // with symbolic offsets. + if (!Offset.getRegion()) + return RegionInterval(0, 0, 0); + int64_t Start = Offset.getOffset(); + int64_t Size = Ctx.getTypeSize(cast(R)->getValueType()); + return RegionInterval(Offset.getRegion(), Start, Start+Size); + } + default: llvm_unreachable("Region kind unhandled."); - return Interval(0, 0); + return RegionInterval(0, 0, 0); } } diff --git a/lib/Checker/GRCXXExprEngine.cpp b/lib/Checker/GRCXXExprEngine.cpp index 18e112c..a49989b 100644 --- a/lib/Checker/GRCXXExprEngine.cpp +++ b/lib/Checker/GRCXXExprEngine.cpp @@ -17,7 +17,7 @@ using namespace clang; -void GRExprEngine::EvalArguments(ExprIterator AI, ExprIterator AE, +void GRExprEngine::EvalArguments(ConstExprIterator AI, ConstExprIterator AE, const FunctionProtoType *FnType, ExplodedNode *Pred, ExplodedNodeSet &Dst) { llvm::SmallVector WorkList; @@ -55,7 +55,7 @@ const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D, return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC); } -void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred, +void GRExprEngine::CreateCXXTemporaryObject(const Expr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNodeSet Tmp; Visit(Ex, Pred, Tmp); @@ -94,9 +94,7 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, // Evaluate other arguments. ExplodedNodeSet ArgsEvaluated; const FunctionProtoType *FnType = CD->getType()->getAs(); - EvalArguments(const_cast(E)->arg_begin(), - const_cast(E)->arg_end(), - FnType, Pred, ArgsEvaluated); + EvalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, ArgsEvaluated); // The callee stack frame context used to create the 'this' parameter region. const StackFrameContext *SFC = AMgr.getStackFrame(CD, Pred->getLocationContext(), @@ -104,11 +102,12 @@ void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest, const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC); - CallEnter Loc(E, CD, Pred->getLocationContext()); + CallEnter Loc(E, SFC->getAnalysisContext(), Pred->getLocationContext()); for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(), NE = ArgsEvaluated.end(); NI != NE; ++NI) { const GRState *state = GetState(*NI); - // Setup 'this' region. + // Setup 'this' region, so that the ctor is evaluated on the object pointed + // by 'Dest'. state = state->bindLoc(loc::MemRegionVal(ThisR), Dest); ExplodedNode *N = Builder->generateNode(Loc, state, Pred); if (N) @@ -126,9 +125,7 @@ void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, // Evaluate explicit arguments with a worklist. ExplodedNodeSet ArgsEvaluated; - EvalArguments(const_cast(MCE)->arg_begin(), - const_cast(MCE)->arg_end(), - FnType, Pred, ArgsEvaluated); + EvalArguments(MCE->arg_begin(), MCE->arg_end(), FnType, Pred, ArgsEvaluated); // Evaluate the implicit object argument. ExplodedNodeSet AllArgsEvaluated; @@ -157,7 +154,7 @@ void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, Builder->getBlock(), Builder->getIndex()); const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); - CallEnter Loc(MCE, MD, Pred->getLocationContext()); + CallEnter Loc(MCE, SFC->getAnalysisContext(), Pred->getLocationContext()); for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(), E = AllArgsEvaluated.end(); I != E; ++I) { // Set up 'this' region. @@ -169,7 +166,7 @@ void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, } } -void GRExprEngine::VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred, +void GRExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { if (CNE->isArray()) { // FIXME: allocating an array has not been handled. @@ -177,7 +174,7 @@ void GRExprEngine::VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred, } unsigned Count = Builder->getCurrentBlockCount(); - DefinedOrUnknownSVal SymVal = getValueManager().getConjuredSymbolVal(NULL,CNE, + DefinedOrUnknownSVal SymVal = getValueManager().getConjuredSymbolVal(NULL,CNE, CNE->getType(), Count); const MemRegion *NewReg = cast(SymVal).getRegion(); @@ -201,10 +198,7 @@ void GRExprEngine::VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred, const GRState *state = GetState(*I); if (ObjTy->isRecordType()) { - Store store = state->getStore(); - StoreManager::InvalidatedSymbols IS; - store = getStoreManager().InvalidateRegion(store, EleReg, CNE, Count, &IS); - state = state->makeWithStore(store); + state = state->InvalidateRegion(EleReg, CNE, Count); } else { if (CNE->hasInitializer()) { SVal V = state->getSVal(*CNE->constructor_arg_begin()); @@ -220,8 +214,8 @@ void GRExprEngine::VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred, } } -void GRExprEngine::VisitCXXDeleteExpr(CXXDeleteExpr *CDE, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { +void GRExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, + ExplodedNode *Pred,ExplodedNodeSet &Dst) { // Should do more checking. ExplodedNodeSet ArgEvaluated; Visit(CDE->getArgument(), Pred, ArgEvaluated); @@ -232,7 +226,7 @@ void GRExprEngine::VisitCXXDeleteExpr(CXXDeleteExpr *CDE, ExplodedNode *Pred, } } -void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred, +void GRExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // Get the this object region from StoreManager. const MemRegion *R = diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp index a816186..5125f36 100644 --- a/lib/Checker/GRCoreEngine.cpp +++ b/lib/Checker/GRCoreEngine.cpp @@ -12,8 +12,10 @@ // //===----------------------------------------------------------------------===// +#include "clang/Checker/PathSensitive/AnalysisManager.h" #include "clang/Checker/PathSensitive/GRCoreEngine.h" #include "clang/Checker/PathSensitive/GRExprEngine.h" +#include "clang/Index/TranslationUnit.h" #include "clang/AST/Expr.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/DenseMap.h" @@ -24,6 +26,12 @@ using llvm::cast; using llvm::isa; using namespace clang; +// This should be removed in the future. +namespace clang { +GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, + const LangOptions& lopts); +} + //===----------------------------------------------------------------------===// // Worklist classes for exploration of reachable states. //===----------------------------------------------------------------------===// @@ -118,47 +126,15 @@ GRWorkList* GRWorkList::MakeBFSBlockDFSContents() { //===----------------------------------------------------------------------===// // Core analysis engine. //===----------------------------------------------------------------------===// -void GRCoreEngine::ProcessEndPath(GREndPathNodeBuilder& Builder) { - SubEngine.ProcessEndPath(Builder); -} - -void GRCoreEngine::ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder) { - SubEngine.ProcessStmt(E, Builder); -} - -bool GRCoreEngine::ProcessBlockEntrance(CFGBlock* Blk, const ExplodedNode *Pred, - GRBlockCounter BC) { - return SubEngine.ProcessBlockEntrance(Blk, Pred, BC); -} - -void GRCoreEngine::ProcessBranch(Stmt* Condition, Stmt* Terminator, - GRBranchNodeBuilder& Builder) { - SubEngine.ProcessBranch(Condition, Terminator, Builder); -} - -void GRCoreEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& Builder) { - SubEngine.ProcessIndirectGoto(Builder); -} - -void GRCoreEngine::ProcessSwitch(GRSwitchNodeBuilder& Builder) { - SubEngine.ProcessSwitch(Builder); -} - -void GRCoreEngine::ProcessCallEnter(GRCallEnterNodeBuilder &Builder) { - SubEngine.ProcessCallEnter(Builder); -} - -void GRCoreEngine::ProcessCallExit(GRCallExitNodeBuilder &Builder) { - SubEngine.ProcessCallExit(Builder); -} /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. -bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { +bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, + const GRState *InitState) { if (G->num_roots() == 0) { // Initialize the analysis by constructing // the root if none exists. - CFGBlock* Entry = &(L->getCFG()->getEntry()); + const CFGBlock* Entry = &(L->getCFG()->getEntry()); assert (Entry->empty() && "Entry block must be empty."); @@ -167,7 +143,7 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { "Entry block must have 1 successor."); // Get the solitary successor. - CFGBlock* Succ = *(Entry->succ_begin()); + const CFGBlock* Succ = *(Entry->succ_begin()); // Construct an edge representing the // starting location in the function. @@ -176,8 +152,11 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { // Set the current block counter to being empty. WList->setBlockCounter(BCounterFactory.GetEmptyCounter()); - // Generate the root. - GenerateNode(StartLoc, getInitialState(L), 0); + if (!InitState) + // Generate the root. + GenerateNode(StartLoc, getInitialState(L), 0); + else + GenerateNode(StartLoc, InitState, 0); } while (Steps && WList->hasWork()) { @@ -221,14 +200,25 @@ bool GRCoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps) { } } - SubEngine.ProcessEndWorklist(WList->hasWork() || BlockAborted); + SubEngine.ProcessEndWorklist(hasWorkRemaining()); return WList->hasWork(); } +void GRCoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L, + unsigned Steps, + const GRState *InitState, + ExplodedNodeSet &Dst) { + ExecuteWorkList(L, Steps, InitState); + for (llvm::SmallVectorImpl::iterator I = G->EndNodes.begin(), + E = G->EndNodes.end(); I != E; ++I) { + Dst.Add(*I); + } +} + void GRCoreEngine::HandleCallEnter(const CallEnter &L, const CFGBlock *Block, unsigned Index, ExplodedNode *Pred) { - GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), L.getCallee(), - Block, Index); + GRCallEnterNodeBuilder Builder(*this, Pred, L.getCallExpr(), + L.getCalleeContext(), Block, Index); ProcessCallEnter(Builder); } @@ -239,7 +229,7 @@ void GRCoreEngine::HandleCallExit(const CallExit &L, ExplodedNode *Pred) { void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { - CFGBlock* Blk = L.getDst(); + const CFGBlock* Blk = L.getDst(); // Check if we are entering the EXIT block. if (Blk == &(L.getLocationContext()->getCFG()->getExit())) { @@ -260,8 +250,9 @@ void GRCoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { if (ProcessBlockEntrance(Blk, Pred, WList->getBlockCounter())) GenerateNode(BlockEntrance(Blk, Pred->getLocationContext()), Pred->State, Pred); - else - BlockAborted = true; + else { + blocksAborted.push_back(std::make_pair(L, Pred)); + } } void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L, @@ -284,9 +275,9 @@ void GRCoreEngine::HandleBlockEntrance(const BlockEntrance& L, HandleBlockExit(L.getBlock(), Pred); } -void GRCoreEngine::HandleBlockExit(CFGBlock * B, ExplodedNode* Pred) { +void GRCoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode* Pred) { - if (Stmt* Term = B->getTerminator()) { + if (const Stmt* Term = B->getTerminator()) { switch (Term->getStmtClass()) { default: assert(false && "Analysis for this terminator not implemented."); @@ -372,8 +363,8 @@ void GRCoreEngine::HandleBlockExit(CFGBlock * B, ExplodedNode* Pred) { Pred->State, Pred); } -void GRCoreEngine::HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock * B, - ExplodedNode* Pred) { +void GRCoreEngine::HandleBranch(const Stmt* Cond, const Stmt* Term, + const CFGBlock * B, ExplodedNode* Pred) { assert (B->succ_size() == 2); GRBranchNodeBuilder Builder(B, *(B->succ_begin()), *(B->succ_begin()+1), @@ -382,7 +373,7 @@ void GRCoreEngine::HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock * B, ProcessBranch(Cond, Term, Builder); } -void GRCoreEngine::HandlePostStmt(const PostStmt& L, CFGBlock* B, +void GRCoreEngine::HandlePostStmt(const PostStmt& L, const CFGBlock* B, unsigned StmtIdx, ExplodedNode* Pred) { assert (!B->empty()); @@ -415,7 +406,7 @@ void GRCoreEngine::GenerateNode(const ProgramPoint& Loc, if (IsNew) WList->Enqueue(Node); } -GRStmtNodeBuilder::GRStmtNodeBuilder(CFGBlock* b, unsigned idx, +GRStmtNodeBuilder::GRStmtNodeBuilder(const CFGBlock* b, unsigned idx, ExplodedNode* N, GRCoreEngine* e, GRStateManager &mgr) : Eng(*e), B(*b), Idx(idx), Pred(N), Mgr(mgr), Auditor(0), @@ -438,7 +429,7 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { if (isa(N->getLocation())) { // Still use the index of the CallExpr. It's needed to create the callee // StackFrameContext. - Eng.WList->Enqueue(N, B, Idx); + Eng.WList->Enqueue(N, &B, Idx); return; } @@ -447,7 +438,7 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { if (Loc == N->getLocation()) { // Note: 'N' should be a fresh node because otherwise it shouldn't be // a member of Deferred. - Eng.WList->Enqueue(N, B, Idx+1); + Eng.WList->Enqueue(N, &B, Idx+1); return; } @@ -456,10 +447,10 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) { Succ->addPredecessor(N, *Eng.G); if (IsNew) - Eng.WList->Enqueue(Succ, B, Idx+1); + Eng.WList->Enqueue(Succ, &B, Idx+1); } -ExplodedNode* GRStmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, Stmt* S, +ExplodedNode* GRStmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, const Stmt* S, ExplodedNode* Pred, const GRState* St, ProgramPoint::Kind K) { const GRState* PredState = GetState(Pred); @@ -692,6 +683,59 @@ void GREndPathNodeBuilder::GenerateCallExitNode(const GRState *state) { void GRCallEnterNodeBuilder::GenerateNode(const GRState *state, const LocationContext *LocCtx) { + // Check if the callee is in the same translation unit. + if (CalleeCtx->getTranslationUnit() != + Pred->getLocationContext()->getTranslationUnit()) { + // Create a new engine. We must be careful that the new engine should not + // reference data structures owned by the old engine. + + AnalysisManager &OldMgr = Eng.SubEngine.getAnalysisManager(); + + // Get the callee's translation unit. + idx::TranslationUnit *TU = CalleeCtx->getTranslationUnit(); + + // Create a new AnalysisManager with components of the callee's + // TranslationUnit. + // The Diagnostic is actually shared when we create ASTUnits from AST files. + AnalysisManager AMgr(TU->getASTContext(), TU->getDiagnostic(), + OldMgr.getLangOptions(), + OldMgr.getPathDiagnosticClient(), + OldMgr.getStoreManagerCreator(), + OldMgr.getConstraintManagerCreator(), + OldMgr.getIndexer(), + OldMgr.getMaxNodes(), OldMgr.getMaxLoop(), + OldMgr.shouldVisualizeGraphviz(), + OldMgr.shouldVisualizeUbigraph(), + OldMgr.shouldPurgeDead(), + OldMgr.shouldEagerlyAssume(), + OldMgr.shouldTrimGraph(), + OldMgr.shouldInlineCall(), + OldMgr.getAnalysisContextManager().getUseUnoptimizedCFG()); + llvm::OwningPtr TF(MakeCFRefCountTF(AMgr.getASTContext(), + /* GCEnabled */ false, + AMgr.getLangOptions())); + // Create the new engine. + GRExprEngine NewEng(AMgr, TF.take()); + + // Create the new LocationContext. + AnalysisContext *NewAnaCtx = AMgr.getAnalysisContext(CalleeCtx->getDecl(), + CalleeCtx->getTranslationUnit()); + const StackFrameContext *OldLocCtx = cast(LocCtx); + const StackFrameContext *NewLocCtx = AMgr.getStackFrame(NewAnaCtx, + OldLocCtx->getParent(), + OldLocCtx->getCallSite(), + OldLocCtx->getCallSiteBlock(), + OldLocCtx->getIndex()); + + // Now create an initial state for the new engine. + const GRState *NewState = NewEng.getStateManager().MarshalState(state, + NewLocCtx); + ExplodedNodeSet ReturnNodes; + NewEng.ExecuteWorkListWithInitialState(NewLocCtx, AMgr.getMaxNodes(), + NewState, ReturnNodes); + return; + } + // Get the callee entry block. const CFGBlock *Entry = &(LocCtx->getCFG()->getEntry()); assert(Entry->empty()); @@ -721,6 +765,6 @@ void GRCallExitNodeBuilder::GenerateNode(const GRState *state) { ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew); Node->addPredecessor(const_cast(Pred), *Eng.G); if (isNew) - Eng.WList->Enqueue(Node, *const_cast(LocCtx->getCallSiteBlock()), + Eng.WList->Enqueue(Node, LocCtx->getCallSiteBlock(), LocCtx->getIndex() + 1); } diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index 07fee9d..feb826e 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -169,17 +169,18 @@ public: // Checker worklist routines. //===----------------------------------------------------------------------===// -void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, bool isPrevisit) { +void GRExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, CallbackKind Kind) { // Determine if we already have a cached 'CheckersOrdered' vector - // specifically tailored for the provided . This + // specifically tailored for the provided . This // can reduce the number of checkers actually called. CheckersOrdered *CO = &Checkers; llvm::OwningPtr NewCO; - - const std::pair &K = - std::make_pair((unsigned)S->getStmtClass(), isPrevisit ? 1U : 0U); + + // The cache key is made up of the and the callback kind (pre- or post-visit) + // and the statement kind. + CallbackTag K = GetCallbackTag(Kind, S->getStmtClass()); CheckersOrdered *& CO_Ref = COCache[K]; @@ -204,7 +205,10 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet *PrevSet = &Src; unsigned checkersEvaluated = 0; - for (CheckersOrdered::iterator I=CO->begin(), E=CO->end(); I!=E; ++I){ + for (CheckersOrdered::iterator I=CO->begin(), E=CO->end(); I!=E; ++I) { + // If all nodes are sunk, bail out early. + if (PrevSet->empty()) + break; ExplodedNodeSet *CurrSet = 0; if (I+1 == E) CurrSet = &Dst; @@ -219,8 +223,8 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); NI != NE; ++NI) { - checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit, - respondsToCallback); + checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, + Kind == PreVisitStmtCallback, respondsToCallback); } @@ -235,7 +239,9 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, // If we built NewCO, check if we called all the checkers. This is important // so that we know that we accurately determined the entire set of checkers - // that responds to this callback. + // that responds to this callback. Note that 'checkersEvaluated' might + // not be the same as Checkers.size() if one of the Checkers generates + // a sink node. if (NewCO.get() && checkersEvaluated == Checkers.size()) CO_Ref = NewCO.take(); @@ -300,10 +306,9 @@ bool GRExprEngine::CheckerEvalCall(const CallExpr *CE, // FIXME: This is largely copy-paste from CheckerVisit(). Need to // unify. -void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, - ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, - SVal location, SVal val, bool isPrevisit) { +void GRExprEngine::CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, SVal location, + SVal val, bool isPrevisit) { if (Checkers.empty()) { Dst.insert(Src); @@ -328,7 +333,7 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE, for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); NI != NE; ++NI) - checker->GR_VisitBind(*CurrSet, *Builder, *this, AssignE, StoreE, + checker->GR_VisitBind(*CurrSet, *Builder, *this, StoreE, *NI, tag, location, val, isPrevisit); // Update which NodeSet is the current one. @@ -457,7 +462,7 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { break; SVal V = state->getSVal(loc::MemRegionVal(R)); - SVal Constraint_untested = EvalBinOp(state, BinaryOperator::GT, V, + SVal Constraint_untested = EvalBinOp(state, BO_GT, V, ValMgr.makeZeroVal(T), getContext().IntTy); @@ -499,29 +504,135 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) { /// logic for handling assumptions on symbolic values. const GRState *GRExprEngine::ProcessAssume(const GRState *state, SVal cond, bool assumption) { - for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); - I != E; ++I) { + // Determine if we already have a cached 'CheckersOrdered' vector + // specifically tailored for processing assumptions. This + // can reduce the number of checkers actually called. + CheckersOrdered *CO = &Checkers; + llvm::OwningPtr NewCO; - if (!state) - return NULL; + CallbackTag K = GetCallbackTag(ProcessAssumeCallback); + CheckersOrdered *& CO_Ref = COCache[K]; + + if (!CO_Ref) { + // If we have no previously cached CheckersOrdered vector for this + // statement kind, then create one. + NewCO.reset(new CheckersOrdered); + } + else { + // Use the already cached set. + CO = CO_Ref; + } + + if (!CO->empty()) { + // Let the checkers have a crack at the assume before the transfer functions + // get their turn. + for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I!=E; ++I) { - state = I->second->EvalAssume(state, cond, assumption); + // If any checker declares the state infeasible (or if it starts that + // way), bail out. + if (!state) + return NULL; + + Checker *C = I->second; + bool respondsToCallback = true; + + state = C->EvalAssume(state, cond, assumption, &respondsToCallback); + + // Check if we're building the cache of checkers that care about Assumes. + if (NewCO.get() && respondsToCallback) + NewCO->push_back(*I); + } + + // If we got through all the checkers, and we built a list of those that + // care about Assumes, save it. + if (NewCO.get()) + CO_Ref = NewCO.take(); } + // If the state is infeasible at this point, bail out. if (!state) return NULL; return TF->EvalAssume(state, cond, assumption); } +bool GRExprEngine::WantsRegionChangeUpdate(const GRState* state) { + CallbackTag K = GetCallbackTag(EvalRegionChangesCallback); + CheckersOrdered *CO = COCache[K]; + + if (!CO) + CO = &Checkers; + + for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) { + Checker *C = I->second; + if (C->WantsRegionChangeUpdate(state)) + return true; + } + + return false; +} + +const GRState * +GRExprEngine::ProcessRegionChanges(const GRState *state, + const MemRegion * const *Begin, + const MemRegion * const *End) { + // FIXME: Most of this method is copy-pasted from ProcessAssume. + + // Determine if we already have a cached 'CheckersOrdered' vector + // specifically tailored for processing region changes. This + // can reduce the number of checkers actually called. + CheckersOrdered *CO = &Checkers; + llvm::OwningPtr NewCO; + + CallbackTag K = GetCallbackTag(EvalRegionChangesCallback); + CheckersOrdered *& CO_Ref = COCache[K]; + + if (!CO_Ref) { + // If we have no previously cached CheckersOrdered vector for this + // callback, then create one. + NewCO.reset(new CheckersOrdered); + } + else { + // Use the already cached set. + CO = CO_Ref; + } + + // If there are no checkers, just return the state as is. + if (CO->empty()) + return state; + + for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) { + // If any checker declares the state infeasible (or if it starts that way), + // bail out. + if (!state) + return NULL; + + Checker *C = I->second; + bool respondsToCallback = true; + + state = C->EvalRegionChanges(state, Begin, End, &respondsToCallback); + + // See if we're building a cache of checkers that care about region changes. + if (NewCO.get() && respondsToCallback) + NewCO->push_back(*I); + } + + // If we got through all the checkers, and we built a list of those that + // care about region changes, save it. + if (NewCO.get()) + CO_Ref = NewCO.take(); + + return state; +} + void GRExprEngine::ProcessEndWorklist(bool hasWorkRemaining) { for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); I != E; ++I) { - I->second->VisitEndAnalysis(G, BR, hasWorkRemaining); + I->second->VisitEndAnalysis(G, BR, *this); } } -void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) { +void GRExprEngine::ProcessStmt(const CFGElement CE,GRStmtNodeBuilder& builder) { CurrentStmt = CE.getStmt(); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), CurrentStmt->getLocStart(), @@ -535,15 +646,23 @@ void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) { Builder->setAuditor(BatchAuditor.get()); // Create the cleaned state. - const ExplodedNode *BasePred = Builder->getBasePredecessor(); + const LocationContext *LC = EntryNode->getLocationContext(); + SymbolReaper SymReaper(LC, CurrentStmt, SymMgr); + + if (AMgr.shouldPurgeDead()) { + const GRState *St = EntryNode->getState(); - SymbolReaper SymReaper(BasePred->getLocationContext(), CurrentStmt, SymMgr); + for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); + I != E; ++I) { + Checker *checker = I->second; + checker->MarkLiveSymbols(St, SymReaper); + } - CleanedState = AMgr.shouldPurgeDead() - ? StateMgr.RemoveDeadBindings(EntryNode->getState(), - BasePred->getLocationContext()->getCurrentStackFrame(), - SymReaper) - : EntryNode->getState(); + const StackFrameContext *SFC = LC->getCurrentStackFrame(); + CleanedState = StateMgr.RemoveDeadBindings(St, SFC, SymReaper); + } else { + CleanedState = EntryNode->getState(); + } // Process any special transfer function for dead symbols. ExplodedNodeSet Tmp; @@ -625,7 +744,8 @@ void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) { Builder = NULL; } -void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { +void GRExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, + ExplodedNodeSet& Dst) { PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), S->getLocStart(), "Error evaluating statement"); @@ -641,7 +761,6 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { switch (S->getStmtClass()) { // C++ stuff we don't support yet. - case Stmt::CXXBindReferenceExprClass: case Stmt::CXXBindTemporaryExprClass: case Stmt::CXXCatchStmtClass: case Stmt::CXXConstructExprClass: @@ -740,13 +859,13 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; case Stmt::BinaryOperatorClass: { - BinaryOperator* B = cast(S); + const BinaryOperator* B = cast(S); if (B->isLogicalOp()) { VisitLogicalExpr(B, Pred, Dst); break; } - else if (B->getOpcode() == BinaryOperator::Comma) { + else if (B->getOpcode() == BO_Comma) { const GRState* state = GetState(Pred); MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS()))); break; @@ -766,25 +885,25 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: { - CallExpr* C = cast(S); + const CallExpr* C = cast(S); VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, false); break; } case Stmt::CXXMemberCallExprClass: { - CXXMemberCallExpr *MCE = cast(S); + const CXXMemberCallExpr *MCE = cast(S); VisitCXXMemberCallExpr(MCE, Pred, Dst); break; } case Stmt::CXXNewExprClass: { - CXXNewExpr *NE = cast(S); + const CXXNewExpr *NE = cast(S); VisitCXXNewExpr(NE, Pred, Dst); break; } case Stmt::CXXDeleteExprClass: { - CXXDeleteExpr *CDE = cast(S); + const CXXDeleteExpr *CDE = cast(S); VisitCXXDeleteExpr(CDE, Pred, Dst); break; } @@ -792,7 +911,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { // the CFG do not model them as explicit control-flow. case Stmt::ChooseExprClass: { // __builtin_choose_expr - ChooseExpr* C = cast(S); + const ChooseExpr* C = cast(S); VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); break; } @@ -806,7 +925,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; case Stmt::ConditionalOperatorClass: { // '?' operator - ConditionalOperator* C = cast(S); + const ConditionalOperator* C = cast(S); VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); break; } @@ -836,7 +955,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { case Stmt::CXXReinterpretCastExprClass: case Stmt::CXXConstCastExprClass: case Stmt::CXXFunctionalCastExprClass: { - CastExpr* C = cast(S); + const CastExpr* C = cast(S); VisitCast(C, C->getSubExpr(), Pred, Dst, false); break; } @@ -893,7 +1012,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; case Stmt::StmtExprClass: { - StmtExpr* SE = cast(S); + const StmtExpr* SE = cast(S); if (SE->getSubStmt()->body_empty()) { // Empty statement expression. @@ -924,8 +1043,8 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { break; case Stmt::UnaryOperatorClass: { - UnaryOperator *U = cast(S); - if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UnaryOperator::LNot)) { + const UnaryOperator *U = cast(S); + if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UO_LNot)) { ExplodedNodeSet Tmp; VisitUnaryOperator(U, Pred, Tmp, false); EvalEagerlyAssume(Dst, Tmp, U); @@ -943,7 +1062,7 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { } } -void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, +void GRExprEngine::VisitLValue(const Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst) { PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), @@ -984,7 +1103,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: { - CallExpr *C = cast(Ex); + const CallExpr *C = cast(Ex); assert(CalleeReturnsReferenceOrRecord(C)); VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true); break; @@ -1000,7 +1119,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, case Stmt::ImplicitCastExprClass: case Stmt::CStyleCastExprClass: { - CastExpr *C = cast(Ex); + const CastExpr *C = cast(Ex); QualType T = Ex->getType(); VisitCast(C, C->getSubExpr(), Pred, Dst, true); break; @@ -1015,7 +1134,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, return; case Stmt::ObjCMessageExprClass: { - ObjCMessageExpr *ME = cast(Ex); + const ObjCMessageExpr *ME = cast(Ex); assert(ReceiverReturnsReferenceOrRecord(ME)); VisitObjCMessageExpr(ME, Pred, Dst, true); return; @@ -1056,6 +1175,9 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, // In C++, binding an rvalue to a reference requires to create an object. case Stmt::CXXBoolLiteralExprClass: case Stmt::IntegerLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::FloatingLiteralClass: + case Stmt::ImaginaryLiteralClass: CreateCXXTemporaryObject(Ex, Pred, Dst); return; @@ -1081,7 +1203,8 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred, // Block entrance. (Update counters). //===----------------------------------------------------------------------===// -bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred, +bool GRExprEngine::ProcessBlockEntrance(const CFGBlock* B, + const ExplodedNode *Pred, GRBlockCounter BC) { return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(), B->getBlockID()) < AMgr.getMaxLoop(); @@ -1091,7 +1214,7 @@ bool GRExprEngine::ProcessBlockEntrance(CFGBlock* B, const ExplodedNode *Pred, // Generic node creation. //===----------------------------------------------------------------------===// -ExplodedNode* GRExprEngine::MakeNode(ExplodedNodeSet& Dst, Stmt* S, +ExplodedNode* GRExprEngine::MakeNode(ExplodedNodeSet& Dst, const Stmt* S, ExplodedNode* Pred, const GRState* St, ProgramPoint::Kind K, const void *tag) { assert (Builder && "GRStmtNodeBuilder not present."); @@ -1105,8 +1228,8 @@ ExplodedNode* GRExprEngine::MakeNode(ExplodedNodeSet& Dst, Stmt* S, //===----------------------------------------------------------------------===// const GRState* GRExprEngine::MarkBranch(const GRState* state, - Stmt* Terminator, - bool branchTaken) { + const Stmt* Terminator, + bool branchTaken) { switch (Terminator->getStmtClass()) { default: @@ -1114,10 +1237,10 @@ const GRState* GRExprEngine::MarkBranch(const GRState* state, case Stmt::BinaryOperatorClass: { // '&&' and '||' - BinaryOperator* B = cast(Terminator); + const BinaryOperator* B = cast(Terminator); BinaryOperator::Opcode Op = B->getOpcode(); - assert (Op == BinaryOperator::LAnd || Op == BinaryOperator::LOr); + assert (Op == BO_LAnd || Op == BO_LOr); // For &&, if we take the true branch, then the value of the whole // expression is that of the RHS expression. @@ -1125,21 +1248,21 @@ const GRState* GRExprEngine::MarkBranch(const GRState* state, // For ||, if we take the false branch, then the value of the whole // expression is that of the RHS expression. - Expr* Ex = (Op == BinaryOperator::LAnd && branchTaken) || - (Op == BinaryOperator::LOr && !branchTaken) - ? B->getRHS() : B->getLHS(); + const Expr* Ex = (Op == BO_LAnd && branchTaken) || + (Op == BO_LOr && !branchTaken) + ? B->getRHS() : B->getLHS(); return state->BindExpr(B, UndefinedVal(Ex)); } case Stmt::ConditionalOperatorClass: { // ?: - ConditionalOperator* C = cast(Terminator); + const ConditionalOperator* C = cast(Terminator); // For ?, if branchTaken == true then the value is either the LHS or // the condition itself. (GNU extension). - Expr* Ex; + const Expr* Ex; if (branchTaken) Ex = C->getLHS() ? C->getLHS() : C->getCond(); @@ -1151,9 +1274,9 @@ const GRState* GRExprEngine::MarkBranch(const GRState* state, case Stmt::ChooseExprClass: { // ?: - ChooseExpr* C = cast(Terminator); + const ChooseExpr* C = cast(Terminator); - Expr* Ex = branchTaken ? C->getLHS() : C->getRHS(); + const Expr* Ex = branchTaken ? C->getLHS() : C->getRHS(); return state->BindExpr(C, UndefinedVal(Ex)); } } @@ -1165,16 +1288,16 @@ const GRState* GRExprEngine::MarkBranch(const GRState* state, /// This function returns the SVal bound to Condition->IgnoreCasts if all the // cast(s) did was sign-extend the original value. static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state, - Stmt* Condition, ASTContext& Ctx) { + const Stmt* Condition, ASTContext& Ctx) { - Expr *Ex = dyn_cast(Condition); + const Expr *Ex = dyn_cast(Condition); if (!Ex) return UnknownVal(); uint64_t bits = 0; bool bitsInit = false; - while (CastExpr *CE = dyn_cast(Ex)) { + while (const CastExpr *CE = dyn_cast(Ex)) { QualType T = CE->getType(); if (!T->isIntegerType()) @@ -1198,7 +1321,7 @@ static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state, return state->getSVal(Ex); } -void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term, +void GRExprEngine::ProcessBranch(const Stmt* Condition, const Stmt* Term, GRBranchNodeBuilder& builder) { // Check for NULL conditions; e.g. "for(;;)" @@ -1285,7 +1408,7 @@ void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) { typedef GRIndirectGotoNodeBuilder::iterator iterator; if (isa(V)) { - LabelStmt* L = cast(V).getLabel(); + const LabelStmt* L = cast(V).getLabel(); for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) { if (I.getLabel() == L) { @@ -1314,7 +1437,8 @@ void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) { } -void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, +void GRExprEngine::VisitGuardedExpr(const Expr* Ex, const Expr* L, + const Expr* R, ExplodedNode* Pred, ExplodedNodeSet& Dst) { assert(Ex == CurrentStmt && @@ -1325,7 +1449,7 @@ void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, assert (X.isUndef()); - Expr *SE = (Expr*) cast(X).getData(); + const Expr *SE = (Expr*) cast(X).getData(); assert(SE); X = state->getSVal(SE); @@ -1350,7 +1474,7 @@ void GRExprEngine::ProcessEndPath(GREndPathNodeBuilder& builder) { void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { typedef GRSwitchNodeBuilder::iterator iterator; const GRState* state = builder.getState(); - Expr* CondE = builder.getCondition(); + const Expr* CondE = builder.getCondition(); SVal CondV_untested = state->getSVal(CondE); if (CondV_untested.isUndef()) { @@ -1363,10 +1487,12 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { DefinedOrUnknownSVal CondV = cast(CondV_untested); const GRState *DefaultSt = state; - bool defaultIsFeasible = false; + + iterator I = builder.begin(), EI = builder.end(); + bool defaultIsFeasible = I == EI; - for (iterator I = builder.begin(), EI = builder.end(); I != EI; ++I) { - CaseStmt* Case = cast(I.getCase()); + for ( ; I != EI; ++I) { + const CaseStmt* Case = I.getCase(); // Evaluate the LHS of the case value. Expr::EvalResult V1; @@ -1382,7 +1508,7 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { // Get the RHS of the case, if it exists. Expr::EvalResult V2; - if (Expr* E = Case->getRHS()) { + if (const Expr* E = Case->getRHS()) { b = E->Evaluate(V2, getContext()); assert(b && V2.Val.isInt() && !V2.HasSideEffects && "Case condition must evaluate to an integer constant."); @@ -1440,15 +1566,14 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) { } void GRExprEngine::ProcessCallEnter(GRCallEnterNodeBuilder &B) { - const FunctionDecl *FD = B.getCallee(); - const StackFrameContext *LocCtx = AMgr.getStackFrame(FD, - B.getLocationContext(), - B.getCallExpr(), - B.getBlock(), - B.getIndex()); + const StackFrameContext *LocCtx + = AMgr.getStackFrame(B.getCalleeContext(), + B.getLocationContext(), + B.getCallExpr(), + B.getBlock(), + B.getIndex()); - const GRState *state = B.getState(); - state = getStoreManager().EnterStackFrame(state, LocCtx); + const GRState *state = B.getState()->EnterStackFrame(LocCtx); B.GenerateNode(state, LocCtx); } @@ -1490,11 +1615,11 @@ void GRExprEngine::ProcessCallExit(GRCallExitNodeBuilder &B) { // Transfer functions: logical operations ('&&', '||'). //===----------------------------------------------------------------------===// -void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, +void GRExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst) { - assert(B->getOpcode() == BinaryOperator::LAnd || - B->getOpcode() == BinaryOperator::LOr); + assert(B->getOpcode() == BO_LAnd || + B->getOpcode() == BO_LOr); assert(B==CurrentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B)); @@ -1534,7 +1659,7 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, // We took the LHS expression. Depending on whether we are '&&' or // '||' we know what the value of the expression is via properties of // the short-circuiting. - X = ValMgr.makeIntVal(B->getOpcode() == BinaryOperator::LAnd ? 0U : 1U, + X = ValMgr.makeIntVal(B->getOpcode() == BO_LAnd ? 0U : 1U, B->getType()); MakeNode(Dst, B, Pred, state->BindExpr(B, X)); } @@ -1544,7 +1669,7 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred, // Transfer functions: Loads and stores. //===----------------------------------------------------------------------===// -void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred, +void GRExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNodeSet Tmp; @@ -1557,21 +1682,21 @@ void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred, ProgramPoint::PostLValueKind); // Post-visit the BlockExpr. - CheckerVisit(BE, Dst, Tmp, false); + CheckerVisit(BE, Dst, Tmp, PostVisitStmtCallback); } -void GRExprEngine::VisitDeclRefExpr(DeclRefExpr *Ex, ExplodedNode *Pred, +void GRExprEngine::VisitDeclRefExpr(const DeclRefExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst, bool asLValue) { VisitCommonDeclRefExpr(Ex, Ex->getDecl(), Pred, Dst, asLValue); } -void GRExprEngine::VisitBlockDeclRefExpr(BlockDeclRefExpr *Ex, +void GRExprEngine::VisitBlockDeclRefExpr(const BlockDeclRefExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst, bool asLValue) { VisitCommonDeclRefExpr(Ex, Ex->getDecl(), Pred, Dst, asLValue); } -void GRExprEngine::VisitCommonDeclRefExpr(Expr *Ex, const NamedDecl *D, +void GRExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, ExplodedNode *Pred, ExplodedNodeSet &Dst, bool asLValue) { @@ -1618,12 +1743,12 @@ void GRExprEngine::VisitCommonDeclRefExpr(Expr *Ex, const NamedDecl *D, } /// VisitArraySubscriptExpr - Transfer function for array accesses -void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, +void GRExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr* A, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue){ - Expr* Base = A->getBase()->IgnoreParens(); - Expr* Idx = A->getIdx()->IgnoreParens(); + const Expr* Base = A->getBase()->IgnoreParens(); + const Expr* Idx = A->getIdx()->IgnoreParens(); ExplodedNodeSet Tmp; if (Base->getType()->isVectorType()) { @@ -1641,7 +1766,7 @@ void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, Visit(Idx, *I1, Tmp2); // Evaluate the index. ExplodedNodeSet Tmp3; - CheckerVisit(A, Tmp3, Tmp2, true); + CheckerVisit(A, Tmp3, Tmp2, PreVisitStmtCallback); for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) { const GRState* state = GetState(*I2); @@ -1658,7 +1783,7 @@ void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A, } /// VisitMemberExpr - Transfer function for member expressions. -void GRExprEngine::VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, +void GRExprEngine::VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue) { Expr* Base = M->getBase()->IgnoreParens(); @@ -1689,16 +1814,15 @@ void GRExprEngine::VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, /// EvalBind - Handle the semantics of binding a value to a specific location. /// This method is used by EvalStore and (soon) VisitDeclStmt, and others. -void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt *AssignE, - Stmt* StoreE, ExplodedNode* Pred, - const GRState* state, SVal location, SVal Val, - bool atDeclInit) { +void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, const Stmt* StoreE, + ExplodedNode* Pred, const GRState* state, + SVal location, SVal Val, bool atDeclInit) { // Do a previsit of the bind. ExplodedNodeSet CheckedSet, Src; Src.Add(Pred); - CheckerVisitBind(AssignE, StoreE, CheckedSet, Src, location, Val, true); + CheckerVisitBind(StoreE, CheckedSet, Src, location, Val, true); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I!=E; ++I) { @@ -1731,6 +1855,10 @@ void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt *AssignE, // The next thing to do is check if the GRTransferFuncs object wants to // update the state based on the new binding. If the GRTransferFunc object // doesn't do anything, just auto-propagate the current state. + + // NOTE: We use 'AssignE' for the location of the PostStore if 'AssignE' + // is non-NULL. Checkers typically care about + GRStmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, StoreE, newState != state); @@ -1740,12 +1868,14 @@ void GRExprEngine::EvalBind(ExplodedNodeSet& Dst, Stmt *AssignE, /// EvalStore - Handle the semantics of a store via an assignment. /// @param Dst The node set to store generated state nodes -/// @param Ex The expression representing the location of the store +/// @param AssignE The assignment expression if the store happens in an +/// assignment. +/// @param LocatioinE The location expression that is stored to. /// @param state The current simulation state /// @param location The location to store the value /// @param Val The value to be stored -void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr *AssignE, - Expr* StoreE, +void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, const Expr *AssignE, + const Expr* LocationE, ExplodedNode* Pred, const GRState* state, SVal location, SVal Val, const void *tag) { @@ -1754,7 +1884,7 @@ void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr *AssignE, // Evaluate the location (checks for bad dereferences). ExplodedNodeSet Tmp; - EvalLocation(Tmp, StoreE, Pred, state, location, tag, false); + EvalLocation(Tmp, LocationE, Pred, state, location, tag, false); if (Tmp.empty()) return; @@ -1765,12 +1895,16 @@ void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr *AssignE, ProgramPoint::PostStoreKind); SaveAndRestore OldTag(Builder->Tag, tag); - // Proceed with the store. + // Proceed with the store. We use AssignE as the anchor for the PostStore + // ProgramPoint if it is non-NULL, and LocationE otherwise. + const Expr *StoreE = AssignE ? AssignE : LocationE; + for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) - EvalBind(Dst, AssignE, StoreE, *NI, GetState(*NI), location, Val); + EvalBind(Dst, StoreE, *NI, GetState(*NI), location, Val); } -void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred, +void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, const Expr *Ex, + ExplodedNode* Pred, const GRState* state, SVal location, const void *tag, QualType LoadTy) { @@ -1780,7 +1914,7 @@ void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred, if (const TypedRegion *TR = dyn_cast_or_null(location.getAsRegion())) { - QualType ValTy = TR->getValueType(getContext()); + QualType ValTy = TR->getValueType(); if (const ReferenceType *RT = ValTy->getAs()) { static int loadReferenceTag = 0; ExplodedNodeSet Tmp; @@ -1800,7 +1934,7 @@ void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred, EvalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy); } -void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, Expr *Ex, +void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex, ExplodedNode* Pred, const GRState* state, SVal location, const void *tag, QualType LoadTy) { @@ -1834,7 +1968,7 @@ void GRExprEngine::EvalLoadCommon(ExplodedNodeSet& Dst, Expr *Ex, } } -void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S, +void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, const Stmt *S, ExplodedNode* Pred, const GRState* state, SVal location, const void *tag, bool isLoad) { @@ -1885,21 +2019,34 @@ bool GRExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, if (!FD) return false; - if (!FD->hasBody(FD)) - return false; + // Check if the function definition is in the same translation unit. + if (FD->hasBody(FD)) { + // Now we have the definition of the callee, create a CallEnter node. + CallEnter Loc(CE, AMgr.getAnalysisContext(FD), Pred->getLocationContext()); + + ExplodedNode *N = Builder->generateNode(Loc, state, Pred); + Dst.Add(N); + return true; + } - // Now we have the definition of the callee, create a CallEnter node. - CallEnter Loc(CE, FD, Pred->getLocationContext()); + // Check if we can find the function definition in other translation units. + if (AMgr.hasIndexer()) { + const AnalysisContext *C = AMgr.getAnalysisContextInAnotherTU(FD); + if (C == 0) + return false; - ExplodedNode *N = Builder->generateNode(Loc, state, Pred); - if (N) + CallEnter Loc(CE, C, Pred->getLocationContext()); + ExplodedNode *N = Builder->generateNode(Loc, state, Pred); Dst.Add(N); - return true; + return true; + } + + return false; } -void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, - CallExpr::arg_iterator AI, - CallExpr::arg_iterator AE, +void GRExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred, + CallExpr::const_arg_iterator AI, + CallExpr::const_arg_iterator AE, ExplodedNodeSet& Dst, bool asLValue) { // Determine the type of function we're calling (if available). @@ -1946,7 +2093,7 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, // Now process the call itself. ExplodedNodeSet DstTmp; - Expr* Callee = CE->getCallee()->IgnoreParens(); + const Expr* Callee = CE->getCallee()->IgnoreParens(); for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(), NE=ArgsEvaluated.end(); NI != NE; ++NI) { @@ -1954,7 +2101,7 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, ExplodedNodeSet DstTmp2; Visit(Callee, *NI, DstTmp2); // Perform the previsit of the CallExpr, storing the results in DstTmp. - CheckerVisit(CE, DstTmp, DstTmp2, true); + CheckerVisit(CE, DstTmp, DstTmp2, PreVisitStmtCallback); } // Finally, evaluate the function call. We try each of the checkers @@ -2009,7 +2156,7 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, // If the callee returns a reference and we want an rvalue, skip this check // and do the load. if (!(!asLValue && CalleeReturnsReference(CE))) { - CheckerVisit(CE, Dst, DstTmp3, false); + CheckerVisit(CE, Dst, DstTmp3, PostVisitStmtCallback); return; } @@ -2019,7 +2166,7 @@ void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred, // FIXME: This conversion doesn't actually happen unless the result // of CallExpr is consumed by another expression. ExplodedNodeSet DstTmp4; - CheckerVisit(CE, DstTmp4, DstTmp3, false); + CheckerVisit(CE, DstTmp4, DstTmp3, PostVisitStmtCallback); QualType LoadTy = CE->getType(); static int *ConvertToRvalueTag = 0; @@ -2039,7 +2186,7 @@ static std::pair EagerlyAssumeTag = std::pair(&EagerlyAssumeTag,static_cast(0)); void GRExprEngine::EvalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, - Expr *Ex) { + const Expr *Ex) { for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) { ExplodedNode *Pred = *I; @@ -2082,10 +2229,11 @@ void GRExprEngine::EvalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, // Transfer function: Objective-C ivar references. //===----------------------------------------------------------------------===// -void GRExprEngine::VisitObjCIvarRefExpr(ObjCIvarRefExpr* Ex, ExplodedNode* Pred, +void GRExprEngine::VisitObjCIvarRefExpr(const ObjCIvarRefExpr* Ex, + ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue) { - Expr* Base = cast(Ex->getBase()); + const Expr* Base = cast(Ex->getBase()); ExplodedNodeSet Tmp; Visit(Base, Pred, Tmp); @@ -2105,7 +2253,7 @@ void GRExprEngine::VisitObjCIvarRefExpr(ObjCIvarRefExpr* Ex, ExplodedNode* Pred, // Transfer function: Objective-C fast enumeration 'for' statements. //===----------------------------------------------------------------------===// -void GRExprEngine::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, +void GRExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { // ObjCForCollectionStmts are processed in two places. This method @@ -2133,11 +2281,11 @@ void GRExprEngine::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, // container is empty. Thus this transfer function will by default // result in state splitting. - Stmt* elem = S->getElement(); + const Stmt* elem = S->getElement(); SVal ElementV; - if (DeclStmt* DS = dyn_cast(elem)) { - VarDecl* ElemD = cast(DS->getSingleDecl()); + if (const DeclStmt* DS = dyn_cast(elem)) { + const VarDecl* ElemD = cast(DS->getSingleDecl()); assert (ElemD->getInit() == 0); ElementV = GetState(Pred)->getLValue(ElemD, Pred->getLocationContext()); VisitObjCForCollectionStmtAux(S, Pred, Dst, ElementV); @@ -2153,12 +2301,12 @@ void GRExprEngine::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, } } -void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, +void GRExprEngine::VisitObjCForCollectionStmtAux(const ObjCForCollectionStmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst, SVal ElementV) { // Check if the location we are writing back to is a null pointer. - Stmt* elem = S->getElement(); + const Stmt* elem = S->getElement(); ExplodedNodeSet Tmp; EvalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false); @@ -2182,7 +2330,7 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, // FIXME: The proper thing to do is to really iterate over the // container. We will do this with dispatch logic to the store. // For now, just 'conjure' up a symbolic value. - QualType T = R->getValueType(getContext()); + QualType T = R->getValueType(); assert(Loc::IsLocType(T)); unsigned Count = Builder->getCurrentBlockCount(); SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count); @@ -2207,23 +2355,24 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S, namespace { class ObjCMsgWLItem { public: - ObjCMessageExpr::arg_iterator I; + ObjCMessageExpr::const_arg_iterator I; ExplodedNode *N; - ObjCMsgWLItem(const ObjCMessageExpr::arg_iterator &i, ExplodedNode *n) + ObjCMsgWLItem(const ObjCMessageExpr::const_arg_iterator &i, ExplodedNode *n) : I(i), N(n) {} }; } // end anonymous namespace -void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, +void GRExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME, + ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue){ // Create a worklist to process both the arguments. llvm::SmallVector WL; // But first evaluate the receiver (if any). - ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end(); - if (Expr *Receiver = ME->getInstanceReceiver()) { + ObjCMessageExpr::const_arg_iterator AI = ME->arg_begin(), AE = ME->arg_end(); + if (const Expr *Receiver = ME->getInstanceReceiver()) { ExplodedNodeSet Tmp; Visit(Receiver, Pred, Tmp); @@ -2261,7 +2410,7 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, // Now that the arguments are processed, handle the previsits checks. ExplodedNodeSet DstPrevisit; - CheckerVisit(ME, DstPrevisit, ArgsEvaluated, true); + CheckerVisit(ME, DstPrevisit, ArgsEvaluated, PreVisitStmtCallback); // Proceed with evaluate the message expression. ExplodedNodeSet DstEval; @@ -2364,7 +2513,7 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, // Finally, perform the post-condition check of the ObjCMessageExpr and store // the created nodes in 'Dst'. if (!(!asLValue && ReceiverReturnsReference(ME))) { - CheckerVisit(ME, Dst, DstEval, false); + CheckerVisit(ME, Dst, DstEval, PostVisitStmtCallback); return; } @@ -2374,7 +2523,7 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, // FIXME: This conversion doesn't actually happen unless the result // of ObjCMessageExpr is consumed by another expression. ExplodedNodeSet DstRValueConvert; - CheckerVisit(ME, DstRValueConvert, DstEval, false); + CheckerVisit(ME, DstRValueConvert, DstEval, PostVisitStmtCallback); QualType LoadTy = ME->getType(); static int *ConvertToRvalueTag = 0; @@ -2390,8 +2539,9 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred, // Transfer functions: Miscellaneous statements. //===----------------------------------------------------------------------===// -void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, - ExplodedNodeSet &Dst, bool asLValue) { +void GRExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, + ExplodedNode *Pred, ExplodedNodeSet &Dst, + bool asLValue) { ExplodedNodeSet S1; QualType T = CastE->getType(); QualType ExTy = Ex->getType(); @@ -2406,7 +2556,7 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, Visit(Ex, Pred, S1); ExplodedNodeSet S2; - CheckerVisit(CastE, S2, S1, true); + CheckerVisit(CastE, S2, S1, PreVisitStmtCallback); // If we are evaluating the cast in an lvalue context, we implicitly want // the cast to evaluate to a location. @@ -2417,14 +2567,14 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, } switch (CastE->getCastKind()) { - case CastExpr::CK_ToVoid: + case CK_ToVoid: assert(!asLValue); for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) Dst.Add(*I); return; - case CastExpr::CK_NoOp: - case CastExpr::CK_FunctionToPointerDecay: + case CK_NoOp: + case CK_FunctionToPointerDecay: for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { // Copy the SVal of Ex to CastE. ExplodedNode *N = *I; @@ -2435,20 +2585,21 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, } return; - case CastExpr::CK_Unknown: - case CastExpr::CK_ArrayToPointerDecay: - case CastExpr::CK_BitCast: - case CastExpr::CK_LValueBitCast: - case CastExpr::CK_IntegralCast: - case CastExpr::CK_IntegralToPointer: - case CastExpr::CK_PointerToIntegral: - case CastExpr::CK_IntegralToFloating: - case CastExpr::CK_FloatingToIntegral: - case CastExpr::CK_FloatingCast: - case CastExpr::CK_AnyPointerToObjCPointerCast: - case CastExpr::CK_AnyPointerToBlockPointerCast: - case CastExpr::CK_DerivedToBase: - case CastExpr::CK_UncheckedDerivedToBase: { + case CK_Unknown: + case CK_ArrayToPointerDecay: + case CK_BitCast: + case CK_LValueBitCast: + case CK_IntegralCast: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + case CK_FloatingCast: + case CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + case CK_ObjCObjectLValueCast: { // Delegate to SValuator to process. for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { ExplodedNode* N = *I; @@ -2462,16 +2613,16 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, } // Various C++ casts that are not handled yet. - case CastExpr::CK_Dynamic: - case CastExpr::CK_ToUnion: - case CastExpr::CK_BaseToDerived: - case CastExpr::CK_NullToMemberPointer: - case CastExpr::CK_BaseToDerivedMemberPointer: - case CastExpr::CK_DerivedToBaseMemberPointer: - case CastExpr::CK_UserDefinedConversion: - case CastExpr::CK_ConstructorConversion: - case CastExpr::CK_VectorSplat: - case CastExpr::CK_MemberPointerToBoolean: { + case CK_Dynamic: + case CK_ToUnion: + case CK_BaseToDerived: + case CK_NullToMemberPointer: + case CK_BaseToDerivedMemberPointer: + case CK_DerivedToBaseMemberPointer: + case CK_UserDefinedConversion: + case CK_ConstructorConversion: + case CK_VectorSplat: + case CK_MemberPointerToBoolean: { SaveAndRestore OldSink(Builder->BuildSinks); Builder->BuildSinks = true; MakeNode(Dst, CastE, Pred, GetState(Pred)); @@ -2480,11 +2631,12 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred, } } -void GRExprEngine::VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, +void GRExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr* CL, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue) { - InitListExpr* ILE = cast(CL->getInitializer()->IgnoreParens()); + const InitListExpr* ILE + = cast(CL->getInitializer()->IgnoreParens()); ExplodedNodeSet Tmp; Visit(ILE, Pred, Tmp); @@ -2502,17 +2654,17 @@ void GRExprEngine::VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, } } -void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, +void GRExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, ExplodedNodeSet& Dst) { // The CFG has one DeclStmt per Decl. - Decl* D = *DS->decl_begin(); + const Decl* D = *DS->decl_begin(); if (!D || !isa(D)) return; const VarDecl* VD = dyn_cast(D); - Expr* InitEx = const_cast(VD->getInit()); + const Expr* InitEx = VD->getInit(); // FIXME: static variables may have an initializer, but the second // time a function is called those values may not be current. @@ -2534,7 +2686,7 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, Tmp.Add(Pred); ExplodedNodeSet Tmp2; - CheckerVisit(DS, Tmp2, Tmp, true); + CheckerVisit(DS, Tmp2, Tmp, PreVisitStmtCallback); for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) { ExplodedNode *N = *I; @@ -2555,7 +2707,7 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, Builder->getCurrentBlockCount()); } - EvalBind(Dst, DS, DS, *I, state, + EvalBind(Dst, DS, *I, state, loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); } else { @@ -2565,10 +2717,10 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, } } -void GRExprEngine::VisitCondInit(VarDecl *VD, Stmt *S, +void GRExprEngine::VisitCondInit(const VarDecl *VD, const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet& Dst) { - Expr* InitEx = VD->getInit(); + const Expr* InitEx = VD->getInit(); ExplodedNodeSet Tmp; Visit(InitEx, Pred, Tmp); @@ -2587,7 +2739,7 @@ void GRExprEngine::VisitCondInit(VarDecl *VD, Stmt *S, Builder->getCurrentBlockCount()); } - EvalBind(Dst, S, S, N, state, + EvalBind(Dst, S, N, state, loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); } } @@ -2599,16 +2751,16 @@ class InitListWLItem { public: llvm::ImmutableList Vals; ExplodedNode* N; - InitListExpr::reverse_iterator Itr; + InitListExpr::const_reverse_iterator Itr; InitListWLItem(ExplodedNode* n, llvm::ImmutableList vals, - InitListExpr::reverse_iterator itr) + InitListExpr::const_reverse_iterator itr) : Vals(vals), N(n), Itr(itr) {} }; } -void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, +void GRExprEngine::VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred, ExplodedNodeSet& Dst) { const GRState* state = GetState(Pred); @@ -2630,7 +2782,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, llvm::SmallVector WorkList; WorkList.reserve(NumInitElements); WorkList.push_back(InitListWLItem(Pred, StartVals, E->rbegin())); - InitListExpr::reverse_iterator ItrEnd = E->rend(); + InitListExpr::const_reverse_iterator ItrEnd = E->rend(); assert(!(E->rbegin() == E->rend())); // Process the worklist until it is empty. @@ -2641,7 +2793,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, ExplodedNodeSet Tmp; Visit(*X.Itr, X.N, Tmp); - InitListExpr::reverse_iterator NewItr = X.Itr + 1; + InitListExpr::const_reverse_iterator NewItr = X.Itr + 1; for (ExplodedNodeSet::iterator NI=Tmp.begin(),NE=Tmp.end();NI!=NE;++NI) { // Get the last initializer value. @@ -2673,7 +2825,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, if (Loc::IsLocType(T) || T->isIntegerType()) { assert (E->getNumInits() == 1); ExplodedNodeSet Tmp; - Expr* Init = E->getInit(0); + const Expr* Init = E->getInit(0); Visit(Init, Pred, Tmp); for (ExplodedNodeSet::iterator I=Tmp.begin(), EI=Tmp.end(); I != EI; ++I) { state = GetState(*I); @@ -2686,7 +2838,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred, } /// VisitSizeOfAlignOfExpr - Transfer function for sizeof(type). -void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, +void GRExprEngine::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst) { QualType T = Ex->getTypeOfArgument(); @@ -2709,7 +2861,7 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, // Get the size by getting the extent of the sub-expression. // First, visit the sub-expression to find its region. - Expr *Arg = Ex->getArgumentExpr(); + const Expr *Arg = Ex->getArgumentExpr(); ExplodedNodeSet Tmp; VisitLValue(Arg, Pred, Tmp); @@ -2751,8 +2903,8 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ValMgr.makeIntVal(amt.getQuantity(), Ex->getType()))); } -void GRExprEngine::VisitOffsetOfExpr(OffsetOfExpr* OOE, ExplodedNode* Pred, - ExplodedNodeSet& Dst) { +void GRExprEngine::VisitOffsetOfExpr(const OffsetOfExpr* OOE, + ExplodedNode* Pred, ExplodedNodeSet& Dst) { Expr::EvalResult Res; if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) { const APSInt &IV = Res.Val.getInt(); @@ -2767,7 +2919,8 @@ void GRExprEngine::VisitOffsetOfExpr(OffsetOfExpr* OOE, ExplodedNode* Pred, Dst.Add(Pred); } -void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, +void GRExprEngine::VisitUnaryOperator(const UnaryOperator* U, + ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue) { switch (U->getOpcode()) { @@ -2775,9 +2928,9 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, default: break; - case UnaryOperator::Deref: { + case UO_Deref: { - Expr* Ex = U->getSubExpr()->IgnoreParens(); + const Expr* Ex = U->getSubExpr()->IgnoreParens(); ExplodedNodeSet Tmp; Visit(Ex, Pred, Tmp); @@ -2796,9 +2949,9 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, return; } - case UnaryOperator::Real: { + case UO_Real: { - Expr* Ex = U->getSubExpr()->IgnoreParens(); + const Expr* Ex = U->getSubExpr()->IgnoreParens(); ExplodedNodeSet Tmp; Visit(Ex, Pred, Tmp); @@ -2811,7 +2964,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, continue; } - // For all other types, UnaryOperator::Real is an identity operation. + // For all other types, UO_Real is an identity operation. assert (U->getType() == Ex->getType()); const GRState* state = GetState(*I); MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex))); @@ -2820,9 +2973,9 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, return; } - case UnaryOperator::Imag: { + case UO_Imag: { - Expr* Ex = U->getSubExpr()->IgnoreParens(); + const Expr* Ex = U->getSubExpr()->IgnoreParens(); ExplodedNodeSet Tmp; Visit(Ex, Pred, Tmp); @@ -2834,8 +2987,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, continue; } - // For all other types, UnaryOperator::Float returns 0. - assert (Ex->getType()->isIntegerType()); + // For all other types, UO_Imag returns 0. const GRState* state = GetState(*I); SVal X = ValMgr.makeZeroVal(Ex->getType()); MakeNode(Dst, U, *I, state->BindExpr(U, X)); @@ -2843,38 +2995,22 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, return; } - - case UnaryOperator::OffsetOf: { - Expr::EvalResult Res; - if (U->Evaluate(Res, getContext()) && Res.Val.isInt()) { - const APSInt &IV = Res.Val.getInt(); - assert(IV.getBitWidth() == getContext().getTypeSize(U->getType())); - assert(U->getType()->isIntegerType()); - assert(IV.isSigned() == U->getType()->isSignedIntegerType()); - SVal X = ValMgr.makeIntVal(IV); - MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X)); - return; - } - // FIXME: Handle the case where __builtin_offsetof is not a constant. - Dst.Add(Pred); - return; - } - case UnaryOperator::Plus: assert(!asLValue); // FALL-THROUGH. - case UnaryOperator::Extension: { + case UO_Plus: assert(!asLValue); // FALL-THROUGH. + case UO_Extension: { // Unary "+" is a no-op, similar to a parentheses. We still have places // where it may be a block-level expression, so we need to // generate an extra node that just propagates the value of the // subexpression. - Expr* Ex = U->getSubExpr()->IgnoreParens(); + const Expr* Ex = U->getSubExpr()->IgnoreParens(); ExplodedNodeSet Tmp; if (asLValue) - VisitLValue(Ex, Pred, Tmp); + VisitLValue(Ex, Pred, Tmp); else - Visit(Ex, Pred, Tmp); + Visit(Ex, Pred, Tmp); for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { const GRState* state = GetState(*I); @@ -2884,10 +3020,10 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, return; } - case UnaryOperator::AddrOf: { + case UO_AddrOf: { assert(!asLValue); - Expr* Ex = U->getSubExpr()->IgnoreParens(); + const Expr* Ex = U->getSubExpr()->IgnoreParens(); ExplodedNodeSet Tmp; VisitLValue(Ex, Pred, Tmp); @@ -2901,12 +3037,12 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, return; } - case UnaryOperator::LNot: - case UnaryOperator::Minus: - case UnaryOperator::Not: { + case UO_LNot: + case UO_Minus: + case UO_Not: { assert (!asLValue); - Expr* Ex = U->getSubExpr()->IgnoreParens(); + const Expr* Ex = U->getSubExpr()->IgnoreParens(); ExplodedNodeSet Tmp; Visit(Ex, Pred, Tmp); @@ -2937,17 +3073,17 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, assert(false && "Invalid Opcode."); break; - case UnaryOperator::Not: + case UO_Not: // FIXME: Do we need to handle promotions? state = state->BindExpr(U, EvalComplement(cast(V))); break; - case UnaryOperator::Minus: + case UO_Minus: // FIXME: Do we need to handle promotions? state = state->BindExpr(U, EvalMinus(cast(V))); break; - case UnaryOperator::LNot: + case UO_LNot: // C99 6.5.3.3: "The expression !E is equivalent to (0==E)." // @@ -2957,12 +3093,12 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, if (isa(V)) { Loc X = ValMgr.makeNull(); - Result = EvalBinOp(state, BinaryOperator::EQ, cast(V), X, + Result = EvalBinOp(state, BO_EQ, cast(V), X, U->getType()); } else { nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType())); - Result = EvalBinOp(state, BinaryOperator::EQ, cast(V), X, + Result = EvalBinOp(state, BO_EQ, cast(V), X, U->getType()); } @@ -2982,7 +3118,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, assert (U->isIncrementDecrementOp()); ExplodedNodeSet Tmp; - Expr* Ex = U->getSubExpr()->IgnoreParens(); + const Expr* Ex = U->getSubExpr()->IgnoreParens(); VisitLValue(Ex, Pred, Tmp); for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) { @@ -3007,8 +3143,8 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, DefinedSVal V2 = cast(V2_untested); // Handle all other values. - BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add - : BinaryOperator::Sub; + BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add + : BO_Sub; // If the UnaryOperator has non-location type, use its type to create the // constant value. If the UnaryOperator has location type, create the @@ -3057,14 +3193,14 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, } } -void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, +void GRExprEngine::VisitAsmStmt(const AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst) { VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst); } -void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A, - AsmStmt::outputs_iterator I, - AsmStmt::outputs_iterator E, +void GRExprEngine::VisitAsmStmtHelperOutputs(const AsmStmt* A, + AsmStmt::const_outputs_iterator I, + AsmStmt::const_outputs_iterator E, ExplodedNode* Pred, ExplodedNodeSet& Dst) { if (I == E) { VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst); @@ -3080,9 +3216,9 @@ void GRExprEngine::VisitAsmStmtHelperOutputs(AsmStmt* A, VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst); } -void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A, - AsmStmt::inputs_iterator I, - AsmStmt::inputs_iterator E, +void GRExprEngine::VisitAsmStmtHelperInputs(const AsmStmt* A, + AsmStmt::const_inputs_iterator I, + AsmStmt::const_inputs_iterator E, ExplodedNode* Pred, ExplodedNodeSet& Dst) { if (I == E) { @@ -3096,7 +3232,7 @@ void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A, const GRState* state = GetState(Pred); - for (AsmStmt::outputs_iterator OI = A->begin_outputs(), + for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(), OE = A->end_outputs(); OI != OE; ++OI) { SVal X = state->getSVal(*OI); @@ -3119,10 +3255,10 @@ void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A, VisitAsmStmtHelperInputs(A, I, E, *NI, Dst); } -void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred, +void GRExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNodeSet Src; - if (Expr *RetE = RS->getRetValue()) { + if (const Expr *RetE = RS->getRetValue()) { // Record the returned expression in the state. It will be used in // ProcessCallExit to bind the return value to the call expr. { @@ -3141,7 +3277,7 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred, } ExplodedNodeSet CheckedSet; - CheckerVisit(RS, CheckedSet, Src, true); + CheckerVisit(RS, CheckedSet, Src, PreVisitStmtCallback); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I != E; ++I) { @@ -3167,7 +3303,7 @@ void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred, // Transfer functions: Binary operators. //===----------------------------------------------------------------------===// -void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, +void GRExprEngine::VisitBinaryOperator(const BinaryOperator* B, ExplodedNode* Pred, ExplodedNodeSet& Dst, bool asLValue) { @@ -3194,7 +3330,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, Visit(RHS, *I1, Tmp2); ExplodedNodeSet CheckedSet; - CheckerVisit(B, CheckedSet, Tmp2, true); + CheckerVisit(B, CheckedSet, Tmp2, PreVisitStmtCallback); // With both the LHS and RHS evaluated, process the operation itself. @@ -3207,13 +3343,13 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, BinaryOperator::Opcode Op = B->getOpcode(); - if (Op == BinaryOperator::Assign) { + if (Op == BO_Assign) { // EXPERIMENTAL: "Conjured" symbols. // FIXME: Handle structs. QualType T = RHS->getType(); - if ((RightV.isUnknown()||!getConstraintManager().canReasonAbout(RightV)) - && (Loc::IsLocType(T) || (T->isScalarType()&&T->isIntegerType()))) { + if (RightV.isUnknown() ||!getConstraintManager().canReasonAbout(RightV)) + { unsigned Count = Builder->getCurrentBlockCount(); RightV = ValMgr.getConjuredSymbolVal(NULL, B->getRHS(), Count); } @@ -3253,16 +3389,16 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, switch (Op) { default: assert(0 && "Invalid opcode for compound assignment."); - case BinaryOperator::MulAssign: Op = BinaryOperator::Mul; break; - case BinaryOperator::DivAssign: Op = BinaryOperator::Div; break; - case BinaryOperator::RemAssign: Op = BinaryOperator::Rem; break; - case BinaryOperator::AddAssign: Op = BinaryOperator::Add; break; - case BinaryOperator::SubAssign: Op = BinaryOperator::Sub; break; - case BinaryOperator::ShlAssign: Op = BinaryOperator::Shl; break; - case BinaryOperator::ShrAssign: Op = BinaryOperator::Shr; break; - case BinaryOperator::AndAssign: Op = BinaryOperator::And; break; - case BinaryOperator::XorAssign: Op = BinaryOperator::Xor; break; - case BinaryOperator::OrAssign: Op = BinaryOperator::Or; break; + case BO_MulAssign: Op = BO_Mul; break; + case BO_DivAssign: Op = BO_Div; break; + case BO_RemAssign: Op = BO_Rem; break; + case BO_AddAssign: Op = BO_Add; break; + case BO_SubAssign: Op = BO_Sub; break; + case BO_ShlAssign: Op = BO_Shl; break; + case BO_ShrAssign: Op = BO_Shr; break; + case BO_AndAssign: Op = BO_And; break; + case BO_XorAssign: Op = BO_Xor; break; + case BO_OrAssign: Op = BO_Or; break; } // Perform a load (the LHS). This performs the checks for @@ -3300,10 +3436,8 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, SVal LHSVal; - if ((Result.isUnknown() || - !getConstraintManager().canReasonAbout(Result)) - && (Loc::IsLocType(CTy) - || (CTy->isScalarType() && CTy->isIntegerType()))) { + if (Result.isUnknown() || + !getConstraintManager().canReasonAbout(Result)) { unsigned Count = Builder->getCurrentBlockCount(); @@ -3327,7 +3461,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, } } - CheckerVisit(B, Dst, Tmp3, false); + CheckerVisit(B, Dst, Tmp3, PostVisitStmtCallback); } //===----------------------------------------------------------------------===// @@ -3457,7 +3591,7 @@ struct DOTGraphTraits : Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B" << E.getDst()->getBlockID() << ')'; - if (Stmt* T = E.getSrc()->getTerminator()) { + if (const Stmt* T = E.getSrc()->getTerminator()) { SourceLocation SLoc = T->getLocStart(); @@ -3473,15 +3607,15 @@ struct DOTGraphTraits : } if (isa(T)) { - Stmt* Label = E.getDst()->getLabel(); + const Stmt* Label = E.getDst()->getLabel(); if (Label) { - if (CaseStmt* C = dyn_cast(Label)) { + if (const CaseStmt* C = dyn_cast(Label)) { Out << "\\lcase "; LangOptions LO; // FIXME. C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO)); - if (Stmt* RHS = C->getRHS()) { + if (const Stmt* RHS = C->getRHS()) { Out << " .. "; RHS->printPretty(Out, 0, PrintingPolicy(LO)); } diff --git a/lib/Checker/GRExprEngineExperimentalChecks.cpp b/lib/Checker/GRExprEngineExperimentalChecks.cpp index d138e81..84262b0 100644 --- a/lib/Checker/GRExprEngineExperimentalChecks.cpp +++ b/lib/Checker/GRExprEngineExperimentalChecks.cpp @@ -18,13 +18,14 @@ using namespace clang; -void clang::RegisterExperimentalChecks(GRExprEngine &Eng) { +void clang::RegisterExperimentalChecks(GRExprEngine &Eng) { // These are checks that never belong as internal checks // within GRExprEngine. - RegisterPthreadLockChecker(Eng); + RegisterCStringChecker(Eng); RegisterMallocChecker(Eng); + RegisterPthreadLockChecker(Eng); RegisterStreamChecker(Eng); - RegisterCStringChecker(Eng); + RegisterUnreachableCodeChecker(Eng); } void clang::RegisterExperimentalInternalChecks(GRExprEngine &Eng) { @@ -34,11 +35,10 @@ void clang::RegisterExperimentalInternalChecks(GRExprEngine &Eng) { // Note that this must be registered after ReturnStackAddresEngsChecker. RegisterReturnPointerRangeChecker(Eng); + RegisterArrayBoundChecker(Eng); + RegisterCastSizeChecker(Eng); + RegisterCastToStructChecker(Eng); RegisterFixedAddressChecker(Eng); - RegisterPointerSubChecker(Eng); RegisterPointerArithChecker(Eng); - RegisterCastToStructChecker(Eng); - RegisterCastSizeChecker(Eng); - RegisterArrayBoundChecker(Eng); - + RegisterPointerSubChecker(Eng); } diff --git a/lib/Checker/GRExprEngineExperimentalChecks.h b/lib/Checker/GRExprEngineExperimentalChecks.h index 7d1eb77..7b5b0ed 100644 --- a/lib/Checker/GRExprEngineExperimentalChecks.h +++ b/lib/Checker/GRExprEngineExperimentalChecks.h @@ -20,10 +20,11 @@ namespace clang { class GRExprEngine; void RegisterCStringChecker(GRExprEngine &Eng); -void RegisterPthreadLockChecker(GRExprEngine &Eng); +void RegisterIdempotentOperationChecker(GRExprEngine &Eng); void RegisterMallocChecker(GRExprEngine &Eng); +void RegisterPthreadLockChecker(GRExprEngine &Eng); void RegisterStreamChecker(GRExprEngine &Eng); -void RegisterIdempotentOperationChecker(GRExprEngine &Eng); +void RegisterUnreachableCodeChecker(GRExprEngine &Eng); } // end clang namespace #endif diff --git a/lib/Checker/GRState.cpp b/lib/Checker/GRState.cpp index 9e584b5..d38ae21 100644 --- a/lib/Checker/GRState.cpp +++ b/lib/Checker/GRState.cpp @@ -14,6 +14,7 @@ #include "clang/Analysis/CFG.h" #include "clang/Checker/PathSensitive/GRStateTrait.h" #include "clang/Checker/PathSensitive/GRState.h" +#include "clang/Checker/PathSensitive/GRSubEngine.h" #include "clang/Checker/PathSensitive/GRTransferFuncs.h" #include "llvm/Support/raw_ostream.h" @@ -51,22 +52,105 @@ GRStateManager::RemoveDeadBindings(const GRState* state, state, RegionRoots); // Clean up the store. - const GRState *s = StoreMgr->RemoveDeadBindings(NewState, LCtx, - SymReaper, RegionRoots); + NewState.St = StoreMgr->RemoveDeadBindings(NewState.St, LCtx, + SymReaper, RegionRoots); + state = getPersistentState(NewState); + return ConstraintMgr->RemoveDeadBindings(state, SymReaper); +} + +const GRState *GRStateManager::MarshalState(const GRState *state, + const StackFrameContext *InitLoc) { + // make up an empty state for now. + GRState State(this, + EnvMgr.getInitialEnvironment(), + StoreMgr->getInitialStore(InitLoc), + GDMFactory.GetEmptyMap()); + + return getPersistentState(State); +} + +const GRState *GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL, + const LocationContext *LC, + SVal V) const { + Store new_store = + getStateManager().StoreMgr->BindCompoundLiteral(St, CL, LC, V); + return makeWithStore(new_store); +} + +const GRState *GRState::bindDecl(const VarRegion* VR, SVal IVal) const { + Store new_store = getStateManager().StoreMgr->BindDecl(St, VR, IVal); + return makeWithStore(new_store); +} + +const GRState *GRState::bindDeclWithNoInit(const VarRegion* VR) const { + Store new_store = getStateManager().StoreMgr->BindDeclWithNoInit(St, VR); + return makeWithStore(new_store); +} + +const GRState *GRState::bindLoc(Loc LV, SVal V) const { + GRStateManager &Mgr = getStateManager(); + Store new_store = Mgr.StoreMgr->Bind(St, LV, V); + const GRState *new_state = makeWithStore(new_store); - return ConstraintMgr->RemoveDeadBindings(s, SymReaper); + const MemRegion *MR = LV.getAsRegion(); + if (MR) + return Mgr.getOwningEngine().ProcessRegionChange(new_state, MR); + + return new_state; +} + +const GRState *GRState::bindDefault(SVal loc, SVal V) const { + GRStateManager &Mgr = getStateManager(); + const MemRegion *R = cast(loc).getRegion(); + Store new_store = Mgr.StoreMgr->BindDefault(St, R, V); + const GRState *new_state = makeWithStore(new_store); + return Mgr.getOwningEngine().ProcessRegionChange(new_state, R); +} + +const GRState *GRState::InvalidateRegions(const MemRegion * const *Begin, + const MemRegion * const *End, + const Expr *E, unsigned Count, + StoreManager::InvalidatedSymbols *IS, + bool invalidateGlobals) const { + GRStateManager &Mgr = getStateManager(); + GRSubEngine &Eng = Mgr.getOwningEngine(); + + if (Eng.WantsRegionChangeUpdate(this)) { + StoreManager::InvalidatedRegions Regions; + + Store new_store = Mgr.StoreMgr->InvalidateRegions(St, Begin, End, + E, Count, IS, + invalidateGlobals, + &Regions); + const GRState *new_state = makeWithStore(new_store); + + return Eng.ProcessRegionChanges(new_state, + &Regions.front(), + &Regions.back()+1); + } + + Store new_store = Mgr.StoreMgr->InvalidateRegions(St, Begin, End, + E, Count, IS, + invalidateGlobals, + NULL); + return makeWithStore(new_store); } const GRState *GRState::unbindLoc(Loc LV) const { + assert(!isa(LV) && "Use InvalidateRegion instead."); + Store OldStore = getStore(); Store NewStore = getStateManager().StoreMgr->Remove(OldStore, LV); if (NewStore == OldStore) return this; - GRState NewSt = *this; - NewSt.St = NewStore; - return getStateManager().getPersistentState(NewSt); + return makeWithStore(NewStore); +} + +const GRState *GRState::EnterStackFrame(const StackFrameContext *frame) const { + Store new_store = getStateManager().StoreMgr->EnterStackFrame(this, frame); + return makeWithStore(new_store); } SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const { @@ -77,7 +161,7 @@ SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const { return UnknownVal(); if (const TypedRegion *TR = dyn_cast(R)) { - QualType T = TR->getValueType(getStateManager().getContext()); + QualType T = TR->getValueType(); if (Loc::IsLocType(T) || T->isIntegerType()) return getSVal(R); } @@ -85,9 +169,45 @@ SVal GRState::getSValAsScalarOrLoc(const MemRegion *R) const { return UnknownVal(); } +SVal GRState::getSimplifiedSVal(Loc location, QualType T) const { + SVal V = getSVal(cast(location), T); + + // If 'V' is a symbolic value that is *perfectly* constrained to + // be a constant value, use that value instead to lessen the burden + // on later analysis stages (so we have less symbolic values to reason + // about). + if (!T.isNull()) { + if (SymbolRef sym = V.getAsSymbol()) { + if (const llvm::APSInt *Int = getSymVal(sym)) { + // FIXME: Because we don't correctly model (yet) sign-extension + // and truncation of symbolic values, we need to convert + // the integer value to the correct signedness and bitwidth. + // + // This shows up in the following: + // + // char foo(); + // unsigned x = foo(); + // if (x == 54) + // ... + // + // The symbolic value stored to 'x' is actually the conjured + // symbol for the call to foo(); the type of that symbol is 'char', + // not unsigned. + const llvm::APSInt &NewV = getBasicVals().Convert(T, *Int); + + if (isa(V)) + return loc::ConcreteInt(NewV); + else + return nonloc::ConcreteInt(NewV); + } + } + } + + return V; +} -const GRState *GRState::BindExpr(const Stmt* Ex, SVal V, bool Invalidate) const{ - Environment NewEnv = getStateManager().EnvMgr.BindExpr(Env, Ex, V, +const GRState *GRState::BindExpr(const Stmt* S, SVal V, bool Invalidate) const{ + Environment NewEnv = getStateManager().EnvMgr.bindExpr(Env, S, V, Invalidate); if (NewEnv == Env) return this; @@ -97,6 +217,63 @@ const GRState *GRState::BindExpr(const Stmt* Ex, SVal V, bool Invalidate) const{ return getStateManager().getPersistentState(NewSt); } +const GRState *GRState::bindExprAndLocation(const Stmt *S, SVal location, + SVal V) const { + Environment NewEnv = + getStateManager().EnvMgr.bindExprAndLocation(Env, S, location, V); + + if (NewEnv == Env) + return this; + + GRState NewSt = *this; + NewSt.Env = NewEnv; + return getStateManager().getPersistentState(NewSt); +} + +const GRState *GRState::AssumeInBound(DefinedOrUnknownSVal Idx, + DefinedOrUnknownSVal UpperBound, + bool Assumption) const { + if (Idx.isUnknown() || UpperBound.isUnknown()) + return this; + + // Build an expression for 0 <= Idx < UpperBound. + // This is the same as Idx + MIN < UpperBound + MIN, if overflow is allowed. + // FIXME: This should probably be part of SValuator. + GRStateManager &SM = getStateManager(); + ValueManager &VM = SM.getValueManager(); + SValuator &SV = VM.getSValuator(); + ASTContext &Ctx = VM.getContext(); + + // Get the offset: the minimum value of the array index type. + BasicValueFactory &BVF = VM.getBasicValueFactory(); + // FIXME: This should be using ValueManager::ArrayIndexTy...somehow. + QualType IndexTy = Ctx.IntTy; + nonloc::ConcreteInt Min = BVF.getMinValue(IndexTy); + + // Adjust the index. + SVal NewIdx = SV.EvalBinOpNN(this, BO_Add, + cast(Idx), Min, IndexTy); + if (NewIdx.isUnknownOrUndef()) + return this; + + // Adjust the upper bound. + SVal NewBound = SV.EvalBinOpNN(this, BO_Add, + cast(UpperBound), Min, IndexTy); + if (NewBound.isUnknownOrUndef()) + return this; + + // Build the actual comparison. + SVal InBound = SV.EvalBinOpNN(this, BO_LT, + cast(NewIdx), cast(NewBound), + Ctx.IntTy); + if (InBound.isUnknownOrUndef()) + return this; + + // Finally, let the constraint manager take care of it. + ConstraintManager &CM = SM.getConstraintManager(); + return CM.Assume(this, cast(InBound), Assumption); +} + const GRState* GRStateManager::getInitialState(const LocationContext *InitLoc) { GRState State(this, EnvMgr.getInitialEnvironment(), @@ -131,6 +308,11 @@ const GRState* GRState::makeWithStore(Store store) const { // State pretty-printing. //===----------------------------------------------------------------------===// +static bool IsEnvLoc(const Stmt *S) { + // FIXME: This is a layering violation. Should be in environment. + return (bool) (((uintptr_t) S) & 0x1); +} + void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl, const char* sep) const { // Print the store. @@ -140,8 +322,9 @@ void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl, // Print Subexpression bindings. bool isFirst = true; + // FIXME: All environment printing should be moved inside Environment. for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { - if (C.isBlkExpr(I.getKey())) + if (C.isBlkExpr(I.getKey()) || IsEnvLoc(I.getKey())) continue; if (isFirst) { @@ -174,6 +357,27 @@ void GRState::print(llvm::raw_ostream& Out, CFG &C, const char* nl, I.getKey()->printPretty(Out, 0, PrintingPolicy(LO)); Out << " : " << I.getData(); } + + // Print locations. + isFirst = true; + + for (Environment::iterator I = Env.begin(), E = Env.end(); I != E; ++I) { + if (!IsEnvLoc(I.getKey())) + continue; + + if (isFirst) { + Out << nl << nl << "Load/store locations:" << nl; + isFirst = false; + } + else { Out << nl; } + + const Stmt *S = (Stmt*) (((uintptr_t) I.getKey()) & ((uintptr_t) ~0x1)); + + Out << " (" << (void*) S << ") "; + LangOptions LO; // FIXME. + S->printPretty(Out, 0, PrintingPolicy(LO)); + Out << " : " << I.getData(); + } Mgr.getConstraintManager().print(this, Out, nl, sep); diff --git a/lib/Checker/IdempotentOperationChecker.cpp b/lib/Checker/IdempotentOperationChecker.cpp index 6ed1841..6411c79 100644 --- a/lib/Checker/IdempotentOperationChecker.cpp +++ b/lib/Checker/IdempotentOperationChecker.cpp @@ -36,25 +36,26 @@ // != | 0 | | | | | | //===----------------------------------------------------------------------===// // -// Ways to reduce false positives (that need to be implemented): -// - Don't flag downsizing casts -// - Improved handling of static/global variables -// - Per-block marking of incomplete analysis -// - Handling ~0 values -// - False positives involving silencing unused variable warnings -// -// Other things TODO: +// Things TODO: // - Improved error messages // - Handle mixed assumptions (which assumptions can belong together?) // - Finer grained false positive control (levels) +// - Handling ~0 values #include "GRExprEngineExperimentalChecks.h" +#include "clang/Analysis/CFGStmtMap.h" +#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h" +#include "clang/Checker/BugReporter/BugReporter.h" #include "clang/Checker/BugReporter/BugType.h" +#include "clang/Checker/PathSensitive/CheckerHelpers.h" #include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/GRCoreEngine.h" #include "clang/Checker/PathSensitive/SVals.h" #include "clang/AST/Stmt.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/Support/ErrorHandling.h" +#include using namespace clang; @@ -64,38 +65,41 @@ class IdempotentOperationChecker public: static void *getTag(); void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); - void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, - bool hasWorkRemaining); + void PostVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); + void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, GRExprEngine &Eng); private: // Our assumption about a particular operation. - enum Assumption { Possible, Impossible, Equal, LHSis1, RHSis1, LHSis0, + enum Assumption { Possible = 0, Impossible, Equal, LHSis1, RHSis1, LHSis0, RHSis0 }; void UpdateAssumption(Assumption &A, const Assumption &New); - /// contains* - Useful recursive methods to see if a statement contains an - /// element somewhere. Used in static analysis to reduce false positives. - static bool containsMacro(const Stmt *S); - static bool containsEnum(const Stmt *S); - static bool containsBuiltinOffsetOf(const Stmt *S); - static bool containsZeroConstant(const Stmt *S); - static bool containsOneConstant(const Stmt *S); - template static bool containsStmt(const Stmt *S) { - if (isa(S)) - return true; - - for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); - ++I) - if (const Stmt *child = *I) - if (containsStmt(child)) - return true; - - return false; - } - - // Hash table - typedef llvm::DenseMap AssumptionMap; + // False positive reduction methods + static bool isSelfAssign(const Expr *LHS, const Expr *RHS); + static bool isUnused(const Expr *E, AnalysisContext *AC); + //static bool isTruncationExtensionAssignment(const Expr *LHS, + // const Expr *RHS); + static bool PathWasCompletelyAnalyzed(const CFG *C, + const CFGBlock *CB, + const GRCoreEngine &CE); + static bool CanVary(const Expr *Ex, + AnalysisContext *AC); + static bool isConstantOrPseudoConstant(const DeclRefExpr *DR, + AnalysisContext *AC); + static bool containsNonLocalVarDecl(const Stmt *S); + + // Hash table and related data structures + struct BinaryOperatorData { + BinaryOperatorData() : assumption(Possible), analysisContext(0) {} + + Assumption assumption; + AnalysisContext *analysisContext; + ExplodedNodeSet explodedNodes; // Set of ExplodedNodes that refer to a + // BinaryOperator + }; + typedef llvm::DenseMap + AssumptionMap; AssumptionMap hash; }; } @@ -112,30 +116,38 @@ void clang::RegisterIdempotentOperationChecker(GRExprEngine &Eng) { void IdempotentOperationChecker::PreVisitBinaryOperator( CheckerContext &C, const BinaryOperator *B) { - // Find or create an entry in the hash for this BinaryOperator instance - AssumptionMap::iterator i = hash.find(B); - Assumption &A = i == hash.end() ? hash[B] : i->second; - - // If we had to create an entry, initialise the value to Possible - if (i == hash.end()) - A = Possible; + // Find or create an entry in the hash for this BinaryOperator instance. + // If we haven't done a lookup before, it will get default initialized to + // 'Possible'. At this stage we do not store the ExplodedNode, as it has not + // been created yet. + BinaryOperatorData &Data = hash[B]; + Assumption &A = Data.assumption; + AnalysisContext *AC = C.getCurrentAnalysisContext(); + Data.analysisContext = AC; // If we already have visited this node on a path that does not contain an // idempotent operation, return immediately. if (A == Impossible) return; - // Skip binary operators containing common false positives - if (containsMacro(B) || containsEnum(B) || containsStmt(B) - || containsZeroConstant(B) || containsOneConstant(B) - || containsBuiltinOffsetOf(B)) { - A = Impossible; - return; - } - + // Retrieve both sides of the operator and determine if they can vary (which + // may mean this is a false positive. const Expr *LHS = B->getLHS(); const Expr *RHS = B->getRHS(); + // At this stage we can calculate whether each side contains a false positive + // that applies to all operators. We only need to calculate this the first + // time. + bool LHSContainsFalsePositive = false, RHSContainsFalsePositive = false; + if (A == Possible) { + // An expression contains a false positive if it can't vary, or if it + // contains a known false positive VarDecl. + LHSContainsFalsePositive = !CanVary(LHS, AC) + || containsNonLocalVarDecl(LHS); + RHSContainsFalsePositive = !CanVary(RHS, AC) + || containsNonLocalVarDecl(RHS); + } + const GRState *state = C.getState(); SVal LHSVal = state->getSVal(LHS); @@ -154,16 +166,16 @@ void IdempotentOperationChecker::PreVisitBinaryOperator( break; // Fall through intentional - case BinaryOperator::AddAssign: - case BinaryOperator::SubAssign: - case BinaryOperator::MulAssign: - case BinaryOperator::DivAssign: - case BinaryOperator::AndAssign: - case BinaryOperator::OrAssign: - case BinaryOperator::XorAssign: - case BinaryOperator::ShlAssign: - case BinaryOperator::ShrAssign: - case BinaryOperator::Assign: + case BO_AddAssign: + case BO_SubAssign: + case BO_MulAssign: + case BO_DivAssign: + case BO_AndAssign: + case BO_OrAssign: + case BO_XorAssign: + case BO_ShlAssign: + case BO_ShrAssign: + case BO_Assign: // Assign statements have one extra level of indirection if (!isa(LHSVal)) { A = Impossible; @@ -181,20 +193,37 @@ void IdempotentOperationChecker::PreVisitBinaryOperator( break; // We don't care about any other operators. // Fall through intentional - case BinaryOperator::SubAssign: - case BinaryOperator::DivAssign: - case BinaryOperator::AndAssign: - case BinaryOperator::OrAssign: - case BinaryOperator::XorAssign: - case BinaryOperator::Assign: - case BinaryOperator::Sub: - case BinaryOperator::Div: - case BinaryOperator::And: - case BinaryOperator::Or: - case BinaryOperator::Xor: - case BinaryOperator::LOr: - case BinaryOperator::LAnd: - if (LHSVal != RHSVal) + case BO_Assign: + // x Assign x can be used to silence unused variable warnings intentionally. + // If this is a self assignment and the variable is referenced elsewhere, + // then it is a false positive. + if (isSelfAssign(LHS, RHS)) { + if (!isUnused(LHS, AC)) { + UpdateAssumption(A, Equal); + return; + } + else { + A = Impossible; + return; + } + } + + case BO_SubAssign: + case BO_DivAssign: + case BO_AndAssign: + case BO_OrAssign: + case BO_XorAssign: + case BO_Sub: + case BO_Div: + case BO_And: + case BO_Or: + case BO_Xor: + case BO_LOr: + case BO_LAnd: + case BO_EQ: + case BO_NE: + if (LHSVal != RHSVal || LHSContainsFalsePositive + || RHSContainsFalsePositive) break; UpdateAssumption(A, Equal); return; @@ -206,13 +235,13 @@ void IdempotentOperationChecker::PreVisitBinaryOperator( break; // We don't care about any other operators. // Fall through intentional - case BinaryOperator::MulAssign: - case BinaryOperator::DivAssign: - case BinaryOperator::Mul: - case BinaryOperator::Div: - case BinaryOperator::LOr: - case BinaryOperator::LAnd: - if (!RHSVal.isConstant(1)) + case BO_MulAssign: + case BO_DivAssign: + case BO_Mul: + case BO_Div: + case BO_LOr: + case BO_LAnd: + if (!RHSVal.isConstant(1) || RHSContainsFalsePositive) break; UpdateAssumption(A, RHSis1); return; @@ -224,11 +253,11 @@ void IdempotentOperationChecker::PreVisitBinaryOperator( break; // We don't care about any other operators. // Fall through intentional - case BinaryOperator::MulAssign: - case BinaryOperator::Mul: - case BinaryOperator::LOr: - case BinaryOperator::LAnd: - if (!LHSVal.isConstant(1)) + case BO_MulAssign: + case BO_Mul: + case BO_LOr: + case BO_LAnd: + if (!LHSVal.isConstant(1) || LHSContainsFalsePositive) break; UpdateAssumption(A, LHSis1); return; @@ -240,23 +269,23 @@ void IdempotentOperationChecker::PreVisitBinaryOperator( break; // We don't care about any other operators. // Fall through intentional - case BinaryOperator::AddAssign: - case BinaryOperator::SubAssign: - case BinaryOperator::MulAssign: - case BinaryOperator::AndAssign: - case BinaryOperator::OrAssign: - case BinaryOperator::XorAssign: - case BinaryOperator::Add: - case BinaryOperator::Sub: - case BinaryOperator::Mul: - case BinaryOperator::And: - case BinaryOperator::Or: - case BinaryOperator::Xor: - case BinaryOperator::Shl: - case BinaryOperator::Shr: - case BinaryOperator::LOr: - case BinaryOperator::LAnd: - if (!RHSVal.isConstant(0)) + case BO_AddAssign: + case BO_SubAssign: + case BO_MulAssign: + case BO_AndAssign: + case BO_OrAssign: + case BO_XorAssign: + case BO_Add: + case BO_Sub: + case BO_Mul: + case BO_And: + case BO_Or: + case BO_Xor: + case BO_Shl: + case BO_Shr: + case BO_LOr: + case BO_LAnd: + if (!RHSVal.isConstant(0) || RHSContainsFalsePositive) break; UpdateAssumption(A, RHSis0); return; @@ -268,27 +297,27 @@ void IdempotentOperationChecker::PreVisitBinaryOperator( break; // We don't care about any other operators. // Fall through intentional - //case BinaryOperator::AddAssign: // Common false positive - case BinaryOperator::SubAssign: // Check only if unsigned - case BinaryOperator::MulAssign: - case BinaryOperator::DivAssign: - case BinaryOperator::AndAssign: - //case BinaryOperator::OrAssign: // Common false positive - //case BinaryOperator::XorAssign: // Common false positive - case BinaryOperator::ShlAssign: - case BinaryOperator::ShrAssign: - case BinaryOperator::Add: - case BinaryOperator::Sub: - case BinaryOperator::Mul: - case BinaryOperator::Div: - case BinaryOperator::And: - case BinaryOperator::Or: - case BinaryOperator::Xor: - case BinaryOperator::Shl: - case BinaryOperator::Shr: - case BinaryOperator::LOr: - case BinaryOperator::LAnd: - if (!LHSVal.isConstant(0)) + //case BO_AddAssign: // Common false positive + case BO_SubAssign: // Check only if unsigned + case BO_MulAssign: + case BO_DivAssign: + case BO_AndAssign: + //case BO_OrAssign: // Common false positive + //case BO_XorAssign: // Common false positive + case BO_ShlAssign: + case BO_ShrAssign: + case BO_Add: + case BO_Sub: + case BO_Mul: + case BO_Div: + case BO_And: + case BO_Or: + case BO_Xor: + case BO_Shl: + case BO_Shr: + case BO_LOr: + case BO_LAnd: + if (!LHSVal.isConstant(0) || LHSContainsFalsePositive) break; UpdateAssumption(A, LHSis0); return; @@ -298,47 +327,103 @@ void IdempotentOperationChecker::PreVisitBinaryOperator( A = Impossible; } -void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G, - BugReporter &B, - bool hasWorkRemaining) { - // If there is any work remaining we cannot be 100% sure about our warnings - if (hasWorkRemaining) - return; +// At the post visit stage, the predecessor ExplodedNode will be the +// BinaryOperator that was just created. We use this hook to collect the +// ExplodedNode. +void IdempotentOperationChecker::PostVisitBinaryOperator( + CheckerContext &C, + const BinaryOperator *B) { + // Add the ExplodedNode we just visited + BinaryOperatorData &Data = hash[B]; + Data.explodedNodes.Add(C.getPredecessor()); +} +void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G, + BugReporter &BR, + GRExprEngine &Eng) { + BugType *BT = new BugType("Idempotent operation", "Dead code"); // Iterate over the hash to see if we have any paths with definite // idempotent operations. - for (AssumptionMap::const_iterator i = - hash.begin(); i != hash.end(); ++i) { - if (i->second != Impossible) { - // Select the error message. - const char *msg = 0; - switch (i->second) { - case Equal: - msg = "idempotent operation; both operands are always equal in value"; - break; - case LHSis1: - msg = "idempotent operation; the left operand is always 1"; - break; - case RHSis1: - msg = "idempotent operation; the right operand is always 1"; - break; - case LHSis0: - msg = "idempotent operation; the left operand is always 0"; - break; - case RHSis0: - msg = "idempotent operation; the right operand is always 0"; - break; - case Possible: - llvm_unreachable("Operation was never marked with an assumption"); - case Impossible: - llvm_unreachable(0); + for (AssumptionMap::const_iterator i = hash.begin(); i != hash.end(); ++i) { + // Unpack the hash contents + const BinaryOperatorData &Data = i->second; + const Assumption &A = Data.assumption; + AnalysisContext *AC = Data.analysisContext; + const ExplodedNodeSet &ES = Data.explodedNodes; + + const BinaryOperator *B = i->first; + + if (A == Impossible) + continue; + + // If the analyzer did not finish, check to see if we can still emit this + // warning + if (Eng.hasWorkRemaining()) { + const CFGStmtMap *CBM = CFGStmtMap::Build(AC->getCFG(), + &AC->getParentMap()); + + // If we can trace back + if (!PathWasCompletelyAnalyzed(AC->getCFG(), + CBM->getBlock(B), + Eng.getCoreEngine())) + continue; + + delete CBM; + } + + // Select the error message and SourceRanges to report. + llvm::SmallString<128> buf; + llvm::raw_svector_ostream os(buf); + bool LHSRelevant = false, RHSRelevant = false; + switch (A) { + case Equal: + LHSRelevant = true; + RHSRelevant = true; + if (B->getOpcode() == BO_Assign) + os << "Assigned value is always the same as the existing value"; + else + os << "Both operands to '" << B->getOpcodeStr() + << "' always have the same value"; + break; + case LHSis1: + LHSRelevant = true; + os << "The left operand to '" << B->getOpcodeStr() << "' is always 1"; + break; + case RHSis1: + RHSRelevant = true; + os << "The right operand to '" << B->getOpcodeStr() << "' is always 1"; + break; + case LHSis0: + LHSRelevant = true; + os << "The left operand to '" << B->getOpcodeStr() << "' is always 0"; + break; + case RHSis0: + RHSRelevant = true; + os << "The right operand to '" << B->getOpcodeStr() << "' is always 0"; + break; + case Possible: + llvm_unreachable("Operation was never marked with an assumption"); + case Impossible: + llvm_unreachable(0); + } + + // Add a report for each ExplodedNode + for (ExplodedNodeSet::iterator I = ES.begin(), E = ES.end(); I != E; ++I) { + EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), *I); + + // Add source ranges and visitor hooks + if (LHSRelevant) { + const Expr *LHS = i->first->getLHS(); + report->addRange(LHS->getSourceRange()); + report->addVisitorCreator(bugreporter::registerVarDeclsLastStore, LHS); + } + if (RHSRelevant) { + const Expr *RHS = i->first->getRHS(); + report->addRange(i->first->getRHS()->getSourceRange()); + report->addVisitorCreator(bugreporter::registerVarDeclsLastStore, RHS); } - // Create the SourceRange Arrays - SourceRange S[2] = { i->first->getLHS()->getSourceRange(), - i->first->getRHS()->getSourceRange() }; - B.EmitBasicReport("Idempotent operation", msg, i->first->getOperatorLoc(), - S, 2); + BR.EmitReport(report); } } } @@ -346,6 +431,10 @@ void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G, // Updates the current assumption given the new assumption inline void IdempotentOperationChecker::UpdateAssumption(Assumption &A, const Assumption &New) { +// If the assumption is the same, there is nothing to do + if (A == New) + return; + switch (A) { // If we don't currently have an assumption, set it case Possible: @@ -366,89 +455,249 @@ inline void IdempotentOperationChecker::UpdateAssumption(Assumption &A, } } -// Recursively find any substatements containing macros -bool IdempotentOperationChecker::containsMacro(const Stmt *S) { - if (S->getLocStart().isMacroID()) - return true; +// Check for a statement where a variable is self assigned to possibly avoid an +// unused variable warning. +bool IdempotentOperationChecker::isSelfAssign(const Expr *LHS, const Expr *RHS) { + LHS = LHS->IgnoreParenCasts(); + RHS = RHS->IgnoreParenCasts(); - if (S->getLocEnd().isMacroID()) - return true; + const DeclRefExpr *LHS_DR = dyn_cast(LHS); + if (!LHS_DR) + return false; - for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); - ++I) - if (const Stmt *child = *I) - if (containsMacro(child)) - return true; + const VarDecl *VD = dyn_cast(LHS_DR->getDecl()); + if (!VD) + return false; - return false; + const DeclRefExpr *RHS_DR = dyn_cast(RHS); + if (!RHS_DR) + return false; + + if (VD != RHS_DR->getDecl()) + return false; + + return true; } -// Recursively find any substatements containing enum constants -bool IdempotentOperationChecker::containsEnum(const Stmt *S) { - const DeclRefExpr *DR = dyn_cast(S); +// Returns true if the Expr points to a VarDecl that is not read anywhere +// outside of self-assignments. +bool IdempotentOperationChecker::isUnused(const Expr *E, + AnalysisContext *AC) { + if (!E) + return false; - if (DR && isa(DR->getDecl())) - return true; + const DeclRefExpr *DR = dyn_cast(E->IgnoreParenCasts()); + if (!DR) + return false; - for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); - ++I) - if (const Stmt *child = *I) - if (containsEnum(child)) - return true; + const VarDecl *VD = dyn_cast(DR->getDecl()); + if (!VD) + return false; - return false; + if (AC->getPseudoConstantAnalysis()->wasReferenced(VD)) + return false; + + return true; } -// Recursively find any substatements containing __builtin_offset_of -bool IdempotentOperationChecker::containsBuiltinOffsetOf(const Stmt *S) { - const UnaryOperator *UO = dyn_cast(S); +#if 0 +// Check for self casts truncating/extending a variable +bool IdempotentOperationChecker::isTruncationExtensionAssignment( + const Expr *LHS, + const Expr *RHS) { - if (UO && UO->getOpcode() == UnaryOperator::OffsetOf) - return true; + const DeclRefExpr *LHS_DR = dyn_cast(LHS->IgnoreParenCasts()); + if (!LHS_DR) + return false; - for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); - ++I) - if (const Stmt *child = *I) - if (containsBuiltinOffsetOf(child)) - return true; + const VarDecl *VD = dyn_cast(LHS_DR->getDecl()); + if (!VD) + return false; - return false; + const DeclRefExpr *RHS_DR = dyn_cast(RHS->IgnoreParenCasts()); + if (!RHS_DR) + return false; + + if (VD != RHS_DR->getDecl()) + return false; + + return dyn_cast(RHS->IgnoreParens()) == NULL; } +#endif + +// Returns false if a path to this block was not completely analyzed, or true +// otherwise. +bool IdempotentOperationChecker::PathWasCompletelyAnalyzed( + const CFG *C, + const CFGBlock *CB, + const GRCoreEngine &CE) { + std::deque WorkList; + llvm::SmallSet Aborted; + llvm::SmallSet Visited; + + // Create a set of all aborted blocks + typedef GRCoreEngine::BlocksAborted::const_iterator AbortedIterator; + for (AbortedIterator I = CE.blocks_aborted_begin(), + E = CE.blocks_aborted_end(); I != E; ++I) { + const BlockEdge &BE = I->first; + + // The destination block on the BlockEdge is the first block that was not + // analyzed. + Aborted.insert(BE.getDst()->getBlockID()); + } -bool IdempotentOperationChecker::containsZeroConstant(const Stmt *S) { - const IntegerLiteral *IL = dyn_cast(S); - if (IL && IL->getValue() == 0) + // Save the entry block ID for early exiting + unsigned EntryBlockID = C->getEntry().getBlockID(); + + // Create initial node + WorkList.push_back(CB); + + while (!WorkList.empty()) { + const CFGBlock *Head = WorkList.front(); + WorkList.pop_front(); + Visited.insert(Head->getBlockID()); + + // If we found the entry block, then there exists a path from the target + // node to the entry point of this function -> the path was completely + // analyzed. + if (Head->getBlockID() == EntryBlockID) + return true; + + // If any of the aborted blocks are on the path to the beginning, then all + // paths to this block were not analyzed. + if (Aborted.count(Head->getBlockID())) + return false; + + // Add the predecessors to the worklist unless we have already visited them + for (CFGBlock::const_pred_iterator I = Head->pred_begin(); + I != Head->pred_end(); ++I) + if (!Visited.count((*I)->getBlockID())) + WorkList.push_back(*I); + } + + // If we get to this point, there is no connection to the entry block or an + // aborted block. This path is unreachable and we can report the error. + return true; +} + +// Recursive function that determines whether an expression contains any element +// that varies. This could be due to a compile-time constant like sizeof. An +// expression may also involve a variable that behaves like a constant. The +// function returns true if the expression varies, and false otherwise. +bool IdempotentOperationChecker::CanVary(const Expr *Ex, + AnalysisContext *AC) { + // Parentheses and casts are irrelevant here + Ex = Ex->IgnoreParenCasts(); + + if (Ex->getLocStart().isMacroID()) + return false; + + switch (Ex->getStmtClass()) { + // Trivially true cases + case Stmt::ArraySubscriptExprClass: + case Stmt::MemberExprClass: + case Stmt::StmtExprClass: + case Stmt::CallExprClass: + case Stmt::VAArgExprClass: + case Stmt::ShuffleVectorExprClass: + return true; + default: return true; - const FloatingLiteral *FL = dyn_cast(S); - if (FL && FL->getValue().isZero()) + // Trivially false cases + case Stmt::IntegerLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::FloatingLiteralClass: + case Stmt::PredefinedExprClass: + case Stmt::ImaginaryLiteralClass: + case Stmt::StringLiteralClass: + case Stmt::OffsetOfExprClass: + case Stmt::CompoundLiteralExprClass: + case Stmt::AddrLabelExprClass: + case Stmt::TypesCompatibleExprClass: + case Stmt::GNUNullExprClass: + case Stmt::InitListExprClass: + case Stmt::DesignatedInitExprClass: + case Stmt::BlockExprClass: + case Stmt::BlockDeclRefExprClass: + return false; + + // Cases requiring custom logic + case Stmt::SizeOfAlignOfExprClass: { + const SizeOfAlignOfExpr *SE = cast(Ex); + if (!SE->isSizeOf()) + return false; + return SE->getTypeOfArgument()->isVariableArrayType(); + } + case Stmt::DeclRefExprClass: + // Check for constants/pseudoconstants + return !isConstantOrPseudoConstant(cast(Ex), AC); + + // The next cases require recursion for subexpressions + case Stmt::BinaryOperatorClass: { + const BinaryOperator *B = cast(Ex); + return CanVary(B->getRHS(), AC) + || CanVary(B->getLHS(), AC); + } + case Stmt::UnaryOperatorClass: { + const UnaryOperator *U = cast(Ex); + // Handle trivial case first + switch (U->getOpcode()) { + case UO_Extension: + return false; + default: + return CanVary(U->getSubExpr(), AC); + } + } + case Stmt::ChooseExprClass: + return CanVary(cast(Ex)->getChosenSubExpr( + AC->getASTContext()), AC); + case Stmt::ConditionalOperatorClass: + return CanVary(cast(Ex)->getCond(), AC); + } +} + +// Returns true if a DeclRefExpr is or behaves like a constant. +bool IdempotentOperationChecker::isConstantOrPseudoConstant( + const DeclRefExpr *DR, + AnalysisContext *AC) { + // Check if the type of the Decl is const-qualified + if (DR->getType().isConstQualified()) return true; - for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); - ++I) - if (const Stmt *child = *I) - if (containsZeroConstant(child)) - return true; + // Check for an enum + if (isa(DR->getDecl())) + return true; + + const VarDecl *VD = dyn_cast(DR->getDecl()); + if (!VD) + return true; + + // Check if the Decl behaves like a constant. This check also takes care of + // static variables, which can only change between function calls if they are + // modified in the AST. + PseudoConstantAnalysis *PCA = AC->getPseudoConstantAnalysis(); + if (PCA->isPseudoConstant(VD)) + return true; return false; } -bool IdempotentOperationChecker::containsOneConstant(const Stmt *S) { - const IntegerLiteral *IL = dyn_cast(S); - if (IL && IL->getValue() == 1) - return true; +// Recursively find any substatements containing VarDecl's with storage other +// than local +bool IdempotentOperationChecker::containsNonLocalVarDecl(const Stmt *S) { + const DeclRefExpr *DR = dyn_cast(S); - const FloatingLiteral *FL = dyn_cast(S); - const llvm::APFloat one(1.0); - if (FL && FL->getValue().compare(one) == llvm::APFloat::cmpEqual) - return true; + if (DR) + if (const VarDecl *VD = dyn_cast(DR->getDecl())) + if (!VD->hasLocalStorage()) + return true; for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end(); ++I) if (const Stmt *child = *I) - if (containsOneConstant(child)) + if (containsNonLocalVarDecl(child)) return true; return false; } - diff --git a/lib/Checker/LLVMConventionsChecker.cpp b/lib/Checker/LLVMConventionsChecker.cpp index c121257..2f87da1 100644 --- a/lib/Checker/LLVMConventionsChecker.cpp +++ b/lib/Checker/LLVMConventionsChecker.cpp @@ -128,7 +128,6 @@ public: void VisitDeclStmt(DeclStmt *DS); private: void VisitVarDecl(VarDecl *VD); - void CheckStringRefBoundtoTemporaryString(VarDecl *VD); }; } // end anonymous namespace diff --git a/lib/Checker/Makefile b/lib/Checker/Makefile index 1bc6529..4ec6f65 100644 --- a/lib/Checker/Makefile +++ b/lib/Checker/Makefile @@ -13,7 +13,6 @@ CLANG_LEVEL := ../.. LIBRARYNAME := clangChecker -BUILD_ARCHIVE = 1 include $(CLANG_LEVEL)/Makefile diff --git a/lib/Checker/MallocChecker.cpp b/lib/Checker/MallocChecker.cpp index dcc21ca..c9b6d75 100644 --- a/lib/Checker/MallocChecker.cpp +++ b/lib/Checker/MallocChecker.cpp @@ -24,15 +24,18 @@ using namespace clang; namespace { class RefState { - enum Kind { AllocateUnchecked, AllocateFailed, Released, Escaped } K; + enum Kind { AllocateUnchecked, AllocateFailed, Released, Escaped, + Relinquished } K; const Stmt *S; public: RefState(Kind k, const Stmt *s) : K(k), S(s) {} bool isAllocated() const { return K == AllocateUnchecked; } + //bool isFailed() const { return K == AllocateFailed; } bool isReleased() const { return K == Released; } - bool isEscaped() const { return K == Escaped; } + //bool isEscaped() const { return K == Escaped; } + //bool isRelinquished() const { return K == Relinquished; } bool operator==(const RefState &X) const { return K == X.K && S == X.S; @@ -46,6 +49,9 @@ public: } static RefState getReleased(const Stmt *s) { return RefState(Released, s); } static RefState getEscaped(const Stmt *s) { return RefState(Escaped, s); } + static RefState getRelinquished(const Stmt *s) { + return RefState(Relinquished, s); + } void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); @@ -59,23 +65,30 @@ class MallocChecker : public CheckerVisitor { BuiltinBug *BT_DoubleFree; BuiltinBug *BT_Leak; BuiltinBug *BT_UseFree; + BuiltinBug *BT_UseRelinquished; BuiltinBug *BT_BadFree; IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc; public: MallocChecker() - : BT_DoubleFree(0), BT_Leak(0), BT_UseFree(0), BT_BadFree(0), + : BT_DoubleFree(0), BT_Leak(0), BT_UseFree(0), BT_UseRelinquished(0), + BT_BadFree(0), II_malloc(0), II_free(0), II_realloc(0), II_calloc(0) {} static void *getTag(); bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); void EvalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper); void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng); void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S); - const GRState *EvalAssume(const GRState *state, SVal Cond, bool Assumption); + const GRState *EvalAssume(const GRState *state, SVal Cond, bool Assumption, + bool *respondsToCallback); void VisitLocation(CheckerContext &C, const Stmt *S, SVal l); + virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE, + SVal location, SVal val); private: void MallocMem(CheckerContext &C, const CallExpr *CE); + void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, + const OwnershipAttr* Att); const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, const Expr *SizeEx, SVal Init, const GRState *state) { @@ -86,8 +99,10 @@ private: const GRState *state); void FreeMem(CheckerContext &C, const CallExpr *CE); + void FreeMemAttr(CheckerContext &C, const CallExpr *CE, + const OwnershipAttr* Att); const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE, - const GRState *state); + const GRState *state, unsigned Num, bool Hold); void ReallocMem(CheckerContext &C, const CallExpr *CE); void CallocMem(CheckerContext &C, const CallExpr *CE); @@ -103,7 +118,7 @@ typedef llvm::ImmutableMap RegionStateTy; namespace clang { template <> struct GRStateTrait - : public GRStatePartialTrait > { + : public GRStatePartialTrait { static void *GDMIndex() { return MallocChecker::getTag(); } }; } @@ -156,7 +171,32 @@ bool MallocChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { return true; } - return false; + // Check all the attributes, if there are any. + // There can be multiple of these attributes. + bool rv = false; + if (FD->hasAttrs()) { + for (specific_attr_iterator + i = FD->specific_attr_begin(), + e = FD->specific_attr_end(); + i != e; ++i) { + switch ((*i)->getOwnKind()) { + case OwnershipAttr::Returns: { + MallocMemReturnsAttr(C, CE, *i); + rv = true; + break; + } + case OwnershipAttr::Takes: + case OwnershipAttr::Holds: { + FreeMemAttr(C, CE, *i); + rv = true; + break; + } + default: + break; + } + } + } + return rv; } void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { @@ -165,6 +205,23 @@ void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) { C.addTransition(state); } +void MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, + const OwnershipAttr* Att) { + if (Att->getModule() != "malloc") + return; + + OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); + if (I != E) { + const GRState *state = + MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), C.getState()); + C.addTransition(state); + return; + } + const GRState *state = MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), + C.getState()); + C.addTransition(state); +} + const GRState *MallocChecker::MallocMemAux(CheckerContext &C, const CallExpr *CE, SVal Size, SVal Init, @@ -196,25 +253,53 @@ const GRState *MallocChecker::MallocMemAux(CheckerContext &C, } void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { - const GRState *state = FreeMemAux(C, CE, C.getState()); + const GRState *state = FreeMemAux(C, CE, C.getState(), 0, false); if (state) C.addTransition(state); } +void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE, + const OwnershipAttr* Att) { + if (Att->getModule() != "malloc") + return; + + for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); + I != E; ++I) { + const GRState *state = FreeMemAux(C, CE, C.getState(), *I, + Att->getOwnKind() == OwnershipAttr::Holds); + if (state) + C.addTransition(state); + } +} + const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, - const GRState *state) { - const Expr *ArgExpr = CE->getArg(0); + const GRState *state, unsigned Num, + bool Hold) { + const Expr *ArgExpr = CE->getArg(Num); SVal ArgVal = state->getSVal(ArgExpr); - // If ptr is NULL, no operation is preformed. - if (ArgVal.isZeroConstant()) + DefinedOrUnknownSVal location = cast(ArgVal); + + // Check for null dereferences. + if (!isa(location)) return state; - + + // FIXME: Technically using 'Assume' here can result in a path + // bifurcation. In such cases we need to return two states, not just one. + const GRState *notNullState, *nullState; + llvm::tie(notNullState, nullState) = state->Assume(location); + + // The explicit NULL case, no operation is performed. + if (nullState && !notNullState) + return nullState; + + assert(notNullState); + // Unknown values could easily be okay // Undefined values are handled elsewhere if (ArgVal.isUnknownOrUndef()) - return state; + return notNullState; const MemRegion *R = ArgVal.getAsRegion(); @@ -253,24 +338,23 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, // Various cases could lead to non-symbol values here. // For now, ignore them. if (!SR) - return state; + return notNullState; SymbolRef Sym = SR->getSymbol(); - const RefState *RS = state->get(Sym); // If the symbol has not been tracked, return. This is possible when free() is // called on a pointer that does not get its pointee directly from malloc(). // Full support of this requires inter-procedural analysis. if (!RS) - return state; + return notNullState; // Check double free. if (RS->isReleased()) { - ExplodedNode *N = C.GenerateSink(); - if (N) { + if (ExplodedNode *N = C.GenerateSink()) { if (!BT_DoubleFree) - BT_DoubleFree = new BuiltinBug("Double free", + BT_DoubleFree + = new BuiltinBug("Double free", "Try to free a memory block that has been released"); // FIXME: should find where it's freed last time. BugReport *R = new BugReport(*BT_DoubleFree, @@ -281,7 +365,9 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, } // Normal free. - return state->set(Sym, RefState::getReleased(CE)); + if (Hold) + return notNullState->set(Sym, RefState::getRelinquished(CE)); + return notNullState->set(Sym, RefState::getReleased(CE)); } bool MallocChecker::SummarizeValue(llvm::raw_ostream& os, SVal V) { @@ -376,8 +462,7 @@ bool MallocChecker::SummarizeRegion(llvm::raw_ostream& os, void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) { - ExplodedNode *N = C.GenerateSink(); - if (N) { + if (ExplodedNode *N = C.GenerateSink()) { if (!BT_BadFree) BT_BadFree = new BuiltinBug("Bad free"); @@ -446,13 +531,13 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) { ValMgr.makeIntValWithPtrWidth(0, false)); if (const GRState *stateSizeZero = stateNotEqual->Assume(SizeZero, true)) { - const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero); + const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero, 0, false); if (stateFree) C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true)); } if (const GRState *stateSizeNotZero=stateNotEqual->Assume(SizeZero,false)) { - const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero); + const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero, 0, false); if (stateFree) { // FIXME: We should copy the content of the original buffer. const GRState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1), @@ -471,7 +556,7 @@ void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) { SVal Count = state->getSVal(CE->getArg(0)); SVal EleSize = state->getSVal(CE->getArg(1)); - SVal TotalSize = SVator.EvalBinOp(state, BinaryOperator::Mul, Count, EleSize, + SVal TotalSize = SVator.EvalBinOp(state, BO_Mul, Count, EleSize, ValMgr.getContext().getSizeType()); SVal Zero = ValMgr.makeZeroVal(ValMgr.getContext().CharTy); @@ -481,36 +566,42 @@ void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) { } void MallocChecker::EvalDeadSymbols(CheckerContext &C,SymbolReaper &SymReaper) { - for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), - E = SymReaper.dead_end(); I != E; ++I) { - SymbolRef Sym = *I; - const GRState *state = C.getState(); - const RefState *RS = state->get(Sym); - if (!RS) - return; - - if (RS->isAllocated()) { - ExplodedNode *N = C.GenerateSink(); - if (N) { - if (!BT_Leak) - BT_Leak = new BuiltinBug("Memory leak", + if (!SymReaper.hasDeadSymbols()) + return; + + const GRState *state = C.getState(); + RegionStateTy RS = state->get(); + RegionStateTy::Factory &F = state->get_context(); + + for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) { + if (SymReaper.isDead(I->first)) { + if (I->second.isAllocated()) { + if (ExplodedNode *N = C.GenerateNode()) { + if (!BT_Leak) + BT_Leak = new BuiltinBug("Memory leak", "Allocated memory never released. Potential memory leak."); - // FIXME: where it is allocated. - BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N); - C.EmitReport(R); + // FIXME: where it is allocated. + BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N); + C.EmitReport(R); + } } + + // Remove the dead symbol from the map. + RS = F.Remove(RS, I->first); } } + + state = state->set(RS); + C.GenerateNode(state); } void MallocChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng) { SaveAndRestore OldHasGen(B.HasGeneratedNode); const GRState *state = B.getState(); - typedef llvm::ImmutableMap SymMap; - SymMap M = state->get(); + RegionStateTy M = state->get(); - for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) { + for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) { RefState RS = I->second; if (RS.isAllocated()) { ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor()); @@ -549,7 +640,8 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) { } const GRState *MallocChecker::EvalAssume(const GRState *state, SVal Cond, - bool Assumption) { + bool Assumption, + bool * /* respondsToCallback */) { // If a symblic region is assumed to NULL, set its state to AllocateFailed. // FIXME: should also check symbols assumed to non-null. @@ -568,9 +660,8 @@ void MallocChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l) { SymbolRef Sym = l.getLocSymbolInBase(); if (Sym) { const RefState *RS = C.getState()->get(Sym); - if (RS) - if (RS->isReleased()) { - ExplodedNode *N = C.GenerateSink(); + if (RS && RS->isReleased()) { + if (ExplodedNode *N = C.GenerateNode()) { if (!BT_UseFree) BT_UseFree = new BuiltinBug("Use dynamically allocated memory after" " it is freed."); @@ -579,5 +670,67 @@ void MallocChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l) { N); C.EmitReport(R); } + } + } +} + +void MallocChecker::PreVisitBind(CheckerContext &C, + const Stmt *StoreE, + SVal location, + SVal val) { + // The PreVisitBind implements the same algorithm as already used by the + // Objective C ownership checker: if the pointer escaped from this scope by + // assignment, let it go. However, assigning to fields of a stack-storage + // structure does not transfer ownership. + + const GRState *state = C.getState(); + DefinedOrUnknownSVal l = cast(location); + + // Check for null dereferences. + if (!isa(l)) + return; + + // Before checking if the state is null, check if 'val' has a RefState. + // Only then should we check for null and bifurcate the state. + SymbolRef Sym = val.getLocSymbolInBase(); + if (Sym) { + if (const RefState *RS = state->get(Sym)) { + // If ptr is NULL, no operation is performed. + const GRState *notNullState, *nullState; + llvm::tie(notNullState, nullState) = state->Assume(l); + + // Generate a transition for 'nullState' to record the assumption + // that the state was null. + if (nullState) + C.addTransition(nullState); + + if (!notNullState) + return; + + if (RS->isAllocated()) { + // Something we presently own is being assigned somewhere. + const MemRegion *AR = location.getAsRegion(); + if (!AR) + return; + AR = AR->StripCasts()->getBaseRegion(); + do { + // If it is on the stack, we still own it. + if (AR->hasStackNonParametersStorage()) + break; + + // If the state can't represent this binding, we still own it. + if (notNullState == (notNullState->bindLoc(cast(location), + UnknownVal()))) + break; + + // We no longer own this pointer. + notNullState = + notNullState->set(Sym, + RefState::getRelinquished(StoreE)); + } + while (false); + } + C.addTransition(notNullState); + } } } diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp index 9cfeb7a..3f706e1 100644 --- a/lib/Checker/MemRegion.cpp +++ b/lib/Checker/MemRegion.cpp @@ -18,6 +18,7 @@ #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/Support/BumpVector.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/RecordLayout.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -177,7 +178,7 @@ const StackFrameContext *VarRegion::getStackFrame() const { DefinedOrUnknownSVal DeclRegion::getExtent(ValueManager& ValMgr) const { ASTContext& Ctx = ValMgr.getContext(); - QualType T = getDesugaredValueType(Ctx); + QualType T = getDesugaredValueType(); if (isa(T)) return nonloc::SymbolVal(ValMgr.getSymbolManager().getExtentSymbol(this)); @@ -195,8 +196,7 @@ DefinedOrUnknownSVal FieldRegion::getExtent(ValueManager& ValMgr) const { // A zero-length array at the end of a struct often stands for dynamically- // allocated extra memory. if (Extent.isZeroConstant()) { - ASTContext& Ctx = ValMgr.getContext(); - QualType T = getDesugaredValueType(Ctx); + QualType T = getDesugaredValueType(); if (isa(T)) return UnknownVal(); @@ -785,7 +785,7 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) { return true; } -RegionRawOffset ElementRegion::getAsRawOffset() const { +RegionRawOffset ElementRegion::getAsArrayOffset() const { CharUnits offset = CharUnits::Zero(); const ElementRegion *ER = this; const MemRegion *superR = NULL; @@ -827,6 +827,67 @@ RegionRawOffset ElementRegion::getAsRawOffset() const { return RegionRawOffset(superR, offset.getQuantity()); } +RegionOffset MemRegion::getAsOffset() const { + const MemRegion *R = this; + int64_t Offset = 0; + + while (1) { + switch (R->getKind()) { + default: + return RegionOffset(0); + case SymbolicRegionKind: + case AllocaRegionKind: + case CompoundLiteralRegionKind: + case CXXThisRegionKind: + case StringRegionKind: + case VarRegionKind: + case CXXObjectRegionKind: + goto Finish; + case ElementRegionKind: { + const ElementRegion *ER = cast(R); + QualType EleTy = ER->getValueType(); + + if (!IsCompleteType(getContext(), EleTy)) + return RegionOffset(0); + + SVal Index = ER->getIndex(); + if (const nonloc::ConcreteInt *CI=dyn_cast(&Index)) { + int64_t i = CI->getValue().getSExtValue(); + CharUnits Size = getContext().getTypeSizeInChars(EleTy); + Offset += i * Size.getQuantity() * 8; + } else { + // We cannot compute offset for non-concrete index. + return RegionOffset(0); + } + R = ER->getSuperRegion(); + break; + } + case FieldRegionKind: { + const FieldRegion *FR = cast(R); + const RecordDecl *RD = FR->getDecl()->getParent(); + if (!RD->isDefinition()) + // We cannot compute offset for incomplete type. + return RegionOffset(0); + // Get the field number. + unsigned idx = 0; + for (RecordDecl::field_iterator FI = RD->field_begin(), + FE = RD->field_end(); FI != FE; ++FI, ++idx) + if (FR->getDecl() == *FI) + break; + + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); + // This is offset in bits. + Offset += Layout.getFieldOffset(idx); + R = FR->getSuperRegion(); + break; + } + } + } + + Finish: + return RegionOffset(R, Offset); +} + //===----------------------------------------------------------------------===// // BlockDataRegion //===----------------------------------------------------------------------===// diff --git a/lib/Checker/OSAtomicChecker.cpp b/lib/Checker/OSAtomicChecker.cpp index 1ea1bd9..02de0a8 100644 --- a/lib/Checker/OSAtomicChecker.cpp +++ b/lib/Checker/OSAtomicChecker.cpp @@ -110,9 +110,9 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C, QualType LoadTy; if (const TypedRegion *TR = dyn_cast_or_null(location.getAsRegion())) { - LoadTy = TR->getValueType(Ctx); + LoadTy = TR->getValueType(); } - Engine.EvalLoad(Tmp, const_cast(theValueExpr), C.getPredecessor(), + Engine.EvalLoad(Tmp, theValueExpr, C.getPredecessor(), state, location, OSAtomicLoadTag, LoadTy); if (Tmp.empty()) { @@ -158,10 +158,10 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C, // Handle implicit value casts. if (const TypedRegion *R = dyn_cast_or_null(location.getAsRegion())) { - val = SVator.EvalCast(val,R->getValueType(Ctx),newValueExpr->getType()); + val = SVator.EvalCast(val,R->getValueType(), newValueExpr->getType()); } - Engine.EvalStore(TmpStore, NULL, const_cast(theValueExpr), N, + Engine.EvalStore(TmpStore, NULL, theValueExpr, N, stateEqual, location, val, OSAtomicStoreTag); if (TmpStore.empty()) { diff --git a/lib/Checker/PointerArithChecker.cpp b/lib/Checker/PointerArithChecker.cpp index ed60c42..cbac423 100644 --- a/lib/Checker/PointerArithChecker.cpp +++ b/lib/Checker/PointerArithChecker.cpp @@ -36,8 +36,7 @@ void *PointerArithChecker::getTag() { void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B) { - if (B->getOpcode() != BinaryOperator::Sub && - B->getOpcode() != BinaryOperator::Add) + if (B->getOpcode() != BO_Sub && B->getOpcode() != BO_Add) return; const GRState *state = C.getState(); diff --git a/lib/Checker/PointerSubChecker.cpp b/lib/Checker/PointerSubChecker.cpp index bc0fd24..d64b6ae 100644 --- a/lib/Checker/PointerSubChecker.cpp +++ b/lib/Checker/PointerSubChecker.cpp @@ -39,7 +39,7 @@ void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B) { // When doing pointer subtraction, if the two pointers do not point to the // same memory chunk, emit a warning. - if (B->getOpcode() != BinaryOperator::Sub) + if (B->getOpcode() != BO_Sub) return; const GRState *state = C.getState(); diff --git a/lib/Checker/RangeConstraintManager.cpp b/lib/Checker/RangeConstraintManager.cpp index 2a35d32..697694e 100644 --- a/lib/Checker/RangeConstraintManager.cpp +++ b/lib/Checker/RangeConstraintManager.cpp @@ -83,7 +83,6 @@ public: typedef PrimRangeSet::iterator iterator; RangeSet(PrimRangeSet RS) : ranges(RS) {} - RangeSet(Factory& F) : ranges(F.GetEmptySet()) {} iterator begin() const { return ranges.begin(); } iterator end() const { return ranges.end(); } diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp index 74a7fee..1a3eded 100644 --- a/lib/Checker/RegionStore.cpp +++ b/lib/Checker/RegionStore.cpp @@ -44,10 +44,9 @@ private: uint64_t Offset; explicit BindingKey(const MemRegion *r, uint64_t offset, Kind k) - : P(r, (unsigned) k), Offset(offset) { assert(r); } + : P(r, (unsigned) k), Offset(offset) {} public: - bool isDefault() const { return P.getInt() == Default; } bool isDirect() const { return P.getInt() == Direct; } const MemRegion *getRegion() const { return P.getPointer(); } @@ -72,9 +71,26 @@ public: return P.getOpaqueValue() == X.P.getOpaqueValue() && Offset == X.Offset; } + + bool isValid() const { + return getRegion() != NULL; + } }; } // end anonymous namespace +BindingKey BindingKey::Make(const MemRegion *R, Kind k) { + if (const ElementRegion *ER = dyn_cast(R)) { + const RegionRawOffset &O = ER->getAsArrayOffset(); + + // FIXME: There are some ElementRegions for which we cannot compute + // raw offsets yet, including regions with symbolic offsets. These will be + // ignored by the store. + return BindingKey(O.getRegion(), O.getByteOffset(), k); + } + + return BindingKey(R, 0, k); +} + namespace llvm { static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) { @@ -101,35 +117,20 @@ struct maximal_features_tag {}; class RegionStoreFeatures { bool SupportsFields; - bool SupportsRemaining; - public: RegionStoreFeatures(minimal_features_tag) : - SupportsFields(false), SupportsRemaining(false) {} + SupportsFields(false) {} RegionStoreFeatures(maximal_features_tag) : - SupportsFields(true), SupportsRemaining(false) {} + SupportsFields(true) {} void enableFields(bool t) { SupportsFields = t; } bool supportsFields() const { return SupportsFields; } - bool supportsRemaining() const { return SupportsRemaining; } }; } //===----------------------------------------------------------------------===// -// Utility functions. -//===----------------------------------------------------------------------===// - -static bool IsAnyPointerOrIntptr(QualType ty, ASTContext &Ctx) { - if (ty->isAnyPointerType()) - return true; - - return ty->isIntegerType() && ty->isScalarType() && - Ctx.getTypeSize(ty) == Ctx.getTypeSize(Ctx.VoidPtrTy); -} - -//===----------------------------------------------------------------------===// // Main RegionStore logic. //===----------------------------------------------------------------------===// @@ -180,6 +181,14 @@ public: } }; +void +RegionStoreSubRegionMap::process(llvm::SmallVectorImpl &WL, + const SubRegion *R) { + const MemRegion *superR = R->getSuperRegion(); + if (add(superR, R)) + if (const SubRegion *sr = dyn_cast(superR)) + WL.push_back(sr); +} class RegionStoreManager : public StoreManager { const RegionStoreFeatures Features; @@ -197,7 +206,6 @@ public: RegionStoreSubRegionMap *getRegionStoreSubRegionMap(Store store); - Optional getBinding(RegionBindings B, const MemRegion *R); Optional getDirectBinding(RegionBindings B, const MemRegion *R); /// getDefaultBinding - Returns an SVal* representing an optional default /// binding associated with a region and its subregions. @@ -226,18 +234,13 @@ public: // Binding values to regions. //===-------------------------------------------------------------------===// - Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E, - unsigned Count, InvalidatedSymbols *IS) { - return RegionStoreManager::InvalidateRegions(store, &R, &R+1, E, Count, IS, - false); - } - Store InvalidateRegions(Store store, const MemRegion * const *Begin, const MemRegion * const *End, const Expr *E, unsigned Count, InvalidatedSymbols *IS, - bool invalidateGlobals); + bool invalidateGlobals, + InvalidatedRegions *Regions); public: // Made public for helper classes. @@ -260,8 +263,6 @@ public: // Made public for helper classes. return Remove(Remove(B, R, BindingKey::Direct), R, BindingKey::Default); } - Store Remove(Store store, BindingKey K); - public: // Part of public interface to class. Store Bind(Store store, Loc LV, SVal V); @@ -289,7 +290,7 @@ public: // Part of public interface to class. Store BindArray(Store store, const TypedRegion* R, SVal V); /// KillStruct - Set the entire struct to unknown. - Store KillStruct(Store store, const TypedRegion* R); + Store KillStruct(Store store, const TypedRegion* R, SVal DefaultVal); Store Remove(Store store, Loc LV); @@ -352,13 +353,11 @@ public: // Part of public interface to class. /// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values. /// It returns a new Store with these values removed. - const GRState *RemoveDeadBindings(GRState &state, - const StackFrameContext *LCtx, - SymbolReaper& SymReaper, + Store RemoveDeadBindings(Store store, const StackFrameContext *LCtx, + SymbolReaper& SymReaper, llvm::SmallVectorImpl& RegionRoots); - const GRState *EnterStackFrame(const GRState *state, - const StackFrameContext *frame); + Store EnterStackFrame(const GRState *state, const StackFrameContext *frame); //===------------------------------------------------------------------===// // Region "extents". @@ -392,9 +391,6 @@ public: // Part of public interface to class. } } } - - // FIXME: Remove. - ASTContext& getContext() { return StateMgr.getContext(); } }; } // end anonymous namespace @@ -414,14 +410,6 @@ StoreManager *clang::CreateFieldsOnlyRegionStoreManager(GRStateManager &StMgr) { return new RegionStoreManager(StMgr, F); } -void -RegionStoreSubRegionMap::process(llvm::SmallVectorImpl &WL, - const SubRegion *R) { - const MemRegion *superR = R->getSuperRegion(); - if (add(superR, R)) - if (const SubRegion *sr = dyn_cast(superR)) - WL.push_back(sr); -} RegionStoreSubRegionMap* RegionStoreManager::getRegionStoreSubRegionMap(Store store) { @@ -579,14 +567,16 @@ class InvalidateRegionsWorker : public ClusterAnalysis const Expr *Ex; unsigned Count; StoreManager::InvalidatedSymbols *IS; + StoreManager::InvalidatedRegions *Regions; public: InvalidateRegionsWorker(RegionStoreManager &rm, GRStateManager &stateMgr, RegionBindings b, const Expr *ex, unsigned count, - StoreManager::InvalidatedSymbols *is) + StoreManager::InvalidatedSymbols *is, + StoreManager::InvalidatedRegions *r) : ClusterAnalysis(rm, stateMgr, b), - Ex(ex), Count(count), IS(is) {} + Ex(ex), Count(count), IS(is), Regions(r) {} void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E); void VisitBaseRegion(const MemRegion *baseR); @@ -657,6 +647,10 @@ void InvalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { return; } + // Otherwise, we have a normal data region. Record that we touched the region. + if (Regions) + Regions->push_back(baseR); + if (isa(baseR) || isa(baseR)) { // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelavant. @@ -670,19 +664,12 @@ void InvalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { return; const TypedRegion *TR = cast(baseR); - QualType T = TR->getValueType(Ctx); + QualType T = TR->getValueType(); // Invalidate the binding. - if (const RecordType *RT = T->getAsStructureType()) { - const RecordDecl *RD = RT->getDecl()->getDefinition(); - // No record definition. There is nothing we can do. - if (!RD) { - B = RM.Remove(B, baseR); - return; - } - - // Invalidate the region by setting its default value to - // conjured symbol. The type of the symbol is irrelavant. + if (T->isStructureType()) { + // Invalidate the region by setting its default value to + // conjured symbol. The type of the symbol is irrelavant. DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy, Count); B = RM.Add(B, baseR, BindingKey::Default, V); @@ -707,10 +694,11 @@ Store RegionStoreManager::InvalidateRegions(Store store, const MemRegion * const *E, const Expr *Ex, unsigned Count, InvalidatedSymbols *IS, - bool invalidateGlobals) { + bool invalidateGlobals, + InvalidatedRegions *Regions) { InvalidateRegionsWorker W(*this, StateMgr, RegionStoreManager::GetRegionBindings(store), - Ex, Count, IS); + Ex, Count, IS, Regions); // Scan the bindings and generate the clusters. W.GenerateClusters(invalidateGlobals); @@ -733,6 +721,11 @@ Store RegionStoreManager::InvalidateRegions(Store store, /* symbol type, doesn't matter */ Ctx.IntTy, Count); B = Add(B, BindingKey::Make(GS, BindingKey::Default), V); + + // Even if there are no bindings in the global scope, we still need to + // record that we touched it. + if (Regions) + Regions->push_back(GS); } return B.getRoot(); @@ -752,7 +745,7 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state, return UnknownVal(); CharUnits RegionSize = CharUnits::fromQuantity(SizeInt->getSExtValue()); - CharUnits EleSize = getContext().getTypeSizeInChars(EleTy); + CharUnits EleSize = Ctx.getTypeSizeInChars(EleTy); // If a variable is reinterpreted as a type that doesn't fit into a larger // type evenly, round it down. @@ -781,13 +774,12 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) { return UnknownVal(); // Strip off typedefs from the ArrayRegion's ValueType. - QualType T = ArrayR->getValueType(getContext()).getDesugaredType(); + QualType T = ArrayR->getValueType().getDesugaredType(); ArrayType *AT = cast(T); T = AT->getElementType(); SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); - return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, ArrayR, - getContext())); + return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, ArrayR, Ctx)); } //===----------------------------------------------------------------------===// @@ -806,8 +798,8 @@ SVal RegionStoreManager::EvalBinOp(BinaryOperator::Opcode Op, Loc L, NonLoc R, default: // Handle it normally. break; - case BinaryOperator::Add: - case BinaryOperator::Sub: + case BO_Add: + case BO_Sub: // FIXME: does this need to be casted to match resultTy? return L; } @@ -820,7 +812,7 @@ SVal RegionStoreManager::EvalBinOp(BinaryOperator::Opcode Op, Loc L, NonLoc R, case MemRegion::SymbolicRegionKind: { const SymbolicRegion *SR = cast(MR); SymbolRef Sym = SR->getSymbol(); - QualType T = Sym->getType(getContext()); + QualType T = Sym->getType(Ctx); QualType EleTy; if (const PointerType *PT = T->getAs()) @@ -829,14 +821,14 @@ SVal RegionStoreManager::EvalBinOp(BinaryOperator::Opcode Op, Loc L, NonLoc R, EleTy = T->getAs()->getPointeeType(); SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); - ER = MRMgr.getElementRegion(EleTy, ZeroIdx, SR, getContext()); + ER = MRMgr.getElementRegion(EleTy, ZeroIdx, SR, Ctx); break; } case MemRegion::AllocaRegionKind: { const AllocaRegion *AR = cast(MR); - QualType EleTy = getContext().CharTy; // Create an ElementRegion of bytes. + QualType EleTy = Ctx.CharTy; // Create an ElementRegion of bytes. SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); - ER = MRMgr.getElementRegion(EleTy, ZeroIdx, AR, getContext()); + ER = MRMgr.getElementRegion(EleTy, ZeroIdx, AR, Ctx); break; } @@ -891,13 +883,13 @@ SVal RegionStoreManager::EvalBinOp(BinaryOperator::Opcode Op, Loc L, NonLoc R, cast(ValMgr.convertToArrayIndex(*Offset))); const MemRegion* NewER = MRMgr.getElementRegion(ER->getElementType(), NewIdx, - ER->getSuperRegion(), getContext()); + ER->getSuperRegion(), Ctx); return ValMgr.makeLoc(NewER); } if (0 == Base->getValue()) { const MemRegion* NewER = MRMgr.getElementRegion(ER->getElementType(), R, - ER->getSuperRegion(), getContext()); + ER->getSuperRegion(), Ctx); return ValMgr.makeLoc(NewER); } } @@ -922,7 +914,7 @@ Optional RegionStoreManager::getDefaultBinding(RegionBindings B, const MemRegion *R) { if (R->isBoundable()) if (const TypedRegion *TR = dyn_cast(R)) - if (TR->getValueType(getContext())->isUnionType()) + if (TR->getValueType()->isUnionType()) return UnknownVal(); if (const SVal *V = Lookup(B, R, BindingKey::Default)) @@ -931,38 +923,6 @@ Optional RegionStoreManager::getDefaultBinding(RegionBindings B, return Optional(); } -Optional RegionStoreManager::getBinding(RegionBindings B, - const MemRegion *R) { - - if (const Optional &V = getDirectBinding(B, R)) - return V; - - return getDefaultBinding(B, R); -} - -static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) { - RTy = Ctx.getCanonicalType(RTy); - UsedTy = Ctx.getCanonicalType(UsedTy); - - if (RTy == UsedTy) - return false; - - - // Recursively check the types. We basically want to see if a pointer value - // is ever reinterpreted as a non-pointer, e.g. void** and intptr_t* - // represents a reinterpretation. - if (Loc::IsLocType(RTy) && Loc::IsLocType(UsedTy)) { - const PointerType *PRTy = RTy->getAs(); - const PointerType *PUsedTy = UsedTy->getAs(); - - return PUsedTy && PRTy && - IsReinterpreted(PRTy->getPointeeType(), - PUsedTy->getPointeeType(), Ctx); - } - - return true; -} - SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { assert(!isa(L) && "location unknown"); assert(!isa(L) && "location undefined"); @@ -977,7 +937,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { if (isa(MR) || isa(MR)) { if (T.isNull()) { const SymbolicRegion *SR = cast(MR); - T = SR->getSymbol()->getType(getContext()); + T = SR->getSymbol()->getType(Ctx); } MR = GetElementZeroRegion(MR, T); } @@ -990,7 +950,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { // FIXME: Perhaps this method should just take a 'const MemRegion*' argument // instead of 'Loc', and have the other Loc cases handled at a higher level. const TypedRegion *R = cast(MR); - QualType RTy = R->getValueType(getContext()); + QualType RTy = R->getValueType(); // FIXME: We should eventually handle funny addressing. e.g.: // @@ -1001,17 +961,6 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { // // Such funny addressing will occur due to layering of regions. -#if 0 - ASTContext &Ctx = getContext(); - if (!T.isNull() && IsReinterpreted(RTy, T, Ctx)) { - SVal ZeroIdx = ValMgr.makeZeroArrayIndex(); - R = MRMgr.getElementRegion(T, ZeroIdx, R, Ctx); - RTy = T; - assert(Ctx.getCanonicalType(RTy) == - Ctx.getCanonicalType(R->getValueType(Ctx))); - } -#endif - if (RTy->isStructureOrClassType()) return RetrieveStruct(store, R); @@ -1121,8 +1070,7 @@ SVal RegionStoreManager::RetrieveElement(Store store, if (const StringRegion *StrR=dyn_cast(superR)) { // FIXME: Handle loads from strings where the literal is treated as // an integer, e.g., *((unsigned int*)"hello") - ASTContext &Ctx = getContext(); - QualType T = Ctx.getAsArrayType(StrR->getValueType(Ctx))->getElementType(); + QualType T = Ctx.getAsArrayType(StrR->getValueType())->getElementType(); if (T != Ctx.getCanonicalType(R->getElementType())) return UnknownVal(); @@ -1131,16 +1079,18 @@ SVal RegionStoreManager::RetrieveElement(Store store, if (nonloc::ConcreteInt *CI = dyn_cast(&Idx)) { int64_t i = CI->getValue().getSExtValue(); int64_t byteLength = Str->getByteLength(); - if (i > byteLength) { - // Buffer overflow checking in GRExprEngine should handle this case, - // but we shouldn't rely on it to not overflow here if that checking - // is disabled. - return UnknownVal(); - } - char c = (i == byteLength) ? '\0' : Str->getStrData()[i]; + // Technically, only i == byteLength is guaranteed to be null. + // However, such overflows should be caught before reaching this point; + // the only time such an access would be made is if a string literal was + // used to initialize a larger array. + char c = (i >= byteLength) ? '\0' : Str->getString()[i]; return ValMgr.makeIntVal(c, T); } } + + // Check for loads from a code text region. For such loads, just give up. + if (isa(superR)) + return UnknownVal(); // Handle the case where we are indexing into a larger scalar object. // For example, this handles: @@ -1148,9 +1098,9 @@ SVal RegionStoreManager::RetrieveElement(Store store, // char *y = &x; // return *y; // FIXME: This is a hack, and doesn't do anything really intelligent yet. - const RegionRawOffset &O = R->getAsRawOffset(); + const RegionRawOffset &O = R->getAsArrayOffset(); if (const TypedRegion *baseR = dyn_cast_or_null(O.getRegion())) { - QualType baseT = baseR->getValueType(Ctx); + QualType baseT = baseR->getValueType(); if (baseT->isScalarType()) { QualType elemT = R->getElementType(); if (elemT->isScalarType()) { @@ -1180,7 +1130,7 @@ SVal RegionStoreManager::RetrieveField(Store store, if (const Optional &V = getDirectBinding(B, R)) return *V; - QualType Ty = R->getValueType(getContext()); + QualType Ty = R->getValueType(); return RetrieveFieldOrElementCommon(store, R, Ty, R->getSuperRegion()); } @@ -1243,13 +1193,18 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store, } if (R->hasStackNonParametersStorage()) { - if (isa(R)) { + if (const ElementRegion *ER = dyn_cast(R)) { // Currently we don't reason specially about Clang-style vectors. Check // if superR is a vector and if so return Unknown. if (const TypedRegion *typedSuperR = dyn_cast(superR)) { - if (typedSuperR->getValueType(getContext())->isVectorType()) + if (typedSuperR->getValueType()->isVectorType()) return UnknownVal(); } + + // FIXME: We also need to take ElementRegions with symbolic indexes into + // account. + if (!ER->getIndex().isConstant()) + return UnknownVal(); } return UndefinedVal(); @@ -1332,21 +1287,18 @@ SVal RegionStoreManager::RetrieveVar(Store store, const VarRegion *R) { } SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) { - - QualType valTy = R->getValueType(getContext()); - // All other values are symbolic. return ValMgr.getRegionValueSymbolVal(R); } SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) { - QualType T = R->getValueType(getContext()); + QualType T = R->getValueType(); assert(T->isStructureOrClassType()); return ValMgr.makeLazyCompoundVal(store, R); } SVal RegionStoreManager::RetrieveArray(Store store, const TypedRegion * R) { - assert(isa(R->getValueType(getContext()))); + assert(isa(R->getValueType())); return ValMgr.makeLazyCompoundVal(store, R); } @@ -1371,38 +1323,26 @@ Store RegionStoreManager::Bind(Store store, Loc L, SVal V) { // Check if the region is a struct region. if (const TypedRegion* TR = dyn_cast(R)) - if (TR->getValueType(getContext())->isStructureOrClassType()) + if (TR->getValueType()->isStructureOrClassType()) return BindStruct(store, TR, V); - // Special case: the current region represents a cast and it and the super - // region both have pointer types or intptr_t types. If so, perform the - // bind to the super region. - // This is needed to support OSAtomicCompareAndSwap and friends or other - // loads that treat integers as pointers and vis versa. if (const ElementRegion *ER = dyn_cast(R)) { if (ER->getIndex().isZeroConstant()) { if (const TypedRegion *superR = dyn_cast(ER->getSuperRegion())) { - ASTContext &Ctx = getContext(); - QualType superTy = superR->getValueType(Ctx); - QualType erTy = ER->getValueType(Ctx); - - if (IsAnyPointerOrIntptr(superTy, Ctx) && - IsAnyPointerOrIntptr(erTy, Ctx)) { - V = ValMgr.getSValuator().EvalCast(V, superTy, erTy); - return Bind(store, loc::MemRegionVal(superR), V); - } + QualType superTy = superR->getValueType(); // For now, just invalidate the fields of the struct/union/class. + // This is for test rdar_test_7185607 in misc-ps-region-store.m. // FIXME: Precisely handle the fields of the record. - if (superTy->isRecordType()) - return InvalidateRegion(store, superR, NULL, 0, NULL); + if (superTy->isStructureOrClassType()) + return KillStruct(store, superR, UnknownVal()); } } } else if (const SymbolicRegion *SR = dyn_cast(R)) { // Binding directly to a symbolic region should be treated as binding // to element 0. - QualType T = SR->getSymbol()->getType(getContext()); + QualType T = SR->getSymbol()->getType(Ctx); // FIXME: Is this the right way to handle symbols that are references? if (const PointerType *PT = T->getAs()) @@ -1454,7 +1394,7 @@ Store RegionStoreManager::setImplicitDefaultValue(Store store, else if (T->isStructureOrClassType() || T->isArrayType()) { // Set the default value to a zero constant when it is a structure // or array. The type doesn't really matter. - V = ValMgr.makeZeroVal(ValMgr.getContext().IntTy); + V = ValMgr.makeZeroVal(Ctx.IntTy); } else { return store; @@ -1466,44 +1406,21 @@ Store RegionStoreManager::setImplicitDefaultValue(Store store, Store RegionStoreManager::BindArray(Store store, const TypedRegion* R, SVal Init) { - ASTContext &Ctx = getContext(); - const ArrayType *AT = - cast(Ctx.getCanonicalType(R->getValueType(Ctx))); + const ArrayType *AT =cast(Ctx.getCanonicalType(R->getValueType())); QualType ElementTy = AT->getElementType(); Optional Size; if (const ConstantArrayType* CAT = dyn_cast(AT)) Size = CAT->getSize().getZExtValue(); - // Check if the init expr is a StringLiteral. - if (isa(Init)) { - const MemRegion* InitR = cast(Init).getRegion(); - const StringLiteral* S = cast(InitR)->getStringLiteral(); - const char* str = S->getStrData(); - unsigned len = S->getByteLength(); - unsigned j = 0; - - // Copy bytes from the string literal into the target array. Trailing bytes - // in the array that are not covered by the string literal are initialized - // to zero. + // Check if the init expr is a string literal. + if (loc::MemRegionVal *MRV = dyn_cast(&Init)) { + const StringRegion *S = cast(MRV->getRegion()); - // We assume that string constants are bound to - // constant arrays. - uint64_t size = Size.getValue(); - - for (uint64_t i = 0; i < size; ++i, ++j) { - if (j >= len) - break; - - SVal Idx = ValMgr.makeArrayIndex(i); - const ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, - getContext()); - - SVal V = ValMgr.makeIntVal(str[j], sizeof(char)*8, true); - store = Bind(store, loc::MemRegionVal(ER), V); - } - - return store; + // Treat the string as a lazy compound value. + nonloc::LazyCompoundVal LCV = + cast(ValMgr.makeLazyCompoundVal(store, S)); + return CopyLazyBindings(LCV, store, R); } // Handle lazy compound values. @@ -1525,10 +1442,12 @@ Store RegionStoreManager::BindArray(Store store, const TypedRegion* R, break; SVal Idx = ValMgr.makeArrayIndex(i); - const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext()); + const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, Ctx); if (ElementTy->isStructureOrClassType()) store = BindStruct(store, ER, *VI); + else if (ElementTy->isArrayType()) + store = BindArray(store, ER, *VI); else store = Bind(store, ValMgr.makeLoc(ER), *VI); } @@ -1547,7 +1466,7 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R, if (!Features.supportsFields()) return store; - QualType T = R->getValueType(getContext()); + QualType T = R->getValueType(); assert(T->isStructureOrClassType()); const RecordType* RT = T->getAs(); @@ -1560,10 +1479,13 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R, if (const nonloc::LazyCompoundVal *LCV=dyn_cast(&V)) return CopyLazyBindings(*LCV, store, R); - // We may get non-CompoundVal accidentally due to imprecise cast logic. - // Ignore them and kill the field values. - if (V.isUnknown() || !isa(V)) - return KillStruct(store, R); + // We may get non-CompoundVal accidentally due to imprecise cast logic or + // that we are binding symbolic struct value. Kill the field values, and if + // the value is symbolic go and bind it as a "default" binding. + if (V.isUnknown() || !isa(V)) { + SVal SV = isa(V) ? V : UnknownVal(); + return KillStruct(store, R, SV); + } nonloc::CompoundVal& CV = cast(V); nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end(); @@ -1596,14 +1518,15 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R, return store; } -Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) { +Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R, + SVal DefaultVal) { RegionBindings B = GetRegionBindings(store); llvm::OwningPtr SubRegions(getRegionStoreSubRegionMap(store)); RemoveSubRegionBindings(B, R, *SubRegions); // Set the default value of the struct region to "unknown". - return Add(B, R, BindingKey::Default, UnknownVal()).getRoot(); + return Add(B, R, BindingKey::Default, DefaultVal).getRoot(); } Store RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V, @@ -1627,21 +1550,10 @@ Store RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V, // "Raw" retrievals and bindings. //===----------------------------------------------------------------------===// -BindingKey BindingKey::Make(const MemRegion *R, Kind k) { - if (const ElementRegion *ER = dyn_cast(R)) { - const RegionRawOffset &O = ER->getAsRawOffset(); - - if (O.getRegion()) - return BindingKey(O.getRegion(), O.getByteOffset(), k); - - // FIXME: There are some ElementRegions for which we cannot compute - // raw offsets yet, including regions with symbolic offsets. - } - - return BindingKey(R, 0, k); -} RegionBindings RegionStoreManager::Add(RegionBindings B, BindingKey K, SVal V) { + if (!K.isValid()) + return B; return RBFactory.Add(B, K, V); } @@ -1651,6 +1563,8 @@ RegionBindings RegionStoreManager::Add(RegionBindings B, const MemRegion *R, } const SVal *RegionStoreManager::Lookup(RegionBindings B, BindingKey K) { + if (!K.isValid()) + return NULL; return B.lookup(K); } @@ -1661,6 +1575,8 @@ const SVal *RegionStoreManager::Lookup(RegionBindings B, } RegionBindings RegionStoreManager::Remove(RegionBindings B, BindingKey K) { + if (!K.isValid()) + return B; return RBFactory.Remove(B, K); } @@ -1669,11 +1585,6 @@ RegionBindings RegionStoreManager::Remove(RegionBindings B, const MemRegion *R, return Remove(B, BindingKey::Make(R, k)); } -Store RegionStoreManager::Remove(Store store, BindingKey K) { - RegionBindings B = GetRegionBindings(store); - return Remove(B, K).getRoot(); -} - //===----------------------------------------------------------------------===// // State pruning. //===----------------------------------------------------------------------===// @@ -1818,12 +1729,12 @@ bool RemoveDeadBindingsWorker::UpdatePostponed() { return changed; } -const GRState *RegionStoreManager::RemoveDeadBindings(GRState &state, +Store RegionStoreManager::RemoveDeadBindings(Store store, const StackFrameContext *LCtx, SymbolReaper& SymReaper, llvm::SmallVectorImpl& RegionRoots) { - RegionBindings B = GetRegionBindings(state.getStore()); + RegionBindings B = GetRegionBindings(store); RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, LCtx); W.GenerateClusters(); @@ -1856,14 +1767,13 @@ const GRState *RegionStoreManager::RemoveDeadBindings(GRState &state, for (; SI != SE; ++SI) SymReaper.maybeDead(*SI); } - state.setStore(B.getRoot()); - const GRState *s = StateMgr.getPersistentState(state); - return s; + + return B.getRoot(); } -GRState const *RegionStoreManager::EnterStackFrame(GRState const *state, - StackFrameContext const *frame) { +Store RegionStoreManager::EnterStackFrame(const GRState *state, + const StackFrameContext *frame) { FunctionDecl const *FD = cast(frame->getDecl()); FunctionDecl::param_const_iterator PI = FD->param_begin(); Store store = state->getStore(); @@ -1887,9 +1797,9 @@ GRState const *RegionStoreManager::EnterStackFrame(GRState const *state, store = Bind(store, ValMgr.makeLoc(MRMgr.getVarRegion(*PI,frame)),ArgVal); } } else - assert(0 && "Unhandled call expression."); + llvm_unreachable("Unhandled call expression."); - return state->makeWithStore(store); + return store; } //===----------------------------------------------------------------------===// diff --git a/lib/Checker/ReturnPointerRangeChecker.cpp b/lib/Checker/ReturnPointerRangeChecker.cpp index 14edf56..a9eb5ce 100644 --- a/lib/Checker/ReturnPointerRangeChecker.cpp +++ b/lib/Checker/ReturnPointerRangeChecker.cpp @@ -66,7 +66,7 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C, DefinedOrUnknownSVal NumElements = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), - ER->getValueType(C.getASTContext())); + ER->getValueType()); const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true); const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false); diff --git a/lib/Checker/ReturnUndefChecker.cpp b/lib/Checker/ReturnUndefChecker.cpp index 52a0b30..73d1890 100644 --- a/lib/Checker/ReturnUndefChecker.cpp +++ b/lib/Checker/ReturnUndefChecker.cpp @@ -61,6 +61,7 @@ void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C, EnhancedBugReport *report = new EnhancedBugReport(*BT, BT->getDescription(), N); + report->addRange(RetE->getSourceRange()); report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, RetE); C.EmitReport(report); diff --git a/lib/Checker/SVals.cpp b/lib/Checker/SVals.cpp index 7a99e86..97ba74e 100644 --- a/lib/Checker/SVals.cpp +++ b/lib/Checker/SVals.cpp @@ -62,6 +62,9 @@ const FunctionDecl *SVal::getAsFunctionDecl() const { /// wraps a symbol, return that SymbolRef. Otherwise return 0. // FIXME: should we consider SymbolRef wrapped in CodeTextRegion? SymbolRef SVal::getAsLocSymbol() const { + if (const nonloc::LocAsInteger *X = dyn_cast(this)) + return X->getLoc().getAsLocSymbol(); + if (const loc::MemRegionVal *X = dyn_cast(this)) { const MemRegion *R = X->StripCasts(); if (const SymbolicRegion *SymR = dyn_cast(R)) @@ -247,8 +250,8 @@ SVal loc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, const loc::ConcreteInt& R) const { - assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub || - (Op >= BinaryOperator::LT && Op <= BinaryOperator::NE)); + assert (Op == BO_Add || Op == BO_Sub || + (Op >= BO_LT && Op <= BO_NE)); const llvm::APSInt* X = BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue()); diff --git a/lib/Checker/SValuator.cpp b/lib/Checker/SValuator.cpp index a7e15fc..273e574 100644 --- a/lib/Checker/SValuator.cpp +++ b/lib/Checker/SValuator.cpp @@ -37,7 +37,7 @@ SVal SValuator::EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op, if (isa(R)) { // Support pointer arithmetic where the addend is on the left // and the pointer on the right. - assert(Op == BinaryOperator::Add); + assert(Op == BO_Add); // Commute the operands. return EvalBinOpLN(ST, Op, cast(R), cast(L), T); @@ -49,7 +49,7 @@ SVal SValuator::EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op, DefinedOrUnknownSVal SValuator::EvalEQ(const GRState *ST, DefinedOrUnknownSVal L, DefinedOrUnknownSVal R) { - return cast(EvalBinOp(ST, BinaryOperator::EQ, L, R, + return cast(EvalBinOp(ST, BO_EQ, L, R, ValMgr.getContext().IntTy)); } diff --git a/lib/Checker/SimpleConstraintManager.cpp b/lib/Checker/SimpleConstraintManager.cpp index 321381b..04496e1 100644 --- a/lib/Checker/SimpleConstraintManager.cpp +++ b/lib/Checker/SimpleConstraintManager.cpp @@ -31,17 +31,17 @@ bool SimpleConstraintManager::canReasonAbout(SVal X) const { if (const SymIntExpr *SIE = dyn_cast(SE)) { switch (SIE->getOpcode()) { // We don't reason yet about bitwise-constraints on symbolic values. - case BinaryOperator::And: - case BinaryOperator::Or: - case BinaryOperator::Xor: + case BO_And: + case BO_Or: + case BO_Xor: return false; // We don't reason yet about these arithmetic constraints on // symbolic values. - case BinaryOperator::Mul: - case BinaryOperator::Div: - case BinaryOperator::Rem: - case BinaryOperator::Shl: - case BinaryOperator::Shr: + case BO_Mul: + case BO_Div: + case BO_Rem: + case BO_Shl: + case BO_Shr: return false; // All other cases. default: @@ -125,12 +125,12 @@ static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) { switch (op) { default: assert(false && "Invalid opcode."); - case BinaryOperator::LT: return BinaryOperator::GE; - case BinaryOperator::GT: return BinaryOperator::LE; - case BinaryOperator::LE: return BinaryOperator::GT; - case BinaryOperator::GE: return BinaryOperator::LT; - case BinaryOperator::EQ: return BinaryOperator::NE; - case BinaryOperator::NE: return BinaryOperator::EQ; + case BO_LT: return BO_GE; + case BO_GT: return BO_LE; + case BO_LE: return BO_GT; + case BO_GE: return BO_LT; + case BO_EQ: return BO_NE; + case BO_NE: return BO_EQ; } } @@ -178,7 +178,7 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state, if (!BinaryOperator::isComparisonOp(op)) { QualType T = SymMgr.getType(SE); const llvm::APSInt &zero = BasicVals.getValue(0, T); - op = (Assumption ? BinaryOperator::NE : BinaryOperator::EQ); + op = (Assumption ? BO_NE : BO_EQ); return AssumeSymRel(state, SE, op, zero); } @@ -238,10 +238,10 @@ const GRState *SimpleConstraintManager::AssumeSymRel(const GRState *state, // Get the constant out of the expression "($sym+constant1)". switch (SE->getOpcode()) { - case BinaryOperator::Add: + case BO_Add: Adjustment = SE->getRHS(); break; - case BinaryOperator::Sub: + case BO_Sub: Adjustment = -SE->getRHS(); break; default: @@ -276,48 +276,24 @@ const GRState *SimpleConstraintManager::AssumeSymRel(const GRState *state, // No logic yet for other operators. Assume the constraint is feasible. return state; - case BinaryOperator::EQ: + case BO_EQ: return AssumeSymEQ(state, Sym, ConvertedInt, Adjustment); - case BinaryOperator::NE: + case BO_NE: return AssumeSymNE(state, Sym, ConvertedInt, Adjustment); - case BinaryOperator::GT: + case BO_GT: return AssumeSymGT(state, Sym, ConvertedInt, Adjustment); - case BinaryOperator::GE: + case BO_GE: return AssumeSymGE(state, Sym, ConvertedInt, Adjustment); - case BinaryOperator::LT: + case BO_LT: return AssumeSymLT(state, Sym, ConvertedInt, Adjustment); - case BinaryOperator::LE: + case BO_LE: return AssumeSymLE(state, Sym, ConvertedInt, Adjustment); } // end switch } -const GRState *SimpleConstraintManager::AssumeInBound(const GRState *state, - DefinedSVal Idx, - DefinedSVal UpperBound, - bool Assumption) { - - // Only support ConcreteInt for now. - if (!(isa(Idx) && isa(UpperBound))) - return state; - - const llvm::APSInt& Zero = state->getBasicVals().getZeroWithPtrWidth(false); - llvm::APSInt IdxV = cast(Idx).getValue(); - // IdxV might be too narrow. - if (IdxV.getBitWidth() < Zero.getBitWidth()) - IdxV.extend(Zero.getBitWidth()); - // UBV might be too narrow, too. - llvm::APSInt UBV = cast(UpperBound).getValue(); - if (UBV.getBitWidth() < Zero.getBitWidth()) - UBV.extend(Zero.getBitWidth()); - - bool InBound = (Zero <= IdxV) && (IdxV < UBV); - bool isFeasible = Assumption ? InBound : !InBound; - return isFeasible ? state : NULL; -} - } // end of namespace clang diff --git a/lib/Checker/SimpleConstraintManager.h b/lib/Checker/SimpleConstraintManager.h index 45057e6..96811b3 100644 --- a/lib/Checker/SimpleConstraintManager.h +++ b/lib/Checker/SimpleConstraintManager.h @@ -43,10 +43,6 @@ public: BinaryOperator::Opcode op, const llvm::APSInt& Int); - const GRState *AssumeInBound(const GRState *state, DefinedSVal Idx, - DefinedSVal UpperBound, - bool Assumption); - protected: //===------------------------------------------------------------------===// diff --git a/lib/Checker/SimpleSValuator.cpp b/lib/Checker/SimpleSValuator.cpp index 3bc4ee7..782cd4f 100644 --- a/lib/Checker/SimpleSValuator.cpp +++ b/lib/Checker/SimpleSValuator.cpp @@ -168,12 +168,12 @@ static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) { switch (op) { default: assert(false && "Invalid opcode."); - case BinaryOperator::LT: return BinaryOperator::GE; - case BinaryOperator::GT: return BinaryOperator::LE; - case BinaryOperator::LE: return BinaryOperator::GT; - case BinaryOperator::GE: return BinaryOperator::LT; - case BinaryOperator::EQ: return BinaryOperator::NE; - case BinaryOperator::NE: return BinaryOperator::EQ; + case BO_LT: return BO_GE; + case BO_GT: return BO_LE; + case BO_LE: return BO_GT; + case BO_GE: return BO_LT; + case BO_EQ: return BO_NE; + case BO_NE: return BO_EQ; } } @@ -181,12 +181,12 @@ static BinaryOperator::Opcode ReverseComparison(BinaryOperator::Opcode op) { switch (op) { default: assert(false && "Invalid opcode."); - case BinaryOperator::LT: return BinaryOperator::GT; - case BinaryOperator::GT: return BinaryOperator::LT; - case BinaryOperator::LE: return BinaryOperator::GE; - case BinaryOperator::GE: return BinaryOperator::LE; - case BinaryOperator::EQ: - case BinaryOperator::NE: + case BO_LT: return BO_GT; + case BO_GT: return BO_LT; + case BO_LE: return BO_GE; + case BO_GE: return BO_LE; + case BO_EQ: + case BO_NE: return op; } } @@ -202,14 +202,14 @@ SVal SimpleSValuator::MakeSymIntVal(const SymExpr *LHS, default: // We can't reduce this case; just treat it normally. break; - case BinaryOperator::Mul: + case BO_Mul: // a*0 and a*1 if (RHS == 0) return ValMgr.makeIntVal(0, resultTy); else if (RHS == 1) isIdempotent = true; break; - case BinaryOperator::Div: + case BO_Div: // a/0 and a/1 if (RHS == 0) // This is also handled elsewhere. @@ -217,7 +217,7 @@ SVal SimpleSValuator::MakeSymIntVal(const SymExpr *LHS, else if (RHS == 1) isIdempotent = true; break; - case BinaryOperator::Rem: + case BO_Rem: // a%0 and a%1 if (RHS == 0) // This is also handled elsewhere. @@ -225,23 +225,23 @@ SVal SimpleSValuator::MakeSymIntVal(const SymExpr *LHS, else if (RHS == 1) return ValMgr.makeIntVal(0, resultTy); break; - case BinaryOperator::Add: - case BinaryOperator::Sub: - case BinaryOperator::Shl: - case BinaryOperator::Shr: - case BinaryOperator::Xor: + case BO_Add: + case BO_Sub: + case BO_Shl: + case BO_Shr: + case BO_Xor: // a+0, a-0, a<<0, a>>0, a^0 if (RHS == 0) isIdempotent = true; break; - case BinaryOperator::And: + case BO_And: // a&0 and a&(~0) if (RHS == 0) return ValMgr.makeIntVal(0, resultTy); else if (RHS.isAllOnesValue()) isIdempotent = true; break; - case BinaryOperator::Or: + case BO_Or: // a|0 and a|(~0) if (RHS == 0) isIdempotent = true; @@ -275,19 +275,19 @@ SVal SimpleSValuator::EvalBinOpNN(const GRState *state, switch (op) { default: break; - case BinaryOperator::EQ: - case BinaryOperator::LE: - case BinaryOperator::GE: + case BO_EQ: + case BO_LE: + case BO_GE: return ValMgr.makeTruthVal(true, resultTy); - case BinaryOperator::LT: - case BinaryOperator::GT: - case BinaryOperator::NE: + case BO_LT: + case BO_GT: + case BO_NE: return ValMgr.makeTruthVal(false, resultTy); - case BinaryOperator::Xor: - case BinaryOperator::Sub: + case BO_Xor: + case BO_Sub: return ValMgr.makeIntVal(0, resultTy); - case BinaryOperator::Or: - case BinaryOperator::And: + case BO_Or: + case BO_And: return EvalCastNL(lhs, resultTy); } @@ -312,9 +312,9 @@ SVal SimpleSValuator::EvalBinOpNN(const GRState *state, } default: switch (op) { - case BinaryOperator::EQ: + case BO_EQ: return ValMgr.makeTruthVal(false, resultTy); - case BinaryOperator::NE: + case BO_NE: return ValMgr.makeTruthVal(true, resultTy); default: // This case also handles pointer arithmetic. @@ -333,7 +333,7 @@ SVal SimpleSValuator::EvalBinOpNN(const GRState *state, return UnknownVal(); // Is this a logical not? (!x is represented as x == 0.) - if (op == BinaryOperator::EQ && rhs.isZeroConstant()) { + if (op == BO_EQ && rhs.isZeroConstant()) { // We know how to negate certain expressions. Simplify them here. BinaryOperator::Opcode opc = symIntExpr->getOpcode(); @@ -342,34 +342,34 @@ SVal SimpleSValuator::EvalBinOpNN(const GRState *state, // We don't know how to negate this operation. // Just handle it as if it were a normal comparison to 0. break; - case BinaryOperator::LAnd: - case BinaryOperator::LOr: + case BO_LAnd: + case BO_LOr: assert(false && "Logical operators handled by branching logic."); return UnknownVal(); - case BinaryOperator::Assign: - case BinaryOperator::MulAssign: - case BinaryOperator::DivAssign: - case BinaryOperator::RemAssign: - case BinaryOperator::AddAssign: - case BinaryOperator::SubAssign: - case BinaryOperator::ShlAssign: - case BinaryOperator::ShrAssign: - case BinaryOperator::AndAssign: - case BinaryOperator::XorAssign: - case BinaryOperator::OrAssign: - case BinaryOperator::Comma: + case BO_Assign: + case BO_MulAssign: + case BO_DivAssign: + case BO_RemAssign: + case BO_AddAssign: + case BO_SubAssign: + case BO_ShlAssign: + case BO_ShrAssign: + case BO_AndAssign: + case BO_XorAssign: + case BO_OrAssign: + case BO_Comma: assert(false && "'=' and ',' operators handled by GRExprEngine."); return UnknownVal(); - case BinaryOperator::PtrMemD: - case BinaryOperator::PtrMemI: + case BO_PtrMemD: + case BO_PtrMemI: assert(false && "Pointer arithmetic not handled here."); return UnknownVal(); - case BinaryOperator::LT: - case BinaryOperator::GT: - case BinaryOperator::LE: - case BinaryOperator::GE: - case BinaryOperator::EQ: - case BinaryOperator::NE: + case BO_LT: + case BO_GT: + case BO_LE: + case BO_GE: + case BO_EQ: + case BO_NE: // Negate the comparison and make a value. opc = NegateComparison(opc); assert(symIntExpr->getType(ValMgr.getContext()) == resultTy); @@ -402,9 +402,9 @@ SVal SimpleSValuator::EvalBinOpNN(const GRState *state, const llvm::APSInt *newRHS; if (lop == op) - newRHS = BVF.EvaluateAPSInt(BinaryOperator::Add, first, second); + newRHS = BVF.EvaluateAPSInt(BO_Add, first, second); else - newRHS = BVF.EvaluateAPSInt(BinaryOperator::Sub, first, second); + newRHS = BVF.EvaluateAPSInt(BO_Sub, first, second); return MakeSymIntVal(symIntExpr->getLHS(), lop, *newRHS, resultTy); } } @@ -429,26 +429,26 @@ SVal SimpleSValuator::EvalBinOpNN(const GRState *state, lhs = tmp; switch (op) { - case BinaryOperator::LT: - case BinaryOperator::GT: - case BinaryOperator::LE: - case BinaryOperator::GE: + case BO_LT: + case BO_GT: + case BO_LE: + case BO_GE: op = ReverseComparison(op); continue; - case BinaryOperator::EQ: - case BinaryOperator::NE: - case BinaryOperator::Add: - case BinaryOperator::Mul: - case BinaryOperator::And: - case BinaryOperator::Xor: - case BinaryOperator::Or: + case BO_EQ: + case BO_NE: + case BO_Add: + case BO_Mul: + case BO_And: + case BO_Xor: + case BO_Or: continue; - case BinaryOperator::Shr: + case BO_Shr: if (lhsValue.isAllOnesValue() && lhsValue.isSigned()) // At this point lhs and rhs have been swapped. return rhs; // FALL-THROUGH - case BinaryOperator::Shl: + case BO_Shl: if (lhsValue == 0) // At this point lhs and rhs have been swapped. return rhs; @@ -461,10 +461,12 @@ SVal SimpleSValuator::EvalBinOpNN(const GRState *state, case nonloc::SymbolValKind: { nonloc::SymbolVal *slhs = cast(&lhs); SymbolRef Sym = slhs->getSymbol(); - + + ASTContext& Ctx = ValMgr.getContext(); + // Does the symbol simplify to a constant? If so, "fold" the constant // by setting 'lhs' to a ConcreteInt and try again. - if (Sym->getType(ValMgr.getContext())->isIntegerType()) + if (Sym->getType(Ctx)->isIntegerType()) if (const llvm::APSInt *Constant = state->getSymVal(Sym)) { // The symbol evaluates to a constant. If necessary, promote the // folded constant (LHS) to the result type. @@ -474,7 +476,7 @@ SVal SimpleSValuator::EvalBinOpNN(const GRState *state, // Also promote the RHS (if necessary). - // For shifts, it necessary promote the RHS to the result type. + // For shifts, it is not necessary to promote the RHS. if (BinaryOperator::isShiftOp(op)) continue; @@ -486,7 +488,20 @@ SVal SimpleSValuator::EvalBinOpNN(const GRState *state, continue; } - + + // Is the RHS a symbol we can simplify? + if (const nonloc::SymbolVal *srhs = dyn_cast(&rhs)) { + SymbolRef RSym = srhs->getSymbol(); + if (RSym->getType(Ctx)->isIntegerType()) { + if (const llvm::APSInt *Constant = state->getSymVal(RSym)) { + // The symbol evaluates to a constant. + BasicValueFactory &BVF = ValMgr.getBasicValueFactory(); + const llvm::APSInt &rhs_I = BVF.Convert(resultTy, *Constant); + rhs = nonloc::ConcreteInt(rhs_I); + } + } + } + if (isa(rhs)) { return MakeSymIntVal(slhs->getSymbol(), op, cast(rhs).getValue(), @@ -510,7 +525,7 @@ SVal SimpleSValuator::EvalBinOpLL(const GRState *state, // calling this function with another operation (PR7527). We don't attempt to // model this for now, but it could be useful, particularly when the // "location" is actually an integer value that's been passed through a void*. - if (!(BinaryOperator::isComparisonOp(op) || op == BinaryOperator::Sub)) + if (!(BinaryOperator::isComparisonOp(op) || op == BO_Sub)) return UnknownVal(); // Special cases for when both sides are identical. @@ -519,15 +534,15 @@ SVal SimpleSValuator::EvalBinOpLL(const GRState *state, default: assert(false && "Unimplemented operation for two identical values"); return UnknownVal(); - case BinaryOperator::Sub: + case BO_Sub: return ValMgr.makeZeroVal(resultTy); - case BinaryOperator::EQ: - case BinaryOperator::LE: - case BinaryOperator::GE: + case BO_EQ: + case BO_LE: + case BO_GE: return ValMgr.makeTruthVal(true, resultTy); - case BinaryOperator::NE: - case BinaryOperator::LT: - case BinaryOperator::GT: + case BO_NE: + case BO_LT: + case BO_GT: return ValMgr.makeTruthVal(false, resultTy); } } @@ -543,15 +558,15 @@ SVal SimpleSValuator::EvalBinOpLL(const GRState *state, switch (op) { default: break; - case BinaryOperator::Sub: + case BO_Sub: return EvalCastL(lhs, resultTy); - case BinaryOperator::EQ: - case BinaryOperator::LE: - case BinaryOperator::LT: + case BO_EQ: + case BO_LE: + case BO_LT: return ValMgr.makeTruthVal(false, resultTy); - case BinaryOperator::NE: - case BinaryOperator::GT: - case BinaryOperator::GE: + case BO_NE: + case BO_GT: + case BO_GE: return ValMgr.makeTruthVal(true, resultTy); } } @@ -594,13 +609,13 @@ SVal SimpleSValuator::EvalBinOpLL(const GRState *state, switch (op) { default: break; - case BinaryOperator::EQ: - case BinaryOperator::GT: - case BinaryOperator::GE: + case BO_EQ: + case BO_GT: + case BO_GE: return ValMgr.makeTruthVal(false, resultTy); - case BinaryOperator::NE: - case BinaryOperator::LT: - case BinaryOperator::LE: + case BO_NE: + case BO_LT: + case BO_LE: return ValMgr.makeTruthVal(true, resultTy); } } @@ -624,15 +639,15 @@ SVal SimpleSValuator::EvalBinOpLL(const GRState *state, switch (op) { default: break; - case BinaryOperator::Sub: + case BO_Sub: return EvalCastL(lhs, resultTy); - case BinaryOperator::EQ: - case BinaryOperator::LT: - case BinaryOperator::LE: + case BO_EQ: + case BO_LT: + case BO_LE: return ValMgr.makeTruthVal(false, resultTy); - case BinaryOperator::NE: - case BinaryOperator::GT: - case BinaryOperator::GE: + case BO_NE: + case BO_GT: + case BO_GE: return ValMgr.makeTruthVal(true, resultTy); } } @@ -660,9 +675,9 @@ SVal SimpleSValuator::EvalBinOpLL(const GRState *state, switch (op) { default: return UnknownVal(); - case BinaryOperator::EQ: + case BO_EQ: return ValMgr.makeTruthVal(false, resultTy); - case BinaryOperator::NE: + case BO_NE: return ValMgr.makeTruthVal(true, resultTy); } } @@ -711,8 +726,8 @@ SVal SimpleSValuator::EvalBinOpLL(const GRState *state, } // If the element indexes aren't comparable, see if the raw offsets are. - RegionRawOffset LeftOffset = LeftER->getAsRawOffset(); - RegionRawOffset RightOffset = RightER->getAsRawOffset(); + RegionRawOffset LeftOffset = LeftER->getAsArrayOffset(); + RegionRawOffset RightOffset = RightER->getAsArrayOffset(); if (LeftOffset.getRegion() != NULL && LeftOffset.getRegion() == RightOffset.getRegion()) { @@ -722,17 +737,17 @@ SVal SimpleSValuator::EvalBinOpLL(const GRState *state, switch (op) { default: return UnknownVal(); - case BinaryOperator::LT: + case BO_LT: return ValMgr.makeTruthVal(left < right, resultTy); - case BinaryOperator::GT: + case BO_GT: return ValMgr.makeTruthVal(left > right, resultTy); - case BinaryOperator::LE: + case BO_LE: return ValMgr.makeTruthVal(left <= right, resultTy); - case BinaryOperator::GE: + case BO_GE: return ValMgr.makeTruthVal(left >= right, resultTy); - case BinaryOperator::EQ: + case BO_EQ: return ValMgr.makeTruthVal(left == right, resultTy); - case BinaryOperator::NE: + case BO_NE: return ValMgr.makeTruthVal(left != right, resultTy); } } @@ -770,16 +785,16 @@ SVal SimpleSValuator::EvalBinOpLL(const GRState *state, // We know for sure that the two fields are not the same, since that // would have given us the same SVal. - if (op == BinaryOperator::EQ) + if (op == BO_EQ) return ValMgr.makeTruthVal(false, resultTy); - if (op == BinaryOperator::NE) + if (op == BO_NE) return ValMgr.makeTruthVal(true, resultTy); // Iterate through the fields and see which one comes first. // [C99 6.7.2.1.13] "Within a structure object, the non-bit-field // members and the units in which bit-fields reside have addresses that // increase in the order in which they are declared." - bool leftFirst = (op == BinaryOperator::LT || op == BinaryOperator::LE); + bool leftFirst = (op == BO_LT || op == BO_LE); for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I!=E; ++I) { if (*I == LeftFD) @@ -818,8 +833,41 @@ SVal SimpleSValuator::EvalBinOpLN(const GRState *state, } } } + + // We are dealing with pointer arithmetic. + + // Handle pointer arithmetic on constant values. + if (nonloc::ConcreteInt *rhsInt = dyn_cast(&rhs)) { + if (loc::ConcreteInt *lhsInt = dyn_cast(&lhs)) { + const llvm::APSInt &leftI = lhsInt->getValue(); + assert(leftI.isUnsigned()); + llvm::APSInt rightI(rhsInt->getValue(), /* isUnsigned */ true); + + // Convert the bitwidth of rightI. This should deal with overflow + // since we are dealing with concrete values. + rightI.extOrTrunc(leftI.getBitWidth()); + + // Offset the increment by the pointer size. + llvm::APSInt Multiplicand(rightI.getBitWidth(), /* isUnsigned */ true); + rightI *= Multiplicand; + + // Compute the adjusted pointer. + switch (op) { + case BO_Add: + rightI = leftI + rightI; + break; + case BO_Sub: + rightI = leftI - rightI; + break; + default: + llvm_unreachable("Invalid pointer arithmetic operation"); + } + return loc::ConcreteInt(ValMgr.getBasicValueFactory().getValue(rightI)); + } + } + - // Delegate pointer arithmetic to the StoreManager. + // Delegate remaining pointer arithmetic to the StoreManager. return state->getStateManager().getStoreManager().EvalBinOp(op, lhs, rhs, resultTy); } diff --git a/lib/Checker/StackAddrLeakChecker.cpp b/lib/Checker/StackAddrLeakChecker.cpp index f4a9db6..c67a81d 100644 --- a/lib/Checker/StackAddrLeakChecker.cpp +++ b/lib/Checker/StackAddrLeakChecker.cpp @@ -108,7 +108,7 @@ void StackAddrLeakChecker::EmitStackError(CheckerContext &C, const MemRegion *R, report->addRange(range); C.EmitReport(report); -} +} void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS) { diff --git a/lib/Checker/Store.cpp b/lib/Checker/Store.cpp index b128331..1cb5cd7 100644 --- a/lib/Checker/Store.cpp +++ b/lib/Checker/Store.cpp @@ -21,6 +21,11 @@ StoreManager::StoreManager(GRStateManager &stateMgr) : ValMgr(stateMgr.getValueManager()), StateMgr(stateMgr), MRMgr(ValMgr.getRegionManager()), Ctx(stateMgr.getContext()) {} +Store StoreManager::EnterStackFrame(const GRState *state, + const StackFrameContext *frame) { + return state->getStore(); +} + const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base, QualType EleTy, uint64_t index) { SVal idx = ValMgr.makeArrayIndex(index); @@ -78,7 +83,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) // Handle casts from compatible types. if (R->isBoundable()) if (const TypedRegion *TR = dyn_cast(R)) { - QualType ObjTy = Ctx.getCanonicalType(TR->getValueType(Ctx)); + QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); if (CanonPointeeTy == ObjTy) return R; } @@ -96,17 +101,10 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) assert(0 && "Invalid region cast"); break; } - + case MemRegion::FunctionTextRegionKind: case MemRegion::BlockTextRegionKind: - case MemRegion::BlockDataRegionKind: { - // CodeTextRegion should be cast to only a function or block pointer type, - // although they can in practice be casted to anything, e.g, void*, char*, - // etc. - // Just return the region. - return R; - } - + case MemRegion::BlockDataRegionKind: case MemRegion::StringRegionKind: // FIXME: Need to handle arbitrary downcasts. case MemRegion::SymbolicRegionKind: @@ -139,7 +137,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) // FIXME: Handle symbolic raw offsets. const ElementRegion *elementR = cast(R); - const RegionRawOffset &rawOff = elementR->getAsRawOffset(); + const RegionRawOffset &rawOff = elementR->getAsArrayOffset(); const MemRegion *baseR = rawOff.getRegion(); // If we cannot compute a raw offset, throw up our hands and return @@ -154,7 +152,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) // check to see if type we are casting to is the same as the base // region. If so, just return the base region. if (const TypedRegion *TR = dyn_cast(baseR)) { - QualType ObjTy = Ctx.getCanonicalType(TR->getValueType(Ctx)); + QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy); if (CanonPointeeTy == ObjTy) return baseR; @@ -217,7 +215,7 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, if (performTestOnly) { // Automatically translate references to pointers. - QualType T = R->getValueType(Ctx); + QualType T = R->getValueType(); if (const ReferenceType *RT = T->getAs()) T = Ctx.getPointerType(RT->getPointeeType()); @@ -279,10 +277,6 @@ SVal StoreManager::getLValueElement(QualType elementType, SVal Offset, if (Base.isUnknownOrUndef() || isa(Base)) return Base; - // Only handle integer offsets... for now. - if (!isa(Offset)) - return UnknownVal(); - const MemRegion* BaseRegion = cast(Base).getRegion(); // Pointer of any type can be cast and used as array base. @@ -311,6 +305,19 @@ SVal StoreManager::getLValueElement(QualType elementType, SVal Offset, return UnknownVal(); const llvm::APSInt& BaseIdxI = cast(BaseIdx).getValue(); + + // Only allow non-integer offsets if the base region has no offset itself. + // FIXME: This is a somewhat arbitrary restriction. We should be using + // SValuator here to add the two offsets without checking their types. + if (!isa(Offset)) { + if (isa(BaseRegion->StripCasts())) + return UnknownVal(); + + return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset, + ElemR->getSuperRegion(), + Ctx)); + } + const llvm::APSInt& OffI = cast(Offset).getValue(); assert(BaseIdxI.isSigned()); diff --git a/lib/Checker/StreamChecker.cpp b/lib/Checker/StreamChecker.cpp index c527ca2..8553875 100644 --- a/lib/Checker/StreamChecker.cpp +++ b/lib/Checker/StreamChecker.cpp @@ -23,18 +23,49 @@ using namespace clang; namespace { +struct StreamState { + enum Kind { Opened, Closed, OpenFailed, Escaped } K; + const Stmt *S; + + StreamState(Kind k, const Stmt *s) : K(k), S(s) {} + + bool isOpened() const { return K == Opened; } + bool isClosed() const { return K == Closed; } + //bool isOpenFailed() const { return K == OpenFailed; } + //bool isEscaped() const { return K == Escaped; } + + bool operator==(const StreamState &X) const { + return K == X.K && S == X.S; + } + + static StreamState getOpened(const Stmt *s) { return StreamState(Opened, s); } + static StreamState getClosed(const Stmt *s) { return StreamState(Closed, s); } + static StreamState getOpenFailed(const Stmt *s) { + return StreamState(OpenFailed, s); + } + static StreamState getEscaped(const Stmt *s) { + return StreamState(Escaped, s); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(K); + ID.AddPointer(S); + } +}; + class StreamChecker : public CheckerVisitor { - IdentifierInfo *II_fopen, *II_fread, *II_fwrite, + IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread, *II_fwrite, *II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos, *II_clearerr, *II_feof, *II_ferror, *II_fileno; - BuiltinBug *BT_nullfp, *BT_illegalwhence; + BuiltinBug *BT_nullfp, *BT_illegalwhence, *BT_doubleclose, *BT_ResourceLeak; public: StreamChecker() - : II_fopen(0), II_fread(0), II_fwrite(0), + : II_fopen(0), II_tmpfile(0) ,II_fclose(0), II_fread(0), II_fwrite(0), II_fseek(0), II_ftell(0), II_rewind(0), II_fgetpos(0), II_fsetpos(0), II_clearerr(0), II_feof(0), II_ferror(0), II_fileno(0), - BT_nullfp(0), BT_illegalwhence(0) {} + BT_nullfp(0), BT_illegalwhence(0), BT_doubleclose(0), + BT_ResourceLeak(0) {} static void *getTag() { static int x; @@ -42,9 +73,14 @@ public: } virtual bool EvalCallExpr(CheckerContext &C, const CallExpr *CE); + void EvalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper); + void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng); + void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S); private: void Fopen(CheckerContext &C, const CallExpr *CE); + void Tmpfile(CheckerContext &C, const CallExpr *CE); + void Fclose(CheckerContext &C, const CallExpr *CE); void Fread(CheckerContext &C, const CallExpr *CE); void Fwrite(CheckerContext &C, const CallExpr *CE); void Fseek(CheckerContext &C, const CallExpr *CE); @@ -56,14 +92,25 @@ private: void Feof(CheckerContext &C, const CallExpr *CE); void Ferror(CheckerContext &C, const CallExpr *CE); void Fileno(CheckerContext &C, const CallExpr *CE); + + void OpenFileAux(CheckerContext &C, const CallExpr *CE); - // Return true indicates the stream pointer is NULL. const GRState *CheckNullStream(SVal SV, const GRState *state, CheckerContext &C); + const GRState *CheckDoubleClose(const CallExpr *CE, const GRState *state, + CheckerContext &C); }; } // end anonymous namespace +namespace clang { + template <> + struct GRStateTrait + : public GRStatePartialTrait > { + static void *GDMIndex() { return StreamChecker::getTag(); } + }; +} + void clang::RegisterStreamChecker(GRExprEngine &Eng) { Eng.registerCheck(new StreamChecker()); } @@ -79,6 +126,10 @@ bool StreamChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { ASTContext &Ctx = C.getASTContext(); if (!II_fopen) II_fopen = &Ctx.Idents.get("fopen"); + if (!II_tmpfile) + II_tmpfile = &Ctx.Idents.get("tmpfile"); + if (!II_fclose) + II_fclose = &Ctx.Idents.get("fclose"); if (!II_fread) II_fread = &Ctx.Idents.get("fread"); if (!II_fwrite) @@ -106,6 +157,14 @@ bool StreamChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { Fopen(C, CE); return true; } + if (FD->getIdentifier() == II_tmpfile) { + Tmpfile(C, CE); + return true; + } + if (FD->getIdentifier() == II_fclose) { + Fclose(C, CE); + return true; + } if (FD->getIdentifier() == II_fread) { Fread(C, CE); return true; @@ -155,21 +214,43 @@ bool StreamChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) { } void StreamChecker::Fopen(CheckerContext &C, const CallExpr *CE) { + OpenFileAux(C, CE); +} + +void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) { + OpenFileAux(C, CE); +} + +void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) { const GRState *state = C.getState(); unsigned Count = C.getNodeBuilder().getCurrentBlockCount(); ValueManager &ValMgr = C.getValueManager(); DefinedSVal RetVal = cast(ValMgr.getConjuredSymbolVal(0, CE, Count)); state = state->BindExpr(CE, RetVal); - + ConstraintManager &CM = C.getConstraintManager(); // Bifurcate the state into two: one with a valid FILE* pointer, the other // with a NULL. const GRState *stateNotNull, *stateNull; llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, RetVal); + + if (SymbolRef Sym = RetVal.getAsSymbol()) { + // if RetVal is not NULL, set the symbol's state to Opened. + stateNotNull = + stateNotNull->set(Sym,StreamState::getOpened(CE)); + stateNull = + stateNull->set(Sym, StreamState::getOpenFailed(CE)); + + C.addTransition(stateNotNull); + C.addTransition(stateNull); + } +} - C.addTransition(stateNotNull); - C.addTransition(stateNull); +void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) { + const GRState *state = CheckDoubleClose(CE, C.getState(), C); + if (state) + C.addTransition(state); } void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) { @@ -285,3 +366,103 @@ const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state, } return stateNotNull; } + +const GRState *StreamChecker::CheckDoubleClose(const CallExpr *CE, + const GRState *state, + CheckerContext &C) { + SymbolRef Sym = state->getSVal(CE->getArg(0)).getAsSymbol(); + if (!Sym) + return state; + + const StreamState *SS = state->get(Sym); + + // If the file stream is not tracked, return. + if (!SS) + return state; + + // Check: Double close a File Descriptor could cause undefined behaviour. + // Conforming to man-pages + if (SS->isClosed()) { + ExplodedNode *N = C.GenerateSink(); + if (N) { + if (!BT_doubleclose) + BT_doubleclose = new BuiltinBug("Double fclose", + "Try to close a file Descriptor already" + " closed. Cause undefined behaviour."); + BugReport *R = new BugReport(*BT_doubleclose, + BT_doubleclose->getDescription(), N); + C.EmitReport(R); + } + return NULL; + } + + // Close the File Descriptor. + return state->set(Sym, StreamState::getClosed(CE)); +} + +void StreamChecker::EvalDeadSymbols(CheckerContext &C,SymbolReaper &SymReaper) { + for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), + E = SymReaper.dead_end(); I != E; ++I) { + SymbolRef Sym = *I; + const GRState *state = C.getState(); + const StreamState *SS = state->get(Sym); + if (!SS) + return; + + if (SS->isOpened()) { + ExplodedNode *N = C.GenerateSink(); + if (N) { + if (!BT_ResourceLeak) + BT_ResourceLeak = new BuiltinBug("Resource Leak", + "Opened File never closed. Potential Resource leak."); + BugReport *R = new BugReport(*BT_ResourceLeak, + BT_ResourceLeak->getDescription(), N); + C.EmitReport(R); + } + } + } +} + +void StreamChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag, + GRExprEngine &Eng) { + SaveAndRestore OldHasGen(B.HasGeneratedNode); + const GRState *state = B.getState(); + typedef llvm::ImmutableMap SymMap; + SymMap M = state->get(); + + for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) { + StreamState SS = I->second; + if (SS.isOpened()) { + ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor()); + if (N) { + if (!BT_ResourceLeak) + BT_ResourceLeak = new BuiltinBug("Resource Leak", + "Opened File never closed. Potential Resource leak."); + BugReport *R = new BugReport(*BT_ResourceLeak, + BT_ResourceLeak->getDescription(), N); + Eng.getBugReporter().EmitReport(R); + } + } + } +} + +void StreamChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) { + const Expr *RetE = S->getRetValue(); + if (!RetE) + return; + + const GRState *state = C.getState(); + SymbolRef Sym = state->getSVal(RetE).getAsSymbol(); + + if (!Sym) + return; + + const StreamState *SS = state->get(Sym); + if(!SS) + return; + + if (SS->isOpened()) + state = state->set(Sym, StreamState::getEscaped(S)); + + C.addTransition(state); +} diff --git a/lib/Checker/SymbolManager.cpp b/lib/Checker/SymbolManager.cpp index c2b557e..3b1bb6d 100644 --- a/lib/Checker/SymbolManager.cpp +++ b/lib/Checker/SymbolManager.cpp @@ -28,22 +28,22 @@ static void print(llvm::raw_ostream& os, BinaryOperator::Opcode Op) { default: assert(false && "operator printing not implemented"); break; - case BinaryOperator::Mul: os << '*' ; break; - case BinaryOperator::Div: os << '/' ; break; - case BinaryOperator::Rem: os << '%' ; break; - case BinaryOperator::Add: os << '+' ; break; - case BinaryOperator::Sub: os << '-' ; break; - case BinaryOperator::Shl: os << "<<" ; break; - case BinaryOperator::Shr: os << ">>" ; break; - case BinaryOperator::LT: os << "<" ; break; - case BinaryOperator::GT: os << '>' ; break; - case BinaryOperator::LE: os << "<=" ; break; - case BinaryOperator::GE: os << ">=" ; break; - case BinaryOperator::EQ: os << "==" ; break; - case BinaryOperator::NE: os << "!=" ; break; - case BinaryOperator::And: os << '&' ; break; - case BinaryOperator::Xor: os << '^' ; break; - case BinaryOperator::Or: os << '|' ; break; + case BO_Mul: os << '*' ; break; + case BO_Div: os << '/' ; break; + case BO_Rem: os << '%' ; break; + case BO_Add: os << '+' ; break; + case BO_Sub: os << '-' ; break; + case BO_Shl: os << "<<" ; break; + case BO_Shr: os << ">>" ; break; + case BO_LT: os << "<" ; break; + case BO_GT: os << '>' ; break; + case BO_LE: os << "<=" ; break; + case BO_GE: os << ">=" ; break; + case BO_EQ: os << "==" ; break; + case BO_NE: os << "!=" ; break; + case BO_And: os << '&' ; break; + case BO_Xor: os << '^' ; break; + case BO_Or: os << '|' ; break; } } @@ -78,6 +78,11 @@ void SymbolExtent::dumpToStream(llvm::raw_ostream& os) const { os << "extent_$" << getSymbolID() << '{' << getRegion() << '}'; } +void SymbolMetadata::dumpToStream(llvm::raw_ostream& os) const { + os << "meta_$" << getSymbolID() << '{' + << getRegion() << ',' << T.getAsString() << '}'; +} + void SymbolRegionValue::dumpToStream(llvm::raw_ostream& os) const { os << "reg_$" << getSymbolID() << "<" << R << ">"; } @@ -150,6 +155,24 @@ SymbolManager::getExtentSymbol(const SubRegion *R) { return cast(SD); } +const SymbolMetadata* +SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt* S, QualType T, + unsigned Count, const void* SymbolTag) { + + llvm::FoldingSetNodeID profile; + SymbolMetadata::Profile(profile, R, S, T, Count, SymbolTag); + void* InsertPos; + SymExpr *SD = DataSet.FindNodeOrInsertPos(profile, InsertPos); + if (!SD) { + SD = (SymExpr*) BPAlloc.Allocate(); + new (SD) SymbolMetadata(SymbolCounter, R, S, T, Count, SymbolTag); + DataSet.InsertNode(SD, InsertPos); + ++SymbolCounter; + } + + return cast(SD); +} + const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const llvm::APSInt& v, @@ -191,21 +214,34 @@ QualType SymbolConjured::getType(ASTContext&) const { } QualType SymbolDerived::getType(ASTContext& Ctx) const { - return R->getValueType(Ctx); + return R->getValueType(); } QualType SymbolExtent::getType(ASTContext& Ctx) const { return Ctx.getSizeType(); } +QualType SymbolMetadata::getType(ASTContext&) const { + return T; +} + QualType SymbolRegionValue::getType(ASTContext& C) const { - return R->getValueType(C); + return R->getValueType(); } SymbolManager::~SymbolManager() {} bool SymbolManager::canSymbolicate(QualType T) { - return Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType()); + if (Loc::IsLocType(T)) + return true; + + if (T->isIntegerType()) + return T->isScalarType(); + + if (T->isRecordType()) + return true; + + return false; } void SymbolReaper::markLive(SymbolRef sym) { @@ -213,6 +249,11 @@ void SymbolReaper::markLive(SymbolRef sym) { TheDead.erase(sym); } +void SymbolReaper::markInUse(SymbolRef sym) { + if (isa(sym)) + MetadataInUse.insert(sym); +} + bool SymbolReaper::maybeDead(SymbolRef sym) { if (isLive(sym)) return false; @@ -221,6 +262,31 @@ bool SymbolReaper::maybeDead(SymbolRef sym) { return true; } +static bool IsLiveRegion(SymbolReaper &Reaper, const MemRegion *MR) { + MR = MR->getBaseRegion(); + + if (const SymbolicRegion *SR = dyn_cast(MR)) + return Reaper.isLive(SR->getSymbol()); + + if (const VarRegion *VR = dyn_cast(MR)) + return Reaper.isLive(VR); + + // FIXME: This is a gross over-approximation. What we really need is a way to + // tell if anything still refers to this region. Unlike SymbolicRegions, + // AllocaRegions don't have associated symbols, though, so we don't actually + // have a way to track their liveness. + if (isa(MR)) + return true; + + if (isa(MR)) + return true; + + if (isa(MR)) + return true; + + return false; +} + bool SymbolReaper::isLive(SymbolRef sym) { if (TheLiving.count(sym)) return true; @@ -234,11 +300,21 @@ bool SymbolReaper::isLive(SymbolRef sym) { } if (const SymbolExtent *extent = dyn_cast(sym)) { - const MemRegion *Base = extent->getRegion()->getBaseRegion(); - if (const VarRegion *VR = dyn_cast(Base)) - return isLive(VR); - if (const SymbolicRegion *SR = dyn_cast(Base)) - return isLive(SR->getSymbol()); + if (IsLiveRegion(*this, extent->getRegion())) { + markLive(sym); + return true; + } + return false; + } + + if (const SymbolMetadata *metadata = dyn_cast(sym)) { + if (MetadataInUse.count(sym)) { + if (IsLiveRegion(*this, metadata->getRegion())) { + markLive(sym); + MetadataInUse.erase(sym); + return true; + } + } return false; } @@ -248,16 +324,19 @@ bool SymbolReaper::isLive(SymbolRef sym) { } bool SymbolReaper::isLive(const Stmt* ExprVal) const { - return LCtx->getLiveVariables()->isLive(Loc, ExprVal); + return LCtx->getAnalysisContext()->getRelaxedLiveVariables()-> + isLive(Loc, ExprVal); } bool SymbolReaper::isLive(const VarRegion *VR) const { - const StackFrameContext *SFC = VR->getStackFrame(); + const StackFrameContext *VarContext = VR->getStackFrame(); + const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame(); + + if (VarContext == CurrentContext) + return LCtx->getAnalysisContext()->getRelaxedLiveVariables()-> + isLive(Loc, VR->getDecl()); - if (SFC == LCtx->getCurrentStackFrame()) - return LCtx->getLiveVariables()->isLive(Loc, VR->getDecl()); - else - return SFC->isParentOf(LCtx->getCurrentStackFrame()); + return VarContext->isParentOf(CurrentContext); } SymbolVisitor::~SymbolVisitor() {} diff --git a/lib/Checker/UndefBranchChecker.cpp b/lib/Checker/UndefBranchChecker.cpp index 9088345..1ff0641 100644 --- a/lib/Checker/UndefBranchChecker.cpp +++ b/lib/Checker/UndefBranchChecker.cpp @@ -29,27 +29,28 @@ class UndefBranchChecker : public Checker { FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {} - Expr* FindExpr(Expr* Ex) { + const Expr* FindExpr(const Expr* Ex) { if (!MatchesCriteria(Ex)) return 0; - for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end();I!=E;++I) - if (Expr* ExI = dyn_cast_or_null(*I)) { - Expr* E2 = FindExpr(ExI); + for (Stmt::const_child_iterator I = Ex->child_begin(), + E = Ex->child_end();I!=E;++I) + if (const Expr* ExI = dyn_cast_or_null(*I)) { + const Expr* E2 = FindExpr(ExI); if (E2) return E2; } return Ex; } - bool MatchesCriteria(Expr* Ex) { return St->getSVal(Ex).isUndef(); } + bool MatchesCriteria(const Expr* Ex) { return St->getSVal(Ex).isUndef(); } }; public: UndefBranchChecker() : BT(0) {} static void *getTag(); void VisitBranchCondition(GRBranchNodeBuilder &Builder, GRExprEngine &Eng, - Stmt *Condition, void *tag); + const Stmt *Condition, void *tag); }; } @@ -65,7 +66,7 @@ void *UndefBranchChecker::getTag() { void UndefBranchChecker::VisitBranchCondition(GRBranchNodeBuilder &Builder, GRExprEngine &Eng, - Stmt *Condition, void *tag) { + const Stmt *Condition, void *tag){ const GRState *state = Builder.getState(); SVal X = state->getSVal(Condition); if (X.isUndef()) { @@ -81,7 +82,7 @@ void UndefBranchChecker::VisitBranchCondition(GRBranchNodeBuilder &Builder, // subexpressions and roughly look for the most nested subexpression // that binds to Undefined. We then highlight that expression's range. BlockEdge B = cast(N->getLocation()); - Expr* Ex = cast(B.getSrc()->getTerminatorCondition()); + const Expr* Ex = cast(B.getSrc()->getTerminatorCondition()); assert (Ex && "Block must have a terminator."); // Get the predecessor node and check if is a PostStmt with the Stmt diff --git a/lib/Checker/UndefinedAssignmentChecker.cpp b/lib/Checker/UndefinedAssignmentChecker.cpp index 6cef60e..ccc9748 100644 --- a/lib/Checker/UndefinedAssignmentChecker.cpp +++ b/lib/Checker/UndefinedAssignmentChecker.cpp @@ -25,9 +25,8 @@ class UndefinedAssignmentChecker public: UndefinedAssignmentChecker() : BT(0) {} static void *getTag(); - virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE, - const Stmt *StoreE, SVal location, - SVal val); + virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE, + SVal location, SVal val); }; } @@ -41,7 +40,6 @@ void *UndefinedAssignmentChecker::getTag() { } void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, - const Stmt *AssignE, const Stmt *StoreE, SVal location, SVal val) { @@ -61,8 +59,8 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, // Generate a report for this bug. const Expr *ex = 0; - while (AssignE) { - if (const BinaryOperator *B = dyn_cast(AssignE)) { + while (StoreE) { + if (const BinaryOperator *B = dyn_cast(StoreE)) { if (B->isCompoundAssignmentOp()) { const GRState *state = C.getState(); if (state->getSVal(B->getLHS()).isUndef()) { @@ -77,7 +75,7 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, break; } - if (const DeclStmt *DS = dyn_cast(AssignE)) { + if (const DeclStmt *DS = dyn_cast(StoreE)) { const VarDecl* VD = dyn_cast(DS->getSingleDecl()); ex = VD->getInit(); } diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp index e9b8f09..de7346d 100644 --- a/lib/Checker/UnixAPIChecker.cpp +++ b/lib/Checker/UnixAPIChecker.cpp @@ -100,7 +100,7 @@ static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC, NonLoc ocreateFlag = cast(C.getValueManager().makeIntVal(UC.Val_O_CREAT.getValue(), oflagsEx->getType())); - SVal maskedFlagsUC = C.getSValuator().EvalBinOpNN(state, BinaryOperator::And, + SVal maskedFlagsUC = C.getSValuator().EvalBinOpNN(state, BO_And, oflags, ocreateFlag, oflagsEx->getType()); if (maskedFlagsUC.isUnknownOrUndef()) diff --git a/lib/Checker/UnreachableCodeChecker.cpp b/lib/Checker/UnreachableCodeChecker.cpp new file mode 100644 index 0000000..7a56c7f --- /dev/null +++ b/lib/Checker/UnreachableCodeChecker.cpp @@ -0,0 +1,226 @@ +//==- UnreachableCodeChecker.cpp - Generalized dead code checker -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// This file implements a generalized unreachable code checker using a +// path-sensitive analysis. We mark any path visited, and then walk the CFG as a +// post-analysis to determine what was never visited. +// +// A similar flow-sensitive only check exists in Analysis/ReachableCode.cpp +//===----------------------------------------------------------------------===// + +#include "clang/AST/ParentMap.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Checker/PathSensitive/CheckerVisitor.h" +#include "clang/Checker/PathSensitive/ExplodedGraph.h" +#include "clang/Checker/PathSensitive/SVals.h" +#include "clang/Checker/PathSensitive/CheckerHelpers.h" +#include "clang/Checker/BugReporter/BugReporter.h" +#include "GRExprEngineExperimentalChecks.h" +#include "llvm/ADT/SmallPtrSet.h" + +// The number of CFGBlock pointers we want to reserve memory for. This is used +// once for each function we analyze. +#define DEFAULT_CFGBLOCKS 256 + +using namespace clang; + +namespace { +class UnreachableCodeChecker : public CheckerVisitor { +public: + static void *getTag(); + void VisitEndAnalysis(ExplodedGraph &G, + BugReporter &B, + GRExprEngine &Eng); +private: + static inline const Stmt *getUnreachableStmt(const CFGBlock *CB); + void FindUnreachableEntryPoints(const CFGBlock *CB); + static bool isInvalidPath(const CFGBlock *CB, const ParentMap &PM); + static inline bool isEmptyCFGBlock(const CFGBlock *CB); + + llvm::SmallSet reachable; + llvm::SmallSet visited; +}; +} + +void *UnreachableCodeChecker::getTag() { + static int x = 0; + return &x; +} + +void clang::RegisterUnreachableCodeChecker(GRExprEngine &Eng) { + Eng.registerCheck(new UnreachableCodeChecker()); +} + +void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G, + BugReporter &B, + GRExprEngine &Eng) { + // Bail out if we didn't cover all paths + if (Eng.hasWorkRemaining()) + return; + + CFG *C = 0; + ParentMap *PM = 0; + // Iterate over ExplodedGraph + for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end(); + I != E; ++I) { + const ProgramPoint &P = I->getLocation(); + const LocationContext *LC = P.getLocationContext(); + + // Save the CFG if we don't have it already + if (!C) + C = LC->getAnalysisContext()->getUnoptimizedCFG(); + if (!PM) + PM = &LC->getParentMap(); + + if (const BlockEntrance *BE = dyn_cast(&P)) { + const CFGBlock *CB = BE->getBlock(); + reachable.insert(CB->getBlockID()); + } + } + + // Bail out if we didn't get the CFG or the ParentMap. + if (!C || !PM) + return; + + ASTContext &Ctx = B.getContext(); + + // Find CFGBlocks that were not covered by any node + for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) { + const CFGBlock *CB = *I; + // Check if the block is unreachable + if (reachable.count(CB->getBlockID())) + continue; + + // Check if the block is empty (an artificial block) + if (isEmptyCFGBlock(CB)) + continue; + + // Find the entry points for this block + FindUnreachableEntryPoints(CB); + + // This block may have been pruned; check if we still want to report it + if (reachable.count(CB->getBlockID())) + continue; + + // Check for false positives + if (CB->size() > 0 && isInvalidPath(CB, *PM)) + continue; + + // Special case for __builtin_unreachable. + // FIXME: This should be extended to include other unreachable markers, + // such as llvm_unreachable. + if (!CB->empty()) { + const Stmt *First = CB->front(); + if (const CallExpr *CE = dyn_cast(First)) { + if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable) + continue; + } + } + + // We found a block that wasn't covered - find the statement to report + SourceRange SR; + SourceLocation SL; + if (const Stmt *S = getUnreachableStmt(CB)) { + SR = S->getSourceRange(); + SL = S->getLocStart(); + if (SR.isInvalid() || SL.isInvalid()) + continue; + } + else + continue; + + // Check if the SourceLocation is in a system header + const SourceManager &SM = B.getSourceManager(); + if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL)) + continue; + + B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never" + " executed", SL, SR); + } +} + +// Recursively finds the entry point(s) for this dead CFGBlock. +void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB) { + bool allPredecessorsReachable = true; + + visited.insert(CB->getBlockID()); + + for (CFGBlock::const_pred_iterator I = CB->pred_begin(); I != CB->pred_end(); + ++I) { + // Recurse over all unreachable blocks + if (!reachable.count((*I)->getBlockID())) { + // At least one predeccessor was unreachable + allPredecessorsReachable = false; + + // Only visit the block once + if (!visited.count((*I)->getBlockID())) + FindUnreachableEntryPoints(*I); + } + } + + // If at least one predecessor is unreachable, mark this block as reachable + // so we don't report this block. + if (!allPredecessorsReachable) { + reachable.insert(CB->getBlockID()); + } +} + +// Find the Stmt* in a CFGBlock for reporting a warning +const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) { + if (CB->size() > 0) + return CB->front().getStmt(); + else if (const Stmt *S = CB->getTerminator()) + return S; + else + return 0; +} + +// Determines if the path to this CFGBlock contained an element that infers this +// block is a false positive. We assume that FindUnreachableEntryPoints has +// already marked only the entry points to any dead code, so we need only to +// find the condition that led to this block (the predecessor of this block.) +// There will never be more than one predecessor. +bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB, + const ParentMap &PM) { + // We only expect a predecessor size of 0 or 1. If it is >1, then an external + // condition has broken our assumption (for example, a sink being placed by + // another check). In these cases, we choose not to report. + if (CB->pred_size() > 1) + return true; + + // If there are no predecessors, then this block is trivially unreachable + if (CB->pred_size() == 0) + return false; + + const CFGBlock *pred = *CB->pred_begin(); + + // Get the predecessor block's terminator conditon + const Stmt *cond = pred->getTerminatorCondition(); + + //assert(cond && "CFGBlock's predecessor has a terminator condition"); + // The previous assertion is invalid in some cases (eg do/while). Leaving + // reporting of these situations on at the moment to help triage these cases. + if (!cond) + return false; + + // Run each of the checks on the conditions + if (containsMacro(cond) || containsEnum(cond) + || containsStaticLocal(cond) || containsBuiltinOffsetOf(cond) + || containsStmt(cond)) + return true; + + return false; +} + +// Returns true if the given CFGBlock is empty +bool UnreachableCodeChecker::isEmptyCFGBlock(const CFGBlock *CB) { + return CB->getLabel() == 0 // No labels + && CB->size() == 0 // No statements + && CB->getTerminator() == 0; // No terminator +} diff --git a/lib/Checker/VLASizeChecker.cpp b/lib/Checker/VLASizeChecker.cpp index 936991d..0800b8b 100644 --- a/lib/Checker/VLASizeChecker.cpp +++ b/lib/Checker/VLASizeChecker.cpp @@ -117,7 +117,7 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { SVal EleSizeVal = ValMgr.makeIntVal(EleSize.getQuantity(), SizeTy); // Multiply the array length by the element size. - SVal ArraySizeVal = SV.EvalBinOpNN(state, BinaryOperator::Mul, ArrayLength, + SVal ArraySizeVal = SV.EvalBinOpNN(state, BO_Mul, ArrayLength, cast(EleSizeVal), SizeTy); // Finally, Assume that the array's extent matches the given size. diff --git a/lib/Checker/ValueManager.cpp b/lib/Checker/ValueManager.cpp index aa0c3c8..8b7cd7b 100644 --- a/lib/Checker/ValueManager.cpp +++ b/lib/Checker/ValueManager.cpp @@ -72,7 +72,7 @@ SVal ValueManager::convertToArrayIndex(SVal V) { DefinedOrUnknownSVal ValueManager::getRegionValueSymbolVal(const TypedRegion* R) { - QualType T = R->getValueType(SymMgr.getContext()); + QualType T = R->getValueType(); if (!SymbolManager::canSymbolicate(T)) return UnknownVal(); @@ -117,11 +117,24 @@ DefinedOrUnknownSVal ValueManager::getConjuredSymbolVal(const void *SymbolTag, return nonloc::SymbolVal(sym); } +DefinedSVal ValueManager::getMetadataSymbolVal(const void *SymbolTag, + const MemRegion *MR, + const Expr *E, QualType T, + unsigned Count) { + assert(SymbolManager::canSymbolicate(T) && "Invalid metadata symbol type"); + + SymbolRef sym = SymMgr.getMetadataSymbol(MR, E, T, Count, SymbolTag); + + if (Loc::IsLocType(T)) + return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); + + return nonloc::SymbolVal(sym); +} DefinedOrUnknownSVal ValueManager::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, const TypedRegion *R) { - QualType T = R->getValueType(R->getContext()); + QualType T = R->getValueType(); if (!SymbolManager::canSymbolicate(T)) return UnknownVal(); diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h index 85524ac..91b77425 100644 --- a/lib/CodeGen/ABIInfo.h +++ b/lib/CodeGen/ABIInfo.h @@ -16,52 +16,52 @@ namespace llvm { class Value; class LLVMContext; + class TargetData; } namespace clang { class ASTContext; - // FIXME: This is a layering issue if we want to move ABIInfo - // down. Fortunately CGFunctionInfo has no real tie to CodeGen. namespace CodeGen { class CGFunctionInfo; class CodeGenFunction; + class CodeGenTypes; } - /* FIXME: All of this stuff should be part of the target interface - somehow. It is currently here because it is not clear how to factor - the targets to support this, since the Targets currently live in a - layer below types n'stuff. - */ + // FIXME: All of this stuff should be part of the target interface + // somehow. It is currently here because it is not clear how to factor + // the targets to support this, since the Targets currently live in a + // layer below types n'stuff. /// ABIArgInfo - Helper class to encapsulate information about how a /// specific C type should be passed to or returned from a function. class ABIArgInfo { public: enum Kind { - Direct, /// Pass the argument directly using the normal - /// converted LLVM type. Complex and structure types - /// are passed using first class aggregates. - - Extend, /// Valid only for integer argument types. Same as 'direct' - /// but also emit a zero/sign extension attribute. - - Indirect, /// Pass the argument indirectly via a hidden pointer - /// with the specified alignment (0 indicates default - /// alignment). - - Ignore, /// Ignore the argument (treat as void). Useful for - /// void and empty structs. - - Coerce, /// Only valid for aggregate return types, the argument - /// should be accessed by coercion to a provided type. - - Expand, /// Only valid for aggregate argument types. The - /// structure should be expanded into consecutive - /// arguments for its constituent fields. Currently - /// expand is only allowed on structures whose fields - /// are all scalar types or are themselves expandable - /// types. + /// Direct - Pass the argument directly using the normal converted LLVM + /// type, or by coercing to another specified type stored in + /// 'CoerceToType'). If an offset is specified (in UIntData), then the + /// argument passed is offset by some number of bytes in the memory + /// representation. + Direct, + + /// Extend - Valid only for integer argument types. Same as 'direct' + /// but also emit a zero/sign extension attribute. + Extend, + + /// Indirect - Pass the argument indirectly via a hidden pointer + /// with the specified alignment (0 indicates default alignment). + Indirect, + + /// Ignore - Ignore the argument (treat as void). Useful for void and + /// empty structs. + Ignore, + + /// Expand - Only valid for aggregate argument types. The structure should + /// be expanded into consecutive arguments for its constituent fields. + /// Currently expand is only allowed on structures whose fields + /// are all scalar types or are themselves expandable types. + Expand, KindFirst=Direct, KindLast=Expand }; @@ -79,18 +79,15 @@ namespace clang { public: ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {} - static ABIArgInfo getDirect() { - return ABIArgInfo(Direct); + static ABIArgInfo getDirect(const llvm::Type *T = 0, unsigned Offset = 0) { + return ABIArgInfo(Direct, T, Offset); } - static ABIArgInfo getExtend() { - return ABIArgInfo(Extend); + static ABIArgInfo getExtend(const llvm::Type *T = 0) { + return ABIArgInfo(Extend, T, 0); } static ABIArgInfo getIgnore() { return ABIArgInfo(Ignore); } - static ABIArgInfo getCoerce(const llvm::Type *T) { - return ABIArgInfo(Coerce, T); - } static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true) { return ABIArgInfo(Indirect, 0, Alignment, ByVal); } @@ -102,16 +99,28 @@ namespace clang { bool isDirect() const { return TheKind == Direct; } bool isExtend() const { return TheKind == Extend; } bool isIgnore() const { return TheKind == Ignore; } - bool isCoerce() const { return TheKind == Coerce; } bool isIndirect() const { return TheKind == Indirect; } bool isExpand() const { return TheKind == Expand; } - // Coerce accessors + bool canHaveCoerceToType() const { + return TheKind == Direct || TheKind == Extend; + } + + // Direct/Extend accessors + unsigned getDirectOffset() const { + assert((isDirect() || isExtend()) && "Not a direct or extend kind"); + return UIntData; + } const llvm::Type *getCoerceToType() const { - assert(TheKind == Coerce && "Invalid kind!"); + assert(canHaveCoerceToType() && "Invalid kind!"); return TypeData; } - + + void setCoerceToType(const llvm::Type *T) { + assert(canHaveCoerceToType() && "Invalid kind!"); + TypeData = T; + } + // Indirect accessors unsigned getIndirectAlign() const { assert(TheKind == Indirect && "Invalid kind!"); @@ -130,15 +139,16 @@ namespace clang { /// passed or returned from functions. class ABIInfo { public: + CodeGen::CodeGenTypes &CGT; + + ABIInfo(CodeGen::CodeGenTypes &cgt) : CGT(cgt) {} virtual ~ABIInfo(); + + ASTContext &getContext() const; + llvm::LLVMContext &getVMContext() const; + const llvm::TargetData &getTargetData() const; - virtual void computeInfo(CodeGen::CGFunctionInfo &FI, - ASTContext &Ctx, - llvm::LLVMContext &VMContext, - // This is the preferred type for argument lowering - // which can be used to generate better IR. - const llvm::Type *const *PrefTypes = 0, - unsigned NumPrefTypes = 0) const = 0; + virtual void computeInfo(CodeGen::CGFunctionInfo &FI) const = 0; /// EmitVAArg - Emit the target dependent code to load a value of /// \arg Ty from the va_list pointed to by \arg VAListAddr. diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index cb9e636..04f1ef2 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -24,36 +24,6 @@ using namespace clang; using namespace CodeGen; -/// CGBlockInfo - Information to generate a block literal. -class clang::CodeGen::CGBlockInfo { -public: - /// Name - The name of the block, kindof. - const char *Name; - - /// DeclRefs - Variables from parent scopes that have been - /// imported into this block. - llvm::SmallVector DeclRefs; - - /// InnerBlocks - This block and the blocks it encloses. - llvm::SmallPtrSet InnerBlocks; - - /// CXXThisRef - Non-null if 'this' was required somewhere, in - /// which case this is that expression. - const CXXThisExpr *CXXThisRef; - - /// NeedsObjCSelf - True if something in this block has an implicit - /// reference to 'self'. - bool NeedsObjCSelf; - - /// These are initialized by GenerateBlockFunction. - bool BlockHasCopyDispose; - CharUnits BlockSize; - CharUnits BlockAlign; - llvm::SmallVector BlockLayout; - - CGBlockInfo(const char *Name); -}; - CGBlockInfo::CGBlockInfo(const char *N) : Name(N), CXXThisRef(0), NeedsObjCSelf(false) { @@ -64,9 +34,12 @@ CGBlockInfo::CGBlockInfo(const char *N) llvm::Constant *CodeGenFunction:: -BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnits Size, +BuildDescriptorBlockDecl(const BlockExpr *BE, const CGBlockInfo &Info, const llvm::StructType* Ty, + llvm::Constant *BlockVarLayout, std::vector *NoteForHelper) { + bool BlockHasCopyDispose = Info.BlockHasCopyDispose; + CharUnits Size = Info.BlockSize; const llvm::Type *UnsignedLongTy = CGM.getTypes().ConvertType(getContext().UnsignedLongTy); llvm::Constant *C; @@ -100,7 +73,8 @@ BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnit CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty)); // Layout. - C = llvm::ConstantInt::get(UnsignedLongTy, 0); + C = BlockVarLayout; + Elts.push_back(C); C = llvm::ConstantStruct::get(VMContext, Elts, false); @@ -111,20 +85,6 @@ BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnit return C; } -llvm::Constant *BlockModule::getNSConcreteGlobalBlock() { - if (NSConcreteGlobalBlock == 0) - NSConcreteGlobalBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty, - "_NSConcreteGlobalBlock"); - return NSConcreteGlobalBlock; -} - -llvm::Constant *BlockModule::getNSConcreteStackBlock() { - if (NSConcreteStackBlock == 0) - NSConcreteStackBlock = CGM.CreateRuntimeVariable(PtrToInt8Ty, - "_NSConcreteStackBlock"); - return NSConcreteStackBlock; -} - static void CollectBlockDeclRefInfo(const Stmt *S, CGBlockInfo &Info) { for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); I != E; ++I) @@ -198,6 +158,21 @@ static void AllocateAllBlockDeclRefs(CodeGenFunction &CGF, CGBlockInfo &Info) { } } +static unsigned computeBlockFlag(CodeGenModule &CGM, + const BlockExpr *BE, unsigned flags) { + QualType BPT = BE->getType(); + const FunctionType *ftype = BPT->getPointeeType()->getAs(); + QualType ResultType = ftype->getResultType(); + + CallArgList Args; + CodeGenTypes &Types = CGM.getTypes(); + const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, Args, + FunctionType::ExtInfo()); + if (CGM.ReturnTypeUsesSRet(FnInfo)) + flags |= CodeGenFunction::BLOCK_USE_STRET; + return flags; +} + // FIXME: Push most into CGM, passing down a few bits, like current function // name. llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { @@ -221,6 +196,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { llvm::Value *V; { + llvm::Constant *BlockVarLayout; // C = BuildBlockStructInitlist(); unsigned int flags = BLOCK_HAS_SIGNATURE; @@ -229,6 +205,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // __invoke llvm::Function *Fn = CodeGenFunction(CGM).GenerateBlockFunction(CurGD, BE, Info, CurFuncDecl, + BlockVarLayout, LocalDeclMap); BlockHasCopyDispose |= Info.BlockHasCopyDispose; Elts[3] = Fn; @@ -244,18 +221,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { Elts[0] = C; // __flags - { - QualType BPT = BE->getType(); - const FunctionType *ftype = BPT->getPointeeType()->getAs(); - QualType ResultType = ftype->getResultType(); - - CallArgList Args; - CodeGenTypes &Types = CGM.getTypes(); - const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, Args, - FunctionType::ExtInfo()); - if (CGM.ReturnTypeUsesSRet(FnInfo)) - flags |= BLOCK_USE_STRET; - } + flags = computeBlockFlag(CGM, BE, flags); const llvm::IntegerType *IntTy = cast( CGM.getTypes().ConvertType(CGM.getContext().IntTy)); C = llvm::ConstantInt::get(IntTy, flags); @@ -267,8 +233,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { if (Info.BlockLayout.empty()) { // __descriptor - Elts[4] = BuildDescriptorBlockDecl(BE, Info.BlockHasCopyDispose, - Info.BlockSize, 0, 0); + C = llvm::Constant::getNullValue(PtrToInt8Ty); + Elts[4] = BuildDescriptorBlockDecl(BE, Info, 0, C, 0); // Optimize to being a global block. Elts[0] = CGM.getNSConcreteGlobalBlock(); @@ -371,7 +337,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { SourceLocation()); if (VD->getType()->isReferenceType()) { E = new (getContext()) - UnaryOperator(const_cast(E), UnaryOperator::AddrOf, + UnaryOperator(const_cast(E), UO_AddrOf, getContext().getPointerType(E->getType()), SourceLocation()); } @@ -381,7 +347,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { if (BDRE->isByRef()) { E = new (getContext()) - UnaryOperator(const_cast(E), UnaryOperator::AddrOf, + UnaryOperator(const_cast(E), UO_AddrOf, getContext().getPointerType(E->getType()), SourceLocation()); } @@ -422,9 +388,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { NoteForHelper.resize(NumHelpers); // __descriptor - llvm::Value *Descriptor = BuildDescriptorBlockDecl(BE, - Info.BlockHasCopyDispose, - Info.BlockSize, Ty, + llvm::Value *Descriptor = BuildDescriptorBlockDecl(BE, Info, Ty, + BlockVarLayout, &NoteForHelper); Descriptor = Builder.CreateBitCast(Descriptor, PtrToInt8Ty); Builder.CreateStore(Descriptor, Builder.CreateStructGEP(V, 4, "block.tmp")); @@ -693,18 +658,23 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { std::vector LiteralFields(FieldCount); CGBlockInfo Info(n); + llvm::Constant *BlockVarLayout; llvm::DenseMap LocalDeclMap; llvm::Function *Fn - = CodeGenFunction(CGM).GenerateBlockFunction(GlobalDecl(), BE, Info, 0, LocalDeclMap); + = CodeGenFunction(CGM).GenerateBlockFunction(GlobalDecl(), BE, + Info, 0, BlockVarLayout, + LocalDeclMap); assert(Info.BlockSize == BlockLiteralSize && "no imports allowed for global block"); // isa - LiteralFields[0] = getNSConcreteGlobalBlock(); + LiteralFields[0] = CGM.getNSConcreteGlobalBlock(); - // Flags + // __flags + unsigned flags = computeBlockFlag(CGM, BE, + (BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE)); LiteralFields[1] = - llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE); + llvm::ConstantInt::get(IntTy, flags); // Reserved LiteralFields[2] = llvm::Constant::getNullValue(IntTy); @@ -737,6 +707,7 @@ llvm::Function * CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const BlockExpr *BExpr, CGBlockInfo &Info, const Decl *OuterFuncDecl, + llvm::Constant *& BlockVarLayout, llvm::DenseMap ldm) { // Check if we should generate debug info for this block. @@ -751,7 +722,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const BlockExpr *BExpr, ++i) { const VarDecl *VD = dyn_cast(i->first); - if (VD->getStorageClass() == VarDecl::Static || VD->hasExternalStorage()) + if (VD->getStorageClass() == SC_Static || VD->hasExternalStorage()) LocalDeclMap[VD] = i->second; } @@ -784,6 +755,12 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const BlockExpr *BExpr, // Build the block struct now. AllocateAllBlockDeclRefs(*this, Info); + // Capture block layout info. here. + if (CGM.getContext().getLangOptions().ObjC1) + BlockVarLayout = CGM.getObjCRuntime().GCBlockLayout(*this, Info.DeclRefs); + else + BlockVarLayout = llvm::Constant::getNullValue(PtrToInt8Ty); + QualType ParmTy = getContext().getBlockParmType(BlockHasCopyDispose, BlockLayout); @@ -813,7 +790,11 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const BlockExpr *BExpr, Name.getString(), &CGM.getModule()); CGM.SetInternalFunctionAttributes(BD, Fn, FI); - + StartFunction(BD, ResultType, Fn, Args, + BExpr->getBody()->getLocEnd()); + + CurFuncDecl = OuterFuncDecl; + QualType FnType(BlockFunctionType, 0); bool HasPrototype = isa(BlockFunctionType); @@ -822,15 +803,22 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const BlockExpr *BExpr, getContext().getTranslationUnitDecl(), SourceLocation(), ID, FnType, 0, - FunctionDecl::Static, - FunctionDecl::None, + SC_Static, + SC_None, false, HasPrototype); + if (FunctionProtoType *FT = dyn_cast(FnType)) { + const FunctionDecl *CFD = dyn_cast(CurCodeDecl); + FunctionDecl *FD = const_cast(CFD); + llvm::SmallVector Params; + for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) + Params.push_back(ParmVarDecl::Create(getContext(), FD, + SourceLocation(), 0, + FT->getArgType(i), /*TInfo=*/0, + SC_None, SC_None, 0)); + FD->setParams(Params.data(), Params.size()); + } + - StartFunction(BD, ResultType, Fn, Args, - BExpr->getBody()->getLocEnd()); - - CurFuncDecl = OuterFuncDecl; - // If we have a C++ 'this' reference, go ahead and force it into // existence now. if (Info.CXXThisRef) { @@ -928,7 +916,7 @@ CharUnits BlockFunction::getBlockOffset(CharUnits Size, CharUnits Align) { getContext().getTranslationUnitDecl(), SourceLocation(), 0, QualType(PadTy), 0, - VarDecl::None, VarDecl::None); + SC_None, SC_None); Expr *E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(), SourceLocation()); BlockLayout.push_back(E); @@ -974,8 +962,8 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, - FunctionDecl::None, + SC_Static, + SC_None, false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); @@ -1012,7 +1000,7 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, Dstv = Builder.CreateBitCast(Dstv, PtrToInt8Ty); llvm::Value *N = llvm::ConstantInt::get(CGF.Int32Ty, flag); - llvm::Value *F = getBlockObjectAssign(); + llvm::Value *F = CGM.getBlockObjectAssign(); Builder.CreateCall3(F, Dstv, Srcv, N); } } @@ -1056,8 +1044,8 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, - FunctionDecl::None, + SC_Static, + SC_None, false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); @@ -1141,8 +1129,8 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, - FunctionDecl::None, + SC_Static, + SC_None, false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); @@ -1164,7 +1152,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { flag |= BLOCK_BYREF_CALLER; llvm::Value *N = llvm::ConstantInt::get(CGF.Int32Ty, flag); - llvm::Value *F = getBlockObjectAssign(); + llvm::Value *F = CGM.getBlockObjectAssign(); Builder.CreateCall3(F, DstObj, SrcObj, N); CGF.FinishFunction(); @@ -1205,8 +1193,8 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, FunctionDecl *FD = FunctionDecl::Create(getContext(), getContext().getTranslationUnitDecl(), SourceLocation(), II, R, 0, - FunctionDecl::Static, - FunctionDecl::None, + SC_Static, + SC_None, false, true); CGF.StartFunction(FD, R, Fn, Args, SourceLocation()); @@ -1259,37 +1247,8 @@ llvm::Constant *BlockFunction::BuildbyrefDestroyHelper(const llvm::Type *T, return Entry=CodeGenFunction(CGM).GeneratebyrefDestroyHelperFunction(T, Flag); } -llvm::Value *BlockFunction::getBlockObjectDispose() { - if (CGM.BlockObjectDispose == 0) { - const llvm::FunctionType *FTy; - std::vector ArgTys; - const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); - ArgTys.push_back(PtrToInt8Ty); - ArgTys.push_back(CGF.Int32Ty); - FTy = llvm::FunctionType::get(ResultType, ArgTys, false); - CGM.BlockObjectDispose - = CGM.CreateRuntimeFunction(FTy, "_Block_object_dispose"); - } - return CGM.BlockObjectDispose; -} - -llvm::Value *BlockFunction::getBlockObjectAssign() { - if (CGM.BlockObjectAssign == 0) { - const llvm::FunctionType *FTy; - std::vector ArgTys; - const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); - ArgTys.push_back(PtrToInt8Ty); - ArgTys.push_back(PtrToInt8Ty); - ArgTys.push_back(CGF.Int32Ty); - FTy = llvm::FunctionType::get(ResultType, ArgTys, false); - CGM.BlockObjectAssign - = CGM.CreateRuntimeFunction(FTy, "_Block_object_assign"); - } - return CGM.BlockObjectAssign; -} - void BlockFunction::BuildBlockRelease(llvm::Value *V, int flag) { - llvm::Value *F = getBlockObjectDispose(); + llvm::Value *F = CGM.getBlockObjectDispose(); llvm::Value *N; V = Builder.CreateBitCast(V, PtrToInt8Ty); N = llvm::ConstantInt::get(CGF.Int32Ty, flag); diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index 772a62c..743e3c8 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -73,8 +73,6 @@ class BlockModule : public BlockBase { CodeGenTypes &getTypes() { return Types; } const llvm::TargetData &getTargetData() const { return TheTargetData; } public: - llvm::Constant *getNSConcreteGlobalBlock(); - llvm::Constant *getNSConcreteStackBlock(); int getGlobalUniqueCount() { return ++Block.GlobalUniqueCount; } const llvm::Type *getBlockDescriptorType(); @@ -82,14 +80,6 @@ public: llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, const char *); - /// NSConcreteGlobalBlock - Cached reference to the class pointer for global - /// blocks. - llvm::Constant *NSConcreteGlobalBlock; - - /// NSConcreteStackBlock - Cached reference to the class poinnter for stack - /// blocks. - llvm::Constant *NSConcreteStackBlock; - const llvm::Type *BlockDescriptorType; const llvm::Type *GenericBlockLiteralType; @@ -97,8 +87,6 @@ public: int GlobalUniqueCount; } Block; - llvm::Value *BlockObjectAssign; - llvm::Value *BlockObjectDispose; const llvm::PointerType *PtrToInt8Ty; std::map AssignCache; @@ -108,9 +96,7 @@ public: CodeGenTypes &T, CodeGenModule &CodeGen) : Context(C), TheModule(M), TheTargetData(TD), Types(T), CGM(CodeGen), VMContext(M.getContext()), - NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), BlockDescriptorType(0), - GenericBlockLiteralType(0), - BlockObjectAssign(0), BlockObjectDispose(0) { + BlockDescriptorType(0), GenericBlockLiteralType(0) { Block.GlobalUniqueCount = 0; PtrToInt8Ty = llvm::Type::getInt8PtrTy(M.getContext()); } @@ -207,8 +193,6 @@ public: llvm::Constant *BuildbyrefDestroyHelper(const llvm::Type *T, int flag, unsigned Align); - llvm::Value *getBlockObjectAssign(); - llvm::Value *getBlockObjectDispose(); void BuildBlockRelease(llvm::Value *DeclPtr, int flag = BLOCK_FIELD_IS_BYREF); bool BlockRequiresCopying(QualType Ty) diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index fff4bac..986f621 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -41,6 +41,31 @@ static void EmitMemoryBarrier(CodeGenFunction &CGF, C, C + 5); } +static Value *EmitCastToInt(CodeGenFunction &CGF, + const llvm::Type *ToType, Value *Val) { + if (Val->getType()->isPointerTy()) { + return CGF.Builder.CreatePtrToInt(Val, ToType); + } + assert(Val->getType()->isIntegerTy() && + "Used a non-integer and non-pointer type with atomic builtin"); + assert(Val->getType()->getScalarSizeInBits() <= + ToType->getScalarSizeInBits() && "Integer type too small"); + return CGF.Builder.CreateSExtOrBitCast(Val, ToType); +} + +static Value *EmitCastFromInt(CodeGenFunction &CGF, QualType ToQualType, + Value *Val) { + const llvm::Type *ToType = CGF.ConvertType(ToQualType); + if (ToType->isPointerTy()) { + return CGF.Builder.CreateIntToPtr(Val, ToType); + } + assert(Val->getType()->isIntegerTy() && + "Used a non-integer and non-pointer type with atomic builtin"); + assert(Val->getType()->getScalarSizeInBits() >= + ToType->getScalarSizeInBits() && "Integer type too small"); + return CGF.Builder.CreateTruncOrBitCast(Val, ToType); +} + // The atomic builtins are also full memory barriers. This is a utility for // wrapping a call to the builtins with memory barriers. static Value *EmitCallWithBarrier(CodeGenFunction &CGF, Value *Fn, @@ -60,13 +85,20 @@ static Value *EmitCallWithBarrier(CodeGenFunction &CGF, Value *Fn, /// and the expression node. static RValue EmitBinaryAtomic(CodeGenFunction &CGF, Intrinsic::ID Id, const CallExpr *E) { - Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)), - CGF.EmitScalarExpr(E->getArg(1)) }; - const llvm::Type *ResType[2]; - ResType[0] = CGF.ConvertType(E->getType()); - ResType[1] = CGF.ConvertType(E->getArg(0)->getType()); - Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2); - return RValue::get(EmitCallWithBarrier(CGF, AtomF, Args, Args + 2)); + const llvm::Type *ValueType = + llvm::IntegerType::get(CGF.getLLVMContext(), + CGF.getContext().getTypeSize(E->getType())); + const llvm::Type *PtrType = ValueType->getPointerTo(); + const llvm::Type *IntrinsicTypes[2] = { ValueType, PtrType }; + Value *AtomF = CGF.CGM.getIntrinsic(Id, IntrinsicTypes, 2); + + Value *Args[2] = { CGF.Builder.CreateBitCast(CGF.EmitScalarExpr(E->getArg(0)), + PtrType), + EmitCastToInt(CGF, ValueType, + CGF.EmitScalarExpr(E->getArg(1))) }; + return RValue::get(EmitCastFromInt(CGF, E->getType(), + EmitCallWithBarrier(CGF, AtomF, Args, + Args + 2))); } /// Utility to insert an atomic instruction based Instrinsic::ID and @@ -75,14 +107,21 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF, static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF, Intrinsic::ID Id, const CallExpr *E, Instruction::BinaryOps Op) { - const llvm::Type *ResType[2]; - ResType[0] = CGF.ConvertType(E->getType()); - ResType[1] = CGF.ConvertType(E->getArg(0)->getType()); - Value *AtomF = CGF.CGM.getIntrinsic(Id, ResType, 2); - Value *Args[2] = { CGF.EmitScalarExpr(E->getArg(0)), - CGF.EmitScalarExpr(E->getArg(1)) }; + const llvm::Type *ValueType = + llvm::IntegerType::get(CGF.getLLVMContext(), + CGF.getContext().getTypeSize(E->getType())); + const llvm::Type *PtrType = ValueType->getPointerTo(); + const llvm::Type *IntrinsicTypes[2] = { ValueType, PtrType }; + Value *AtomF = CGF.CGM.getIntrinsic(Id, IntrinsicTypes, 2); + + Value *Args[2] = { CGF.Builder.CreateBitCast(CGF.EmitScalarExpr(E->getArg(0)), + PtrType), + EmitCastToInt(CGF, ValueType, + CGF.EmitScalarExpr(E->getArg(1))) }; Value *Result = EmitCallWithBarrier(CGF, AtomF, Args, Args + 2); - return RValue::get(CGF.Builder.CreateBinOp(Op, Result, Args[1])); + return RValue::get(EmitCastFromInt(CGF, E->getType(), + CGF.Builder.CreateBinOp(Op, Result, + Args[1]))); } /// EmitFAbs - Emit a call to fabs/fabsf/fabsl, depending on the type of ValTy, @@ -245,9 +284,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, "cast"); return RValue::get(Result); } - case Builtin::BI__builtin_expect: + case Builtin::BI__builtin_expect: { // FIXME: pass expect through to LLVM + if (E->getArg(1)->HasSideEffects(getContext())) + (void)EmitScalarExpr(E->getArg(1)); return RValue::get(EmitScalarExpr(E->getArg(0))); + } case Builtin::BI__builtin_bswap32: case Builtin::BI__builtin_bswap64: { Value *ArgValue = EmitScalarExpr(E->getArg(0)); @@ -746,14 +788,23 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_val_compare_and_swap_4: case Builtin::BI__sync_val_compare_and_swap_8: case Builtin::BI__sync_val_compare_and_swap_16: { - const llvm::Type *ResType[2]; - ResType[0]= ConvertType(E->getType()); - ResType[1] = ConvertType(E->getArg(0)->getType()); - Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2); - Value *Args[3] = { EmitScalarExpr(E->getArg(0)), - EmitScalarExpr(E->getArg(1)), - EmitScalarExpr(E->getArg(2)) }; - return RValue::get(EmitCallWithBarrier(*this, AtomF, Args, Args + 3)); + const llvm::Type *ValueType = + llvm::IntegerType::get(CGF.getLLVMContext(), + CGF.getContext().getTypeSize(E->getType())); + const llvm::Type *PtrType = ValueType->getPointerTo(); + const llvm::Type *IntrinsicTypes[2] = { ValueType, PtrType }; + Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, + IntrinsicTypes, 2); + + Value *Args[3] = { Builder.CreateBitCast(CGF.EmitScalarExpr(E->getArg(0)), + PtrType), + EmitCastToInt(CGF, ValueType, + CGF.EmitScalarExpr(E->getArg(1))), + EmitCastToInt(CGF, ValueType, + CGF.EmitScalarExpr(E->getArg(2))) }; + return RValue::get(EmitCastFromInt(CGF, E->getType(), + EmitCallWithBarrier(CGF, AtomF, Args, + Args + 3))); } case Builtin::BI__sync_bool_compare_and_swap_1: @@ -761,14 +812,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_bool_compare_and_swap_4: case Builtin::BI__sync_bool_compare_and_swap_8: case Builtin::BI__sync_bool_compare_and_swap_16: { - const llvm::Type *ResType[2]; - ResType[0]= ConvertType(E->getArg(1)->getType()); - ResType[1] = llvm::PointerType::getUnqual(ResType[0]); - Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, ResType, 2); - Value *OldVal = EmitScalarExpr(E->getArg(1)); - Value *Args[3] = { EmitScalarExpr(E->getArg(0)), - OldVal, - EmitScalarExpr(E->getArg(2)) }; + const llvm::Type *ValueType = + llvm::IntegerType::get( + CGF.getLLVMContext(), + CGF.getContext().getTypeSize(E->getArg(1)->getType())); + const llvm::Type *PtrType = ValueType->getPointerTo(); + const llvm::Type *IntrinsicTypes[2] = { ValueType, PtrType }; + Value *AtomF = CGM.getIntrinsic(Intrinsic::atomic_cmp_swap, + IntrinsicTypes, 2); + + Value *Args[3] = { Builder.CreateBitCast(CGF.EmitScalarExpr(E->getArg(0)), + PtrType), + EmitCastToInt(CGF, ValueType, + CGF.EmitScalarExpr(E->getArg(1))), + EmitCastToInt(CGF, ValueType, + CGF.EmitScalarExpr(E->getArg(2))) }; + Value *OldVal = Args[1]; Value *PrevVal = EmitCallWithBarrier(*this, AtomF, Args, Args + 3); Value *Result = Builder.CreateICmpEQ(PrevVal, OldVal); // zext bool to int. @@ -953,8 +1012,10 @@ const llvm::VectorType *GetNeonType(LLVMContext &C, unsigned type, bool q) { return 0; } -Value *CodeGenFunction::EmitNeonSplat(Value *V, Constant *C) { +Value *CodeGenFunction::EmitNeonSplat(Value *V, Constant *C, bool widen) { unsigned nElts = cast(V->getType())->getNumElements(); + if (widen) + nElts <<= 1; SmallVector Indices(nElts, C); Value* SV = llvm::ConstantVector::get(Indices.begin(), Indices.size()); return Builder.CreateShuffleVector(V, V, SV, "lane"); @@ -989,6 +1050,28 @@ Value *CodeGenFunction::EmitNeonShiftVector(Value *V, const llvm::Type *Ty, return llvm::ConstantVector::get(CV.begin(), CV.size()); } +/// GetPointeeAlignment - Given an expression with a pointer type, find the +/// alignment of the type referenced by the pointer. Skip over implicit +/// casts. +static Value *GetPointeeAlignment(CodeGenFunction &CGF, const Expr *Addr) { + unsigned Align = 1; + // Check if the type is a pointer. The implicit cast operand might not be. + while (Addr->getType()->isPointerType()) { + QualType PtTy = Addr->getType()->getPointeeType(); + unsigned NewA = CGF.getContext().getTypeAlignInChars(PtTy).getQuantity(); + if (NewA > Align) + Align = NewA; + + // If the address is an implicit cast, repeat with the cast operand. + if (const ImplicitCastExpr *CastAddr = dyn_cast(Addr)) { + Addr = CastAddr->getSubExpr(); + continue; + } + break; + } + return llvm::ConstantInt::get(CGF.Int32Ty, Align); +} + Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { if (BuiltinID == ARM::BI__clear_cache) { @@ -1002,9 +1085,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, a, b); } - // Determine the type of this overloaded NEON intrinsic. - assert(BuiltinID > ARM::BI__builtin_thread_pointer); - llvm::SmallVector Ops; for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) Ops.push_back(EmitScalarExpr(E->getArg(i))); @@ -1014,6 +1094,25 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, if (!Arg->isIntegerConstantExpr(Result, getContext())) return 0; + if (BuiltinID == ARM::BI__builtin_arm_vcvtr_f || + BuiltinID == ARM::BI__builtin_arm_vcvtr_d) { + // Determine the overloaded type of this builtin. + const llvm::Type *Ty; + if (BuiltinID == ARM::BI__builtin_arm_vcvtr_f) + Ty = llvm::Type::getFloatTy(VMContext); + else + Ty = llvm::Type::getDoubleTy(VMContext); + + // Determine whether this is an unsigned conversion or not. + bool usgn = Result.getZExtValue() == 1; + unsigned Int = usgn ? Intrinsic::arm_vcvtru : Intrinsic::arm_vcvtr; + + // Call the appropriate intrinsic. + Function *F = CGM.getIntrinsic(Int, &Ty, 1); + return Builder.CreateCall(F, Ops.begin(), Ops.end(), "vcvtr"); + } + + // Determine the type of this overloaded NEON intrinsic. unsigned type = Result.getZExtValue(); bool usgn = type & 0x08; bool quad = type & 0x10; @@ -1029,19 +1128,36 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, switch (BuiltinID) { default: return 0; case ARM::BI__builtin_neon_vaba_v: - case ARM::BI__builtin_neon_vabaq_v: - Int = usgn ? Intrinsic::arm_neon_vabau : Intrinsic::arm_neon_vabas; - return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vaba"); - case ARM::BI__builtin_neon_vabal_v: - Int = usgn ? Intrinsic::arm_neon_vabalu : Intrinsic::arm_neon_vabals; - return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vabal"); + case ARM::BI__builtin_neon_vabaq_v: { + Ops[0] = Builder.CreateBitCast(Ops[0], Ty); + SmallVector Args; + Args.push_back(Ops[1]); + Args.push_back(Ops[2]); + Int = usgn ? Intrinsic::arm_neon_vabdu : Intrinsic::arm_neon_vabds; + Ops[1] = EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Args, "vaba"); + return Builder.CreateAdd(Ops[0], Ops[1], "vaba"); + } + case ARM::BI__builtin_neon_vabal_v: { + Ops[0] = Builder.CreateBitCast(Ops[0], Ty); + SmallVector Args; + Args.push_back(Ops[1]); + Args.push_back(Ops[2]); + Int = usgn ? Intrinsic::arm_neon_vabdu : Intrinsic::arm_neon_vabds; + const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + Ops[1] = EmitNeonCall(CGM.getIntrinsic(Int, &DTy, 1), Args, "vabal"); + Ops[1] = Builder.CreateZExt(Ops[1], Ty); + return Builder.CreateAdd(Ops[0], Ops[1], "vabal"); + } case ARM::BI__builtin_neon_vabd_v: case ARM::BI__builtin_neon_vabdq_v: Int = usgn ? Intrinsic::arm_neon_vabdu : Intrinsic::arm_neon_vabds; return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vabd"); - case ARM::BI__builtin_neon_vabdl_v: - Int = usgn ? Intrinsic::arm_neon_vabdlu : Intrinsic::arm_neon_vabdls; - return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vabdl"); + case ARM::BI__builtin_neon_vabdl_v: { + Int = usgn ? Intrinsic::arm_neon_vabdu : Intrinsic::arm_neon_vabds; + const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, &DTy, 1), Ops, "vabdl"); + return Builder.CreateZExt(Ops[0], Ty, "vabdl"); + } case ARM::BI__builtin_neon_vabs_v: case ARM::BI__builtin_neon_vabsq_v: return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vabs, &Ty, 1), @@ -1049,12 +1165,29 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, case ARM::BI__builtin_neon_vaddhn_v: return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vaddhn, &Ty, 1), Ops, "vaddhn"); - case ARM::BI__builtin_neon_vaddl_v: - Int = usgn ? Intrinsic::arm_neon_vaddlu : Intrinsic::arm_neon_vaddls; - return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vaddl"); - case ARM::BI__builtin_neon_vaddw_v: - Int = usgn ? Intrinsic::arm_neon_vaddws : Intrinsic::arm_neon_vaddwu; - return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vaddw"); + case ARM::BI__builtin_neon_vaddl_v: { + const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + Ops[0] = Builder.CreateBitCast(Ops[0], DTy); + Ops[1] = Builder.CreateBitCast(Ops[1], DTy); + if (usgn) { + Ops[0] = Builder.CreateZExt(Ops[0], Ty); + Ops[1] = Builder.CreateZExt(Ops[1], Ty); + } else { + Ops[0] = Builder.CreateSExt(Ops[0], Ty); + Ops[1] = Builder.CreateSExt(Ops[1], Ty); + } + return Builder.CreateAdd(Ops[0], Ops[1], "vaddl"); + } + case ARM::BI__builtin_neon_vaddw_v: { + const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + Ops[0] = Builder.CreateBitCast(Ops[0], Ty); + Ops[1] = Builder.CreateBitCast(Ops[1], DTy); + if (usgn) + Ops[1] = Builder.CreateZExt(Ops[1], Ty); + else + Ops[1] = Builder.CreateSExt(Ops[1], Ty); + return Builder.CreateAdd(Ops[0], Ops[1], "vaddw"); + } case ARM::BI__builtin_neon_vcale_v: std::swap(Ops[0], Ops[1]); case ARM::BI__builtin_neon_vcage_v: { @@ -1126,6 +1259,12 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Function *F = CGM.getIntrinsic(Int, Tys, 2); return EmitNeonCall(F, Ops, "vcvt_n"); } + case ARM::BI__builtin_neon_vdup_lane_v: + Ops[0] = Builder.CreateBitCast(Ops[0], Ty); + return EmitNeonSplat(Ops[0], cast(Ops[1])); + case ARM::BI__builtin_neon_vdupq_lane_v: + Ops[0] = Builder.CreateBitCast(Ops[0], Ty); + return EmitNeonSplat(Ops[0], cast(Ops[1]), true); case ARM::BI__builtin_neon_vext_v: case ARM::BI__builtin_neon_vextq_v: { ConstantInt *C = dyn_cast(Ops[2]); @@ -1161,6 +1300,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vhsub"); case ARM::BI__builtin_neon_vld1_v: case ARM::BI__builtin_neon_vld1q_v: + Ops.push_back(GetPointeeAlignment(*this, E->getArg(0))); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vld1, &Ty, 1), Ops, "vld1"); case ARM::BI__builtin_neon_vld1_lane_v: @@ -1183,7 +1323,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, case ARM::BI__builtin_neon_vld2_v: case ARM::BI__builtin_neon_vld2q_v: { Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2, &Ty, 1); - Ops[1] = Builder.CreateCall(F, Ops[1], "vld2"); + Value *Align = GetPointeeAlignment(*this, E->getArg(1)); + Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld2"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); return Builder.CreateStore(Ops[1], Ops[0]); @@ -1191,7 +1332,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, case ARM::BI__builtin_neon_vld3_v: case ARM::BI__builtin_neon_vld3q_v: { Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld3, &Ty, 1); - Ops[1] = Builder.CreateCall(F, Ops[1], "vld3"); + Value *Align = GetPointeeAlignment(*this, E->getArg(1)); + Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld3"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); return Builder.CreateStore(Ops[1], Ops[0]); @@ -1199,7 +1341,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, case ARM::BI__builtin_neon_vld4_v: case ARM::BI__builtin_neon_vld4q_v: { Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld4, &Ty, 1); - Ops[1] = Builder.CreateCall(F, Ops[1], "vld4"); + Value *Align = GetPointeeAlignment(*this, E->getArg(1)); + Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld4"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); return Builder.CreateStore(Ops[1], Ops[0]); @@ -1209,6 +1352,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2lane, &Ty, 1); Ops[2] = Builder.CreateBitCast(Ops[2], Ty); Ops[3] = Builder.CreateBitCast(Ops[3], Ty); + Ops.push_back(GetPointeeAlignment(*this, E->getArg(1))); Ops[1] = Builder.CreateCall(F, Ops.begin() + 1, Ops.end(), "vld2_lane"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); @@ -1220,6 +1364,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops[2] = Builder.CreateBitCast(Ops[2], Ty); Ops[3] = Builder.CreateBitCast(Ops[3], Ty); Ops[4] = Builder.CreateBitCast(Ops[4], Ty); + Ops.push_back(GetPointeeAlignment(*this, E->getArg(1))); Ops[1] = Builder.CreateCall(F, Ops.begin() + 1, Ops.end(), "vld3_lane"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); @@ -1232,6 +1377,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops[3] = Builder.CreateBitCast(Ops[3], Ty); Ops[4] = Builder.CreateBitCast(Ops[4], Ty); Ops[5] = Builder.CreateBitCast(Ops[5], Ty); + Ops.push_back(GetPointeeAlignment(*this, E->getArg(1))); Ops[1] = Builder.CreateCall(F, Ops.begin() + 1, Ops.end(), "vld3_lane"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); @@ -1261,6 +1407,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, llvm::Constant *CI = ConstantInt::get(Int32Ty, 0); Args.push_back(CI); + Args.push_back(GetPointeeAlignment(*this, E->getArg(1))); Ops[1] = Builder.CreateCall(F, Args.begin(), Args.end(), "vld_dup"); // splat lane 0 to all elts in each vector of the result. @@ -1283,28 +1430,79 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, case ARM::BI__builtin_neon_vminq_v: Int = usgn ? Intrinsic::arm_neon_vminu : Intrinsic::arm_neon_vmins; return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vmin"); - case ARM::BI__builtin_neon_vmlal_lane_v: - splat = true; - case ARM::BI__builtin_neon_vmlal_v: - Int = usgn ? Intrinsic::arm_neon_vmlalu : Intrinsic::arm_neon_vmlals; - return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vmlal", splat); - case ARM::BI__builtin_neon_vmlsl_lane_v: - splat = true; - case ARM::BI__builtin_neon_vmlsl_v: - Int = usgn ? Intrinsic::arm_neon_vmlslu : Intrinsic::arm_neon_vmlsls; - return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vmlsl", splat); - case ARM::BI__builtin_neon_vmovl_v: - Int = usgn ? Intrinsic::arm_neon_vmovlu : Intrinsic::arm_neon_vmovls; - return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vmovl"); - case ARM::BI__builtin_neon_vmovn_v: - return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vmovn, &Ty, 1), - Ops, "vmovn"); - case ARM::BI__builtin_neon_vmull_lane_v: - splat = true; - case ARM::BI__builtin_neon_vmull_v: - Int = usgn ? Intrinsic::arm_neon_vmullu : Intrinsic::arm_neon_vmulls; - Int = poly ? (unsigned)Intrinsic::arm_neon_vmullp : Int; - return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vmlal", splat); + case ARM::BI__builtin_neon_vmlal_lane_v: { + const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + Ops[2] = Builder.CreateBitCast(Ops[2], DTy); + Ops[2] = EmitNeonSplat(Ops[2], cast(Ops[3])); + } + case ARM::BI__builtin_neon_vmlal_v: { + const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + Ops[0] = Builder.CreateBitCast(Ops[0], Ty); + Ops[1] = Builder.CreateBitCast(Ops[1], DTy); + Ops[2] = Builder.CreateBitCast(Ops[2], DTy); + if (usgn) { + Ops[1] = Builder.CreateZExt(Ops[1], Ty); + Ops[2] = Builder.CreateZExt(Ops[2], Ty); + } else { + Ops[1] = Builder.CreateSExt(Ops[1], Ty); + Ops[2] = Builder.CreateSExt(Ops[2], Ty); + } + Ops[1] = Builder.CreateMul(Ops[1], Ops[2]); + return Builder.CreateAdd(Ops[0], Ops[1], "vmlal"); + } + case ARM::BI__builtin_neon_vmlsl_lane_v: { + const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + Ops[2] = Builder.CreateBitCast(Ops[2], DTy); + Ops[2] = EmitNeonSplat(Ops[2], cast(Ops[3])); + } + case ARM::BI__builtin_neon_vmlsl_v: { + const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + Ops[0] = Builder.CreateBitCast(Ops[0], Ty); + Ops[1] = Builder.CreateBitCast(Ops[1], DTy); + Ops[2] = Builder.CreateBitCast(Ops[2], DTy); + if (usgn) { + Ops[1] = Builder.CreateZExt(Ops[1], Ty); + Ops[2] = Builder.CreateZExt(Ops[2], Ty); + } else { + Ops[1] = Builder.CreateSExt(Ops[1], Ty); + Ops[2] = Builder.CreateSExt(Ops[2], Ty); + } + Ops[1] = Builder.CreateMul(Ops[1], Ops[2]); + return Builder.CreateSub(Ops[0], Ops[1], "vmlsl"); + } + case ARM::BI__builtin_neon_vmovl_v: { + const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + Ops[0] = Builder.CreateBitCast(Ops[0], DTy); + if (usgn) + return Builder.CreateZExt(Ops[0], Ty, "vmovl"); + return Builder.CreateSExt(Ops[0], Ty, "vmovl"); + } + case ARM::BI__builtin_neon_vmovn_v: { + const llvm::Type *QTy = llvm::VectorType::getExtendedElementVectorType(VTy); + Ops[0] = Builder.CreateBitCast(Ops[0], QTy); + return Builder.CreateTrunc(Ops[0], Ty, "vmovn"); + } + case ARM::BI__builtin_neon_vmull_lane_v: { + const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + Ops[1] = Builder.CreateBitCast(Ops[1], DTy); + Ops[1] = EmitNeonSplat(Ops[1], cast(Ops[2])); + } + case ARM::BI__builtin_neon_vmull_v: { + if (poly) + return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vmullp, &Ty, 1), + Ops, "vmull"); + const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + Ops[0] = Builder.CreateBitCast(Ops[0], DTy); + Ops[1] = Builder.CreateBitCast(Ops[1], DTy); + if (usgn) { + Ops[0] = Builder.CreateZExt(Ops[0], Ty); + Ops[1] = Builder.CreateZExt(Ops[1], Ty); + } else { + Ops[0] = Builder.CreateSExt(Ops[0], Ty); + Ops[1] = Builder.CreateSExt(Ops[1], Ty); + } + return Builder.CreateMul(Ops[0], Ops[1], "vmull"); + } case ARM::BI__builtin_neon_vpadal_v: case ARM::BI__builtin_neon_vpadalq_v: Int = usgn ? Intrinsic::arm_neon_vpadalu : Intrinsic::arm_neon_vpadals; @@ -1503,6 +1701,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, return Builder.CreateAdd(Ops[0], Ops[1]); case ARM::BI__builtin_neon_vst1_v: case ARM::BI__builtin_neon_vst1q_v: + Ops.push_back(GetPointeeAlignment(*this, E->getArg(0))); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1, &Ty, 1), Ops, ""); case ARM::BI__builtin_neon_vst1_lane_v: @@ -1513,37 +1712,60 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, return Builder.CreateStore(Ops[1], Builder.CreateBitCast(Ops[0], Ty)); case ARM::BI__builtin_neon_vst2_v: case ARM::BI__builtin_neon_vst2q_v: + Ops.push_back(GetPointeeAlignment(*this, E->getArg(0))); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2, &Ty, 1), Ops, ""); case ARM::BI__builtin_neon_vst2_lane_v: case ARM::BI__builtin_neon_vst2q_lane_v: + Ops.push_back(GetPointeeAlignment(*this, E->getArg(0))); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2lane, &Ty, 1), Ops, ""); case ARM::BI__builtin_neon_vst3_v: case ARM::BI__builtin_neon_vst3q_v: + Ops.push_back(GetPointeeAlignment(*this, E->getArg(0))); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3, &Ty, 1), Ops, ""); case ARM::BI__builtin_neon_vst3_lane_v: case ARM::BI__builtin_neon_vst3q_lane_v: + Ops.push_back(GetPointeeAlignment(*this, E->getArg(0))); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3lane, &Ty, 1), Ops, ""); case ARM::BI__builtin_neon_vst4_v: case ARM::BI__builtin_neon_vst4q_v: + Ops.push_back(GetPointeeAlignment(*this, E->getArg(0))); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4, &Ty, 1), Ops, ""); case ARM::BI__builtin_neon_vst4_lane_v: case ARM::BI__builtin_neon_vst4q_lane_v: + Ops.push_back(GetPointeeAlignment(*this, E->getArg(0))); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4lane, &Ty, 1), Ops, ""); case ARM::BI__builtin_neon_vsubhn_v: return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vsubhn, &Ty, 1), Ops, "vsubhn"); - case ARM::BI__builtin_neon_vsubl_v: - Int = usgn ? Intrinsic::arm_neon_vsublu : Intrinsic::arm_neon_vsubls; - return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vsubl"); - case ARM::BI__builtin_neon_vsubw_v: - Int = usgn ? Intrinsic::arm_neon_vsubws : Intrinsic::arm_neon_vsubwu; - return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vsubw"); + case ARM::BI__builtin_neon_vsubl_v: { + const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + Ops[0] = Builder.CreateBitCast(Ops[0], DTy); + Ops[1] = Builder.CreateBitCast(Ops[1], DTy); + if (usgn) { + Ops[0] = Builder.CreateZExt(Ops[0], Ty); + Ops[1] = Builder.CreateZExt(Ops[1], Ty); + } else { + Ops[0] = Builder.CreateSExt(Ops[0], Ty); + Ops[1] = Builder.CreateSExt(Ops[1], Ty); + } + return Builder.CreateSub(Ops[0], Ops[1], "vsubl"); + } + case ARM::BI__builtin_neon_vsubw_v: { + const llvm::Type *DTy =llvm::VectorType::getTruncatedElementVectorType(VTy); + Ops[0] = Builder.CreateBitCast(Ops[0], Ty); + Ops[1] = Builder.CreateBitCast(Ops[1], DTy); + if (usgn) + Ops[1] = Builder.CreateZExt(Ops[1], Ty); + else + Ops[1] = Builder.CreateSExt(Ops[1], Ty); + return Builder.CreateSub(Ops[0], Ops[1], "vsubw"); + } case ARM::BI__builtin_neon_vtbl1_v: return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vtbl1), Ops, "vtbl1"); @@ -1626,8 +1848,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, for (unsigned vi = 0; vi != 2; ++vi) { SmallVector Indices; for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) { - Indices.push_back(ConstantInt::get(Int32Ty, (i >> 1))); - Indices.push_back(ConstantInt::get(Int32Ty, (i >> 1)+e)); + Indices.push_back(ConstantInt::get(Int32Ty, (i + vi*e) >> 1)); + Indices.push_back(ConstantInt::get(Int32Ty, ((i + vi*e) >> 1)+e)); } Value *Addr = Builder.CreateConstInBoundsGEP1_32(Ops[0], vi); SV = llvm::ConstantVector::get(Indices.begin(), Indices.size()); diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 7b7be9a..179716f 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -287,44 +287,6 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D, return cast(GetOrCreateLLVMFunction(Name, FTy, GD)); } -llvm::Constant * -CodeGenModule::GetCXXMemberFunctionPointerValue(const CXXMethodDecl *MD) { - assert(MD->isInstance() && "Member function must not be static!"); - - MD = MD->getCanonicalDecl(); - - const llvm::Type *PtrDiffTy = Types.ConvertType(Context.getPointerDiffType()); - - // Get the function pointer (or index if this is a virtual function). - if (MD->isVirtual()) { - uint64_t Index = VTables.getMethodVTableIndex(MD); - - // FIXME: We shouldn't use / 8 here. - uint64_t PointerWidthInBytes = Context.Target.getPointerWidth(0) / 8; - - // Itanium C++ ABI 2.3: - // For a non-virtual function, this field is a simple function pointer. - // For a virtual function, it is 1 plus the virtual table offset - // (in bytes) of the function, represented as a ptrdiff_t. - return llvm::ConstantInt::get(PtrDiffTy, (Index * PointerWidthInBytes) + 1); - } - - const FunctionProtoType *FPT = MD->getType()->getAs(); - const llvm::Type *Ty; - // Check whether the function has a computable LLVM signature. - if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) { - // The function has a computable LLVM signature; use the correct type. - Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic()); - } else { - // Use an arbitrary non-function type to tell GetAddrOfFunction that the - // function type is incomplete. - Ty = PtrDiffTy; - } - - llvm::Constant *FuncPtr = GetAddrOfFunction(MD, Ty); - return llvm::ConstantExpr::getPtrToInt(FuncPtr, PtrDiffTy); -} - static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VTableIndex, llvm::Value *This, const llvm::Type *Ty) { Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo(); @@ -356,4 +318,154 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type, return ::BuildVirtualCall(*this, VTableIndex, This, Ty); } -CXXABI::~CXXABI() {} +/// Implementation for CGCXXABI. Possibly this should be moved into +/// the incomplete ABI implementations? + +CGCXXABI::~CGCXXABI() {} + +static void ErrorUnsupportedABI(CodeGenFunction &CGF, + llvm::StringRef S) { + Diagnostic &Diags = CGF.CGM.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot yet compile %1 in this ABI"); + Diags.Report(CGF.getContext().getFullLoc(CGF.CurCodeDecl->getLocation()), + DiagID) + << S; +} + +static llvm::Constant *GetBogusMemberPointer(CodeGenModule &CGM, + QualType T) { + return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T)); +} + +const llvm::Type * +CGCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) { + return CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); +} + +llvm::Value *CGCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, + llvm::Value *&This, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + ErrorUnsupportedABI(CGF, "calls through member pointers"); + + const FunctionProtoType *FPT = + MPT->getPointeeType()->getAs(); + const CXXRecordDecl *RD = + cast(MPT->getClass()->getAs()->getDecl()); + const llvm::FunctionType *FTy = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), + FPT->isVariadic()); + return llvm::Constant::getNullValue(FTy->getPointerTo()); +} + +llvm::Value *CGCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, + llvm::Value *Base, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + ErrorUnsupportedABI(CGF, "loads of member pointers"); + const llvm::Type *Ty = CGF.ConvertType(MPT->getPointeeType())->getPointerTo(); + return llvm::Constant::getNullValue(Ty); +} + +llvm::Value *CGCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, + const CastExpr *E, + llvm::Value *Src) { + ErrorUnsupportedABI(CGF, "member function pointer conversions"); + return GetBogusMemberPointer(CGM, E->getType()); +} + +llvm::Value * +CGCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality) { + ErrorUnsupportedABI(CGF, "member function pointer comparison"); + return CGF.Builder.getFalse(); +} + +llvm::Value * +CGCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + ErrorUnsupportedABI(CGF, "member function pointer null testing"); + return CGF.Builder.getFalse(); +} + +llvm::Constant * +CGCXXABI::EmitMemberPointerConversion(llvm::Constant *C, const CastExpr *E) { + return GetBogusMemberPointer(CGM, E->getType()); +} + +llvm::Constant * +CGCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { + return GetBogusMemberPointer(CGM, QualType(MPT, 0)); +} + +llvm::Constant *CGCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { + return GetBogusMemberPointer(CGM, + CGM.getContext().getMemberPointerType(MD->getType(), + MD->getParent()->getTypeForDecl())); +} + +llvm::Constant *CGCXXABI::EmitMemberPointer(const FieldDecl *FD) { + return GetBogusMemberPointer(CGM, + CGM.getContext().getMemberPointerType(FD->getType(), + FD->getParent()->getTypeForDecl())); +} + +bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) { + // Fake answer. + return true; +} + +void CGCXXABI::BuildThisParam(CodeGenFunction &CGF, FunctionArgList &Params) { + const CXXMethodDecl *MD = cast(CGF.CurGD.getDecl()); + + // FIXME: I'm not entirely sure I like using a fake decl just for code + // generation. Maybe we can come up with a better way? + ImplicitParamDecl *ThisDecl + = ImplicitParamDecl::Create(CGM.getContext(), 0, MD->getLocation(), + &CGM.getContext().Idents.get("this"), + MD->getThisType(CGM.getContext())); + Params.push_back(std::make_pair(ThisDecl, ThisDecl->getType())); + getThisDecl(CGF) = ThisDecl; +} + +void CGCXXABI::EmitThisParam(CodeGenFunction &CGF) { + /// Initialize the 'this' slot. + assert(getThisDecl(CGF) && "no 'this' variable for function"); + getThisValue(CGF) + = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getThisDecl(CGF)), + "this"); +} + +void CGCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF, + RValue RV, QualType ResultType) { + CGF.EmitReturnOfRValue(RV, ResultType); +} + +CharUnits CGCXXABI::GetArrayCookieSize(QualType ElementType) { + return CharUnits::Zero(); +} + +llvm::Value *CGCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, + llvm::Value *NewPtr, + llvm::Value *NumElements, + QualType ElementType) { + // Should never be called. + ErrorUnsupportedABI(CGF, "array cookie initialization"); + return 0; +} + +void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, + QualType ElementType, llvm::Value *&NumElements, + llvm::Value *&AllocPtr, CharUnits &CookieSize) { + ErrorUnsupportedABI(CGF, "array cookie reading"); + + // This should be enough to avoid assertions. + NumElements = 0; + AllocPtr = llvm::Constant::getNullValue(CGF.Builder.getInt8PtrTy()); + CookieSize = CharUnits::Zero(); +} diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index e1bbb0a..367e345 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -15,23 +15,215 @@ #ifndef CLANG_CODEGEN_CXXABI_H #define CLANG_CODEGEN_CXXABI_H +#include "CodeGenFunction.h" + +namespace llvm { + class Constant; + class Type; + class Value; + + template class SmallVectorImpl; +} + namespace clang { + class CastExpr; + class CXXConstructorDecl; + class CXXDestructorDecl; + class CXXMethodDecl; + class CXXRecordDecl; + class FieldDecl; + namespace CodeGen { + class CodeGenFunction; class CodeGenModule; class MangleContext; /// Implements C++ ABI-specific code generation functions. -class CXXABI { +class CGCXXABI { +protected: + CodeGenModule &CGM; + + CGCXXABI(CodeGenModule &CGM) : CGM(CGM) {} + +protected: + ImplicitParamDecl *&getThisDecl(CodeGenFunction &CGF) { + return CGF.CXXThisDecl; + } + llvm::Value *&getThisValue(CodeGenFunction &CGF) { + return CGF.CXXThisValue; + } + + ImplicitParamDecl *&getVTTDecl(CodeGenFunction &CGF) { + return CGF.CXXVTTDecl; + } + llvm::Value *&getVTTValue(CodeGenFunction &CGF) { + return CGF.CXXVTTValue; + } + + /// Build a parameter variable suitable for 'this'. + void BuildThisParam(CodeGenFunction &CGF, FunctionArgList &Params); + + /// Perform prolog initialization of the parameter variable suitable + /// for 'this' emitted by BuildThisParam. + void EmitThisParam(CodeGenFunction &CGF); + + ASTContext &getContext() const { return CGM.getContext(); } + public: - virtual ~CXXABI(); + + virtual ~CGCXXABI(); /// Gets the mangle context. virtual MangleContext &getMangleContext() = 0; + + /// Find the LLVM type used to represent the given member pointer + /// type. + virtual const llvm::Type * + ConvertMemberPointerType(const MemberPointerType *MPT); + + /// Load a member function from an object and a member function + /// pointer. Apply the this-adjustment and set 'This' to the + /// adjusted value. + virtual llvm::Value * + EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, + llvm::Value *&This, + llvm::Value *MemPtr, + const MemberPointerType *MPT); + + /// Calculate an l-value from an object and a data member pointer. + virtual llvm::Value *EmitMemberDataPointerAddress(CodeGenFunction &CGF, + llvm::Value *Base, + llvm::Value *MemPtr, + const MemberPointerType *MPT); + + /// Perform a derived-to-base or base-to-derived member pointer + /// conversion. + virtual llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF, + const CastExpr *E, + llvm::Value *Src); + + /// Perform a derived-to-base or base-to-derived member pointer + /// conversion on a constant member pointer. + virtual llvm::Constant *EmitMemberPointerConversion(llvm::Constant *C, + const CastExpr *E); + + /// Return true if the given member pointer can be zero-initialized + /// (in the C++ sense) with an LLVM zeroinitializer. + virtual bool isZeroInitializable(const MemberPointerType *MPT); + + /// Create a null member pointer of the given type. + virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); + + /// Create a member pointer for the given method. + virtual llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD); + + /// Create a member pointer for the given field. + virtual llvm::Constant *EmitMemberPointer(const FieldDecl *FD); + + /// Emit a comparison between two member pointers. Returns an i1. + virtual llvm::Value * + EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality); + + /// Determine if a member pointer is non-null. Returns an i1. + virtual llvm::Value * + EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *MemPtr, + const MemberPointerType *MPT); + + /// Build the signature of the given constructor variant by adding + /// any required parameters. For convenience, ResTy has been + /// initialized to 'void', and ArgTys has been initialized with the + /// type of 'this' (although this may be changed by the ABI) and + /// will have the formal parameters added to it afterwards. + /// + /// If there are ever any ABIs where the implicit parameters are + /// intermixed with the formal parameters, we can address those + /// then. + virtual void BuildConstructorSignature(const CXXConstructorDecl *Ctor, + CXXCtorType T, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) = 0; + + /// Build the signature of the given destructor variant by adding + /// any required parameters. For convenience, ResTy has been + /// initialized to 'void' and ArgTys has been initialized with the + /// type of 'this' (although this may be changed by the ABI). + virtual void BuildDestructorSignature(const CXXDestructorDecl *Dtor, + CXXDtorType T, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) = 0; + + /// Build the ABI-specific portion of the parameter list for a + /// function. This generally involves a 'this' parameter and + /// possibly some extra data for constructors and destructors. + /// + /// ABIs may also choose to override the return type, which has been + /// initialized with the formal return type of the function. + virtual void BuildInstanceFunctionParams(CodeGenFunction &CGF, + QualType &ResTy, + FunctionArgList &Params) = 0; + + /// Emit the ABI-specific prolog for the function. + virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0; + + virtual void EmitReturnFromThunk(CodeGenFunction &CGF, + RValue RV, QualType ResultType); + + /**************************** Array cookies ******************************/ + + /// Returns the extra size required in order to store the array + /// cookie for the given type. May return 0 to indicate that no + /// array cookie is required. + /// + /// Several cases are filtered out before this method is called: + /// - non-array allocations never need a cookie + /// - calls to ::operator new(size_t, void*) never need a cookie + /// + /// \param ElementType - the allocated type of the expression, + /// i.e. the pointee type of the expression result type + virtual CharUnits GetArrayCookieSize(QualType ElementType); + + /// Initialize the array cookie for the given allocation. + /// + /// \param NewPtr - a char* which is the presumed-non-null + /// return value of the allocation function + /// \param NumElements - the computed number of elements, + /// potentially collapsed from the multidimensional array case + /// \param ElementType - the base element allocated type, + /// i.e. the allocated type after stripping all array types + virtual llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF, + llvm::Value *NewPtr, + llvm::Value *NumElements, + QualType ElementType); + + /// Reads the array cookie associated with the given pointer, + /// if it has one. + /// + /// \param Ptr - a pointer to the first element in the array + /// \param ElementType - the base element type of elements of the array + /// \param NumElements - an out parameter which will be initialized + /// with the number of elements allocated, or zero if there is no + /// cookie + /// \param AllocPtr - an out parameter which will be initialized + /// with a char* pointing to the address returned by the allocation + /// function + /// \param CookieSize - an out parameter which will be initialized + /// with the size of the cookie, or zero if there is no cookie + virtual void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, + QualType ElementType, llvm::Value *&NumElements, + llvm::Value *&AllocPtr, CharUnits &CookieSize); + }; /// Creates an instance of a C++ ABI class. -CXXABI *CreateItaniumCXXABI(CodeGenModule &CGM); -CXXABI *CreateMicrosoftCXXABI(CodeGenModule &CGM); +CGCXXABI *CreateARMCXXABI(CodeGenModule &CGM); +CGCXXABI *CreateItaniumCXXABI(CodeGenModule &CGM); +CGCXXABI *CreateMicrosoftCXXABI(CodeGenModule &CGM); + } } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 3d1e143..475dfa5 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "CGCall.h" +#include "CGCXXABI.h" #include "ABIInfo.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" @@ -35,6 +36,7 @@ static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) { case CC_X86StdCall: return llvm::CallingConv::X86_StdCall; case CC_X86FastCall: return llvm::CallingConv::X86_FastCall; case CC_X86ThisCall: return llvm::CallingConv::X86_ThisCall; + // TODO: add support for CC_X86Pascal to llvm } } @@ -99,6 +101,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D) { if (D->hasAttr()) return CC_X86ThisCall; + if (D->hasAttr()) + return CC_X86Pascal; + return CC_C; } @@ -116,6 +121,9 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { llvm::SmallVector ArgTys; + assert(!isa(MD) && "wrong method for contructors!"); + assert(!isa(MD) && "wrong method for destructors!"); + // Add the 'this' pointer unless this is a static method. if (MD->isInstance()) ArgTys.push_back(GetThisType(Context, MD->getParent())); @@ -126,29 +134,32 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D, CXXCtorType Type) { llvm::SmallVector ArgTys; - - // Add the 'this' pointer. ArgTys.push_back(GetThisType(Context, D->getParent())); + CanQualType ResTy = Context.VoidTy; - // Check if we need to add a VTT parameter (which has type void **). - if (Type == Ctor_Base && D->getParent()->getNumVBases() != 0) - ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); + TheCXXABI.BuildConstructorSignature(D, Type, ResTy, ArgTys); - return ::getFunctionInfo(*this, ArgTys, GetFormalType(D)); + CanQual FTP = GetFormalType(D); + + // Add the formal parameters. + for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) + ArgTys.push_back(FTP->getArgType(i)); + + return getFunctionInfo(ResTy, ArgTys, FTP->getExtInfo()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D, CXXDtorType Type) { - llvm::SmallVector ArgTys; - - // Add the 'this' pointer. + llvm::SmallVector ArgTys; ArgTys.push_back(GetThisType(Context, D->getParent())); - - // Check if we need to add a VTT parameter (which has type void **). - if (Type == Dtor_Base && D->getParent()->getNumVBases() != 0) - ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); + CanQualType ResTy = Context.VoidTy; + + TheCXXABI.BuildDestructorSignature(D, Type, ResTy, ArgTys); - return ::getFunctionInfo(*this, ArgTys, GetFormalType(D)); + CanQual FTP = GetFormalType(D); + assert(FTP->getNumArgs() == 0 && "dtor with formal parameters"); + + return getFunctionInfo(ResTy, ArgTys, FTP->getExtInfo()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) { @@ -243,34 +254,26 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, ArgTys.data(), ArgTys.size()); FunctionInfos.InsertNode(FI, InsertPos); - // ABI lowering wants to know what our preferred type for the argument is in - // various situations, pass it in. - llvm::SmallVector PreferredArgTypes; - for (llvm::SmallVectorImpl::const_iterator - I = ArgTys.begin(), E = ArgTys.end(); I != E; ++I) { - // If this is being called from the guts of the ConvertType loop, make sure - // to call ConvertTypeRecursive so we don't get into issues with cyclic - // pointer type structures. - PreferredArgTypes.push_back(ConvertTypeRecursive(*I)); - } - // Compute ABI information. - getABIInfo().computeInfo(*FI, getContext(), TheModule.getContext(), - PreferredArgTypes.data(), PreferredArgTypes.size()); + getABIInfo().computeInfo(*FI); + + // Loop over all of the computed argument and return value info. If any of + // them are direct or extend without a specified coerce type, specify the + // default now. + ABIArgInfo &RetInfo = FI->getReturnInfo(); + if (RetInfo.canHaveCoerceToType() && RetInfo.getCoerceToType() == 0) + RetInfo.setCoerceToType(ConvertTypeRecursive(FI->getReturnType())); + + for (CGFunctionInfo::arg_iterator I = FI->arg_begin(), E = FI->arg_end(); + I != E; ++I) + if (I->info.canHaveCoerceToType() && I->info.getCoerceToType() == 0) + I->info.setCoerceToType(ConvertTypeRecursive(I->type)); // If this is a top-level call and ConvertTypeRecursive hit unresolved pointer // types, resolve them now. These pointers may point to this function, which // we *just* filled in the FunctionInfo for. - if (!IsRecursive && !PointersToResolve.empty()) { - // Use PATypeHolder's so that our preferred types don't dangle under - // refinement. - llvm::SmallVector Handles(PreferredArgTypes.begin(), - PreferredArgTypes.end()); + if (!IsRecursive && !PointersToResolve.empty()) HandleLateResolvedPointers(); - PreferredArgTypes.clear(); - PreferredArgTypes.append(Handles.begin(), Handles.end()); - } - return *FI; } @@ -311,11 +314,10 @@ void CodeGenTypes::GetExpandedTypes(QualType Ty, "Cannot expand structure with bit-field members."); QualType FT = FD->getType(); - if (CodeGenFunction::hasAggregateLLVMType(FT)) { + if (CodeGenFunction::hasAggregateLLVMType(FT)) GetExpandedTypes(FT, ArgTys, IsRecursive); - } else { + else ArgTys.push_back(ConvertType(FT, IsRecursive)); - } } } @@ -613,7 +615,7 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic, case ABIArgInfo::Extend: case ABIArgInfo::Direct: - ResultType = ConvertType(RetTy, IsRecursive); + ResultType = RetAI.getCoerceToType(); break; case ABIArgInfo::Indirect: { @@ -627,10 +629,6 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic, case ABIArgInfo::Ignore: ResultType = llvm::Type::getVoidTy(getLLVMContext()); break; - - case ABIArgInfo::Coerce: - ResultType = RetAI.getCoerceToType(); - break; } for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), @@ -641,7 +639,15 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic, case ABIArgInfo::Ignore: break; - case ABIArgInfo::Coerce: { + case ABIArgInfo::Indirect: { + // indirect arguments are always on the stack, which is addr space #0. + const llvm::Type *LTy = ConvertTypeForMem(it->type, IsRecursive); + ArgTys.push_back(llvm::PointerType::getUnqual(LTy)); + break; + } + + case ABIArgInfo::Extend: + case ABIArgInfo::Direct: { // If the coerce-to type is a first class aggregate, flatten it. Either // way is semantically identical, but fast-isel and the optimizer // generally likes scalar values better than FCAs. @@ -655,18 +661,6 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic, break; } - case ABIArgInfo::Indirect: { - // indirect arguments are always on the stack, which is addr space #0. - const llvm::Type *LTy = ConvertTypeForMem(it->type, IsRecursive); - ArgTys.push_back(llvm::PointerType::getUnqual(LTy)); - break; - } - - case ABIArgInfo::Extend: - case ABIArgInfo::Direct: - ArgTys.push_back(ConvertType(it->type, IsRecursive)); - break; - case ABIArgInfo::Expand: GetExpandedTypes(it->type, ArgTys, IsRecursive); break; @@ -676,12 +670,18 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic, return llvm::FunctionType::get(ResultType, ArgTys, IsVariadic); } -const llvm::Type * -CodeGenTypes::GetFunctionTypeForVTable(const CXXMethodDecl *MD) { +const llvm::Type *CodeGenTypes::GetFunctionTypeForVTable(GlobalDecl GD) { + const CXXMethodDecl *MD = cast(GD.getDecl()); const FunctionProtoType *FPT = MD->getType()->getAs(); - if (!VerifyFuncTypeComplete(FPT)) - return GetFunctionType(getFunctionInfo(MD), FPT->isVariadic(), false); + if (!VerifyFuncTypeComplete(FPT)) { + const CGFunctionInfo *Info; + if (isa(MD)) + Info = &getFunctionInfo(cast(MD), GD.getDtorType()); + else + Info = &getFunctionInfo(MD); + return GetFunctionType(*Info, FPT->isVariadic(), false); + } return llvm::OpaqueType::get(getLLVMContext()); } @@ -730,13 +730,13 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const ABIArgInfo &RetAI = FI.getReturnInfo(); switch (RetAI.getKind()) { case ABIArgInfo::Extend: - if (RetTy->isSignedIntegerType()) { + if (RetTy->hasSignedIntegerRepresentation()) RetAttrs |= llvm::Attribute::SExt; - } else if (RetTy->isUnsignedIntegerType()) { + else if (RetTy->hasUnsignedIntegerRepresentation()) RetAttrs |= llvm::Attribute::ZExt; - } - // FALLTHROUGH + break; case ABIArgInfo::Direct: + case ABIArgInfo::Ignore: break; case ABIArgInfo::Indirect: @@ -748,10 +748,6 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, llvm::Attribute::ReadNone); break; - case ABIArgInfo::Ignore: - case ABIArgInfo::Coerce: - break; - case ABIArgInfo::Expand: assert(0 && "Invalid ABI kind for return argument"); } @@ -759,7 +755,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, if (RetAttrs) PAL.push_back(llvm::AttributeWithIndex::get(0, RetAttrs)); - // FIXME: we need to honour command line settings also... + // FIXME: we need to honor command line settings also. // FIXME: RegParm should be reduced in case of nested functions and/or global // register variable. signed RegParm = FI.getRegParm(); @@ -774,15 +770,27 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, // 'restrict' -> 'noalias' is done in EmitFunctionProlog when we // have the corresponding parameter variable. It doesn't make // sense to do it here because parameters are so fucked up. - switch (AI.getKind()) { - case ABIArgInfo::Coerce: + case ABIArgInfo::Extend: + if (ParamType->isSignedIntegerType()) + Attributes |= llvm::Attribute::SExt; + else if (ParamType->isUnsignedIntegerType()) + Attributes |= llvm::Attribute::ZExt; + // FALL THROUGH + case ABIArgInfo::Direct: + if (RegParm > 0 && + (ParamType->isIntegerType() || ParamType->isPointerType())) { + RegParm -= + (Context.getTypeSize(ParamType) + PointerWidth - 1) / PointerWidth; + if (RegParm >= 0) + Attributes |= llvm::Attribute::InReg; + } + // FIXME: handle sseregparm someday... + if (const llvm::StructType *STy = - dyn_cast(AI.getCoerceToType())) - Index += STy->getNumElements(); - else - ++Index; - continue; // Skip index increment. + dyn_cast(AI.getCoerceToType())) + Index += STy->getNumElements()-1; // 1 will be added below. + break; case ABIArgInfo::Indirect: if (AI.getIndirectByVal()) @@ -795,24 +803,6 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, llvm::Attribute::ReadNone); break; - case ABIArgInfo::Extend: - if (ParamType->isSignedIntegerType()) { - Attributes |= llvm::Attribute::SExt; - } else if (ParamType->isUnsignedIntegerType()) { - Attributes |= llvm::Attribute::ZExt; - } - // FALLS THROUGH - case ABIArgInfo::Direct: - if (RegParm > 0 && - (ParamType->isIntegerType() || ParamType->isPointerType())) { - RegParm -= - (Context.getTypeSize(ParamType) + PointerWidth - 1) / PointerWidth; - if (RegParm >= 0) - Attributes |= llvm::Attribute::InReg; - } - // FIXME: handle sseregparm someday... - break; - case ABIArgInfo::Ignore: // Skip increment, no matching LLVM parameter. continue; @@ -881,7 +871,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // reference. } else { // Load scalar value from indirect argument. - V = EmitLoadOfScalar(V, false, Ty); + unsigned Alignment = getContext().getTypeAlignInChars(Ty).getQuantity(); + V = EmitLoadOfScalar(V, false, Alignment, Ty); if (!getContext().typesAreCompatible(Ty, Arg->getType())) { // This must be a promotion, for something like // "void a(x) short x; {..." @@ -894,15 +885,13 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, case ABIArgInfo::Extend: case ABIArgInfo::Direct: { - assert(AI != Fn->arg_end() && "Argument mismatch!"); - llvm::Value *V = AI; - if (hasAggregateLLVMType(Ty)) { - // Create a temporary alloca to hold the argument; the rest of - // codegen expects to access aggregates & complex values by - // reference. - V = CreateMemTemp(Ty); - Builder.CreateStore(AI, V); - } else { + // If we have the trivial case, handle it with no muss and fuss. + if (!isa(ArgI.getCoerceToType()) && + ArgI.getCoerceToType() == ConvertType(Ty) && + ArgI.getDirectOffset() == 0) { + assert(AI != Fn->arg_end() && "Argument mismatch!"); + llvm::Value *V = AI; + if (Arg->getType().isRestrictQualified()) AI->addAttr(llvm::Attribute::NoAlias); @@ -911,53 +900,36 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // "void a(x) short x; {..." V = EmitScalarConversion(V, Ty, Arg->getType()); } + EmitParmDecl(*Arg, V); + break; } - EmitParmDecl(*Arg, V); - break; - } - - case ABIArgInfo::Expand: { - // If this structure was expanded into multiple arguments then - // we need to create a temporary and reconstruct it from the - // arguments. - llvm::Value *Temp = CreateMemTemp(Ty, Arg->getName() + ".addr"); - // FIXME: What are the right qualifiers here? - llvm::Function::arg_iterator End = - ExpandTypeFromArgs(Ty, LValue::MakeAddr(Temp, Qualifiers()), AI); - EmitParmDecl(*Arg, Temp); - - // Name the arguments used in expansion and increment AI. - unsigned Index = 0; - for (; AI != End; ++AI, ++Index) - AI->setName(Arg->getName() + "." + llvm::Twine(Index)); - continue; - } - - case ABIArgInfo::Ignore: - // Initialize the local variable appropriately. - if (hasAggregateLLVMType(Ty)) { - EmitParmDecl(*Arg, CreateMemTemp(Ty)); - } else { - EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType()))); - } - - // Skip increment, no matching LLVM parameter. - continue; - case ABIArgInfo::Coerce: { - // FIXME: This is very wasteful; EmitParmDecl is just going to drop the - // result in a new alloca anyway, so we could just store into that - // directly if we broke the abstraction down more. llvm::AllocaInst *Alloca = CreateMemTemp(Ty, "coerce"); - Alloca->setAlignment(getContext().getDeclAlign(Arg).getQuantity()); + + // The alignment we need to use is the max of the requested alignment for + // the argument plus the alignment required by our access code below. + unsigned AlignmentToUse = + CGF.CGM.getTargetData().getABITypeAlignment(ArgI.getCoerceToType()); + AlignmentToUse = std::max(AlignmentToUse, + (unsigned)getContext().getDeclAlign(Arg).getQuantity()); + + Alloca->setAlignment(AlignmentToUse); llvm::Value *V = Alloca; + llvm::Value *Ptr = V; // Pointer to store into. + + // If the value is offset in memory, apply the offset now. + if (unsigned Offs = ArgI.getDirectOffset()) { + Ptr = Builder.CreateBitCast(Ptr, Builder.getInt8PtrTy()); + Ptr = Builder.CreateConstGEP1_32(Ptr, Offs); + Ptr = Builder.CreateBitCast(Ptr, + llvm::PointerType::getUnqual(ArgI.getCoerceToType())); + } // If the coerce-to type is a first class aggregate, we flatten it and // pass the elements. Either way is semantically identical, but fast-isel // and the optimizer generally likes scalar values better than FCAs. if (const llvm::StructType *STy = dyn_cast(ArgI.getCoerceToType())) { - llvm::Value *Ptr = V; Ptr = Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(STy)); for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { @@ -970,13 +942,13 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // Simple case, just do a coerced store of the argument into the alloca. assert(AI != Fn->arg_end() && "Argument mismatch!"); AI->setName(Arg->getName() + ".coerce"); - CreateCoercedStore(AI++, V, /*DestIsVolatile=*/false, *this); + CreateCoercedStore(AI++, Ptr, /*DestIsVolatile=*/false, *this); } // Match to what EmitParmDecl is expecting for this type. if (!CodeGenFunction::hasAggregateLLVMType(Ty)) { - V = EmitLoadOfScalar(V, false, Ty); + V = EmitLoadOfScalar(V, false, AlignmentToUse, Ty); if (!getContext().typesAreCompatible(Ty, Arg->getType())) { // This must be a promotion, for something like // "void a(x) short x; {..." @@ -986,6 +958,32 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, EmitParmDecl(*Arg, V); continue; // Skip ++AI increment, already done. } + + case ABIArgInfo::Expand: { + // If this structure was expanded into multiple arguments then + // we need to create a temporary and reconstruct it from the + // arguments. + llvm::Value *Temp = CreateMemTemp(Ty, Arg->getName() + ".addr"); + llvm::Function::arg_iterator End = + ExpandTypeFromArgs(Ty, MakeAddrLValue(Temp, Ty), AI); + EmitParmDecl(*Arg, Temp); + + // Name the arguments used in expansion and increment AI. + unsigned Index = 0; + for (; AI != End; ++AI, ++Index) + AI->setName(Arg->getName() + "." + llvm::Twine(Index)); + continue; + } + + case ABIArgInfo::Ignore: + // Initialize the local variable appropriately. + if (hasAggregateLLVMType(Ty)) + EmitParmDecl(*Arg, CreateMemTemp(Ty)); + else + EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType()))); + + // Skip increment, no matching LLVM parameter. + continue; } ++AI; @@ -1000,13 +998,14 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) { return; } - llvm::MDNode *RetDbgInfo = 0; + llvm::DebugLoc RetDbgLoc; llvm::Value *RV = 0; QualType RetTy = FI.getReturnType(); const ABIArgInfo &RetAI = FI.getReturnInfo(); switch (RetAI.getKind()) { - case ABIArgInfo::Indirect: + case ABIArgInfo::Indirect: { + unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity(); if (RetTy->isAnyComplexType()) { ComplexPairTy RT = LoadComplexFromAddr(ReturnValue, false); StoreComplexToAddr(RT, CurFn->arg_begin(), false); @@ -1014,43 +1013,54 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) { // Do nothing; aggregrates get evaluated directly into the destination. } else { EmitStoreOfScalar(Builder.CreateLoad(ReturnValue), CurFn->arg_begin(), - false, RetTy); + false, Alignment, RetTy); } break; + } case ABIArgInfo::Extend: - case ABIArgInfo::Direct: { - // The internal return value temp always will have pointer-to-return-type - // type, just do a load. - - // If the instruction right before the insertion point is a store to the - // return value, we can elide the load, zap the store, and usually zap the - // alloca. - llvm::BasicBlock *InsertBB = Builder.GetInsertBlock(); - llvm::StoreInst *SI = 0; - if (InsertBB->empty() || - !(SI = dyn_cast(&InsertBB->back())) || - SI->getPointerOperand() != ReturnValue || SI->isVolatile()) { - RV = Builder.CreateLoad(ReturnValue); + case ABIArgInfo::Direct: + if (RetAI.getCoerceToType() == ConvertType(RetTy) && + RetAI.getDirectOffset() == 0) { + // The internal return value temp always will have pointer-to-return-type + // type, just do a load. + + // If the instruction right before the insertion point is a store to the + // return value, we can elide the load, zap the store, and usually zap the + // alloca. + llvm::BasicBlock *InsertBB = Builder.GetInsertBlock(); + llvm::StoreInst *SI = 0; + if (InsertBB->empty() || + !(SI = dyn_cast(&InsertBB->back())) || + SI->getPointerOperand() != ReturnValue || SI->isVolatile()) { + RV = Builder.CreateLoad(ReturnValue); + } else { + // Get the stored value and nuke the now-dead store. + RetDbgLoc = SI->getDebugLoc(); + RV = SI->getValueOperand(); + SI->eraseFromParent(); + + // If that was the only use of the return value, nuke it as well now. + if (ReturnValue->use_empty() && isa(ReturnValue)) { + cast(ReturnValue)->eraseFromParent(); + ReturnValue = 0; + } + } } else { - // Get the stored value and nuke the now-dead store. - RetDbgInfo = SI->getDbgMetadata(); - RV = SI->getValueOperand(); - SI->eraseFromParent(); - - // If that was the only use of the return value, nuke it as well now. - if (ReturnValue->use_empty() && isa(ReturnValue)) { - cast(ReturnValue)->eraseFromParent(); - ReturnValue = 0; + llvm::Value *V = ReturnValue; + // If the value is offset in memory, apply the offset now. + if (unsigned Offs = RetAI.getDirectOffset()) { + V = Builder.CreateBitCast(V, Builder.getInt8PtrTy()); + V = Builder.CreateConstGEP1_32(V, Offs); + V = Builder.CreateBitCast(V, + llvm::PointerType::getUnqual(RetAI.getCoerceToType())); } + + RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), *this); } break; - } - case ABIArgInfo::Ignore: - break; - case ABIArgInfo::Coerce: - RV = CreateCoercedLoad(ReturnValue, RetAI.getCoerceToType(), *this); + case ABIArgInfo::Ignore: break; case ABIArgInfo::Expand: @@ -1058,8 +1068,8 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) { } llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid(); - if (RetDbgInfo) - Ret->setDbgMetadata(RetDbgInfo); + if (!RetDbgLoc.isUnknown()) + Ret->setDebugLoc(RetDbgLoc); } RValue CodeGenFunction::EmitDelegateCallArg(const VarDecl *Param) { @@ -1089,7 +1099,8 @@ RValue CodeGenFunction::EmitDelegateCallArg(const VarDecl *Param) { if (hasAggregateLLVMType(ArgType)) return RValue::getAggregate(Local); - return RValue::get(EmitLoadOfScalar(Local, false, ArgType)); + unsigned Alignment = getContext().getDeclAlign(Param).getQuantity(); + return RValue::get(EmitLoadOfScalar(Local, false, Alignment, ArgType)); } RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) { @@ -1149,49 +1160,60 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, const ABIArgInfo &ArgInfo = info_it->info; RValue RV = I->first; + unsigned Alignment = + getContext().getTypeAlignInChars(I->second).getQuantity(); switch (ArgInfo.getKind()) { - case ABIArgInfo::Indirect: + case ABIArgInfo::Indirect: { if (RV.isScalar() || RV.isComplex()) { // Make a temporary alloca to pass the argument. Args.push_back(CreateMemTemp(I->second)); if (RV.isScalar()) - EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false, I->second); + EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false, + Alignment, I->second); else StoreComplexToAddr(RV.getComplexVal(), Args.back(), false); } else { Args.push_back(RV.getAggregateAddr()); } break; - - case ABIArgInfo::Extend: - case ABIArgInfo::Direct: - if (RV.isScalar()) { - Args.push_back(RV.getScalarVal()); - } else if (RV.isComplex()) { - llvm::Value *Tmp = llvm::UndefValue::get(ConvertType(I->second)); - Tmp = Builder.CreateInsertValue(Tmp, RV.getComplexVal().first, 0); - Tmp = Builder.CreateInsertValue(Tmp, RV.getComplexVal().second, 1); - Args.push_back(Tmp); - } else { - Args.push_back(Builder.CreateLoad(RV.getAggregateAddr())); - } - break; + } case ABIArgInfo::Ignore: break; + + case ABIArgInfo::Extend: + case ABIArgInfo::Direct: { + if (!isa(ArgInfo.getCoerceToType()) && + ArgInfo.getCoerceToType() == ConvertType(info_it->type) && + ArgInfo.getDirectOffset() == 0) { + if (RV.isScalar()) + Args.push_back(RV.getScalarVal()); + else + Args.push_back(Builder.CreateLoad(RV.getAggregateAddr())); + break; + } - case ABIArgInfo::Coerce: { // FIXME: Avoid the conversion through memory if possible. llvm::Value *SrcPtr; if (RV.isScalar()) { SrcPtr = CreateMemTemp(I->second, "coerce"); - EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, I->second); + EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, Alignment, + I->second); } else if (RV.isComplex()) { SrcPtr = CreateMemTemp(I->second, "coerce"); StoreComplexToAddr(RV.getComplexVal(), SrcPtr, false); } else SrcPtr = RV.getAggregateAddr(); + // If the value is offset in memory, apply the offset now. + if (unsigned Offs = ArgInfo.getDirectOffset()) { + SrcPtr = Builder.CreateBitCast(SrcPtr, Builder.getInt8PtrTy()); + SrcPtr = Builder.CreateConstGEP1_32(SrcPtr, Offs); + SrcPtr = Builder.CreateBitCast(SrcPtr, + llvm::PointerType::getUnqual(ArgInfo.getCoerceToType())); + + } + // If the coerce-to type is a first class aggregate, we flatten it and // pass the elements. Either way is semantically identical, but fast-isel // and the optimizer generally likes scalar values better than FCAs. @@ -1201,7 +1223,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, llvm::PointerType::getUnqual(STy)); for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { llvm::Value *EltPtr = Builder.CreateConstGEP2_32(SrcPtr, 0, i); - Args.push_back(Builder.CreateLoad(EltPtr)); + llvm::LoadInst *LI = Builder.CreateLoad(EltPtr); + // We don't know what we're loading from. + LI->setAlignment(1); + Args.push_back(LI); } } else { // In the simple case, just pass the coerced loaded value. @@ -1294,39 +1319,43 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, CI->setName("call"); switch (RetAI.getKind()) { - case ABIArgInfo::Indirect: + case ABIArgInfo::Indirect: { + unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity(); if (RetTy->isAnyComplexType()) return RValue::getComplex(LoadComplexFromAddr(Args[0], false)); if (CodeGenFunction::hasAggregateLLVMType(RetTy)) return RValue::getAggregate(Args[0]); - return RValue::get(EmitLoadOfScalar(Args[0], false, RetTy)); - - case ABIArgInfo::Extend: - case ABIArgInfo::Direct: - if (RetTy->isAnyComplexType()) { - llvm::Value *Real = Builder.CreateExtractValue(CI, 0); - llvm::Value *Imag = Builder.CreateExtractValue(CI, 1); - return RValue::getComplex(std::make_pair(Real, Imag)); - } - if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { - llvm::Value *DestPtr = ReturnValue.getValue(); - bool DestIsVolatile = ReturnValue.isVolatile(); - - if (!DestPtr) { - DestPtr = CreateMemTemp(RetTy, "agg.tmp"); - DestIsVolatile = false; - } - Builder.CreateStore(CI, DestPtr, DestIsVolatile); - return RValue::getAggregate(DestPtr); - } - return RValue::get(CI); + return RValue::get(EmitLoadOfScalar(Args[0], false, Alignment, RetTy)); + } case ABIArgInfo::Ignore: // If we are ignoring an argument that had a result, make sure to // construct the appropriate return value for our caller. return GetUndefRValue(RetTy); + + case ABIArgInfo::Extend: + case ABIArgInfo::Direct: { + if (RetAI.getCoerceToType() == ConvertType(RetTy) && + RetAI.getDirectOffset() == 0) { + if (RetTy->isAnyComplexType()) { + llvm::Value *Real = Builder.CreateExtractValue(CI, 0); + llvm::Value *Imag = Builder.CreateExtractValue(CI, 1); + return RValue::getComplex(std::make_pair(Real, Imag)); + } + if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { + llvm::Value *DestPtr = ReturnValue.getValue(); + bool DestIsVolatile = ReturnValue.isVolatile(); - case ABIArgInfo::Coerce: { + if (!DestPtr) { + DestPtr = CreateMemTemp(RetTy, "agg.tmp"); + DestIsVolatile = false; + } + Builder.CreateStore(CI, DestPtr, DestIsVolatile); + return RValue::getAggregate(DestPtr); + } + return RValue::get(CI); + } + llvm::Value *DestPtr = ReturnValue.getValue(); bool DestIsVolatile = ReturnValue.isVolatile(); @@ -1335,12 +1364,22 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, DestIsVolatile = false; } - CreateCoercedStore(CI, DestPtr, DestIsVolatile, *this); + // If the value is offset in memory, apply the offset now. + llvm::Value *StorePtr = DestPtr; + if (unsigned Offs = RetAI.getDirectOffset()) { + StorePtr = Builder.CreateBitCast(StorePtr, Builder.getInt8PtrTy()); + StorePtr = Builder.CreateConstGEP1_32(StorePtr, Offs); + StorePtr = Builder.CreateBitCast(StorePtr, + llvm::PointerType::getUnqual(RetAI.getCoerceToType())); + } + CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this); + + unsigned Alignment = getContext().getTypeAlignInChars(RetTy).getQuantity(); if (RetTy->isAnyComplexType()) return RValue::getComplex(LoadComplexFromAddr(DestPtr, false)); if (CodeGenFunction::hasAggregateLLVMType(RetTy)) return RValue::getAggregate(DestPtr); - return RValue::get(EmitLoadOfScalar(DestPtr, false, RetTy)); + return RValue::get(EmitLoadOfScalar(DestPtr, false, Alignment, RetTy)); } case ABIArgInfo::Expand: diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index c50fe90..bf26799 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "CGDebugInfo.h" #include "CodeGenFunction.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/RecordLayout.h" @@ -22,13 +23,13 @@ using namespace CodeGen; static uint64_t ComputeNonVirtualBaseClassOffset(ASTContext &Context, const CXXRecordDecl *DerivedClass, - CXXBaseSpecifierArray::iterator Start, - CXXBaseSpecifierArray::iterator End) { + CastExpr::path_const_iterator Start, + CastExpr::path_const_iterator End) { uint64_t Offset = 0; const CXXRecordDecl *RD = DerivedClass; - for (CXXBaseSpecifierArray::iterator I = Start; I != End; ++I) { + for (CastExpr::path_const_iterator I = Start; I != End; ++I) { const CXXBaseSpecifier *Base = *I; assert(!Base->isVirtual() && "Should not see virtual bases here!"); @@ -50,12 +51,13 @@ ComputeNonVirtualBaseClassOffset(ASTContext &Context, llvm::Constant * CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, - const CXXBaseSpecifierArray &BasePath) { - assert(!BasePath.empty() && "Base path should not be empty!"); + CastExpr::path_const_iterator PathBegin, + CastExpr::path_const_iterator PathEnd) { + assert(PathBegin != PathEnd && "Base path should not be empty!"); uint64_t Offset = - ComputeNonVirtualBaseClassOffset(getContext(), ClassDecl, - BasePath.begin(), BasePath.end()); + ComputeNonVirtualBaseClassOffset(getContext(), ClassDecl, + PathBegin, PathEnd); if (!Offset) return 0; @@ -131,11 +133,12 @@ ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr, llvm::Value * CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, const CXXRecordDecl *Derived, - const CXXBaseSpecifierArray &BasePath, + CastExpr::path_const_iterator PathBegin, + CastExpr::path_const_iterator PathEnd, bool NullCheckValue) { - assert(!BasePath.empty() && "Base path should not be empty!"); + assert(PathBegin != PathEnd && "Base path should not be empty!"); - CXXBaseSpecifierArray::iterator Start = BasePath.begin(); + CastExpr::path_const_iterator Start = PathBegin; const CXXRecordDecl *VBase = 0; // Get the virtual base. @@ -147,11 +150,11 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, uint64_t NonVirtualOffset = ComputeNonVirtualBaseClassOffset(getContext(), VBase ? VBase : Derived, - Start, BasePath.end()); + Start, PathEnd); // Get the base pointer type. const llvm::Type *BasePtrTy = - ConvertType((BasePath.end()[-1])->getType())->getPointerTo(); + ConvertType((PathEnd[-1])->getType())->getPointerTo(); if (!NonVirtualOffset && !VBase) { // Just cast back. @@ -206,16 +209,17 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, llvm::Value * CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, const CXXRecordDecl *Derived, - const CXXBaseSpecifierArray &BasePath, + CastExpr::path_const_iterator PathBegin, + CastExpr::path_const_iterator PathEnd, bool NullCheckValue) { - assert(!BasePath.empty() && "Base path should not be empty!"); + assert(PathBegin != PathEnd && "Base path should not be empty!"); QualType DerivedTy = getContext().getCanonicalType(getContext().getTagDeclType(Derived)); const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo(); llvm::Value *NonVirtualOffset = - CGM.GetNonVirtualBaseClassOffset(Derived, BasePath); + CGM.GetNonVirtualBaseClassOffset(Derived, PathBegin, PathEnd); if (!NonVirtualOffset) { // No offset, we can just cast back. @@ -310,6 +314,28 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD, return VTT; } +namespace { + /// Call the destructor for a direct base class. + struct CallBaseDtor : EHScopeStack::Cleanup { + const CXXRecordDecl *BaseClass; + bool BaseIsVirtual; + CallBaseDtor(const CXXRecordDecl *Base, bool BaseIsVirtual) + : BaseClass(Base), BaseIsVirtual(BaseIsVirtual) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + const CXXRecordDecl *DerivedClass = + cast(CGF.CurCodeDecl)->getParent(); + + const CXXDestructorDecl *D = BaseClass->getDestructor(); + llvm::Value *Addr = + CGF.GetAddressOfDirectBaseInCompleteClass(CGF.LoadCXXThis(), + DerivedClass, BaseClass, + BaseIsVirtual); + CGF.EmitCXXDestructorCall(D, Dtor_Base, BaseIsVirtual, Addr); + } + }; +} + static void EmitBaseInitializer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, CXXBaseOrMemberInitializer *BaseInit, @@ -333,18 +359,14 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, // virtual bases, and we only do virtual bases for complete ctors. llvm::Value *V = CGF.GetAddressOfDirectBaseInCompleteClass(ThisPtr, ClassDecl, - BaseClassDecl, - BaseInit->isBaseVirtual()); + BaseClassDecl, + isBaseVirtual); CGF.EmitAggExpr(BaseInit->getInit(), V, false, false, true); - if (CGF.Exceptions && !BaseClassDecl->hasTrivialDestructor()) { - // FIXME: Is this OK for C++0x delegating constructors? - CodeGenFunction::CleanupBlock Cleanup(CGF, EHCleanup); - - CXXDestructorDecl *DD = BaseClassDecl->getDestructor(); - CGF.EmitCXXDestructorCall(DD, Dtor_Base, isBaseVirtual, V); - } + if (CGF.Exceptions && !BaseClassDecl->hasTrivialDestructor()) + CGF.EHStack.pushCleanup(EHCleanup, BaseClassDecl, + isBaseVirtual); } static void EmitAggMemberInitializer(CodeGenFunction &CGF, @@ -432,6 +454,25 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF, // Emit the fall-through block. CGF.EmitBlock(AfterFor, true); } + +namespace { + struct CallMemberDtor : EHScopeStack::Cleanup { + FieldDecl *Field; + CXXDestructorDecl *Dtor; + + CallMemberDtor(FieldDecl *Field, CXXDestructorDecl *Dtor) + : Field(Field), Dtor(Dtor) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + // FIXME: Is this OK for C++0x delegating constructors? + llvm::Value *ThisPtr = CGF.LoadCXXThis(); + LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0); + + CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, + LHS.getAddress()); + } + }; +} static void EmitMemberInitializer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, @@ -487,7 +528,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, BasePtr = llvm::PointerType::getUnqual(BasePtr); llvm::Value *BaseAddrPtr = CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr); - LHS = LValue::MakeAddr(BaseAddrPtr, CGF.MakeQualifiers(BaseElementTy)); + LHS = CGF.MakeAddrLValue(BaseAddrPtr, BaseElementTy); // Create an array index that will be used to walk over all of the // objects we're constructing. @@ -532,17 +573,9 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, return; CXXRecordDecl *RD = cast(RT->getDecl()); - if (!RD->hasTrivialDestructor()) { - // FIXME: Is this OK for C++0x delegating constructors? - CodeGenFunction::CleanupBlock Cleanup(CGF, EHCleanup); - - llvm::Value *ThisPtr = CGF.LoadCXXThis(); - LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0); - - CXXDestructorDecl *DD = RD->getDestructor(); - CGF.EmitCXXDestructorCall(DD, Dtor_Complete, /*ForVirtualBase=*/false, - LHS.getAddress()); - } + if (!RD->hasTrivialDestructor()) + CGF.EHStack.pushCleanup(EHCleanup, Field, + RD->getDestructor()); } } @@ -598,6 +631,8 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { // Before we go any further, try the complete->base constructor // delegation optimization. if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor)) { + if (CGDebugInfo *DI = getDebugInfo()) + DI->EmitStopPoint(Builder); EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args); return; } @@ -663,113 +698,158 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { const CXXDestructorDecl *Dtor = cast(CurGD.getDecl()); CXXDtorType DtorType = CurGD.getDtorType(); + // The call to operator delete in a deleting destructor happens + // outside of the function-try-block, which means it's always + // possible to delegate the destructor body to the complete + // destructor. Do so. + if (DtorType == Dtor_Deleting) { + EnterDtorCleanups(Dtor, Dtor_Deleting); + EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, + LoadCXXThis()); + PopCleanupBlock(); + return; + } + Stmt *Body = Dtor->getBody(); // If the body is a function-try-block, enter the try before - // anything else --- unless we're in a deleting destructor, in which - // case we're just going to call the complete destructor and then - // call operator delete() on the way out. - bool isTryBody = (DtorType != Dtor_Deleting && - Body && isa(Body)); + // anything else. + bool isTryBody = (Body && isa(Body)); if (isTryBody) EnterCXXTryStmt(*cast(Body), true); - // Emit the destructor epilogue now. If this is a complete - // destructor with a function-try-block, perform the base epilogue - // as well. - // - // FIXME: This isn't really right, because an exception in the - // non-EH epilogue should jump to the appropriate place in the - // EH epilogue. - { - CleanupBlock Cleanup(*this, NormalCleanup); - - if (isTryBody && DtorType == Dtor_Complete) - EmitDtorEpilogue(Dtor, Dtor_Base); - EmitDtorEpilogue(Dtor, DtorType); - - if (Exceptions) { - Cleanup.beginEHCleanup(); - - if (isTryBody && DtorType == Dtor_Complete) - EmitDtorEpilogue(Dtor, Dtor_Base); - EmitDtorEpilogue(Dtor, DtorType); - } - } - - bool SkipBody = false; // should get jump-threaded - - // If this is the deleting variant, just invoke the complete - // variant, then call the appropriate operator delete() on the way - // out. - if (DtorType == Dtor_Deleting) { - EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, - LoadCXXThis()); - SkipBody = true; - + // Enter the epilogue cleanups. + RunCleanupsScope DtorEpilogue(*this); + // If this is the complete variant, just invoke the base variant; // the epilogue will destruct the virtual bases. But we can't do // this optimization if the body is a function-try-block, because // we'd introduce *two* handler blocks. - } else if (!isTryBody && DtorType == Dtor_Complete) { - EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false, - LoadCXXThis()); - SkipBody = true; + switch (DtorType) { + case Dtor_Deleting: llvm_unreachable("already handled deleting case"); + + case Dtor_Complete: + // Enter the cleanup scopes for virtual bases. + EnterDtorCleanups(Dtor, Dtor_Complete); + + if (!isTryBody) { + EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false, + LoadCXXThis()); + break; + } + // Fallthrough: act like we're in the base variant. - // Otherwise, we're in the base variant, so we need to ensure the - // vtable ptrs are right before emitting the body. - } else { + case Dtor_Base: + // Enter the cleanup scopes for fields and non-virtual bases. + EnterDtorCleanups(Dtor, Dtor_Base); + + // Initialize the vtable pointers before entering the body. InitializeVTablePointers(Dtor->getParent()); - } - // Emit the body of the statement. - if (SkipBody) - (void) 0; - else if (isTryBody) - EmitStmt(cast(Body)->getTryBlock()); - else if (Body) - EmitStmt(Body); - else { - assert(Dtor->isImplicit() && "bodyless dtor not implicit"); - // nothing to do besides what's in the epilogue + if (isTryBody) + EmitStmt(cast(Body)->getTryBlock()); + else if (Body) + EmitStmt(Body); + else { + assert(Dtor->isImplicit() && "bodyless dtor not implicit"); + // nothing to do besides what's in the epilogue + } + break; } - // We're done with the epilogue cleanup. - PopCleanupBlock(); + // Jump out through the epilogue cleanups. + DtorEpilogue.ForceCleanup(); // Exit the try if applicable. if (isTryBody) ExitCXXTryStmt(*cast(Body), true); } +namespace { + /// Call the operator delete associated with the current destructor. + struct CallDtorDelete : EHScopeStack::Cleanup { + CallDtorDelete() {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + const CXXDestructorDecl *Dtor = cast(CGF.CurCodeDecl); + const CXXRecordDecl *ClassDecl = Dtor->getParent(); + CGF.EmitDeleteCall(Dtor->getOperatorDelete(), CGF.LoadCXXThis(), + CGF.getContext().getTagDeclType(ClassDecl)); + } + }; + + struct CallArrayFieldDtor : EHScopeStack::Cleanup { + const FieldDecl *Field; + CallArrayFieldDtor(const FieldDecl *Field) : Field(Field) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + QualType FieldType = Field->getType(); + const ConstantArrayType *Array = + CGF.getContext().getAsConstantArrayType(FieldType); + + QualType BaseType = + CGF.getContext().getBaseElementType(Array->getElementType()); + const CXXRecordDecl *FieldClassDecl = BaseType->getAsCXXRecordDecl(); + + llvm::Value *ThisPtr = CGF.LoadCXXThis(); + LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, + // FIXME: Qualifiers? + /*CVRQualifiers=*/0); + + const llvm::Type *BasePtr = CGF.ConvertType(BaseType)->getPointerTo(); + llvm::Value *BaseAddrPtr = + CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr); + CGF.EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(), + Array, BaseAddrPtr); + } + }; + + struct CallFieldDtor : EHScopeStack::Cleanup { + const FieldDecl *Field; + CallFieldDtor(const FieldDecl *Field) : Field(Field) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + const CXXRecordDecl *FieldClassDecl = + Field->getType()->getAsCXXRecordDecl(); + + llvm::Value *ThisPtr = CGF.LoadCXXThis(); + LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, + // FIXME: Qualifiers? + /*CVRQualifiers=*/0); + + CGF.EmitCXXDestructorCall(FieldClassDecl->getDestructor(), + Dtor_Complete, /*ForVirtualBase=*/false, + LHS.getAddress()); + } + }; +} + /// EmitDtorEpilogue - Emit all code that comes at the end of class's /// destructor. This is to call destructors on members and base classes /// in reverse order of their construction. -void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, - CXXDtorType DtorType) { +void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD, + CXXDtorType DtorType) { assert(!DD->isTrivial() && "Should not emit dtor epilogue for trivial dtor!"); - const CXXRecordDecl *ClassDecl = DD->getParent(); - - // In a deleting destructor, we've already called the complete - // destructor as a subroutine, so we just have to delete the - // appropriate value. + // The deleting-destructor phase just needs to call the appropriate + // operator delete that Sema picked up. if (DtorType == Dtor_Deleting) { assert(DD->getOperatorDelete() && "operator delete missing - EmitDtorEpilogue"); - EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(), - getContext().getTagDeclType(ClassDecl)); + EHStack.pushCleanup(NormalAndEHCleanup); return; } - // For complete destructors, we've already called the base - // destructor (in GenerateBody), so we just need to destruct all the - // virtual bases. + const CXXRecordDecl *ClassDecl = DD->getParent(); + + // The complete-destructor phase just destructs all the virtual bases. if (DtorType == Dtor_Complete) { - // Handle virtual bases. - for (CXXRecordDecl::reverse_base_class_const_iterator I = - ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); + + // We push them in the forward order so that they'll be popped in + // the reverse order. + for (CXXRecordDecl::base_class_const_iterator I = + ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); I != E; ++I) { const CXXBaseSpecifier &Base = *I; CXXRecordDecl *BaseClassDecl @@ -778,26 +858,48 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, // Ignore trivial destructors. if (BaseClassDecl->hasTrivialDestructor()) continue; - const CXXDestructorDecl *D = BaseClassDecl->getDestructor(); - llvm::Value *V = - GetAddressOfDirectBaseInCompleteClass(LoadCXXThis(), - ClassDecl, BaseClassDecl, - /*BaseIsVirtual=*/true); - EmitCXXDestructorCall(D, Dtor_Base, /*ForVirtualBase=*/true, V); + + EHStack.pushCleanup(NormalAndEHCleanup, + BaseClassDecl, + /*BaseIsVirtual*/ true); } + return; } assert(DtorType == Dtor_Base); + + // Destroy non-virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = + ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) { + const CXXBaseSpecifier &Base = *I; + + // Ignore virtual bases. + if (Base.isVirtual()) + continue; + + CXXRecordDecl *BaseClassDecl = Base.getType()->getAsCXXRecordDecl(); + + // Ignore trivial destructors. + if (BaseClassDecl->hasTrivialDestructor()) + continue; + + EHStack.pushCleanup(NormalAndEHCleanup, + BaseClassDecl, + /*BaseIsVirtual*/ false); + } - // Collect the fields. + // Destroy direct fields. llvm::SmallVector FieldDecls; for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(), E = ClassDecl->field_end(); I != E; ++I) { const FieldDecl *Field = *I; QualType FieldType = getContext().getCanonicalType(Field->getType()); - FieldType = getContext().getBaseElementType(FieldType); + const ConstantArrayType *Array = + getContext().getAsConstantArrayType(FieldType); + if (Array) + FieldType = getContext().getBaseElementType(Array->getElementType()); const RecordType *RT = FieldType->getAs(); if (!RT) @@ -806,64 +908,11 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, CXXRecordDecl *FieldClassDecl = cast(RT->getDecl()); if (FieldClassDecl->hasTrivialDestructor()) continue; - - FieldDecls.push_back(Field); - } - - // Now destroy the fields. - for (size_t i = FieldDecls.size(); i > 0; --i) { - const FieldDecl *Field = FieldDecls[i - 1]; - - QualType FieldType = Field->getType(); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = getContext().getBaseElementType(FieldType); - - const RecordType *RT = FieldType->getAs(); - CXXRecordDecl *FieldClassDecl = cast(RT->getDecl()); - llvm::Value *ThisPtr = LoadCXXThis(); - - LValue LHS = EmitLValueForField(ThisPtr, Field, - // FIXME: Qualifiers? - /*CVRQualifiers=*/0); - if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(LHS.getAddress(), BasePtr); - EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(), - Array, BaseAddrPtr); - } else - EmitCXXDestructorCall(FieldClassDecl->getDestructor(), - Dtor_Complete, /*ForVirtualBase=*/false, - LHS.getAddress()); - } - - // Destroy non-virtual bases. - for (CXXRecordDecl::reverse_base_class_const_iterator I = - ClassDecl->bases_rbegin(), E = ClassDecl->bases_rend(); I != E; ++I) { - const CXXBaseSpecifier &Base = *I; - - // Ignore virtual bases. - if (Base.isVirtual()) - continue; - - CXXRecordDecl *BaseClassDecl - = cast(Base.getType()->getAs()->getDecl()); - - // Ignore trivial destructors. - if (BaseClassDecl->hasTrivialDestructor()) - continue; - - const CXXDestructorDecl *D = BaseClassDecl->getDestructor(); - llvm::Value *V = - GetAddressOfDirectBaseInCompleteClass(LoadCXXThis(), ClassDecl, - BaseClassDecl, - /*BaseIsVirtual=*/false); - - EmitCXXDestructorCall(D, Dtor_Base, /*ForVirtualBase=*/false, V); + if (Array) + EHStack.pushCleanup(NormalAndEHCleanup, Field); + else + EHStack.pushCleanup(NormalAndEHCleanup, Field); } } @@ -873,19 +922,24 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD, /// 'D' is the default constructor for elements of the array, 'ArrayTy' is the /// array type and 'ArrayPtr' points to the beginning fo the array. /// It is assumed that all relevant checks have been made by the caller. +/// +/// \param ZeroInitialization True if each element should be zero-initialized +/// before it is constructed. void CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, - const ConstantArrayType *ArrayTy, - llvm::Value *ArrayPtr, - CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd) { + const ConstantArrayType *ArrayTy, + llvm::Value *ArrayPtr, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd, + bool ZeroInitialization) { const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); llvm::Value * NumElements = llvm::ConstantInt::get(SizeTy, getContext().getConstantArrayElementCount(ArrayTy)); - EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd); + EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd, + ZeroInitialization); } void @@ -893,7 +947,8 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, llvm::Value *NumElements, llvm::Value *ArrayPtr, CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd) { + CallExpr::const_arg_iterator ArgEnd, + bool ZeroInitialization) { const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); // Create a temporary for the loop index and initialize it with 0. @@ -924,6 +979,11 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter, "arrayidx"); + // Zero initialize the storage, if requested. + if (ZeroInitialization) + EmitNullInitialization(Address, + getContext().getTypeDeclType(D->getParent())); + // C++ [class.temporary]p4: // There are two contexts in which temporaries are destroyed at a different // point than the end of the full-expression. The first context is when a @@ -1109,21 +1169,33 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0); } +namespace { + struct CallLocalDtor : EHScopeStack::Cleanup { + const CXXDestructorDecl *Dtor; + llvm::Value *Addr; + + CallLocalDtor(const CXXDestructorDecl *D, llvm::Value *Addr) + : Dtor(D), Addr(Addr) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, + /*ForVirtualBase=*/false, Addr); + } + }; +} + +void CodeGenFunction::PushDestructorCleanup(const CXXDestructorDecl *D, + llvm::Value *Addr) { + EHStack.pushCleanup(NormalAndEHCleanup, D, Addr); +} + void CodeGenFunction::PushDestructorCleanup(QualType T, llvm::Value *Addr) { CXXRecordDecl *ClassDecl = T->getAsCXXRecordDecl(); if (!ClassDecl) return; if (ClassDecl->hasTrivialDestructor()) return; const CXXDestructorDecl *D = ClassDecl->getDestructor(); - - CleanupBlock Scope(*this, NormalCleanup); - - EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, Addr); - - if (Exceptions) { - Scope.beginEHCleanup(); - EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, Addr); - } + PushDestructorCleanup(D, Addr); } llvm::Value * diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 4e15895..406db88 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -15,7 +15,9 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/SourceManager.h" @@ -37,7 +39,7 @@ using namespace clang::CodeGen; CGDebugInfo::CGDebugInfo(CodeGenModule &CGM) : CGM(CGM), DebugFactory(CGM.getModule()), - FwdDeclCount(0), BlockLiteralGenericSet(false) { + BlockLiteralGenericSet(false) { CreateCompileUnit(); } @@ -93,6 +95,58 @@ llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) { return llvm::StringRef(StrPtr, NS.length()); } +llvm::StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) { + llvm::SmallString<256> MethodName; + llvm::raw_svector_ostream OS(MethodName); + OS << (OMD->isInstanceMethod() ? '-' : '+') << '['; + const DeclContext *DC = OMD->getDeclContext(); + if (const ObjCImplementationDecl *OID = dyn_cast(DC)) { + OS << OID->getName(); + } else if (const ObjCCategoryImplDecl *OCD = dyn_cast(DC)){ + OS << ((NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' << + OCD->getIdentifier()->getNameStart() << ')'; + } + OS << ' ' << OMD->getSelector().getAsString() << ']'; + + char *StrPtr = DebugInfoNames.Allocate(OS.tell()); + memcpy(StrPtr, MethodName.begin(), OS.tell()); + return llvm::StringRef(StrPtr, OS.tell()); +} + +/// getClassName - Get class name including template argument list. +llvm::StringRef +CGDebugInfo::getClassName(RecordDecl *RD) { + ClassTemplateSpecializationDecl *Spec + = dyn_cast(RD); + if (!Spec) + return RD->getName(); + + const TemplateArgument *Args; + unsigned NumArgs; + std::string Buffer; + if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) { + const TemplateSpecializationType *TST = + cast(TAW->getType()); + Args = TST->getArgs(); + NumArgs = TST->getNumArgs(); + } else { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + Args = TemplateArgs.getFlatArgumentList(); + NumArgs = TemplateArgs.flat_size(); + } + Buffer = RD->getIdentifier()->getNameStart(); + PrintingPolicy Policy(CGM.getLangOptions()); + Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args, + NumArgs, + Policy); + + // Copy this name on the side and use its reference. + char *StrPtr = DebugInfoNames.Allocate(Buffer.length()); + memcpy(StrPtr, Buffer.data(), Buffer.length()); + return llvm::StringRef(StrPtr, Buffer.length()); + +} + /// getOrCreateFile - Get the file debug info descriptor for the input location. llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) { if (!Loc.isValid()) @@ -113,13 +167,8 @@ llvm::DIFile CGDebugInfo::getOrCreateFile(SourceLocation Loc) { return llvm::DIFile(cast(it->second)); } - // FIXME: We shouldn't even need to call 'makeAbsolute()' in the cases - // where we can consult the FileEntry. - llvm::sys::Path AbsFileName(PLoc.getFilename()); - AbsFileName.makeAbsolute(); - - llvm::DIFile F = DebugFactory.CreateFile(AbsFileName.getLast(), - AbsFileName.getDirname(), TheCU); + llvm::DIFile F = DebugFactory.CreateFile(PLoc.getFilename(), + getCurrentDirname(), TheCU); DIFileCache[fname] = F; return F; @@ -144,6 +193,16 @@ unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) { return PLoc.getColumn(); } +llvm::StringRef CGDebugInfo::getCurrentDirname() { + if (!CWDName.empty()) + return CWDName; + char *CompDirnamePtr = NULL; + llvm::sys::Path CWD = llvm::sys::Path::GetCurrentDirectory(); + CompDirnamePtr = DebugInfoNames.Allocate(CWD.size()); + memcpy(CompDirnamePtr, CWD.c_str(), CWD.size()); + return CWDName = llvm::StringRef(CompDirnamePtr, CWD.size()); +} + /// CreateCompileUnit - Create new compile unit. void CGDebugInfo::CreateCompileUnit() { @@ -153,19 +212,22 @@ void CGDebugInfo::CreateCompileUnit() { if (MainFileName.empty()) MainFileName = ""; - llvm::sys::Path AbsFileName(MainFileName); - AbsFileName.makeAbsolute(); - // The main file name provided via the "-main-file-name" option contains just // the file name itself with no path information. This file name may have had // a relative path, so we look into the actual file entry for the main // file to determine the real absolute path for the file. std::string MainFileDir; - if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) + if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { MainFileDir = MainFile->getDir()->getName(); - else - MainFileDir = AbsFileName.getDirname(); + if (MainFileDir != ".") + MainFileName = MainFileDir + "/" + MainFileName; + } + // Save filename string. + char *FilenamePtr = DebugInfoNames.Allocate(MainFileName.length()); + memcpy(FilenamePtr, MainFileName.c_str(), MainFileName.length()); + llvm::StringRef Filename(FilenamePtr, MainFileName.length()); + unsigned LangTag; const LangOptions &LO = CGM.getLangOptions(); if (LO.CPlusPlus) { @@ -181,11 +243,7 @@ void CGDebugInfo::CreateCompileUnit() { LangTag = llvm::dwarf::DW_LANG_C89; } - const char *Producer = -#ifdef CLANG_VENDOR - CLANG_VENDOR -#endif - "clang " CLANG_VERSION_STRING; + std::string Producer = getClangFullVersion(); // Figure out which version of the ObjC runtime we have. unsigned RuntimeVers = 0; @@ -194,7 +252,8 @@ void CGDebugInfo::CreateCompileUnit() { // Create new compile unit. TheCU = DebugFactory.CreateCompileUnit( - LangTag, AbsFileName.getLast(), MainFileDir, Producer, true, + LangTag, Filename, getCurrentDirname(), + Producer, true, LO.Optimize, CGM.getCodeGenOpts().DwarfDebugFlags, RuntimeVers); } @@ -203,10 +262,49 @@ void CGDebugInfo::CreateCompileUnit() { llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT, llvm::DIFile Unit) { unsigned Encoding = 0; + const char *BTName = NULL; switch (BT->getKind()) { default: case BuiltinType::Void: return llvm::DIType(); + case BuiltinType::ObjCClass: + return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_structure_type, + Unit, "objc_class", Unit, 0, 0, 0, 0, + llvm::DIType::FlagFwdDecl, + llvm::DIType(), llvm::DIArray()); + case BuiltinType::ObjCId: { + // typedef struct objc_class *Class; + // typedef struct objc_object { + // Class isa; + // } *id; + + llvm::DIType OCTy = + DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_structure_type, + Unit, "objc_class", Unit, 0, 0, 0, 0, + llvm::DIType::FlagFwdDecl, + llvm::DIType(), llvm::DIArray()); + unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); + + llvm::DIType ISATy = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, + Unit, "", Unit, + 0, Size, 0, 0, 0, OCTy); + + llvm::SmallVector EltTys; + + llvm::DIType FieldTy = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit, + "isa", Unit, + 0,Size, 0, 0, 0, ISATy); + EltTys.push_back(FieldTy); + llvm::DIArray Elements = + DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size()); + + return DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_structure_type, + Unit, "objc_object", Unit, 0, 0, 0, 0, + 0, + llvm::DIType(), Elements); + } case BuiltinType::UChar: case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break; case BuiltinType::Char_S: @@ -224,14 +322,23 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT, case BuiltinType::LongDouble: case BuiltinType::Double: Encoding = llvm::dwarf::DW_ATE_float; break; } + + switch (BT->getKind()) { + case BuiltinType::Long: BTName = "long int"; break; + case BuiltinType::LongLong: BTName = "long long int"; break; + case BuiltinType::ULong: BTName = "long unsigned int"; break; + case BuiltinType::ULongLong: BTName = "long long unsigned int"; break; + default: + BTName = BT->getName(CGM.getContext().getLangOptions()); + break; + } // Bit size, align and offset of the type. uint64_t Size = CGM.getContext().getTypeSize(BT); uint64_t Align = CGM.getContext().getTypeAlign(BT); uint64_t Offset = 0; - + llvm::DIType DbgTy = - DebugFactory.CreateBasicType(Unit, - BT->getName(CGM.getContext().getLangOptions()), + DebugFactory.CreateBasicType(Unit, BTName, Unit, 0, Size, Align, Offset, /*flags*/ 0, Encoding); return DbgTy; @@ -461,7 +568,6 @@ CollectRecordFields(const RecordDecl *RD, llvm::DIFile Unit, I != E; ++I, ++FieldNo) { FieldDecl *Field = *I; llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit); - llvm::StringRef FieldName = Field->getName(); // Ignore unnamed fields. Do not ignore unnamed records. @@ -481,7 +587,6 @@ CollectRecordFields(const RecordDecl *RD, llvm::DIFile Unit, Expr *BitWidth = Field->getBitWidth(); if (BitWidth) FieldSize = BitWidth->EvaluateAsInt(CGM.getContext()).getZExtValue(); - FieldAlign = CGM.getContext().getTypeAlign(FType); } @@ -516,9 +621,12 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, 0), Unit); - // Static methods do not need "this" pointer argument. - if (Method->isStatic()) - return FnTy; + unsigned BFlags=0; + AccessSpecifier Access = Method->getAccess(); + if (Access == clang::AS_private) + BFlags |= llvm::DIType::FlagPrivate; + else if (Access == clang::AS_protected) + BFlags |= llvm::DIType::FlagProtected; // Add "this" pointer. @@ -530,27 +638,18 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, // First element is always return type. For 'void' functions it is NULL. Elts.push_back(Args.getElement(0)); - // "this" pointer is always first argument. - ASTContext &Context = CGM.getContext(); - QualType ThisPtr = - Context.getPointerType(Context.getTagDeclType(Method->getParent())); - llvm::DIType ThisPtrType = - DebugFactory.CreateArtificialType(getOrCreateType(ThisPtr, Unit)); - - unsigned Quals = Method->getTypeQualifiers(); - if (Quals & Qualifiers::Const) - ThisPtrType = - DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_const_type, - Unit, "", Unit, - 0, 0, 0, 0, 0, ThisPtrType); - if (Quals & Qualifiers::Volatile) - ThisPtrType = - DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_volatile_type, - Unit, "", Unit, - 0, 0, 0, 0, 0, ThisPtrType); - - TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType; - Elts.push_back(ThisPtrType); + if (!Method->isStatic()) + { + // "this" pointer is always first argument. + ASTContext &Context = CGM.getContext(); + QualType ThisPtr = + Context.getPointerType(Context.getTagDeclType(Method->getParent())); + llvm::DIType ThisPtrType = + DebugFactory.CreateArtificialType(getOrCreateType(ThisPtr, Unit)); + + TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType; + Elts.push_back(ThisPtrType); + } // Copy rest of the arguments. for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i) @@ -571,7 +670,7 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, llvm::DISubprogram CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, llvm::DIFile Unit, - llvm::DICompositeType &RecordTy) { + llvm::DIType RecordTy) { bool IsCtorOrDtor = isa(Method) || isa(Method); @@ -612,7 +711,9 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, MethodDefUnit, MethodLine, MethodTy, /*isLocalToUnit=*/false, /* isDefintion=*/ false, - Virtuality, VIndex, ContainingType); + Virtuality, VIndex, ContainingType, + Method->isImplicit(), + CGM.getLangOptions().Optimize); // Don't cache ctors or dtors since we have to emit multiple functions for // a single ctor or dtor. @@ -628,7 +729,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, void CGDebugInfo:: CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit, llvm::SmallVectorImpl &EltTys, - llvm::DICompositeType &RecordTy) { + llvm::DIType RecordTy) { for(CXXRecordDecl::method_iterator I = RD->method_begin(), E = RD->method_end(); I != E; ++I) { const CXXMethodDecl *Method = *I; @@ -640,13 +741,41 @@ CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit, } } +/// CollectCXXFriends - A helper function to collect debug info for +/// C++ base classes. This is used while creating debug info entry for +/// a Record. +void CGDebugInfo:: +CollectCXXFriends(const CXXRecordDecl *RD, llvm::DIFile Unit, + llvm::SmallVectorImpl &EltTys, + llvm::DIType RecordTy) { + + for (CXXRecordDecl::friend_iterator BI = RD->friend_begin(), + BE = RD->friend_end(); BI != BE; ++BI) { + + TypeSourceInfo *TInfo = (*BI)->getFriendType(); + if(TInfo) + { + llvm::DIType Ty = getOrCreateType(TInfo->getType(), Unit); + + llvm::DIType DTy = + DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_friend, + RecordTy, llvm::StringRef(), + Unit, 0, 0, 0, + 0, 0, Ty); + + EltTys.push_back(DTy); + } + + } +} + /// CollectCXXBases - A helper function to collect debug info for /// C++ base classes. This is used while creating debug info entry for /// a Record. void CGDebugInfo:: CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit, llvm::SmallVectorImpl &EltTys, - llvm::DICompositeType &RecordTy) { + llvm::DIType RecordTy) { const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); for (CXXRecordDecl::base_class_const_iterator BI = RD->bases_begin(), @@ -786,14 +915,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, return FwdDecl; } - // A RD->getName() is not unique. However, the debug info descriptors - // are uniqued so use type name to ensure uniquness. - llvm::SmallString<128> FwdDeclName; - llvm::raw_svector_ostream(FwdDeclName) << "fwd.type." << FwdDeclCount++; - llvm::DICompositeType FwdDecl = - DebugFactory.CreateCompositeType(Tag, FDContext, FwdDeclName, - DefUnit, Line, 0, 0, 0, 0, - llvm::DIType(), llvm::DIArray()); + llvm::DIType FwdDecl = DebugFactory.CreateTemporaryType(); llvm::MDNode *MN = FwdDecl; llvm::TrackingVH FwdDeclNode = MN; @@ -812,10 +934,36 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, CollectCXXBases(CXXDecl, Unit, EltTys, FwdDecl); CollectVTableInfo(CXXDecl, Unit, EltTys); } + + // Collect static variables with initializers. + for (RecordDecl::decl_iterator I = RD->decls_begin(), E = RD->decls_end(); + I != E; ++I) + if (const VarDecl *V = dyn_cast(*I)) { + if (const Expr *Init = V->getInit()) { + Expr::EvalResult Result; + if (Init->Evaluate(Result, CGM.getContext()) && Result.Val.isInt()) { + llvm::ConstantInt *CI + = llvm::ConstantInt::get(CGM.getLLVMContext(), Result.Val.getInt()); + + // Create the descriptor for static variable. + llvm::DIFile VUnit = getOrCreateFile(V->getLocation()); + llvm::StringRef VName = V->getName(); + llvm::DIType VTy = getOrCreateType(V->getType(), VUnit); + // Do not use DIGlobalVariable for enums. + if (VTy.getTag() != llvm::dwarf::DW_TAG_enumeration_type) { + DebugFactory.CreateGlobalVariable(FwdDecl, VName, VName, VName, VUnit, + getLineNumber(V->getLocation()), + VTy, true, true, CI); + } + } + } + } + CollectRecordFields(RD, Unit, EltTys); llvm::MDNode *ContainingType = NULL; if (CXXDecl) { CollectCXXMemberFunctions(CXXDecl, Unit, EltTys, FwdDecl); + CollectCXXFriends(CXXDecl, Unit, EltTys, FwdDecl); // A class's primary base or the class itself contains the vtable. const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); @@ -841,16 +989,22 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, llvm::DIDescriptor RDContext = getContextDescriptor(dyn_cast(RD->getDeclContext()), Unit); + + llvm::StringRef RDName = RD->getName(); + // If this is a class, include the template arguments also. + if (Tag == llvm::dwarf::DW_TAG_class_type) + RDName = getClassName(RD); + llvm::DICompositeType RealDecl = DebugFactory.CreateCompositeType(Tag, RDContext, - RD->getName(), + RDName, DefUnit, Line, Size, Align, 0, 0, llvm::DIType(), Elements, 0, ContainingType); // Now that we have a real decl for the struct, replace anything using the // old decl with the new one. This will recursively update the debug info. - llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl); + llvm::DIType(FwdDeclNode).replaceAllUsesWith(RealDecl); RegionMap[RD] = llvm::WeakVH(RealDecl); return RealDecl; } @@ -873,21 +1027,24 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, unsigned Line = getLineNumber(ID->getLocation()); unsigned RuntimeLang = TheCU.getLanguage(); + // If this is just a forward declaration, return a special forward-declaration + // debug type. + if (ID->isForwardDecl()) { + llvm::DICompositeType FwdDecl = + DebugFactory.CreateCompositeType(Tag, Unit, ID->getName(), + DefUnit, Line, 0, 0, 0, 0, + llvm::DIType(), llvm::DIArray(), + RuntimeLang); + return FwdDecl; + } + // To handle recursive interface, we // first generate a debug descriptor for the struct as a forward declaration. // Then (if it is a definition) we go through and get debug info for all of // its members. Finally, we create a descriptor for the complete type (which // may refer to the forward decl if the struct is recursive) and replace all // uses of the forward declaration with the final definition. - llvm::DICompositeType FwdDecl = - DebugFactory.CreateCompositeType(Tag, Unit, ID->getName(), - DefUnit, Line, 0, 0, 0, 0, - llvm::DIType(), llvm::DIArray(), - RuntimeLang); - - // If this is just a forward declaration, return it. - if (ID->isForwardDecl()) - return FwdDecl; + llvm::DIType FwdDecl = DebugFactory.CreateTemporaryType(); llvm::MDNode *MN = FwdDecl; llvm::TrackingVH FwdDeclNode = MN; @@ -982,7 +1139,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, // Now that we have a real decl for the struct, replace anything using the // old decl with the new one. This will recursively update the debug info. - llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl); + llvm::DIType(FwdDeclNode).replaceAllUsesWith(RealDecl); RegionMap[ID] = llvm::WeakVH(RealDecl); return RealDecl; @@ -990,39 +1147,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty, llvm::DIFile Unit) { - EnumDecl *ED = Ty->getDecl(); - - llvm::SmallVector Enumerators; - - // Create DIEnumerator elements for each enumerator. - for (EnumDecl::enumerator_iterator - Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end(); - Enum != EnumEnd; ++Enum) { - Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getName(), - Enum->getInitVal().getZExtValue())); - } + return CreateEnumType(Ty->getDecl(), Unit); - // Return a CompositeType for the enum itself. - llvm::DIArray EltArray = - DebugFactory.GetOrCreateArray(Enumerators.data(), Enumerators.size()); - - llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation()); - unsigned Line = getLineNumber(ED->getLocation()); - - // Size and align of the type. - uint64_t Size = 0; - unsigned Align = 0; - if (!Ty->isIncompleteType()) { - Size = CGM.getContext().getTypeSize(Ty); - Align = CGM.getContext().getTypeAlign(Ty); - } - - llvm::DIType DbgTy = - DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type, - Unit, ED->getName(), DefUnit, Line, - Size, Align, 0, 0, - llvm::DIType(), EltArray); - return DbgTy; } llvm::DIType CGDebugInfo::CreateType(const TagType *Ty, @@ -1036,7 +1162,7 @@ llvm::DIType CGDebugInfo::CreateType(const TagType *Ty, } llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, - llvm::DIFile Unit) { + llvm::DIFile Unit) { llvm::DIType ElementTy = getOrCreateType(Ty->getElementType(), Unit); uint64_t NumElems = Ty->getNumElements(); if (NumElems > 0) @@ -1052,7 +1178,7 @@ llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_vector_type, Unit, "", Unit, 0, Size, Align, 0, 0, - ElementTy, SubscriptArray); + ElementTy, SubscriptArray); } llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, @@ -1149,6 +1275,38 @@ llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty, 0, 0, 0, llvm::DIType(), Elements); } +/// CreateEnumType - get enumeration type. +llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED, llvm::DIFile Unit){ + llvm::SmallVector Enumerators; + + // Create DIEnumerator elements for each enumerator. + for (EnumDecl::enumerator_iterator + Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end(); + Enum != EnumEnd; ++Enum) { + Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getName(), + Enum->getInitVal().getZExtValue())); + } + + // Return a CompositeType for the enum itself. + llvm::DIArray EltArray = + DebugFactory.GetOrCreateArray(Enumerators.data(), Enumerators.size()); + + llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation()); + unsigned Line = getLineNumber(ED->getLocation()); + uint64_t Size = 0; + uint64_t Align = 0; + if (!ED->getTypeForDecl()->isIncompleteType()) { + Size = CGM.getContext().getTypeSize(ED->getTypeForDecl()); + Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl()); + } + llvm::DIType DbgTy = + DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type, + Unit, ED->getName(), DefUnit, Line, + Size, Align, 0, 0, + llvm::DIType(), EltArray); + return DbgTy; +} + static QualType UnwrapTypeForDebugInfo(QualType T) { do { QualType LastT = T; @@ -1312,6 +1470,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, llvm::StringRef Name; llvm::StringRef LinkageName; + FnBeginRegionCount.push_back(RegionStack.size()); + const Decl *D = GD.getDecl(); if (const FunctionDecl *FD = dyn_cast(D)) { // If there is a DISubprogram for this function available then use it. @@ -1329,6 +1489,9 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, Name = getFunctionName(FD); // Use mangled name as linkage name for c/c++ functions. LinkageName = CGM.getMangledName(GD); + } else if (const ObjCMethodDecl *OMD = dyn_cast(D)) { + Name = getObjCMethodName(OMD); + LinkageName = Name; } else { // Use llvm function name as linkage name. Name = Fn->getName(); @@ -1346,16 +1509,22 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, llvm::DISubprogram SP = DebugFactory.CreateSubprogram(Unit, Name, Name, LinkageName, Unit, LineNo, getOrCreateType(FnType, Unit), - Fn->hasInternalLinkage(), true/*definition*/); + Fn->hasInternalLinkage(), true/*definition*/, + 0, 0, llvm::DIType(), + D->isImplicit(), + CGM.getLangOptions().Optimize, Fn); // Push function on region stack. llvm::MDNode *SPN = SP; RegionStack.push_back(SPN); RegionMap[D] = llvm::WeakVH(SP); + + // Clear stack used to keep track of #line directives. + LineDirectiveFiles.clear(); } -void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) { +void CGDebugInfo::EmitStopPoint(CGBuilderTy &Builder) { if (CurLoc.isInvalid() || CurLoc.isMacroID()) return; // Don't bother if things are the same as last time. @@ -1377,13 +1546,63 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) { Scope)); } +/// UpdateLineDirectiveRegion - Update region stack only if #line directive +/// has introduced scope change. +void CGDebugInfo::UpdateLineDirectiveRegion(CGBuilderTy &Builder) { + if (CurLoc.isInvalid() || CurLoc.isMacroID() || + PrevLoc.isInvalid() || PrevLoc.isMacroID()) + return; + SourceManager &SM = CGM.getContext().getSourceManager(); + PresumedLoc PCLoc = SM.getPresumedLoc(CurLoc); + PresumedLoc PPLoc = SM.getPresumedLoc(PrevLoc); + + if (!strcmp(PPLoc.getFilename(), PCLoc.getFilename())) + return; + + // If #line directive stack is empty then we are entering a new scope. + if (LineDirectiveFiles.empty()) { + EmitRegionStart(Builder); + LineDirectiveFiles.push_back(PCLoc.getFilename()); + return; + } + + assert (RegionStack.size() >= LineDirectiveFiles.size() + && "error handling #line regions!"); + + bool SeenThisFile = false; + for(std::vector::iterator I = LineDirectiveFiles.begin(), + E = LineDirectiveFiles.end(); I != E; ++I) + if (!strcmp(PPLoc.getFilename(), *I)) { + SeenThisFile = true; + break; + } + + // If #line for this file is seen earlier then pop out #line regions. + if (SeenThisFile) { + while (!LineDirectiveFiles.empty()) { + const char *LastFile = LineDirectiveFiles.back(); + RegionStack.pop_back(); + LineDirectiveFiles.pop_back(); + if (!strcmp(PPLoc.getFilename(), LastFile)) + break; + } + return; + } + + // .. otherwise insert new #line region. + EmitRegionStart(Builder); + LineDirectiveFiles.push_back(PCLoc.getFilename()); + + return; +} /// EmitRegionStart- Constructs the debug code for entering a declarative /// region - "llvm.dbg.region.start.". -void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder) { +void CGDebugInfo::EmitRegionStart(CGBuilderTy &Builder) { llvm::DIDescriptor D = DebugFactory.CreateLexicalBlock(RegionStack.empty() ? llvm::DIDescriptor() : llvm::DIDescriptor(RegionStack.back()), + getOrCreateFile(CurLoc), getLineNumber(CurLoc), getColumnNumber(CurLoc)); llvm::MDNode *DN = D; @@ -1392,15 +1611,27 @@ void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder) { /// EmitRegionEnd - Constructs the debug code for exiting a declarative /// region - "llvm.dbg.region.end." -void CGDebugInfo::EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder) { +void CGDebugInfo::EmitRegionEnd(CGBuilderTy &Builder) { assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); // Provide an region stop point. - EmitStopPoint(Fn, Builder); + EmitStopPoint(Builder); RegionStack.pop_back(); } +/// EmitFunctionEnd - Constructs the debug code for exiting a function. +void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) { + assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); + unsigned RCount = FnBeginRegionCount.back(); + assert(RCount <= RegionStack.size() && "Region stack mismatch"); + + // Pop all regions for this function. + while (RegionStack.size() != RCount) + EmitRegionEnd(Builder); + FnBeginRegionCount.pop_back(); +} + // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. // See BuildByRefType. llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, @@ -1643,6 +1874,26 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, true/*definition*/, Var); } +/// EmitGlobalVariable - Emit global variable's debug info. +void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, + llvm::ConstantInt *Init, + CGBuilderTy &Builder) { + // Create the descriptor for the variable. + llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); + llvm::StringRef Name = VD->getName(); + llvm::DIType Ty = getOrCreateType(VD->getType(), Unit); + if (const EnumConstantDecl *ECD = dyn_cast(VD)) { + if (const EnumDecl *ED = dyn_cast(ECD->getDeclContext())) + Ty = CreateEnumType(ED, Unit); + } + // Do not use DIGlobalVariable for enums. + if (Ty.getTag() == llvm::dwarf::DW_TAG_enumeration_type) + return; + DebugFactory.CreateGlobalVariable(Unit, Name, Name, Name, Unit, + getLineNumber(VD->getLocation()), + Ty, true, true, Init); +} + /// getOrCreateNamesSpace - Return namespace descriptor for the given /// namespace decl. llvm::DINameSpace @@ -1659,7 +1910,7 @@ CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl, getContextDescriptor(dyn_cast(NSDecl->getDeclContext()), Unit); llvm::DINameSpace NS = DebugFactory.CreateNameSpace(Context, NSDecl->getName(), - llvm::DIFile(Unit), LineNo); + llvm::DIFile(Unit), LineNo); NameSpaceCache[NSDecl] = llvm::WeakVH(NS); return NS; } diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 620a5f2..a1ad012 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -46,9 +46,6 @@ class CGDebugInfo { llvm::DICompileUnit TheCU; SourceLocation CurLoc, PrevLoc; llvm::DIType VTablePtrType; - /// FwdDeclCount - This counter is used to ensure unique names for forward - /// record decls. - unsigned FwdDeclCount; /// TypeCache - Cache of previously constructed Types. llvm::DenseMap TypeCache; @@ -58,10 +55,19 @@ class CGDebugInfo { std::vector > RegionStack; llvm::DenseMap RegionMap; + // FnBeginRegionCount - Keep track of RegionStack counter at the beginning + // of a function. This is used to pop unbalanced regions at the end of a + // function. + std::vector FnBeginRegionCount; + + /// LineDirectiveFiles - This stack is used to keep track of + /// scopes introduced by #line directives. + std::vector LineDirectiveFiles; /// DebugInfoNames - This is a storage for names that are /// constructed on demand. For example, C++ destructors, C++ operators etc.. llvm::BumpPtrAllocator DebugInfoNames; + llvm::StringRef CWDName; llvm::DenseMap DIFileCache; llvm::DenseMap SPCache; @@ -86,6 +92,7 @@ class CGDebugInfo { llvm::DIType CreateType(const ArrayType *Ty, llvm::DIFile F); llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DIFile F); llvm::DIType CreateType(const MemberPointerType *Ty, llvm::DIFile F); + llvm::DIType CreateEnumType(const EnumDecl *ED, llvm::DIFile Unit); llvm::DIType getOrCreateMethodType(const CXXMethodDecl *Method, llvm::DIFile F); llvm::DIType getOrCreateVTablePtrType(llvm::DIFile F); @@ -98,16 +105,22 @@ class CGDebugInfo { llvm::DISubprogram CreateCXXMemberFunction(const CXXMethodDecl *Method, llvm::DIFile F, - llvm::DICompositeType &RecordTy); + llvm::DIType RecordTy); void CollectCXXMemberFunctions(const CXXRecordDecl *Decl, llvm::DIFile F, llvm::SmallVectorImpl &E, - llvm::DICompositeType &T); + llvm::DIType T); + + void CollectCXXFriends(const CXXRecordDecl *Decl, + llvm::DIFile F, + llvm::SmallVectorImpl &EltTys, + llvm::DIType RecordTy); + void CollectCXXBases(const CXXRecordDecl *Decl, llvm::DIFile F, llvm::SmallVectorImpl &EltTys, - llvm::DICompositeType &RecordTy); + llvm::DIType RecordTy); void CollectRecordFields(const RecordDecl *Decl, llvm::DIFile F, @@ -127,20 +140,27 @@ public: /// EmitStopPoint - Emit a call to llvm.dbg.stoppoint to indicate a change of /// source line. - void EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder); + void EmitStopPoint(CGBuilderTy &Builder); /// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate /// start of a new function. void EmitFunctionStart(GlobalDecl GD, QualType FnType, llvm::Function *Fn, CGBuilderTy &Builder); + /// EmitFunctionEnd - Constructs the debug code for exiting a function. + void EmitFunctionEnd(CGBuilderTy &Builder); + + /// UpdateLineDirectiveRegion - Update region stack only if #line directive + /// has introduced scope change. + void UpdateLineDirectiveRegion(CGBuilderTy &Builder); + /// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start /// of a new block. - void EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder); + void EmitRegionStart(CGBuilderTy &Builder); /// EmitRegionEnd - Emit call to llvm.dbg.region.end to indicate end of a /// block. - void EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder); + void EmitRegionEnd(CGBuilderTy &Builder); /// EmitDeclareOfAutoVariable - Emit call to llvm.dbg.declare for an automatic /// variable declaration. @@ -165,6 +185,10 @@ public: /// EmitGlobalVariable - Emit information about an objective-c interface. void EmitGlobalVariable(llvm::GlobalVariable *GV, ObjCInterfaceDecl *Decl); + /// EmitGlobalVariable - Emit global variable's debug info. + void EmitGlobalVariable(const ValueDecl *VD, llvm::ConstantInt *Init, + CGBuilderTy &Builder); + private: /// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration. void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI, @@ -183,6 +207,9 @@ private: llvm::DIDescriptor getContextDescriptor(const Decl *Decl, llvm::DIDescriptor &CU); + /// getCurrentDirname - Return current directory name. + llvm::StringRef getCurrentDirname(); + /// CreateCompileUnit - Create new compile unit. void CreateCompileUnit(); @@ -205,6 +232,12 @@ private: /// name is constructred on demand (e.g. C++ destructor) then the name /// is stored on the side. llvm::StringRef getFunctionName(const FunctionDecl *FD); + /// getObjCMethodName - Returns the unmangled name of an Objective-C method. + /// This is the display name for the debugging info. + llvm::StringRef getObjCMethodName(const ObjCMethodDecl *FD); + + /// getClassName - Get class name including template argument list. + llvm::StringRef getClassName(RecordDecl *RD); /// getVTableName - Get vtable name for the given Class. llvm::StringRef getVTableName(const CXXRecordDecl *Decl); diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 1a62ea9..57e5236 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -107,11 +107,11 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) { CGM.ErrorUnsupported(&D, "__asm__"); switch (D.getStorageClass()) { - case VarDecl::None: - case VarDecl::Auto: - case VarDecl::Register: + case SC_None: + case SC_Auto: + case SC_Register: return EmitLocalBlockVarDecl(D); - case VarDecl::Static: { + case SC_Static: { llvm::GlobalValue::LinkageTypes Linkage = llvm::GlobalValue::InternalLinkage; @@ -126,8 +126,8 @@ void CodeGenFunction::EmitBlockVarDecl(const VarDecl &D) { return EmitStaticBlockVarDecl(D, Linkage); } - case VarDecl::Extern: - case VarDecl::PrivateExtern: + case SC_Extern: + case SC_PrivateExtern: // Don't emit it now, allow it to be emitted lazily on its first use. return; } @@ -183,7 +183,7 @@ llvm::GlobalVariable * CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D, llvm::GlobalVariable *GV) { llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), D.getType(), this); - + // If constant emission failed, then this should be a C++ static // initializer. if (!Init) { @@ -198,12 +198,12 @@ CodeGenFunction::AddInitializerToGlobalBlockVarDecl(const VarDecl &D, } return GV; } - + // The initializer may differ in type from the global. Rewrite // the global to match the initializer. (We have to do this // because some types, like unions, can't be completely represented // in the LLVM type system.) - if (GV->getType() != Init->getType()) { + if (GV->getType()->getElementType() != Init->getType()) { llvm::GlobalVariable *OldGV = GV; GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), @@ -373,7 +373,7 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) { } // T x; - Types.push_back(ConvertType(Ty)); + Types.push_back(ConvertTypeForMem(Ty)); const llvm::Type *T = llvm::StructType::get(VMContext, Types, Packed); @@ -389,7 +389,7 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) { } namespace { - struct CallArrayDtor : EHScopeStack::LazyCleanup { + struct CallArrayDtor : EHScopeStack::Cleanup { CallArrayDtor(const CXXDestructorDecl *Dtor, const ConstantArrayType *Type, llvm::Value *Loc) @@ -408,7 +408,7 @@ namespace { } }; - struct CallVarDtor : EHScopeStack::LazyCleanup { + struct CallVarDtor : EHScopeStack::Cleanup { CallVarDtor(const CXXDestructorDecl *Dtor, llvm::Value *NRVOFlag, llvm::Value *Loc) @@ -440,12 +440,64 @@ namespace { }; } +namespace { + struct CallStackRestore : EHScopeStack::Cleanup { + llvm::Value *Stack; + CallStackRestore(llvm::Value *Stack) : Stack(Stack) {} + void Emit(CodeGenFunction &CGF, bool IsForEH) { + llvm::Value *V = CGF.Builder.CreateLoad(Stack, "tmp"); + llvm::Value *F = CGF.CGM.getIntrinsic(llvm::Intrinsic::stackrestore); + CGF.Builder.CreateCall(F, V); + } + }; + + struct CallCleanupFunction : EHScopeStack::Cleanup { + llvm::Constant *CleanupFn; + const CGFunctionInfo &FnInfo; + llvm::Value *Addr; + const VarDecl &Var; + + CallCleanupFunction(llvm::Constant *CleanupFn, const CGFunctionInfo *Info, + llvm::Value *Addr, const VarDecl *Var) + : CleanupFn(CleanupFn), FnInfo(*Info), Addr(Addr), Var(*Var) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + // In some cases, the type of the function argument will be different from + // the type of the pointer. An example of this is + // void f(void* arg); + // __attribute__((cleanup(f))) void *g; + // + // To fix this we insert a bitcast here. + QualType ArgTy = FnInfo.arg_begin()->type; + llvm::Value *Arg = + CGF.Builder.CreateBitCast(Addr, CGF.ConvertType(ArgTy)); + + CallArgList Args; + Args.push_back(std::make_pair(RValue::get(Arg), + CGF.getContext().getPointerType(Var.getType()))); + CGF.EmitCall(FnInfo, CleanupFn, ReturnValueSlot(), Args); + } + }; + + struct CallBlockRelease : EHScopeStack::Cleanup { + llvm::Value *Addr; + CallBlockRelease(llvm::Value *Addr) : Addr(Addr) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + llvm::Value *V = CGF.Builder.CreateStructGEP(Addr, 1, "forwarding"); + V = CGF.Builder.CreateLoad(V); + CGF.BuildBlockRelease(V); + } + }; +} + /// EmitLocalBlockVarDecl - Emit code and set up an entry in LocalDeclMap for a /// variable declaration with auto, register, or no storage class specifier. /// These turn into simple stack objects, or GlobalValues depending on target. void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D, SpecialInitFn *SpecialInit) { QualType Ty = D.getType(); + unsigned Alignment = getContext().getDeclAlign(&D).getQuantity(); bool isByRef = D.hasAttr(); bool needsDispose = false; CharUnits Align = CharUnits::Zero(); @@ -461,10 +513,10 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D, // If this value is an array or struct, is POD, and if the initializer is // a staticly determinable constant, try to optimize it (unless the NRVO // is already optimizing this). - if (D.getInit() && !isByRef && + if (!NRVO && D.getInit() && !isByRef && (Ty->isArrayType() || Ty->isRecordType()) && Ty->isPODType() && - D.getInit()->isConstantInitializer(getContext()) && !NRVO) { + D.getInit()->isConstantInitializer(getContext(), false)) { // If this variable is marked 'const', emit the value as a global. if (CGM.getCodeGenOpts().MergeAllConstants && Ty.isConstant(getContext())) { @@ -516,7 +568,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D, } else { // Targets that don't support recursion emit locals as globals. const char *Class = - D.getStorageClass() == VarDecl::Register ? ".reg." : ".auto."; + D.getStorageClass() == SC_Register ? ".reg." : ".auto."; DeclPtr = CreateStaticBlockVarDecl(D, Class, llvm::GlobalValue ::InternalLinkage); @@ -540,20 +592,14 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D, DidCallStackSave = true; - { - // Push a cleanup block and restore the stack there. - CleanupBlock scope(*this, NormalCleanup); - - V = Builder.CreateLoad(Stack, "tmp"); - llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stackrestore); - Builder.CreateCall(F, V); - } + // Push a cleanup block and restore the stack there. + EHStack.pushCleanup(NormalCleanup, Stack); } // Get the element type. const llvm::Type *LElemTy = ConvertTypeForMem(Ty); const llvm::Type *LElemPtrTy = - llvm::PointerType::get(LElemTy, D.getType().getAddressSpace()); + llvm::PointerType::get(LElemTy, Ty.getAddressSpace()); llvm::Value *VLASize = EmitVLASize(Ty); @@ -658,13 +704,12 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D, Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D), D.getNameAsString()); - bool isVolatile = - getContext().getCanonicalType(D.getType()).isVolatileQualified(); + bool isVolatile = getContext().getCanonicalType(Ty).isVolatileQualified(); // If the initializer was a simple constant initializer, we can optimize it // in various ways. if (IsSimpleConstantInitializer) { - llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(),D.getType(),this); + llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), Ty,this); assert(Init != 0 && "Wasn't a simple constant init?"); llvm::Value *AlignVal = @@ -708,10 +753,10 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D, } } else if (Ty->isReferenceType()) { RValue RV = EmitReferenceBindingToExpr(Init, &D); - EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Ty); + EmitStoreOfScalar(RV.getScalarVal(), Loc, false, Alignment, Ty); } else if (!hasAggregateLLVMType(Init->getType())) { llvm::Value *V = EmitScalarExpr(Init); - EmitStoreOfScalar(V, Loc, isVolatile, D.getType()); + EmitStoreOfScalar(V, Loc, isVolatile, Alignment, Ty); } else if (Init->getType()->isAnyComplexType()) { EmitComplexExprIntoAddr(Init, Loc, isVolatile); } else { @@ -738,11 +783,11 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D, if (const ConstantArrayType *Array = getContext().getAsConstantArrayType(Ty)) { - EHStack.pushLazyCleanup(NormalAndEHCleanup, - D, Array, Loc); + EHStack.pushCleanup(NormalAndEHCleanup, + D, Array, Loc); } else { - EHStack.pushLazyCleanup(NormalAndEHCleanup, - D, NRVOFlag, Loc); + EHStack.pushCleanup(NormalAndEHCleanup, + D, NRVOFlag, Loc); } } } @@ -755,52 +800,14 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D, assert(F && "Could not find function!"); const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD); - - // In some cases, the type of the function argument will be different from - // the type of the pointer. An example of this is - // void f(void* arg); - // __attribute__((cleanup(f))) void *g; - // - // To fix this we insert a bitcast here. - QualType ArgTy = Info.arg_begin()->type; - - CleanupBlock CleanupScope(*this, NormalCleanup); - - // Normal cleanup. - CallArgList Args; - Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr, - ConvertType(ArgTy))), - getContext().getPointerType(D.getType()))); - EmitCall(Info, F, ReturnValueSlot(), Args); - - // EH cleanup. - if (Exceptions) { - CleanupScope.beginEHCleanup(); - - CallArgList Args; - Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr, - ConvertType(ArgTy))), - getContext().getPointerType(D.getType()))); - EmitCall(Info, F, ReturnValueSlot(), Args); - } + EHStack.pushCleanup(NormalAndEHCleanup, + F, &Info, DeclPtr, &D); } - if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) { - CleanupBlock CleanupScope(*this, NormalCleanup); - - llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); - V = Builder.CreateLoad(V); - BuildBlockRelease(V); - - // FIXME: Turn this on and audit the codegen - if (0 && Exceptions) { - CleanupScope.beginEHCleanup(); - - llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); - V = Builder.CreateLoad(V); - BuildBlockRelease(V); - } - } + // If this is a block variable, clean it up. + // FIXME: this should be an EH cleanup as well. rdar://problem/8224178 + if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) + EHStack.pushCleanup(NormalCleanup, DeclPtr); } /// Emit an alloca (or GlobalValue depending on target) @@ -822,7 +829,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { DeclPtr = CreateMemTemp(Ty, D.getName() + ".addr"); // Store the initial value into the alloca. - EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Ty); + unsigned Alignment = getContext().getDeclAlign(&D).getQuantity(); + EmitStoreOfScalar(Arg, DeclPtr, CTy.isVolatileQualified(), Alignment, Ty); } Arg->setName(D.getName()); diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index ec3f386..e2f1975 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" +#include "CGCXXABI.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/Intrinsics.h" @@ -30,9 +31,10 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, QualType T = D.getType(); bool isVolatile = Context.getCanonicalType(T).isVolatileQualified(); + unsigned Alignment = Context.getDeclAlign(&D).getQuantity(); if (!CGF.hasAggregateLLVMType(T)) { llvm::Value *V = CGF.EmitScalarExpr(Init); - CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, T); + CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, Alignment, T); } else if (T->isAnyComplexType()) { CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); } else { @@ -45,19 +47,15 @@ static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D, CodeGenModule &CGM = CGF.CGM; ASTContext &Context = CGF.getContext(); - const Expr *Init = D.getInit(); QualType T = D.getType(); - if (!CGF.hasAggregateLLVMType(T) || T->isAnyComplexType()) - return; - - // Avoid generating destructor(s) for initialized objects. - if (!isa(Init)) - return; + // Drill down past array types. const ConstantArrayType *Array = Context.getAsConstantArrayType(T); if (Array) T = Context.getBaseElementType(Array); + /// If that's not a record, we're done. + /// FIXME: __attribute__((cleanup)) ? const RecordType *RT = T->getAs(); if (!RT) return; @@ -94,8 +92,9 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, return; } + unsigned Alignment = getContext().getDeclAlign(&D).getQuantity(); RValue RV = EmitReferenceBindingToExpr(Init, &D); - EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, T); + EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, Alignment, T); } void @@ -174,13 +173,26 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) { unsigned int order = D->getAttr()->getPriority(); OrderGlobalInits Key(order, PrioritizedCXXGlobalInits.size()); PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn)); + DelayedCXXInitPosition.erase(D); + } + else { + llvm::DenseMap::iterator I = + DelayedCXXInitPosition.find(D); + if (I == DelayedCXXInitPosition.end()) { + CXXGlobalInits.push_back(Fn); + } else { + assert(CXXGlobalInits[I->second] == 0); + CXXGlobalInits[I->second] = Fn; + DelayedCXXInitPosition.erase(I); + } } - else - CXXGlobalInits.push_back(Fn); } void CodeGenModule::EmitCXXGlobalInitFunc() { + while (!CXXGlobalInits.empty() && !CXXGlobalInits.back()) + CXXGlobalInits.pop_back(); + if (CXXGlobalInits.empty() && PrioritizedCXXGlobalInits.empty()) return; @@ -200,8 +212,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() { llvm::Function *Fn = PrioritizedCXXGlobalInits[i].second; LocalCXXGlobalInits.push_back(Fn); } - for (unsigned i = 0; i < CXXGlobalInits.size(); i++) - LocalCXXGlobalInits.push_back(CXXGlobalInits[i]); + LocalCXXGlobalInits.append(CXXGlobalInits.begin(), CXXGlobalInits.end()); CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, &LocalCXXGlobalInits[0], LocalCXXGlobalInits.size()); @@ -247,7 +258,8 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, SourceLocation()); for (unsigned i = 0; i != NumDecls; ++i) - Builder.CreateCall(Decls[i]); + if (Decls[i]) + Builder.CreateCall(Decls[i]); FinishFunction(); } @@ -316,6 +328,20 @@ static llvm::Constant *getGuardAbortFn(CodeGenFunction &CGF) { return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort"); } +namespace { + struct CallGuardAbort : EHScopeStack::Cleanup { + llvm::GlobalVariable *Guard; + CallGuardAbort(llvm::GlobalVariable *Guard) : Guard(Guard) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + // It shouldn't be possible for this to throw, but if it can, + // this should allow for the possibility of an invoke. + CGF.Builder.CreateCall(getGuardAbortFn(CGF), Guard) + ->setDoesNotThrow(); + } + }; +} + void CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, llvm::GlobalVariable *GV) { @@ -325,10 +351,10 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, bool ThreadsafeStatics = getContext().getLangOptions().ThreadsafeStatics; llvm::SmallString<256> GuardVName; - CGM.getMangleContext().mangleGuardVariable(&D, GuardVName); + CGM.getCXXABI().getMangleContext().mangleGuardVariable(&D, GuardVName); // Create the guard variable. - llvm::GlobalValue *GuardVariable = + llvm::GlobalVariable *GuardVariable = new llvm::GlobalVariable(CGM.getModule(), Int64Ty, false, GV->getLinkage(), llvm::Constant::getNullValue(Int64Ty), @@ -360,23 +386,25 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, InitBlock, EndBlock); // Call __cxa_guard_abort along the exceptional edge. - if (Exceptions) { - CleanupBlock Cleanup(*this, EHCleanup); - Builder.CreateCall(getGuardAbortFn(*this), GuardVariable); - } + if (Exceptions) + EHStack.pushCleanup(EHCleanup, GuardVariable); EmitBlock(InitBlock); } if (D.getType()->isReferenceType()) { + unsigned Alignment = getContext().getDeclAlign(&D).getQuantity(); QualType T = D.getType(); RValue RV = EmitReferenceBindingToExpr(D.getInit(), &D); - EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T); - + EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, Alignment, T); } else EmitDeclInit(*this, D, GV); if (ThreadsafeStatics) { + // Pop the guard-abort cleanup if we pushed one. + if (Exceptions) + PopCleanupBlock(); + // Call __cxa_guard_release. This cannot throw. Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable); } else { diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index 4980aad..7fb616e5 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -16,8 +16,10 @@ #include "llvm/Intrinsics.h" #include "llvm/Support/CallSite.h" +#include "CGObjCRuntime.h" #include "CodeGenFunction.h" #include "CGException.h" +#include "TargetInfo.h" using namespace clang; using namespace CodeGen; @@ -62,29 +64,26 @@ EHScopeStack::getEnclosingEHCleanup(iterator it) const { return stabilize(it); return cast(*it).getEnclosingEHCleanup(); } - if (isa(*it)) { - if (cast(*it).isEHCleanup()) - return stabilize(it); - return cast(*it).getEnclosingEHCleanup(); - } ++it; } while (it != end()); return stable_end(); } -void *EHScopeStack::pushLazyCleanup(CleanupKind Kind, size_t Size) { +void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) { assert(((Size % sizeof(void*)) == 0) && "cleanup type is misaligned"); - char *Buffer = allocate(EHLazyCleanupScope::getSizeForCleanupSize(Size)); - bool IsNormalCleanup = Kind != EHCleanup; - bool IsEHCleanup = Kind != NormalCleanup; - EHLazyCleanupScope *Scope = - new (Buffer) EHLazyCleanupScope(IsNormalCleanup, - IsEHCleanup, - Size, - BranchFixups.size(), - InnermostNormalCleanup, - InnermostEHCleanup); + char *Buffer = allocate(EHCleanupScope::getSizeForCleanupSize(Size)); + bool IsNormalCleanup = Kind & NormalCleanup; + bool IsEHCleanup = Kind & EHCleanup; + bool IsActive = !(Kind & InactiveCleanup); + EHCleanupScope *Scope = + new (Buffer) EHCleanupScope(IsNormalCleanup, + IsEHCleanup, + IsActive, + Size, + BranchFixups.size(), + InnermostNormalCleanup, + InnermostEHCleanup); if (IsNormalCleanup) InnermostNormalCleanup = stable_begin(); if (IsEHCleanup) @@ -93,36 +92,19 @@ void *EHScopeStack::pushLazyCleanup(CleanupKind Kind, size_t Size) { return Scope->getCleanupBuffer(); } -void EHScopeStack::pushCleanup(llvm::BasicBlock *NormalEntry, - llvm::BasicBlock *NormalExit, - llvm::BasicBlock *EHEntry, - llvm::BasicBlock *EHExit) { - char *Buffer = allocate(EHCleanupScope::getSize()); - new (Buffer) EHCleanupScope(BranchFixups.size(), - InnermostNormalCleanup, - InnermostEHCleanup, - NormalEntry, NormalExit, EHEntry, EHExit); - if (NormalEntry) - InnermostNormalCleanup = stable_begin(); - if (EHEntry) - InnermostEHCleanup = stable_begin(); -} - void EHScopeStack::popCleanup() { assert(!empty() && "popping exception stack when not empty"); - if (isa(*begin())) { - EHLazyCleanupScope &Cleanup = cast(*begin()); - InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup(); - InnermostEHCleanup = Cleanup.getEnclosingEHCleanup(); - StartOfData += Cleanup.getAllocatedSize(); - } else { - assert(isa(*begin())); - EHCleanupScope &Cleanup = cast(*begin()); - InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup(); - InnermostEHCleanup = Cleanup.getEnclosingEHCleanup(); - StartOfData += EHCleanupScope::getSize(); - } + assert(isa(*begin())); + EHCleanupScope &Cleanup = cast(*begin()); + InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup(); + InnermostEHCleanup = Cleanup.getEnclosingEHCleanup(); + StartOfData += Cleanup.getAllocatedSize(); + + if (empty()) NextEHDestIndex = FirstEHDestIndex; + + // Destroy the cleanup. + Cleanup.~EHCleanupScope(); // Check whether we can shrink the branch-fixups stack. if (!BranchFixups.empty()) { @@ -149,6 +131,8 @@ void EHScopeStack::popFilter() { EHFilterScope &Filter = cast(*begin()); StartOfData += EHFilterScope::getSizeForNumFilters(Filter.getNumFilters()); + if (empty()) NextEHDestIndex = FirstEHDestIndex; + assert(CatchDepth > 0 && "mismatched filter push/pop"); CatchDepth--; } @@ -156,13 +140,16 @@ void EHScopeStack::popFilter() { EHCatchScope *EHScopeStack::pushCatch(unsigned NumHandlers) { char *Buffer = allocate(EHCatchScope::getSizeForNumHandlers(NumHandlers)); CatchDepth++; - return new (Buffer) EHCatchScope(NumHandlers); + EHCatchScope *Scope = new (Buffer) EHCatchScope(NumHandlers); + for (unsigned I = 0; I != NumHandlers; ++I) + Scope->getHandlers()[I].Index = getNextEHDestIndex(); + return Scope; } void EHScopeStack::pushTerminate() { char *Buffer = allocate(EHTerminateScope::getSize()); CatchDepth++; - new (Buffer) EHTerminateScope(); + new (Buffer) EHTerminateScope(getNextEHDestIndex()); } /// Remove any 'null' fixups on the stack. However, we can't pop more @@ -176,11 +163,7 @@ void EHScopeStack::popNullFixups() { assert(hasNormalCleanups()); EHScopeStack::iterator it = find(InnermostNormalCleanup); - unsigned MinSize; - if (isa(*it)) - MinSize = cast(*it).getFixupDepth(); - else - MinSize = cast(*it).getFixupDepth(); + unsigned MinSize = cast(*it).getFixupDepth(); assert(BranchFixups.size() >= MinSize && "fixup stack out of order"); while (BranchFixups.size() > MinSize && @@ -188,20 +171,6 @@ void EHScopeStack::popNullFixups() { BranchFixups.pop_back(); } -void EHScopeStack::resolveBranchFixups(llvm::BasicBlock *Dest) { - assert(Dest && "null block passed to resolveBranchFixups"); - - if (BranchFixups.empty()) return; - assert(hasNormalCleanups() && - "branch fixups exist with no normal cleanups on stack"); - - for (unsigned I = 0, E = BranchFixups.size(); I != E; ++I) - if (BranchFixups[I].Destination == Dest) - BranchFixups[I].Destination = 0; - - popNullFixups(); -} - static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { // void *__cxa_allocate_exception(size_t thrown_size); const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); @@ -303,7 +272,7 @@ llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() { false); if (CGM.getLangOptions().SjLjExceptions) - return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); + return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume_or_Rethrow"); return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow"); } @@ -317,74 +286,88 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { CGF.CGM.getLangOptions().CPlusPlus ? "_ZSt9terminatev" : "abort"); } -static const char *getCPersonalityFn(CodeGenFunction &CGF) { - return "__gcc_personality_v0"; +static llvm::Constant *getCatchallRethrowFn(CodeGenFunction &CGF, + const char *Name) { + const llvm::Type *Int8PtrTy = + llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector Args(1, Int8PtrTy); + + const llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext()); + const llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, Name); +} + +const EHPersonality EHPersonality::GNU_C("__gcc_personality_v0"); +const EHPersonality EHPersonality::NeXT_ObjC("__objc_personality_v0"); +const EHPersonality EHPersonality::GNU_CPlusPlus("__gxx_personality_v0"); +const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ("__gxx_personality_sj0"); +const EHPersonality EHPersonality::GNU_ObjC("__gnu_objc_personality_v0", + "objc_exception_throw"); + +static const EHPersonality &getCPersonality(const LangOptions &L) { + return EHPersonality::GNU_C; } -static const char *getObjCPersonalityFn(CodeGenFunction &CGF) { - if (CGF.CGM.getLangOptions().NeXTRuntime) { - if (CGF.CGM.getLangOptions().ObjCNonFragileABI) - return "__objc_personality_v0"; - else - return getCPersonalityFn(CGF); +static const EHPersonality &getObjCPersonality(const LangOptions &L) { + if (L.NeXTRuntime) { + if (L.ObjCNonFragileABI) return EHPersonality::NeXT_ObjC; + else return getCPersonality(L); } else { - return "__gnu_objc_personality_v0"; + return EHPersonality::GNU_ObjC; } } -static const char *getCXXPersonalityFn(CodeGenFunction &CGF) { - if (CGF.CGM.getLangOptions().SjLjExceptions) - return "__gxx_personality_sj0"; +static const EHPersonality &getCXXPersonality(const LangOptions &L) { + if (L.SjLjExceptions) + return EHPersonality::GNU_CPlusPlus_SJLJ; else - return "__gxx_personality_v0"; + return EHPersonality::GNU_CPlusPlus; } /// Determines the personality function to use when both C++ /// and Objective-C exceptions are being caught. -static const char *getObjCXXPersonalityFn(CodeGenFunction &CGF) { +static const EHPersonality &getObjCXXPersonality(const LangOptions &L) { // The ObjC personality defers to the C++ personality for non-ObjC // handlers. Unlike the C++ case, we use the same personality // function on targets using (backend-driven) SJLJ EH. - if (CGF.CGM.getLangOptions().NeXTRuntime) { - if (CGF.CGM.getLangOptions().ObjCNonFragileABI) - return "__objc_personality_v0"; + if (L.NeXTRuntime) { + if (L.ObjCNonFragileABI) + return EHPersonality::NeXT_ObjC; // In the fragile ABI, just use C++ exception handling and hope // they're not doing crazy exception mixing. else - return getCXXPersonalityFn(CGF); + return getCXXPersonality(L); } - // I'm pretty sure the GNU runtime doesn't support mixed EH. - // TODO: we don't necessarily need mixed EH here; remember what - // kind of exceptions we actually try to catch in this function. - CGF.CGM.ErrorUnsupported(CGF.CurCodeDecl, - "the GNU Objective C runtime does not support " - "catching C++ and Objective C exceptions in the " - "same function"); - // Use the C++ personality just to avoid returning null. - return getCXXPersonalityFn(CGF); + // The GNU runtime's personality function inherently doesn't support + // mixed EH. Use the C++ personality just to avoid returning null. + return getCXXPersonality(L); } -static llvm::Constant *getPersonalityFn(CodeGenFunction &CGF) { - const char *Name; - const LangOptions &Opts = CGF.CGM.getLangOptions(); - if (Opts.CPlusPlus && Opts.ObjC1) - Name = getObjCXXPersonalityFn(CGF); - else if (Opts.CPlusPlus) - Name = getCXXPersonalityFn(CGF); - else if (Opts.ObjC1) - Name = getObjCPersonalityFn(CGF); +const EHPersonality &EHPersonality::get(const LangOptions &L) { + if (L.CPlusPlus && L.ObjC1) + return getObjCXXPersonality(L); + else if (L.CPlusPlus) + return getCXXPersonality(L); + else if (L.ObjC1) + return getObjCPersonality(L); else - Name = getCPersonalityFn(CGF); + return getCPersonality(L); +} + +static llvm::Constant *getPersonalityFn(CodeGenFunction &CGF, + const EHPersonality &Personality) { + const char *Name = Personality.getPersonalityFnName(); - llvm::Constant *Personality = + llvm::Constant *Fn = CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get( llvm::Type::getInt32Ty( CGF.CGM.getLLVMContext()), true), Name); - return llvm::ConstantExpr::getBitCast(Personality, CGF.CGM.PtrToInt8Ty); + return llvm::ConstantExpr::getBitCast(Fn, CGF.CGM.PtrToInt8Ty); } /// Returns the value to inject into a selector to indicate the @@ -403,7 +386,7 @@ static llvm::Constant *getCleanupValue(CodeGenFunction &CGF) { namespace { /// A cleanup to free the exception object if its initialization /// throws. - struct FreeExceptionCleanup : EHScopeStack::LazyCleanup { + struct FreeExceptionCleanup : EHScopeStack::Cleanup { FreeExceptionCleanup(llvm::Value *ShouldFreeVar, llvm::Value *ExnLocVar) : ShouldFreeVar(ShouldFreeVar), ExnLocVar(ExnLocVar) {} @@ -453,9 +436,9 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *E, // exception during initialization. // FIXME: stmt expressions might require this to be a normal // cleanup, too. - CGF.EHStack.pushLazyCleanup(EHCleanup, - ShouldFreeVar, - ExnLocVar); + CGF.EHStack.pushCleanup(EHCleanup, + ShouldFreeVar, + ExnLocVar); EHScopeStack::stable_iterator Cleanup = CGF.EHStack.stable_begin(); CGF.Builder.CreateStore(ExnLoc, ExnLocVar); @@ -637,7 +620,12 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#388 QualType CaughtType = C->getCaughtType(); CaughtType = CaughtType.getNonReferenceType().getUnqualifiedType(); - llvm::Value *TypeInfo = CGM.GetAddrOfRTTIDescriptor(CaughtType, true); + + llvm::Value *TypeInfo = 0; + if (CaughtType->isObjCObjectPointerType()) + TypeInfo = CGM.getObjCRuntime().GetEHType(CaughtType); + else + TypeInfo = CGM.GetAddrOfRTTIDescriptor(CaughtType, true); CatchScope->setHandler(I, TypeInfo, Handler); } else { // No exception decl indicates '...', a catch-all. @@ -653,8 +641,6 @@ static bool isNonEHScope(const EHScope &S) { switch (S.getKind()) { case EHScope::Cleanup: return !cast(S).isEHCleanup(); - case EHScope::LazyCleanup: - return !cast(S).isEHCleanup(); case EHScope::Filter: case EHScope::Catch: case EHScope::Terminate: @@ -753,6 +739,9 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { // Save the current IR generation state. CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); + const EHPersonality &Personality = + EHPersonality::get(CGF.CGM.getLangOptions()); + // Create and configure the landing pad. llvm::BasicBlock *LP = createBasicBlock("lpad"); EmitBlock(LP); @@ -768,11 +757,11 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { // Build the selector arguments. llvm::SmallVector EHSelector; EHSelector.push_back(Exn); - EHSelector.push_back(getPersonalityFn(*this)); + EHSelector.push_back(getPersonalityFn(*this, Personality)); // Accumulate all the handlers in scope. - llvm::DenseMap EHHandlers; - JumpDest CatchAll; + llvm::DenseMap EHHandlers; + UnwindDest CatchAll; bool HasEHCleanup = false; bool HasEHFilter = false; llvm::SmallVector EHFilters; @@ -780,12 +769,6 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { I != E; ++I) { switch (I->getKind()) { - case EHScope::LazyCleanup: - if (!HasEHCleanup) - HasEHCleanup = cast(*I).isEHCleanup(); - // We otherwise don't care about cleanups. - continue; - case EHScope::Cleanup: if (!HasEHCleanup) HasEHCleanup = cast(*I).isEHCleanup(); @@ -794,7 +777,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { case EHScope::Filter: { assert(I.next() == EHStack.end() && "EH filter is not end of EH stack"); - assert(!CatchAll.Block && "EH filter reached after catch-all"); + assert(!CatchAll.isValid() && "EH filter reached after catch-all"); // Filter scopes get added to the selector in wierd ways. EHFilterScope &Filter = cast(*I); @@ -812,9 +795,10 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { case EHScope::Terminate: // Terminate scopes are basically catch-alls. - assert(!CatchAll.Block); - CatchAll.Block = getTerminateHandler(); - CatchAll.ScopeDepth = EHStack.getEnclosingEHCleanup(I); + assert(!CatchAll.isValid()); + CatchAll = UnwindDest(getTerminateHandler(), + EHStack.getEnclosingEHCleanup(I), + cast(*I).getDestIndex()); goto done; case EHScope::Catch: @@ -827,30 +811,32 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { // Catch-all. We should only have one of these per catch. if (!Handler.Type) { - assert(!CatchAll.Block); - CatchAll.Block = Handler.Block; - CatchAll.ScopeDepth = EHStack.getEnclosingEHCleanup(I); + assert(!CatchAll.isValid()); + CatchAll = UnwindDest(Handler.Block, + EHStack.getEnclosingEHCleanup(I), + Handler.Index); continue; } // Check whether we already have a handler for this type. - JumpDest &Dest = EHHandlers[Handler.Type]; - if (Dest.Block) continue; + UnwindDest &Dest = EHHandlers[Handler.Type]; + if (Dest.isValid()) continue; EHSelector.push_back(Handler.Type); - Dest.Block = Handler.Block; - Dest.ScopeDepth = EHStack.getEnclosingEHCleanup(I); + Dest = UnwindDest(Handler.Block, + EHStack.getEnclosingEHCleanup(I), + Handler.Index); } // Stop if we found a catch-all. - if (CatchAll.Block) break; + if (CatchAll.isValid()) break; } done: unsigned LastToEmitInLoop = EHSelector.size(); // If we have a catch-all, add null to the selector. - if (CatchAll.Block) { + if (CatchAll.isValid()) { EHSelector.push_back(getCatchAllValue(CGF)); // If we have an EH filter, we need to add those handlers in the @@ -899,14 +885,15 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { // filter (possibly with a cleanup), a catch-all, or another catch). for (unsigned I = 2; I != LastToEmitInLoop; ++I) { llvm::Value *Type = EHSelector[I]; - JumpDest Dest = EHHandlers[Type]; - assert(Dest.Block && "no handler entry for value in selector?"); + UnwindDest Dest = EHHandlers[Type]; + assert(Dest.isValid() && "no handler entry for value in selector?"); // Figure out where to branch on a match. As a debug code-size // optimization, if the scope depth matches the innermost cleanup, // we branch directly to the catch handler. - llvm::BasicBlock *Match = Dest.Block; - bool MatchNeedsCleanup = Dest.ScopeDepth != EHStack.getInnermostEHCleanup(); + llvm::BasicBlock *Match = Dest.getBlock(); + bool MatchNeedsCleanup = + Dest.getScopeDepth() != EHStack.getInnermostEHCleanup(); if (MatchNeedsCleanup) Match = createBasicBlock("eh.match"); @@ -932,7 +919,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { // Emit the final case in the selector. // This might be a catch-all.... - if (CatchAll.Block) { + if (CatchAll.isValid()) { assert(isa(EHSelector.back())); EmitBranchThroughEHCleanup(CatchAll); @@ -951,7 +938,8 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { } llvm::BasicBlock *CleanupContBB = createBasicBlock("ehspec.cleanup.cont"); - EmitBranchThroughEHCleanup(JumpDest(CleanupContBB, EHStack.stable_end())); + EmitBranchThroughEHCleanup(UnwindDest(CleanupContBB, EHStack.stable_end(), + EHStack.getNextEHDestIndex())); EmitBlock(CleanupContBB); if (HasEHCleanup) @@ -996,22 +984,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { // ...or a cleanup. } else { - // We emit a jump to a notional label at the outermost unwind state. - llvm::BasicBlock *Unwind = createBasicBlock("eh.resume"); - JumpDest Dest(Unwind, EHStack.stable_end()); - EmitBranchThroughEHCleanup(Dest); - - // The unwind block. We have to reload the exception here because - // we might have unwound through arbitrary blocks, so the landing - // pad might not dominate. - EmitBlock(Unwind); - - // This can always be a call because we necessarily didn't find - // anything on the EH stack which needs our help. - Builder.CreateCall(getUnwindResumeOrRethrowFn(), - Builder.CreateLoad(getExceptionSlot())) - ->setDoesNotReturn(); - Builder.CreateUnreachable(); + EmitBranchThroughEHCleanup(getRethrowDest()); } // Restore the old IR generation state. @@ -1033,7 +1006,7 @@ namespace { /// of the caught type, so we have to assume the actual thrown /// exception type might have a throwing destructor, even if the /// caught type's destructor is trivial or nothrow. - struct CallEndCatch : EHScopeStack::LazyCleanup { + struct CallEndCatch : EHScopeStack::Cleanup { CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {} bool MightThrow; @@ -1058,7 +1031,7 @@ static llvm::Value *CallBeginCatch(CodeGenFunction &CGF, llvm::CallInst *Call = CGF.Builder.CreateCall(getBeginCatchFn(CGF), Exn); Call->setDoesNotThrow(); - CGF.EHStack.pushLazyCleanup(NormalAndEHCleanup, EndMightThrow); + CGF.EHStack.pushCleanup(NormalAndEHCleanup, EndMightThrow); return Call; } @@ -1078,11 +1051,57 @@ static void InitCatchParam(CodeGenFunction &CGF, // If we're catching by reference, we can just cast the object // pointer to the appropriate pointer. if (isa(CatchType)) { - bool EndCatchMightThrow = cast(CatchType)->getPointeeType() - ->isRecordType(); + QualType CaughtType = cast(CatchType)->getPointeeType(); + bool EndCatchMightThrow = CaughtType->isRecordType(); // __cxa_begin_catch returns the adjusted object pointer. llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, EndCatchMightThrow); + + // We have no way to tell the personality function that we're + // catching by reference, so if we're catching a pointer, + // __cxa_begin_catch will actually return that pointer by value. + if (const PointerType *PT = dyn_cast(CaughtType)) { + QualType PointeeType = PT->getPointeeType(); + + // When catching by reference, generally we should just ignore + // this by-value pointer and use the exception object instead. + if (!PointeeType->isRecordType()) { + + // Exn points to the struct _Unwind_Exception header, which + // we have to skip past in order to reach the exception data. + unsigned HeaderSize = + CGF.CGM.getTargetCodeGenInfo().getSizeOfUnwindException(); + AdjustedExn = CGF.Builder.CreateConstGEP1_32(Exn, HeaderSize); + + // However, if we're catching a pointer-to-record type that won't + // work, because the personality function might have adjusted + // the pointer. There's actually no way for us to fully satisfy + // the language/ABI contract here: we can't use Exn because it + // might have the wrong adjustment, but we can't use the by-value + // pointer because it's off by a level of abstraction. + // + // The current solution is to dump the adjusted pointer into an + // alloca, which breaks language semantics (because changing the + // pointer doesn't change the exception) but at least works. + // The better solution would be to filter out non-exact matches + // and rethrow them, but this is tricky because the rethrow + // really needs to be catchable by other sites at this landing + // pad. The best solution is to fix the personality function. + } else { + // Pull the pointer for the reference type off. + const llvm::Type *PtrTy = + cast(LLVMCatchTy)->getElementType(); + + // Create the temporary and write the adjusted pointer into it. + llvm::Value *ExnPtrTmp = CGF.CreateTempAlloca(PtrTy, "exn.byref.tmp"); + llvm::Value *Casted = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy); + CGF.Builder.CreateStore(Casted, ExnPtrTmp); + + // Bind the reference to the temporary. + AdjustedExn = ExnPtrTmp; + } + } + llvm::Value *ExnCast = CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.byref"); CGF.Builder.CreateStore(ExnCast, ParamAddr); @@ -1113,8 +1132,11 @@ static void InitCatchParam(CodeGenFunction &CGF, CGF.StoreComplexToAddr(CGF.LoadComplexFromAddr(Cast, /*volatile*/ false), ParamAddr, /*volatile*/ false); } else { + unsigned Alignment = + CGF.getContext().getDeclAlign(&CatchParam).getQuantity(); llvm::Value *ExnLoad = CGF.Builder.CreateLoad(Cast, "exn.scalar"); - CGF.EmitStoreOfScalar(ExnLoad, ParamAddr, /*volatile*/ false, CatchType); + CGF.EmitStoreOfScalar(ExnLoad, ParamAddr, /*volatile*/ false, Alignment, + CatchType); } return; } @@ -1203,7 +1225,7 @@ static void BeginCatch(CodeGenFunction &CGF, } namespace { - struct CallRethrow : EHScopeStack::LazyCleanup { + struct CallRethrow : EHScopeStack::Cleanup { void Emit(CodeGenFunction &CGF, bool IsForEH) { CGF.EmitCallOrInvoke(getReThrowFn(CGF), 0, 0); } @@ -1253,7 +1275,7 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { // _cxa_rethrow. This needs to happen before __cxa_end_catch is // called, and so it is pushed after BeginCatch. if (ImplicitRethrow) - EHStack.pushLazyCleanup(NormalCleanup); + EHStack.pushCleanup(NormalCleanup); // Perform the body of the catch. EmitStmt(C->getHandlerBlock()); @@ -1269,6 +1291,97 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) { EmitBlock(ContBB); } +namespace { + struct CallEndCatchForFinally : EHScopeStack::Cleanup { + llvm::Value *ForEHVar; + llvm::Value *EndCatchFn; + CallEndCatchForFinally(llvm::Value *ForEHVar, llvm::Value *EndCatchFn) + : ForEHVar(ForEHVar), EndCatchFn(EndCatchFn) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + llvm::BasicBlock *EndCatchBB = CGF.createBasicBlock("finally.endcatch"); + llvm::BasicBlock *CleanupContBB = + CGF.createBasicBlock("finally.cleanup.cont"); + + llvm::Value *ShouldEndCatch = + CGF.Builder.CreateLoad(ForEHVar, "finally.endcatch"); + CGF.Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB); + CGF.EmitBlock(EndCatchBB); + CGF.EmitCallOrInvoke(EndCatchFn, 0, 0); // catch-all, so might throw + CGF.EmitBlock(CleanupContBB); + } + }; + + struct PerformFinally : EHScopeStack::Cleanup { + const Stmt *Body; + llvm::Value *ForEHVar; + llvm::Value *EndCatchFn; + llvm::Value *RethrowFn; + llvm::Value *SavedExnVar; + + PerformFinally(const Stmt *Body, llvm::Value *ForEHVar, + llvm::Value *EndCatchFn, + llvm::Value *RethrowFn, llvm::Value *SavedExnVar) + : Body(Body), ForEHVar(ForEHVar), EndCatchFn(EndCatchFn), + RethrowFn(RethrowFn), SavedExnVar(SavedExnVar) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + // Enter a cleanup to call the end-catch function if one was provided. + if (EndCatchFn) + CGF.EHStack.pushCleanup(NormalAndEHCleanup, + ForEHVar, EndCatchFn); + + // Save the current cleanup destination in case there are + // cleanups in the finally block. + llvm::Value *SavedCleanupDest = + CGF.Builder.CreateLoad(CGF.getNormalCleanupDestSlot(), + "cleanup.dest.saved"); + + // Emit the finally block. + CGF.EmitStmt(Body); + + // If the end of the finally is reachable, check whether this was + // for EH. If so, rethrow. + if (CGF.HaveInsertPoint()) { + llvm::BasicBlock *RethrowBB = CGF.createBasicBlock("finally.rethrow"); + llvm::BasicBlock *ContBB = CGF.createBasicBlock("finally.cont"); + + llvm::Value *ShouldRethrow = + CGF.Builder.CreateLoad(ForEHVar, "finally.shouldthrow"); + CGF.Builder.CreateCondBr(ShouldRethrow, RethrowBB, ContBB); + + CGF.EmitBlock(RethrowBB); + if (SavedExnVar) { + llvm::Value *Args[] = { CGF.Builder.CreateLoad(SavedExnVar) }; + CGF.EmitCallOrInvoke(RethrowFn, Args, Args+1); + } else { + CGF.EmitCallOrInvoke(RethrowFn, 0, 0); + } + CGF.Builder.CreateUnreachable(); + + CGF.EmitBlock(ContBB); + + // Restore the cleanup destination. + CGF.Builder.CreateStore(SavedCleanupDest, + CGF.getNormalCleanupDestSlot()); + } + + // Leave the end-catch cleanup. As an optimization, pretend that + // the fallthrough path was inaccessible; we've dynamically proven + // that we're not in the EH case along that path. + if (EndCatchFn) { + CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); + CGF.PopCleanupBlock(); + CGF.Builder.restoreIP(SavedIP); + } + + // Now make sure we actually have an insertion point or the + // cleanup gods will hate us. + CGF.EnsureInsertPoint(); + } + }; +} + /// Enters a finally block for an implementation using zero-cost /// exceptions. This is mostly general, but hard-codes some /// language/ABI-specific behavior in the catch-all sections. @@ -1320,62 +1433,9 @@ CodeGenFunction::EnterFinallyBlock(const Stmt *Body, InitTempAlloca(ForEHVar, llvm::ConstantInt::getFalse(getLLVMContext())); // Enter a normal cleanup which will perform the @finally block. - { - CodeGenFunction::CleanupBlock Cleanup(*this, NormalCleanup); - - // Enter a cleanup to call the end-catch function if one was provided. - if (EndCatchFn) { - CodeGenFunction::CleanupBlock FinallyExitCleanup(CGF, NormalAndEHCleanup); - - llvm::BasicBlock *EndCatchBB = createBasicBlock("finally.endcatch"); - llvm::BasicBlock *CleanupContBB = createBasicBlock("finally.cleanup.cont"); - - llvm::Value *ShouldEndCatch = - Builder.CreateLoad(ForEHVar, "finally.endcatch"); - Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB); - EmitBlock(EndCatchBB); - EmitCallOrInvoke(EndCatchFn, 0, 0); // catch-all, so might throw - EmitBlock(CleanupContBB); - } - - // Emit the finally block. - EmitStmt(Body); - - // If the end of the finally is reachable, check whether this was - // for EH. If so, rethrow. - if (HaveInsertPoint()) { - llvm::BasicBlock *RethrowBB = createBasicBlock("finally.rethrow"); - llvm::BasicBlock *ContBB = createBasicBlock("finally.cont"); - - llvm::Value *ShouldRethrow = - Builder.CreateLoad(ForEHVar, "finally.shouldthrow"); - Builder.CreateCondBr(ShouldRethrow, RethrowBB, ContBB); - - EmitBlock(RethrowBB); - if (SavedExnVar) { - llvm::Value *Args[] = { Builder.CreateLoad(SavedExnVar) }; - EmitCallOrInvoke(RethrowFn, Args, Args+1); - } else { - EmitCallOrInvoke(RethrowFn, 0, 0); - } - Builder.CreateUnreachable(); - - EmitBlock(ContBB); - } - - // Leave the end-catch cleanup. As an optimization, pretend that - // the fallthrough path was inaccessible; we've dynamically proven - // that we're not in the EH case along that path. - if (EndCatchFn) { - CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); - PopCleanupBlock(); - Builder.restoreIP(SavedIP); - } - - // Now make sure we actually have an insertion point or the - // cleanup gods will hate us. - EnsureInsertPoint(); - } + EHStack.pushCleanup(NormalCleanup, Body, + ForEHVar, EndCatchFn, + RethrowFn, SavedExnVar); // Enter a catch-all scope. llvm::BasicBlock *CatchAllBB = createBasicBlock("finally.catchall"); @@ -1437,10 +1497,12 @@ llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() { llvm::CallInst *Exn = Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_exception), "exn"); Exn->setDoesNotThrow(); + + const EHPersonality &Personality = EHPersonality::get(CGM.getLangOptions()); // Tell the backend what the exception table should be: // nothing but a catch-all. - llvm::Value *Args[3] = { Exn, getPersonalityFn(*this), + llvm::Value *Args[3] = { Exn, getPersonalityFn(*this, Personality), getCatchAllValue(*this) }; Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::eh_selector), Args, Args+3, "eh.selector") @@ -1478,69 +1540,35 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { return TerminateHandler; } -CodeGenFunction::CleanupBlock::CleanupBlock(CodeGenFunction &CGF, - CleanupKind Kind) - : CGF(CGF), SavedIP(CGF.Builder.saveIP()), NormalCleanupExitBB(0) { - llvm::BasicBlock *EntryBB = CGF.createBasicBlock("cleanup"); - CGF.Builder.SetInsertPoint(EntryBB); - - switch (Kind) { - case NormalAndEHCleanup: - NormalCleanupEntryBB = EHCleanupEntryBB = EntryBB; - break; - - case NormalCleanup: - NormalCleanupEntryBB = EntryBB; - EHCleanupEntryBB = 0; - break; - - case EHCleanup: - NormalCleanupEntryBB = 0; - EHCleanupEntryBB = EntryBB; - CGF.EHStack.pushTerminate(); - break; - } -} +CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() { + if (RethrowBlock.isValid()) return RethrowBlock; -void CodeGenFunction::CleanupBlock::beginEHCleanup() { - assert(EHCleanupEntryBB == 0 && "already started an EH cleanup"); - NormalCleanupExitBB = CGF.Builder.GetInsertBlock(); - assert(NormalCleanupExitBB && "end of normal cleanup is unreachable"); - - EHCleanupEntryBB = CGF.createBasicBlock("eh.cleanup"); - CGF.Builder.SetInsertPoint(EHCleanupEntryBB); - CGF.EHStack.pushTerminate(); -} + CGBuilderTy::InsertPoint SavedIP = Builder.saveIP(); -CodeGenFunction::CleanupBlock::~CleanupBlock() { - llvm::BasicBlock *EHCleanupExitBB = 0; + // We emit a jump to a notional label at the outermost unwind state. + llvm::BasicBlock *Unwind = createBasicBlock("eh.resume"); + Builder.SetInsertPoint(Unwind); - // If we're currently writing the EH cleanup... - if (EHCleanupEntryBB) { - // Set the EH cleanup exit block. - EHCleanupExitBB = CGF.Builder.GetInsertBlock(); - assert(EHCleanupExitBB && "end of EH cleanup is unreachable"); + const EHPersonality &Personality = EHPersonality::get(CGM.getLangOptions()); - // If we're actually writing both at once, set the normal exit, too. - if (EHCleanupEntryBB == NormalCleanupEntryBB) - NormalCleanupExitBB = EHCleanupExitBB; + // This can always be a call because we necessarily didn't find + // anything on the EH stack which needs our help. + llvm::Constant *RethrowFn; + if (const char *RethrowName = Personality.getCatchallRethrowFnName()) + RethrowFn = getCatchallRethrowFn(*this, RethrowName); + else + RethrowFn = getUnwindResumeOrRethrowFn(); - // Otherwise, we must have pushed a terminate handler. - else - CGF.EHStack.popTerminate(); + Builder.CreateCall(RethrowFn, Builder.CreateLoad(getExceptionSlot())) + ->setDoesNotReturn(); + Builder.CreateUnreachable(); - // Otherwise, just set the normal cleanup exit block. - } else { - NormalCleanupExitBB = CGF.Builder.GetInsertBlock(); - assert(NormalCleanupExitBB && "end of normal cleanup is unreachable"); - } - - CGF.EHStack.pushCleanup(NormalCleanupEntryBB, NormalCleanupExitBB, - EHCleanupEntryBB, EHCleanupExitBB); + Builder.restoreIP(SavedIP); - CGF.Builder.restoreIP(SavedIP); + RethrowBlock = UnwindDest(Unwind, EHStack.stable_end(), 0); + return RethrowBlock; } -EHScopeStack::LazyCleanup::~LazyCleanup() { - llvm_unreachable("LazyCleanup is indestructable"); +EHScopeStack::Cleanup::~Cleanup() { + llvm_unreachable("Cleanup is indestructable"); } diff --git a/lib/CodeGen/CGException.h b/lib/CodeGen/CGException.h index 80739cd..f129474 100644 --- a/lib/CodeGen/CGException.h +++ b/lib/CodeGen/CGException.h @@ -27,17 +27,43 @@ namespace llvm { namespace clang { namespace CodeGen { +/// The exceptions personality for a function. When +class EHPersonality { + const char *PersonalityFn; + + // If this is non-null, this personality requires a non-standard + // function for rethrowing an exception after a catchall cleanup. + // This function must have prototype void(void*). + const char *CatchallRethrowFn; + + EHPersonality(const char *PersonalityFn, + const char *CatchallRethrowFn = 0) + : PersonalityFn(PersonalityFn), + CatchallRethrowFn(CatchallRethrowFn) {} + +public: + static const EHPersonality &get(const LangOptions &Lang); + static const EHPersonality GNU_C; + static const EHPersonality GNU_ObjC; + static const EHPersonality NeXT_ObjC; + static const EHPersonality GNU_CPlusPlus; + static const EHPersonality GNU_CPlusPlus_SJLJ; + + const char *getPersonalityFnName() const { return PersonalityFn; } + const char *getCatchallRethrowFnName() const { return CatchallRethrowFn; } +}; + /// A protected scope for zero-cost EH handling. class EHScope { llvm::BasicBlock *CachedLandingPad; - unsigned K : 3; + unsigned K : 2; protected: - enum { BitsRemaining = 29 }; + enum { BitsRemaining = 30 }; public: - enum Kind { Cleanup, LazyCleanup, Catch, Terminate, Filter }; + enum Kind { Cleanup, Catch, Terminate, Filter }; EHScope(Kind K) : CachedLandingPad(0), K(K) {} @@ -74,15 +100,13 @@ public: /// The catch handler for this type. llvm::BasicBlock *Block; - static Handler make(llvm::Value *Type, llvm::BasicBlock *Block) { - Handler Temp; - Temp.Type = Type; - Temp.Block = Block; - return Temp; - } + /// The unwind destination index for this handler. + unsigned Index; }; private: + friend class EHScopeStack; + Handler *getHandlers() { return reinterpret_cast(this+1); } @@ -110,7 +134,8 @@ public: void setHandler(unsigned I, llvm::Value *Type, llvm::BasicBlock *Block) { assert(I < getNumHandlers()); - getHandlers()[I] = Handler::make(Type, Block); + getHandlers()[I].Type = Type; + getHandlers()[I].Block = Block; } const Handler &getHandler(unsigned I) const { @@ -128,21 +153,27 @@ public: }; /// A cleanup scope which generates the cleanup blocks lazily. -class EHLazyCleanupScope : public EHScope { +class EHCleanupScope : public EHScope { /// Whether this cleanup needs to be run along normal edges. bool IsNormalCleanup : 1; /// Whether this cleanup needs to be run along exception edges. bool IsEHCleanup : 1; - /// The amount of extra storage needed by the LazyCleanup. + /// Whether this cleanup was activated before all normal uses. + bool ActivatedBeforeNormalUse : 1; + + /// Whether this cleanup was activated before all EH uses. + bool ActivatedBeforeEHUse : 1; + + /// The amount of extra storage needed by the Cleanup. /// Always a multiple of the scope-stack alignment. unsigned CleanupSize : 12; /// The number of fixups required by enclosing scopes (not including /// this one). If this is the top cleanup scope, all the fixups /// from this index onwards belong to this scope. - unsigned FixupDepth : BitsRemaining - 14; + unsigned FixupDepth : BitsRemaining - 16; /// The nearest normal cleanup scope enclosing this one. EHScopeStack::stable_iterator EnclosingNormal; @@ -158,27 +189,78 @@ class EHLazyCleanupScope : public EHScope { /// created if needed before the cleanup is popped. llvm::BasicBlock *EHBlock; + /// An optional i1 variable indicating whether this cleanup has been + /// activated yet. This has one of three states: + /// - it is null if the cleanup is inactive + /// - it is activeSentinel() if the cleanup is active and was not + /// required before activation + /// - it points to a valid variable + llvm::AllocaInst *ActiveVar; + + /// Extra information required for cleanups that have resolved + /// branches through them. This has to be allocated on the side + /// because everything on the cleanup stack has be trivially + /// movable. + struct ExtInfo { + /// The destinations of normal branch-afters and branch-throughs. + llvm::SmallPtrSet Branches; + + /// Normal branch-afters. + llvm::SmallVector, 4> + BranchAfters; + + /// The destinations of EH branch-afters and branch-throughs. + /// TODO: optimize for the extremely common case of a single + /// branch-through. + llvm::SmallPtrSet EHBranches; + + /// EH branch-afters. + llvm::SmallVector, 4> + EHBranchAfters; + }; + mutable struct ExtInfo *ExtInfo; + + struct ExtInfo &getExtInfo() { + if (!ExtInfo) ExtInfo = new struct ExtInfo(); + return *ExtInfo; + } + + const struct ExtInfo &getExtInfo() const { + if (!ExtInfo) ExtInfo = new struct ExtInfo(); + return *ExtInfo; + } + public: /// Gets the size required for a lazy cleanup scope with the given /// cleanup-data requirements. static size_t getSizeForCleanupSize(size_t Size) { - return sizeof(EHLazyCleanupScope) + Size; + return sizeof(EHCleanupScope) + Size; } size_t getAllocatedSize() const { - return sizeof(EHLazyCleanupScope) + CleanupSize; + return sizeof(EHCleanupScope) + CleanupSize; } - EHLazyCleanupScope(bool IsNormal, bool IsEH, unsigned CleanupSize, - unsigned FixupDepth, - EHScopeStack::stable_iterator EnclosingNormal, - EHScopeStack::stable_iterator EnclosingEH) - : EHScope(EHScope::LazyCleanup), + EHCleanupScope(bool IsNormal, bool IsEH, bool IsActive, + unsigned CleanupSize, unsigned FixupDepth, + EHScopeStack::stable_iterator EnclosingNormal, + EHScopeStack::stable_iterator EnclosingEH) + : EHScope(EHScope::Cleanup), IsNormalCleanup(IsNormal), IsEHCleanup(IsEH), + ActivatedBeforeNormalUse(IsActive), + ActivatedBeforeEHUse(IsActive), CleanupSize(CleanupSize), FixupDepth(FixupDepth), EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH), - NormalBlock(0), EHBlock(0) - {} + NormalBlock(0), EHBlock(0), + ActiveVar(IsActive ? activeSentinel() : 0), + ExtInfo(0) + { + assert(this->CleanupSize == CleanupSize && "cleanup size overflow"); + } + + ~EHCleanupScope() { + delete ExtInfo; + } bool isNormalCleanup() const { return IsNormalCleanup; } llvm::BasicBlock *getNormalBlock() const { return NormalBlock; } @@ -188,6 +270,20 @@ public: llvm::BasicBlock *getEHBlock() const { return EHBlock; } void setEHBlock(llvm::BasicBlock *BB) { EHBlock = BB; } + static llvm::AllocaInst *activeSentinel() { + return reinterpret_cast(1); + } + + bool isActive() const { return ActiveVar != 0; } + llvm::AllocaInst *getActiveVar() const { return ActiveVar; } + void setActiveVar(llvm::AllocaInst *Var) { ActiveVar = Var; } + + bool wasActivatedBeforeNormalUse() const { return ActivatedBeforeNormalUse; } + void setActivatedBeforeNormalUse(bool B) { ActivatedBeforeNormalUse = B; } + + bool wasActivatedBeforeEHUse() const { return ActivatedBeforeEHUse; } + void setActivatedBeforeEHUse(bool B) { ActivatedBeforeEHUse = B; } + unsigned getFixupDepth() const { return FixupDepth; } EHScopeStack::stable_iterator getEnclosingNormalCleanup() const { return EnclosingNormal; @@ -199,67 +295,108 @@ public: size_t getCleanupSize() const { return CleanupSize; } void *getCleanupBuffer() { return this + 1; } - EHScopeStack::LazyCleanup *getCleanup() { - return reinterpret_cast(getCleanupBuffer()); + EHScopeStack::Cleanup *getCleanup() { + return reinterpret_cast(getCleanupBuffer()); } - static bool classof(const EHScope *Scope) { - return (Scope->getKind() == LazyCleanup); + /// True if this cleanup scope has any branch-afters or branch-throughs. + bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); } + + /// Add a branch-after to this cleanup scope. A branch-after is a + /// branch from a point protected by this (normal) cleanup to a + /// point in the normal cleanup scope immediately containing it. + /// For example, + /// for (;;) { A a; break; } + /// contains a branch-after. + /// + /// Branch-afters each have their own destination out of the + /// cleanup, guaranteed distinct from anything else threaded through + /// it. Therefore branch-afters usually force a switch after the + /// cleanup. + void addBranchAfter(llvm::ConstantInt *Index, + llvm::BasicBlock *Block) { + struct ExtInfo &ExtInfo = getExtInfo(); + if (ExtInfo.Branches.insert(Block)) + ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index)); } -}; -/// A scope which needs to execute some code if we try to unwind --- -/// either normally, via the EH mechanism, or both --- through it. -class EHCleanupScope : public EHScope { - /// The number of fixups required by enclosing scopes (not including - /// this one). If this is the top cleanup scope, all the fixups - /// from this index onwards belong to this scope. - unsigned FixupDepth : BitsRemaining; + /// Return the number of unique branch-afters on this scope. + unsigned getNumBranchAfters() const { + return ExtInfo ? ExtInfo->BranchAfters.size() : 0; + } - /// The nearest normal cleanup scope enclosing this one. - EHScopeStack::stable_iterator EnclosingNormal; + llvm::BasicBlock *getBranchAfterBlock(unsigned I) const { + assert(I < getNumBranchAfters()); + return ExtInfo->BranchAfters[I].first; + } - /// The nearest EH cleanup scope enclosing this one. - EHScopeStack::stable_iterator EnclosingEH; + llvm::ConstantInt *getBranchAfterIndex(unsigned I) const { + assert(I < getNumBranchAfters()); + return ExtInfo->BranchAfters[I].second; + } - llvm::BasicBlock *NormalEntry; - llvm::BasicBlock *NormalExit; - llvm::BasicBlock *EHEntry; - llvm::BasicBlock *EHExit; + /// Add a branch-through to this cleanup scope. A branch-through is + /// a branch from a scope protected by this (normal) cleanup to an + /// enclosing scope other than the immediately-enclosing normal + /// cleanup scope. + /// + /// In the following example, the branch through B's scope is a + /// branch-through, while the branch through A's scope is a + /// branch-after: + /// for (;;) { A a; B b; break; } + /// + /// All branch-throughs have a common destination out of the + /// cleanup, one possibly shared with the fall-through. Therefore + /// branch-throughs usually don't force a switch after the cleanup. + /// + /// \return true if the branch-through was new to this scope + bool addBranchThrough(llvm::BasicBlock *Block) { + return getExtInfo().Branches.insert(Block); + } -public: - static size_t getSize() { return sizeof(EHCleanupScope); } + /// Determines if this cleanup scope has any branch throughs. + bool hasBranchThroughs() const { + if (!ExtInfo) return false; + return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size()); + } - EHCleanupScope(unsigned FixupDepth, - EHScopeStack::stable_iterator EnclosingNormal, - EHScopeStack::stable_iterator EnclosingEH, - llvm::BasicBlock *NormalEntry, llvm::BasicBlock *NormalExit, - llvm::BasicBlock *EHEntry, llvm::BasicBlock *EHExit) - : EHScope(Cleanup), FixupDepth(FixupDepth), - EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH), - NormalEntry(NormalEntry), NormalExit(NormalExit), - EHEntry(EHEntry), EHExit(EHExit) { - assert((NormalEntry != 0) == (NormalExit != 0)); - assert((EHEntry != 0) == (EHExit != 0)); + // Same stuff, only for EH branches instead of normal branches. + // It's quite possible that we could find a better representation + // for this. + + bool hasEHBranches() const { return ExtInfo && !ExtInfo->EHBranches.empty(); } + void addEHBranchAfter(llvm::ConstantInt *Index, + llvm::BasicBlock *Block) { + struct ExtInfo &ExtInfo = getExtInfo(); + if (ExtInfo.EHBranches.insert(Block)) + ExtInfo.EHBranchAfters.push_back(std::make_pair(Block, Index)); } - bool isNormalCleanup() const { return NormalEntry != 0; } - bool isEHCleanup() const { return EHEntry != 0; } + unsigned getNumEHBranchAfters() const { + return ExtInfo ? ExtInfo->EHBranchAfters.size() : 0; + } - llvm::BasicBlock *getNormalEntry() const { return NormalEntry; } - llvm::BasicBlock *getNormalExit() const { return NormalExit; } - llvm::BasicBlock *getEHEntry() const { return EHEntry; } - llvm::BasicBlock *getEHExit() const { return EHExit; } - unsigned getFixupDepth() const { return FixupDepth; } - EHScopeStack::stable_iterator getEnclosingNormalCleanup() const { - return EnclosingNormal; + llvm::BasicBlock *getEHBranchAfterBlock(unsigned I) const { + assert(I < getNumEHBranchAfters()); + return ExtInfo->EHBranchAfters[I].first; } - EHScopeStack::stable_iterator getEnclosingEHCleanup() const { - return EnclosingEH; + + llvm::ConstantInt *getEHBranchAfterIndex(unsigned I) const { + assert(I < getNumEHBranchAfters()); + return ExtInfo->EHBranchAfters[I].second; + } + + bool addEHBranchThrough(llvm::BasicBlock *Block) { + return getExtInfo().EHBranches.insert(Block); + } + + bool hasEHBranchThroughs() const { + if (!ExtInfo) return false; + return (ExtInfo->EHBranchAfters.size() != ExtInfo->EHBranches.size()); } static bool classof(const EHScope *Scope) { - return Scope->getKind() == Cleanup; + return (Scope->getKind() == Cleanup); } }; @@ -310,10 +447,13 @@ public: /// An exceptions scope which calls std::terminate if any exception /// reaches it. class EHTerminateScope : public EHScope { + unsigned DestIndex : BitsRemaining; public: - EHTerminateScope() : EHScope(Terminate) {} + EHTerminateScope(unsigned Index) : EHScope(Terminate), DestIndex(Index) {} static size_t getSize() { return sizeof(EHTerminateScope); } + unsigned getDestIndex() const { return DestIndex; } + static bool classof(const EHScope *Scope) { return Scope->getKind() == Terminate; } @@ -348,13 +488,9 @@ public: static_cast(get())->getNumFilters()); break; - case EHScope::LazyCleanup: - Ptr += static_cast(get()) - ->getAllocatedSize(); - break; - case EHScope::Cleanup: - Ptr += EHCleanupScope::getSize(); + Ptr += static_cast(get()) + ->getAllocatedSize(); break; case EHScope::Terminate: @@ -377,6 +513,9 @@ public: return copy; } + bool encloses(iterator other) const { return Ptr >= other.Ptr; } + bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; } + bool operator==(iterator other) const { return Ptr == other.Ptr; } bool operator!=(iterator other) const { return Ptr != other.Ptr; } }; @@ -396,6 +535,8 @@ inline void EHScopeStack::popCatch() { StartOfData += EHCatchScope::getSizeForNumHandlers( cast(*begin()).getNumHandlers()); + if (empty()) NextEHDestIndex = FirstEHDestIndex; + assert(CatchDepth > 0 && "mismatched catch/terminate push/pop"); CatchDepth--; } @@ -406,6 +547,8 @@ inline void EHScopeStack::popTerminate() { assert(isa(*begin())); StartOfData += EHTerminateScope::getSize(); + if (empty()) NextEHDestIndex = FirstEHDestIndex; + assert(CatchDepth > 0 && "mismatched catch/terminate push/pop"); CatchDepth--; } @@ -422,6 +565,28 @@ EHScopeStack::stabilize(iterator ir) const { return stable_iterator(EndOfBuffer - ir.Ptr); } +inline EHScopeStack::stable_iterator +EHScopeStack::getInnermostActiveNormalCleanup() const { + for (EHScopeStack::stable_iterator + I = getInnermostNormalCleanup(), E = stable_end(); I != E; ) { + EHCleanupScope &S = cast(*find(I)); + if (S.isActive()) return I; + I = S.getEnclosingNormalCleanup(); + } + return stable_end(); +} + +inline EHScopeStack::stable_iterator +EHScopeStack::getInnermostActiveEHCleanup() const { + for (EHScopeStack::stable_iterator + I = getInnermostEHCleanup(), E = stable_end(); I != E; ) { + EHCleanupScope &S = cast(*find(I)); + if (S.isActive()) return I; + I = S.getEnclosingEHCleanup(); + } + return stable_end(); +} + } } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 43bab9f..3750ab8 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -14,6 +14,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "CGCall.h" +#include "CGCXXABI.h" #include "CGRecordLayout.h" #include "CGObjCRuntime.h" #include "clang/AST/ASTContext.h" @@ -65,22 +66,12 @@ llvm::AllocaInst *CodeGenFunction::CreateMemTemp(QualType Ty, /// EvaluateExprAsBool - Perform the usual unary conversions on the specified /// expression and compare the result against zero, returning an Int1Ty value. llvm::Value *CodeGenFunction::EvaluateExprAsBool(const Expr *E) { - QualType BoolTy = getContext().BoolTy; - if (E->getType()->isMemberFunctionPointerType()) { - LValue LV = EmitAggExprToLValue(E); - - // Get the pointer. - llvm::Value *FuncPtr = Builder.CreateStructGEP(LV.getAddress(), 0, - "src.ptr"); - FuncPtr = Builder.CreateLoad(FuncPtr); - - llvm::Value *IsNotNull = - Builder.CreateICmpNE(FuncPtr, - llvm::Constant::getNullValue(FuncPtr->getType()), - "tobool"); - - return IsNotNull; + if (const MemberPointerType *MPT = E->getType()->getAs()) { + llvm::Value *MemPtr = EmitScalarExpr(E); + return CGM.getCXXABI().EmitMemberPointerIsNotNull(CGF, MemPtr, MPT); } + + QualType BoolTy = getContext().BoolTy; if (!E->getType()->isAnyComplexType()) return EmitScalarConversion(EmitScalarExpr(E), E->getType(), BoolTy); @@ -130,7 +121,7 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E, EmitAggExpr(E, Location, IsLocationVolatile, /*Ignore*/ false, IsInit); else { RValue RV = RValue::get(EmitScalarExpr(E, /*Ignore*/ false)); - LValue LV = LValue::MakeAddr(Location, MakeQualifiers(E->getType())); + LValue LV = MakeAddrLValue(Location, E->getType()); EmitStoreThroughLValue(RV, LV, E->getType()); } } @@ -142,17 +133,14 @@ struct SubobjectAdjustment { union { struct { - const CXXBaseSpecifierArray *BasePath; + const CastExpr *BasePath; const CXXRecordDecl *DerivedClass; } DerivedToBase; - struct { - FieldDecl *Field; - unsigned CVRQualifiers; - } Field; + FieldDecl *Field; }; - SubobjectAdjustment(const CXXBaseSpecifierArray *BasePath, + SubobjectAdjustment(const CastExpr *BasePath, const CXXRecordDecl *DerivedClass) : Kind(DerivedToBaseAdjustment) { @@ -160,11 +148,10 @@ struct SubobjectAdjustment { DerivedToBase.DerivedClass = DerivedClass; } - SubobjectAdjustment(FieldDecl *Field, unsigned CVRQualifiers) - : Kind(FieldAdjustment) + SubobjectAdjustment(FieldDecl *Field) + : Kind(FieldAdjustment) { - this->Field.Field = Field; - this->Field.CVRQualifiers = CVRQualifiers; + this->Field = Field; } }; @@ -174,7 +161,7 @@ CreateReferenceTemporary(CodeGenFunction& CGF, QualType Type, if (const VarDecl *VD = dyn_cast_or_null(InitializedDecl)) { if (VD->hasGlobalStorage()) { llvm::SmallString<256> Name; - CGF.CGM.getMangleContext().mangleReferenceTemporary(VD, Name); + CGF.CGM.getCXXABI().getMangleContext().mangleReferenceTemporary(VD, Name); const llvm::Type *RefTempTy = CGF.ConvertTypeForMem(Type); @@ -230,18 +217,17 @@ EmitExprForReferenceBinding(CodeGenFunction& CGF, const Expr* E, } if (const CastExpr *CE = dyn_cast(E)) { - if ((CE->getCastKind() == CastExpr::CK_DerivedToBase || - CE->getCastKind() == CastExpr::CK_UncheckedDerivedToBase) && + if ((CE->getCastKind() == CK_DerivedToBase || + CE->getCastKind() == CK_UncheckedDerivedToBase) && E->getType()->isRecordType()) { E = CE->getSubExpr(); CXXRecordDecl *Derived = cast(E->getType()->getAs()->getDecl()); - Adjustments.push_back(SubobjectAdjustment(&CE->getBasePath(), - Derived)); + Adjustments.push_back(SubobjectAdjustment(CE, Derived)); continue; } - if (CE->getCastKind() == CastExpr::CK_NoOp) { + if (CE->getCastKind() == CK_NoOp) { E = CE->getSubExpr(); continue; } @@ -250,8 +236,7 @@ EmitExprForReferenceBinding(CodeGenFunction& CGF, const Expr* E, ME->getBase()->getType()->isRecordType()) { if (FieldDecl *Field = dyn_cast(ME->getMemberDecl())) { E = ME->getBase(); - Adjustments.push_back(SubobjectAdjustment(Field, - E->getType().getCVRQualifiers())); + Adjustments.push_back(SubobjectAdjustment(Field)); continue; } } @@ -291,14 +276,14 @@ EmitExprForReferenceBinding(CodeGenFunction& CGF, const Expr* E, Object = CGF.GetAddressOfBaseClass(Object, Adjustment.DerivedToBase.DerivedClass, - *Adjustment.DerivedToBase.BasePath, + Adjustment.DerivedToBase.BasePath->path_begin(), + Adjustment.DerivedToBase.BasePath->path_end(), /*NullCheckValue=*/false); break; case SubobjectAdjustment::FieldAdjustment: { - unsigned CVR = Adjustment.Field.CVRQualifiers; LValue LV = - CGF.EmitLValueForField(Object, Adjustment.Field.Field, CVR); + CGF.EmitLValueForField(Object, Adjustment.Field, 0); if (LV.isSimple()) { Object = LV.getAddress(); break; @@ -306,11 +291,11 @@ EmitExprForReferenceBinding(CodeGenFunction& CGF, const Expr* E, // For non-simple lvalues, we actually have to create a copy of // the object we're binding to. - QualType T = Adjustment.Field.Field->getType().getNonReferenceType() - .getUnqualifiedType(); + QualType T = Adjustment.Field->getType().getNonReferenceType() + .getUnqualifiedType(); Object = CreateReferenceTemporary(CGF, T, InitializedDecl); - LValue TempLV = LValue::MakeAddr(Object, - Qualifiers::fromCVRMask(CVR)); + LValue TempLV = CGF.MakeAddrLValue(Object, + Adjustment.Field->getType()); CGF.EmitStoreThroughLValue(CGF.EmitLoadOfLValue(LV, T), TempLV, T); break; } @@ -330,9 +315,12 @@ EmitExprForReferenceBinding(CodeGenFunction& CGF, const Expr* E, ReferenceTemporary = CreateReferenceTemporary(CGF, E->getType(), InitializedDecl); + + unsigned Alignment = + CGF.getContext().getTypeAlignInChars(E->getType()).getQuantity(); if (RV.isScalar()) CGF.EmitStoreOfScalar(RV.getScalarVal(), ReferenceTemporary, - /*Volatile=*/false, E->getType()); + /*Volatile=*/false, Alignment, E->getType()); else CGF.StoreComplexToAddr(RV.getComplexVal(), ReferenceTemporary, /*Volatile=*/false); @@ -347,7 +335,6 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, llvm::Value *Value = EmitExprForReferenceBinding(*this, E, ReferenceTemporary, ReferenceTemporaryDtor, InitializedDecl); - if (!ReferenceTemporaryDtor) return RValue::get(Value); @@ -362,16 +349,8 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E, return RValue::get(Value); } } - - CleanupBlock Cleanup(*this, NormalCleanup); - EmitCXXDestructorCall(ReferenceTemporaryDtor, Dtor_Complete, - /*ForVirtualBase=*/false, ReferenceTemporary); - - if (Exceptions) { - Cleanup.beginEHCleanup(); - EmitCXXDestructorCall(ReferenceTemporaryDtor, Dtor_Complete, - /*ForVirtualBase=*/false, ReferenceTemporary); - } + + PushDestructorCleanup(ReferenceTemporaryDtor, ReferenceTemporary); return RValue::get(Value); } @@ -462,9 +441,12 @@ RValue CodeGenFunction::GetUndefRValue(QualType Ty) { return RValue::getComplex(std::make_pair(U, U)); } + // If this is a use of an undefined aggregate type, the aggregate must have an + // identifiable address. Just because the contents of the value are undefined + // doesn't mean that the address can't be taken and compared. if (hasAggregateLLVMType(Ty)) { - const llvm::Type *LTy = llvm::PointerType::getUnqual(ConvertType(Ty)); - return RValue::getAggregate(llvm::UndefValue::get(LTy)); + llvm::Value *DestPtr = CreateMemTemp(Ty, "undef.agg.tmp"); + return RValue::getAggregate(DestPtr); } return RValue::get(llvm::UndefValue::get(ConvertType(Ty))); @@ -480,8 +462,7 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E, const char *Name) { ErrorUnsupported(E, Name); llvm::Type *Ty = llvm::PointerType::getUnqual(ConvertType(E->getType())); - return LValue::MakeAddr(llvm::UndefValue::get(Ty), - MakeQualifiers(E->getType())); + return MakeAddrLValue(llvm::UndefValue::get(Ty), E->getType()); } LValue CodeGenFunction::EmitCheckedLValue(const Expr *E) { @@ -590,10 +571,12 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { } llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, - QualType Ty) { + unsigned Alignment, QualType Ty) { llvm::LoadInst *Load = Builder.CreateLoad(Addr, "tmp"); if (Volatile) Load->setVolatile(true); + if (Alignment) + Load->setAlignment(Alignment); // Bool can have different representation in memory than in registers. llvm::Value *V = Load; @@ -605,14 +588,18 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, } void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr, - bool Volatile, QualType Ty) { + bool Volatile, unsigned Alignment, + QualType Ty) { if (Ty->isBooleanType()) { // Bool can have different representation in memory than in registers. const llvm::PointerType *DstPtr = cast(Addr->getType()); Value = Builder.CreateIntCast(Value, DstPtr->getElementType(), false); } - Builder.CreateStore(Value, Addr, Volatile); + + llvm::StoreInst *Store = Builder.CreateStore(Value, Addr, Volatile); + if (Alignment) + Store->setAlignment(Alignment); } /// EmitLoadOfLValue - Given an expression that represents a value lvalue, this @@ -628,18 +615,15 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, QualType ExprType) { if (LV.isSimple()) { llvm::Value *Ptr = LV.getAddress(); - const llvm::Type *EltTy = - cast(Ptr->getType())->getElementType(); - // Simple scalar l-value. - // - // FIXME: We shouldn't have to use isSingleValueType here. - if (EltTy->isSingleValueType()) - return RValue::get(EmitLoadOfScalar(Ptr, LV.isVolatileQualified(), - ExprType)); + // Functions are l-values that don't require loading. + if (ExprType->isFunctionType()) + return RValue::get(Ptr); + + // Everything needs a load. + return RValue::get(EmitLoadOfScalar(Ptr, LV.isVolatileQualified(), + LV.getAlignment(), ExprType)); - assert(ExprType->isFunctionType() && "Unknown scalar value"); - return RValue::get(Ptr); } if (LV.isVectorElt()) { @@ -836,8 +820,10 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, llvm::Value *BytesBetween = Builder.CreateSub(LHS, RHS, "ivar.offset"); CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, dst, BytesBetween); - } else if (Dst.isGlobalObjCRef()) - CGM.getObjCRuntime().EmitObjCGlobalAssign(*this, src, LvalueDst); + } else if (Dst.isGlobalObjCRef()) { + CGM.getObjCRuntime().EmitObjCGlobalAssign(*this, src, LvalueDst, + Dst.isThreadLocalRef()); + } else CGM.getObjCRuntime().EmitObjCStrongCastAssign(*this, src, LvalueDst); return; @@ -845,7 +831,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, assert(Src.isScalar() && "Can't emit an agg store with this method"); EmitStoreOfScalar(Src.getScalarVal(), Dst.getAddress(), - Dst.isVolatileQualified(), Ty); + Dst.isVolatileQualified(), Dst.getAlignment(), Ty); } void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, @@ -1045,20 +1031,22 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, return; if (isa(E)) { - LV.SetObjCIvar(LV, true); + LV.setObjCIvar(true); ObjCIvarRefExpr *Exp = cast(const_cast(E)); LV.setBaseIvarExp(Exp->getBase()); - LV.SetObjCArray(LV, E->getType()->isArrayType()); + LV.setObjCArray(E->getType()->isArrayType()); return; } if (const DeclRefExpr *Exp = dyn_cast(E)) { if (const VarDecl *VD = dyn_cast(Exp->getDecl())) { if ((VD->isBlockVarDecl() && !VD->hasLocalStorage()) || - VD->isFileVarDecl()) - LV.SetGlobalObjCRef(LV, true); + VD->isFileVarDecl()) { + LV.setGlobalObjCRef(true); + LV.setThreadLocalRef(VD->isThreadSpecified()); + } } - LV.SetObjCArray(LV, E->getType()->isArrayType()); + LV.setObjCArray(E->getType()->isArrayType()); return; } @@ -1076,7 +1064,7 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, if (ExpTy->isPointerType()) ExpTy = ExpTy->getAs()->getPointeeType(); if (ExpTy->isRecordType()) - LV.SetObjCIvar(LV, false); + LV.setObjCIvar(false); } return; } @@ -1095,11 +1083,11 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, if (LV.isObjCIvar() && !LV.isObjCArray()) // Using array syntax to assigning to what an ivar points to is not // same as assigning to the ivar itself. {id *Names;} Names[i] = 0; - LV.SetObjCIvar(LV, false); + LV.setObjCIvar(false); else if (LV.isGlobalObjCRef() && !LV.isObjCArray()) // Using array syntax to assigning to what global points to is not // same as assigning to the global itself. {id *G;} G[i] = 0; - LV.SetGlobalObjCRef(LV, false); + LV.setGlobalObjCRef(false); return; } @@ -1107,7 +1095,7 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, setObjCGCLValueClass(Ctx, Exp->getBase(), LV); // We don't know if member is an 'ivar', but this flag is looked at // only in the context of LV.isObjCIvar(). - LV.SetObjCArray(LV, E->getType()->isArrayType()); + LV.setObjCArray(E->getType()->isArrayType()); return; } } @@ -1120,7 +1108,8 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF, llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD); if (VD->getType()->isReferenceType()) V = CGF.Builder.CreateLoad(V, "tmp"); - LValue LV = LValue::MakeAddr(V, CGF.MakeQualifiers(E->getType())); + unsigned Alignment = CGF.getContext().getDeclAlign(VD).getQuantity(); + LValue LV = CGF.MakeAddrLValue(V, E->getType(), Alignment); setObjCGCLValueClass(CGF.getContext(), E, LV); return LV; } @@ -1140,20 +1129,18 @@ static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF, V = CGF.Builder.CreateBitCast(V, CGF.ConvertType(NoProtoType), "tmp"); } } - return LValue::MakeAddr(V, CGF.MakeQualifiers(E->getType())); + unsigned Alignment = CGF.getContext().getDeclAlign(FD).getQuantity(); + return CGF.MakeAddrLValue(V, E->getType(), Alignment); } LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { const NamedDecl *ND = E->getDecl(); + unsigned Alignment = CGF.getContext().getDeclAlign(ND).getQuantity(); if (ND->hasAttr()) { const ValueDecl* VD = cast(ND); llvm::Constant *Aliasee = CGM.GetWeakRefReference(VD); - - Qualifiers Quals = MakeQualifiers(E->getType()); - LValue LV = LValue::MakeAddr(Aliasee, Quals); - - return LV; + return MakeAddrLValue(Aliasee, E->getType(), Alignment); } if (const VarDecl *VD = dyn_cast(ND)) { @@ -1170,11 +1157,6 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { V = CGM.getStaticLocalDeclAddress(VD); assert(V && "DeclRefExpr not entered in LocalDeclMap?"); - Qualifiers Quals = MakeQualifiers(E->getType()); - // local variables do not get their gc attribute set. - // local static? - if (NonGCable) Quals.removeObjCGCAttr(); - if (VD->hasAttr()) { V = Builder.CreateStructGEP(V, 1, "forwarding"); V = Builder.CreateLoad(V); @@ -1183,21 +1165,31 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { } if (VD->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); - LValue LV = LValue::MakeAddr(V, Quals); - LValue::SetObjCNonGC(LV, NonGCable); + + LValue LV = MakeAddrLValue(V, E->getType(), Alignment); + if (NonGCable) { + LV.getQuals().removeObjCGCAttr(); + LV.setNonGC(true); + } setObjCGCLValueClass(getContext(), E, LV); return LV; } + // If we're emitting an instance method as an independent lvalue, + // we're actually emitting a member pointer. + if (const CXXMethodDecl *MD = dyn_cast(ND)) + if (MD->isInstance()) { + llvm::Value *V = CGM.getCXXABI().EmitMemberPointer(MD); + return MakeAddrLValue(V, MD->getType(), Alignment); + } if (const FunctionDecl *FD = dyn_cast(ND)) return EmitFunctionDeclLValue(*this, E, FD); - // FIXME: the qualifier check does not seem sufficient here - if (E->getQualifier()) { - const FieldDecl *FD = cast(ND); - llvm::Value *V = CGM.EmitPointerToDataMember(FD); - - return LValue::MakeAddr(V, MakeQualifiers(FD->getType())); + // If we're emitting a field as an independent lvalue, we're + // actually emitting a member pointer. + if (const FieldDecl *FD = dyn_cast(ND)) { + llvm::Value *V = CGM.getCXXABI().EmitMemberPointer(FD); + return MakeAddrLValue(V, FD->getType(), Alignment); } assert(false && "Unhandled DeclRefExpr"); @@ -1208,25 +1200,26 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { } LValue CodeGenFunction::EmitBlockDeclRefLValue(const BlockDeclRefExpr *E) { - return LValue::MakeAddr(GetAddrOfBlockDecl(E), MakeQualifiers(E->getType())); + unsigned Alignment = + CGF.getContext().getDeclAlign(E->getDecl()).getQuantity(); + return MakeAddrLValue(GetAddrOfBlockDecl(E), E->getType(), Alignment); } LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { // __extension__ doesn't affect lvalue-ness. - if (E->getOpcode() == UnaryOperator::Extension) + if (E->getOpcode() == UO_Extension) return EmitLValue(E->getSubExpr()); QualType ExprTy = getContext().getCanonicalType(E->getSubExpr()->getType()); switch (E->getOpcode()) { default: assert(0 && "Unknown unary operator lvalue!"); - case UnaryOperator::Deref: { + case UO_Deref: { QualType T = E->getSubExpr()->getType()->getPointeeType(); assert(!T.isNull() && "CodeGenFunction::EmitUnaryOpLValue: Illegal type"); - Qualifiers Quals = MakeQualifiers(T); - Quals.setAddressSpace(ExprTy.getAddressSpace()); + LValue LV = MakeAddrLValue(EmitScalarExpr(E->getSubExpr()), T); + LV.getQuals().setAddressSpace(ExprTy.getAddressSpace()); - LValue LV = LValue::MakeAddr(EmitScalarExpr(E->getSubExpr()), Quals); // We should not generate __weak write barrier on indirect reference // of a pointer to object; as in void foo (__weak id *param); *param = 0; // But, we continue to generate __strong write barrier on indirect write @@ -1234,21 +1227,21 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { if (getContext().getLangOptions().ObjC1 && getContext().getLangOptions().getGCMode() != LangOptions::NonGC && LV.isObjCWeak()) - LValue::SetObjCNonGC(LV, !E->isOBJCGCCandidate(getContext())); + LV.setNonGC(!E->isOBJCGCCandidate(getContext())); return LV; } - case UnaryOperator::Real: - case UnaryOperator::Imag: { + case UO_Real: + case UO_Imag: { LValue LV = EmitLValue(E->getSubExpr()); - unsigned Idx = E->getOpcode() == UnaryOperator::Imag; - return LValue::MakeAddr(Builder.CreateStructGEP(LV.getAddress(), + unsigned Idx = E->getOpcode() == UO_Imag; + return MakeAddrLValue(Builder.CreateStructGEP(LV.getAddress(), Idx, "idx"), - MakeQualifiers(ExprTy)); + ExprTy); } - case UnaryOperator::PreInc: - case UnaryOperator::PreDec: { + case UO_PreInc: + case UO_PreDec: { LValue LV = EmitLValue(E->getSubExpr()); - bool isInc = E->getOpcode() == UnaryOperator::PreInc; + bool isInc = E->getOpcode() == UO_PreInc; if (E->getType()->isAnyComplexType()) EmitComplexPrePostIncDec(E, LV, isInc, true/*isPre*/); @@ -1260,53 +1253,56 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { } LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) { - return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromLiteral(E), - Qualifiers()); + return MakeAddrLValue(CGM.GetAddrOfConstantStringFromLiteral(E), + E->getType()); } LValue CodeGenFunction::EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E) { - return LValue::MakeAddr(CGM.GetAddrOfConstantStringFromObjCEncode(E), - Qualifiers()); + return MakeAddrLValue(CGM.GetAddrOfConstantStringFromObjCEncode(E), + E->getType()); } -LValue CodeGenFunction::EmitPredefinedFunctionName(unsigned Type) { - std::string GlobalVarName; +LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { + switch (E->getIdentType()) { + default: + return EmitUnsupportedLValue(E, "predefined expression"); - switch (Type) { - default: assert(0 && "Invalid type"); case PredefinedExpr::Func: - GlobalVarName = "__func__."; - break; case PredefinedExpr::Function: - GlobalVarName = "__FUNCTION__."; - break; - case PredefinedExpr::PrettyFunction: - GlobalVarName = "__PRETTY_FUNCTION__."; - break; - } + case PredefinedExpr::PrettyFunction: { + unsigned Type = E->getIdentType(); + std::string GlobalVarName; + + switch (Type) { + default: assert(0 && "Invalid type"); + case PredefinedExpr::Func: + GlobalVarName = "__func__."; + break; + case PredefinedExpr::Function: + GlobalVarName = "__FUNCTION__."; + break; + case PredefinedExpr::PrettyFunction: + GlobalVarName = "__PRETTY_FUNCTION__."; + break; + } - llvm::StringRef FnName = CurFn->getName(); - if (FnName.startswith("\01")) - FnName = FnName.substr(1); - GlobalVarName += FnName; + llvm::StringRef FnName = CurFn->getName(); + if (FnName.startswith("\01")) + FnName = FnName.substr(1); + GlobalVarName += FnName; - std::string FunctionName = - PredefinedExpr::ComputeName((PredefinedExpr::IdentType)Type, CurCodeDecl); + const Decl *CurDecl = CurCodeDecl; + if (CurDecl == 0) + CurDecl = getContext().getTranslationUnitDecl(); - llvm::Constant *C = - CGM.GetAddrOfConstantCString(FunctionName, GlobalVarName.c_str()); - return LValue::MakeAddr(C, Qualifiers()); -} + std::string FunctionName = + PredefinedExpr::ComputeName((PredefinedExpr::IdentType)Type, CurDecl); -LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { - switch (E->getIdentType()) { - default: - return EmitUnsupportedLValue(E, "predefined expression"); - case PredefinedExpr::Func: - case PredefinedExpr::Function: - case PredefinedExpr::PrettyFunction: - return EmitPredefinedFunctionName(E->getIdentType()); + llvm::Constant *C = + CGM.GetAddrOfConstantCString(FunctionName, GlobalVarName.c_str()); + return MakeAddrLValue(C, E->getType()); + } } } @@ -1315,10 +1311,9 @@ llvm::BasicBlock *CodeGenFunction::getTrapBB() { // If we are not optimzing, don't collapse all calls to trap in the function // to the same call, that way, in the debugger they can see which operation - // did in fact fail. If we are optimizing, we collpase all call to trap down + // did in fact fail. If we are optimizing, we collapse all calls to trap down // to just one per function to save on codesize. - if (GCO.OptimizationLevel - && TrapBB) + if (GCO.OptimizationLevel && TrapBB) return TrapBB; llvm::BasicBlock *Cont = 0; @@ -1345,7 +1340,7 @@ llvm::BasicBlock *CodeGenFunction::getTrapBB() { static const Expr *isSimpleArrayDecayOperand(const Expr *E) { // If this isn't just an array->pointer decay, bail out. const CastExpr *CE = dyn_cast(E); - if (CE == 0 || CE->getCastKind() != CastExpr::CK_ArrayToPointerDecay) + if (CE == 0 || CE->getCastKind() != CK_ArrayToPointerDecay) return 0; // If this is a decay from variable width array, bail out. @@ -1382,7 +1377,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { if (CatchUndefined) { if (const ImplicitCastExpr *ICE = dyn_cast(E->getBase())){ if (const DeclRefExpr *DRE = dyn_cast(ICE->getSubExpr())) { - if (ICE->getCastKind() == CastExpr::CK_ArrayToPointerDecay) { + if (ICE->getCastKind() == CK_ArrayToPointerDecay) { if (const ConstantArrayType *CAT = getContext().getAsConstantArrayType(DRE->getType())) { llvm::APInt Size = CAT->getSize(); @@ -1454,13 +1449,12 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { assert(!T.isNull() && "CodeGenFunction::EmitArraySubscriptExpr(): Illegal base type"); - Qualifiers Quals = MakeQualifiers(T); - Quals.setAddressSpace(E->getBase()->getType().getAddressSpace()); + LValue LV = MakeAddrLValue(Address, T); + LV.getQuals().setAddressSpace(E->getBase()->getType().getAddressSpace()); - LValue LV = LValue::MakeAddr(Address, Quals); if (getContext().getLangOptions().ObjC1 && getContext().getLangOptions().getGCMode() != LangOptions::NonGC) { - LValue::SetObjCNonGC(LV, !E->isOBJCGCCandidate(getContext())); + LV.setNonGC(!E->isOBJCGCCandidate(getContext())); setObjCGCLValueClass(getContext(), E, LV); } return LV; @@ -1489,9 +1483,8 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { // it. llvm::Value *Ptr = EmitScalarExpr(E->getBase()); const PointerType *PT = E->getBase()->getType()->getAs(); - Qualifiers Quals = MakeQualifiers(PT->getPointeeType()); - Quals.removeObjCGCAttr(); - Base = LValue::MakeAddr(Ptr, Quals); + Base = MakeAddrLValue(Ptr, PT->getPointeeType()); + Base.getQuals().removeObjCGCAttr(); } else if (E->getBase()->isLvalue(getContext()) == Expr::LV_Valid) { // Otherwise, if the base is an lvalue ( as in the case of foo.x.x), // emit the base as an lvalue. @@ -1506,7 +1499,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { // Store the vector to memory (because LValue wants an address). llvm::Value *VecMem = CreateMemTemp(E->getBase()->getType()); Builder.CreateStore(Vec, VecMem); - Base = LValue::MakeAddr(VecMem, Qualifiers()); + Base = MakeAddrLValue(VecMem, E->getBase()->getType()); } // Encode the element access list into a vector of unsigned indices. @@ -1566,7 +1559,7 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { if (FieldDecl *Field = dyn_cast(ND)) { LValue LV = EmitLValueForField(BaseValue, Field, BaseQuals.getCVRQualifiers()); - LValue::SetObjCNonGC(LV, isNonGC); + LV.setNonGC(isNonGC); setObjCGCLValueClass(getContext(), E, LV); return LV; } @@ -1645,13 +1638,15 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue, if (Field->getType()->isReferenceType()) V = Builder.CreateLoad(V, "tmp"); - Qualifiers Quals = MakeQualifiers(Field->getType()); - Quals.addCVRQualifiers(CVRQualifiers); + unsigned Alignment = getContext().getDeclAlign(Field).getQuantity(); + LValue LV = MakeAddrLValue(V, Field->getType(), Alignment); + LV.getQuals().addCVRQualifiers(CVRQualifiers); + // __weak attribute on a field is ignored. - if (Quals.getObjCGCAttr() == Qualifiers::Weak) - Quals.removeObjCGCAttr(); + if (LV.getQuals().getObjCGCAttr() == Qualifiers::Weak) + LV.getQuals().removeObjCGCAttr(); - return LValue::MakeAddr(V, Quals); + return LV; } LValue @@ -1670,13 +1665,14 @@ CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value* BaseValue, assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs"); - return LValue::MakeAddr(V, MakeQualifiers(FieldType)); + unsigned Alignment = getContext().getDeclAlign(Field).getQuantity(); + return MakeAddrLValue(V, FieldType, Alignment); } LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr* E){ llvm::Value *DeclPtr = CreateMemTemp(E->getType(), ".compoundliteral"); const Expr* InitExpr = E->getInitializer(); - LValue Result = LValue::MakeAddr(DeclPtr, MakeQualifiers(E->getType())); + LValue Result = MakeAddrLValue(DeclPtr, E->getType()); EmitAnyExprToMem(InitExpr, DeclPtr, /*Volatile*/ false); @@ -1729,7 +1725,7 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) { EmitBlock(ContBlock); Temp = Builder.CreateLoad(Temp, "lv"); - return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); + return MakeAddrLValue(Temp, E->getType()); } // ?: here should be an aggregate. @@ -1749,35 +1745,65 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) { /// cast from scalar to union. LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { switch (E->getCastKind()) { - default: + case CK_ToVoid: return EmitUnsupportedLValue(E, "unexpected cast lvalue"); - - case CastExpr::CK_Dynamic: { + + case CK_NoOp: + if (E->getSubExpr()->Classify(getContext()).getKind() + != Expr::Classification::CL_PRValue) { + LValue LV = EmitLValue(E->getSubExpr()); + if (LV.isPropertyRef() || LV.isKVCRef()) { + QualType QT = E->getSubExpr()->getType(); + RValue RV = + LV.isPropertyRef() ? EmitLoadOfPropertyRefLValue(LV, QT) + : EmitLoadOfKVCRefLValue(LV, QT); + assert(!RV.isScalar() && "EmitCastLValue-scalar cast of property ref"); + llvm::Value *V = RV.getAggregateAddr(); + return MakeAddrLValue(V, QT); + } + return LV; + } + // Fall through to synthesize a temporary. + + case CK_Unknown: + case CK_BitCast: + case CK_ArrayToPointerDecay: + case CK_FunctionToPointerDecay: + case CK_NullToMemberPointer: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_VectorSplat: + case CK_IntegralCast: + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + case CK_FloatingCast: + case CK_DerivedToBaseMemberPointer: + case CK_BaseToDerivedMemberPointer: + case CK_MemberPointerToBoolean: + case CK_AnyPointerToBlockPointerCast: { + // These casts only produce lvalues when we're binding a reference to a + // temporary realized from a (converted) pure rvalue. Emit the expression + // as a value, copy it into a temporary, and return an lvalue referring to + // that temporary. + llvm::Value *V = CreateMemTemp(E->getType(), "ref.temp"); + EmitAnyExprToMem(E, V, false, false); + return MakeAddrLValue(V, E->getType()); + } + + case CK_Dynamic: { LValue LV = EmitLValue(E->getSubExpr()); llvm::Value *V = LV.getAddress(); const CXXDynamicCastExpr *DCE = cast(E); - return LValue::MakeAddr(EmitDynamicCast(V, DCE), - MakeQualifiers(E->getType())); + return MakeAddrLValue(EmitDynamicCast(V, DCE), E->getType()); } - case CastExpr::CK_NoOp: { - LValue LV = EmitLValue(E->getSubExpr()); - if (LV.isPropertyRef()) { - QualType QT = E->getSubExpr()->getType(); - RValue RV = EmitLoadOfPropertyRefLValue(LV, QT); - assert(!RV.isScalar() && "EmitCastLValue - scalar cast of property ref"); - llvm::Value *V = RV.getAggregateAddr(); - return LValue::MakeAddr(V, MakeQualifiers(QT)); - } - return LV; - } - case CastExpr::CK_ConstructorConversion: - case CastExpr::CK_UserDefinedConversion: - case CastExpr::CK_AnyPointerToObjCPointerCast: + case CK_ConstructorConversion: + case CK_UserDefinedConversion: + case CK_AnyPointerToObjCPointerCast: return EmitLValue(E->getSubExpr()); - case CastExpr::CK_UncheckedDerivedToBase: - case CastExpr::CK_DerivedToBase: { + case CK_UncheckedDerivedToBase: + case CK_DerivedToBase: { const RecordType *DerivedClassTy = E->getSubExpr()->getType()->getAs(); CXXRecordDecl *DerivedClassDecl = @@ -1785,8 +1811,11 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { LValue LV = EmitLValue(E->getSubExpr()); llvm::Value *This; - if (LV.isPropertyRef()) { - RValue RV = EmitLoadOfPropertyRefLValue(LV, E->getSubExpr()->getType()); + if (LV.isPropertyRef() || LV.isKVCRef()) { + QualType QT = E->getSubExpr()->getType(); + RValue RV = + LV.isPropertyRef() ? EmitLoadOfPropertyRefLValue(LV, QT) + : EmitLoadOfKVCRefLValue(LV, QT); assert (!RV.isScalar() && "EmitCastLValue"); This = RV.getAggregateAddr(); } @@ -1796,13 +1825,14 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { // Perform the derived-to-base conversion llvm::Value *Base = GetAddressOfBaseClass(This, DerivedClassDecl, - E->getBasePath(), /*NullCheckValue=*/false); + E->path_begin(), E->path_end(), + /*NullCheckValue=*/false); - return LValue::MakeAddr(Base, MakeQualifiers(E->getType())); + return MakeAddrLValue(Base, E->getType()); } - case CastExpr::CK_ToUnion: + case CK_ToUnion: return EmitAggExprToLValue(E); - case CastExpr::CK_BaseToDerived: { + case CK_BaseToDerived: { const RecordType *DerivedClassTy = E->getType()->getAs(); CXXRecordDecl *DerivedClassDecl = cast(DerivedClassTy->getDecl()); @@ -1812,26 +1842,36 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { // Perform the base-to-derived conversion llvm::Value *Derived = GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl, - E->getBasePath(),/*NullCheckValue=*/false); + E->path_begin(), E->path_end(), + /*NullCheckValue=*/false); - return LValue::MakeAddr(Derived, MakeQualifiers(E->getType())); + return MakeAddrLValue(Derived, E->getType()); } - case CastExpr::CK_LValueBitCast: { + case CK_LValueBitCast: { // This must be a reinterpret_cast (or c-style equivalent). const ExplicitCastExpr *CE = cast(E); LValue LV = EmitLValue(E->getSubExpr()); llvm::Value *V = Builder.CreateBitCast(LV.getAddress(), ConvertType(CE->getTypeAsWritten())); - return LValue::MakeAddr(V, MakeQualifiers(E->getType())); + return MakeAddrLValue(V, E->getType()); } + case CK_ObjCObjectLValueCast: { + LValue LV = EmitLValue(E->getSubExpr()); + QualType ToType = getContext().getLValueReferenceType(E->getType()); + llvm::Value *V = Builder.CreateBitCast(LV.getAddress(), + ConvertType(ToType)); + return MakeAddrLValue(V, E->getType()); } + } + + llvm_unreachable("Unhandled lvalue cast kind?"); } LValue CodeGenFunction::EmitNullInitializationLValue( const CXXScalarValueInitExpr *E) { QualType Ty = E->getType(); - LValue LV = LValue::MakeAddr(CreateMemTemp(Ty), MakeQualifiers(Ty)); + LValue LV = MakeAddrLValue(CreateMemTemp(Ty), Ty); EmitNullInitialization(LV.getAddress(), Ty); return LV; } @@ -1881,28 +1921,26 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { // Comma expressions just emit their LHS then their RHS as an l-value. - if (E->getOpcode() == BinaryOperator::Comma) { + if (E->getOpcode() == BO_Comma) { EmitAnyExpr(E->getLHS()); EnsureInsertPoint(); return EmitLValue(E->getRHS()); } - if (E->getOpcode() == BinaryOperator::PtrMemD || - E->getOpcode() == BinaryOperator::PtrMemI) + if (E->getOpcode() == BO_PtrMemD || + E->getOpcode() == BO_PtrMemI) return EmitPointerToDataMemberBinaryExpr(E); // Can only get l-value for binary operator expressions which are a // simple assignment of aggregate type. - if (E->getOpcode() != BinaryOperator::Assign) + if (E->getOpcode() != BO_Assign) return EmitUnsupportedLValue(E, "binary l-value expression"); if (!hasAggregateLLVMType(E->getType())) { // Emit the LHS as an l-value. LValue LV = EmitLValue(E->getLHS()); - - llvm::Value *RHS = EmitScalarExpr(E->getRHS()); - EmitStoreOfScalar(RHS, LV.getAddress(), LV.isVolatileQualified(), - E->getType()); + // Store the value through the l-value. + EmitStoreThroughLValue(EmitAnyExpr(E->getRHS()), LV, E->getType()); return LV; } @@ -1913,13 +1951,13 @@ LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E) { RValue RV = EmitCallExpr(E); if (!RV.isScalar()) - return LValue::MakeAddr(RV.getAggregateAddr(),MakeQualifiers(E->getType())); + return MakeAddrLValue(RV.getAggregateAddr(), E->getType()); assert(E->getCallReturnType()->isReferenceType() && "Can't have a scalar return unless the return type is a " "reference type!"); - return LValue::MakeAddr(RV.getScalarVal(), MakeQualifiers(E->getType())); + return MakeAddrLValue(RV.getScalarVal(), E->getType()); } LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) { @@ -1930,13 +1968,12 @@ LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) { LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { llvm::Value *Temp = CreateMemTemp(E->getType(), "tmp"); EmitCXXConstructExpr(Temp, E); - return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); + return MakeAddrLValue(Temp, E->getType()); } LValue CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) { - llvm::Value *Temp = EmitCXXTypeidExpr(E); - return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); + return MakeAddrLValue(EmitCXXTypeidExpr(E), E->getType()); } LValue @@ -1950,20 +1987,19 @@ LValue CodeGenFunction::EmitObjCMessageExprLValue(const ObjCMessageExpr *E) { RValue RV = EmitObjCMessageExpr(E); if (!RV.isScalar()) - return LValue::MakeAddr(RV.getAggregateAddr(), - MakeQualifiers(E->getType())); + return MakeAddrLValue(RV.getAggregateAddr(), E->getType()); assert(E->getMethodDecl()->getResultType()->isReferenceType() && "Can't have a scalar return unless the return type is a " "reference type!"); - return LValue::MakeAddr(RV.getScalarVal(), MakeQualifiers(E->getType())); + return MakeAddrLValue(RV.getScalarVal(), E->getType()); } LValue CodeGenFunction::EmitObjCSelectorLValue(const ObjCSelectorExpr *E) { llvm::Value *V = CGM.getObjCRuntime().GetSelector(Builder, E->getSelector(), true); - return LValue::MakeAddr(V, MakeQualifiers(E->getType())); + return MakeAddrLValue(V, E->getType()); } llvm::Value *CodeGenFunction::EmitIvarOffset(const ObjCInterfaceDecl *Interface, @@ -2025,7 +2061,7 @@ LValue CodeGenFunction::EmitObjCSuperExprLValue(const ObjCSuperExpr *E) { LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { // Can only get l-value for message expression returning aggregate type RValue RV = EmitAnyExprToTemp(E); - return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType())); + return MakeAddrLValue(RV.getAggregateAddr(), E->getType()); } RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, @@ -2054,20 +2090,19 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, LValue CodeGenFunction:: EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) { llvm::Value *BaseV; - if (E->getOpcode() == BinaryOperator::PtrMemI) + if (E->getOpcode() == BO_PtrMemI) BaseV = EmitScalarExpr(E->getLHS()); else BaseV = EmitLValue(E->getLHS()).getAddress(); - const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(getLLVMContext()); - BaseV = Builder.CreateBitCast(BaseV, i8Ty); + llvm::Value *OffsetV = EmitScalarExpr(E->getRHS()); - llvm::Value *AddV = Builder.CreateInBoundsGEP(BaseV, OffsetV, "add.ptr"); - QualType Ty = E->getRHS()->getType(); - Ty = Ty->getAs()->getPointeeType(); - - const llvm::Type *PType = ConvertType(getContext().getPointerType(Ty)); - AddV = Builder.CreateBitCast(AddV, PType); - return LValue::MakeAddr(AddV, MakeQualifiers(Ty)); + const MemberPointerType *MPT + = E->getRHS()->getType()->getAs(); + + llvm::Value *AddV = + CGM.getCXXABI().EmitMemberDataPointerAddress(*this, BaseV, OffsetV, MPT); + + return MakeAddrLValue(AddV, MPT->getPointeeType()); } diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 219a5f9..28c8b35 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -108,7 +108,6 @@ public: void VisitPointerToDataMemberBinaryOperator(const BinaryOperator *BO); void VisitBinAssign(const BinaryOperator *E); void VisitBinComma(const BinaryOperator *E); - void VisitUnaryAddrOf(const UnaryOperator *E); void VisitObjCMessageExpr(ObjCMessageExpr *E); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { @@ -193,10 +192,18 @@ void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) { void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) { assert(Src.isAggregate() && "value must be aggregate value!"); - // If the result is ignored, don't copy from the value. + // If DestPtr is null, then we're evaluating an aggregate expression + // in a context (like an expression statement) that doesn't care + // about the result. C says that an lvalue-to-rvalue conversion is + // performed in these cases; C++ says that it is not. In either + // case, we don't actually need to do anything unless the value is + // volatile. if (DestPtr == 0) { - if (!Src.isVolatileQualified() || (IgnoreResult && Ignore)) + if (!Src.isVolatileQualified() || + CGF.CGM.getLangOptions().CPlusPlus || + (IgnoreResult && Ignore)) return; + // If the source is volatile, we must read from it; to do that, we need // some place to put it. DestPtr = CGF.CreateMemTemp(E->getType(), "agg.tmp"); @@ -235,7 +242,7 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) { //===----------------------------------------------------------------------===// void AggExprEmitter::VisitCastExpr(CastExpr *E) { - if (!DestPtr && E->getCastKind() != CastExpr::CK_Dynamic) { + if (!DestPtr && E->getCastKind() != CK_Dynamic) { Visit(E->getSubExpr()); return; } @@ -243,7 +250,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { switch (E->getCastKind()) { default: assert(0 && "Unhandled cast kind!"); - case CastExpr::CK_Dynamic: { + case CK_Dynamic: { assert(isa(E) && "CK_Dynamic without a dynamic_cast?"); LValue LV = CGF.EmitCheckedLValue(E->getSubExpr()); // FIXME: Do we also need to handle property references here? @@ -257,105 +264,39 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { break; } - case CastExpr::CK_ToUnion: { + case CK_ToUnion: { // GCC union extension - QualType PtrTy = - CGF.getContext().getPointerType(E->getSubExpr()->getType()); + QualType Ty = E->getSubExpr()->getType(); + QualType PtrTy = CGF.getContext().getPointerType(Ty); llvm::Value *CastPtr = Builder.CreateBitCast(DestPtr, CGF.ConvertType(PtrTy)); - EmitInitializationToLValue(E->getSubExpr(), - LValue::MakeAddr(CastPtr, Qualifiers()), - E->getSubExpr()->getType()); + EmitInitializationToLValue(E->getSubExpr(), CGF.MakeAddrLValue(CastPtr, Ty), + Ty); break; } - case CastExpr::CK_DerivedToBase: - case CastExpr::CK_BaseToDerived: - case CastExpr::CK_UncheckedDerivedToBase: { + case CK_DerivedToBase: + case CK_BaseToDerived: + case CK_UncheckedDerivedToBase: { assert(0 && "cannot perform hierarchy conversion in EmitAggExpr: " "should have been unpacked before we got here"); break; } // FIXME: Remove the CK_Unknown check here. - case CastExpr::CK_Unknown: - case CastExpr::CK_NoOp: - case CastExpr::CK_UserDefinedConversion: - case CastExpr::CK_ConstructorConversion: + case CK_Unknown: + case CK_NoOp: + case CK_UserDefinedConversion: + case CK_ConstructorConversion: assert(CGF.getContext().hasSameUnqualifiedType(E->getSubExpr()->getType(), E->getType()) && "Implicit cast types must be compatible"); Visit(E->getSubExpr()); break; - case CastExpr::CK_NullToMemberPointer: { - // If the subexpression's type is the C++0x nullptr_t, emit the - // subexpression, which may have side effects. - if (E->getSubExpr()->getType()->isNullPtrType()) - Visit(E->getSubExpr()); - - const llvm::Type *PtrDiffTy = - CGF.ConvertType(CGF.getContext().getPointerDiffType()); - - llvm::Value *NullValue = llvm::Constant::getNullValue(PtrDiffTy); - llvm::Value *Ptr = Builder.CreateStructGEP(DestPtr, 0, "ptr"); - Builder.CreateStore(NullValue, Ptr, VolatileDest); - - llvm::Value *Adj = Builder.CreateStructGEP(DestPtr, 1, "adj"); - Builder.CreateStore(NullValue, Adj, VolatileDest); - - break; - } - - case CastExpr::CK_LValueBitCast: + case CK_LValueBitCast: llvm_unreachable("there are no lvalue bit-casts on aggregates"); break; - - case CastExpr::CK_BitCast: { - // This must be a member function pointer cast. - Visit(E->getSubExpr()); - break; - } - - case CastExpr::CK_DerivedToBaseMemberPointer: - case CastExpr::CK_BaseToDerivedMemberPointer: { - QualType SrcType = E->getSubExpr()->getType(); - - llvm::Value *Src = CGF.CreateMemTemp(SrcType, "tmp"); - CGF.EmitAggExpr(E->getSubExpr(), Src, SrcType.isVolatileQualified()); - - llvm::Value *SrcPtr = Builder.CreateStructGEP(Src, 0, "src.ptr"); - SrcPtr = Builder.CreateLoad(SrcPtr); - - llvm::Value *SrcAdj = Builder.CreateStructGEP(Src, 1, "src.adj"); - SrcAdj = Builder.CreateLoad(SrcAdj); - - llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr"); - Builder.CreateStore(SrcPtr, DstPtr, VolatileDest); - - llvm::Value *DstAdj = Builder.CreateStructGEP(DestPtr, 1, "dst.adj"); - - // Now See if we need to update the adjustment. - const CXXRecordDecl *BaseDecl = - cast(SrcType->getAs()-> - getClass()->getAs()->getDecl()); - const CXXRecordDecl *DerivedDecl = - cast(E->getType()->getAs()-> - getClass()->getAs()->getDecl()); - if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) - std::swap(DerivedDecl, BaseDecl); - - if (llvm::Constant *Adj = - CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, E->getBasePath())) { - if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) - SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj"); - else - SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj"); - } - - Builder.CreateStore(SrcAdj, DstAdj, VolatileDest); - break; - } } } @@ -391,42 +332,12 @@ void AggExprEmitter::VisitBinComma(const BinaryOperator *E) { /*IgnoreResult=*/false, IsInitializer); } -void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) { - // We have a member function pointer. - const MemberPointerType *MPT = E->getType()->getAs(); - (void) MPT; - assert(MPT->getPointeeType()->isFunctionProtoType() && - "Unexpected member pointer type!"); - - // The creation of member function pointers has no side effects; if - // there is no destination pointer, we have nothing to do. - if (!DestPtr) - return; - - const DeclRefExpr *DRE = cast(E->getSubExpr()); - const CXXMethodDecl *MD = - cast(DRE->getDecl())->getCanonicalDecl(); - - const llvm::Type *PtrDiffTy = - CGF.ConvertType(CGF.getContext().getPointerDiffType()); - - llvm::Value *DstPtr = Builder.CreateStructGEP(DestPtr, 0, "dst.ptr"); - llvm::Value *FuncPtr = CGF.CGM.GetCXXMemberFunctionPointerValue(MD); - Builder.CreateStore(FuncPtr, DstPtr, VolatileDest); - - llvm::Value *AdjPtr = Builder.CreateStructGEP(DestPtr, 1, "dst.adj"); - // The adjustment will always be 0. - Builder.CreateStore(llvm::ConstantInt::get(PtrDiffTy, 0), AdjPtr, - VolatileDest); -} - void AggExprEmitter::VisitStmtExpr(const StmtExpr *E) { CGF.EmitCompoundStmt(*E->getSubStmt(), true, DestPtr, VolatileDest); } void AggExprEmitter::VisitBinaryOperator(const BinaryOperator *E) { - if (E->getOpcode() == BinaryOperator::PtrMemD || - E->getOpcode() == BinaryOperator::PtrMemI) + if (E->getOpcode() == BO_PtrMemD || E->getOpcode() == BO_PtrMemI) VisitPointerToDataMemberBinaryOperator(E); else CGF.ErrorUnsupported(E, "aggregate binary expression"); @@ -519,7 +430,7 @@ void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { return; } - EmitFinalDestCopy(VE, LValue::MakeAddr(ArgPtr, Qualifiers())); + EmitFinalDestCopy(VE, CGF.MakeAddrLValue(ArgPtr, VE->getType())); } void AggExprEmitter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { @@ -546,12 +457,6 @@ AggExprEmitter::VisitCXXConstructExpr(const CXXConstructExpr *E) { if (!Val) // Create a temporary variable. Val = CGF.CreateMemTemp(E->getType(), "tmp"); - if (E->requiresZeroInitialization()) - EmitNullInitializationToLValue(LValue::MakeAddr(Val, - // FIXME: Qualifiers()? - E->getType().getQualifiers()), - E->getType()); - CGF.EmitCXXConstructExpr(Val, E); } @@ -568,8 +473,8 @@ void AggExprEmitter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) { // Create a temporary variable. Val = CGF.CreateMemTemp(E->getType(), "tmp"); } - LValue LV = LValue::MakeAddr(Val, Qualifiers()); - EmitNullInitializationToLValue(LV, E->getType()); + EmitNullInitializationToLValue(CGF.MakeAddrLValue(Val, E->getType()), + E->getType()); } void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { @@ -579,8 +484,8 @@ void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { // Create a temporary variable. Val = CGF.CreateMemTemp(E->getType(), "tmp"); } - LValue LV = LValue::MakeAddr(Val, Qualifiers()); - EmitNullInitializationToLValue(LV, E->getType()); + EmitNullInitializationToLValue(CGF.MakeAddrLValue(Val, E->getType()), + E->getType()); } void @@ -625,7 +530,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { llvm::GlobalVariable* GV = new llvm::GlobalVariable(CGF.CGM.getModule(), C->getType(), true, llvm::GlobalValue::InternalLinkage, C, ""); - EmitFinalDestCopy(E, LValue::MakeAddr(GV, Qualifiers())); + EmitFinalDestCopy(E, CGF.MakeAddrLValue(GV, E->getType())); return; } #endif @@ -656,17 +561,15 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType(); // FIXME: were we intentionally ignoring address spaces and GC attributes? - Qualifiers Quals = CGF.MakeQualifiers(ElementType); for (uint64_t i = 0; i != NumArrayElements; ++i) { llvm::Value *NextVal = Builder.CreateStructGEP(DestPtr, i, ".array"); + LValue LV = CGF.MakeAddrLValue(NextVal, ElementType); if (i < NumInitElements) - EmitInitializationToLValue(E->getInit(i), - LValue::MakeAddr(NextVal, Quals), - ElementType); + EmitInitializationToLValue(E->getInit(i), LV, ElementType); + else - EmitNullInitializationToLValue(LValue::MakeAddr(NextVal, Quals), - ElementType); + EmitNullInitializationToLValue(LV, ElementType); } return; } @@ -679,8 +582,17 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // the optimizer, especially with bitfields. unsigned NumInitElements = E->getNumInits(); RecordDecl *SD = E->getType()->getAs()->getDecl(); - unsigned CurInitVal = 0; - + + // If we're initializing the whole aggregate, just do it in place. + // FIXME: This is a hack around an AST bug (PR6537). + if (NumInitElements == 1 && E->getType() == E->getInit(0)->getType()) { + EmitInitializationToLValue(E->getInit(0), + CGF.MakeAddrLValue(DestPtr, E->getType()), + E->getType()); + return; + } + + if (E->getType()->isUnionType()) { // Only initialize one field of a union. The field itself is // specified by the initializer list. @@ -712,19 +624,10 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { return; } - - // If we're initializing the whole aggregate, just do it in place. - // FIXME: This is a hack around an AST bug (PR6537). - if (NumInitElements == 1 && E->getType() == E->getInit(0)->getType()) { - EmitInitializationToLValue(E->getInit(0), - LValue::MakeAddr(DestPtr, Qualifiers()), - E->getType()); - return; - } - // Here we iterate over the fields; this makes it simpler to both // default-initialize fields and skip over unnamed fields. + unsigned CurInitVal = 0; for (RecordDecl::field_iterator Field = SD->field_begin(), FieldEnd = SD->field_end(); Field != FieldEnd; ++Field) { @@ -738,7 +641,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // FIXME: volatility LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestPtr, *Field, 0); // We never generate write-barries for initialized fields. - LValue::SetObjCNonGC(FieldLoc, true); + FieldLoc.setNonGC(true); if (CurInitVal < NumInitElements) { // Store the initializer into the field. EmitInitializationToLValue(E->getInit(CurInitVal++), FieldLoc, @@ -776,10 +679,10 @@ void CodeGenFunction::EmitAggExpr(const Expr *E, llvm::Value *DestPtr, LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) { assert(hasAggregateLLVMType(E->getType()) && "Invalid argument!"); - Qualifiers Q = MakeQualifiers(E->getType()); llvm::Value *Temp = CreateMemTemp(E->getType()); - EmitAggExpr(E, Temp, Q.hasVolatile()); - return LValue::MakeAddr(Temp, Q); + LValue LV = MakeAddrLValue(Temp, E->getType()); + EmitAggExpr(E, Temp, LV.isVolatileQualified()); + return LV; } void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 69e5f0e..9a98281 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -12,7 +12,9 @@ //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" +#include "CGCXXABI.h" #include "CGObjCRuntime.h" +#include "llvm/Intrinsics.h" using namespace clang; using namespace CodeGen; @@ -91,14 +93,9 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, return EmitCall(getContext().getPointerType(MD->getType()), Callee, ReturnValue, CE->arg_begin(), CE->arg_end()); } - - const FunctionProtoType *FPT = MD->getType()->getAs(); - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), - FPT->isVariadic()); + // Compute the object pointer. llvm::Value *This; - if (ME->isArrow()) This = EmitScalarExpr(ME->getBase()); else { @@ -106,7 +103,10 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, This = BaseLV.getAddress(); } - if (MD->isCopyAssignment() && MD->isTrivial()) { + if (MD->isTrivial()) { + if (isa(MD)) return RValue::get(0); + + assert(MD->isCopyAssignment() && "unknown trivial member function"); // We don't like to generate the trivial copy assignment operator when // it isn't necessary; just produce the proper effect here. llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress(); @@ -114,25 +114,34 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, return RValue::get(This); } + // Compute the function type we're calling. + const CGFunctionInfo &FInfo = + (isa(MD) + ? CGM.getTypes().getFunctionInfo(cast(MD), + Dtor_Complete) + : CGM.getTypes().getFunctionInfo(MD)); + + const FunctionProtoType *FPT = MD->getType()->getAs(); + const llvm::Type *Ty + = CGM.getTypes().GetFunctionType(FInfo, FPT->isVariadic()); + // C++ [class.virtual]p12: // Explicit qualification with the scope operator (5.1) suppresses the // virtual call mechanism. // // We also don't emit a virtual call if the base expression has a record type // because then we know what the type is. + bool UseVirtualCall = MD->isVirtual() && !ME->hasQualifier() + && !canDevirtualizeMemberFunctionCalls(ME->getBase()); + llvm::Value *Callee; - if (const CXXDestructorDecl *Destructor - = dyn_cast(MD)) { - if (Destructor->isTrivial()) - return RValue::get(0); - if (MD->isVirtual() && !ME->hasQualifier() && - !canDevirtualizeMemberFunctionCalls(ME->getBase())) { - Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty); + if (const CXXDestructorDecl *Dtor = dyn_cast(MD)) { + if (UseVirtualCall) { + Callee = BuildVirtualCall(Dtor, Dtor_Complete, This, Ty); } else { - Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty); + Callee = CGM.GetAddrOfFunction(GlobalDecl(Dtor, Dtor_Complete), Ty); } - } else if (MD->isVirtual() && !ME->hasQualifier() && - !canDevirtualizeMemberFunctionCalls(ME->getBase())) { + } else if (UseVirtualCall) { Callee = BuildVirtualCall(MD, This, Ty); } else { Callee = CGM.GetAddrOfFunction(MD, Ty); @@ -152,89 +161,27 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, const MemberPointerType *MPT = MemFnExpr->getType()->getAs(); + const FunctionProtoType *FPT = MPT->getPointeeType()->getAs(); const CXXRecordDecl *RD = cast(MPT->getClass()->getAs()->getDecl()); - const llvm::FunctionType *FTy = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), - FPT->isVariadic()); - - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); - // Get the member function pointer. - llvm::Value *MemFnPtr = CreateMemTemp(MemFnExpr->getType(), "mem.fn"); - EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false); + llvm::Value *MemFnPtr = EmitScalarExpr(MemFnExpr); // Emit the 'this' pointer. llvm::Value *This; - if (BO->getOpcode() == BinaryOperator::PtrMemI) + if (BO->getOpcode() == BO_PtrMemI) This = EmitScalarExpr(BaseExpr); else This = EmitLValue(BaseExpr).getAddress(); - - // Adjust it. - llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1); - Adj = Builder.CreateLoad(Adj, "mem.fn.adj"); - - llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr"); - Ptr = Builder.CreateGEP(Ptr, Adj, "adj"); - - This = Builder.CreateBitCast(Ptr, This->getType(), "this"); - - llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr"); - - const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); - llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn"); - - // If the LSB in the function pointer is 1, the function pointer points to - // a virtual function. - llvm::Value *IsVirtual - = Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1), - "and"); - - IsVirtual = Builder.CreateTrunc(IsVirtual, - llvm::Type::getInt1Ty(VMContext)); + // Ask the ABI to load the callee. Note that This is modified. + llvm::Value *Callee = + CGM.getCXXABI().EmitLoadOfMemberFunctionPointer(CGF, This, MemFnPtr, MPT); - llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual"); - llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual"); - llvm::BasicBlock *FnEnd = createBasicBlock("fn.end"); - - Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual); - EmitBlock(FnVirtual); - - const llvm::Type *VTableTy = - FTy->getPointerTo()->getPointerTo(); - - llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo()); - VTable = Builder.CreateLoad(VTable); - - VTable = Builder.CreateBitCast(VTable, Int8PtrTy); - llvm::Value *VTableOffset = - Builder.CreateSub(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1)); - - VTable = Builder.CreateGEP(VTable, VTableOffset, "fn"); - VTable = Builder.CreateBitCast(VTable, VTableTy); - - llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn"); - - EmitBranch(FnEnd); - EmitBlock(FnNonVirtual); - - // If the function is not virtual, just load the pointer. - llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn"); - NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo()); - - EmitBlock(FnEnd); - - llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo()); - Callee->reserveOperandSpace(2); - Callee->addIncoming(VirtualFn, FnVirtual); - Callee->addIncoming(NonVirtualFn, FnNonVirtual); - CallArgList Args; QualType ThisType = @@ -263,11 +210,17 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, "EmitCXXOperatorMemberCallExpr - user declared copy assignment"); LValue LV = EmitLValue(E->getArg(0)); llvm::Value *This; - if (LV.isPropertyRef()) { + if (LV.isPropertyRef() || LV.isKVCRef()) { llvm::Value *AggLoc = CreateMemTemp(E->getArg(1)->getType()); EmitAggExpr(E->getArg(1), AggLoc, false /*VolatileDest*/); - EmitObjCPropertySet(LV.getPropertyRefExpr(), - RValue::getAggregate(AggLoc, false /*VolatileDest*/)); + if (LV.isPropertyRef()) + EmitObjCPropertySet(LV.getPropertyRefExpr(), + RValue::getAggregate(AggLoc, + false /*VolatileDest*/)); + else + EmitObjCPropertySet(LV.getKVCRefExpr(), + RValue::getAggregate(AggLoc, + false /*VolatileDest*/)); return RValue::getAggregate(0, false); } else @@ -286,8 +239,11 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, FPT->isVariadic()); LValue LV = EmitLValue(E->getArg(0)); llvm::Value *This; - if (LV.isPropertyRef()) { - RValue RV = EmitLoadOfPropertyRefLValue(LV, E->getArg(0)->getType()); + if (LV.isPropertyRef() || LV.isKVCRef()) { + QualType QT = E->getArg(0)->getType(); + RValue RV = + LV.isPropertyRef() ? EmitLoadOfPropertyRefLValue(LV, QT) + : EmitLoadOfKVCRefLValue(LV, QT); assert (!RV.isScalar() && "EmitCXXOperatorMemberCallExpr"); This = RV.getAggregateAddr(); } @@ -309,19 +265,18 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, const CXXConstructExpr *E) { assert(Dest && "Must have a destination!"); const CXXConstructorDecl *CD = E->getConstructor(); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(E->getType()); - // For a copy constructor, even if it is trivial, must fall thru so - // its argument is code-gen'ed. - if (!CD->isCopyConstructor()) { - QualType InitType = E->getType(); - if (Array) - InitType = getContext().getBaseElementType(Array); - const CXXRecordDecl *RD = - cast(InitType->getAs()->getDecl()); - if (RD->hasTrivialConstructor()) - return; - } + + // If we require zero initialization before (or instead of) calling the + // constructor, as can be the case with a non-user-provided default + // constructor, emit the zero initialization now. + if (E->requiresZeroInitialization()) + EmitNullInitialization(Dest, E->getType()); + + + // If this is a call to a trivial default constructor, do nothing. + if (CD->isTrivial() && CD->isDefaultConstructor()) + return; + // Code gen optimization to eliminate copy constructor and return // its first argument instead, if in fact that argument is a temporary // object. @@ -331,6 +286,9 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, return; } } + + const ConstantArrayType *Array + = getContext().getAsConstantArrayType(E->getType()); if (Array) { QualType BaseElementTy = getContext().getBaseElementType(Array); const llvm::Type *BasePtr = ConvertType(BaseElementTy); @@ -354,131 +312,205 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest, } } -static CharUnits CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) { - const RecordType *RT = ElementType->getAs(); - if (!RT) - return CharUnits::Zero(); - - const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); - if (!RD) - return CharUnits::Zero(); - - // Check if the class has a trivial destructor. - if (RD->hasTrivialDestructor()) { - // Check if the usual deallocation function takes two arguments. - const CXXMethodDecl *UsualDeallocationFunction = 0; - - DeclarationName OpName = - Ctx.DeclarationNames.getCXXOperatorName(OO_Array_Delete); - DeclContext::lookup_const_iterator Op, OpEnd; - for (llvm::tie(Op, OpEnd) = RD->lookup(OpName); - Op != OpEnd; ++Op) { - const CXXMethodDecl *Delete = cast(*Op); - - if (Delete->isUsualDeallocationFunction()) { - UsualDeallocationFunction = Delete; - break; - } - } - - // No usual deallocation function, we don't need a cookie. - if (!UsualDeallocationFunction) - return CharUnits::Zero(); - - // The usual deallocation function doesn't take a size_t argument, so we - // don't need a cookie. - if (UsualDeallocationFunction->getNumParams() == 1) - return CharUnits::Zero(); - - assert(UsualDeallocationFunction->getNumParams() == 2 && - "Unexpected deallocation function type!"); - } - - // Padding is the maximum of sizeof(size_t) and alignof(ElementType) - return std::max(Ctx.getTypeSizeInChars(Ctx.getSizeType()), - Ctx.getTypeAlignInChars(ElementType)); +/// Check whether the given operator new[] is the global placement +/// operator new[]. +static bool IsPlacementOperatorNewArray(ASTContext &Ctx, + const FunctionDecl *Fn) { + // Must be in global scope. Note that allocation functions can't be + // declared in namespaces. + if (!Fn->getDeclContext()->getRedeclContext()->isFileContext()) + return false; + + // Signature must be void *operator new[](size_t, void*). + // The size_t is common to all operator new[]s. + if (Fn->getNumParams() != 2) + return false; + + CanQualType ParamType = Ctx.getCanonicalType(Fn->getParamDecl(1)->getType()); + return (ParamType == Ctx.VoidPtrTy); } -static CharUnits CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) { +static CharUnits CalculateCookiePadding(CodeGenFunction &CGF, + const CXXNewExpr *E) { if (!E->isArray()) return CharUnits::Zero(); // No cookie is required if the new operator being used is // ::operator new[](size_t, void*). const FunctionDecl *OperatorNew = E->getOperatorNew(); - if (OperatorNew->getDeclContext()->getLookupContext()->isFileContext()) { - if (OperatorNew->getNumParams() == 2) { - CanQualType ParamType = - Ctx.getCanonicalType(OperatorNew->getParamDecl(1)->getType()); - - if (ParamType == Ctx.VoidPtrTy) - return CharUnits::Zero(); - } - } - - return CalculateCookiePadding(Ctx, E->getAllocatedType()); + if (IsPlacementOperatorNewArray(CGF.getContext(), OperatorNew)) + return CharUnits::Zero(); + + return CGF.CGM.getCXXABI().GetArrayCookieSize(E->getAllocatedType()); } static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context, - CodeGenFunction &CGF, + CodeGenFunction &CGF, const CXXNewExpr *E, - llvm::Value *& NumElements) { - QualType Type = E->getAllocatedType(); - CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(Type); - const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); - - if (!E->isArray()) - return llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity()); + llvm::Value *&NumElements, + llvm::Value *&SizeWithoutCookie) { + QualType ElemType = E->getAllocatedType(); - CharUnits CookiePadding = CalculateCookiePadding(CGF.getContext(), E); + const llvm::IntegerType *SizeTy = + cast(CGF.ConvertType(CGF.getContext().getSizeType())); - Expr::EvalResult Result; - if (E->getArraySize()->Evaluate(Result, CGF.getContext()) && - !Result.HasSideEffects && Result.Val.isInt()) { + CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(ElemType); - CharUnits AllocSize = - Result.Val.getInt().getZExtValue() * TypeSize + CookiePadding; - - NumElements = - llvm::ConstantInt::get(SizeTy, Result.Val.getInt().getZExtValue()); - while (const ArrayType *AType = Context.getAsArrayType(Type)) { - const llvm::ArrayType *llvmAType = - cast(CGF.ConvertType(Type)); - NumElements = - CGF.Builder.CreateMul(NumElements, - llvm::ConstantInt::get( - SizeTy, llvmAType->getNumElements())); - Type = AType->getElementType(); - } - - return llvm::ConstantInt::get(SizeTy, AllocSize.getQuantity()); + if (!E->isArray()) { + SizeWithoutCookie = llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity()); + return SizeWithoutCookie; } - + + // Figure out the cookie size. + CharUnits CookieSize = CalculateCookiePadding(CGF, E); + // Emit the array size expression. + // We multiply the size of all dimensions for NumElements. + // e.g for 'int[2][3]', ElemType is 'int' and NumElements is 6. NumElements = CGF.EmitScalarExpr(E->getArraySize()); - - // Multiply with the type size. - llvm::Value *V = - CGF.Builder.CreateMul(NumElements, - llvm::ConstantInt::get(SizeTy, - TypeSize.getQuantity())); - - while (const ArrayType *AType = Context.getAsArrayType(Type)) { - const llvm::ArrayType *llvmAType = - cast(CGF.ConvertType(Type)); - NumElements = - CGF.Builder.CreateMul(NumElements, - llvm::ConstantInt::get( - SizeTy, llvmAType->getNumElements())); - Type = AType->getElementType(); + assert(NumElements->getType() == SizeTy && "element count not a size_t"); + + uint64_t ArraySizeMultiplier = 1; + while (const ConstantArrayType *CAT + = CGF.getContext().getAsConstantArrayType(ElemType)) { + ElemType = CAT->getElementType(); + ArraySizeMultiplier *= CAT->getSize().getZExtValue(); } - // And add the cookie padding if necessary. - if (!CookiePadding.isZero()) - V = CGF.Builder.CreateAdd(V, - llvm::ConstantInt::get(SizeTy, CookiePadding.getQuantity())); - - return V; + llvm::Value *Size; + + // If someone is doing 'new int[42]' there is no need to do a dynamic check. + // Don't bloat the -O0 code. + if (llvm::ConstantInt *NumElementsC = + dyn_cast(NumElements)) { + llvm::APInt NEC = NumElementsC->getValue(); + unsigned SizeWidth = NEC.getBitWidth(); + + // Determine if there is an overflow here by doing an extended multiply. + NEC.zext(SizeWidth*2); + llvm::APInt SC(SizeWidth*2, TypeSize.getQuantity()); + SC *= NEC; + + if (!CookieSize.isZero()) { + // Save the current size without a cookie. We don't care if an + // overflow's already happened because SizeWithoutCookie isn't + // used if the allocator returns null or throws, as it should + // always do on an overflow. + llvm::APInt SWC = SC; + SWC.trunc(SizeWidth); + SizeWithoutCookie = llvm::ConstantInt::get(SizeTy, SWC); + + // Add the cookie size. + SC += llvm::APInt(SizeWidth*2, CookieSize.getQuantity()); + } + + if (SC.countLeadingZeros() >= SizeWidth) { + SC.trunc(SizeWidth); + Size = llvm::ConstantInt::get(SizeTy, SC); + } else { + // On overflow, produce a -1 so operator new throws. + Size = llvm::Constant::getAllOnesValue(SizeTy); + } + + // Scale NumElements while we're at it. + uint64_t N = NEC.getZExtValue() * ArraySizeMultiplier; + NumElements = llvm::ConstantInt::get(SizeTy, N); + + // Otherwise, we don't need to do an overflow-checked multiplication if + // we're multiplying by one. + } else if (TypeSize.isOne()) { + assert(ArraySizeMultiplier == 1); + + Size = NumElements; + + // If we need a cookie, add its size in with an overflow check. + // This is maybe a little paranoid. + if (!CookieSize.isZero()) { + SizeWithoutCookie = Size; + + llvm::Value *CookieSizeV + = llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity()); + + const llvm::Type *Types[] = { SizeTy }; + llvm::Value *UAddF + = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, Types, 1); + llvm::Value *AddRes + = CGF.Builder.CreateCall2(UAddF, Size, CookieSizeV); + + Size = CGF.Builder.CreateExtractValue(AddRes, 0); + llvm::Value *DidOverflow = CGF.Builder.CreateExtractValue(AddRes, 1); + Size = CGF.Builder.CreateSelect(DidOverflow, + llvm::ConstantInt::get(SizeTy, -1), + Size); + } + + // Otherwise use the int.umul.with.overflow intrinsic. + } else { + llvm::Value *OutermostElementSize + = llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity()); + + llvm::Value *NumOutermostElements = NumElements; + + // Scale NumElements by the array size multiplier. This might + // overflow, but only if the multiplication below also overflows, + // in which case this multiplication isn't used. + if (ArraySizeMultiplier != 1) + NumElements = CGF.Builder.CreateMul(NumElements, + llvm::ConstantInt::get(SizeTy, ArraySizeMultiplier)); + + // The requested size of the outermost array is non-constant. + // Multiply that by the static size of the elements of that array; + // on unsigned overflow, set the size to -1 to trigger an + // exception from the allocation routine. This is sufficient to + // prevent buffer overruns from the allocator returning a + // seemingly valid pointer to insufficient space. This idea comes + // originally from MSVC, and GCC has an open bug requesting + // similar behavior: + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19351 + // + // This will not be sufficient for C++0x, which requires a + // specific exception class (std::bad_array_new_length). + // That will require ABI support that has not yet been specified. + const llvm::Type *Types[] = { SizeTy }; + llvm::Value *UMulF + = CGF.CGM.getIntrinsic(llvm::Intrinsic::umul_with_overflow, Types, 1); + llvm::Value *MulRes = CGF.Builder.CreateCall2(UMulF, NumOutermostElements, + OutermostElementSize); + + // The overflow bit. + llvm::Value *DidOverflow = CGF.Builder.CreateExtractValue(MulRes, 1); + + // The result of the multiplication. + Size = CGF.Builder.CreateExtractValue(MulRes, 0); + + // If we have a cookie, we need to add that size in, too. + if (!CookieSize.isZero()) { + SizeWithoutCookie = Size; + + llvm::Value *CookieSizeV + = llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity()); + llvm::Value *UAddF + = CGF.CGM.getIntrinsic(llvm::Intrinsic::uadd_with_overflow, Types, 1); + llvm::Value *AddRes + = CGF.Builder.CreateCall2(UAddF, SizeWithoutCookie, CookieSizeV); + + Size = CGF.Builder.CreateExtractValue(AddRes, 0); + + llvm::Value *AddDidOverflow = CGF.Builder.CreateExtractValue(AddRes, 1); + DidOverflow = CGF.Builder.CreateAnd(DidOverflow, AddDidOverflow); + } + + Size = CGF.Builder.CreateSelect(DidOverflow, + llvm::ConstantInt::get(SizeTy, -1), + Size); + } + + if (CookieSize.isZero()) + SizeWithoutCookie = Size; + else + assert(SizeWithoutCookie && "didn't set SizeWithoutCookie?"); + + return Size; } static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E, @@ -489,10 +521,13 @@ static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E, const Expr *Init = E->getConstructorArg(0); QualType AllocType = E->getAllocatedType(); - + + unsigned Alignment = + CGF.getContext().getTypeAlignInChars(AllocType).getQuantity(); if (!CGF.hasAggregateLLVMType(AllocType)) CGF.EmitStoreOfScalar(CGF.EmitScalarExpr(Init), NewPtr, - AllocType.isVolatileQualified(), AllocType); + AllocType.isVolatileQualified(), Alignment, + AllocType); else if (AllocType->isAnyComplexType()) CGF.EmitComplexExprIntoAddr(Init, NewPtr, AllocType.isVolatileQualified()); @@ -554,18 +589,59 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E, EmitBlock(AfterFor, true); } +static void EmitZeroMemSet(CodeGenFunction &CGF, QualType T, + llvm::Value *NewPtr, llvm::Value *Size) { + llvm::LLVMContext &VMContext = CGF.CGM.getLLVMContext(); + const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); + if (NewPtr->getType() != BP) + NewPtr = CGF.Builder.CreateBitCast(NewPtr, BP, "tmp"); + + CGF.Builder.CreateCall5(CGF.CGM.getMemSetFn(BP, CGF.IntPtrTy), NewPtr, + llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)), + Size, + llvm::ConstantInt::get(CGF.Int32Ty, + CGF.getContext().getTypeAlign(T)/8), + llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), + 0)); +} + static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, llvm::Value *NewPtr, - llvm::Value *NumElements) { + llvm::Value *NumElements, + llvm::Value *AllocSizeWithoutCookie) { if (E->isArray()) { if (CXXConstructorDecl *Ctor = E->getConstructor()) { - if (!Ctor->getParent()->hasTrivialConstructor()) - CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr, - E->constructor_arg_begin(), - E->constructor_arg_end()); + bool RequiresZeroInitialization = false; + if (Ctor->getParent()->hasTrivialConstructor()) { + // If new expression did not specify value-initialization, then there + // is no initialization. + if (!E->hasInitializer() || Ctor->getParent()->isEmpty()) + return; + + if (CGF.CGM.getTypes().isZeroInitializable(E->getAllocatedType())) { + // Optimization: since zero initialization will just set the memory + // to all zeroes, generate a single memset to do it in one shot. + EmitZeroMemSet(CGF, E->getAllocatedType(), NewPtr, + AllocSizeWithoutCookie); + return; + } + + RequiresZeroInitialization = true; + } + + CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr, + E->constructor_arg_begin(), + E->constructor_arg_end(), + RequiresZeroInitialization); return; - } - else { + } else if (E->getNumConstructorArgs() == 1 && + isa(E->getConstructorArg(0))) { + // Optimization: since zero initialization will just set the memory + // to all zeroes, generate a single memset to do it in one shot. + EmitZeroMemSet(CGF, E->getAllocatedType(), NewPtr, + AllocSizeWithoutCookie); + return; + } else { CGF.EmitNewArrayInitializer(E, NewPtr, NumElements); return; } @@ -595,6 +671,10 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { QualType AllocType = E->getAllocatedType(); + if (AllocType->isArrayType()) + while (const ArrayType *AType = getContext().getAsArrayType(AllocType)) + AllocType = AType->getElementType(); + FunctionDecl *NewFD = E->getOperatorNew(); const FunctionProtoType *NewFTy = NewFD->getType()->getAs(); @@ -604,8 +684,10 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { QualType SizeTy = getContext().getSizeType(); llvm::Value *NumElements = 0; + llvm::Value *AllocSizeWithoutCookie = 0; llvm::Value *AllocSize = EmitCXXNewAllocSize(getContext(), - *this, E, NumElements); + *this, E, NumElements, + AllocSizeWithoutCookie); NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy)); @@ -654,112 +736,69 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { bool NullCheckResult = NewFTy->hasEmptyExceptionSpec() && !(AllocType->isPODType() && !E->hasInitializer()); - llvm::BasicBlock *NewNull = 0; + llvm::BasicBlock *NullCheckSource = 0; llvm::BasicBlock *NewNotNull = 0; llvm::BasicBlock *NewEnd = 0; llvm::Value *NewPtr = RV.getScalarVal(); + unsigned AS = cast(NewPtr->getType())->getAddressSpace(); if (NullCheckResult) { - NewNull = createBasicBlock("new.null"); + NullCheckSource = Builder.GetInsertBlock(); NewNotNull = createBasicBlock("new.notnull"); NewEnd = createBasicBlock("new.end"); - llvm::Value *IsNull = - Builder.CreateICmpEQ(NewPtr, - llvm::Constant::getNullValue(NewPtr->getType()), - "isnull"); - - Builder.CreateCondBr(IsNull, NewNull, NewNotNull); + llvm::Value *IsNull = Builder.CreateIsNull(NewPtr, "new.isnull"); + Builder.CreateCondBr(IsNull, NewEnd, NewNotNull); EmitBlock(NewNotNull); } - CharUnits CookiePadding = CalculateCookiePadding(getContext(), E); - if (!CookiePadding.isZero()) { - CharUnits CookieOffset = - CookiePadding - getContext().getTypeSizeInChars(SizeTy); - - llvm::Value *NumElementsPtr = - Builder.CreateConstInBoundsGEP1_64(NewPtr, CookieOffset.getQuantity()); - - NumElementsPtr = Builder.CreateBitCast(NumElementsPtr, - ConvertType(SizeTy)->getPointerTo()); - Builder.CreateStore(NumElements, NumElementsPtr); - - // Now add the padding to the new ptr. - NewPtr = Builder.CreateConstInBoundsGEP1_64(NewPtr, - CookiePadding.getQuantity()); + assert((AllocSize == AllocSizeWithoutCookie) == + CalculateCookiePadding(*this, E).isZero()); + if (AllocSize != AllocSizeWithoutCookie) { + assert(E->isArray()); + NewPtr = CGM.getCXXABI().InitializeArrayCookie(CGF, NewPtr, NumElements, + AllocType); } - - if (AllocType->isArrayType()) { - while (const ArrayType *AType = getContext().getAsArrayType(AllocType)) - AllocType = AType->getElementType(); - NewPtr = - Builder.CreateBitCast(NewPtr, - ConvertType(getContext().getPointerType(AllocType))); - EmitNewInitializer(*this, E, NewPtr, NumElements); - NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType())); - } - else { - NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType())); - EmitNewInitializer(*this, E, NewPtr, NumElements); + + const llvm::Type *ElementPtrTy + = ConvertTypeForMem(AllocType)->getPointerTo(AS); + NewPtr = Builder.CreateBitCast(NewPtr, ElementPtrTy); + if (E->isArray()) { + EmitNewInitializer(*this, E, NewPtr, NumElements, AllocSizeWithoutCookie); + + // NewPtr is a pointer to the base element type. If we're + // allocating an array of arrays, we'll need to cast back to the + // array pointer type. + const llvm::Type *ResultTy = ConvertTypeForMem(E->getType()); + if (NewPtr->getType() != ResultTy) + NewPtr = Builder.CreateBitCast(NewPtr, ResultTy); + } else { + EmitNewInitializer(*this, E, NewPtr, NumElements, AllocSizeWithoutCookie); } if (NullCheckResult) { Builder.CreateBr(NewEnd); - NewNotNull = Builder.GetInsertBlock(); - EmitBlock(NewNull); - Builder.CreateBr(NewEnd); + llvm::BasicBlock *NotNullSource = Builder.GetInsertBlock(); EmitBlock(NewEnd); llvm::PHINode *PHI = Builder.CreatePHI(NewPtr->getType()); PHI->reserveOperandSpace(2); - PHI->addIncoming(NewPtr, NewNotNull); - PHI->addIncoming(llvm::Constant::getNullValue(NewPtr->getType()), NewNull); + PHI->addIncoming(NewPtr, NotNullSource); + PHI->addIncoming(llvm::Constant::getNullValue(NewPtr->getType()), + NullCheckSource); NewPtr = PHI; } - - return NewPtr; -} - -static std::pair -GetAllocatedObjectPtrAndNumElements(CodeGenFunction &CGF, - llvm::Value *Ptr, QualType DeleteTy) { - QualType SizeTy = CGF.getContext().getSizeType(); - const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy); - - CharUnits DeleteTypeAlign = CGF.getContext().getTypeAlignInChars(DeleteTy); - CharUnits CookiePadding = - std::max(CGF.getContext().getTypeSizeInChars(SizeTy), - DeleteTypeAlign); - assert(!CookiePadding.isZero() && "CookiePadding should not be 0."); - - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - CharUnits CookieOffset = - CookiePadding - CGF.getContext().getTypeSizeInChars(SizeTy); - - llvm::Value *AllocatedObjectPtr = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy); - AllocatedObjectPtr = - CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, - -CookiePadding.getQuantity()); - - llvm::Value *NumElementsPtr = - CGF.Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr, - CookieOffset.getQuantity()); - NumElementsPtr = - CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo()); - - llvm::Value *NumElements = CGF.Builder.CreateLoad(NumElementsPtr); - NumElements = - CGF.Builder.CreateIntCast(NumElements, SizeLTy, /*isSigned=*/false); - return std::make_pair(AllocatedObjectPtr, NumElements); + return NewPtr; } void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, llvm::Value *Ptr, QualType DeleteTy) { + assert(DeleteFD->getOverloadedOperator() == OO_Delete); + const FunctionProtoType *DeleteFTy = DeleteFD->getType()->getAs(); @@ -775,21 +814,6 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, DeleteTypeSize.getQuantity()); } - if (DeleteFD->getOverloadedOperator() == OO_Array_Delete && - !CalculateCookiePadding(getContext(), DeleteTy).isZero()) { - // We need to get the number of elements in the array from the cookie. - llvm::Value *AllocatedObjectPtr; - llvm::Value *NumElements; - llvm::tie(AllocatedObjectPtr, NumElements) = - GetAllocatedObjectPtrAndNumElements(*this, Ptr, DeleteTy); - - // Multiply the size with the number of elements. - if (Size) - Size = Builder.CreateMul(NumElements, Size); - - Ptr = AllocatedObjectPtr; - } - QualType ArgTy = DeleteFTy->getArgType(0); llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy)); DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy)); @@ -803,20 +827,169 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, DeleteArgs, DeleteFD); } +namespace { + /// Calls the given 'operator delete' on a single object. + struct CallObjectDelete : EHScopeStack::Cleanup { + llvm::Value *Ptr; + const FunctionDecl *OperatorDelete; + QualType ElementType; + + CallObjectDelete(llvm::Value *Ptr, + const FunctionDecl *OperatorDelete, + QualType ElementType) + : Ptr(Ptr), OperatorDelete(OperatorDelete), ElementType(ElementType) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + CGF.EmitDeleteCall(OperatorDelete, Ptr, ElementType); + } + }; +} + +/// Emit the code for deleting a single object. +static void EmitObjectDelete(CodeGenFunction &CGF, + const FunctionDecl *OperatorDelete, + llvm::Value *Ptr, + QualType ElementType) { + // Find the destructor for the type, if applicable. If the + // destructor is virtual, we'll just emit the vcall and return. + const CXXDestructorDecl *Dtor = 0; + if (const RecordType *RT = ElementType->getAs()) { + CXXRecordDecl *RD = cast(RT->getDecl()); + if (!RD->hasTrivialDestructor()) { + Dtor = RD->getDestructor(); + + if (Dtor->isVirtual()) { + const llvm::Type *Ty = + CGF.getTypes().GetFunctionType(CGF.getTypes().getFunctionInfo(Dtor, + Dtor_Complete), + /*isVariadic=*/false); + + llvm::Value *Callee + = CGF.BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty); + CGF.EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0, + 0, 0); + + // The dtor took care of deleting the object. + return; + } + } + } + + // Make sure that we call delete even if the dtor throws. + CGF.EHStack.pushCleanup(NormalAndEHCleanup, + Ptr, OperatorDelete, ElementType); + + if (Dtor) + CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, + /*ForVirtualBase=*/false, Ptr); + + CGF.PopCleanupBlock(); +} + +namespace { + /// Calls the given 'operator delete' on an array of objects. + struct CallArrayDelete : EHScopeStack::Cleanup { + llvm::Value *Ptr; + const FunctionDecl *OperatorDelete; + llvm::Value *NumElements; + QualType ElementType; + CharUnits CookieSize; + + CallArrayDelete(llvm::Value *Ptr, + const FunctionDecl *OperatorDelete, + llvm::Value *NumElements, + QualType ElementType, + CharUnits CookieSize) + : Ptr(Ptr), OperatorDelete(OperatorDelete), NumElements(NumElements), + ElementType(ElementType), CookieSize(CookieSize) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + const FunctionProtoType *DeleteFTy = + OperatorDelete->getType()->getAs(); + assert(DeleteFTy->getNumArgs() == 1 || DeleteFTy->getNumArgs() == 2); + + CallArgList Args; + + // Pass the pointer as the first argument. + QualType VoidPtrTy = DeleteFTy->getArgType(0); + llvm::Value *DeletePtr + = CGF.Builder.CreateBitCast(Ptr, CGF.ConvertType(VoidPtrTy)); + Args.push_back(std::make_pair(RValue::get(DeletePtr), VoidPtrTy)); + + // Pass the original requested size as the second argument. + if (DeleteFTy->getNumArgs() == 2) { + QualType size_t = DeleteFTy->getArgType(1); + const llvm::IntegerType *SizeTy + = cast(CGF.ConvertType(size_t)); + + CharUnits ElementTypeSize = + CGF.CGM.getContext().getTypeSizeInChars(ElementType); + + // The size of an element, multiplied by the number of elements. + llvm::Value *Size + = llvm::ConstantInt::get(SizeTy, ElementTypeSize.getQuantity()); + Size = CGF.Builder.CreateMul(Size, NumElements); + + // Plus the size of the cookie if applicable. + if (!CookieSize.isZero()) { + llvm::Value *CookieSizeV + = llvm::ConstantInt::get(SizeTy, CookieSize.getQuantity()); + Size = CGF.Builder.CreateAdd(Size, CookieSizeV); + } + + Args.push_back(std::make_pair(RValue::get(Size), size_t)); + } + + // Emit the call to delete. + CGF.EmitCall(CGF.getTypes().getFunctionInfo(Args, DeleteFTy), + CGF.CGM.GetAddrOfFunction(OperatorDelete), + ReturnValueSlot(), Args, OperatorDelete); + } + }; +} + +/// Emit the code for deleting an array of objects. +static void EmitArrayDelete(CodeGenFunction &CGF, + const FunctionDecl *OperatorDelete, + llvm::Value *Ptr, + QualType ElementType) { + llvm::Value *NumElements = 0; + llvm::Value *AllocatedPtr = 0; + CharUnits CookieSize; + CGF.CGM.getCXXABI().ReadArrayCookie(CGF, Ptr, ElementType, + NumElements, AllocatedPtr, CookieSize); + + assert(AllocatedPtr && "ReadArrayCookie didn't set AllocatedPtr"); + + // Make sure that we call delete even if one of the dtors throws. + CGF.EHStack.pushCleanup(NormalAndEHCleanup, + AllocatedPtr, OperatorDelete, + NumElements, ElementType, + CookieSize); + + if (const CXXRecordDecl *RD = ElementType->getAsCXXRecordDecl()) { + if (!RD->hasTrivialDestructor()) { + assert(NumElements && "ReadArrayCookie didn't find element count" + " for a class with destructor"); + CGF.EmitCXXAggrDestructorCall(RD->getDestructor(), NumElements, Ptr); + } + } + + CGF.PopCleanupBlock(); +} + void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { // Get at the argument before we performed the implicit conversion // to void*. const Expr *Arg = E->getArgument(); while (const ImplicitCastExpr *ICE = dyn_cast(Arg)) { - if (ICE->getCastKind() != CastExpr::CK_UserDefinedConversion && + if (ICE->getCastKind() != CK_UserDefinedConversion && ICE->getType()->isVoidPointerType()) Arg = ICE->getSubExpr(); else break; } - - QualType DeleteTy = Arg->getType()->getAs()->getPointeeType(); llvm::Value *Ptr = EmitScalarExpr(Arg); @@ -830,41 +1003,38 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull); EmitBlock(DeleteNotNull); - - bool ShouldCallDelete = true; - - // Call the destructor if necessary. - if (const RecordType *RT = DeleteTy->getAs()) { - if (CXXRecordDecl *RD = dyn_cast(RT->getDecl())) { - if (!RD->hasTrivialDestructor()) { - const CXXDestructorDecl *Dtor = RD->getDestructor(); - if (E->isArrayForm()) { - llvm::Value *AllocatedObjectPtr; - llvm::Value *NumElements; - llvm::tie(AllocatedObjectPtr, NumElements) = - GetAllocatedObjectPtrAndNumElements(*this, Ptr, DeleteTy); - - EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr); - } else if (Dtor->isVirtual()) { - const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(Dtor), - /*isVariadic=*/false); - - llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty); - EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0, - 0, 0); - - // The dtor took care of deleting the object. - ShouldCallDelete = false; - } else - EmitCXXDestructorCall(Dtor, Dtor_Complete, /*ForVirtualBase=*/false, - Ptr); - } + + // We might be deleting a pointer to array. If so, GEP down to the + // first non-array element. + // (this assumes that A(*)[3][7] is converted to [3 x [7 x %A]]*) + QualType DeleteTy = Arg->getType()->getAs()->getPointeeType(); + if (DeleteTy->isConstantArrayType()) { + llvm::Value *Zero = Builder.getInt32(0); + llvm::SmallVector GEP; + + GEP.push_back(Zero); // point at the outermost array + + // For each layer of array type we're pointing at: + while (const ConstantArrayType *Arr + = getContext().getAsConstantArrayType(DeleteTy)) { + // 1. Unpeel the array type. + DeleteTy = Arr->getElementType(); + + // 2. GEP to the first element of the array. + GEP.push_back(Zero); } + + Ptr = Builder.CreateInBoundsGEP(Ptr, GEP.begin(), GEP.end(), "del.first"); } - if (ShouldCallDelete) - EmitDeleteCall(E->getOperatorDelete(), Ptr, DeleteTy); + assert(ConvertTypeForMem(DeleteTy) == + cast(Ptr->getType())->getElementType()); + + if (E->isArrayForm()) { + EmitArrayDelete(*this, E->getOperatorDelete(), Ptr, DeleteTy); + } else { + EmitObjectDelete(*this, E->getOperatorDelete(), Ptr, DeleteTy); + } EmitBlock(DeleteEnd); } @@ -895,7 +1065,7 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { // FIXME: PointerType->hasAttr() bool CanBeZero = false; if (UnaryOperator *UO = dyn_cast(subE->IgnoreParens())) - if (UO->getOpcode() == UnaryOperator::Deref) + if (UO->getOpcode() == UO_Deref) CanBeZero = true; if (CanBeZero) { llvm::BasicBlock *NonZeroBlock = createBasicBlock(); diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 0927319..79e9dd4 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -347,7 +347,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op, // FIXME: We should be looking at all of the cast kinds here, not // cherry-picking the ones we have test cases for. - if (CK == CastExpr::CK_LValueBitCast) { + if (CK == CK_LValueBitCast) { llvm::Value *V = CGF.EmitLValue(Op).getAddress(); V = Builder.CreateBitCast(V, CGF.ConvertType(CGF.getContext().getPointerType(DestTy))); @@ -532,7 +532,7 @@ EmitCompoundAssign(const CompoundAssignOperator *E, // improve codegen a little. It is possible for the RHS to be complex or // scalar. OpInfo.Ty = E->getComputationResultType(); - OpInfo.RHS = EmitCast(CastExpr::CK_Unknown, E->getRHS(), OpInfo.Ty); + OpInfo.RHS = EmitCast(CK_Unknown, E->getRHS(), OpInfo.Ty); LValue LHS = CGF.EmitLValue(E->getLHS()); // We know the LHS is a complex lvalue. diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index bbd256c..9c31c2a 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -13,6 +13,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CGRecordLayout.h" #include "clang/AST/APValue.h" @@ -81,10 +82,6 @@ AppendField(const FieldDecl *Field, uint64_t FieldOffset, assert(NextFieldOffsetInBytes <= FieldOffsetInBytes && "Field offset mismatch!"); - // Emit the field. - if (!InitCst) - return false; - unsigned FieldAlignment = getAlignment(InitCst); // Round up the field offset to the alignment of the field type. @@ -360,6 +357,9 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) { Field->getType(), CGF); else EltInit = CGM.EmitNullConstant(Field->getType()); + + if (!EltInit) + return false; if (!Field->isBitField()) { // Handle non-bitfield members. @@ -455,37 +455,15 @@ public: return Visit(E->getInitializer()); } - llvm::Constant *EmitMemberFunctionPointer(CXXMethodDecl *MD) { - assert(MD->isInstance() && "Member function must not be static!"); - - MD = MD->getCanonicalDecl(); - - const llvm::Type *PtrDiffTy = - CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType()); - - llvm::Constant *Values[2]; - - Values[0] = CGM.GetCXXMemberFunctionPointerValue(MD); - - // The adjustment will always be 0. - Values[1] = llvm::ConstantInt::get(PtrDiffTy, 0); - - return llvm::ConstantStruct::get(CGM.getLLVMContext(), - Values, 2, /*Packed=*/false); - } - llvm::Constant *VisitUnaryAddrOf(UnaryOperator *E) { if (const MemberPointerType *MPT = - E->getType()->getAs()) { - QualType T = MPT->getPointeeType(); + E->getType()->getAs()) { DeclRefExpr *DRE = cast(E->getSubExpr()); - NamedDecl *ND = DRE->getDecl(); - if (T->isFunctionProtoType()) - return EmitMemberFunctionPointer(cast(ND)); - - // We have a pointer to data member. - return CGM.EmitPointerToDataMember(cast(ND)); + if (MPT->isMemberFunctionPointer()) + return CGM.getCXXABI().EmitMemberPointer(cast(ND)); + else + return CGM.getCXXABI().EmitMemberPointer(cast(ND)); } return 0; @@ -514,7 +492,7 @@ public: llvm::Constant *VisitCastExpr(CastExpr* E) { switch (E->getCastKind()) { - case CastExpr::CK_ToUnion: { + case CK_ToUnion: { // GCC cast to union extension assert(E->getType()->isUnionType() && "Destination type is not union type!"); @@ -549,44 +527,21 @@ public: llvm::StructType::get(C->getType()->getContext(), Types, false); return llvm::ConstantStruct::get(STy, Elts); } - case CastExpr::CK_NullToMemberPointer: - return CGM.EmitNullConstant(E->getType()); + case CK_NullToMemberPointer: { + const MemberPointerType *MPT = E->getType()->getAs(); + return CGM.getCXXABI().EmitNullMemberPointer(MPT); + } - case CastExpr::CK_BaseToDerivedMemberPointer: { + case CK_BaseToDerivedMemberPointer: { Expr *SubExpr = E->getSubExpr(); + llvm::Constant *C = + CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF); + if (!C) return 0; - const MemberPointerType *SrcTy = - SubExpr->getType()->getAs(); - const MemberPointerType *DestTy = - E->getType()->getAs(); - - const CXXRecordDecl *DerivedClass = - cast(cast(DestTy->getClass())->getDecl()); - - if (SrcTy->getPointeeType()->isFunctionProtoType()) { - llvm::Constant *C = - CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF); - if (!C) - return 0; - - llvm::ConstantStruct *CS = cast(C); - - // Check if we need to update the adjustment. - if (llvm::Constant *Offset = - CGM.GetNonVirtualBaseClassOffset(DerivedClass, E->getBasePath())) { - llvm::Constant *Values[2]; - - Values[0] = CS->getOperand(0); - Values[1] = llvm::ConstantExpr::getAdd(CS->getOperand(1), Offset); - return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2, - /*Packed=*/false); - } - - return CS; - } + return CGM.getCXXABI().EmitMemberPointerConversion(C, E); } - case CastExpr::CK_BitCast: + case CK_BitCast: // This must be a member function pointer cast. return Visit(E->getSubExpr()); @@ -792,7 +747,7 @@ public: case Expr::DeclRefExprClass: { ValueDecl *Decl = cast(E)->getDecl(); if (Decl->hasAttr()) - return CGM.GetWeakRefReference(Decl); + return CGM.GetWeakRefReference(Decl); if (const FunctionDecl *FD = dyn_cast(Decl)) return CGM.GetAddrOfFunction(FD); if (const VarDecl* VD = dyn_cast(Decl)) { @@ -821,7 +776,7 @@ public: case Expr::PredefinedExprClass: { unsigned Type = cast(E)->getIdentType(); if (CGF) { - LValue Res = CGF->EmitPredefinedFunctionName(Type); + LValue Res = CGF->EmitPredefinedLValue(cast(E)); return cast(Res.getAddress()); } else if (Type == PredefinedExpr::PrettyFunction) { return CGM.GetAddrOfConstantCString("top level", ".tmp"); @@ -989,7 +944,7 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T, uint64_t StartOffset) { assert(StartOffset % 8 == 0 && "StartOffset not byte aligned!"); - if (!CGM.getTypes().ContainsPointerToDataMember(T)) + if (CGM.getTypes().isZeroInitializable(T)) return; if (const ConstantArrayType *CAT = @@ -1022,7 +977,7 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T, continue; // Ignore bases that don't have any pointer to data members. - if (!CGM.getTypes().ContainsPointerToDataMember(BaseDecl)) + if (CGM.getTypes().isZeroInitializable(BaseDecl)) continue; uint64_t BaseOffset = Layout.getBaseClassOffset(BaseDecl); @@ -1036,7 +991,7 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T, E = RD->field_end(); I != E; ++I, ++FieldNo) { QualType FieldType = I->getType(); - if (!CGM.getTypes().ContainsPointerToDataMember(FieldType)) + if (CGM.getTypes().isZeroInitializable(FieldType)) continue; uint64_t FieldOffset = StartOffset + Layout.getFieldOffset(FieldNo); @@ -1061,7 +1016,7 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T, } llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { - if (!getTypes().ContainsPointerToDataMember(T)) + if (getTypes().isZeroInitializable(T)) return llvm::Constant::getNullValue(getTypes().ConvertTypeForMem(T)); if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(T)) { @@ -1105,7 +1060,7 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { continue; // Ignore bases that don't have any pointer to data members. - if (!getTypes().ContainsPointerToDataMember(BaseDecl)) + if (getTypes().isZeroInitializable(BaseDecl)) continue; // Currently, all bases are arrays of i8. Figure out how many elements @@ -1165,29 +1120,3 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { return llvm::ConstantInt::get(getTypes().ConvertTypeForMem(T), -1ULL, /*isSigned=*/true); } - -llvm::Constant * -CodeGenModule::EmitPointerToDataMember(const FieldDecl *FD) { - - // Itanium C++ ABI 2.3: - // A pointer to data member is an offset from the base address of the class - // object containing it, represented as a ptrdiff_t - - const CXXRecordDecl *ClassDecl = cast(FD->getParent()); - QualType ClassType = - getContext().getTypeDeclType(const_cast(ClassDecl)); - - const llvm::StructType *ClassLTy = - cast(getTypes().ConvertType(ClassType)); - - const CGRecordLayout &RL = - getTypes().getCGRecordLayout(FD->getParent()); - unsigned FieldNo = RL.getLLVMFieldNo(FD); - uint64_t Offset = - getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo); - - const llvm::Type *PtrDiffTy = - getTypes().ConvertType(getContext().getPointerDiffType()); - - return llvm::ConstantInt::get(PtrDiffTy, Offset); -} diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index ef38209..2318cc4 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" +#include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CodeGenModule.h" #include "clang/AST/ASTContext.h" @@ -137,7 +138,7 @@ public: CGF.getContext().typesAreCompatible( E->getArgType1(), E->getArgType2())); } - Value *VisitOffsetOfExpr(const OffsetOfExpr *E); + Value *VisitOffsetOfExpr(OffsetOfExpr *E); Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); Value *VisitAddrLabelExpr(const AddrLabelExpr *E) { llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel()); @@ -149,7 +150,10 @@ public: Expr::EvalResult Result; if (E->Evaluate(Result, CGF.getContext()) && Result.Val.isInt()) { assert(!Result.HasSideEffects && "Constant declref with side-effect?!"); - return llvm::ConstantInt::get(VMContext, Result.Val.getInt()); + llvm::ConstantInt *CI + = llvm::ConstantInt::get(VMContext, Result.Val.getInt()); + CGF.EmitDeclRefExprDbgValue(E, CI); + return CI; } return EmitLoadOfLValue(E); } @@ -235,6 +239,9 @@ public: Value *VisitUnaryAddrOf(const UnaryOperator *E) { + // If the sub-expression is an instance member reference, + // EmitDeclRefLValue will magically emit it with the appropriate + // value as the "address". return EmitLValue(E->getSubExpr()).getAddress(); } Value *VisitUnaryDeref(const Expr *E) { return EmitLoadOfLValue(E); } @@ -251,7 +258,6 @@ public: Value *VisitUnaryExtension(const UnaryOperator *E) { return Visit(E->getSubExpr()); } - Value *VisitUnaryOffsetOf(const UnaryOperator *E); // C++ Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { @@ -297,7 +303,7 @@ public: // Binary Operators. Value *EmitMul(const BinOpInfo &Ops) { - if (Ops.Ty->isSignedIntegerType()) { + if (Ops.Ty->hasSignedIntegerRepresentation()) { switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { case LangOptions::SOB_Undefined: return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); @@ -409,11 +415,8 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) { return Builder.CreateFCmpUNE(Src, Zero, "tobool"); } - if (SrcType->isMemberPointerType()) { - // Compare against -1. - llvm::Value *NegativeOne = llvm::Constant::getAllOnesValue(Src->getType()); - return Builder.CreateICmpNE(Src, NegativeOne, "tobool"); - } + if (const MemberPointerType *MPT = dyn_cast(SrcType)) + return CGF.CGM.getCXXABI().EmitMemberPointerIsNotNull(CGF, Src, MPT); assert((SrcType->isIntegerType() || isa(Src->getType())) && "Unknown scalar type to convert"); @@ -562,17 +565,10 @@ EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src, } Value *ScalarExprEmitter::EmitNullValue(QualType Ty) { - const llvm::Type *LTy = ConvertType(Ty); - - if (!Ty->isMemberPointerType()) - return llvm::Constant::getNullValue(LTy); - - assert(!Ty->isMemberFunctionPointerType() && - "member function pointers are not scalar!"); + if (const MemberPointerType *MPT = Ty->getAs()) + return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT); - // Itanium C++ ABI 2.3: - // A NULL pointer is represented as -1. - return llvm::ConstantInt::get(LTy, -1ULL, /*isSigned=*/true); + return llvm::Constant::getNullValue(ConvertType(Ty)); } //===----------------------------------------------------------------------===// @@ -888,7 +884,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { static bool ShouldNullCheckClassCastValue(const CastExpr *CE) { const Expr *E = CE->getSubExpr(); - if (CE->getCastKind() == CastExpr::CK_UncheckedDerivedToBase) + if (CE->getCastKind() == CK_UncheckedDerivedToBase) return false; if (isa(E)) { @@ -897,8 +893,8 @@ static bool ShouldNullCheckClassCastValue(const CastExpr *CE) { } if (const ImplicitCastExpr *ICE = dyn_cast(CE)) { - // And that lvalue casts are never null. - if (ICE->isLvalueCast()) + // And that glvalue casts are never null. + if (ICE->getValueKind() != VK_RValue) return false; } @@ -911,7 +907,7 @@ static bool ShouldNullCheckClassCastValue(const CastExpr *CE) { Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { Expr *E = CE->getSubExpr(); QualType DestTy = CE->getType(); - CastExpr::CastKind Kind = CE->getCastKind(); + CastKind Kind = CE->getCastKind(); if (!DestTy->isVoidType()) TestAndClearIgnoreResultAssign(); @@ -920,59 +916,58 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { // a default case, so the compiler will warn on a missing case. The cases // are in the same order as in the CastKind enum. switch (Kind) { - case CastExpr::CK_Unknown: + case CK_Unknown: // FIXME: All casts should have a known kind! //assert(0 && "Unknown cast kind!"); break; - case CastExpr::CK_LValueBitCast: { + case CK_LValueBitCast: + case CK_ObjCObjectLValueCast: { Value *V = EmitLValue(E).getAddress(); V = Builder.CreateBitCast(V, ConvertType(CGF.getContext().getPointerType(DestTy))); - // FIXME: Are the qualifiers correct here? - return EmitLoadOfLValue(LValue::MakeAddr(V, CGF.MakeQualifiers(DestTy)), - DestTy); + return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy), DestTy); } - case CastExpr::CK_AnyPointerToObjCPointerCast: - case CastExpr::CK_AnyPointerToBlockPointerCast: - case CastExpr::CK_BitCast: { + case CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_BitCast: { Value *Src = Visit(const_cast(E)); return Builder.CreateBitCast(Src, ConvertType(DestTy)); } - case CastExpr::CK_NoOp: - case CastExpr::CK_UserDefinedConversion: + case CK_NoOp: + case CK_UserDefinedConversion: return Visit(const_cast(E)); - case CastExpr::CK_BaseToDerived: { + case CK_BaseToDerived: { const CXXRecordDecl *DerivedClassDecl = DestTy->getCXXRecordDeclForPointerType(); return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl, - CE->getBasePath(), + CE->path_begin(), CE->path_end(), ShouldNullCheckClassCastValue(CE)); } - case CastExpr::CK_UncheckedDerivedToBase: - case CastExpr::CK_DerivedToBase: { + case CK_UncheckedDerivedToBase: + case CK_DerivedToBase: { const RecordType *DerivedClassTy = E->getType()->getAs()->getPointeeType()->getAs(); CXXRecordDecl *DerivedClassDecl = cast(DerivedClassTy->getDecl()); return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl, - CE->getBasePath(), + CE->path_begin(), CE->path_end(), ShouldNullCheckClassCastValue(CE)); } - case CastExpr::CK_Dynamic: { + case CK_Dynamic: { Value *V = Visit(const_cast(E)); const CXXDynamicCastExpr *DCE = cast(CE); return CGF.EmitDynamicCast(V, DCE); } - case CastExpr::CK_ToUnion: + case CK_ToUnion: assert(0 && "Should be unreachable!"); break; - case CastExpr::CK_ArrayToPointerDecay: { + case CK_ArrayToPointerDecay: { assert(E->getType()->isArrayType() && "Array to pointer decay must have array source type!"); @@ -990,62 +985,66 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { return V; } - case CastExpr::CK_FunctionToPointerDecay: + case CK_FunctionToPointerDecay: return EmitLValue(E).getAddress(); - case CastExpr::CK_NullToMemberPointer: - return CGF.CGM.EmitNullConstant(DestTy); + case CK_NullToMemberPointer: { + // If the subexpression's type is the C++0x nullptr_t, emit the + // subexpression, which may have side effects. + if (E->getType()->isNullPtrType()) + (void) Visit(E); - case CastExpr::CK_BaseToDerivedMemberPointer: - case CastExpr::CK_DerivedToBaseMemberPointer: { - Value *Src = Visit(E); + const MemberPointerType *MPT = CE->getType()->getAs(); + return CGF.CGM.getCXXABI().EmitNullMemberPointer(MPT); + } - // See if we need to adjust the pointer. - const CXXRecordDecl *BaseDecl = - cast(E->getType()->getAs()-> - getClass()->getAs()->getDecl()); - const CXXRecordDecl *DerivedDecl = - cast(CE->getType()->getAs()-> - getClass()->getAs()->getDecl()); - if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) - std::swap(DerivedDecl, BaseDecl); - - if (llvm::Constant *Adj = - CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, CE->getBasePath())){ - if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer) - Src = Builder.CreateNSWSub(Src, Adj, "adj"); - else - Src = Builder.CreateNSWAdd(Src, Adj, "adj"); - } + case CK_BaseToDerivedMemberPointer: + case CK_DerivedToBaseMemberPointer: { + Value *Src = Visit(E); - return Src; + // Note that the AST doesn't distinguish between checked and + // unchecked member pointer conversions, so we always have to + // implement checked conversions here. This is inefficient when + // actual control flow may be required in order to perform the + // check, which it is for data member pointers (but not member + // function pointers on Itanium and ARM). + return CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, CE, Src); } + - case CastExpr::CK_ConstructorConversion: + case CK_ConstructorConversion: assert(0 && "Should be unreachable!"); break; - case CastExpr::CK_IntegralToPointer: { + case CK_IntegralToPointer: { Value *Src = Visit(const_cast(E)); - + // First, convert to the correct width so that we control the kind of // extension. const llvm::Type *MiddleTy = CGF.IntPtrTy; bool InputSigned = E->getType()->isSignedIntegerType(); llvm::Value* IntResult = Builder.CreateIntCast(Src, MiddleTy, InputSigned, "conv"); - + return Builder.CreateIntToPtr(IntResult, ConvertType(DestTy)); } - case CastExpr::CK_PointerToIntegral: { + case CK_PointerToIntegral: { Value *Src = Visit(const_cast(E)); + + // Handle conversion to bool correctly. + if (DestTy->isBooleanType()) + return EmitScalarConversion(Src, E->getType(), DestTy); + return Builder.CreatePtrToInt(Src, ConvertType(DestTy)); } - case CastExpr::CK_ToVoid: { - CGF.EmitAnyExpr(E, 0, false, true); + case CK_ToVoid: { + if (E->Classify(CGF.getContext()).isGLValue()) + CGF.EmitLValue(E); + else + CGF.EmitAnyExpr(E, 0, false, true); return 0; } - case CastExpr::CK_VectorSplat: { + case CK_VectorSplat: { const llvm::Type *DstTy = ConvertType(DestTy); Value *Elt = Visit(const_cast(E)); @@ -1064,16 +1063,19 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat"); return Yay; } - case CastExpr::CK_IntegralCast: - case CastExpr::CK_IntegralToFloating: - case CastExpr::CK_FloatingToIntegral: - case CastExpr::CK_FloatingCast: + case CK_IntegralCast: + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + case CK_FloatingCast: return EmitScalarConversion(Visit(E), E->getType(), DestTy); - case CastExpr::CK_MemberPointerToBoolean: - return CGF.EvaluateExprAsBool(E); + case CK_MemberPointerToBoolean: { + llvm::Value *MemPtr = Visit(E); + const MemberPointerType *MPT = E->getType()->getAs(); + return CGF.CGM.getCXXABI().EmitMemberPointerIsNotNull(CGF, MemPtr, MPT); } - + } + // Handle cases where the source is an non-complex type. if (!CGF.hasAggregateLLVMType(E->getType())) { @@ -1116,7 +1118,7 @@ Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) { llvm::Value *V = CGF.GetAddrOfBlockDecl(E); if (E->getType().isObjCGCWeak()) return CGF.CGM.getObjCRuntime().EmitObjCWeakRead(CGF, V); - return Builder.CreateLoad(V, "tmp"); + return CGF.EmitLoadOfScalar(V, false, 0, E->getType()); } //===----------------------------------------------------------------------===// @@ -1156,7 +1158,7 @@ EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, NextVal = Builder.CreateGEP(InVal, Inc, "add.ptr"); llvm::Value *lhs = LV.getAddress(); lhs = Builder.CreateBitCast(lhs, llvm::PointerType::getUnqual(i8Ty)); - LV = LValue::MakeAddr(lhs, CGF.MakeQualifiers(ValTy)); + LV = CGF.MakeAddrLValue(lhs, ValTy); } else NextVal = Builder.CreateInBoundsGEP(InVal, Inc, "ptrincdec"); } else { @@ -1191,9 +1193,10 @@ EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, BinOp.LHS = InVal; BinOp.RHS = NextVal; BinOp.Ty = E->getType(); - BinOp.Opcode = BinaryOperator::Add; + BinOp.Opcode = BO_Add; BinOp.E = E; - return EmitOverflowCheckedBinOp(BinOp); + NextVal = EmitOverflowCheckedBinOp(BinOp); + break; } } } else { @@ -1240,7 +1243,7 @@ Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) { else BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType()); BinOp.Ty = E->getType(); - BinOp.Opcode = BinaryOperator::Sub; + BinOp.Opcode = BO_Sub; BinOp.E = E; return EmitSub(BinOp); } @@ -1264,19 +1267,94 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) { return Builder.CreateZExt(BoolVal, ConvertType(E->getType()), "lnot.ext"); } -Value *ScalarExprEmitter::VisitOffsetOfExpr(const OffsetOfExpr *E) { - Expr::EvalResult Result; - if(E->Evaluate(Result, CGF.getContext())) - return llvm::ConstantInt::get(VMContext, Result.Val.getInt()); - - // FIXME: Cannot support code generation for non-constant offsetof. - unsigned DiagID = CGF.CGM.getDiags().getCustomDiagID(Diagnostic::Error, - "cannot compile non-constant __builtin_offsetof"); - CGF.CGM.getDiags().Report(CGF.getContext().getFullLoc(E->getLocStart()), - DiagID) - << E->getSourceRange(); - - return llvm::Constant::getNullValue(ConvertType(E->getType())); +Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) { + // Try folding the offsetof to a constant. + Expr::EvalResult EvalResult; + if (E->Evaluate(EvalResult, CGF.getContext())) + return llvm::ConstantInt::get(VMContext, EvalResult.Val.getInt()); + + // Loop over the components of the offsetof to compute the value. + unsigned n = E->getNumComponents(); + const llvm::Type* ResultType = ConvertType(E->getType()); + llvm::Value* Result = llvm::Constant::getNullValue(ResultType); + QualType CurrentType = E->getTypeSourceInfo()->getType(); + for (unsigned i = 0; i != n; ++i) { + OffsetOfExpr::OffsetOfNode ON = E->getComponent(i); + llvm::Value *Offset = 0; + switch (ON.getKind()) { + case OffsetOfExpr::OffsetOfNode::Array: { + // Compute the index + Expr *IdxExpr = E->getIndexExpr(ON.getArrayExprIndex()); + llvm::Value* Idx = CGF.EmitScalarExpr(IdxExpr); + bool IdxSigned = IdxExpr->getType()->isSignedIntegerType(); + Idx = Builder.CreateIntCast(Idx, ResultType, IdxSigned, "conv"); + + // Save the element type + CurrentType = + CGF.getContext().getAsArrayType(CurrentType)->getElementType(); + + // Compute the element size + llvm::Value* ElemSize = llvm::ConstantInt::get(ResultType, + CGF.getContext().getTypeSizeInChars(CurrentType).getQuantity()); + + // Multiply out to compute the result + Offset = Builder.CreateMul(Idx, ElemSize); + break; + } + + case OffsetOfExpr::OffsetOfNode::Field: { + FieldDecl *MemberDecl = ON.getField(); + RecordDecl *RD = CurrentType->getAs()->getDecl(); + const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD); + + // Compute the index of the field in its parent. + unsigned i = 0; + // FIXME: It would be nice if we didn't have to loop here! + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; (void)++Field, ++i) { + if (*Field == MemberDecl) + break; + } + assert(i < RL.getFieldCount() && "offsetof field in wrong type"); + + // Compute the offset to the field + int64_t OffsetInt = RL.getFieldOffset(i) / + CGF.getContext().getCharWidth(); + Offset = llvm::ConstantInt::get(ResultType, OffsetInt); + + // Save the element type. + CurrentType = MemberDecl->getType(); + break; + } + + case OffsetOfExpr::OffsetOfNode::Identifier: + llvm_unreachable("dependent __builtin_offsetof"); + + case OffsetOfExpr::OffsetOfNode::Base: { + if (ON.getBase()->isVirtual()) { + CGF.ErrorUnsupported(E, "virtual base in offsetof"); + continue; + } + + RecordDecl *RD = CurrentType->getAs()->getDecl(); + const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD); + + // Save the element type. + CurrentType = ON.getBase()->getType(); + + // Compute the offset to the base. + const RecordType *BaseRT = CurrentType->getAs(); + CXXRecordDecl *BaseRD = cast(BaseRT->getDecl()); + int64_t OffsetInt = RL.getBaseClassOffset(BaseRD) / + CGF.getContext().getCharWidth(); + Offset = llvm::ConstantInt::get(ResultType, OffsetInt); + break; + } + } + Result = Builder.CreateAdd(Result, Offset); + } + return Result; } /// VisitSizeOfAlignOfExpr - Return the size or alignment of the type of @@ -1327,12 +1405,6 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) { return llvm::Constant::getNullValue(ConvertType(E->getType())); } -Value *ScalarExprEmitter::VisitUnaryOffsetOf(const UnaryOperator *E) { - Value* ResultAsPtr = EmitLValue(E->getSubExpr()).getAddress(); - const llvm::Type* ResultType = ConvertType(E->getType()); - return Builder.CreatePtrToInt(ResultAsPtr, ResultType, "offsetof"); -} - //===----------------------------------------------------------------------===// // Binary Operators //===----------------------------------------------------------------------===// @@ -1422,7 +1494,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { if (Ops.LHS->getType()->isFPOrFPVectorTy()) return Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div"); - else if (Ops.Ty->isUnsignedIntegerType()) + else if (Ops.Ty->hasUnsignedIntegerRepresentation()) return Builder.CreateUDiv(Ops.LHS, Ops.RHS, "div"); else return Builder.CreateSDiv(Ops.LHS, Ops.RHS, "div"); @@ -1441,18 +1513,18 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { unsigned OpID = 0; switch (Ops.Opcode) { - case BinaryOperator::Add: - case BinaryOperator::AddAssign: + case BO_Add: + case BO_AddAssign: OpID = 1; IID = llvm::Intrinsic::sadd_with_overflow; break; - case BinaryOperator::Sub: - case BinaryOperator::SubAssign: + case BO_Sub: + case BO_SubAssign: OpID = 2; IID = llvm::Intrinsic::ssub_with_overflow; break; - case BinaryOperator::Mul: - case BinaryOperator::MulAssign: + case BO_Mul: + case BO_MulAssign: OpID = 3; IID = llvm::Intrinsic::smul_with_overflow; break; @@ -1472,58 +1544,26 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { Value *overflow = Builder.CreateExtractValue(resultAndOverflow, 1); // Branch in case of overflow. - llvm::BasicBlock *initialBB = Builder.GetInsertBlock(); - llvm::BasicBlock *overflowBB = - CGF.createBasicBlock("overflow", CGF.CurFn); - llvm::BasicBlock *continueBB = - CGF.createBasicBlock("overflow.continue", CGF.CurFn); + llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", CGF.CurFn); + llvm::BasicBlock *continueBB = CGF.createBasicBlock("nooverflow", CGF.CurFn); Builder.CreateCondBr(overflow, overflowBB, continueBB); - // Handle overflow - + // Handle overflow with llvm.trap. + // TODO: it would be better to generate one of these blocks per function. Builder.SetInsertPoint(overflowBB); - - // Handler is: - // long long *__overflow_handler)(long long a, long long b, char op, - // char width) - std::vector handerArgTypes; - handerArgTypes.push_back(CGF.Int64Ty); - handerArgTypes.push_back(CGF.Int64Ty); - handerArgTypes.push_back(llvm::Type::getInt8Ty(VMContext)); - handerArgTypes.push_back(llvm::Type::getInt8Ty(VMContext)); - llvm::FunctionType *handlerTy = - llvm::FunctionType::get(CGF.Int64Ty, handerArgTypes, false); - llvm::Value *handlerFunction = - CGF.CGM.getModule().getOrInsertGlobal("__overflow_handler", - llvm::PointerType::getUnqual(handlerTy)); - handlerFunction = Builder.CreateLoad(handlerFunction); - - llvm::Value *handlerResult = Builder.CreateCall4(handlerFunction, - Builder.CreateSExt(Ops.LHS, CGF.Int64Ty), - Builder.CreateSExt(Ops.RHS, CGF.Int64Ty), - llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), OpID), - llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), - cast(opTy)->getBitWidth())); - - handlerResult = Builder.CreateTrunc(handlerResult, opTy); - - Builder.CreateBr(continueBB); - - // Set up the continuation + llvm::Function *Trap = CGF.CGM.getIntrinsic(llvm::Intrinsic::trap); + Builder.CreateCall(Trap); + Builder.CreateUnreachable(); + + // Continue on. Builder.SetInsertPoint(continueBB); - // Get the correct result - llvm::PHINode *phi = Builder.CreatePHI(opTy); - phi->reserveOperandSpace(2); - phi->addIncoming(result, initialBB); - phi->addIncoming(handlerResult, overflowBB); - - return phi; + return result; } Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { if (!Ops.Ty->isAnyPointerType()) { - if (Ops.Ty->isSignedIntegerType()) { + if (Ops.Ty->hasSignedIntegerRepresentation()) { switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { case LangOptions::SOB_Undefined: return Builder.CreateNSWAdd(Ops.LHS, Ops.RHS, "add"); @@ -1606,7 +1646,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { if (!isa(Ops.LHS->getType())) { - if (Ops.Ty->isSignedIntegerType()) { + if (Ops.Ty->hasSignedIntegerRepresentation()) { switch (CGF.getContext().getLangOptions().getSignedOverflowBehavior()) { case LangOptions::SOB_Undefined: return Builder.CreateNSWSub(Ops.LHS, Ops.RHS, "sub"); @@ -1747,7 +1787,7 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { CGF.EmitBlock(Cont); } - if (Ops.Ty->isUnsignedIntegerType()) + if (Ops.Ty->hasUnsignedIntegerRepresentation()) return Builder.CreateLShr(Ops.LHS, RHS, "shr"); return Builder.CreateAShr(Ops.LHS, RHS, "shr"); } @@ -1757,33 +1797,13 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, TestAndClearIgnoreResultAssign(); Value *Result; QualType LHSTy = E->getLHS()->getType(); - if (LHSTy->isMemberFunctionPointerType()) { - Value *LHSPtr = CGF.EmitAnyExprToTemp(E->getLHS()).getAggregateAddr(); - Value *RHSPtr = CGF.EmitAnyExprToTemp(E->getRHS()).getAggregateAddr(); - llvm::Value *LHSFunc = Builder.CreateStructGEP(LHSPtr, 0); - LHSFunc = Builder.CreateLoad(LHSFunc); - llvm::Value *RHSFunc = Builder.CreateStructGEP(RHSPtr, 0); - RHSFunc = Builder.CreateLoad(RHSFunc); - Value *ResultF = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, - LHSFunc, RHSFunc, "cmp.func"); - Value *NullPtr = llvm::Constant::getNullValue(LHSFunc->getType()); - Value *ResultNull = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, - LHSFunc, NullPtr, "cmp.null"); - llvm::Value *LHSAdj = Builder.CreateStructGEP(LHSPtr, 1); - LHSAdj = Builder.CreateLoad(LHSAdj); - llvm::Value *RHSAdj = Builder.CreateStructGEP(RHSPtr, 1); - RHSAdj = Builder.CreateLoad(RHSAdj); - Value *ResultA = Builder.CreateICmp((llvm::ICmpInst::Predicate)UICmpOpc, - LHSAdj, RHSAdj, "cmp.adj"); - if (E->getOpcode() == BinaryOperator::EQ) { - Result = Builder.CreateOr(ResultNull, ResultA, "or.na"); - Result = Builder.CreateAnd(Result, ResultF, "and.f"); - } else { - assert(E->getOpcode() == BinaryOperator::NE && - "Member pointer comparison other than == or != ?"); - Result = Builder.CreateAnd(ResultNull, ResultA, "and.na"); - Result = Builder.CreateOr(Result, ResultF, "or.f"); - } + if (const MemberPointerType *MPT = LHSTy->getAs()) { + assert(E->getOpcode() == BO_EQ || + E->getOpcode() == BO_NE); + Value *LHS = CGF.EmitScalarExpr(E->getLHS()); + Value *RHS = CGF.EmitScalarExpr(E->getRHS()); + Result = CGF.CGM.getCXXABI().EmitMemberPointerComparison( + CGF, LHS, RHS, MPT, E->getOpcode() == BO_NE); } else if (!LHSTy->isAnyComplexType()) { Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); @@ -1791,7 +1811,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, if (LHS->getType()->isFPOrFPVectorTy()) { Result = Builder.CreateFCmp((llvm::CmpInst::Predicate)FCmpOpc, LHS, RHS, "cmp"); - } else if (LHSTy->isSignedIntegerType()) { + } else if (LHSTy->hasSignedIntegerRepresentation()) { Result = Builder.CreateICmp((llvm::ICmpInst::Predicate)SICmpOpc, LHS, RHS, "cmp"); } else { @@ -1827,10 +1847,10 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, LHS.second, RHS.second, "cmp.i"); } - if (E->getOpcode() == BinaryOperator::EQ) { + if (E->getOpcode() == BO_EQ) { Result = Builder.CreateAnd(ResultR, ResultI, "and.ri"); } else { - assert(E->getOpcode() == BinaryOperator::NE && + assert(E->getOpcode() == BO_NE && "Complex comparison other than == or != ?"); Result = Builder.CreateOr(ResultR, ResultI, "or.ri"); } @@ -2044,7 +2064,12 @@ VisitConditionalOperator(const ConditionalOperator *E) { return Builder.CreateSelect(CondV, LHS, RHS, "cond"); } - + if (!E->getLHS() && CGF.getContext().getLangOptions().CPlusPlus) { + // Does not support GNU missing condition extension in C++ yet (see #7726) + CGF.ErrorUnsupported(E, "conditional operator with missing LHS"); + return llvm::UndefValue::get(ConvertType(E->getType())); + } + llvm::BasicBlock *LHSBlock = CGF.createBasicBlock("cond.true"); llvm::BasicBlock *RHSBlock = CGF.createBasicBlock("cond.false"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("cond.end"); @@ -2188,21 +2213,19 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) { V = CreateTempAlloca(ClassPtrTy, "resval"); llvm::Value *Src = EmitScalarExpr(BaseExpr); Builder.CreateStore(Src, V); - LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); - V = ScalarExprEmitter(*this).EmitLoadOfLValue(LV, E->getType()); - } - else { - if (E->isArrow()) - V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr); - else - V = EmitLValue(BaseExpr).getAddress(); + V = ScalarExprEmitter(*this).EmitLoadOfLValue( + MakeAddrLValue(V, E->getType()), E->getType()); + } else { + if (E->isArrow()) + V = ScalarExprEmitter(*this).EmitLoadOfLValue(BaseExpr); + else + V = EmitLValue(BaseExpr).getAddress(); } // build Class* type ClassPtrTy = ClassPtrTy->getPointerTo(); V = Builder.CreateBitCast(V, ClassPtrTy); - LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType())); - return LV; + return MakeAddrLValue(V, E->getType()); } @@ -2212,7 +2235,7 @@ LValue CodeGenFunction::EmitCompoundAssignOperatorLValue( Value *Result = 0; switch (E->getOpcode()) { #define COMPOUND_OP(Op) \ - case BinaryOperator::Op##Assign: \ + case BO_##Op##Assign: \ return Scalar.EmitCompoundAssignLValue(E, &ScalarExprEmitter::Emit##Op, \ Result) COMPOUND_OP(Mul); @@ -2227,28 +2250,28 @@ LValue CodeGenFunction::EmitCompoundAssignOperatorLValue( COMPOUND_OP(Or); #undef COMPOUND_OP - case BinaryOperator::PtrMemD: - case BinaryOperator::PtrMemI: - case BinaryOperator::Mul: - case BinaryOperator::Div: - case BinaryOperator::Rem: - case BinaryOperator::Add: - case BinaryOperator::Sub: - case BinaryOperator::Shl: - case BinaryOperator::Shr: - case BinaryOperator::LT: - case BinaryOperator::GT: - case BinaryOperator::LE: - case BinaryOperator::GE: - case BinaryOperator::EQ: - case BinaryOperator::NE: - case BinaryOperator::And: - case BinaryOperator::Xor: - case BinaryOperator::Or: - case BinaryOperator::LAnd: - case BinaryOperator::LOr: - case BinaryOperator::Assign: - case BinaryOperator::Comma: + case BO_PtrMemD: + case BO_PtrMemI: + case BO_Mul: + case BO_Div: + case BO_Rem: + case BO_Add: + case BO_Sub: + case BO_Shl: + case BO_Shr: + case BO_LT: + case BO_GT: + case BO_LE: + case BO_GE: + case BO_EQ: + case BO_NE: + case BO_And: + case BO_Xor: + case BO_Or: + case BO_LAnd: + case BO_LOr: + case BO_Assign: + case BO_Comma: assert(false && "Not valid compound assignment operators"); break; } diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index e735a61..6a6d63d 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -403,13 +403,14 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, // Objective-C pointer types, we can always bit cast the RHS in these cases. if (getContext().getCanonicalType(Ivar->getType()) != getContext().getCanonicalType(ArgDecl->getType())) { - ImplicitCastExpr ArgCasted(Ivar->getType(), CastExpr::CK_BitCast, &Arg, - CXXBaseSpecifierArray(), false); - BinaryOperator Assign(&IvarRef, &ArgCasted, BinaryOperator::Assign, + ImplicitCastExpr ArgCasted(ImplicitCastExpr::OnStack, + Ivar->getType(), CK_BitCast, &Arg, + VK_RValue); + BinaryOperator Assign(&IvarRef, &ArgCasted, BO_Assign, Ivar->getType(), Loc); EmitStmt(&Assign); } else { - BinaryOperator Assign(&IvarRef, &Arg, BinaryOperator::Assign, + BinaryOperator Assign(&IvarRef, &Arg, BO_Assign, Ivar->getType(), Loc); EmitStmt(&Assign); } @@ -571,7 +572,7 @@ void CodeGenFunction::EmitObjCSuperPropertySet(const Expr *Exp, Args.push_back(std::make_pair(Src, Exp->getType())); CGM.getObjCRuntime().GenerateMessageSendSuper(*this, ReturnValueSlot(), - Exp->getType(), + getContext().VoidTy, S, OMD->getClassInterface(), isCategoryImpl, @@ -792,7 +793,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ BreakContinueStack.pop_back(); - EmitBlock(AfterBody.Block); + EmitBlock(AfterBody.getBlock()); llvm::BasicBlock *FetchMore = createBasicBlock("fetchmore"); @@ -828,7 +829,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ LV.getAddress()); } - EmitBlock(LoopEnd.Block); + EmitBlock(LoopEnd.getBlock()); } void CodeGenFunction::EmitObjCAtTryStmt(const ObjCAtTryStmt &S) { diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index f3c80bc..d7960be 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -167,6 +167,7 @@ public: bool lval = false); virtual llvm::Value *GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl *Method); + virtual llvm::Constant *GetEHType(QualType T); virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD); @@ -192,7 +193,8 @@ public: virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst); virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dest); + llvm::Value *src, llvm::Value *dest, + bool threadlocal=false); virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest, llvm::Value *ivarOffset); @@ -210,6 +212,10 @@ public: virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); + virtual llvm::Constant *GCBlockLayout(CodeGen::CodeGenFunction &CGF, + const llvm::SmallVectorImpl &) { + return NULLPtr; + } }; } // end anonymous namespace @@ -402,6 +408,11 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl return Builder.CreateLoad(Sel); } +llvm::Constant *CGObjCGNU::GetEHType(QualType T) { + llvm_unreachable("asking for catch type for ObjC type in GNU runtime"); + return 0; +} + llvm::Constant *CGObjCGNU::MakeConstantString(const std::string &Str, const std::string &Name) { llvm::Constant *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str()); @@ -438,7 +449,7 @@ llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty, /// Generate an NSConstantString object. llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) { - std::string Str(SL->getStrData(), SL->getByteLength()); + std::string Str = SL->getString().str(); // Look for an existing one llvm::StringMap::iterator old = ObjCStrings.find(Str); @@ -691,7 +702,7 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, Params.push_back(SelectorTy); llvm::Value *self; - if (isa(CGF.CurFuncDecl)) { + if (isa(CGF.CurCodeDecl)) { self = CGF.LoadObjCSelf(); } else { self = llvm::ConstantPointerNull::get(IdTy); @@ -721,8 +732,8 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, // The lookup function may have changed the receiver, so make sure we use // the new one. - ActualArgs[0] = - std::make_pair(RValue::get(Builder.CreateLoad(ReceiverPtr)), ASTIdTy); + ActualArgs[0] = std::make_pair(RValue::get( + Builder.CreateLoad(ReceiverPtr, true)), ASTIdTy); } else { std::vector Params; Params.push_back(Receiver->getType()); @@ -1854,6 +1865,19 @@ llvm::Constant *CGObjCGNU::EnumerationMutationFunction() { return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation"); } +namespace { + struct CallSyncExit : EHScopeStack::Cleanup { + llvm::Value *SyncExitFn; + llvm::Value *SyncArg; + CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg) + : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {} + + void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { + CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow(); + } + }; +} + void CGObjCGNU::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtSynchronizedStmt &S) { std::vector Args(1, IdTy); @@ -1870,13 +1894,8 @@ void CGObjCGNU::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.Builder.CreateCall(SyncEnter, SyncArg); // Register an all-paths cleanup to release the lock. - { - CodeGenFunction::CleanupBlock ReleaseScope(CGF, NormalAndEHCleanup); - - llvm::Value *SyncExit = CGM.CreateRuntimeFunction(FTy, "objc_sync_exit"); - SyncArg = CGF.Builder.CreateBitCast(SyncArg, IdTy); - CGF.Builder.CreateCall(SyncExit, SyncArg); - } + llvm::Value *SyncExit = CGM.CreateRuntimeFunction(FTy, "objc_sync_exit"); + CGF.EHStack.pushCleanup(NormalAndEHCleanup, SyncExit, SyncArg); // Emit the body of the statement. CGF.EmitStmt(S.getSynchBody()); @@ -2007,13 +2026,11 @@ void CGObjCGNU::EmitTryStmt(CodeGen::CodeGenFunction &CGF, if (S.getFinallyStmt()) CGF.ExitFinallyBlock(FinallyInfo); - if (Cont.Block) { - if (Cont.Block->use_empty()) - delete Cont.Block; - else { - CGF.EmitBranch(Cont.Block); - CGF.EmitBlock(Cont.Block); - } + if (Cont.isValid()) { + if (Cont.getBlock()->use_empty()) + delete Cont.getBlock(); + else + CGF.EmitBlock(Cont.getBlock()); } } @@ -2075,11 +2092,16 @@ void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, } void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) { + llvm::Value *src, llvm::Value *dst, + bool threadlocal) { CGBuilderTy B = CGF.Builder; src = EnforceType(B, src, IdTy); dst = EnforceType(B, dst, PtrToIdTy); - B.CreateCall2(GlobalAssignFn, src, dst); + if (!threadlocal) + B.CreateCall2(GlobalAssignFn, src, dst); + else + // FIXME. Add threadloca assign API + assert(false && "EmitObjCGlobalAssign - Threal Local API NYI"); } void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 01ead9e..54d0ff2 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -25,7 +25,8 @@ #include "clang/Basic/LangOptions.h" #include "clang/Frontend/CodeGenOptions.h" -#include "llvm/Intrinsics.h" +#include "llvm/InlineAsm.h" +#include "llvm/IntrinsicInst.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/ADT/DenseSet.h" @@ -106,17 +107,33 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, V = CGF.Builder.CreateGEP(V, Offset, "add.ptr"); V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy)); - Qualifiers Quals = CGF.MakeQualifiers(IvarTy); - Quals.addCVRQualifiers(CVRQualifiers); - - if (!Ivar->isBitField()) - return LValue::MakeAddr(V, Quals); + if (!Ivar->isBitField()) { + LValue LV = CGF.MakeAddrLValue(V, IvarTy); + LV.getQuals().addCVRQualifiers(CVRQualifiers); + return LV; + } - // We need to compute the bit offset for the bit-field, the offset is to the - // byte. Note, there is a subtle invariant here: we can only call this routine - // on non-synthesized ivars but we may be called for synthesized ivars. - // However, a synthesized ivar can never be a bit-field, so this is safe. - uint64_t BitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar) % 8; + // We need to compute an access strategy for this bit-field. We are given the + // offset to the first byte in the bit-field, the sub-byte offset is taken + // from the original layout. We reuse the normal bit-field access strategy by + // treating this as an access to a struct where the bit-field is in byte 0, + // and adjust the containing type size as appropriate. + // + // FIXME: Note that currently we make a very conservative estimate of the + // alignment of the bit-field, because (a) it is not clear what guarantees the + // runtime makes us, and (b) we don't have a way to specify that the struct is + // at an alignment plus offset. + // + // Note, there is a subtle invariant here: we can only call this routine on + // non-synthesized ivars but we may be called for synthesized ivars. However, + // a synthesized ivar can never be a bit-field, so this is safe. + const ASTRecordLayout &RL = + CGF.CGM.getContext().getASTObjCInterfaceLayout(OID); + uint64_t TypeSizeInBits = RL.getSize(); + uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar); + uint64_t BitOffset = FieldBitOffset % 8; + uint64_t ContainingTypeAlign = 8; + uint64_t ContainingTypeSize = TypeSizeInBits - (FieldBitOffset - BitOffset); uint64_t BitFieldSize = Ivar->getBitWidth()->EvaluateAsInt(CGF.getContext()).getZExtValue(); @@ -126,24 +143,12 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, // layout object. However, this is blocked on other cleanups to the // Objective-C code, so for now we just live with allocating a bunch of these // objects. + CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo( + CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize, + ContainingTypeSize, ContainingTypeAlign)); - // We always construct a single, possibly unaligned, access for this case. - CGBitFieldInfo::AccessInfo AI; - AI.FieldIndex = 0; - AI.FieldByteOffset = 0; - AI.FieldBitStart = BitOffset; - AI.AccessWidth = CGF.CGM.getContext().getTypeSize(IvarTy); - AI.AccessAlignment = 0; - AI.TargetBitOffset = 0; - AI.TargetBitWidth = BitFieldSize; - - CGBitFieldInfo *Info = - new (CGF.CGM.getContext()) CGBitFieldInfo(BitFieldSize, 1, &AI, - IvarTy->isSignedIntegerType()); - - // FIXME: We need to set a very conservative alignment on this, or make sure - // that the runtime is doing the right thing. - return LValue::MakeBitfield(V, *Info, Quals.getCVRQualifiers()); + return LValue::MakeBitfield(V, *Info, + IvarTy.getCVRQualifiers() | CVRQualifiers); } /// @@ -402,6 +407,16 @@ public: return CGM.CreateRuntimeFunction(FTy, "objc_assign_global"); } + /// GcAssignThreadLocalFn -- LLVM objc_assign_threadlocal function. + llvm::Constant *getGcAssignThreadLocalFn() { + // id objc_assign_threadlocal(id src, id * dest) + std::vector Args(1, ObjectPtrTy); + Args.push_back(ObjectPtrTy->getPointerTo()); + llvm::FunctionType *FTy = + llvm::FunctionType::get(ObjectPtrTy, Args, false); + return CGM.CreateRuntimeFunction(FTy, "objc_assign_threadlocal"); + } + /// GcAssignIvarFn -- LLVM objc_assign_ivar function. llvm::Constant *getGcAssignIvarFn() { // id objc_assign_ivar(id, id *, ptrdiff_t) @@ -425,7 +440,7 @@ public: /// GcAssignStrongCastFn -- LLVM objc_assign_strongCast function. llvm::Constant *getGcAssignStrongCastFn() { - // id objc_assign_global(id, id *) + // id objc_assign_strongCast(id, id *) std::vector Args(1, ObjectPtrTy); Args.push_back(ObjectPtrTy->getPointerTo()); llvm::FunctionType *FTy = @@ -719,25 +734,6 @@ public: "objc_msgSend_stret_fixup"); } - llvm::Constant *getMessageSendIdFixupFn() { - // id objc_msgSendId_fixup(id, struct message_ref_t*, ...) - std::vector Params; - Params.push_back(ObjectPtrTy); - Params.push_back(MessageRefPtrTy); - return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, true), - "objc_msgSendId_fixup"); - } - - llvm::Constant *getMessageSendIdStretFixupFn() { - // id objc_msgSendId_stret_fixup(id, struct message_ref_t*, ...) - std::vector Params; - Params.push_back(ObjectPtrTy); - Params.push_back(MessageRefPtrTy); - return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, - Params, true), - "objc_msgSendId_stret_fixup"); - } llvm::Constant *getMessageSendSuper2FixupFn() { // id objc_msgSendSuper2_fixup (struct objc_super *, // struct _super_message_ref_t*, ...) @@ -760,28 +756,6 @@ public: "objc_msgSendSuper2_stret_fixup"); } - - - /// EHPersonalityPtr - LLVM value for an i8* to the Objective-C - /// exception personality function. - llvm::Value *getEHPersonalityPtr() { - llvm::Constant *Personality = - CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty(VMContext), - true), - "__objc_personality_v0"); - return llvm::ConstantExpr::getBitCast(Personality, Int8PtrTy); - } - - llvm::Constant *getUnwindResumeOrRethrowFn() { - std::vector Params; - Params.push_back(Int8PtrTy); - return CGM.CreateRuntimeFunction( - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), - Params, false), - (CGM.getLangOptions().SjLjExceptions ? "_Unwind_SjLj_Resume" : - "_Unwind_Resume_or_Rethrow")); - } - llvm::Constant *getObjCEndCatchFn() { return CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false), @@ -905,7 +879,6 @@ protected: /// selector's name. The return value has type char *. llvm::Constant *GetMethodVarName(Selector Sel); llvm::Constant *GetMethodVarName(IdentifierInfo *Ident); - llvm::Constant *GetMethodVarName(const std::string &Name); /// GetMethodVarType - Return a unique constant for the given /// selector's name. The return value has type char *. @@ -926,11 +899,15 @@ protected: /// name. The return value has type char *. llvm::Constant *GetClassName(IdentifierInfo *Ident); + llvm::Function *GetMethodDefinition(const ObjCMethodDecl *MD); + /// BuildIvarLayout - Builds ivar layout bitmap for the class /// implementation for the __strong or __weak case. /// llvm::Constant *BuildIvarLayout(const ObjCImplementationDecl *OI, bool ForStrongLayout); + + llvm::Constant *BuildIvarLayoutBitmap(std::string &BitMap); void BuildAggrIvarRecordLayout(const RecordType *RT, unsigned int BytePos, bool ForStrongLayout, @@ -1022,6 +999,9 @@ public: /// forward references will be filled in with empty bodies if no /// definition is seen. The return value has type ProtocolPtrTy. virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0; + virtual llvm::Constant *GCBlockLayout(CodeGen::CodeGenFunction &CGF, + const llvm::SmallVectorImpl &); + }; class CGObjCMac : public CGObjCCommonMac { @@ -1053,15 +1033,6 @@ private: /// EmitSuperClassRef - Emits reference to class's main metadata class. llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID); - CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF, - ReturnValueSlot Return, - QualType ResultType, - Selector Sel, - llvm::Value *Arg0, - QualType Arg0Ty, - bool IsSuper, - const CallArgList &CallArgs); - /// EmitIvarList - Emit the ivar list for the given /// implementation. If ForClass is true the list of class ivars /// (i.e. metaclass ivars) is emitted, otherwise the list of @@ -1174,6 +1145,8 @@ public: virtual llvm::Value *GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl *Method); + virtual llvm::Constant *GetEHType(QualType T); + virtual void GenerateCategory(const ObjCCategoryImplDecl *CMD); virtual void GenerateClass(const ObjCImplementationDecl *ClassDecl); @@ -1198,7 +1171,8 @@ public: virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst); virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dest); + llvm::Value *src, llvm::Value *dest, + bool threadlocal = false); virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest, llvm::Value *ivarOffset); @@ -1343,7 +1317,7 @@ private: /// GetInterfaceEHType - Get the cached ehtype for the given Objective-C /// interface. The return value has type EHTypePtrTy. - llvm::Value *GetInterfaceEHType(const ObjCInterfaceDecl *ID, + llvm::Constant *GetInterfaceEHType(const ObjCInterfaceDecl *ID, bool ForDefinition); const char *getMetaclassSymbolPrefix() const { @@ -1418,6 +1392,8 @@ public: virtual llvm::Value *GenerateProtocolRef(CGBuilderTy &Builder, const ObjCProtocolDecl *PD); + virtual llvm::Constant *GetEHType(QualType T); + virtual llvm::Constant *GetPropertyGetFunction() { return ObjCTypes.getGetPropertyFn(); } @@ -1444,7 +1420,8 @@ public: virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst); virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dest); + llvm::Value *src, llvm::Value *dest, + bool threadlocal = false); virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest, llvm::Value *ivarOffset); @@ -1515,6 +1492,11 @@ llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl return EmitSelector(Builder, Method->getSelector()); } +llvm::Constant *CGObjCMac::GetEHType(QualType T) { + llvm_unreachable("asking for catch type for ObjC type in fragile runtime"); + return 0; +} + /// Generate a constant CFString object. /* struct __builtin_CFString { @@ -1664,6 +1646,90 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, return CGF.EmitCall(FnInfo, Fn, Return, ActualArgs); } +static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) { + if (FQT.isObjCGCStrong()) + return Qualifiers::Strong; + + if (FQT.isObjCGCWeak()) + return Qualifiers::Weak; + + if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType()) + return Qualifiers::Strong; + + if (const PointerType *PT = FQT->getAs()) + return GetGCAttrTypeForType(Ctx, PT->getPointeeType()); + + return Qualifiers::GCNone; +} + +llvm::Constant *CGObjCCommonMac::GCBlockLayout(CodeGen::CodeGenFunction &CGF, + const llvm::SmallVectorImpl &DeclRefs) { + llvm::Constant *NullPtr = + llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext)); + if ((CGM.getLangOptions().getGCMode() == LangOptions::NonGC) || + DeclRefs.empty()) + return NullPtr; + bool hasUnion = false; + SkipIvars.clear(); + IvarsInfo.clear(); + unsigned WordSizeInBits = CGM.getContext().Target.getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getContext().Target.getCharWidth(); + + for (size_t i = 0; i < DeclRefs.size(); ++i) { + const BlockDeclRefExpr *BDRE = DeclRefs[i]; + const ValueDecl *VD = BDRE->getDecl(); + CharUnits Offset = CGF.BlockDecls[VD]; + uint64_t FieldOffset = Offset.getQuantity(); + QualType Ty = VD->getType(); + assert(!Ty->isArrayType() && + "Array block variable should have been caught"); + if ((Ty->isRecordType() || Ty->isUnionType()) && !BDRE->isByRef()) { + BuildAggrIvarRecordLayout(Ty->getAs(), + FieldOffset, + true, + hasUnion); + continue; + } + + Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), Ty); + unsigned FieldSize = CGM.getContext().getTypeSize(Ty); + // __block variables are passed by their descriptior address. So, size + // must reflect this. + if (BDRE->isByRef()) + FieldSize = WordSizeInBits; + if (GCAttr == Qualifiers::Strong || BDRE->isByRef()) + IvarsInfo.push_back(GC_IVAR(FieldOffset, + FieldSize / WordSizeInBits)); + else if (GCAttr == Qualifiers::GCNone || GCAttr == Qualifiers::Weak) + SkipIvars.push_back(GC_IVAR(FieldOffset, + FieldSize / ByteSizeInBits)); + } + + if (IvarsInfo.empty()) + return NullPtr; + // Sort on byte position in case we encounterred a union nested in + // block variable type's aggregate type. + if (hasUnion && !IvarsInfo.empty()) + std::sort(IvarsInfo.begin(), IvarsInfo.end()); + if (hasUnion && !SkipIvars.empty()) + std::sort(SkipIvars.begin(), SkipIvars.end()); + + std::string BitMap; + llvm::Constant *C = BuildIvarLayoutBitmap(BitMap); + if (CGM.getLangOptions().ObjCGCBitmapPrint) { + printf("\n block variable layout for block: "); + const unsigned char *s = (unsigned char*)BitMap.c_str(); + for (unsigned i = 0; i < BitMap.size(); i++) + if (!(s[i] & 0xf0)) + printf("0x0%x%s", s[i], s[i] != 0 ? ", " : ""); + else + printf("0x%x%s", s[i], s[i] != 0 ? ", " : ""); + printf("\n"); + } + + return C; +} + llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder, const ObjCProtocolDecl *PD) { // FIXME: I don't understand why gcc generates this, or where it is @@ -1927,8 +1993,9 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(llvm::Twine Name, Prop)); } if (const ObjCInterfaceDecl *OID = dyn_cast(OCD)) { - for (ObjCInterfaceDecl::protocol_iterator P = OID->protocol_begin(), - E = OID->protocol_end(); P != E; ++P) + for (ObjCInterfaceDecl::all_protocol_iterator + P = OID->all_referenced_protocol_begin(), + E = OID->all_referenced_protocol_end(); P != E; ++P) PushProtocolProperties(PropertySet, Properties, Container, (*P), ObjCTypes); } @@ -2116,8 +2183,8 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { const_cast(ID->getClassInterface()); llvm::Constant *Protocols = EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getName(), - Interface->protocol_begin(), - Interface->protocol_end()); + Interface->all_referenced_protocol_begin(), + Interface->all_referenced_protocol_end()); unsigned Flags = eClassFlags_Factory; if (ID->getNumIvarInitializers()) Flags |= eClassFlags_HasCXXStructors; @@ -2427,8 +2494,7 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, /// given method if it has been defined. The result is null if the /// method has not been defined. The return value has type MethodPtrTy. llvm::Constant *CGObjCMac::GetMethodConstant(const ObjCMethodDecl *MD) { - // FIXME: Use DenseMap::lookup - llvm::Function *Fn = MethodDefinitions[MD]; + llvm::Function *Fn = GetMethodDefinition(MD); if (!Fn) return 0; @@ -2529,6 +2595,214 @@ void CGObjCMac::EmitSynchronizedStmt(CodeGenFunction &CGF, return EmitTryOrSynchronizedStmt(CGF, S); } +namespace { + struct PerformFragileFinally : EHScopeStack::Cleanup { + const Stmt &S; + llvm::Value *SyncArgSlot; + llvm::Value *CallTryExitVar; + llvm::Value *ExceptionData; + ObjCTypesHelper &ObjCTypes; + PerformFragileFinally(const Stmt *S, + llvm::Value *SyncArgSlot, + llvm::Value *CallTryExitVar, + llvm::Value *ExceptionData, + ObjCTypesHelper *ObjCTypes) + : S(*S), SyncArgSlot(SyncArgSlot), CallTryExitVar(CallTryExitVar), + ExceptionData(ExceptionData), ObjCTypes(*ObjCTypes) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + // Check whether we need to call objc_exception_try_exit. + // In optimized code, this branch will always be folded. + llvm::BasicBlock *FinallyCallExit = + CGF.createBasicBlock("finally.call_exit"); + llvm::BasicBlock *FinallyNoCallExit = + CGF.createBasicBlock("finally.no_call_exit"); + CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CallTryExitVar), + FinallyCallExit, FinallyNoCallExit); + + CGF.EmitBlock(FinallyCallExit); + CGF.Builder.CreateCall(ObjCTypes.getExceptionTryExitFn(), ExceptionData) + ->setDoesNotThrow(); + + CGF.EmitBlock(FinallyNoCallExit); + + if (isa(S)) { + if (const ObjCAtFinallyStmt* FinallyStmt = + cast(S).getFinallyStmt()) { + // Save the current cleanup destination in case there's + // control flow inside the finally statement. + llvm::Value *CurCleanupDest = + CGF.Builder.CreateLoad(CGF.getNormalCleanupDestSlot()); + + CGF.EmitStmt(FinallyStmt->getFinallyBody()); + + if (CGF.HaveInsertPoint()) { + CGF.Builder.CreateStore(CurCleanupDest, + CGF.getNormalCleanupDestSlot()); + } else { + // Currently, the end of the cleanup must always exist. + CGF.EnsureInsertPoint(); + } + } + } else { + // Emit objc_sync_exit(expr); as finally's sole statement for + // @synchronized. + llvm::Value *SyncArg = CGF.Builder.CreateLoad(SyncArgSlot); + CGF.Builder.CreateCall(ObjCTypes.getSyncExitFn(), SyncArg) + ->setDoesNotThrow(); + } + } + }; + + class FragileHazards { + CodeGenFunction &CGF; + llvm::SmallVector Locals; + llvm::DenseSet BlocksBeforeTry; + + llvm::InlineAsm *ReadHazard; + llvm::InlineAsm *WriteHazard; + + llvm::FunctionType *GetAsmFnType(); + + void collectLocals(); + void emitReadHazard(CGBuilderTy &Builder); + + public: + FragileHazards(CodeGenFunction &CGF); + + void emitWriteHazard(); + void emitHazardsInNewBlocks(); + }; +} + +/// Create the fragile-ABI read and write hazards based on the current +/// state of the function, which is presumed to be immediately prior +/// to a @try block. These hazards are used to maintain correct +/// semantics in the face of optimization and the fragile ABI's +/// cavalier use of setjmp/longjmp. +FragileHazards::FragileHazards(CodeGenFunction &CGF) : CGF(CGF) { + collectLocals(); + + if (Locals.empty()) return; + + // Collect all the blocks in the function. + for (llvm::Function::iterator + I = CGF.CurFn->begin(), E = CGF.CurFn->end(); I != E; ++I) + BlocksBeforeTry.insert(&*I); + + llvm::FunctionType *AsmFnTy = GetAsmFnType(); + + // Create a read hazard for the allocas. This inhibits dead-store + // optimizations and forces the values to memory. This hazard is + // inserted before any 'throwing' calls in the protected scope to + // reflect the possibility that the variables might be read from the + // catch block if the call throws. + { + std::string Constraint; + for (unsigned I = 0, E = Locals.size(); I != E; ++I) { + if (I) Constraint += ','; + Constraint += "*m"; + } + + ReadHazard = llvm::InlineAsm::get(AsmFnTy, "", Constraint, true, false); + } + + // Create a write hazard for the allocas. This inhibits folding + // loads across the hazard. This hazard is inserted at the + // beginning of the catch path to reflect the possibility that the + // variables might have been written within the protected scope. + { + std::string Constraint; + for (unsigned I = 0, E = Locals.size(); I != E; ++I) { + if (I) Constraint += ','; + Constraint += "=*m"; + } + + WriteHazard = llvm::InlineAsm::get(AsmFnTy, "", Constraint, true, false); + } +} + +/// Emit a write hazard at the current location. +void FragileHazards::emitWriteHazard() { + if (Locals.empty()) return; + + CGF.Builder.CreateCall(WriteHazard, Locals.begin(), Locals.end()) + ->setDoesNotThrow(); +} + +void FragileHazards::emitReadHazard(CGBuilderTy &Builder) { + assert(!Locals.empty()); + Builder.CreateCall(ReadHazard, Locals.begin(), Locals.end()) + ->setDoesNotThrow(); +} + +/// Emit read hazards in all the protected blocks, i.e. all the blocks +/// which have been inserted since the beginning of the try. +void FragileHazards::emitHazardsInNewBlocks() { + if (Locals.empty()) return; + + CGBuilderTy Builder(CGF.getLLVMContext()); + + // Iterate through all blocks, skipping those prior to the try. + for (llvm::Function::iterator + FI = CGF.CurFn->begin(), FE = CGF.CurFn->end(); FI != FE; ++FI) { + llvm::BasicBlock &BB = *FI; + if (BlocksBeforeTry.count(&BB)) continue; + + // Walk through all the calls in the block. + for (llvm::BasicBlock::iterator + BI = BB.begin(), BE = BB.end(); BI != BE; ++BI) { + llvm::Instruction &I = *BI; + + // Ignore instructions that aren't non-intrinsic calls. + // These are the only calls that can possibly call longjmp. + if (!isa(I) && !isa(I)) continue; + if (isa(I)) + continue; + + // Ignore call sites marked nounwind. This may be questionable, + // since 'nounwind' doesn't necessarily mean 'does not call longjmp'. + llvm::CallSite CS(&I); + if (CS.doesNotThrow()) continue; + + // Insert a read hazard before the call. This will ensure that + // any writes to the locals are performed before making the + // call. If the call throws, then this is sufficient to + // guarantee correctness as long as it doesn't also write to any + // locals. + Builder.SetInsertPoint(&BB, BI); + emitReadHazard(Builder); + } + } +} + +static void addIfPresent(llvm::DenseSet &S, llvm::Value *V) { + if (V) S.insert(V); +} + +void FragileHazards::collectLocals() { + // Compute a set of allocas to ignore. + llvm::DenseSet AllocasToIgnore; + addIfPresent(AllocasToIgnore, CGF.ReturnValue); + addIfPresent(AllocasToIgnore, CGF.NormalCleanupDest); + addIfPresent(AllocasToIgnore, CGF.EHCleanupDest); + + // Collect all the allocas currently in the function. This is + // probably way too aggressive. + llvm::BasicBlock &Entry = CGF.CurFn->getEntryBlock(); + for (llvm::BasicBlock::iterator + I = Entry.begin(), E = Entry.end(); I != E; ++I) + if (isa(*I) && !AllocasToIgnore.count(&*I)) + Locals.push_back(&*I); +} + +llvm::FunctionType *FragileHazards::GetAsmFnType() { + std::vector Tys(Locals.size()); + for (unsigned I = 0, E = Locals.size(); I != E; ++I) + Tys[I] = Locals[I]->getType(); + return llvm::FunctionType::get(CGF.Builder.getVoidTy(), Tys, false); +} + /* Objective-C setjmp-longjmp (sjlj) Exception Handling @@ -2657,66 +2931,49 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // For @synchronized, call objc_sync_enter(sync.expr). The // evaluation of the expression must occur before we enter the - // @synchronized. We can safely avoid a temp here because jumps into - // @synchronized are illegal & this will dominate uses. - llvm::Value *SyncArg = 0; + // @synchronized. We can't avoid a temp here because we need the + // value to be preserved. If the backend ever does liveness + // correctly after setjmp, this will be unnecessary. + llvm::Value *SyncArgSlot = 0; if (!isTry) { - SyncArg = + llvm::Value *SyncArg = CGF.EmitScalarExpr(cast(S).getSynchExpr()); SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy); CGF.Builder.CreateCall(ObjCTypes.getSyncEnterFn(), SyncArg) ->setDoesNotThrow(); + + SyncArgSlot = CGF.CreateTempAlloca(SyncArg->getType(), "sync.arg"); + CGF.Builder.CreateStore(SyncArg, SyncArgSlot); } - // Allocate memory for the exception data and rethrow pointer. + // Allocate memory for the setjmp buffer. This needs to be kept + // live throughout the try and catch blocks. llvm::Value *ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy, "exceptiondata.ptr"); - llvm::Value *RethrowPtr = CGF.CreateTempAlloca(ObjCTypes.ObjectPtrTy, - "_rethrow"); + + // Create the fragile hazards. Note that this will not capture any + // of the allocas required for exception processing, but will + // capture the current basic block (which extends all the way to the + // setjmp call) as "before the @try". + FragileHazards Hazards(CGF); // Create a flag indicating whether the cleanup needs to call // objc_exception_try_exit. This is true except when // - no catches match and we're branching through the cleanup // just to rethrow the exception, or // - a catch matched and we're falling out of the catch handler. + // The setjmp-safety rule here is that we should always store to this + // variable in a place that dominates the branch through the cleanup + // without passing through any setjmps. llvm::Value *CallTryExitVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "_call_try_exit"); - CGF.Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext), - CallTryExitVar); // Push a normal cleanup to leave the try scope. - { - CodeGenFunction::CleanupBlock FinallyScope(CGF, NormalCleanup); - - // Check whether we need to call objc_exception_try_exit. - // In optimized code, this branch will always be folded. - llvm::BasicBlock *FinallyCallExit = - CGF.createBasicBlock("finally.call_exit"); - llvm::BasicBlock *FinallyNoCallExit = - CGF.createBasicBlock("finally.no_call_exit"); - CGF.Builder.CreateCondBr(CGF.Builder.CreateLoad(CallTryExitVar), - FinallyCallExit, FinallyNoCallExit); - - CGF.EmitBlock(FinallyCallExit); - CGF.Builder.CreateCall(ObjCTypes.getExceptionTryExitFn(), ExceptionData) - ->setDoesNotThrow(); - - CGF.EmitBlock(FinallyNoCallExit); - - if (isTry) { - if (const ObjCAtFinallyStmt* FinallyStmt = - cast(S).getFinallyStmt()) - CGF.EmitStmt(FinallyStmt->getFinallyBody()); - - // ~CleanupBlock requires there to be an exit block. - CGF.EnsureInsertPoint(); - } else { - // Emit objc_sync_exit(expr); as finally's sole statement for - // @synchronized. - CGF.Builder.CreateCall(ObjCTypes.getSyncExitFn(), SyncArg) - ->setDoesNotThrow(); - } - } + CGF.EHStack.pushCleanup(NormalCleanup, &S, + SyncArgSlot, + CallTryExitVar, + ExceptionData, + &ObjCTypes); // Enter a try block: // - Call objc_exception_try_enter to push ExceptionData on top of @@ -2738,68 +2995,71 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try"); llvm::BasicBlock *TryHandler = CGF.createBasicBlock("try.handler"); llvm::Value *DidCatch = - CGF.Builder.CreateIsNull(SetJmpResult, "did_catch_exception"); - CGF.Builder.CreateCondBr(DidCatch, TryBlock, TryHandler); + CGF.Builder.CreateIsNotNull(SetJmpResult, "did_catch_exception"); + CGF.Builder.CreateCondBr(DidCatch, TryHandler, TryBlock); // Emit the protected block. CGF.EmitBlock(TryBlock); + CGF.Builder.CreateStore(CGF.Builder.getTrue(), CallTryExitVar); CGF.EmitStmt(isTry ? cast(S).getTryBody() : cast(S).getSynchBody()); - CGF.EmitBranchThroughCleanup(FinallyEnd); + + CGBuilderTy::InsertPoint TryFallthroughIP = CGF.Builder.saveAndClearIP(); // Emit the exception handler block. CGF.EmitBlock(TryHandler); - // Retrieve the exception object. We may emit multiple blocks but - // nothing can cross this so the value is already in SSA form. - llvm::CallInst *Caught = - CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(), - ExceptionData, "caught"); - Caught->setDoesNotThrow(); - - // Remember the exception to rethrow. - CGF.Builder.CreateStore(Caught, RethrowPtr); - - // Note: at this point, objc_exception_throw already popped the - // catch handler, so anything that branches to the cleanup needs - // to set CallTryExitVar to false. + // Don't optimize loads of the in-scope locals across this point. + Hazards.emitWriteHazard(); // For a @synchronized (or a @try with no catches), just branch // through the cleanup to the rethrow block. if (!isTry || !cast(S).getNumCatchStmts()) { // Tell the cleanup not to re-pop the exit. - CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), - CallTryExitVar); - + CGF.Builder.CreateStore(CGF.Builder.getFalse(), CallTryExitVar); CGF.EmitBranchThroughCleanup(FinallyRethrow); // Otherwise, we have to match against the caught exceptions. } else { + // Retrieve the exception object. We may emit multiple blocks but + // nothing can cross this so the value is already in SSA form. + llvm::CallInst *Caught = + CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(), + ExceptionData, "caught"); + Caught->setDoesNotThrow(); + // Push the exception to rethrow onto the EH value stack for the // benefit of any @throws in the handlers. CGF.ObjCEHValueStack.push_back(Caught); const ObjCAtTryStmt* AtTryStmt = cast(&S); - - // Enter a new exception try block (in case a @catch block throws - // an exception). Now CallTryExitVar (currently true) is back in - // synch with reality. - CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData) - ->setDoesNotThrow(); - llvm::CallInst *SetJmpResult = - CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer, - "setjmp.result"); - SetJmpResult->setDoesNotThrow(); + bool HasFinally = (AtTryStmt->getFinallyStmt() != 0); - llvm::Value *Threw = - CGF.Builder.CreateIsNotNull(SetJmpResult, "did_catch_exception"); + llvm::BasicBlock *CatchBlock = 0; + llvm::BasicBlock *CatchHandler = 0; + if (HasFinally) { + // Enter a new exception try block (in case a @catch block + // throws an exception). + CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData) + ->setDoesNotThrow(); + + llvm::CallInst *SetJmpResult = + CGF.Builder.CreateCall(ObjCTypes.getSetJmpFn(), SetJmpBuffer, + "setjmp.result"); + SetJmpResult->setDoesNotThrow(); + + llvm::Value *Threw = + CGF.Builder.CreateIsNotNull(SetJmpResult, "did_catch_exception"); - llvm::BasicBlock *CatchBlock = CGF.createBasicBlock("catch"); - llvm::BasicBlock *CatchHandler = CGF.createBasicBlock("catch_for_catch"); - CGF.Builder.CreateCondBr(Threw, CatchHandler, CatchBlock); + CatchBlock = CGF.createBasicBlock("catch"); + CatchHandler = CGF.createBasicBlock("catch_for_catch"); + CGF.Builder.CreateCondBr(Threw, CatchHandler, CatchBlock); + + CGF.EmitBlock(CatchBlock); + } - CGF.EmitBlock(CatchBlock); + CGF.Builder.CreateStore(CGF.Builder.getInt1(HasFinally), CallTryExitVar); // Handle catch list. As a special case we check if everything is // matched and avoid generating code for falling off the end if @@ -2872,7 +3132,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // Collect any cleanups for the catch variable. The scope lasts until // the end of the catch body. - CodeGenFunction::RunCleanupsScope CatchVarCleanups(CGF); + CodeGenFunction::RunCleanupsScope CatchVarCleanups(CGF); CGF.EmitLocalBlockVarDecl(*CatchParam); assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?"); @@ -2896,43 +3156,55 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, CGF.ObjCEHValueStack.pop_back(); - if (!AllMatched) { - // None of the handlers caught the exception, so store it to be - // rethrown at the end of the @finally block. - CGF.Builder.CreateStore(Caught, RethrowPtr); + // If nothing wanted anything to do with the caught exception, + // kill the extract call. + if (Caught->use_empty()) + Caught->eraseFromParent(); + + if (!AllMatched) CGF.EmitBranchThroughCleanup(FinallyRethrow); - } - // Emit the exception handler for the @catch blocks. - CGF.EmitBlock(CatchHandler); + if (HasFinally) { + // Emit the exception handler for the @catch blocks. + CGF.EmitBlock(CatchHandler); - // Rethrow the new exception, not the old one. - Caught = CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(), - ExceptionData); - Caught->setDoesNotThrow(); - CGF.Builder.CreateStore(Caught, RethrowPtr); + // In theory we might now need a write hazard, but actually it's + // unnecessary because there's no local-accessing code between + // the try's write hazard and here. + //Hazards.emitWriteHazard(); - // Don't pop the catch handler; the throw already did. - CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(VMContext), - CallTryExitVar); - CGF.EmitBranchThroughCleanup(FinallyRethrow); + // Don't pop the catch handler; the throw already did. + CGF.Builder.CreateStore(CGF.Builder.getFalse(), CallTryExitVar); + CGF.EmitBranchThroughCleanup(FinallyRethrow); + } } + // Insert read hazards as required in the new blocks. + Hazards.emitHazardsInNewBlocks(); + // Pop the cleanup. + CGF.Builder.restoreIP(TryFallthroughIP); + if (CGF.HaveInsertPoint()) + CGF.Builder.CreateStore(CGF.Builder.getTrue(), CallTryExitVar); CGF.PopCleanupBlock(); - CGF.EmitBlock(FinallyEnd.Block); + CGF.EmitBlock(FinallyEnd.getBlock(), true); // Emit the rethrow block. - CGF.Builder.ClearInsertionPoint(); - CGF.EmitBlock(FinallyRethrow.Block, true); + CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); + CGF.EmitBlock(FinallyRethrow.getBlock(), true); if (CGF.HaveInsertPoint()) { - CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), - CGF.Builder.CreateLoad(RethrowPtr)) + // Just look in the buffer for the exception to throw. + llvm::CallInst *Caught = + CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(), + ExceptionData); + Caught->setDoesNotThrow(); + + CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), Caught) ->setDoesNotThrow(); CGF.Builder.CreateUnreachable(); } - CGF.Builder.SetInsertPoint(FinallyEnd.Block); + CGF.Builder.restoreIP(SavedIP); } void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, @@ -2996,7 +3268,8 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, /// objc_assign_global (id src, id *dst) /// void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) { + llvm::Value *src, llvm::Value *dst, + bool threadlocal) { const llvm::Type * SrcTy = src->getType(); if (!isa(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); @@ -3007,8 +3280,12 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy); - CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(), - src, dst, "globalassign"); + if (!threadlocal) + CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(), + src, dst, "globalassign"); + else + CGF.Builder.CreateCall2(ObjCTypes.getGcAssignThreadLocalFn(), + src, dst, "threadlocalassign"); return; } @@ -3260,6 +3537,22 @@ llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) { return getConstantGEP(VMContext, Entry, 0, 0); } +llvm::Function *CGObjCCommonMac::GetMethodDefinition(const ObjCMethodDecl *MD) { + llvm::DenseMap::iterator + I = MethodDefinitions.find(MD); + if (I != MethodDefinitions.end()) + return I->second; + + if (MD->hasBody() && MD->getPCHLevel() > 0) { + // MD isn't emitted yet because it comes from PCH. + CGM.EmitTopLevelDecl(const_cast(MD)); + assert(MethodDefinitions[MD] && "EmitTopLevelDecl didn't emit the method!"); + return MethodDefinitions[MD]; + } + + return NULL; +} + /// GetIvarLayoutName - Returns a unique constant for the given /// ivar layout bitmap. llvm::Constant *CGObjCCommonMac::GetIvarLayoutName(IdentifierInfo *Ident, @@ -3267,22 +3560,6 @@ llvm::Constant *CGObjCCommonMac::GetIvarLayoutName(IdentifierInfo *Ident, return llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); } -static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) { - if (FQT.isObjCGCStrong()) - return Qualifiers::Strong; - - if (FQT.isObjCGCWeak()) - return Qualifiers::Weak; - - if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType()) - return Qualifiers::Strong; - - if (const PointerType *PT = FQT->getAs()) - return GetGCAttrTypeForType(Ctx, PT->getPointeeType()); - - return Qualifiers::GCNone; -} - void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT, unsigned int BytePos, bool ForStrongLayout, @@ -3446,63 +3723,19 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, MaxSkippedUnionIvarSize)); } -/// BuildIvarLayout - Builds ivar layout bitmap for the class -/// implementation for the __strong or __weak case. -/// The layout map displays which words in ivar list must be skipped -/// and which must be scanned by GC (see below). String is built of bytes. -/// Each byte is divided up in two nibbles (4-bit each). Left nibble is count -/// of words to skip and right nibble is count of words to scan. So, each -/// nibble represents up to 15 workds to skip or scan. Skipping the rest is -/// represented by a 0x00 byte which also ends the string. -/// 1. when ForStrongLayout is true, following ivars are scanned: -/// - id, Class -/// - object * -/// - __strong anything -/// -/// 2. When ForStrongLayout is false, following ivars are scanned: -/// - __weak anything -/// -llvm::Constant *CGObjCCommonMac::BuildIvarLayout( - const ObjCImplementationDecl *OMD, - bool ForStrongLayout) { - bool hasUnion = false; - +/// BuildIvarLayoutBitmap - This routine is the horsework for doing all +/// the computations and returning the layout bitmap (for ivar or blocks) in +/// the given argument BitMap string container. Routine reads +/// two containers, IvarsInfo and SkipIvars which are assumed to be +/// filled already by the caller. +llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string& BitMap) { unsigned int WordsToScan, WordsToSkip; const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext); - if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) - return llvm::Constant::getNullValue(PtrTy); - - llvm::SmallVector RecFields; - const ObjCInterfaceDecl *OI = OMD->getClassInterface(); - CGM.getContext().CollectObjCIvars(OI, RecFields); - - // Add this implementations synthesized ivars. - llvm::SmallVector Ivars; - CGM.getContext().CollectNonClassIvars(OI, Ivars); - for (unsigned k = 0, e = Ivars.size(); k != e; ++k) - RecFields.push_back(cast(Ivars[k])); - - if (RecFields.empty()) - return llvm::Constant::getNullValue(PtrTy); - - SkipIvars.clear(); - IvarsInfo.clear(); - - BuildAggrIvarLayout(OMD, 0, 0, RecFields, 0, ForStrongLayout, hasUnion); - if (IvarsInfo.empty()) - return llvm::Constant::getNullValue(PtrTy); - - // Sort on byte position in case we encounterred a union nested in - // the ivar list. - if (hasUnion && !IvarsInfo.empty()) - std::sort(IvarsInfo.begin(), IvarsInfo.end()); - if (hasUnion && !SkipIvars.empty()) - std::sort(SkipIvars.begin(), SkipIvars.end()); - + // Build the string of skip/scan nibbles llvm::SmallVector SkipScanIvars; unsigned int WordSize = - CGM.getTypes().getTargetData().getTypeAllocSize(PtrTy); + CGM.getTypes().getTargetData().getTypeAllocSize(PtrTy); if (IvarsInfo[0].ivar_bytepos == 0) { WordsToSkip = 0; WordsToScan = IvarsInfo[0].ivar_size; @@ -3512,7 +3745,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( } for (unsigned int i=1, Last=IvarsInfo.size(); i != Last; i++) { unsigned int TailPrevGCObjC = - IvarsInfo[i-1].ivar_bytepos + IvarsInfo[i-1].ivar_size * WordSize; + IvarsInfo[i-1].ivar_bytepos + IvarsInfo[i-1].ivar_size * WordSize; if (IvarsInfo[i].ivar_bytepos == TailPrevGCObjC) { // consecutive 'scanned' object pointers. WordsToScan += IvarsInfo[i].ivar_size; @@ -3526,7 +3759,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( SkScan.skip = WordsToSkip; SkScan.scan = WordsToScan; SkipScanIvars.push_back(SkScan); - + // Skip the hole. SkScan.skip = (IvarsInfo[i].ivar_bytepos - TailPrevGCObjC) / WordSize; SkScan.scan = 0; @@ -3541,15 +3774,15 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( SkScan.scan = WordsToScan; SkipScanIvars.push_back(SkScan); } - + if (!SkipIvars.empty()) { unsigned int LastIndex = SkipIvars.size()-1; int LastByteSkipped = - SkipIvars[LastIndex].ivar_bytepos + SkipIvars[LastIndex].ivar_size; + SkipIvars[LastIndex].ivar_bytepos + SkipIvars[LastIndex].ivar_size; LastIndex = IvarsInfo.size()-1; int LastByteScanned = - IvarsInfo[LastIndex].ivar_bytepos + - IvarsInfo[LastIndex].ivar_size * WordSize; + IvarsInfo[LastIndex].ivar_bytepos + + IvarsInfo[LastIndex].ivar_size * WordSize; // Compute number of bytes to skip at the tail end of the last ivar scanned. if (LastByteSkipped > LastByteScanned) { unsigned int TotalWords = (LastByteSkipped + (WordSize -1)) / WordSize; @@ -3572,20 +3805,19 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( --SkipScan; } } - + // Generate the string. - std::string BitMap; for (int i = 0; i <= SkipScan; i++) { unsigned char byte; unsigned int skip_small = SkipScanIvars[i].skip % 0xf; unsigned int scan_small = SkipScanIvars[i].scan % 0xf; unsigned int skip_big = SkipScanIvars[i].skip / 0xf; unsigned int scan_big = SkipScanIvars[i].scan / 0xf; - + // first skip big. for (unsigned int ix = 0; ix < skip_big; ix++) BitMap += (unsigned char)(0xf0); - + // next (skip small, scan) if (skip_small) { byte = skip_small << 4; @@ -3610,11 +3842,71 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( // null terminate string. unsigned char zero = 0; BitMap += zero; + + llvm::GlobalVariable * Entry = + CreateMetadataVar("\01L_OBJC_CLASS_NAME_", + llvm::ConstantArray::get(VMContext, BitMap.c_str()), + "__TEXT,__cstring,cstring_literals", + 1, true); + return getConstantGEP(VMContext, Entry, 0, 0); +} - if (CGM.getLangOptions().ObjCGCBitmapPrint) { +/// BuildIvarLayout - Builds ivar layout bitmap for the class +/// implementation for the __strong or __weak case. +/// The layout map displays which words in ivar list must be skipped +/// and which must be scanned by GC (see below). String is built of bytes. +/// Each byte is divided up in two nibbles (4-bit each). Left nibble is count +/// of words to skip and right nibble is count of words to scan. So, each +/// nibble represents up to 15 workds to skip or scan. Skipping the rest is +/// represented by a 0x00 byte which also ends the string. +/// 1. when ForStrongLayout is true, following ivars are scanned: +/// - id, Class +/// - object * +/// - __strong anything +/// +/// 2. When ForStrongLayout is false, following ivars are scanned: +/// - __weak anything +/// +llvm::Constant *CGObjCCommonMac::BuildIvarLayout( + const ObjCImplementationDecl *OMD, + bool ForStrongLayout) { + bool hasUnion = false; + + const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext); + if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC) + return llvm::Constant::getNullValue(PtrTy); + + llvm::SmallVector Ivars; + const ObjCInterfaceDecl *OI = OMD->getClassInterface(); + CGM.getContext().DeepCollectObjCIvars(OI, true, Ivars); + + llvm::SmallVector RecFields; + for (unsigned k = 0, e = Ivars.size(); k != e; ++k) + RecFields.push_back(cast(Ivars[k])); + + if (RecFields.empty()) + return llvm::Constant::getNullValue(PtrTy); + + SkipIvars.clear(); + IvarsInfo.clear(); + + BuildAggrIvarLayout(OMD, 0, 0, RecFields, 0, ForStrongLayout, hasUnion); + if (IvarsInfo.empty()) + return llvm::Constant::getNullValue(PtrTy); + // Sort on byte position in case we encounterred a union nested in + // the ivar list. + if (hasUnion && !IvarsInfo.empty()) + std::sort(IvarsInfo.begin(), IvarsInfo.end()); + if (hasUnion && !SkipIvars.empty()) + std::sort(SkipIvars.begin(), SkipIvars.end()); + + std::string BitMap; + llvm::Constant *C = BuildIvarLayoutBitmap(BitMap); + + if (CGM.getLangOptions().ObjCGCBitmapPrint) { printf("\n%s ivar layout for class '%s': ", ForStrongLayout ? "strong" : "weak", - OMD->getClassInterface()->getNameAsCString()); + OMD->getClassInterface()->getName().data()); const unsigned char *s = (unsigned char*)BitMap.c_str(); for (unsigned i = 0; i < BitMap.size(); i++) if (!(s[i] & 0xf0)) @@ -3623,12 +3915,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( printf("0x%x%s", s[i], s[i] != 0 ? ", " : ""); printf("\n"); } - llvm::GlobalVariable * Entry = - CreateMetadataVar("\01L_OBJC_CLASS_NAME_", - llvm::ConstantArray::get(VMContext, BitMap.c_str()), - "__TEXT,__cstring,cstring_literals", - 1, true); - return getConstantGEP(VMContext, Entry, 0, 0); + return C; } llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) { @@ -3649,11 +3936,6 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarName(IdentifierInfo *ID) { return GetMethodVarName(CGM.getContext().Selectors.getNullarySelector(ID)); } -// FIXME: Merge into a single cstring creation function. -llvm::Constant *CGObjCCommonMac::GetMethodVarName(const std::string &Name) { - return GetMethodVarName(&CGM.getContext().Idents.get(Name)); -} - llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) { std::string TypeStr; CGM.getContext().getObjCEncodingForType(Field->getType(), TypeStr, Field); @@ -4526,8 +4808,8 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer"); Values[ 6] = EmitProtocolList("\01l_OBJC_CLASS_PROTOCOLS_$_" + OID->getName(), - OID->protocol_begin(), - OID->protocol_end()); + OID->all_referenced_protocol_begin(), + OID->all_referenced_protocol_end()); if (flags & CLS_META) Values[ 7] = llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy); @@ -4741,7 +5023,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder, ObjCTypes.ExternalProtocolPtrTy); std::string ProtocolName("\01l_OBJC_PROTOCOL_REFERENCE_$_"); - ProtocolName += PD->getNameAsCString(); + ProtocolName += PD->getName(); llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName); if (PTGV) @@ -4855,8 +5137,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { /// method has not been defined. The return value has type MethodPtrTy. llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant( const ObjCMethodDecl *MD) { - // FIXME: Use DenseMap::lookup - llvm::Function *Fn = MethodDefinitions[MD]; + llvm::Function *Fn = GetMethodDefinition(MD); if (!Fn) return 0; @@ -5284,40 +5565,24 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( llvm::Constant *Fn = 0; std::string Name("\01l_"); if (CGM.ReturnTypeUsesSRet(FnInfo)) { -#if 0 - // unlike what is documented. gcc never generates this API!! - if (Receiver->getType() == ObjCTypes.ObjectPtrTy) { - Fn = ObjCTypes.getMessageSendIdStretFixupFn(); - // FIXME. Is there a better way of getting these names. - // They are available in RuntimeFunctions vector pair. - Name += "objc_msgSendId_stret_fixup"; - } else -#endif - if (IsSuper) { - Fn = ObjCTypes.getMessageSendSuper2StretFixupFn(); - Name += "objc_msgSendSuper2_stret_fixup"; - } else { - Fn = ObjCTypes.getMessageSendStretFixupFn(); - Name += "objc_msgSend_stret_fixup"; - } + if (IsSuper) { + Fn = ObjCTypes.getMessageSendSuper2StretFixupFn(); + Name += "objc_msgSendSuper2_stret_fixup"; + } else { + Fn = ObjCTypes.getMessageSendStretFixupFn(); + Name += "objc_msgSend_stret_fixup"; + } } else if (!IsSuper && CGM.ReturnTypeUsesFPRet(ResultType)) { Fn = ObjCTypes.getMessageSendFpretFixupFn(); Name += "objc_msgSend_fpret_fixup"; } else { -#if 0 -// unlike what is documented. gcc never generates this API!! - if (Receiver->getType() == ObjCTypes.ObjectPtrTy) { - Fn = ObjCTypes.getMessageSendIdFixupFn(); - Name += "objc_msgSendId_fixup"; - } else -#endif - if (IsSuper) { - Fn = ObjCTypes.getMessageSendSuper2FixupFn(); - Name += "objc_msgSendSuper2_fixup"; - } else { - Fn = ObjCTypes.getMessageSendFixupFn(); - Name += "objc_msgSend_fixup"; - } + if (IsSuper) { + Fn = ObjCTypes.getMessageSendSuper2FixupFn(); + Name += "objc_msgSendSuper2_fixup"; + } else { + Fn = ObjCTypes.getMessageSendFixupFn(); + Name += "objc_msgSend_fixup"; + } } assert(Fn && "CGObjCNonFragileABIMac::EmitMessageSend"); Name += '_'; @@ -5647,7 +5912,8 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, /// objc_assign_global (id src, id *dst) /// void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dst) { + llvm::Value *src, llvm::Value *dst, + bool threadlocal) { const llvm::Type * SrcTy = src->getType(); if (!isa(SrcTy)) { unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); @@ -5658,11 +5924,28 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy); - CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(), - src, dst, "globalassign"); + if (!threadlocal) + CGF.Builder.CreateCall2(ObjCTypes.getGcAssignGlobalFn(), + src, dst, "globalassign"); + else + CGF.Builder.CreateCall2(ObjCTypes.getGcAssignThreadLocalFn(), + src, dst, "threadlocalassign"); return; } +namespace { + struct CallSyncExit : EHScopeStack::Cleanup { + llvm::Value *SyncExitFn; + llvm::Value *SyncArg; + CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg) + : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {} + + void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { + CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow(); + } + }; +} + void CGObjCNonFragileABIMac::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtSynchronizedStmt &S) { @@ -5675,12 +5958,9 @@ CGObjCNonFragileABIMac::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF, ->setDoesNotThrow(); // Register an all-paths cleanup to release the lock. - { - CodeGenFunction::CleanupBlock ReleaseScope(CGF, NormalAndEHCleanup); - - CGF.Builder.CreateCall(ObjCTypes.getSyncExitFn(), SyncArg) - ->setDoesNotThrow(); - } + CGF.EHStack.pushCleanup(NormalAndEHCleanup, + ObjCTypes.getSyncExitFn(), + SyncArg); // Emit the body of the statement. CGF.EmitStmt(S.getSynchBody()); @@ -5697,7 +5977,7 @@ namespace { llvm::Value *TypeInfo; }; - struct CallObjCEndCatch : EHScopeStack::LazyCleanup { + struct CallObjCEndCatch : EHScopeStack::Cleanup { CallObjCEndCatch(bool MightThrow, llvm::Value *Fn) : MightThrow(MightThrow), Fn(Fn) {} bool MightThrow; @@ -5714,6 +5994,31 @@ namespace { }; } +llvm::Constant * +CGObjCNonFragileABIMac::GetEHType(QualType T) { + // There's a particular fixed type info for 'id'. + if (T->isObjCIdType() || + T->isObjCQualifiedIdType()) { + llvm::Constant *IDEHType = + CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id"); + if (!IDEHType) + IDEHType = + new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, + false, + llvm::GlobalValue::ExternalLinkage, + 0, "OBJC_EHTYPE_id"); + return IDEHType; + } + + // All other types should be Objective-C interface pointer types. + const ObjCObjectPointerType *PT = + T->getAs(); + assert(PT && "Invalid @catch type."); + const ObjCInterfaceType *IT = PT->getInterfaceType(); + assert(IT && "Invalid @catch type."); + return GetInterfaceEHType(IT->getDecl(), false); +} + void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtTryStmt &S) { // Jump destination for falling out of catch bodies. @@ -5749,27 +6054,7 @@ void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF, break; } - // There's a particular fixed type info for 'id'. - if (CatchDecl->getType()->isObjCIdType() || - CatchDecl->getType()->isObjCQualifiedIdType()) { - llvm::Value *IDEHType = - CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id"); - if (!IDEHType) - IDEHType = - new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, - false, - llvm::GlobalValue::ExternalLinkage, - 0, "OBJC_EHTYPE_id"); - Handler.TypeInfo = IDEHType; - } else { - // All other types should be Objective-C interface pointer types. - const ObjCObjectPointerType *PT = - CatchDecl->getType()->getAs(); - assert(PT && "Invalid @catch type."); - const ObjCInterfaceType *IT = PT->getInterfaceType(); - assert(IT && "Invalid @catch type."); - Handler.TypeInfo = GetInterfaceEHType(IT->getDecl(), false); - } + Handler.TypeInfo = GetEHType(CatchDecl->getType()); } EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size()); @@ -5802,9 +6087,9 @@ void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF, // Add a cleanup to leave the catch. bool EndCatchMightThrow = (Handler.Variable == 0); - CGF.EHStack.pushLazyCleanup(NormalAndEHCleanup, - EndCatchMightThrow, - ObjCTypes.getObjCEndCatchFn()); + CGF.EHStack.pushCleanup(NormalAndEHCleanup, + EndCatchMightThrow, + ObjCTypes.getObjCEndCatchFn()); // Bind the catch parameter if it exists. if (const VarDecl *CatchParam = Handler.Variable) { @@ -5832,8 +6117,8 @@ void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF, if (S.getFinallyStmt()) CGF.ExitFinallyBlock(FinallyInfo); - if (Cont.Block) - CGF.EmitBlock(Cont.Block); + if (Cont.isValid()) + CGF.EmitBlock(Cont.getBlock()); } /// EmitThrowStmt - Generate code for a throw statement. @@ -5868,7 +6153,7 @@ void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, CGF.Builder.ClearInsertionPoint(); } -llvm::Value * +llvm::Constant * CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, bool ForDefinition) { llvm::GlobalVariable * &Entry = EHTypeReferences[ID->getIdentifier()]; diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index eb79f09..584760f 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -52,6 +52,7 @@ namespace CodeGen { class Selector; class ObjCIvarDecl; class ObjCStringLiteral; + class BlockDeclRefExpr; namespace CodeGen { class CodeGenModule; @@ -103,6 +104,12 @@ public: virtual llvm::Value *GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl *Method) = 0; + /// Get the type constant to catch for the given ObjC pointer type. + /// This is used externally to implement catching ObjC types in C++. + /// Runtimes which don't support this should add the appropriate + /// error to Sema. + virtual llvm::Constant *GetEHType(QualType T) = 0; + /// Generate a constant string object. virtual llvm::Constant *GenerateConstantString(const StringLiteral *) = 0; @@ -192,7 +199,8 @@ public: virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest) = 0; virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, - llvm::Value *src, llvm::Value *dest) = 0; + llvm::Value *src, llvm::Value *dest, + bool threadlocal=false) = 0; virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest, llvm::Value *ivarOffset) = 0; @@ -211,6 +219,9 @@ public: llvm::Value *DestPtr, llvm::Value *SrcPtr, llvm::Value *Size) = 0; + virtual llvm::Constant *GCBlockLayout(CodeGen::CodeGenFunction &CGF, + const llvm::SmallVectorImpl &) = 0; + }; /// Creates an instance of an Objective-C runtime class. diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 1cca977..60df613 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -11,9 +11,12 @@ // //===----------------------------------------------------------------------===// -#include "clang/AST/Type.h" -#include "clang/AST/RecordLayout.h" #include "CodeGenModule.h" +#include "CGCXXABI.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/Type.h" +#include "clang/Frontend/CodeGenOptions.h" + using namespace clang; using namespace CodeGen; @@ -45,7 +48,11 @@ class RTTIBuilder { /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used /// for pointer types. - void BuildPointerTypeInfo(const PointerType *Ty); + void BuildPointerTypeInfo(QualType PointeeTy); + + /// BuildObjCObjectTypeInfo - Build the appropriate kind of + /// type_info for an object type. + void BuildObjCObjectTypeInfo(const ObjCObjectType *Ty); /// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info /// struct, used for member pointer types. @@ -59,7 +66,7 @@ public: llvm::Constant *BuildName(QualType Ty, bool Hidden, llvm::GlobalVariable::LinkageTypes Linkage) { llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRTTIName(Ty, OutName); + CGM.getCXXABI().getMangleContext().mangleCXXRTTIName(Ty, OutName); llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *OGV = CGM.getModule().getNamedGlobal(Name); @@ -158,7 +165,7 @@ public: llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) { // Mangle the RTTI name. llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); + CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); // Look for an existing global. @@ -244,11 +251,9 @@ static bool TypeInfoIsInStandardLibrary(const PointerType *PointerTy) { return TypeInfoIsInStandardLibrary(BuiltinTy); } -/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for -/// the given type exists somewhere else, and that we should not emit the type -/// information in this translation unit. -static bool ShouldUseExternalRTTIDescriptor(ASTContext &Context, - QualType Ty) { +/// IsStandardLibraryRTTIDescriptor - Returns whether the type +/// information for the given type exists in the standard library. +static bool IsStandardLibraryRTTIDescriptor(QualType Ty) { // Type info for builtin types is defined in the standard library. if (const BuiltinType *BuiltinTy = dyn_cast(Ty)) return TypeInfoIsInStandardLibrary(BuiltinTy); @@ -258,6 +263,15 @@ static bool ShouldUseExternalRTTIDescriptor(ASTContext &Context, if (const PointerType *PointerTy = dyn_cast(Ty)) return TypeInfoIsInStandardLibrary(PointerTy); + return false; +} + +/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for +/// the given type exists somewhere else, and that we should not emit the type +/// information in this translation unit. Assumes that it is not a +/// standard-library type. +static bool ShouldUseExternalRTTIDescriptor(ASTContext &Context, + QualType Ty) { // If RTTI is disabled, don't consider key functions. if (!Context.getLangOptions().RTTI) return false; @@ -270,7 +284,7 @@ static bool ShouldUseExternalRTTIDescriptor(ASTContext &Context, return false; // Get the key function. - const CXXMethodDecl *KeyFunction = RD->getASTContext().getKeyFunction(RD); + const CXXMethodDecl *KeyFunction = Context.getKeyFunction(RD); if (KeyFunction && !KeyFunction->hasBody()) { // The class has a key function, but it is not defined in this translation // unit, so we should use the external descriptor for it. @@ -383,21 +397,45 @@ static bool CanUseSingleInheritance(const CXXRecordDecl *RD) { } void RTTIBuilder::BuildVTablePointer(const Type *Ty) { - const char *VTableName; + // abi::__class_type_info. + static const char * const ClassTypeInfo = + "_ZTVN10__cxxabiv117__class_type_infoE"; + // abi::__si_class_type_info. + static const char * const SIClassTypeInfo = + "_ZTVN10__cxxabiv120__si_class_type_infoE"; + // abi::__vmi_class_type_info. + static const char * const VMIClassTypeInfo = + "_ZTVN10__cxxabiv121__vmi_class_type_infoE"; + + const char *VTableName = 0; switch (Ty->getTypeClass()) { - default: assert(0 && "Unhandled type!"); +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_TYPE(Class, Base) case Type::Class: +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + assert(false && "Non-canonical and dependent types shouldn't get here"); + + case Type::LValueReference: + case Type::RValueReference: + assert(false && "References shouldn't get here"); case Type::Builtin: - // GCC treats vector types as fundamental types. + // GCC treats vector and complex types as fundamental types. case Type::Vector: case Type::ExtVector: + case Type::Complex: + // FIXME: GCC treats block pointers as fundamental types?! + case Type::BlockPointer: // abi::__fundamental_type_info. VTableName = "_ZTVN10__cxxabiv123__fundamental_type_infoE"; break; case Type::ConstantArray: case Type::IncompleteArray: + case Type::VariableArray: // abi::__array_type_info. VTableName = "_ZTVN10__cxxabiv117__array_type_infoE"; break; @@ -412,25 +450,44 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) { // abi::__enum_type_info. VTableName = "_ZTVN10__cxxabiv116__enum_type_infoE"; break; - + case Type::Record: { const CXXRecordDecl *RD = cast(cast(Ty)->getDecl()); if (!RD->hasDefinition() || !RD->getNumBases()) { - // abi::__class_type_info. - VTableName = "_ZTVN10__cxxabiv117__class_type_infoE"; + VTableName = ClassTypeInfo; } else if (CanUseSingleInheritance(RD)) { - // abi::__si_class_type_info. - VTableName = "_ZTVN10__cxxabiv120__si_class_type_infoE"; + VTableName = SIClassTypeInfo; } else { - // abi::__vmi_class_type_info. - VTableName = "_ZTVN10__cxxabiv121__vmi_class_type_infoE"; + VTableName = VMIClassTypeInfo; } break; } + case Type::ObjCObject: + // Ignore protocol qualifiers. + Ty = cast(Ty)->getBaseType().getTypePtr(); + + // Handle id and Class. + if (isa(Ty)) { + VTableName = ClassTypeInfo; + break; + } + + assert(isa(Ty)); + // Fall through. + + case Type::ObjCInterface: + if (cast(Ty)->getDecl()->getSuperClass()) { + VTableName = SIClassTypeInfo; + } else { + VTableName = ClassTypeInfo; + } + break; + + case Type::ObjCObjectPointer: case Type::Pointer: // abi::__pointer_type_info. VTableName = "_ZTVN10__cxxabiv119__pointer_type_infoE"; @@ -456,45 +513,64 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) { Fields.push_back(VTable); } -llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, - bool Force) { +llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) { // We want to operate on the canonical type. Ty = CGM.getContext().getCanonicalType(Ty); // Check if we've already emitted an RTTI descriptor for this type. llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXRTTI(Ty, OutName); + CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, OutName); llvm::StringRef Name = OutName.str(); llvm::GlobalVariable *OldGV = CGM.getModule().getNamedGlobal(Name); if (OldGV && !OldGV->isDeclaration()) return llvm::ConstantExpr::getBitCast(OldGV, Int8PtrTy); - + // Check if there is already an external RTTI descriptor for this type. - if (!Force && ShouldUseExternalRTTIDescriptor(CGM.getContext(), Ty)) + bool IsStdLib = IsStandardLibraryRTTIDescriptor(Ty); + if (!Force && + (IsStdLib || ShouldUseExternalRTTIDescriptor(CGM.getContext(), Ty))) return GetAddrOfExternalRTTIDescriptor(Ty); - llvm::GlobalVariable::LinkageTypes Linkage = getTypeInfoLinkage(Ty); + // Emit the standard library with external linkage. + llvm::GlobalVariable::LinkageTypes Linkage; + if (IsStdLib) + Linkage = llvm::GlobalValue::ExternalLinkage; + else + Linkage = getTypeInfoLinkage(Ty); // Add the vtable pointer. BuildVTablePointer(cast(Ty)); // And the name. Fields.push_back(BuildName(Ty, DecideHidden(Ty), Linkage)); - + switch (Ty->getTypeClass()) { - default: assert(false && "Unhandled type class!"); +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: +#define NON_CANONICAL_TYPE(Class, Base) case Type::Class: +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + assert(false && "Non-canonical and dependent types shouldn't get here"); // GCC treats vector types as fundamental types. case Type::Builtin: case Type::Vector: case Type::ExtVector: + case Type::Complex: + case Type::BlockPointer: // Itanium C++ ABI 2.9.5p4: // abi::__fundamental_type_info adds no data members to std::type_info. break; - + + case Type::LValueReference: + case Type::RValueReference: + assert(false && "References shouldn't get here"); + case Type::ConstantArray: case Type::IncompleteArray: + case Type::VariableArray: // Itanium C++ ABI 2.9.5p5: // abi::__array_type_info adds no data members to std::type_info. break; @@ -525,11 +601,20 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, break; } + + case Type::ObjCObject: + case Type::ObjCInterface: + BuildObjCObjectTypeInfo(cast(Ty)); + break; + + case Type::ObjCObjectPointer: + BuildPointerTypeInfo(cast(Ty)->getPointeeType()); + break; case Type::Pointer: - BuildPointerTypeInfo(cast(Ty)); + BuildPointerTypeInfo(cast(Ty)->getPointeeType()); break; - + case Type::MemberPointer: BuildPointerToMemberTypeInfo(cast(Ty)); break; @@ -551,7 +636,18 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, OldGV->replaceAllUsesWith(NewPtr); OldGV->eraseFromParent(); } - + + // GCC only relies on the uniqueness of the type names, not the + // type_infos themselves, so we can emit these as hidden symbols. + // But don't do this if we're worried about strict visibility + // compatibility. + if (const RecordType *RT = dyn_cast(Ty)) + CGM.setTypeVisibility(GV, cast(RT->getDecl()), + /*ForRTTI*/ true); + else if (CGM.getCodeGenOpts().HiddenWeakVTables && + Linkage == llvm::GlobalValue::WeakODRLinkage) + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); + return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); } @@ -570,6 +666,30 @@ static unsigned ComputeQualifierFlags(Qualifiers Quals) { return Flags; } +/// BuildObjCObjectTypeInfo - Build the appropriate kind of type_info +/// for the given Objective-C object type. +void RTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) { + // Drop qualifiers. + const Type *T = OT->getBaseType().getTypePtr(); + assert(isa(T) || isa(T)); + + // The builtin types are abi::__class_type_infos and don't require + // extra fields. + if (isa(T)) return; + + ObjCInterfaceDecl *Class = cast(T)->getDecl(); + ObjCInterfaceDecl *Super = Class->getSuperClass(); + + // Root classes are also __class_type_info. + if (!Super) return; + + QualType SuperTy = CGM.getContext().getObjCInterfaceType(Super); + + // Everything else is single inheritance. + llvm::Constant *BaseTypeInfo = RTTIBuilder(CGM).BuildTypeInfo(SuperTy); + Fields.push_back(BaseTypeInfo); +} + /// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single /// inheritance, according to the Itanium C++ ABI, 2.95p6b. void RTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) { @@ -677,7 +797,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { // direct proper base. Each description is of the type: // // struct abi::__base_class_type_info { - // public: + // public: // const __class_type_info *__base_type; // long __offset_flags; // @@ -725,9 +845,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, /// used for pointer types. -void RTTIBuilder::BuildPointerTypeInfo(const PointerType *Ty) { - QualType PointeeTy = Ty->getPointeeType(); - +void RTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) { Qualifiers Quals; QualType UnqualifiedPointeeTy = CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals); diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h index e95591e..9b4e9f8 100644 --- a/lib/CodeGen/CGRecordLayout.h +++ b/lib/CodeGen/CGRecordLayout.h @@ -144,6 +144,21 @@ public: void print(llvm::raw_ostream &OS) const; void dump() const; + + /// \brief Given a bit-field decl, build an appropriate helper object for + /// accessing that field (which is expected to have the given offset and + /// size). + static CGBitFieldInfo MakeInfo(class CodeGenTypes &Types, const FieldDecl *FD, + uint64_t FieldOffset, uint64_t FieldSize); + + /// \brief Given a bit-field decl, build an appropriate helper object for + /// accessing that field (which is expected to have the given offset and + /// size). The field decl should be known to be contained within a type of at + /// least the given size and with the given alignment. + static CGBitFieldInfo MakeInfo(CodeGenTypes &Types, const FieldDecl *FD, + uint64_t FieldOffset, uint64_t FieldSize, + uint64_t ContainingTypeSizeInBits, + unsigned ContainingTypeAlign); }; /// CGRecordLayout - This class handles struct and union layout info while @@ -174,20 +189,21 @@ private: /// Whether one of the fields in this record layout is a pointer to data /// member, or a struct that contains pointer to data member. - bool ContainsPointerToDataMember : 1; + bool IsZeroInitializable : 1; public: - CGRecordLayout(const llvm::Type *T, bool ContainsPointerToDataMember) - : LLVMType(T), ContainsPointerToDataMember(ContainsPointerToDataMember) {} + CGRecordLayout(const llvm::Type *T, bool IsZeroInitializable) + : LLVMType(T), IsZeroInitializable(IsZeroInitializable) {} /// \brief Return the LLVM type associated with this record. const llvm::Type *getLLVMType() const { return LLVMType; } - /// \brief Check whether this struct contains pointers to data members. - bool containsPointerToDataMember() const { - return ContainsPointerToDataMember; + /// \brief Check whether this struct can be C++ zero-initialized + /// with a zeroinitializer. + bool isZeroInitializable() const { + return IsZeroInitializable; } /// \brief Return llvm::StructType element number that corresponds to the diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 9f16875..77a319f 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -18,6 +18,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "CodeGenTypes.h" +#include "CGCXXABI.h" #include "llvm/DerivedTypes.h" #include "llvm/Type.h" #include "llvm/Support/Debug.h" @@ -45,10 +46,9 @@ public: typedef std::pair LLVMBaseInfo; llvm::SmallVector LLVMNonVirtualBases; - /// ContainsPointerToDataMember - Whether one of the fields in this record - /// layout is a pointer to data member, or a struct that contains pointer to - /// data member. - bool ContainsPointerToDataMember; + /// IsZeroInitializable - Whether this struct can be C++ + /// zero-initialized with an LLVM zeroinitializer. + bool IsZeroInitializable; /// Packed - Whether the resulting LLVM struct will be packed or not. bool Packed; @@ -115,14 +115,14 @@ private: unsigned getTypeAlignment(const llvm::Type *Ty) const; - /// CheckForPointerToDataMember - Check if the given type contains a pointer + /// CheckZeroInitializable - Check if the given type contains a pointer /// to data member. - void CheckForPointerToDataMember(QualType T); - void CheckForPointerToDataMember(const CXXRecordDecl *RD); + void CheckZeroInitializable(QualType T); + void CheckZeroInitializable(const CXXRecordDecl *RD); public: CGRecordLayoutBuilder(CodeGenTypes &Types) - : ContainsPointerToDataMember(false), Packed(false), Types(Types), + : IsZeroInitializable(true), Packed(false), Types(Types), Alignment(0), AlignmentAsLLVMStruct(1), BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { } @@ -157,15 +157,12 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) { LayoutFields(D); } -static CGBitFieldInfo ComputeBitFieldInfo(CodeGenTypes &Types, - const FieldDecl *FD, - uint64_t FieldOffset, - uint64_t FieldSize) { - const RecordDecl *RD = FD->getParent(); - const ASTRecordLayout &RL = Types.getContext().getASTRecordLayout(RD); - uint64_t ContainingTypeSizeInBits = RL.getSize(); - unsigned ContainingTypeAlign = RL.getAlignment(); - +CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, + const FieldDecl *FD, + uint64_t FieldOffset, + uint64_t FieldSize, + uint64_t ContainingTypeSizeInBits, + unsigned ContainingTypeAlign) { const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(FD->getType()); uint64_t TypeSizeInBytes = Types.getTargetData().getTypeAllocSize(Ty); uint64_t TypeSizeInBits = TypeSizeInBytes * 8; @@ -255,6 +252,19 @@ static CGBitFieldInfo ComputeBitFieldInfo(CodeGenTypes &Types, return CGBitFieldInfo(FieldSize, NumComponents, Components, IsSigned); } +CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, + const FieldDecl *FD, + uint64_t FieldOffset, + uint64_t FieldSize) { + const RecordDecl *RD = FD->getParent(); + const ASTRecordLayout &RL = Types.getContext().getASTRecordLayout(RD); + uint64_t ContainingTypeSizeInBits = RL.getSize(); + unsigned ContainingTypeAlign = RL.getAlignment(); + + return MakeInfo(Types, FD, FieldOffset, FieldSize, ContainingTypeSizeInBits, + ContainingTypeAlign); +} + void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, uint64_t FieldOffset) { uint64_t FieldSize = @@ -287,7 +297,8 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, // Add the bit field info. LLVMBitFields.push_back( - LLVMBitFieldInfo(D, ComputeBitFieldInfo(Types, D, FieldOffset, FieldSize))); + LLVMBitFieldInfo(D, CGBitFieldInfo::MakeInfo(Types, D, FieldOffset, + FieldSize))); AppendBytes(NumBytesToAppend); @@ -311,8 +322,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, return true; } - // Check if we have a pointer to data member in this field. - CheckForPointerToDataMember(D->getType()); + CheckZeroInitializable(D->getType()); assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!"); uint64_t FieldOffsetInBytes = FieldOffset / 8; @@ -380,7 +390,8 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field, // Add the bit field info. LLVMBitFields.push_back( - LLVMBitFieldInfo(Field, ComputeBitFieldInfo(Types, Field, 0, FieldSize))); + LLVMBitFieldInfo(Field, CGBitFieldInfo::MakeInfo(Types, Field, + 0, FieldSize))); return FieldTy; } @@ -458,7 +469,7 @@ void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *BaseDecl, return; } - CheckForPointerToDataMember(BaseDecl); + CheckZeroInitializable(BaseDecl); // FIXME: Actually use a better type than [sizeof(BaseDecl) x i8] when we can. AppendPadding(BaseOffset / 8, 1); @@ -603,9 +614,9 @@ unsigned CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const { return Types.getTargetData().getABITypeAlignment(Ty); } -void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) { +void CGRecordLayoutBuilder::CheckZeroInitializable(QualType T) { // This record already contains a member pointer. - if (ContainsPointerToDataMember) + if (!IsZeroInitializable) return; // Can only have member pointers if we're compiling C++. @@ -615,21 +626,17 @@ void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) { T = Types.getContext().getBaseElementType(T); if (const MemberPointerType *MPT = T->getAs()) { - if (!MPT->getPointeeType()->isFunctionType()) { - // We have a pointer to data member. - ContainsPointerToDataMember = true; - } + if (!Types.getCXXABI().isZeroInitializable(MPT)) + IsZeroInitializable = false; } else if (const RecordType *RT = T->getAs()) { const CXXRecordDecl *RD = cast(RT->getDecl()); - - return CheckForPointerToDataMember(RD); + CheckZeroInitializable(RD); } } -void -CGRecordLayoutBuilder::CheckForPointerToDataMember(const CXXRecordDecl *RD) { +void CGRecordLayoutBuilder::CheckZeroInitializable(const CXXRecordDecl *RD) { // This record already contains a member pointer. - if (ContainsPointerToDataMember) + if (!IsZeroInitializable) return; // FIXME: It would be better if there was a way to explicitly compute the @@ -638,8 +645,8 @@ CGRecordLayoutBuilder::CheckForPointerToDataMember(const CXXRecordDecl *RD) { const CGRecordLayout &Layout = Types.getCGRecordLayout(RD); - if (Layout.containsPointerToDataMember()) - ContainsPointerToDataMember = true; + if (!Layout.isZeroInitializable()) + IsZeroInitializable = false; } CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { @@ -652,7 +659,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { Builder.Packed); CGRecordLayout *RL = - new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember); + new CGRecordLayout(Ty, Builder.IsZeroInitializable); // Add all the non-virtual base field numbers. RL->NonVirtualBaseFields.insert(Builder.LLVMNonVirtualBases.begin(), @@ -723,7 +730,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { void CGRecordLayout::print(llvm::raw_ostream &OS) const { OS << "setLocation(S->getLocEnd()); else DI->setLocation(S->getLocStart()); - DI->EmitStopPoint(CurFn, Builder); + DI->UpdateLineDirectiveRegion(Builder); + DI->EmitStopPoint(Builder); } } @@ -152,7 +153,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, CGDebugInfo *DI = getDebugInfo(); if (DI) { DI->setLocation(S.getLBracLoc()); - DI->EmitRegionStart(CurFn, Builder); + DI->EmitRegionStart(Builder); } // Keep track of the current cleanup stack depth. @@ -164,7 +165,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast, if (DI) { DI->setLocation(S.getRBracLoc()); - DI->EmitRegionEnd(CurFn, Builder); + DI->EmitRegionEnd(Builder); } RValue RV; @@ -247,32 +248,35 @@ void CodeGenFunction::EmitBranch(llvm::BasicBlock *Target) { CodeGenFunction::JumpDest CodeGenFunction::getJumpDestForLabel(const LabelStmt *S) { JumpDest &Dest = LabelMap[S]; - if (Dest.Block) return Dest; + if (Dest.isValid()) return Dest; // Create, but don't insert, the new block. - Dest.Block = createBasicBlock(S->getName()); - Dest.ScopeDepth = EHScopeStack::stable_iterator::invalid(); + Dest = JumpDest(createBasicBlock(S->getName()), + EHScopeStack::stable_iterator::invalid(), + NextCleanupDestIndex++); return Dest; } void CodeGenFunction::EmitLabel(const LabelStmt &S) { JumpDest &Dest = LabelMap[&S]; - // If we didn't needed a forward reference to this label, just go + // If we didn't need a forward reference to this label, just go // ahead and create a destination at the current scope. - if (!Dest.Block) { + if (!Dest.isValid()) { Dest = getJumpDestInCurrentScope(S.getName()); // Otherwise, we need to give this label a target depth and remove // it from the branch-fixups list. } else { - assert(!Dest.ScopeDepth.isValid() && "already emitted label!"); - Dest.ScopeDepth = EHStack.stable_begin(); + assert(!Dest.getScopeDepth().isValid() && "already emitted label!"); + Dest = JumpDest(Dest.getBlock(), + EHStack.stable_begin(), + Dest.getDestIndex()); - EHStack.resolveBranchFixups(Dest.Block); + ResolveBranchFixups(Dest.getBlock()); } - EmitBlock(Dest.Block); + EmitBlock(Dest.getBlock()); } @@ -372,7 +376,7 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) { // Emit the header for the loop, which will also become // the continue target. JumpDest LoopHeader = getJumpDestInCurrentScope("while.cond"); - EmitBlock(LoopHeader.Block); + EmitBlock(LoopHeader.getBlock()); // Create an exit block for when the condition fails, which will // also become the break target. @@ -408,13 +412,13 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) { // As long as the condition is true, go to the loop body. llvm::BasicBlock *LoopBody = createBasicBlock("while.body"); if (EmitBoolCondBranch) { - llvm::BasicBlock *ExitBlock = LoopExit.Block; + llvm::BasicBlock *ExitBlock = LoopExit.getBlock(); if (ConditionScope.requiresCleanups()) ExitBlock = createBasicBlock("while.exit"); Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock); - if (ExitBlock != LoopExit.Block) { + if (ExitBlock != LoopExit.getBlock()) { EmitBlock(ExitBlock); EmitBranchThroughCleanup(LoopExit); } @@ -434,15 +438,15 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) { ConditionScope.ForceCleanup(); // Branch to the loop header again. - EmitBranch(LoopHeader.Block); + EmitBranch(LoopHeader.getBlock()); // Emit the exit block. - EmitBlock(LoopExit.Block, true); + EmitBlock(LoopExit.getBlock(), true); // The LoopHeader typically is just a branch if we skipped emitting // a branch, try to erase it. if (!EmitBoolCondBranch) - SimplifyForwardingBlocks(LoopHeader.Block); + SimplifyForwardingBlocks(LoopHeader.getBlock()); } void CodeGenFunction::EmitDoStmt(const DoStmt &S) { @@ -462,7 +466,7 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) { BreakContinueStack.pop_back(); - EmitBlock(LoopCond.Block); + EmitBlock(LoopCond.getBlock()); // C99 6.8.5.2: "The evaluation of the controlling expression takes place // after each execution of the loop body." @@ -481,15 +485,15 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) { // As long as the condition is true, iterate the loop. if (EmitBoolCondBranch) - Builder.CreateCondBr(BoolCondVal, LoopBody, LoopExit.Block); + Builder.CreateCondBr(BoolCondVal, LoopBody, LoopExit.getBlock()); // Emit the exit block. - EmitBlock(LoopExit.Block); + EmitBlock(LoopExit.getBlock()); // The DoCond block typically is just a branch if we skipped // emitting a branch, try to erase it. if (!EmitBoolCondBranch) - SimplifyForwardingBlocks(LoopCond.Block); + SimplifyForwardingBlocks(LoopCond.getBlock()); } void CodeGenFunction::EmitForStmt(const ForStmt &S) { @@ -497,6 +501,12 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { RunCleanupsScope ForScope(*this); + CGDebugInfo *DI = getDebugInfo(); + if (DI) { + DI->setLocation(S.getSourceRange().getBegin()); + DI->EmitRegionStart(Builder); + } + // Evaluate the first part before the loop. if (S.getInit()) EmitStmt(S.getInit()); @@ -505,7 +515,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { // If there's an increment, the continue scope will be overwritten // later. JumpDest Continue = getJumpDestInCurrentScope("for.cond"); - llvm::BasicBlock *CondBlock = Continue.Block; + llvm::BasicBlock *CondBlock = Continue.getBlock(); EmitBlock(CondBlock); // Create a cleanup scope for the condition variable cleanups. @@ -515,7 +525,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { if (S.getCond()) { // If the for statement has a condition scope, emit the local variable // declaration. - llvm::BasicBlock *ExitBlock = LoopExit.Block; + llvm::BasicBlock *ExitBlock = LoopExit.getBlock(); if (S.getConditionVariable()) { EmitLocalBlockVarDecl(*S.getConditionVariable()); } @@ -533,7 +543,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { BoolCondVal = EvaluateExprAsBool(S.getCond()); Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock); - if (ExitBlock != LoopExit.Block) { + if (ExitBlock != LoopExit.getBlock()) { EmitBlock(ExitBlock); EmitBranchThroughCleanup(LoopExit); } @@ -554,12 +564,6 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { // Store the blocks to use for break and continue. BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); - CGDebugInfo *DI = getDebugInfo(); - if (DI) { - DI->setLocation(S.getSourceRange().getBegin()); - DI->EmitRegionStart(CurFn, Builder); - } - { // Create a separate cleanup scope for the body, in case it is not // a compound statement. @@ -569,7 +573,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { // If there is an increment, emit it next. if (S.getInc()) { - EmitBlock(Continue.Block); + EmitBlock(Continue.getBlock()); EmitStmt(S.getInc()); } @@ -582,11 +586,11 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { if (DI) { DI->setLocation(S.getSourceRange().getEnd()); - DI->EmitRegionEnd(CurFn, Builder); + DI->EmitRegionEnd(Builder); } // Emit the fall-through block. - EmitBlock(LoopExit.Block, true); + EmitBlock(LoopExit.getBlock(), true); } void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) { @@ -839,13 +843,15 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { // Otherwise, just forward the default block to the switch end. } else { - DefaultBlock->replaceAllUsesWith(SwitchExit.Block); + DefaultBlock->replaceAllUsesWith(SwitchExit.getBlock()); delete DefaultBlock; } } + ConditionScope.ForceCleanup(); + // Emit continuation. - EmitBlock(SwitchExit.Block, true); + EmitBlock(SwitchExit.getBlock(), true); SwitchInsn = SavedSwitchInsn; CaseRangeBlock = SavedCRBlock; @@ -855,16 +861,24 @@ static std::string SimplifyConstraint(const char *Constraint, const TargetInfo &Target, llvm::SmallVectorImpl *OutCons=0) { std::string Result; + std::string tmp; while (*Constraint) { switch (*Constraint) { default: - Result += Target.convertConstraint(*Constraint); + tmp = Target.convertConstraint(*Constraint); + if (Result.find(tmp) == std::string::npos) // Combine unique constraints + Result += tmp; break; // Ignore these case '*': case '?': case '!': + case '=': // Will see this and the following in mult-alt constraints. + case '+': + break; + case ',': // FIXME - Until the back-end properly supports + return Result; // multiple alternative constraints, we stop here. break; case 'g': Result += "imr"; @@ -888,40 +902,50 @@ SimplifyConstraint(const char *Constraint, const TargetInfo &Target, return Result; } -llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S, - const TargetInfo::ConstraintInfo &Info, - const Expr *InputExpr, - std::string &ConstraintStr) { +llvm::Value* +CodeGenFunction::EmitAsmInputLValue(const AsmStmt &S, + const TargetInfo::ConstraintInfo &Info, + LValue InputValue, QualType InputType, + std::string &ConstraintStr) { llvm::Value *Arg; if (Info.allowsRegister() || !Info.allowsMemory()) { - if (!CodeGenFunction::hasAggregateLLVMType(InputExpr->getType())) { - Arg = EmitScalarExpr(InputExpr); + if (!CodeGenFunction::hasAggregateLLVMType(InputType)) { + Arg = EmitLoadOfLValue(InputValue, InputType).getScalarVal(); } else { - InputExpr = InputExpr->IgnoreParenNoopCasts(getContext()); - LValue Dest = EmitLValue(InputExpr); - - const llvm::Type *Ty = ConvertType(InputExpr->getType()); + const llvm::Type *Ty = ConvertType(InputType); uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty); if (Size <= 64 && llvm::isPowerOf2_64(Size)) { Ty = llvm::IntegerType::get(VMContext, Size); Ty = llvm::PointerType::getUnqual(Ty); - Arg = Builder.CreateLoad(Builder.CreateBitCast(Dest.getAddress(), Ty)); + Arg = Builder.CreateLoad(Builder.CreateBitCast(InputValue.getAddress(), + Ty)); } else { - Arg = Dest.getAddress(); + Arg = InputValue.getAddress(); ConstraintStr += '*'; } } } else { - InputExpr = InputExpr->IgnoreParenNoopCasts(getContext()); - LValue Dest = EmitLValue(InputExpr); - Arg = Dest.getAddress(); + Arg = InputValue.getAddress(); ConstraintStr += '*'; } return Arg; } +llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S, + const TargetInfo::ConstraintInfo &Info, + const Expr *InputExpr, + std::string &ConstraintStr) { + if (Info.allowsRegister() || !Info.allowsMemory()) + if (!CodeGenFunction::hasAggregateLLVMType(InputExpr->getType())) + return EmitScalarExpr(InputExpr); + + InputExpr = InputExpr->IgnoreParenNoopCasts(getContext()); + LValue Dest = EmitLValue(InputExpr); + return EmitAsmInputLValue(S, Info, Dest, InputExpr->getType(), ConstraintStr); +} + void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // Analyze the asm string to decompose it into its pieces. We know that Sema // has already done this, so it is guaranteed to be successful. @@ -1031,7 +1055,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { InOutConstraints += ','; const Expr *InputExpr = S.getOutputExpr(i); - llvm::Value *Arg = EmitAsmInput(S, Info, InputExpr, InOutConstraints); + llvm::Value *Arg = EmitAsmInputLValue(S, Info, Dest, InputExpr->getType(), + InOutConstraints); if (Info.allowsRegister()) InOutConstraints += llvm::utostr(i); diff --git a/lib/CodeGen/CGTemporaries.cpp b/lib/CodeGen/CGTemporaries.cpp index fd7c616..dfb8dc6 100644 --- a/lib/CodeGen/CGTemporaries.cpp +++ b/lib/CodeGen/CGTemporaries.cpp @@ -15,34 +15,43 @@ using namespace clang; using namespace CodeGen; -static void EmitTemporaryCleanup(CodeGenFunction &CGF, - const CXXTemporary *Temporary, - llvm::Value *Addr, - llvm::Value *CondPtr) { - llvm::BasicBlock *CondEnd = 0; +namespace { + struct DestroyTemporary : EHScopeStack::Cleanup { + const CXXTemporary *Temporary; + llvm::Value *Addr; + llvm::Value *CondPtr; + + DestroyTemporary(const CXXTemporary *Temporary, llvm::Value *Addr, + llvm::Value *CondPtr) + : Temporary(Temporary), Addr(Addr), CondPtr(CondPtr) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + llvm::BasicBlock *CondEnd = 0; - // If this is a conditional temporary, we need to check the condition - // boolean and only call the destructor if it's true. - if (CondPtr) { - llvm::BasicBlock *CondBlock = CGF.createBasicBlock("temp.cond-dtor.call"); - CondEnd = CGF.createBasicBlock("temp.cond-dtor.cont"); + // If this is a conditional temporary, we need to check the condition + // boolean and only call the destructor if it's true. + if (CondPtr) { + llvm::BasicBlock *CondBlock = + CGF.createBasicBlock("temp.cond-dtor.call"); + CondEnd = CGF.createBasicBlock("temp.cond-dtor.cont"); - llvm::Value *Cond = CGF.Builder.CreateLoad(CondPtr); - CGF.Builder.CreateCondBr(Cond, CondBlock, CondEnd); - CGF.EmitBlock(CondBlock); - } + llvm::Value *Cond = CGF.Builder.CreateLoad(CondPtr); + CGF.Builder.CreateCondBr(Cond, CondBlock, CondEnd); + CGF.EmitBlock(CondBlock); + } - CGF.EmitCXXDestructorCall(Temporary->getDestructor(), - Dtor_Complete, /*ForVirtualBase=*/false, - Addr); + CGF.EmitCXXDestructorCall(Temporary->getDestructor(), + Dtor_Complete, /*ForVirtualBase=*/false, + Addr); - if (CondPtr) { - // Reset the condition to false. - CGF.Builder.CreateStore(llvm::ConstantInt::getFalse(CGF.getLLVMContext()), - CondPtr); - CGF.EmitBlock(CondEnd); - } -} + if (CondPtr) { + // Reset the condition to false. + CGF.Builder.CreateStore(CGF.Builder.getFalse(), CondPtr); + CGF.EmitBlock(CondEnd); + } + } + }; +} /// Emits all the code to cause the given temporary to be cleaned up. void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary, @@ -59,16 +68,11 @@ void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary, InitTempAlloca(CondPtr, llvm::ConstantInt::getFalse(VMContext)); // Now set it to true. - Builder.CreateStore(llvm::ConstantInt::getTrue(VMContext), CondPtr); + Builder.CreateStore(Builder.getTrue(), CondPtr); } - CleanupBlock Cleanup(*this, NormalCleanup); - EmitTemporaryCleanup(*this, Temporary, Ptr, CondPtr); - - if (Exceptions) { - Cleanup.beginEHCleanup(); - EmitTemporaryCleanup(*this, Temporary, Ptr, CondPtr); - } + EHStack.pushCleanup(NormalAndEHCleanup, + Temporary, Ptr, CondPtr); } RValue @@ -76,23 +80,13 @@ CodeGenFunction::EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, llvm::Value *AggLoc, bool IsAggLocVolatile, bool IsInitializer) { - RValue RV; - { - RunCleanupsScope Scope(*this); - - RV = EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, + RunCleanupsScope Scope(*this); + return EmitAnyExpr(E->getSubExpr(), AggLoc, IsAggLocVolatile, /*IgnoreResult=*/false, IsInitializer); - } - return RV; } LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue( const CXXExprWithTemporaries *E) { - LValue LV; - { - RunCleanupsScope Scope(*this); - - LV = EmitLValue(E->getSubExpr()); - } - return LV; + RunCleanupsScope Scope(*this); + return EmitLValue(E->getSubExpr()); } diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp index 61c7423..56acfc8 100644 --- a/lib/CodeGen/CGVTT.cpp +++ b/lib/CodeGen/CGVTT.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenModule.h" +#include "CGCXXABI.h" #include "clang/AST/RecordLayout.h" using namespace clang; using namespace CodeGen; @@ -373,7 +374,7 @@ CodeGenVTables::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage, return 0; llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXVTT(RD, OutName); + CGM.getCXXABI().getMangleContext().mangleCXXVTT(RD, OutName); llvm::StringRef Name = OutName.str(); D1(printf("vtt %s\n", RD->getNameAsCString())); diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 6abac26..bed4670 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -13,8 +13,10 @@ #include "CodeGenModule.h" #include "CodeGenFunction.h" +#include "CGCXXABI.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/RecordLayout.h" +#include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SetVector.h" #include "llvm/Support/Compiler.h" @@ -2408,12 +2410,12 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, // Compute the mangled name. llvm::SmallString<256> Name; if (const CXXDestructorDecl* DD = dyn_cast(MD)) - getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), Thunk.This, - Name); + getCXXABI().getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), + Thunk.This, Name); else - getMangleContext().mangleThunk(MD, Thunk, Name); + getCXXABI().getMangleContext().mangleThunk(MD, Thunk, Name); - const llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(MD); + const llvm::Type *Ty = getTypes().GetFunctionTypeForVTable(GD); return GetOrCreateLLVMFunction(Name, Ty, GD); } @@ -2460,6 +2462,54 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF, return CGF.Builder.CreateBitCast(V, Ptr->getType()); } +static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD, + const ThunkInfo &Thunk, llvm::Function *Fn) { + CGM.setGlobalVisibility(Fn, MD); + + if (!CGM.getCodeGenOpts().HiddenWeakVTables) + return; + + // If the thunk has weak/linkonce linkage, but the function must be + // emitted in every translation unit that references it, then we can + // emit its thunks with hidden visibility, since its thunks must be + // emitted when the function is. + + // This follows CodeGenModule::setTypeVisibility; see the comments + // there for explanation. + + if ((Fn->getLinkage() != llvm::GlobalVariable::LinkOnceODRLinkage && + Fn->getLinkage() != llvm::GlobalVariable::WeakODRLinkage) || + Fn->getVisibility() != llvm::GlobalVariable::DefaultVisibility) + return; + + if (MD->hasAttr()) + return; + + switch (MD->getTemplateSpecializationKind()) { + case TSK_ExplicitInstantiationDefinition: + case TSK_ExplicitInstantiationDeclaration: + return; + + case TSK_Undeclared: + break; + + case TSK_ExplicitSpecialization: + case TSK_ImplicitInstantiation: + if (!CGM.getCodeGenOpts().HiddenWeakTemplateVTables) + return; + break; + } + + // If there's an explicit definition, and that definition is + // out-of-line, then we can't assume that all users will have a + // definition to emit. + const FunctionDecl *Def = 0; + if (MD->hasBody(Def) && Def->isOutOfLine()) + return; + + Fn->setVisibility(llvm::GlobalValue::HiddenVisibility); +} + void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, const ThunkInfo &Thunk) { const CXXMethodDecl *MD = cast(GD.getDecl()); @@ -2473,13 +2523,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, // CodeGenFunction::GenerateCode. // Create the implicit 'this' parameter declaration. - CXXThisDecl = ImplicitParamDecl::Create(getContext(), 0, - MD->getLocation(), - &getContext().Idents.get("this"), - ThisType); - - // Add the 'this' parameter. - FunctionArgs.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType())); + CurGD = GD; + CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResultType, FunctionArgs); // Add the rest of the parameters. for (FunctionDecl::param_const_iterator I = MD->param_begin(), @@ -2491,6 +2536,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, StartFunction(GlobalDecl(), ResultType, Fn, FunctionArgs, SourceLocation()); + CGM.getCXXABI().EmitInstanceFunctionProlog(*this); + // Adjust the 'this' pointer if necessary. llvm::Value *AdjustedThisPtr = PerformTypeAdjustment(*this, LoadCXXThis(), @@ -2514,7 +2561,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, // Get our callee. const llvm::Type *Ty = - CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(GD), FPT->isVariadic()); llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty); @@ -2574,24 +2621,20 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, } if (!ResultType->isVoidType() && Slot.isNull()) - EmitReturnOfRValue(RV, ResultType); + CGM.getCXXABI().EmitReturnFromThunk(CGF, RV, ResultType); FinishFunction(); - // Destroy the 'this' declaration. - CXXThisDecl->Destroy(getContext()); - // Set the right linkage. CGM.setFunctionLinkage(MD, Fn); // Set the right visibility. - CGM.setGlobalVisibility(Fn, MD); + setThunkVisibility(CGM, MD, Thunk, Fn); } void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk) { llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk); - const CXXMethodDecl *MD = cast(GD.getDecl()); // Strip off a bitcast if we got one back. if (llvm::ConstantExpr *CE = dyn_cast(Entry)) { @@ -2602,7 +2645,7 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk) // There's already a declaration with the same name, check if it has the same // type or if we need to replace it. if (cast(Entry)->getType()->getElementType() != - CGM.getTypes().GetFunctionTypeForVTable(MD)) { + CGM.getTypes().GetFunctionTypeForVTable(GD)) { llvm::GlobalValue *OldThunkFn = cast(Entry); // If the types mismatch then we have to rewrite the definition. @@ -2821,8 +2864,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, NextVTableThunkIndex++; } else { - const CXXMethodDecl *MD = cast(GD.getDecl()); - const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(MD); + const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVTable(GD); Init = CGM.GetAddrOfFunction(GD, Ty); } @@ -2889,7 +2931,7 @@ GetGlobalVariable(llvm::Module &Module, llvm::StringRef Name, llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXVTable(RD, OutName); + CGM.getCXXABI().getMangleContext().mangleCXXVTable(RD, OutName); llvm::StringRef Name = OutName.str(); ComputeVTableRelatedInformation(RD, true); @@ -2928,7 +2970,7 @@ CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable, VTable->setLinkage(Linkage); // Set the right visibility. - CGM.setGlobalVisibility(VTable, RD); + CGM.setTypeVisibility(VTable, RD, /*ForRTTI*/ false); } llvm::GlobalVariable * @@ -2949,8 +2991,8 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, // Get the mangled construction vtable name. llvm::SmallString<256> OutName; - CGM.getMangleContext().mangleCXXCtorVTable(RD, Base.getBaseOffset() / 8, - Base.getBase(), OutName); + CGM.getCXXABI().getMangleContext(). + mangleCXXCtorVTable(RD, Base.getBaseOffset() / 8, Base.getBase(), OutName); llvm::StringRef Name = OutName.str(); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); diff --git a/lib/CodeGen/CGValue.h b/lib/CodeGen/CGValue.h index 92ef9dc..f57ecd2 100644 --- a/lib/CodeGen/CGValue.h +++ b/lib/CodeGen/CGValue.h @@ -15,6 +15,7 @@ #ifndef CLANG_CODEGEN_CGVALUE_H #define CLANG_CODEGEN_CGVALUE_H +#include "clang/AST/ASTContext.h" #include "clang/AST/Type.h" namespace llvm { @@ -136,6 +137,9 @@ class LValue { // 'const' is unused here Qualifiers Quals; + /// The alignment to use when accessing this lvalue. + unsigned short Alignment; + // objective-c's ivar bool Ivar:1; @@ -148,15 +152,20 @@ class LValue { // Lvalue is a global reference of an objective-c object bool GlobalObjCRef : 1; + + // Lvalue is a thread local reference + bool ThreadLocalRef : 1; Expr *BaseIvarExp; private: - void SetQualifiers(Qualifiers Quals) { + void Initialize(Qualifiers Quals, unsigned Alignment = 0) { this->Quals = Quals; - - // FIXME: Convenient place to set objc flags to 0. This should really be - // done in a user-defined constructor instead. + this->Alignment = Alignment; + assert(this->Alignment == Alignment && "Alignment exceeds allowed max!"); + + // Initialize Objective-C flags. this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false; + this->ThreadLocalRef = false; this->BaseIvarExp = 0; } @@ -175,30 +184,36 @@ public: } bool isObjCIvar() const { return Ivar; } + void setObjCIvar(bool Value) { Ivar = Value; } + bool isObjCArray() const { return ObjIsArray; } + void setObjCArray(bool Value) { ObjIsArray = Value; } + bool isNonGC () const { return NonGC; } + void setNonGC(bool Value) { NonGC = Value; } + bool isGlobalObjCRef() const { return GlobalObjCRef; } - bool isObjCWeak() const { return Quals.getObjCGCAttr() == Qualifiers::Weak; } - bool isObjCStrong() const { return Quals.getObjCGCAttr() == Qualifiers::Strong; } + void setGlobalObjCRef(bool Value) { GlobalObjCRef = Value; } + + bool isThreadLocalRef() const { return ThreadLocalRef; } + void setThreadLocalRef(bool Value) { ThreadLocalRef = Value;} + + bool isObjCWeak() const { + return Quals.getObjCGCAttr() == Qualifiers::Weak; + } + bool isObjCStrong() const { + return Quals.getObjCGCAttr() == Qualifiers::Strong; + } Expr *getBaseIvarExp() const { return BaseIvarExp; } void setBaseIvarExp(Expr *V) { BaseIvarExp = V; } - unsigned getAddressSpace() const { return Quals.getAddressSpace(); } + const Qualifiers &getQuals() const { return Quals; } + Qualifiers &getQuals() { return Quals; } - static void SetObjCIvar(LValue& R, bool iValue) { - R.Ivar = iValue; - } - static void SetObjCArray(LValue& R, bool iValue) { - R.ObjIsArray = iValue; - } - static void SetGlobalObjCRef(LValue& R, bool iValue) { - R.GlobalObjCRef = iValue; - } + unsigned getAddressSpace() const { return Quals.getAddressSpace(); } - static void SetObjCNonGC(LValue& R, bool iValue) { - R.NonGC = iValue; - } + unsigned getAlignment() const { return Alignment; } // simple lvalue llvm::Value *getAddress() const { assert(isSimple()); return V; } @@ -236,11 +251,15 @@ public: return KVCRefExpr; } - static LValue MakeAddr(llvm::Value *V, Qualifiers Quals) { + static LValue MakeAddr(llvm::Value *V, QualType T, unsigned Alignment, + ASTContext &Context) { + Qualifiers Quals = Context.getCanonicalType(T).getQualifiers(); + Quals.setObjCGCAttr(Context.getObjCGCAttrKind(T)); + LValue R; R.LVType = Simple; R.V = V; - R.SetQualifiers(Quals); + R.Initialize(Quals, Alignment); return R; } @@ -250,7 +269,7 @@ public: R.LVType = VectorElt; R.V = Vec; R.VectorIdx = Idx; - R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); + R.Initialize(Qualifiers::fromCVRMask(CVR)); return R; } @@ -260,7 +279,7 @@ public: R.LVType = ExtVectorElt; R.V = Vec; R.VectorElts = Elts; - R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); + R.Initialize(Qualifiers::fromCVRMask(CVR)); return R; } @@ -276,7 +295,7 @@ public: R.LVType = BitField; R.V = BaseValue; R.BitFieldInfo = &Info; - R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); + R.Initialize(Qualifiers::fromCVRMask(CVR)); return R; } @@ -288,7 +307,7 @@ public: LValue R; R.LVType = PropertyRef; R.PropertyRefExpr = E; - R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); + R.Initialize(Qualifiers::fromCVRMask(CVR)); return R; } @@ -297,7 +316,7 @@ public: LValue R; R.LVType = KVCRef; R.KVCRefExpr = E; - R.SetQualifiers(Qualifiers::fromCVRMask(CVR)); + R.Initialize(Qualifiers::fromCVRMask(CVR)); return R; } }; diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index eb6c436..51d084e 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -13,6 +13,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "CGCXXABI.h" #include "CGDebugInfo.h" #include "CGException.h" #include "clang/Basic/TargetInfo.h" @@ -31,8 +32,9 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) : BlockFunction(cgm, *this, Builder), CGM(cgm), Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()), + NormalCleanupDest(0), EHCleanupDest(0), NextCleanupDestIndex(1), ExceptionSlot(0), DebugInfo(0), IndirectBranch(0), - SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0), + SwitchInsn(0), CaseRangeBlock(0), DidCallStackSave(false), UnreachableBlock(0), CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0), ConditionalBranchLevel(0), TerminateLandingPad(0), TerminateHandler(0), @@ -47,7 +49,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) Exceptions = getContext().getLangOptions().Exceptions; CatchUndefined = getContext().getLangOptions().CatchUndefined; - CGM.getMangleContext().startNewFunction(); + CGM.getCXXABI().getMangleContext().startNewFunction(); } ASTContext &CodeGenFunction::getContext() const { @@ -55,17 +57,6 @@ ASTContext &CodeGenFunction::getContext() const { } -llvm::Value *CodeGenFunction::GetAddrOfLocalVar(const VarDecl *VD) { - llvm::Value *Res = LocalDeclMap[VD]; - assert(Res && "Invalid argument to GetAddrOfLocalVar(), no decl!"); - return Res; -} - -llvm::Constant * -CodeGenFunction::GetAddrOfStaticLocalVar(const VarDecl *BVD) { - return cast(GetAddrOfLocalVar(BVD)); -} - const llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) { return CGM.getTypes().ConvertTypeForMem(T); } @@ -76,7 +67,7 @@ const llvm::Type *CodeGenFunction::ConvertType(QualType T) { bool CodeGenFunction::hasAggregateLLVMType(QualType T) { return T->isRecordType() || T->isArrayType() || T->isAnyComplexType() || - T->isMemberFunctionPointerType(); + T->isObjCObjectType(); } void CodeGenFunction::EmitReturnBlock() { @@ -89,26 +80,26 @@ void CodeGenFunction::EmitReturnBlock() { // We have a valid insert point, reuse it if it is empty or there are no // explicit jumps to the return block. - if (CurBB->empty() || ReturnBlock.Block->use_empty()) { - ReturnBlock.Block->replaceAllUsesWith(CurBB); - delete ReturnBlock.Block; + if (CurBB->empty() || ReturnBlock.getBlock()->use_empty()) { + ReturnBlock.getBlock()->replaceAllUsesWith(CurBB); + delete ReturnBlock.getBlock(); } else - EmitBlock(ReturnBlock.Block); + EmitBlock(ReturnBlock.getBlock()); return; } // Otherwise, if the return block is the target of a single direct // branch then we can just put the code in that block instead. This // cleans up functions which started with a unified return block. - if (ReturnBlock.Block->hasOneUse()) { + if (ReturnBlock.getBlock()->hasOneUse()) { llvm::BranchInst *BI = - dyn_cast(*ReturnBlock.Block->use_begin()); + dyn_cast(*ReturnBlock.getBlock()->use_begin()); if (BI && BI->isUnconditional() && - BI->getSuccessor(0) == ReturnBlock.Block) { + BI->getSuccessor(0) == ReturnBlock.getBlock()) { // Reset insertion point and delete the branch. Builder.SetInsertPoint(BI->getParent()); BI->eraseFromParent(); - delete ReturnBlock.Block; + delete ReturnBlock.getBlock(); return; } } @@ -117,7 +108,7 @@ void CodeGenFunction::EmitReturnBlock() { // unless it has uses. However, we still need a place to put the debug // region.end for now. - EmitBlock(ReturnBlock.Block); + EmitBlock(ReturnBlock.getBlock()); } static void EmitIfUsed(CodeGenFunction &CGF, llvm::BasicBlock *BB) { @@ -139,7 +130,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { // Emit debug descriptor for function end. if (CGDebugInfo *DI = getDebugInfo()) { DI->setLocation(EndLoc); - DI->EmitRegionEnd(CurFn, Builder); + DI->EmitFunctionEnd(Builder); } EmitFunctionEpilog(*CurFnInfo); @@ -170,6 +161,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { } } + EmitIfUsed(*this, RethrowBlock.getBlock()); EmitIfUsed(*this, TerminateLandingPad); EmitIfUsed(*this, TerminateHandler); EmitIfUsed(*this, UnreachableBlock); @@ -287,10 +279,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, EmitStartEHSpec(CurCodeDecl); EmitFunctionProlog(*CurFnInfo, CurFn, Args); - if (CXXThisDecl) - CXXThisValue = Builder.CreateLoad(LocalDeclMap[CXXThisDecl], "this"); - if (CXXVTTDecl) - CXXVTTValue = Builder.CreateLoad(LocalDeclMap[CXXVTTDecl], "vtt"); + if (D && isa(D) && cast(D)->isInstance()) + CGM.getCXXABI().EmitInstanceFunctionProlog(*this); // If any of the arguments have a variably modified type, make sure to // emit the type size. @@ -309,6 +299,23 @@ void CodeGenFunction::EmitFunctionBody(FunctionArgList &Args) { EmitStmt(FD->getBody()); } +/// Tries to mark the given function nounwind based on the +/// non-existence of any throwing calls within it. We believe this is +/// lightweight enough to do at -O0. +static void TryMarkNoThrow(llvm::Function *F) { + // LLVM treats 'nounwind' on a function as part of the type, so we + // can't do this on functions that can be overwritten. + if (F->mayBeOverridden()) return; + + for (llvm::Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) + for (llvm::BasicBlock::iterator + BI = FI->begin(), BE = FI->end(); BI != BE; ++BI) + if (llvm::CallInst *Call = dyn_cast(&*BI)) + if (!Call->doesNotThrow()) + return; + F->setDoesNotThrow(true); +} + void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { const FunctionDecl *FD = cast(GD.getDecl()); @@ -317,30 +324,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { DebugInfo = CGM.getDebugInfo(); FunctionArgList Args; + QualType ResTy = FD->getResultType(); CurGD = GD; - if (const CXXMethodDecl *MD = dyn_cast(FD)) { - if (MD->isInstance()) { - // Create the implicit 'this' decl. - // FIXME: I'm not entirely sure I like using a fake decl just for code - // generation. Maybe we can come up with a better way? - CXXThisDecl = ImplicitParamDecl::Create(getContext(), 0, - FD->getLocation(), - &getContext().Idents.get("this"), - MD->getThisType(getContext())); - Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType())); - - // Check if we need a VTT parameter as well. - if (CodeGenVTables::needsVTTParameter(GD)) { - // FIXME: The comment about using a fake decl above applies here too. - QualType T = getContext().getPointerType(getContext().VoidPtrTy); - CXXVTTDecl = - ImplicitParamDecl::Create(getContext(), 0, FD->getLocation(), - &getContext().Idents.get("vtt"), T); - Args.push_back(std::make_pair(CXXVTTDecl, CXXVTTDecl->getType())); - } - } - } + if (isa(FD) && cast(FD)->isInstance()) + CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args); if (FD->getNumParams()) { const FunctionProtoType* FProto = FD->getType()->getAs(); @@ -355,7 +343,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange(); // Emit the standard function prologue. - StartFunction(GD, FD->getResultType(), Fn, Args, BodyRange.getBegin()); + StartFunction(GD, ResTy, Fn, Args, BodyRange.getBegin()); // Generate the body of the function. if (isa(FD)) @@ -368,13 +356,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { // Emit the standard function epilogue. FinishFunction(BodyRange.getEnd()); - // Destroy the 'this' declaration. - if (CXXThisDecl) - CXXThisDecl->Destroy(getContext()); - - // Destroy the VTT declaration. - if (CXXVTTDecl) - CXXVTTDecl->Destroy(getContext()); + // If we haven't marked the function nothrow through other means, do + // a quick pass now to see if we can. + if (!CurFn->doesNotThrow()) + TryMarkNoThrow(CurFn); } /// ContainsLabel - Return true if the statement contains a label in it. If @@ -439,7 +424,7 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, if (const BinaryOperator *CondBOp = dyn_cast(Cond)) { // Handle X && Y in a condition. - if (CondBOp->getOpcode() == BinaryOperator::LAnd) { + if (CondBOp->getOpcode() == BO_LAnd) { // If we have "1 && X", simplify the code. "0 && X" would have constant // folded if the case was simple enough. if (ConstantFoldsToSimpleInteger(CondBOp->getLHS()) == 1) { @@ -466,7 +451,7 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, EndConditionalBranch(); return; - } else if (CondBOp->getOpcode() == BinaryOperator::LOr) { + } else if (CondBOp->getOpcode() == BO_LOr) { // If we have "0 || X", simplify the code. "1 || X" would have constant // folded if the case was simple enough. if (ConstantFoldsToSimpleInteger(CondBOp->getLHS()) == -1) { @@ -498,7 +483,7 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, if (const UnaryOperator *CondUOp = dyn_cast(Cond)) { // br(!x, t, f) -> br(x, f, t) - if (CondUOp->getOpcode() == UnaryOperator::LNot) + if (CondUOp->getOpcode() == UO_LNot) return EmitBranchOnBoolExpr(CondUOp->getSubExpr(), FalseBlock, TrueBlock); } @@ -533,21 +518,6 @@ void CodeGenFunction::ErrorUnsupported(const Stmt *S, const char *Type, void CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) { - // If the type contains a pointer to data member we can't memset it to zero. - // Instead, create a null constant and copy it to the destination. - if (CGM.getTypes().ContainsPointerToDataMember(Ty)) { - llvm::Constant *NullConstant = CGM.EmitNullConstant(Ty); - - llvm::GlobalVariable *NullVariable = - new llvm::GlobalVariable(CGM.getModule(), NullConstant->getType(), - /*isConstant=*/true, - llvm::GlobalVariable::PrivateLinkage, - NullConstant, llvm::Twine()); - EmitAggregateCopy(DestPtr, NullVariable, Ty, /*isVolatile=*/false); - return; - } - - // Ignore empty classes in C++. if (getContext().getLangOptions().CPlusPlus) { if (const RecordType *RT = Ty->getAs()) { @@ -555,29 +525,58 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) { return; } } - - // Otherwise, just memset the whole thing to zero. This is legal - // because in LLVM, all default initializers (other than the ones we just - // handled above) are guaranteed to have a bit pattern of all zeros. - const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext); + + // Cast the dest ptr to the appropriate i8 pointer type. + unsigned DestAS = + cast(DestPtr->getType())->getAddressSpace(); + const llvm::Type *BP = + llvm::Type::getInt8PtrTy(VMContext, DestAS); if (DestPtr->getType() != BP) DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); // Get size and alignment info for this aggregate. std::pair TypeInfo = getContext().getTypeInfo(Ty); + uint64_t Size = TypeInfo.first; + unsigned Align = TypeInfo.second; // Don't bother emitting a zero-byte memset. - if (TypeInfo.first == 0) + if (Size == 0) return; + llvm::ConstantInt *SizeVal = llvm::ConstantInt::get(IntPtrTy, Size / 8); + llvm::ConstantInt *AlignVal = Builder.getInt32(Align / 8); + + // If the type contains a pointer to data member we can't memset it to zero. + // Instead, create a null constant and copy it to the destination. + if (!CGM.getTypes().isZeroInitializable(Ty)) { + llvm::Constant *NullConstant = CGM.EmitNullConstant(Ty); + + llvm::GlobalVariable *NullVariable = + new llvm::GlobalVariable(CGM.getModule(), NullConstant->getType(), + /*isConstant=*/true, + llvm::GlobalVariable::PrivateLinkage, + NullConstant, llvm::Twine()); + llvm::Value *SrcPtr = + Builder.CreateBitCast(NullVariable, Builder.getInt8PtrTy()); + + // FIXME: variable-size types? + + // Get and call the appropriate llvm.memcpy overload. + llvm::Constant *Memcpy = + CGM.getMemCpyFn(DestPtr->getType(), SrcPtr->getType(), IntPtrTy); + Builder.CreateCall5(Memcpy, DestPtr, SrcPtr, SizeVal, AlignVal, + /*volatile*/ Builder.getFalse()); + return; + } + + // Otherwise, just memset the whole thing to zero. This is legal + // because in LLVM, all default initializers (other than the ones we just + // handled above) are guaranteed to have a bit pattern of all zeros. + // FIXME: Handle variable sized types. Builder.CreateCall5(CGM.getMemSetFn(BP, IntPtrTy), DestPtr, - llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)), - // TypeInfo.first describes size in bits. - llvm::ConstantInt::get(IntPtrTy, TypeInfo.first/8), - llvm::ConstantInt::get(Int32Ty, TypeInfo.second/8), - llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), - 0)); + Builder.getInt8(0), + SizeVal, AlignVal, /*volatile*/ Builder.getFalse()); } llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelStmt *L) { @@ -585,7 +584,7 @@ llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelStmt *L) { if (IndirectBranch == 0) GetIndirectGotoBlock(); - llvm::BasicBlock *BB = getJumpDestForLabel(L).Block; + llvm::BasicBlock *BB = getJumpDestForLabel(L).getBlock(); // Make sure the indirect branch includes all of the address-taken blocks. IndirectBranch->addDestination(BB); @@ -666,70 +665,75 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) { void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) { assert(Old.isValid()); - EHScopeStack::iterator E = EHStack.find(Old); - while (EHStack.begin() != E) - PopCleanupBlock(); -} + while (EHStack.stable_begin() != Old) { + EHCleanupScope &Scope = cast(*EHStack.begin()); + + // As long as Old strictly encloses the scope's enclosing normal + // cleanup, we're going to emit another normal cleanup which + // fallthrough can propagate through. + bool FallThroughIsBranchThrough = + Old.strictlyEncloses(Scope.getEnclosingNormalCleanup()); -/// Destroys a cleanup if it was unused. -static void DestroyCleanup(CodeGenFunction &CGF, - llvm::BasicBlock *Entry, - llvm::BasicBlock *Exit) { - assert(Entry->use_empty() && "destroying cleanup with uses!"); - assert(Exit->getTerminator() == 0 && - "exit has terminator but entry has no predecessors!"); - - // This doesn't always remove the entire cleanup, but it's much - // safer as long as we don't know what blocks belong to the cleanup. - // A *much* better approach if we care about this inefficiency would - // be to lazily emit the cleanup. - - // If the exit block is distinct from the entry, give it a branch to - // an unreachable destination. This preserves the well-formedness - // of the IR. - if (Entry != Exit) - llvm::BranchInst::Create(CGF.getUnreachableBlock(), Exit); - - assert(!Entry->getParent() && "cleanup entry already positioned?"); - // We can't just delete the entry; we have to kill any references to - // its instructions in other blocks. - for (llvm::BasicBlock::iterator I = Entry->begin(), E = Entry->end(); - I != E; ++I) - if (!I->use_empty()) - I->replaceAllUsesWith(llvm::UndefValue::get(I->getType())); - delete Entry; + PopCleanupBlock(FallThroughIsBranchThrough); + } } -/// Creates a switch instruction to thread branches out of the given -/// block (which is the exit block of a cleanup). -static void CreateCleanupSwitch(CodeGenFunction &CGF, - llvm::BasicBlock *Block) { - if (Block->getTerminator()) { - assert(isa(Block->getTerminator()) && - "cleanup block already has a terminator, but it isn't a switch"); - return; +static llvm::BasicBlock *CreateNormalEntry(CodeGenFunction &CGF, + EHCleanupScope &Scope) { + assert(Scope.isNormalCleanup()); + llvm::BasicBlock *Entry = Scope.getNormalBlock(); + if (!Entry) { + Entry = CGF.createBasicBlock("cleanup"); + Scope.setNormalBlock(Entry); } + return Entry; +} - llvm::Value *DestCodePtr - = CGF.CreateTempAlloca(CGF.Builder.getInt32Ty(), "cleanup.dst"); - CGBuilderTy Builder(Block); - llvm::Value *DestCode = Builder.CreateLoad(DestCodePtr, "tmp"); +static llvm::BasicBlock *CreateEHEntry(CodeGenFunction &CGF, + EHCleanupScope &Scope) { + assert(Scope.isEHCleanup()); + llvm::BasicBlock *Entry = Scope.getEHBlock(); + if (!Entry) { + Entry = CGF.createBasicBlock("eh.cleanup"); + Scope.setEHBlock(Entry); + } + return Entry; +} - // Create a switch instruction to determine where to jump next. - Builder.CreateSwitch(DestCode, CGF.getUnreachableBlock()); +/// Transitions the terminator of the given exit-block of a cleanup to +/// be a cleanup switch. +static llvm::SwitchInst *TransitionToCleanupSwitch(CodeGenFunction &CGF, + llvm::BasicBlock *Block) { + // If it's a branch, turn it into a switch whose default + // destination is its original target. + llvm::TerminatorInst *Term = Block->getTerminator(); + assert(Term && "can't transition block without terminator"); + + if (llvm::BranchInst *Br = dyn_cast(Term)) { + assert(Br->isUnconditional()); + llvm::LoadInst *Load = + new llvm::LoadInst(CGF.getNormalCleanupDestSlot(), "cleanup.dest", Term); + llvm::SwitchInst *Switch = + llvm::SwitchInst::Create(Load, Br->getSuccessor(0), 4, Block); + Br->eraseFromParent(); + return Switch; + } else { + return cast(Term); + } } /// Attempts to reduce a cleanup's entry block to a fallthrough. This /// is basically llvm::MergeBlockIntoPredecessor, except -/// simplified/optimized for the tighter constraints on cleanup -/// blocks. -static void SimplifyCleanupEntry(CodeGenFunction &CGF, - llvm::BasicBlock *Entry) { +/// simplified/optimized for the tighter constraints on cleanup blocks. +/// +/// Returns the new block, whatever it is. +static llvm::BasicBlock *SimplifyCleanupEntry(CodeGenFunction &CGF, + llvm::BasicBlock *Entry) { llvm::BasicBlock *Pred = Entry->getSinglePredecessor(); - if (!Pred) return; + if (!Pred) return Entry; llvm::BranchInst *Br = dyn_cast(Pred->getTerminator()); - if (!Br || Br->isConditional()) return; + if (!Br || Br->isConditional()) return Entry; assert(Br->getSuccessor(0) == Entry); // If we were previously inserting at the end of the cleanup entry @@ -749,145 +753,44 @@ static void SimplifyCleanupEntry(CodeGenFunction &CGF, if (WasInsertBlock) CGF.Builder.SetInsertPoint(Pred); -} - -/// Attempts to reduce an cleanup's exit switch to an unconditional -/// branch. -static void SimplifyCleanupExit(llvm::BasicBlock *Exit) { - llvm::TerminatorInst *Terminator = Exit->getTerminator(); - assert(Terminator && "completed cleanup exit has no terminator"); - - llvm::SwitchInst *Switch = dyn_cast(Terminator); - if (!Switch) return; - if (Switch->getNumCases() != 2) return; // default + 1 - llvm::LoadInst *Cond = cast(Switch->getCondition()); - llvm::AllocaInst *CondVar = cast(Cond->getPointerOperand()); - - // Replace the switch instruction with an unconditional branch. - llvm::BasicBlock *Dest = Switch->getSuccessor(1); // default is 0 - Switch->eraseFromParent(); - llvm::BranchInst::Create(Dest, Exit); - - // Delete all uses of the condition variable. - Cond->eraseFromParent(); - while (!CondVar->use_empty()) - cast(*CondVar->use_begin())->eraseFromParent(); - - // Delete the condition variable itself. - CondVar->eraseFromParent(); + return Pred; } -/// Threads a branch fixup through a cleanup block. -static void ThreadFixupThroughCleanup(CodeGenFunction &CGF, - BranchFixup &Fixup, - llvm::BasicBlock *Entry, - llvm::BasicBlock *Exit) { - if (!Exit->getTerminator()) - CreateCleanupSwitch(CGF, Exit); - - // Find the switch and its destination index alloca. - llvm::SwitchInst *Switch = cast(Exit->getTerminator()); - llvm::Value *DestCodePtr = - cast(Switch->getCondition())->getPointerOperand(); - - // Compute the index of the new case we're adding to the switch. - unsigned Index = Switch->getNumCases(); - - const llvm::IntegerType *i32 = llvm::Type::getInt32Ty(CGF.getLLVMContext()); - llvm::ConstantInt *IndexV = llvm::ConstantInt::get(i32, Index); - - // Set the index in the origin block. - new llvm::StoreInst(IndexV, DestCodePtr, Fixup.Origin); - - // Add a case to the switch. - Switch->addCase(IndexV, Fixup.Destination); - - // Change the last branch to point to the cleanup entry block. - Fixup.LatestBranch->setSuccessor(Fixup.LatestBranchIndex, Entry); - - // And finally, update the fixup. - Fixup.LatestBranch = Switch; - Fixup.LatestBranchIndex = Index; -} - -/// Try to simplify both the entry and exit edges of a cleanup. -static void SimplifyCleanupEdges(CodeGenFunction &CGF, - llvm::BasicBlock *Entry, - llvm::BasicBlock *Exit) { - - // Given their current implementations, it's important to run these - // in this order: SimplifyCleanupEntry will delete Entry if it can - // be merged into its predecessor, which will then break - // SimplifyCleanupExit if (as is common) Entry == Exit. - - SimplifyCleanupExit(Exit); - SimplifyCleanupEntry(CGF, Entry); -} - -static void EmitLazyCleanup(CodeGenFunction &CGF, - EHScopeStack::LazyCleanup *Fn, - bool ForEH) { +static void EmitCleanup(CodeGenFunction &CGF, + EHScopeStack::Cleanup *Fn, + bool ForEH) { if (ForEH) CGF.EHStack.pushTerminate(); Fn->Emit(CGF, ForEH); if (ForEH) CGF.EHStack.popTerminate(); assert(CGF.HaveInsertPoint() && "cleanup ended with no insertion point?"); } -static void SplitAndEmitLazyCleanup(CodeGenFunction &CGF, - EHScopeStack::LazyCleanup *Fn, - bool ForEH, - llvm::BasicBlock *Entry) { - assert(Entry && "no entry block for cleanup"); - - // Remove the switch and load from the end of the entry block. - llvm::Instruction *Switch = &Entry->getInstList().back(); - Entry->getInstList().remove(Switch); - assert(isa(Switch)); - llvm::Instruction *Load = &Entry->getInstList().back(); - Entry->getInstList().remove(Load); - assert(isa(Load)); - - assert(Entry->getInstList().empty() && - "lazy cleanup block not empty after removing load/switch pair?"); - - // Emit the actual cleanup at the end of the entry block. - CGF.Builder.SetInsertPoint(Entry); - EmitLazyCleanup(CGF, Fn, ForEH); - - // Put the load and switch at the end of the exit block. - llvm::BasicBlock *Exit = CGF.Builder.GetInsertBlock(); - Exit->getInstList().push_back(Load); - Exit->getInstList().push_back(Switch); - - // Clean up the edges if possible. - SimplifyCleanupEdges(CGF, Entry, Exit); - - CGF.Builder.ClearInsertionPoint(); -} - -static void PopLazyCleanupBlock(CodeGenFunction &CGF) { - assert(isa(*CGF.EHStack.begin()) && "top not a cleanup!"); - EHLazyCleanupScope &Scope = cast(*CGF.EHStack.begin()); - assert(Scope.getFixupDepth() <= CGF.EHStack.getNumBranchFixups()); +/// Pops a cleanup block. If the block includes a normal cleanup, the +/// current insertion point is threaded through the cleanup, as are +/// any branch fixups on the cleanup. +void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { + assert(!EHStack.empty() && "cleanup stack is empty!"); + assert(isa(*EHStack.begin()) && "top not a cleanup!"); + EHCleanupScope &Scope = cast(*EHStack.begin()); + assert(Scope.getFixupDepth() <= EHStack.getNumBranchFixups()); + assert(Scope.isActive() && "cleanup was still inactive when popped!"); // Check whether we need an EH cleanup. This is only true if we've // generated a lazy EH cleanup block. - llvm::BasicBlock *EHEntry = Scope.getEHBlock(); - bool RequiresEHCleanup = (EHEntry != 0); + bool RequiresEHCleanup = Scope.hasEHBranches(); // Check the three conditions which might require a normal cleanup: // - whether there are branch fix-ups through this cleanup unsigned FixupDepth = Scope.getFixupDepth(); - bool HasFixups = CGF.EHStack.getNumBranchFixups() != FixupDepth; + bool HasFixups = EHStack.getNumBranchFixups() != FixupDepth; - // - whether control has already been threaded through this cleanup - llvm::BasicBlock *NormalEntry = Scope.getNormalBlock(); - bool HasExistingBranches = (NormalEntry != 0); + // - whether there are branch-throughs or branch-afters + bool HasExistingBranches = Scope.hasBranches(); // - whether there's a fallthrough - llvm::BasicBlock *FallthroughSource = CGF.Builder.GetInsertBlock(); + llvm::BasicBlock *FallthroughSource = Builder.GetInsertBlock(); bool HasFallthrough = (FallthroughSource != 0); bool RequiresNormalCleanup = false; @@ -898,9 +801,9 @@ static void PopLazyCleanupBlock(CodeGenFunction &CGF) { // If we don't need the cleanup at all, we're done. if (!RequiresNormalCleanup && !RequiresEHCleanup) { - CGF.EHStack.popCleanup(); - assert(CGF.EHStack.getNumBranchFixups() == 0 || - CGF.EHStack.hasNormalCleanups()); + EHStack.popCleanup(); // safe because there are no fixups + assert(EHStack.getNumBranchFixups() == 0 || + EHStack.hasNormalCleanups()); return; } @@ -912,319 +815,527 @@ static void PopLazyCleanupBlock(CodeGenFunction &CGF) { memcpy(CleanupBuffer.data(), Scope.getCleanupBuffer(), Scope.getCleanupSize()); CleanupBuffer.set_size(Scope.getCleanupSize()); - EHScopeStack::LazyCleanup *Fn = - reinterpret_cast(CleanupBuffer.data()); + EHScopeStack::Cleanup *Fn = + reinterpret_cast(CleanupBuffer.data()); + + // We want to emit the EH cleanup after the normal cleanup, but go + // ahead and do the setup for the EH cleanup while the scope is still + // alive. + llvm::BasicBlock *EHEntry = 0; + llvm::SmallVector EHInstsToAppend; + if (RequiresEHCleanup) { + EHEntry = CreateEHEntry(*this, Scope); + + // Figure out the branch-through dest if necessary. + llvm::BasicBlock *EHBranchThroughDest = 0; + if (Scope.hasEHBranchThroughs()) { + assert(Scope.getEnclosingEHCleanup() != EHStack.stable_end()); + EHScope &S = *EHStack.find(Scope.getEnclosingEHCleanup()); + EHBranchThroughDest = CreateEHEntry(*this, cast(S)); + } - // We're done with the scope; pop it off so we can emit the cleanups. - CGF.EHStack.popCleanup(); + // If we have exactly one branch-after and no branch-throughs, we + // can dispatch it without a switch. + if (!Scope.hasEHBranchThroughs() && + Scope.getNumEHBranchAfters() == 1) { + assert(!EHBranchThroughDest); + + // TODO: remove the spurious eh.cleanup.dest stores if this edge + // never went through any switches. + llvm::BasicBlock *BranchAfterDest = Scope.getEHBranchAfterBlock(0); + EHInstsToAppend.push_back(llvm::BranchInst::Create(BranchAfterDest)); + + // Otherwise, if we have any branch-afters, we need a switch. + } else if (Scope.getNumEHBranchAfters()) { + // The default of the switch belongs to the branch-throughs if + // they exist. + llvm::BasicBlock *Default = + (EHBranchThroughDest ? EHBranchThroughDest : getUnreachableBlock()); + + const unsigned SwitchCapacity = Scope.getNumEHBranchAfters(); + + llvm::LoadInst *Load = + new llvm::LoadInst(getEHCleanupDestSlot(), "cleanup.dest"); + llvm::SwitchInst *Switch = + llvm::SwitchInst::Create(Load, Default, SwitchCapacity); + + EHInstsToAppend.push_back(Load); + EHInstsToAppend.push_back(Switch); + + for (unsigned I = 0, E = Scope.getNumEHBranchAfters(); I != E; ++I) + Switch->addCase(Scope.getEHBranchAfterIndex(I), + Scope.getEHBranchAfterBlock(I)); + + // Otherwise, we have only branch-throughs; jump to the next EH + // cleanup. + } else { + assert(EHBranchThroughDest); + EHInstsToAppend.push_back(llvm::BranchInst::Create(EHBranchThroughDest)); + } + } + + if (!RequiresNormalCleanup) { + EHStack.popCleanup(); + } else { + // As a kindof crazy internal case, branch-through fall-throughs + // leave the insertion point set to the end of the last cleanup. + bool HasPrebranchedFallthrough = + (HasFallthrough && FallthroughSource->getTerminator()); + assert(!HasPrebranchedFallthrough || + FallthroughSource->getTerminator()->getSuccessor(0) + == Scope.getNormalBlock()); - if (RequiresNormalCleanup) { // If we have a fallthrough and no other need for the cleanup, // emit it directly. - if (HasFallthrough && !HasFixups && !HasExistingBranches) { - EmitLazyCleanup(CGF, Fn, /*ForEH*/ false); + if (HasFallthrough && !HasPrebranchedFallthrough && + !HasFixups && !HasExistingBranches) { + + // Fixups can cause us to optimistically create a normal block, + // only to later have no real uses for it. Just delete it in + // this case. + // TODO: we can potentially simplify all the uses after this. + if (Scope.getNormalBlock()) { + Scope.getNormalBlock()->replaceAllUsesWith(getUnreachableBlock()); + delete Scope.getNormalBlock(); + } + + EHStack.popCleanup(); + + EmitCleanup(*this, Fn, /*ForEH*/ false); // Otherwise, the best approach is to thread everything through // the cleanup block and then try to clean up after ourselves. } else { // Force the entry block to exist. - if (!HasExistingBranches) { - NormalEntry = CGF.createBasicBlock("cleanup"); - CreateCleanupSwitch(CGF, NormalEntry); + llvm::BasicBlock *NormalEntry = CreateNormalEntry(*this, Scope); + + // If there's a fallthrough, we need to store the cleanup + // destination index. For fall-throughs this is always zero. + if (HasFallthrough && !HasPrebranchedFallthrough) + Builder.CreateStore(Builder.getInt32(0), getNormalCleanupDestSlot()); + + // Emit the entry block. This implicitly branches to it if we + // have fallthrough. All the fixups and existing branches should + // already be branched to it. + EmitBlock(NormalEntry); + + bool HasEnclosingCleanups = + (Scope.getEnclosingNormalCleanup() != EHStack.stable_end()); + + // Compute the branch-through dest if we need it: + // - if there are branch-throughs threaded through the scope + // - if fall-through is a branch-through + // - if there are fixups that will be optimistically forwarded + // to the enclosing cleanup + llvm::BasicBlock *BranchThroughDest = 0; + if (Scope.hasBranchThroughs() || + (HasFallthrough && FallthroughIsBranchThrough) || + (HasFixups && HasEnclosingCleanups)) { + assert(HasEnclosingCleanups); + EHScope &S = *EHStack.find(Scope.getEnclosingNormalCleanup()); + BranchThroughDest = CreateNormalEntry(*this, cast(S)); } - CGF.EmitBlock(NormalEntry); - - // Thread the fallthrough edge through the (momentarily trivial) - // cleanup. - llvm::BasicBlock *FallthroughDestination = 0; - if (HasFallthrough) { - assert(isa(FallthroughSource->getTerminator())); - FallthroughDestination = CGF.createBasicBlock("cleanup.cont"); - - BranchFixup Fix; - Fix.Destination = FallthroughDestination; - Fix.LatestBranch = FallthroughSource->getTerminator(); - Fix.LatestBranchIndex = 0; - Fix.Origin = Fix.LatestBranch; + llvm::BasicBlock *FallthroughDest = 0; + llvm::SmallVector InstsToAppend; + + // If there's exactly one branch-after and no other threads, + // we can route it without a switch. + if (!Scope.hasBranchThroughs() && !HasFixups && !HasFallthrough && + Scope.getNumBranchAfters() == 1) { + assert(!BranchThroughDest); + + // TODO: clean up the possibly dead stores to the cleanup dest slot. + llvm::BasicBlock *BranchAfter = Scope.getBranchAfterBlock(0); + InstsToAppend.push_back(llvm::BranchInst::Create(BranchAfter)); + + // Build a switch-out if we need it: + // - if there are branch-afters threaded through the scope + // - if fall-through is a branch-after + // - if there are fixups that have nowhere left to go and + // so must be immediately resolved + } else if (Scope.getNumBranchAfters() || + (HasFallthrough && !FallthroughIsBranchThrough) || + (HasFixups && !HasEnclosingCleanups)) { + + llvm::BasicBlock *Default = + (BranchThroughDest ? BranchThroughDest : getUnreachableBlock()); + + // TODO: base this on the number of branch-afters and fixups + const unsigned SwitchCapacity = 10; + + llvm::LoadInst *Load = + new llvm::LoadInst(getNormalCleanupDestSlot(), "cleanup.dest"); + llvm::SwitchInst *Switch = + llvm::SwitchInst::Create(Load, Default, SwitchCapacity); + + InstsToAppend.push_back(Load); + InstsToAppend.push_back(Switch); + + // Branch-after fallthrough. + if (HasFallthrough && !FallthroughIsBranchThrough) { + FallthroughDest = createBasicBlock("cleanup.cont"); + Switch->addCase(Builder.getInt32(0), FallthroughDest); + } - // Restore fixup invariant. EmitBlock added a branch to the - // cleanup which we need to redirect to the destination. - cast(Fix.LatestBranch) - ->setSuccessor(0, Fix.Destination); + for (unsigned I = 0, E = Scope.getNumBranchAfters(); I != E; ++I) { + Switch->addCase(Scope.getBranchAfterIndex(I), + Scope.getBranchAfterBlock(I)); + } - ThreadFixupThroughCleanup(CGF, Fix, NormalEntry, NormalEntry); + if (HasFixups && !HasEnclosingCleanups) + ResolveAllBranchFixups(Switch); + } else { + // We should always have a branch-through destination in this case. + assert(BranchThroughDest); + InstsToAppend.push_back(llvm::BranchInst::Create(BranchThroughDest)); } - // Thread any "real" fixups we need to thread. - for (unsigned I = FixupDepth, E = CGF.EHStack.getNumBranchFixups(); - I != E; ++I) - if (CGF.EHStack.getBranchFixup(I).Destination) - ThreadFixupThroughCleanup(CGF, CGF.EHStack.getBranchFixup(I), - NormalEntry, NormalEntry); - - SplitAndEmitLazyCleanup(CGF, Fn, /*ForEH*/ false, NormalEntry); - - if (HasFallthrough) - CGF.EmitBlock(FallthroughDestination); + // We're finally ready to pop the cleanup. + EHStack.popCleanup(); + assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups); + + EmitCleanup(*this, Fn, /*ForEH*/ false); + + // Append the prepared cleanup prologue from above. + llvm::BasicBlock *NormalExit = Builder.GetInsertBlock(); + for (unsigned I = 0, E = InstsToAppend.size(); I != E; ++I) + NormalExit->getInstList().push_back(InstsToAppend[I]); + + // Optimistically hope that any fixups will continue falling through. + for (unsigned I = FixupDepth, E = EHStack.getNumBranchFixups(); + I < E; ++I) { + BranchFixup &Fixup = CGF.EHStack.getBranchFixup(I); + if (!Fixup.Destination) continue; + if (!Fixup.OptimisticBranchBlock) { + new llvm::StoreInst(Builder.getInt32(Fixup.DestinationIndex), + getNormalCleanupDestSlot(), + Fixup.InitialBranch); + Fixup.InitialBranch->setSuccessor(0, NormalEntry); + } + Fixup.OptimisticBranchBlock = NormalExit; + } + + if (FallthroughDest) + EmitBlock(FallthroughDest); + else if (!HasFallthrough) + Builder.ClearInsertionPoint(); + + // Check whether we can merge NormalEntry into a single predecessor. + // This might invalidate (non-IR) pointers to NormalEntry. + llvm::BasicBlock *NewNormalEntry = + SimplifyCleanupEntry(*this, NormalEntry); + + // If it did invalidate those pointers, and NormalEntry was the same + // as NormalExit, go back and patch up the fixups. + if (NewNormalEntry != NormalEntry && NormalEntry == NormalExit) + for (unsigned I = FixupDepth, E = EHStack.getNumBranchFixups(); + I < E; ++I) + CGF.EHStack.getBranchFixup(I).OptimisticBranchBlock = NewNormalEntry; } } + assert(EHStack.hasNormalCleanups() || EHStack.getNumBranchFixups() == 0); + // Emit the EH cleanup if required. if (RequiresEHCleanup) { - CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); - CGF.EmitBlock(EHEntry); - SplitAndEmitLazyCleanup(CGF, Fn, /*ForEH*/ true, EHEntry); - CGF.Builder.restoreIP(SavedIP); - } -} + CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); -/// Pops a cleanup block. If the block includes a normal cleanup, the -/// current insertion point is threaded through the cleanup, as are -/// any branch fixups on the cleanup. -void CodeGenFunction::PopCleanupBlock() { - assert(!EHStack.empty() && "cleanup stack is empty!"); - if (isa(*EHStack.begin())) - return PopLazyCleanupBlock(*this); + EmitBlock(EHEntry); + EmitCleanup(*this, Fn, /*ForEH*/ true); - assert(isa(*EHStack.begin()) && "top not a cleanup!"); - EHCleanupScope &Scope = cast(*EHStack.begin()); - assert(Scope.getFixupDepth() <= EHStack.getNumBranchFixups()); + // Append the prepared cleanup prologue from above. + llvm::BasicBlock *EHExit = Builder.GetInsertBlock(); + for (unsigned I = 0, E = EHInstsToAppend.size(); I != E; ++I) + EHExit->getInstList().push_back(EHInstsToAppend[I]); - // Handle the EH cleanup if (1) there is one and (2) it's different - // from the normal cleanup. - if (Scope.isEHCleanup() && - Scope.getEHEntry() != Scope.getNormalEntry()) { - llvm::BasicBlock *EHEntry = Scope.getEHEntry(); - llvm::BasicBlock *EHExit = Scope.getEHExit(); - - if (EHEntry->use_empty()) { - DestroyCleanup(*this, EHEntry, EHExit); - } else { - // TODO: this isn't really the ideal location to put this EH - // cleanup, but lazy emission is a better solution than trying - // to pick a better spot. - CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); - EmitBlock(EHEntry); - Builder.restoreIP(SavedIP); - - SimplifyCleanupEdges(*this, EHEntry, EHExit); - } - } + Builder.restoreIP(SavedIP); - // If we only have an EH cleanup, we don't really need to do much - // here. Branch fixups just naturally drop down to the enclosing - // cleanup scope. - if (!Scope.isNormalCleanup()) { - EHStack.popCleanup(); - assert(EHStack.getNumBranchFixups() == 0 || EHStack.hasNormalCleanups()); - return; + SimplifyCleanupEntry(*this, EHEntry); } +} - // Check whether the scope has any fixups that need to be threaded. - unsigned FixupDepth = Scope.getFixupDepth(); - bool HasFixups = EHStack.getNumBranchFixups() != FixupDepth; +/// Terminate the current block by emitting a branch which might leave +/// the current cleanup-protected scope. The target scope may not yet +/// be known, in which case this will require a fixup. +/// +/// As a side-effect, this method clears the insertion point. +void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) { + assert(Dest.getScopeDepth().encloses(EHStack.getInnermostNormalCleanup()) + && "stale jump destination"); - // Grab the entry and exit blocks. - llvm::BasicBlock *Entry = Scope.getNormalEntry(); - llvm::BasicBlock *Exit = Scope.getNormalExit(); + if (!HaveInsertPoint()) + return; - // Check whether anything's been threaded through the cleanup already. - assert((Exit->getTerminator() == 0) == Entry->use_empty() && - "cleanup entry/exit mismatch"); - bool HasExistingBranches = !Entry->use_empty(); + // Create the branch. + llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock()); - // Check whether we need to emit a "fallthrough" branch through the - // cleanup for the current insertion point. - llvm::BasicBlock *FallThrough = Builder.GetInsertBlock(); - if (FallThrough && FallThrough->getTerminator()) - FallThrough = 0; + // Calculate the innermost active normal cleanup. + EHScopeStack::stable_iterator + TopCleanup = EHStack.getInnermostActiveNormalCleanup(); - // If *nothing* is using the cleanup, kill it. - if (!FallThrough && !HasFixups && !HasExistingBranches) { - EHStack.popCleanup(); - DestroyCleanup(*this, Entry, Exit); + // If we're not in an active normal cleanup scope, or if the + // destination scope is within the innermost active normal cleanup + // scope, we don't need to worry about fixups. + if (TopCleanup == EHStack.stable_end() || + TopCleanup.encloses(Dest.getScopeDepth())) { // works for invalid + Builder.ClearInsertionPoint(); return; } - // Otherwise, add the block to the function. - EmitBlock(Entry); + // If we can't resolve the destination cleanup scope, just add this + // to the current cleanup scope as a branch fixup. + if (!Dest.getScopeDepth().isValid()) { + BranchFixup &Fixup = EHStack.addBranchFixup(); + Fixup.Destination = Dest.getBlock(); + Fixup.DestinationIndex = Dest.getDestIndex(); + Fixup.InitialBranch = BI; + Fixup.OptimisticBranchBlock = 0; - if (FallThrough) - Builder.SetInsertPoint(Exit); - else Builder.ClearInsertionPoint(); - - // Fast case: if we don't have to add any fixups, and either - // we don't have a fallthrough or the cleanup wasn't previously - // used, then the setup above is sufficient. - if (!HasFixups) { - if (!FallThrough) { - assert(HasExistingBranches && "no reason for cleanup but didn't kill before"); - EHStack.popCleanup(); - SimplifyCleanupEdges(*this, Entry, Exit); - return; - } else if (!HasExistingBranches) { - assert(FallThrough && "no reason for cleanup but didn't kill before"); - // We can't simplify the exit edge in this case because we're - // already inserting at the end of the exit block. - EHStack.popCleanup(); - SimplifyCleanupEntry(*this, Entry); - return; - } + return; } - // Otherwise we're going to have to thread things through the cleanup. - llvm::SmallVector Fixups; - - // Synthesize a fixup for the current insertion point. - BranchFixup Cur; - if (FallThrough) { - Cur.Destination = createBasicBlock("cleanup.cont"); - Cur.LatestBranch = FallThrough->getTerminator(); - Cur.LatestBranchIndex = 0; - Cur.Origin = Cur.LatestBranch; - - // Restore fixup invariant. EmitBlock added a branch to the cleanup - // which we need to redirect to the destination. - cast(Cur.LatestBranch)->setSuccessor(0, Cur.Destination); + // Otherwise, thread through all the normal cleanups in scope. - Fixups.push_back(&Cur); - } else { - Cur.Destination = 0; - } + // Store the index at the start. + llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex()); + new llvm::StoreInst(Index, getNormalCleanupDestSlot(), BI); - // Collect any "real" fixups we need to thread. - for (unsigned I = FixupDepth, E = EHStack.getNumBranchFixups(); - I != E; ++I) - if (EHStack.getBranchFixup(I).Destination) - Fixups.push_back(&EHStack.getBranchFixup(I)); - - assert(!Fixups.empty() && "no fixups, invariants broken!"); - - // If there's only a single fixup to thread through, do so with - // unconditional branches. This only happens if there's a single - // branch and no fallthrough. - if (Fixups.size() == 1 && !HasExistingBranches) { - Fixups[0]->LatestBranch->setSuccessor(Fixups[0]->LatestBranchIndex, Entry); - llvm::BranchInst *Br = - llvm::BranchInst::Create(Fixups[0]->Destination, Exit); - Fixups[0]->LatestBranch = Br; - Fixups[0]->LatestBranchIndex = 0; - - // Otherwise, force a switch statement and thread everything through - // the switch. - } else { - CreateCleanupSwitch(*this, Exit); - for (unsigned I = 0, E = Fixups.size(); I != E; ++I) - ThreadFixupThroughCleanup(*this, *Fixups[I], Entry, Exit); + // Adjust BI to point to the first cleanup block. + { + EHCleanupScope &Scope = + cast(*EHStack.find(TopCleanup)); + BI->setSuccessor(0, CreateNormalEntry(*this, Scope)); } - // Emit the fallthrough destination block if necessary. - if (Cur.Destination) - EmitBlock(Cur.Destination); + // Add this destination to all the scopes involved. + EHScopeStack::stable_iterator I = TopCleanup; + EHScopeStack::stable_iterator E = Dest.getScopeDepth(); + if (E.strictlyEncloses(I)) { + while (true) { + EHCleanupScope &Scope = cast(*EHStack.find(I)); + assert(Scope.isNormalCleanup()); + I = Scope.getEnclosingNormalCleanup(); + + // If this is the last cleanup we're propagating through, tell it + // that there's a resolved jump moving through it. + if (!E.strictlyEncloses(I)) { + Scope.addBranchAfter(Index, Dest.getBlock()); + break; + } - // We're finally done with the cleanup. - EHStack.popCleanup(); + // Otherwise, tell the scope that there's a jump propoagating + // through it. If this isn't new information, all the rest of + // the work has been done before. + if (!Scope.addBranchThrough(Dest.getBlock())) + break; + } + } + + Builder.ClearInsertionPoint(); } -void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) { +void CodeGenFunction::EmitBranchThroughEHCleanup(UnwindDest Dest) { + // We should never get invalid scope depths for an UnwindDest; that + // implies that the destination wasn't set up correctly. + assert(Dest.getScopeDepth().isValid() && "invalid scope depth on EH dest?"); + if (!HaveInsertPoint()) return; // Create the branch. - llvm::BranchInst *BI = Builder.CreateBr(Dest.Block); + llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock()); - // If we're not in a cleanup scope, we don't need to worry about - // fixups. - if (!EHStack.hasNormalCleanups()) { + // Calculate the innermost active cleanup. + EHScopeStack::stable_iterator + InnermostCleanup = EHStack.getInnermostActiveEHCleanup(); + + // If the destination is in the same EH cleanup scope as us, we + // don't need to thread through anything. + if (InnermostCleanup.encloses(Dest.getScopeDepth())) { Builder.ClearInsertionPoint(); return; } + assert(InnermostCleanup != EHStack.stable_end()); - // Initialize a fixup. - BranchFixup Fixup; - Fixup.Destination = Dest.Block; - Fixup.Origin = BI; - Fixup.LatestBranch = BI; - Fixup.LatestBranchIndex = 0; + // Store the index at the start. + llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex()); + new llvm::StoreInst(Index, getEHCleanupDestSlot(), BI); - // If we can't resolve the destination cleanup scope, just add this - // to the current cleanup scope. - if (!Dest.ScopeDepth.isValid()) { - EHStack.addBranchFixup() = Fixup; - Builder.ClearInsertionPoint(); - return; + // Adjust BI to point to the first cleanup block. + { + EHCleanupScope &Scope = + cast(*EHStack.find(InnermostCleanup)); + BI->setSuccessor(0, CreateEHEntry(*this, Scope)); } - - for (EHScopeStack::iterator I = EHStack.begin(), - E = EHStack.find(Dest.ScopeDepth); I != E; ++I) { - if (isa(*I)) { - EHCleanupScope &Scope = cast(*I); - if (Scope.isNormalCleanup()) - ThreadFixupThroughCleanup(*this, Fixup, Scope.getNormalEntry(), - Scope.getNormalExit()); - } else if (isa(*I)) { - EHLazyCleanupScope &Scope = cast(*I); - if (Scope.isNormalCleanup()) { - llvm::BasicBlock *Block = Scope.getNormalBlock(); - if (!Block) { - Block = createBasicBlock("cleanup"); - Scope.setNormalBlock(Block); - } - ThreadFixupThroughCleanup(*this, Fixup, Block, Block); - } + + // Add this destination to all the scopes involved. + for (EHScopeStack::stable_iterator + I = InnermostCleanup, E = Dest.getScopeDepth(); ; ) { + assert(E.strictlyEncloses(I)); + EHCleanupScope &Scope = cast(*EHStack.find(I)); + assert(Scope.isEHCleanup()); + I = Scope.getEnclosingEHCleanup(); + + // If this is the last cleanup we're propagating through, add this + // as a branch-after. + if (I == E) { + Scope.addEHBranchAfter(Index, Dest.getBlock()); + break; } + + // Otherwise, add it as a branch-through. If this isn't new + // information, all the rest of the work has been done before. + if (!Scope.addEHBranchThrough(Dest.getBlock())) + break; } Builder.ClearInsertionPoint(); } -void CodeGenFunction::EmitBranchThroughEHCleanup(JumpDest Dest) { - if (!HaveInsertPoint()) - return; +/// All the branch fixups on the EH stack have propagated out past the +/// outermost normal cleanup; resolve them all by adding cases to the +/// given switch instruction. +void CodeGenFunction::ResolveAllBranchFixups(llvm::SwitchInst *Switch) { + llvm::SmallPtrSet CasesAdded; + + for (unsigned I = 0, E = EHStack.getNumBranchFixups(); I != E; ++I) { + // Skip this fixup if its destination isn't set or if we've + // already treated it. + BranchFixup &Fixup = EHStack.getBranchFixup(I); + if (Fixup.Destination == 0) continue; + if (!CasesAdded.insert(Fixup.Destination)) continue; + + Switch->addCase(Builder.getInt32(Fixup.DestinationIndex), + Fixup.Destination); + } - // Create the branch. - llvm::BranchInst *BI = Builder.CreateBr(Dest.Block); + EHStack.clearFixups(); +} - // If we're not in a cleanup scope, we don't need to worry about - // fixups. - if (!EHStack.hasEHCleanups()) { - Builder.ClearInsertionPoint(); - return; +void CodeGenFunction::ResolveBranchFixups(llvm::BasicBlock *Block) { + assert(Block && "resolving a null target block"); + if (!EHStack.getNumBranchFixups()) return; + + assert(EHStack.hasNormalCleanups() && + "branch fixups exist with no normal cleanups on stack"); + + llvm::SmallPtrSet ModifiedOptimisticBlocks; + bool ResolvedAny = false; + + for (unsigned I = 0, E = EHStack.getNumBranchFixups(); I != E; ++I) { + // Skip this fixup if its destination doesn't match. + BranchFixup &Fixup = EHStack.getBranchFixup(I); + if (Fixup.Destination != Block) continue; + + Fixup.Destination = 0; + ResolvedAny = true; + + // If it doesn't have an optimistic branch block, LatestBranch is + // already pointing to the right place. + llvm::BasicBlock *BranchBB = Fixup.OptimisticBranchBlock; + if (!BranchBB) + continue; + + // Don't process the same optimistic branch block twice. + if (!ModifiedOptimisticBlocks.insert(BranchBB)) + continue; + + llvm::SwitchInst *Switch = TransitionToCleanupSwitch(*this, BranchBB); + + // Add a case to the switch. + Switch->addCase(Builder.getInt32(Fixup.DestinationIndex), Block); } - // Initialize a fixup. - BranchFixup Fixup; - Fixup.Destination = Dest.Block; - Fixup.Origin = BI; - Fixup.LatestBranch = BI; - Fixup.LatestBranchIndex = 0; - - // We should never get invalid scope depths for these: invalid scope - // depths only arise for as-yet-unemitted labels, and we can't do an - // EH-unwind to one of those. - assert(Dest.ScopeDepth.isValid() && "invalid scope depth on EH dest?"); - - for (EHScopeStack::iterator I = EHStack.begin(), - E = EHStack.find(Dest.ScopeDepth); I != E; ++I) { - if (isa(*I)) { - EHCleanupScope &Scope = cast(*I); - if (Scope.isEHCleanup()) - ThreadFixupThroughCleanup(*this, Fixup, Scope.getEHEntry(), - Scope.getEHExit()); - } else if (isa(*I)) { - EHLazyCleanupScope &Scope = cast(*I); - if (Scope.isEHCleanup()) { - llvm::BasicBlock *Block = Scope.getEHBlock(); - if (!Block) { - Block = createBasicBlock("eh.cleanup"); - Scope.setEHBlock(Block); + if (ResolvedAny) + EHStack.popNullFixups(); +} + +/// Activate a cleanup that was created in an inactivated state. +void CodeGenFunction::ActivateCleanup(EHScopeStack::stable_iterator C) { + assert(C != EHStack.stable_end() && "activating bottom of stack?"); + EHCleanupScope &Scope = cast(*EHStack.find(C)); + assert(!Scope.isActive() && "double activation"); + + // Calculate whether the cleanup was used: + bool Used = false; + + // - as a normal cleanup + if (Scope.isNormalCleanup()) { + bool NormalUsed = false; + if (Scope.getNormalBlock()) { + NormalUsed = true; + } else { + // Check whether any enclosed cleanups were needed. + for (EHScopeStack::stable_iterator + I = EHStack.getInnermostNormalCleanup(); I != C; ) { + assert(C.strictlyEncloses(I)); + EHCleanupScope &S = cast(*EHStack.find(I)); + if (S.getNormalBlock()) { + NormalUsed = true; + break; } - ThreadFixupThroughCleanup(*this, Fixup, Block, Block); + I = S.getEnclosingNormalCleanup(); } } + + if (NormalUsed) + Used = true; + else + Scope.setActivatedBeforeNormalUse(true); + } + + // - as an EH cleanup + if (Scope.isEHCleanup()) { + bool EHUsed = false; + if (Scope.getEHBlock()) { + EHUsed = true; + } else { + // Check whether any enclosed cleanups were needed. + for (EHScopeStack::stable_iterator + I = EHStack.getInnermostEHCleanup(); I != C; ) { + assert(C.strictlyEncloses(I)); + EHCleanupScope &S = cast(*EHStack.find(I)); + if (S.getEHBlock()) { + EHUsed = true; + break; + } + I = S.getEnclosingEHCleanup(); + } + } + + if (EHUsed) + Used = true; + else + Scope.setActivatedBeforeEHUse(true); } - Builder.ClearInsertionPoint(); + llvm::AllocaInst *Var = EHCleanupScope::activeSentinel(); + if (Used) { + Var = CreateTempAlloca(Builder.getInt1Ty()); + InitTempAlloca(Var, Builder.getFalse()); + } + Scope.setActiveVar(Var); +} + +llvm::Value *CodeGenFunction::getNormalCleanupDestSlot() { + if (!NormalCleanupDest) + NormalCleanupDest = + CreateTempAlloca(Builder.getInt32Ty(), "cleanup.dest.slot"); + return NormalCleanupDest; +} + +llvm::Value *CodeGenFunction::getEHCleanupDestSlot() { + if (!EHCleanupDest) + EHCleanupDest = + CreateTempAlloca(Builder.getInt32Ty(), "eh.cleanup.dest.slot"); + return EHCleanupDest; +} + +void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E, + llvm::ConstantInt *Init) { + assert (Init && "Invalid DeclRefExpr initializer!"); + if (CGDebugInfo *Dbg = getDebugInfo()) + Dbg->EmitGlobalVariable(E->getDecl(), Init, Builder); } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 5ee3db0..4f04205 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -41,6 +41,7 @@ namespace llvm { } namespace clang { + class APValue; class ASTContext; class CXXDestructorDecl; class CXXTryStmt; @@ -69,6 +70,7 @@ namespace CodeGen { class CGFunctionInfo; class CGRecordLayout; class CGBlockInfo; + class CGCXXABI; /// A branch fixup. These are required when emitting a goto to a /// label which hasn't been emitted yet. The goto is optimistically @@ -77,25 +79,34 @@ namespace CodeGen { /// the innermost cleanup. When a (normal) cleanup is popped, any /// unresolved fixups in that scope are threaded through the cleanup. struct BranchFixup { - /// The origin of the branch. Any switch-index stores required by - /// cleanup threading are added before this instruction. - llvm::Instruction *Origin; + /// The block containing the terminator which needs to be modified + /// into a switch if this fixup is resolved into the current scope. + /// If null, LatestBranch points directly to the destination. + llvm::BasicBlock *OptimisticBranchBlock; - /// The destination of the branch. + /// The ultimate destination of the branch. /// /// This can be set to null to indicate that this fixup was /// successfully resolved. llvm::BasicBlock *Destination; - /// The last branch of the fixup. It is an invariant that - /// LatestBranch->getSuccessor(LatestBranchIndex) == Destination. - /// - /// The branch is always either a BranchInst or a SwitchInst. - llvm::TerminatorInst *LatestBranch; - unsigned LatestBranchIndex; + /// The destination index value. + unsigned DestinationIndex; + + /// The initial branch of the fixup. + llvm::BranchInst *InitialBranch; }; -enum CleanupKind { NormalAndEHCleanup, EHCleanup, NormalCleanup }; +enum CleanupKind { + EHCleanup = 0x1, + NormalCleanup = 0x2, + NormalAndEHCleanup = EHCleanup | NormalCleanup, + + InactiveCleanup = 0x4, + InactiveEHCleanup = EHCleanup | InactiveCleanup, + InactiveNormalCleanup = NormalCleanup | InactiveCleanup, + InactiveNormalAndEHCleanup = NormalAndEHCleanup | InactiveCleanup +}; /// A stack of scopes which respond to exceptions, including cleanups /// and catch blocks. @@ -117,6 +128,17 @@ public: bool isValid() const { return Size >= 0; } + /// Returns true if this scope encloses I. + /// Returns false if I is invalid. + /// This scope must be valid. + bool encloses(stable_iterator I) const { return Size <= I.Size; } + + /// Returns true if this scope strictly encloses I: that is, + /// if it encloses I and is not I. + /// Returns false is I is invalid. + /// This scope must be valid. + bool strictlyEncloses(stable_iterator I) const { return Size < I.Size; } + friend bool operator==(stable_iterator A, stable_iterator B) { return A.Size == B.Size; } @@ -125,13 +147,14 @@ public: } }; - /// A lazy cleanup. Subclasses must be POD-like: cleanups will - /// not be destructed, and they will be allocated on the cleanup - /// stack and freely copied and moved around. + /// Information for lazily generating a cleanup. Subclasses must be + /// POD-like: cleanups will not be destructed, and they will be + /// allocated on the cleanup stack and freely copied and moved + /// around. /// - /// LazyCleanup implementations should generally be declared in an + /// Cleanup implementations should generally be declared in an /// anonymous namespace. - class LazyCleanup { + class Cleanup { public: // Anchor the construction vtable. We use the destructor because // gcc gives an obnoxious warning if there are virtual methods @@ -140,7 +163,7 @@ public: // doesn't seem to be any other way around this warning. // // This destructor will never be called. - virtual ~LazyCleanup(); + virtual ~Cleanup(); /// Emit the cleanup. For normal cleanups, this is run in the /// same EH context as when the cleanup was pushed, i.e. the @@ -177,6 +200,11 @@ private: /// The number of catches on the stack. unsigned CatchDepth; + /// The current EH destination index. Reset to FirstCatchIndex + /// whenever the last EH cleanup is popped. + unsigned NextEHDestIndex; + enum { FirstEHDestIndex = 1 }; + /// The current set of branch fixups. A branch fixup is a jump to /// an as-yet unemitted label, i.e. a label for which we don't yet /// know the EH stack depth. Whenever we pop a cleanup, we have @@ -198,64 +226,64 @@ private: char *allocate(size_t Size); - void popNullFixups(); - - void *pushLazyCleanup(CleanupKind K, size_t DataSize); + void *pushCleanup(CleanupKind K, size_t DataSize); public: EHScopeStack() : StartOfBuffer(0), EndOfBuffer(0), StartOfData(0), InnermostNormalCleanup(stable_end()), InnermostEHCleanup(stable_end()), - CatchDepth(0) {} + CatchDepth(0), NextEHDestIndex(FirstEHDestIndex) {} ~EHScopeStack() { delete[] StartOfBuffer; } // Variadic templates would make this not terrible. /// Push a lazily-created cleanup on the stack. template - void pushLazyCleanup(CleanupKind Kind) { - void *Buffer = pushLazyCleanup(Kind, sizeof(T)); - LazyCleanup *Obj = new(Buffer) T(); + void pushCleanup(CleanupKind Kind) { + void *Buffer = pushCleanup(Kind, sizeof(T)); + Cleanup *Obj = new(Buffer) T(); (void) Obj; } /// Push a lazily-created cleanup on the stack. template - void pushLazyCleanup(CleanupKind Kind, A0 a0) { - void *Buffer = pushLazyCleanup(Kind, sizeof(T)); - LazyCleanup *Obj = new(Buffer) T(a0); + void pushCleanup(CleanupKind Kind, A0 a0) { + void *Buffer = pushCleanup(Kind, sizeof(T)); + Cleanup *Obj = new(Buffer) T(a0); (void) Obj; } /// Push a lazily-created cleanup on the stack. template - void pushLazyCleanup(CleanupKind Kind, A0 a0, A1 a1) { - void *Buffer = pushLazyCleanup(Kind, sizeof(T)); - LazyCleanup *Obj = new(Buffer) T(a0, a1); + void pushCleanup(CleanupKind Kind, A0 a0, A1 a1) { + void *Buffer = pushCleanup(Kind, sizeof(T)); + Cleanup *Obj = new(Buffer) T(a0, a1); (void) Obj; } /// Push a lazily-created cleanup on the stack. template - void pushLazyCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2) { - void *Buffer = pushLazyCleanup(Kind, sizeof(T)); - LazyCleanup *Obj = new(Buffer) T(a0, a1, a2); + void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2) { + void *Buffer = pushCleanup(Kind, sizeof(T)); + Cleanup *Obj = new(Buffer) T(a0, a1, a2); (void) Obj; } /// Push a lazily-created cleanup on the stack. template - void pushLazyCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) { - void *Buffer = pushLazyCleanup(Kind, sizeof(T)); - LazyCleanup *Obj = new(Buffer) T(a0, a1, a2, a3); + void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) { + void *Buffer = pushCleanup(Kind, sizeof(T)); + Cleanup *Obj = new(Buffer) T(a0, a1, a2, a3); (void) Obj; } - /// Push a cleanup on the stack. - void pushCleanup(llvm::BasicBlock *NormalEntry, - llvm::BasicBlock *NormalExit, - llvm::BasicBlock *EHEntry, - llvm::BasicBlock *EHExit); + /// Push a lazily-created cleanup on the stack. + template + void pushCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) { + void *Buffer = pushCleanup(Kind, sizeof(T)); + Cleanup *Obj = new(Buffer) T(a0, a1, a2, a3, a4); + (void) Obj; + } /// Pops a cleanup scope off the stack. This should only be called /// by CodeGenFunction::PopCleanupBlock. @@ -298,6 +326,7 @@ public: stable_iterator getInnermostNormalCleanup() const { return InnermostNormalCleanup; } + stable_iterator getInnermostActiveNormalCleanup() const; // CGException.h /// Determines whether there are any EH cleanups on the stack. bool hasEHCleanups() const { @@ -309,6 +338,7 @@ public: stable_iterator getInnermostEHCleanup() const { return InnermostEHCleanup; } + stable_iterator getInnermostActiveEHCleanup() const; // CGException.h /// An unstable reference to a scope-stack depth. Invalidated by /// pushes but not pops. @@ -359,8 +389,17 @@ public: return BranchFixups[I]; } - /// Mark any branch fixups leading to the given block as resolved. - void resolveBranchFixups(llvm::BasicBlock *Dest); + /// Pops lazily-removed fixups from the end of the list. This + /// should only be called by procedures which have just popped a + /// cleanup or resolved one or more fixups. + void popNullFixups(); + + /// Clears the branch-fixups list. This should only be called by + /// CodeGenFunction::ResolveAllBranchFixups. + void clearFixups() { BranchFixups.clear(); } + + /// Gets the next EH destination index. + unsigned getNextEHDestIndex() { return NextEHDestIndex++; } }; /// CodeGenFunction - This class organizes the per-function state that is used @@ -368,17 +407,47 @@ public: class CodeGenFunction : public BlockFunction { CodeGenFunction(const CodeGenFunction&); // DO NOT IMPLEMENT void operator=(const CodeGenFunction&); // DO NOT IMPLEMENT + + friend class CGCXXABI; public: - /// A jump destination is a pair of a basic block and a cleanup - /// depth. They are used to implement direct jumps across cleanup - /// scopes, e.g. goto, break, continue, and return. + /// A jump destination is an abstract label, branching to which may + /// require a jump out through normal cleanups. struct JumpDest { - JumpDest() : Block(0), ScopeDepth() {} - JumpDest(llvm::BasicBlock *Block, EHScopeStack::stable_iterator Depth) - : Block(Block), ScopeDepth(Depth) {} + JumpDest() : Block(0), ScopeDepth(), Index(0) {} + JumpDest(llvm::BasicBlock *Block, + EHScopeStack::stable_iterator Depth, + unsigned Index) + : Block(Block), ScopeDepth(Depth), Index(Index) {} + + bool isValid() const { return Block != 0; } + llvm::BasicBlock *getBlock() const { return Block; } + EHScopeStack::stable_iterator getScopeDepth() const { return ScopeDepth; } + unsigned getDestIndex() const { return Index; } + private: + llvm::BasicBlock *Block; + EHScopeStack::stable_iterator ScopeDepth; + unsigned Index; + }; + + /// An unwind destination is an abstract label, branching to which + /// may require a jump out through EH cleanups. + struct UnwindDest { + UnwindDest() : Block(0), ScopeDepth(), Index(0) {} + UnwindDest(llvm::BasicBlock *Block, + EHScopeStack::stable_iterator Depth, + unsigned Index) + : Block(Block), ScopeDepth(Depth), Index(Index) {} + + bool isValid() const { return Block != 0; } + llvm::BasicBlock *getBlock() const { return Block; } + EHScopeStack::stable_iterator getScopeDepth() const { return ScopeDepth; } + unsigned getDestIndex() const { return Index; } + + private: llvm::BasicBlock *Block; EHScopeStack::stable_iterator ScopeDepth; + unsigned Index; }; CodeGenModule &CGM; // Per-module state. @@ -406,6 +475,9 @@ public: /// iff the function has no return value. llvm::Value *ReturnValue; + /// RethrowBlock - Unified rethrow block. + UnwindDest RethrowBlock; + /// AllocaInsertPoint - This is an instruction in the entry block before which /// we prefer to insert allocas. llvm::AssertingVH AllocaInsertPt; @@ -423,6 +495,12 @@ public: EHScopeStack EHStack; + /// i32s containing the indexes of the cleanup destinations. + llvm::AllocaInst *NormalCleanupDest; + llvm::AllocaInst *EHCleanupDest; + + unsigned NextCleanupDestIndex; + /// The exception slot. All landing pads write the current /// exception pointer into this alloca. llvm::Value *ExceptionSlot; @@ -454,30 +532,17 @@ public: /// non-trivial destructor. void PushDestructorCleanup(QualType T, llvm::Value *Addr); + /// PushDestructorCleanup - Push a cleanup to call the + /// complete-object variant of the given destructor on the object at + /// the given address. + void PushDestructorCleanup(const CXXDestructorDecl *Dtor, + llvm::Value *Addr); + /// PopCleanupBlock - Will pop the cleanup entry on the stack and /// process all branch fixups. - void PopCleanupBlock(); - - /// CleanupBlock - RAII object that will create a cleanup block and - /// set the insert point to that block. When destructed, it sets the - /// insert point to the previous block and pushes a new cleanup - /// entry on the stack. - class CleanupBlock { - CodeGenFunction &CGF; - CGBuilderTy::InsertPoint SavedIP; - llvm::BasicBlock *NormalCleanupEntryBB; - llvm::BasicBlock *NormalCleanupExitBB; - llvm::BasicBlock *EHCleanupEntryBB; - - public: - CleanupBlock(CodeGenFunction &CGF, CleanupKind Kind); + void PopCleanupBlock(bool FallThroughIsBranchThrough = false); - /// If we're currently writing a normal cleanup, tie that off and - /// start writing an EH cleanup. - void beginEHCleanup(); - - ~CleanupBlock(); - }; + void ActivateCleanup(EHScopeStack::stable_iterator Cleanup); /// \brief Enters a new scope for capturing cleanups, all of which /// will be executed once the scope is exited. @@ -528,18 +593,23 @@ public: /// the cleanup blocks that have been added. void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize); + void ResolveAllBranchFixups(llvm::SwitchInst *Switch); + void ResolveBranchFixups(llvm::BasicBlock *Target); + /// The given basic block lies in the current EH scope, but may be a /// target of a potentially scope-crossing jump; get a stable handle /// to which we can perform this jump later. - JumpDest getJumpDestInCurrentScope(llvm::BasicBlock *Target) const { - return JumpDest(Target, EHStack.stable_begin()); + JumpDest getJumpDestInCurrentScope(llvm::BasicBlock *Target) { + return JumpDest(Target, + EHStack.getInnermostNormalCleanup(), + NextCleanupDestIndex++); } /// The given basic block lies in the current EH scope, but may be a /// target of a potentially scope-crossing jump; get a stable handle /// to which we can perform this jump later. JumpDest getJumpDestInCurrentScope(const char *Name = 0) { - return JumpDest(createBasicBlock(Name), EHStack.stable_begin()); + return getJumpDestInCurrentScope(createBasicBlock(Name)); } /// EmitBranchThroughCleanup - Emit a branch from the current insert @@ -550,7 +620,11 @@ public: /// EmitBranchThroughEHCleanup - Emit a branch from the current /// insert block through the EH cleanup handling code (if any) and /// then on to \arg Dest. - void EmitBranchThroughEHCleanup(JumpDest Dest); + void EmitBranchThroughEHCleanup(UnwindDest Dest); + + /// getRethrowDest - Returns the unified outermost-scope rethrow + /// destination. + UnwindDest getRethrowDest(); /// BeginConditionalBranch - Should be called before a conditional part of an /// expression is emitted. For example, before the RHS of the expression below @@ -608,10 +682,6 @@ private: /// statement range in current switch instruction. llvm::BasicBlock *CaseRangeBlock; - /// InvokeDest - This is the nearest exception target for calls - /// which can unwind, when exceptions are being used. - llvm::BasicBlock *InvokeDest; - // VLASizeMap - This keeps track of the associated size for each VLA type. // We track this by the size expression rather than the type itself because // in certain situations, like a const qualifier applied to an VLA typedef, @@ -661,6 +731,7 @@ private: public: CodeGenFunction(CodeGenModule &cgm); + CodeGenTypes &getTypes() const { return CGM.getTypes(); } ASTContext &getContext() const; CGDebugInfo *getDebugInfo() { return DebugInfo; } @@ -668,6 +739,9 @@ public: /// is assigned in every landing pad. llvm::Value *getExceptionSlot(); + llvm::Value *getNormalCleanupDestSlot(); + llvm::Value *getEHCleanupDestSlot(); + llvm::BasicBlock *getUnreachableBlock() { if (!UnreachableBlock) { UnreachableBlock = createBasicBlock("unreachable"); @@ -711,15 +785,16 @@ public: llvm::Value *BuildBlockLiteralTmp(const BlockExpr *); llvm::Constant *BuildDescriptorBlockDecl(const BlockExpr *, - bool BlockHasCopyDispose, - CharUnits Size, + const CGBlockInfo &Info, const llvm::StructType *, + llvm::Constant *BlockVarLayout, std::vector *); llvm::Function *GenerateBlockFunction(GlobalDecl GD, const BlockExpr *BExpr, CGBlockInfo &Info, const Decl *OuterFuncDecl, + llvm::Constant *& BlockVarLayout, llvm::DenseMap ldm); llvm::Value *LoadBlockStruct(); @@ -777,11 +852,11 @@ public: void InitializeVTablePointers(const CXXRecordDecl *ClassDecl); - /// EmitDtorEpilogue - Emit all code that comes at the end of class's - /// destructor. This is to call destructors on members and base classes in - /// reverse order of their construction. - void EmitDtorEpilogue(const CXXDestructorDecl *Dtor, - CXXDtorType Type); + /// EnterDtorCleanups - Enter the cleanups necessary to complete the + /// given phase of destruction for a destructor. The end result + /// should call destructors on members and base classes in reverse + /// order of their construction. + void EnterDtorCleanups(const CXXDestructorDecl *Dtor, CXXDtorType Type); /// ShouldInstrumentFunction - Return true if the current function should be /// instrumented with __cyg_profile_func_* calls @@ -898,10 +973,8 @@ public: // Helpers //===--------------------------------------------------------------------===// - Qualifiers MakeQualifiers(QualType T) { - Qualifiers Quals = getContext().getCanonicalType(T).getQualifiers(); - Quals.setObjCGCAttr(getContext().getObjCGCAttrKind(T)); - return Quals; + LValue MakeAddrLValue(llvm::Value *V, QualType T, unsigned Alignment = 0) { + return LValue::MakeAddr(V, T, Alignment, getContext()); } /// CreateTempAlloca - This creates a alloca and inserts it into the entry @@ -965,10 +1038,16 @@ public: void StartBlock(const char *N); /// GetAddrOfStaticLocalVar - Return the address of a static local variable. - llvm::Constant *GetAddrOfStaticLocalVar(const VarDecl *BVD); + llvm::Constant *GetAddrOfStaticLocalVar(const VarDecl *BVD) { + return cast(GetAddrOfLocalVar(BVD)); + } /// GetAddrOfLocalVar - Return the address of a local variable. - llvm::Value *GetAddrOfLocalVar(const VarDecl *VD); + llvm::Value *GetAddrOfLocalVar(const VarDecl *VD) { + llvm::Value *Res = LocalDeclMap[VD]; + assert(Res && "Invalid argument to GetAddrOfLocalVar(), no decl!"); + return Res; + } /// getAccessedFieldNo - Given an encoded value and a result number, return /// the input field number being accessed. @@ -1025,12 +1104,14 @@ public: /// load of 'this' and returns address of the base class. llvm::Value *GetAddressOfBaseClass(llvm::Value *Value, const CXXRecordDecl *Derived, - const CXXBaseSpecifierArray &BasePath, + CastExpr::path_const_iterator PathBegin, + CastExpr::path_const_iterator PathEnd, bool NullCheckValue); llvm::Value *GetAddressOfDerivedClass(llvm::Value *Value, const CXXRecordDecl *Derived, - const CXXBaseSpecifierArray &BasePath, + CastExpr::path_const_iterator PathBegin, + CastExpr::path_const_iterator PathEnd, bool NullCheckValue); llvm::Value *GetVirtualBaseClassOffset(llvm::Value *This, @@ -1049,13 +1130,15 @@ public: const ConstantArrayType *ArrayTy, llvm::Value *ArrayPtr, CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd); + CallExpr::const_arg_iterator ArgEnd, + bool ZeroInitialization = false); void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, llvm::Value *NumElements, llvm::Value *ArrayPtr, CallExpr::const_arg_iterator ArgBeg, - CallExpr::const_arg_iterator ArgEnd); + CallExpr::const_arg_iterator ArgEnd, + bool ZeroInitialization = false); void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D, const ArrayType *Array, @@ -1224,13 +1307,13 @@ public: /// care to appropriately convert from the memory representation to /// the LLVM value representation. llvm::Value *EmitLoadOfScalar(llvm::Value *Addr, bool Volatile, - QualType Ty); + unsigned Alignment, QualType Ty); /// EmitStoreOfScalar - Store a scalar value to an address, taking /// care to appropriately convert from the memory representation to /// the LLVM value representation. void EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr, - bool Volatile, QualType Ty); + bool Volatile, unsigned Alignment, QualType Ty); /// EmitLoadOfLValue - Given an expression that represents a value lvalue, /// this method emits the address of the lvalue, then loads the result as an @@ -1270,7 +1353,6 @@ public: LValue EmitDeclRefLValue(const DeclRefExpr *E); LValue EmitStringLiteralLValue(const StringLiteral *E); LValue EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E); - LValue EmitPredefinedFunctionName(unsigned Type); LValue EmitPredefinedLValue(const PredefinedExpr *E); LValue EmitUnaryOpLValue(const UnaryOperator *E); LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E); @@ -1319,7 +1401,7 @@ public: LValue EmitStmtExprLValue(const StmtExpr *E); LValue EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E); LValue EmitObjCSelectorLValue(const ObjCSelectorExpr *E); - + void EmitDeclRefExprDbgValue(const DeclRefExpr *E, llvm::ConstantInt *Init); //===--------------------------------------------------------------------===// // Scalar Expression Emission //===--------------------------------------------------------------------===// @@ -1386,7 +1468,8 @@ public: llvm::SmallVectorImpl &O, const char *name, bool splat = false, unsigned shift = 0, bool rightshift = false); - llvm::Value *EmitNeonSplat(llvm::Value *V, llvm::Constant *Idx); + llvm::Value *EmitNeonSplat(llvm::Value *V, llvm::Constant *Idx, + bool widen = false); llvm::Value *EmitNeonShiftVector(llvm::Value *V, const llvm::Type *Ty, bool negateForRightShift); @@ -1542,7 +1625,7 @@ public: /// getTrapBB - Create a basic block that will call the trap intrinsic. We'll /// generate a branch around the created basic block as necessary. - llvm::BasicBlock* getTrapBB(); + llvm::BasicBlock *getTrapBB(); /// EmitCallArg - Emit a single call argument. RValue EmitCallArg(const Expr *E, QualType ArgType); @@ -1575,6 +1658,11 @@ private: const TargetInfo::ConstraintInfo &Info, const Expr *InputExpr, std::string &ConstraintStr); + llvm::Value* EmitAsmInputLValue(const AsmStmt &S, + const TargetInfo::ConstraintInfo &Info, + LValue InputValue, QualType InputType, + std::string &ConstraintStr); + /// EmitCallArgs - Emit call arguments for a function. /// The CallArgTypeInfo parameter is used for iterating over the known /// argument types of the function being called. @@ -1622,7 +1710,36 @@ private: void EmitDeclMetadata(); }; - +/// CGBlockInfo - Information to generate a block literal. +class CGBlockInfo { +public: + /// Name - The name of the block, kindof. + const char *Name; + + /// DeclRefs - Variables from parent scopes that have been + /// imported into this block. + llvm::SmallVector DeclRefs; + + /// InnerBlocks - This block and the blocks it encloses. + llvm::SmallPtrSet InnerBlocks; + + /// CXXThisRef - Non-null if 'this' was required somewhere, in + /// which case this is that expression. + const CXXThisExpr *CXXThisRef; + + /// NeedsObjCSelf - True if something in this block has an implicit + /// reference to 'self'. + bool NeedsObjCSelf; + + /// These are initialized by GenerateBlockFunction. + bool BlockHasCopyDispose; + CharUnits BlockSize; + CharUnits BlockAlign; + llvm::SmallVector BlockLayout; + + CGBlockInfo(const char *Name); +}; + } // end namespace CodeGen } // end namespace clang diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index bf606a6..d125b37 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -15,6 +15,7 @@ #include "CGDebugInfo.h" #include "CodeGenFunction.h" #include "CGCall.h" +#include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "Mangle.h" #include "TargetInfo.h" @@ -41,6 +42,17 @@ using namespace clang; using namespace CodeGen; +static CGCXXABI &createCXXABI(CodeGenModule &CGM) { + switch (CGM.getContext().Target.getCXXABI()) { + case CXXABI_ARM: return *CreateARMCXXABI(CGM); + case CXXABI_Itanium: return *CreateItaniumCXXABI(CGM); + case CXXABI_Microsoft: return *CreateMicrosoftCXXABI(CGM); + } + + llvm_unreachable("invalid C++ ABI kind"); + return *CreateItaniumCXXABI(CGM); +} + CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, llvm::Module &M, const llvm::TargetData &TD, @@ -48,11 +60,15 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, : BlockModule(C, M, TD, Types, *this), Context(C), Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M), TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags), - Types(C, M, TD, getTargetCodeGenInfo().getABIInfo()), - VTables(*this), Runtime(0), ABI(0), - CFConstantStringClassRef(0), - NSConstantStringClassRef(0), - VMContext(M.getContext()) { + ABI(createCXXABI(*this)), + Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI), + VTables(*this), Runtime(0), + CFConstantStringClassRef(0), NSConstantStringClassRef(0), + VMContext(M.getContext()), + NSConcreteGlobalBlockDecl(0), NSConcreteStackBlockDecl(0), + NSConcreteGlobalBlock(0), NSConcreteStackBlock(0), + BlockObjectAssignDecl(0), BlockObjectDisposeDecl(0), + BlockObjectAssign(0), BlockObjectDispose(0){ if (!Features.ObjC1) Runtime = 0; @@ -63,17 +79,13 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, else Runtime = CreateMacObjCRuntime(*this); - if (!Features.CPlusPlus) - ABI = 0; - else createCXXABI(); - // If debug info generation is enabled, create the CGDebugInfo object. DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(*this) : 0; } CodeGenModule::~CodeGenModule() { delete Runtime; - delete ABI; + delete &ABI; delete DebugInfo; } @@ -86,13 +98,6 @@ void CodeGenModule::createObjCRuntime() { Runtime = CreateMacObjCRuntime(*this); } -void CodeGenModule::createCXXABI() { - if (Context.Target.getCXXABI() == "microsoft") - ABI = CreateMicrosoftCXXABI(*this); - else - ABI = CreateItaniumCXXABI(*this); -} - void CodeGenModule::Release() { EmitDeferred(); EmitCXXGlobalInitFunc(); @@ -141,17 +146,17 @@ void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type, LangOptions::VisibilityMode CodeGenModule::getDeclVisibilityMode(const Decl *D) const { if (const VarDecl *VD = dyn_cast(D)) - if (VD->getStorageClass() == VarDecl::PrivateExtern) + if (VD->getStorageClass() == SC_PrivateExtern) return LangOptions::Hidden; if (const VisibilityAttr *attr = D->getAttr()) { switch (attr->getVisibility()) { default: assert(0 && "Unknown visibility!"); - case VisibilityAttr::DefaultVisibility: + case VisibilityAttr::Default: return LangOptions::Default; - case VisibilityAttr::HiddenVisibility: + case VisibilityAttr::Hidden: return LangOptions::Hidden; - case VisibilityAttr::ProtectedVisibility: + case VisibilityAttr::Protected: return LangOptions::Protected; } } @@ -187,9 +192,11 @@ CodeGenModule::getDeclVisibilityMode(const Decl *D) const { return LangOptions::Hidden; } - // This decl should have the same visibility as its parent. + // If this decl is contained in a class, it should have the same visibility + // as the parent class. if (const DeclContext *DC = D->getDeclContext()) - return getDeclVisibilityMode(cast(DC)); + if (DC->isRecord()) + return getDeclVisibilityMode(cast(DC)); return getLangOptions().getVisibilityMode(); } @@ -213,6 +220,67 @@ void CodeGenModule::setGlobalVisibility(llvm::GlobalValue *GV, } } +/// Set the symbol visibility of type information (vtable and RTTI) +/// associated with the given type. +void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV, + const CXXRecordDecl *RD, + bool IsForRTTI) const { + setGlobalVisibility(GV, RD); + + if (!CodeGenOpts.HiddenWeakVTables) + return; + + // We want to drop the visibility to hidden for weak type symbols. + // This isn't possible if there might be unresolved references + // elsewhere that rely on this symbol being visible. + + // This should be kept roughly in sync with setThunkVisibility + // in CGVTables.cpp. + + // Preconditions. + if (GV->getLinkage() != llvm::GlobalVariable::WeakODRLinkage || + GV->getVisibility() != llvm::GlobalVariable::DefaultVisibility) + return; + + // Don't override an explicit visibility attribute. + if (RD->hasAttr()) + return; + + switch (RD->getTemplateSpecializationKind()) { + // We have to disable the optimization if this is an EI definition + // because there might be EI declarations in other shared objects. + case TSK_ExplicitInstantiationDefinition: + case TSK_ExplicitInstantiationDeclaration: + return; + + // Every use of a non-template class's type information has to emit it. + case TSK_Undeclared: + break; + + // In theory, implicit instantiations can ignore the possibility of + // an explicit instantiation declaration because there necessarily + // must be an EI definition somewhere with default visibility. In + // practice, it's possible to have an explicit instantiation for + // an arbitrary template class, and linkers aren't necessarily able + // to deal with mixed-visibility symbols. + case TSK_ExplicitSpecialization: + case TSK_ImplicitInstantiation: + if (!CodeGenOpts.HiddenWeakTemplateVTables) + return; + break; + } + + // If there's a key function, there may be translation units + // that don't have the key function's definition. But ignore + // this if we're emitting RTTI under -fno-rtti. + if (!IsForRTTI || Features.RTTI) + if (Context.getKeyFunction(RD)) + return; + + // Otherwise, drop the visibility to hidden. + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); +} + llvm::StringRef CodeGenModule::getMangledName(GlobalDecl GD) { const NamedDecl *ND = cast(GD.getDecl()); @@ -220,7 +288,7 @@ llvm::StringRef CodeGenModule::getMangledName(GlobalDecl GD) { if (!Str.empty()) return Str; - if (!getMangleContext().shouldMangleDeclName(ND)) { + if (!getCXXABI().getMangleContext().shouldMangleDeclName(ND)) { IdentifierInfo *II = ND->getIdentifier(); assert(II && "Attempt to mangle unnamed decl."); @@ -230,13 +298,13 @@ llvm::StringRef CodeGenModule::getMangledName(GlobalDecl GD) { llvm::SmallString<256> Buffer; if (const CXXConstructorDecl *D = dyn_cast(ND)) - getMangleContext().mangleCXXCtor(D, GD.getCtorType(), Buffer); + getCXXABI().getMangleContext().mangleCXXCtor(D, GD.getCtorType(), Buffer); else if (const CXXDestructorDecl *D = dyn_cast(ND)) - getMangleContext().mangleCXXDtor(D, GD.getDtorType(), Buffer); + getCXXABI().getMangleContext().mangleCXXDtor(D, GD.getDtorType(), Buffer); else if (const BlockDecl *BD = dyn_cast(ND)) - getMangleContext().mangleBlock(GD, BD, Buffer); + getCXXABI().getMangleContext().mangleBlock(GD, BD, Buffer); else - getMangleContext().mangleName(ND, Buffer); + getCXXABI().getMangleContext().mangleName(ND, Buffer); // Allocate space for the mangled name. size_t Length = Buffer.size(); @@ -250,7 +318,7 @@ llvm::StringRef CodeGenModule::getMangledName(GlobalDecl GD) { void CodeGenModule::getMangledName(GlobalDecl GD, MangleBuffer &Buffer, const BlockDecl *BD) { - getMangleContext().mangleBlock(GD, BD, Buffer.getBuffer()); + getCXXABI().getMangleContext().mangleBlock(GD, BD, Buffer.getBuffer()); } llvm::GlobalValue *CodeGenModule::GetGlobalValue(llvm::StringRef Name) { @@ -319,68 +387,9 @@ void CodeGenModule::EmitAnnotations() { gv->setSection("llvm.metadata"); } -static CodeGenModule::GVALinkage -GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, - const LangOptions &Features) { - CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal; - - Linkage L = FD->getLinkage(); - if (L == ExternalLinkage && Context.getLangOptions().CPlusPlus && - FD->getType()->getLinkage() == UniqueExternalLinkage) - L = UniqueExternalLinkage; - - switch (L) { - case NoLinkage: - case InternalLinkage: - case UniqueExternalLinkage: - return CodeGenModule::GVA_Internal; - - case ExternalLinkage: - switch (FD->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - External = CodeGenModule::GVA_StrongExternal; - break; - - case TSK_ExplicitInstantiationDefinition: - return CodeGenModule::GVA_ExplicitTemplateInstantiation; - - case TSK_ExplicitInstantiationDeclaration: - case TSK_ImplicitInstantiation: - External = CodeGenModule::GVA_TemplateInstantiation; - break; - } - } - - if (!FD->isInlined()) - return External; - - if (!Features.CPlusPlus || FD->hasAttr()) { - // GNU or C99 inline semantics. Determine whether this symbol should be - // externally visible. - if (FD->isInlineDefinitionExternallyVisible()) - return External; - - // C99 inline semantics, where the symbol is not externally visible. - return CodeGenModule::GVA_C99Inline; - } - - // C++0x [temp.explicit]p9: - // [ Note: The intent is that an inline function that is the subject of - // an explicit instantiation declaration will still be implicitly - // instantiated when used so that the body can be considered for - // inlining, but that no out-of-line copy of the inline function would be - // generated in the translation unit. -- end note ] - if (FD->getTemplateSpecializationKind() - == TSK_ExplicitInstantiationDeclaration) - return CodeGenModule::GVA_C99Inline; - - return CodeGenModule::GVA_CXXInline; -} - llvm::GlobalValue::LinkageTypes CodeGenModule::getFunctionLinkage(const FunctionDecl *D) { - GVALinkage Linkage = GetLinkageForFunction(getContext(), D, Features); + GVALinkage Linkage = getContext().GetGVALinkageForFunction(D); if (Linkage == GVA_Internal) return llvm::Function::InternalLinkage; @@ -454,12 +463,10 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, else if (Features.getStackProtectorMode() == LangOptions::SSPReq) F->addFnAttr(llvm::Attribute::StackProtectReq); - if (const AlignedAttr *AA = D->getAttr()) { - unsigned width = Context.Target.getCharWidth(); - F->setAlignment(AA->getAlignment() / width); - while ((AA = AA->getNext())) - F->setAlignment(std::max(F->getAlignment(), AA->getAlignment() / width)); - } + unsigned alignment = D->getMaxAlignment() / Context.getCharWidth(); + if (alignment) + F->setAlignment(alignment); + // C++ ABI requires 2-byte alignment for member functions. if (F->getAlignment() < 2 && isa(D)) F->setAlignment(2); @@ -638,102 +645,12 @@ llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV, return llvm::ConstantStruct::get(VMContext, Fields, 4, false); } -static CodeGenModule::GVALinkage -GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) { - // If this is a static data member, compute the kind of template - // specialization. Otherwise, this variable is not part of a - // template. - TemplateSpecializationKind TSK = TSK_Undeclared; - if (VD->isStaticDataMember()) - TSK = VD->getTemplateSpecializationKind(); - - Linkage L = VD->getLinkage(); - if (L == ExternalLinkage && Context.getLangOptions().CPlusPlus && - VD->getType()->getLinkage() == UniqueExternalLinkage) - L = UniqueExternalLinkage; - - switch (L) { - case NoLinkage: - case InternalLinkage: - case UniqueExternalLinkage: - return CodeGenModule::GVA_Internal; - - case ExternalLinkage: - switch (TSK) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - return CodeGenModule::GVA_StrongExternal; - - case TSK_ExplicitInstantiationDeclaration: - llvm_unreachable("Variable should not be instantiated"); - // Fall through to treat this like any other instantiation. - - case TSK_ExplicitInstantiationDefinition: - return CodeGenModule::GVA_ExplicitTemplateInstantiation; - - case TSK_ImplicitInstantiation: - return CodeGenModule::GVA_TemplateInstantiation; - } - } - - return CodeGenModule::GVA_StrongExternal; -} - bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { - // Never defer when EmitAllDecls is specified or the decl has - // attribute used. - if (Features.EmitAllDecls || Global->hasAttr()) - return false; - - if (const FunctionDecl *FD = dyn_cast(Global)) { - // Constructors and destructors should never be deferred. - if (FD->hasAttr() || - FD->hasAttr()) - return false; - - // The key function for a class must never be deferred. - if (const CXXMethodDecl *MD = dyn_cast(Global)) { - const CXXRecordDecl *RD = MD->getParent(); - if (MD->isOutOfLine() && RD->isDynamicClass()) { - const CXXMethodDecl *KeyFunction = getContext().getKeyFunction(RD); - if (KeyFunction && - KeyFunction->getCanonicalDecl() == MD->getCanonicalDecl()) - return false; - } - } - - GVALinkage Linkage = GetLinkageForFunction(getContext(), FD, Features); - - // static, static inline, always_inline, and extern inline functions can - // always be deferred. Normal inline functions can be deferred in C99/C++. - // Implicit template instantiations can also be deferred in C++. - if (Linkage == GVA_Internal || Linkage == GVA_C99Inline || - Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) - return true; + // Never defer when EmitAllDecls is specified. + if (Features.EmitAllDecls) return false; - } - const VarDecl *VD = cast(Global); - assert(VD->isFileVarDecl() && "Invalid decl"); - - // We never want to defer structs that have non-trivial constructors or - // destructors. - - // FIXME: Handle references. - if (const RecordType *RT = VD->getType()->getAs()) { - if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) { - if (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor()) - return false; - } - } - - GVALinkage L = GetLinkageForVariable(getContext(), VD); - if (L == GVA_Internal || L == GVA_TemplateInstantiation) { - if (!(VD->getInit() && VD->getInit()->HasSideEffects(Context))) - return true; - } - - return false; + return !getContext().DeclMustBeEmitted(Global); } llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) { @@ -774,6 +691,15 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { // Ignore declarations, they will be emitted on their first use. if (const FunctionDecl *FD = dyn_cast(Global)) { + if (FD->getIdentifier()) { + llvm::StringRef Name = FD->getName(); + if (Name == "_Block_object_assign") { + BlockObjectAssignDecl = FD; + } else if (Name == "_Block_object_dispose") { + BlockObjectDisposeDecl = FD; + } + } + // Forward declarations are emitted lazily on first use. if (!FD->isThisDeclarationADefinition()) return; @@ -781,6 +707,16 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { const VarDecl *VD = cast(Global); assert(VD->isFileVarDecl() && "Cannot emit local var decl as global."); + if (VD->getIdentifier()) { + llvm::StringRef Name = VD->getName(); + if (Name == "_NSConcreteGlobalBlock") { + NSConcreteGlobalBlockDecl = VD; + } else if (Name == "_NSConcreteStackBlock") { + NSConcreteStackBlockDecl = VD; + } + } + + if (VD->isThisDeclarationADefinition() != VarDecl::Definition) return; } @@ -792,6 +728,14 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { EmitGlobalDefinition(GD); return; } + + // If we're deferring emission of a C++ variable with an + // initializer, remember the order in which it appeared in the file. + if (getLangOptions().CPlusPlus && isa(Global) && + cast(Global)->hasInit()) { + DelayedCXXInitPosition[Global] = CXXGlobalInits.size(); + CXXGlobalInits.push_back(0); + } // If the value has already been used, add it directly to the // DeferredDeclsToEmit list. @@ -816,7 +760,8 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { if (const FunctionDecl *Function = dyn_cast(D)) { // At -O0, don't generate IR for functions with available_externally // linkage. - if (CodeGenOpts.OptimizationLevel == 0 && + if (CodeGenOpts.OptimizationLevel == 0 && + !Function->hasAttr() && getFunctionLinkage(Function) == llvm::Function::AvailableExternallyLinkage) return; @@ -1021,7 +966,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName, GV->setConstant(DeclIsConstantGlobal(Context, D)); // FIXME: Merge with other attribute handling code. - if (D->getStorageClass() == VarDecl::PrivateExtern) + if (D->getStorageClass() == SC_PrivateExtern) GV->setVisibility(llvm::GlobalValue::HiddenVisibility); if (D->hasAttr() || @@ -1174,6 +1119,11 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { ErrorUnsupported(D, "static initializer"); Init = llvm::UndefValue::get(getTypes().ConvertType(T)); } + } else { + // We don't need an initializer, so remove the entry for the delayed + // initializer position (just in case this entry was delayed). + if (getLangOptions().CPlusPlus) + DelayedCXXInitPosition.erase(D); } } @@ -1235,7 +1185,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { GV->setAlignment(getContext().getDeclAlign(D).getQuantity()); // Set the llvm linkage type as appropriate. - GVALinkage Linkage = GetLinkageForVariable(getContext(), D); + GVALinkage Linkage = getContext().GetGVALinkageForVariable(D); if (Linkage == GVA_Internal) GV->setLinkage(llvm::Function::InternalLinkage); else if (D->hasAttr()) @@ -1254,7 +1204,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage); else if (!getLangOptions().CPlusPlus && !CodeGenOpts.NoCommon && !D->hasExternalStorage() && !D->getInit() && - !D->getAttr()) { + !D->getAttr() && !D->isThreadSpecified()) { + // Thread local vars aren't considered common linkage. GV->setLinkage(llvm::GlobalVariable::CommonLinkage); // common vars aren't constant even if declared const. GV->setConstant(false); @@ -1293,6 +1244,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, // TODO: Do invokes ever occur in C code? If so, we should handle them too. llvm::Value::use_iterator I = UI++; // Increment before the CI is erased. llvm::CallInst *CI = dyn_cast(*I); + if (!CI) continue; // FIXME: when we allow Invoke, just do CallSite CS(*I) llvm::CallSite CS(CI); if (!CI || !CS.isCallee(I)) continue; @@ -1343,7 +1295,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { const FunctionDecl *D = cast(GD.getDecl()); const llvm::FunctionType *Ty = getTypes().GetFunctionType(GD); - getMangleContext().mangleInitDiscriminator(); + getCXXABI().getMangleContext().mangleInitDiscriminator(); // Get or create the prototype for the function. llvm::Constant *Entry = GetAddrOfFunction(GD, Ty); @@ -1528,18 +1480,18 @@ GetConstantCFStringEntry(llvm::StringMap &Map, bool TargetIsLSB, bool &IsUTF16, unsigned &StringLength) { - unsigned NumBytes = Literal->getByteLength(); + llvm::StringRef String = Literal->getString(); + unsigned NumBytes = String.size(); // Check for simple case. if (!Literal->containsNonAsciiOrNull()) { StringLength = NumBytes; - return Map.GetOrCreateValue(llvm::StringRef(Literal->getStrData(), - StringLength)); + return Map.GetOrCreateValue(String); } // Otherwise, convert the UTF8 literals into a byte string. llvm::SmallVector ToBuf(NumBytes); - const UTF8 *FromPtr = (UTF8 *)Literal->getStrData(); + const UTF8 *FromPtr = (UTF8 *)String.data(); UTF16 *ToPtr = &ToBuf[0]; ConversionResult Result = ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes, @@ -1552,8 +1504,7 @@ GetConstantCFStringEntry(llvm::StringMap &Map, // this duplicate code. assert(Result == sourceIllegal && "UTF-8 to UTF-16 conversion failed"); StringLength = NumBytes; - return Map.GetOrCreateValue(llvm::StringRef(Literal->getStrData(), - StringLength)); + return Map.GetOrCreateValue(String); } // ConvertUTF8toUTF16 returns the length in ToPtr. @@ -1753,20 +1704,17 @@ CodeGenModule::GetAddrOfConstantNSString(const StringLiteral *Literal) { /// GetStringForStringLiteral - Return the appropriate bytes for a /// string literal, properly padded to match the literal type. std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) { - const char *StrData = E->getStrData(); - unsigned Len = E->getByteLength(); - const ConstantArrayType *CAT = getContext().getAsConstantArrayType(E->getType()); assert(CAT && "String isn't pointer or array!"); // Resize the string to the right size. - std::string Str(StrData, StrData+Len); uint64_t RealLen = CAT->getSize().getZExtValue(); if (E->isWide()) RealLen *= getContext().Target.getWCharWidth()/8; + std::string Str = E->getString().str(); Str.resize(RealLen, '\0'); return Str; @@ -1894,7 +1842,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { D->getLocation(), D->getLocation(), cxxSelector, getContext().VoidTy, 0, - DC, true, false, true, + DC, true, false, true, false, ObjCMethodDecl::Required); D->addInstanceMethod(DTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); @@ -1906,7 +1854,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { D->getLocation(), D->getLocation(), cxxSelector, getContext().getObjCIdType(), 0, - DC, true, false, true, + DC, true, false, true, false, ObjCMethodDecl::Required); D->addInstanceMethod(CTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); @@ -1993,9 +1941,16 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { // Forward declarations, no (immediate) code generation. case Decl::ObjCClass: case Decl::ObjCForwardProtocol: - case Decl::ObjCCategory: case Decl::ObjCInterface: break; + + case Decl::ObjCCategory: { + ObjCCategoryDecl *CD = cast(D); + if (CD->IsClassExtension() && CD->hasSynthBitfield()) + Context.ResetObjCLayout(CD->getClassInterface()); + break; + } + case Decl::ObjCProtocol: Runtime->GenerateProtocol(cast(D)); @@ -2009,6 +1964,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::ObjCImplementation: { ObjCImplementationDecl *OMD = cast(D); + if (Features.ObjCNonFragileABI2 && OMD->hasSynthBitfield()) + Context.ResetObjCLayout(OMD->getClassInterface()); EmitObjCPropertyImplementations(OMD); EmitObjCIvarInitializations(OMD); Runtime->GenerateClass(OMD); @@ -2118,3 +2075,88 @@ void CodeGenFunction::EmitDeclMetadata() { } } } + +///@name Custom Runtime Function Interfaces +///@{ +// +// FIXME: These can be eliminated once we can have clients just get the required +// AST nodes from the builtin tables. + +llvm::Constant *CodeGenModule::getBlockObjectDispose() { + if (BlockObjectDispose) + return BlockObjectDispose; + + // If we saw an explicit decl, use that. + if (BlockObjectDisposeDecl) { + return BlockObjectDispose = GetAddrOfFunction( + BlockObjectDisposeDecl, + getTypes().GetFunctionType(BlockObjectDisposeDecl)); + } + + // Otherwise construct the function by hand. + const llvm::FunctionType *FTy; + std::vector ArgTys; + const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); + ArgTys.push_back(PtrToInt8Ty); + ArgTys.push_back(llvm::Type::getInt32Ty(VMContext)); + FTy = llvm::FunctionType::get(ResultType, ArgTys, false); + return BlockObjectDispose = + CreateRuntimeFunction(FTy, "_Block_object_dispose"); +} + +llvm::Constant *CodeGenModule::getBlockObjectAssign() { + if (BlockObjectAssign) + return BlockObjectAssign; + + // If we saw an explicit decl, use that. + if (BlockObjectAssignDecl) { + return BlockObjectAssign = GetAddrOfFunction( + BlockObjectAssignDecl, + getTypes().GetFunctionType(BlockObjectAssignDecl)); + } + + // Otherwise construct the function by hand. + const llvm::FunctionType *FTy; + std::vector ArgTys; + const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext); + ArgTys.push_back(PtrToInt8Ty); + ArgTys.push_back(PtrToInt8Ty); + ArgTys.push_back(llvm::Type::getInt32Ty(VMContext)); + FTy = llvm::FunctionType::get(ResultType, ArgTys, false); + return BlockObjectAssign = + CreateRuntimeFunction(FTy, "_Block_object_assign"); +} + +llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() { + if (NSConcreteGlobalBlock) + return NSConcreteGlobalBlock; + + // If we saw an explicit decl, use that. + if (NSConcreteGlobalBlockDecl) { + return NSConcreteGlobalBlock = GetAddrOfGlobalVar( + NSConcreteGlobalBlockDecl, + getTypes().ConvertType(NSConcreteGlobalBlockDecl->getType())); + } + + // Otherwise construct the variable by hand. + return NSConcreteGlobalBlock = CreateRuntimeVariable( + PtrToInt8Ty, "_NSConcreteGlobalBlock"); +} + +llvm::Constant *CodeGenModule::getNSConcreteStackBlock() { + if (NSConcreteStackBlock) + return NSConcreteStackBlock; + + // If we saw an explicit decl, use that. + if (NSConcreteStackBlockDecl) { + return NSConcreteStackBlock = GetAddrOfGlobalVar( + NSConcreteStackBlockDecl, + getTypes().ConvertType(NSConcreteStackBlockDecl->getType())); + } + + // Otherwise construct the variable by hand. + return NSConcreteStackBlock = CreateRuntimeVariable( + PtrToInt8Ty, "_NSConcreteStackBlock"); +} + +///@} diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 27f15fc..cabff9e 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -22,7 +22,6 @@ #include "CGCall.h" #include "CGCXX.h" #include "CGVTables.h" -#include "CGCXXABI.h" #include "CodeGenTypes.h" #include "GlobalDecl.h" #include "Mangle.h" @@ -71,6 +70,7 @@ namespace clang { namespace CodeGen { class CodeGenFunction; + class CGCXXABI; class CGDebugInfo; class CGObjCRuntime; class MangleBuffer; @@ -109,6 +109,7 @@ class CodeGenModule : public BlockModule { const llvm::TargetData &TheTargetData; mutable const TargetCodeGenInfo *TheTargetCodeGenInfo; Diagnostic &Diags; + CGCXXABI &ABI; CodeGenTypes Types; /// VTables - Holds information about C++ vtables. @@ -116,7 +117,6 @@ class CodeGenModule : public BlockModule { friend class CodeGenVTables; CGObjCRuntime* Runtime; - CXXABI* ABI; CGDebugInfo* DebugInfo; // WeakRefReferences - A set of references that have only been seen via @@ -162,6 +162,12 @@ class CodeGenModule : public BlockModule { /// CXXGlobalInits - Global variables with initializers that need to run /// before main. std::vector CXXGlobalInits; + + /// When a C++ decl with an initializer is deferred, null is + /// appended to CXXGlobalInits, and the index of that null is placed + /// here so that the initializer will be performed in the correct + /// order. + llvm::DenseMap DelayedCXXInitPosition; /// - Global variables with initializers whose order of initialization /// is set by init_priority attribute. @@ -183,10 +189,23 @@ class CodeGenModule : public BlockModule { /// Lazily create the Objective-C runtime void createObjCRuntime(); - /// Lazily create the C++ ABI - void createCXXABI(); llvm::LLVMContext &VMContext; + + /// @name Cache for Blocks Runtime Globals + /// @{ + + const VarDecl *NSConcreteGlobalBlockDecl; + const VarDecl *NSConcreteStackBlockDecl; + llvm::Constant *NSConcreteGlobalBlock; + llvm::Constant *NSConcreteStackBlock; + + const FunctionDecl *BlockObjectAssignDecl; + const FunctionDecl *BlockObjectDisposeDecl; + llvm::Constant *BlockObjectAssign; + llvm::Constant *BlockObjectDispose; + + /// @} public: CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts, llvm::Module &M, const llvm::TargetData &TD, Diagnostic &Diags); @@ -207,15 +226,8 @@ public: /// been configured. bool hasObjCRuntime() { return !!Runtime; } - /// getCXXABI() - Return a reference to the configured - /// C++ ABI. - CXXABI &getCXXABI() { - if (!ABI) createCXXABI(); - return *ABI; - } - - /// hasCXXABI() - Return true iff a C++ ABI has been configured. - bool hasCXXABI() { return !!ABI; } + /// getCXXABI() - Return a reference to the configured C++ ABI. + CGCXXABI &getCXXABI() { return ABI; } llvm::Value *getStaticLocalDeclAddress(const VarDecl *VD) { return StaticLocalDeclMap[VD]; @@ -231,15 +243,11 @@ public: const LangOptions &getLangOptions() const { return Features; } llvm::Module &getModule() const { return TheModule; } CodeGenTypes &getTypes() { return Types; } - MangleContext &getMangleContext() { - if (!ABI) createCXXABI(); - return ABI->getMangleContext(); - } CodeGenVTables &getVTables() { return VTables; } Diagnostic &getDiags() const { return Diags; } const llvm::TargetData &getTargetData() const { return TheTargetData; } llvm::LLVMContext &getLLVMContext() { return VMContext; } - const TargetCodeGenInfo &getTargetCodeGenInfo() const; + const TargetCodeGenInfo &getTargetCodeGenInfo(); bool isTargetDarwin() const; /// getDeclVisibilityMode - Compute the visibility of the decl \arg D. @@ -249,6 +257,11 @@ public: /// GlobalValue. void setGlobalVisibility(llvm::GlobalValue *GV, const Decl *D) const; + /// setTypeVisibility - Set the visibility for the given global + /// value which holds information about a type. + void setTypeVisibility(llvm::GlobalValue *GV, const CXXRecordDecl *D, + bool IsForRTTI) const; + llvm::Constant *GetAddrOfGlobal(GlobalDecl GD) { if (isa(GD.getDecl())) return GetAddrOfCXXConstructor(cast(GD.getDecl()), @@ -289,7 +302,8 @@ public: /// a class. Returns null if the offset is 0. llvm::Constant * GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, - const CXXBaseSpecifierArray &BasePath); + CastExpr::path_const_iterator PathBegin, + CastExpr::path_const_iterator PathEnd); /// GetStringForStringLiteral - Return the appropriate bytes for a string /// literal, properly padded to match the literal type. If only the address of @@ -344,10 +358,6 @@ public: llvm::GlobalValue *GetAddrOfCXXDestructor(const CXXDestructorDecl *D, CXXDtorType Type); - // GetCXXMemberFunctionPointerValue - Given a method declaration, return the - // integer used in a member function pointer to refer to that value. - llvm::Constant *GetCXXMemberFunctionPointerValue(const CXXMethodDecl *MD); - /// getBuiltinLibFunction - Given a builtin id for a function like /// "__builtin_fabsf", return a Function* for "fabsf". llvm::Value *getBuiltinLibFunction(const FunctionDecl *FD, @@ -392,6 +402,16 @@ public: llvm::Constant *CreateRuntimeVariable(const llvm::Type *Ty, llvm::StringRef Name); + ///@name Custom Blocks Runtime Interfaces + ///@{ + + llvm::Constant *getNSConcreteGlobalBlock(); + llvm::Constant *getNSConcreteStackBlock(); + llvm::Constant *getBlockObjectAssign(); + llvm::Constant *getBlockObjectDispose(); + + ///@} + void UpdateCompletedType(const TagDecl *TD) { // Make sure that this type is translated. Types.UpdateCompletedType(TD); @@ -411,8 +431,6 @@ public: llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV, const AnnotateAttr *AA, unsigned LineNo); - llvm::Constant *EmitPointerToDataMember(const FieldDecl *FD); - /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified stmt yet. /// \param OmitOnError - If true, then this error should only be emitted if no @@ -473,15 +491,6 @@ public: void EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired); - enum GVALinkage { - GVA_Internal, - GVA_C99Inline, - GVA_CXXInline, - GVA_StrongExternal, - GVA_TemplateInstantiation, - GVA_ExplicitTemplateInstantiation - }; - llvm::GlobalVariable::LinkageTypes getFunctionLinkage(const FunctionDecl *FD); diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index d469b90..5ab65c5 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -13,6 +13,7 @@ #include "CodeGenTypes.h" #include "CGCall.h" +#include "CGCXXABI.h" #include "CGRecordLayout.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -26,9 +27,10 @@ using namespace clang; using namespace CodeGen; CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M, - const llvm::TargetData &TD, const ABIInfo &Info) + const llvm::TargetData &TD, const ABIInfo &Info, + CGCXXABI &CXXABI) : Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD), - TheABIInfo(Info) { + TheABIInfo(Info), TheCXXABI(CXXABI) { } CodeGenTypes::~CodeGenTypes() { @@ -400,17 +402,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { } case Type::MemberPointer: { - // FIXME: This is ABI dependent. We use the Itanium C++ ABI. - // http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers - // If we ever want to support other ABIs this needs to be abstracted. - - QualType ETy = cast(Ty).getPointeeType(); - const llvm::Type *PtrDiffTy = - ConvertTypeRecursive(Context.getPointerDiffType()); - if (ETy->isFunctionType()) - return llvm::StructType::get(TheModule.getContext(), PtrDiffTy, PtrDiffTy, - NULL); - return PtrDiffTy; + return getCXXABI().ConvertMemberPointerType(cast(&Ty)); } } @@ -491,31 +483,34 @@ CodeGenTypes::getCGRecordLayout(const RecordDecl *TD) const { return *Layout; } -bool CodeGenTypes::ContainsPointerToDataMember(QualType T) { +bool CodeGenTypes::isZeroInitializable(QualType T) { // No need to check for member pointers when not compiling C++. if (!Context.getLangOptions().CPlusPlus) - return false; + return true; T = Context.getBaseElementType(T); + // Records are non-zero-initializable if they contain any + // non-zero-initializable subobjects. if (const RecordType *RT = T->getAs()) { const CXXRecordDecl *RD = cast(RT->getDecl()); - - return ContainsPointerToDataMember(RD); + return isZeroInitializable(RD); } - + + // We have to ask the ABI about member pointers. if (const MemberPointerType *MPT = T->getAs()) - return !MPT->getPointeeType()->isFunctionType(); + return getCXXABI().isZeroInitializable(MPT); - return false; + // Everything else is okay. + return true; } -bool CodeGenTypes::ContainsPointerToDataMember(const CXXRecordDecl *RD) { +bool CodeGenTypes::isZeroInitializable(const CXXRecordDecl *RD) { // FIXME: It would be better if there was a way to explicitly compute the // record layout instead of converting to a type. ConvertTagDeclType(RD); const CGRecordLayout &Layout = getCGRecordLayout(RD); - return Layout.containsPointerToDataMember(); + return Layout.isZeroInitializable(); } diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index c7f48e6..1fc2153 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -14,13 +14,12 @@ #ifndef CLANG_CODEGEN_CODEGENTYPES_H #define CLANG_CODEGEN_CODEGENTYPES_H +#include "CGCall.h" +#include "GlobalDecl.h" #include "llvm/Module.h" #include "llvm/ADT/DenseMap.h" #include -#include "CGCall.h" -#include "GlobalDecl.h" - namespace llvm { class FunctionType; class Module; @@ -51,6 +50,7 @@ namespace clang { typedef CanQual CanQualType; namespace CodeGen { + class CGCXXABI; class CGRecordLayout; /// CodeGenTypes - This class organizes the cross-module state that is used @@ -61,6 +61,7 @@ class CodeGenTypes { llvm::Module& TheModule; const llvm::TargetData& TheTargetData; const ABIInfo& TheABIInfo; + CGCXXABI &TheCXXABI; llvm::SmallVector, 8> PointersToResolve; @@ -102,13 +103,14 @@ private: public: CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD, - const ABIInfo &Info); + const ABIInfo &Info, CGCXXABI &CXXABI); ~CodeGenTypes(); const llvm::TargetData &getTargetData() const { return TheTargetData; } const TargetInfo &getTarget() const { return Target; } ASTContext &getContext() const { return Context; } const ABIInfo &getABIInfo() const { return TheABIInfo; } + CGCXXABI &getCXXABI() const { return TheCXXABI; } llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); } /// ConvertType - Convert type T into a llvm::Type. @@ -139,7 +141,7 @@ public: /// GetFunctionTypeForVTable - Get the LLVM function type for use in a vtable, /// given a CXXMethodDecl. If the method to has an incomplete return type, /// and/or incomplete argument types, this will return the opaque type. - const llvm::Type *GetFunctionTypeForVTable(const CXXMethodDecl *MD); + const llvm::Type *GetFunctionTypeForVTable(GlobalDecl GD); const CGRecordLayout &getCGRecordLayout(const RecordDecl*) const; @@ -169,7 +171,9 @@ public: const CGFunctionInfo &getFunctionInfo(CanQual Ty, bool IsRecursive = false); - // getFunctionInfo - Get the function info for a member function. + /// getFunctionInfo - Get the function info for a member function of + /// the given type. This is used for calls through member function + /// pointers. const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD, const FunctionProtoType *FTP); @@ -205,13 +209,13 @@ public: // These are internal details of CGT that shouldn't be used externally. void GetExpandedTypes(QualType Ty, std::vector &ArgTys, bool IsRecursive); - /// ContainsPointerToDataMember - Return whether the given type contains a - /// pointer to a data member. - bool ContainsPointerToDataMember(QualType T); + /// IsZeroInitializable - Return whether a type can be + /// zero-initialized (in the C++ sense) with an LLVM zeroinitializer. + bool isZeroInitializable(QualType T); - /// ContainsPointerToDataMember - Return whether the record decl contains a - /// pointer to a data member. - bool ContainsPointerToDataMember(const CXXRecordDecl *RD); + /// IsZeroInitializable - Return whether a record type can be + /// zero-initialized (in the C++ sense) with an LLVM zeroinitializer. + bool isZeroInitializable(const CXXRecordDecl *RD); }; } // end namespace CodeGen diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 98db75e..eefc530 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -12,28 +12,1012 @@ // documented at: // http://www.codesourcery.com/public/cxx-abi/abi.html // http://www.codesourcery.com/public/cxx-abi/abi-eh.html +// +// It also supports the closely-related ARM ABI, documented at: +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf +// //===----------------------------------------------------------------------===// #include "CGCXXABI.h" +#include "CGRecordLayout.h" +#include "CodeGenFunction.h" #include "CodeGenModule.h" #include "Mangle.h" +#include +#include +#include using namespace clang; +using namespace CodeGen; namespace { -class ItaniumCXXABI : public CodeGen::CXXABI { +class ItaniumCXXABI : public CodeGen::CGCXXABI { +private: + const llvm::IntegerType *PtrDiffTy; +protected: CodeGen::MangleContext MangleCtx; + bool IsARM; + + // It's a little silly for us to cache this. + const llvm::IntegerType *getPtrDiffTy() { + if (!PtrDiffTy) { + QualType T = getContext().getPointerDiffType(); + const llvm::Type *Ty = CGM.getTypes().ConvertTypeRecursive(T); + PtrDiffTy = cast(Ty); + } + return PtrDiffTy; + } + + bool NeedsArrayCookie(QualType ElementType); + public: - ItaniumCXXABI(CodeGen::CodeGenModule &CGM) : - MangleCtx(CGM.getContext(), CGM.getDiags()) { } + ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) : + CGCXXABI(CGM), PtrDiffTy(0), MangleCtx(getContext(), CGM.getDiags()), + IsARM(IsARM) { } CodeGen::MangleContext &getMangleContext() { return MangleCtx; } + + bool isZeroInitializable(const MemberPointerType *MPT); + + const llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT); + + llvm::Value *EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, + llvm::Value *&This, + llvm::Value *MemFnPtr, + const MemberPointerType *MPT); + + llvm::Value *EmitMemberDataPointerAddress(CodeGenFunction &CGF, + llvm::Value *Base, + llvm::Value *MemPtr, + const MemberPointerType *MPT); + + llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF, + const CastExpr *E, + llvm::Value *Src); + + llvm::Constant *EmitMemberPointerConversion(llvm::Constant *C, + const CastExpr *E); + + llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT); + + llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD); + llvm::Constant *EmitMemberPointer(const FieldDecl *FD); + + llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality); + + llvm::Value *EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *Addr, + const MemberPointerType *MPT); + + void BuildConstructorSignature(const CXXConstructorDecl *Ctor, + CXXCtorType T, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys); + + void BuildDestructorSignature(const CXXDestructorDecl *Dtor, + CXXDtorType T, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys); + + void BuildInstanceFunctionParams(CodeGenFunction &CGF, + QualType &ResTy, + FunctionArgList &Params); + + void EmitInstanceFunctionProlog(CodeGenFunction &CGF); + + CharUnits GetArrayCookieSize(QualType ElementType); + llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF, + llvm::Value *NewPtr, + llvm::Value *NumElements, + QualType ElementType); + void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, + QualType ElementType, llvm::Value *&NumElements, + llvm::Value *&AllocPtr, CharUnits &CookieSize); +}; + +class ARMCXXABI : public ItaniumCXXABI { +public: + ARMCXXABI(CodeGen::CodeGenModule &CGM) : ItaniumCXXABI(CGM, /*ARM*/ true) {} + + void BuildConstructorSignature(const CXXConstructorDecl *Ctor, + CXXCtorType T, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys); + + void BuildDestructorSignature(const CXXDestructorDecl *Dtor, + CXXDtorType T, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys); + + void BuildInstanceFunctionParams(CodeGenFunction &CGF, + QualType &ResTy, + FunctionArgList &Params); + + void EmitInstanceFunctionProlog(CodeGenFunction &CGF); + + void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy); + + CharUnits GetArrayCookieSize(QualType ElementType); + llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF, + llvm::Value *NewPtr, + llvm::Value *NumElements, + QualType ElementType); + void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, + QualType ElementType, llvm::Value *&NumElements, + llvm::Value *&AllocPtr, CharUnits &CookieSize); + +private: + /// \brief Returns true if the given instance method is one of the + /// kinds that the ARM ABI says returns 'this'. + static bool HasThisReturn(GlobalDecl GD) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + return ((isa(MD) && GD.getDtorType() != Dtor_Deleting) || + (isa(MD))); + } }; } -CodeGen::CXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) { +CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) { return new ItaniumCXXABI(CGM); } +CodeGen::CGCXXABI *CodeGen::CreateARMCXXABI(CodeGenModule &CGM) { + return new ARMCXXABI(CGM); +} + +const llvm::Type * +ItaniumCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) { + if (MPT->isMemberDataPointer()) + return getPtrDiffTy(); + else + return llvm::StructType::get(CGM.getLLVMContext(), + getPtrDiffTy(), getPtrDiffTy(), NULL); +} + +/// In the Itanium and ARM ABIs, method pointers have the form: +/// struct { ptrdiff_t ptr; ptrdiff_t adj; } memptr; +/// +/// In the Itanium ABI: +/// - method pointers are virtual if (memptr.ptr & 1) is nonzero +/// - the this-adjustment is (memptr.adj) +/// - the virtual offset is (memptr.ptr - 1) +/// +/// In the ARM ABI: +/// - method pointers are virtual if (memptr.adj & 1) is nonzero +/// - the this-adjustment is (memptr.adj >> 1) +/// - the virtual offset is (memptr.ptr) +/// ARM uses 'adj' for the virtual flag because Thumb functions +/// may be only single-byte aligned. +/// +/// If the member is virtual, the adjusted 'this' pointer points +/// to a vtable pointer from which the virtual offset is applied. +/// +/// If the member is non-virtual, memptr.ptr is the address of +/// the function to call. +llvm::Value * +ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, + llvm::Value *&This, + llvm::Value *MemFnPtr, + const MemberPointerType *MPT) { + CGBuilderTy &Builder = CGF.Builder; + + const FunctionProtoType *FPT = + MPT->getPointeeType()->getAs(); + const CXXRecordDecl *RD = + cast(MPT->getClass()->getAs()->getDecl()); + + const llvm::FunctionType *FTy = + CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT), + FPT->isVariadic()); + + const llvm::IntegerType *ptrdiff = getPtrDiffTy(); + llvm::Constant *ptrdiff_1 = llvm::ConstantInt::get(ptrdiff, 1); + + llvm::BasicBlock *FnVirtual = CGF.createBasicBlock("memptr.virtual"); + llvm::BasicBlock *FnNonVirtual = CGF.createBasicBlock("memptr.nonvirtual"); + llvm::BasicBlock *FnEnd = CGF.createBasicBlock("memptr.end"); + + // Extract memptr.adj, which is in the second field. + llvm::Value *RawAdj = Builder.CreateExtractValue(MemFnPtr, 1, "memptr.adj"); + + // Compute the true adjustment. + llvm::Value *Adj = RawAdj; + if (IsARM) + Adj = Builder.CreateAShr(Adj, ptrdiff_1, "memptr.adj.shifted"); + + // Apply the adjustment and cast back to the original struct type + // for consistency. + llvm::Value *Ptr = Builder.CreateBitCast(This, Builder.getInt8PtrTy()); + Ptr = Builder.CreateInBoundsGEP(Ptr, Adj); + This = Builder.CreateBitCast(Ptr, This->getType(), "this.adjusted"); + + // Load the function pointer. + llvm::Value *FnAsInt = Builder.CreateExtractValue(MemFnPtr, 0, "memptr.ptr"); + + // If the LSB in the function pointer is 1, the function pointer points to + // a virtual function. + llvm::Value *IsVirtual; + if (IsARM) + IsVirtual = Builder.CreateAnd(RawAdj, ptrdiff_1); + else + IsVirtual = Builder.CreateAnd(FnAsInt, ptrdiff_1); + IsVirtual = Builder.CreateIsNotNull(IsVirtual, "memptr.isvirtual"); + Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual); + + // In the virtual path, the adjustment left 'This' pointing to the + // vtable of the correct base subobject. The "function pointer" is an + // offset within the vtable (+1 for the virtual flag on non-ARM). + CGF.EmitBlock(FnVirtual); + + // Cast the adjusted this to a pointer to vtable pointer and load. + const llvm::Type *VTableTy = Builder.getInt8PtrTy(); + llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy->getPointerTo()); + VTable = Builder.CreateLoad(VTable, "memptr.vtable"); + + // Apply the offset. + llvm::Value *VTableOffset = FnAsInt; + if (!IsARM) VTableOffset = Builder.CreateSub(VTableOffset, ptrdiff_1); + VTable = Builder.CreateGEP(VTable, VTableOffset); + + // Load the virtual function to call. + VTable = Builder.CreateBitCast(VTable, FTy->getPointerTo()->getPointerTo()); + llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "memptr.virtualfn"); + CGF.EmitBranch(FnEnd); + + // In the non-virtual path, the function pointer is actually a + // function pointer. + CGF.EmitBlock(FnNonVirtual); + llvm::Value *NonVirtualFn = + Builder.CreateIntToPtr(FnAsInt, FTy->getPointerTo(), "memptr.nonvirtualfn"); + + // We're done. + CGF.EmitBlock(FnEnd); + llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo()); + Callee->reserveOperandSpace(2); + Callee->addIncoming(VirtualFn, FnVirtual); + Callee->addIncoming(NonVirtualFn, FnNonVirtual); + return Callee; +} + +/// Compute an l-value by applying the given pointer-to-member to a +/// base object. +llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, + llvm::Value *Base, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + assert(MemPtr->getType() == getPtrDiffTy()); + + CGBuilderTy &Builder = CGF.Builder; + + unsigned AS = cast(Base->getType())->getAddressSpace(); + + // Cast to char*. + Base = Builder.CreateBitCast(Base, Builder.getInt8Ty()->getPointerTo(AS)); + + // Apply the offset, which we assume is non-null. + llvm::Value *Addr = Builder.CreateInBoundsGEP(Base, MemPtr, "memptr.offset"); + + // Cast the address to the appropriate pointer type, adopting the + // address space of the base pointer. + const llvm::Type *PType + = CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS); + return Builder.CreateBitCast(Addr, PType); +} + +/// Perform a derived-to-base or base-to-derived member pointer conversion. +/// +/// Obligatory offset/adjustment diagram: +/// <-- offset --> <-- adjustment --> +/// |--------------------------|----------------------|--------------------| +/// ^Derived address point ^Base address point ^Member address point +/// +/// So when converting a base member pointer to a derived member pointer, +/// we add the offset to the adjustment because the address point has +/// decreased; and conversely, when converting a derived MP to a base MP +/// we subtract the offset from the adjustment because the address point +/// has increased. +/// +/// The standard forbids (at compile time) conversion to and from +/// virtual bases, which is why we don't have to consider them here. +/// +/// The standard forbids (at run time) casting a derived MP to a base +/// MP when the derived MP does not point to a member of the base. +/// This is why -1 is a reasonable choice for null data member +/// pointers. +llvm::Value * +ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF, + const CastExpr *E, + llvm::Value *Src) { + assert(E->getCastKind() == CK_DerivedToBaseMemberPointer || + E->getCastKind() == CK_BaseToDerivedMemberPointer); + + if (isa(Src)) + return EmitMemberPointerConversion(cast(Src), E); + + CGBuilderTy &Builder = CGF.Builder; + + const MemberPointerType *SrcTy = + E->getSubExpr()->getType()->getAs(); + const MemberPointerType *DestTy = E->getType()->getAs(); + + const CXXRecordDecl *SrcDecl = SrcTy->getClass()->getAsCXXRecordDecl(); + const CXXRecordDecl *DestDecl = DestTy->getClass()->getAsCXXRecordDecl(); + + bool DerivedToBase = + E->getCastKind() == CK_DerivedToBaseMemberPointer; + + const CXXRecordDecl *BaseDecl, *DerivedDecl; + if (DerivedToBase) + DerivedDecl = SrcDecl, BaseDecl = DestDecl; + else + BaseDecl = SrcDecl, DerivedDecl = DestDecl; + + llvm::Constant *Adj = + CGF.CGM.GetNonVirtualBaseClassOffset(DerivedDecl, + E->path_begin(), + E->path_end()); + if (!Adj) return Src; + + // For member data pointers, this is just a matter of adding the + // offset if the source is non-null. + if (SrcTy->isMemberDataPointer()) { + llvm::Value *Dst; + if (DerivedToBase) + Dst = Builder.CreateNSWSub(Src, Adj, "adj"); + else + Dst = Builder.CreateNSWAdd(Src, Adj, "adj"); + + // Null check. + llvm::Value *Null = llvm::Constant::getAllOnesValue(Src->getType()); + llvm::Value *IsNull = Builder.CreateICmpEQ(Src, Null, "memptr.isnull"); + return Builder.CreateSelect(IsNull, Src, Dst); + } + + // The this-adjustment is left-shifted by 1 on ARM. + if (IsARM) { + uint64_t Offset = cast(Adj)->getZExtValue(); + Offset <<= 1; + Adj = llvm::ConstantInt::get(Adj->getType(), Offset); + } + + llvm::Value *SrcAdj = Builder.CreateExtractValue(Src, 1, "src.adj"); + llvm::Value *DstAdj; + if (DerivedToBase) + DstAdj = Builder.CreateNSWSub(SrcAdj, Adj, "adj"); + else + DstAdj = Builder.CreateNSWAdd(SrcAdj, Adj, "adj"); + + return Builder.CreateInsertValue(Src, DstAdj, 1); +} + +llvm::Constant * +ItaniumCXXABI::EmitMemberPointerConversion(llvm::Constant *C, + const CastExpr *E) { + const MemberPointerType *SrcTy = + E->getSubExpr()->getType()->getAs(); + const MemberPointerType *DestTy = + E->getType()->getAs(); + + bool DerivedToBase = + E->getCastKind() == CK_DerivedToBaseMemberPointer; + + const CXXRecordDecl *DerivedDecl; + if (DerivedToBase) + DerivedDecl = SrcTy->getClass()->getAsCXXRecordDecl(); + else + DerivedDecl = DestTy->getClass()->getAsCXXRecordDecl(); + + // Calculate the offset to the base class. + llvm::Constant *Offset = + CGM.GetNonVirtualBaseClassOffset(DerivedDecl, + E->path_begin(), + E->path_end()); + // If there's no offset, we're done. + if (!Offset) return C; + + // If the source is a member data pointer, we have to do a null + // check and then add the offset. In the common case, we can fold + // away the offset. + if (SrcTy->isMemberDataPointer()) { + assert(C->getType() == getPtrDiffTy()); + + // If it's a constant int, just create a new constant int. + if (llvm::ConstantInt *CI = dyn_cast(C)) { + int64_t Src = CI->getSExtValue(); + + // Null converts to null. + if (Src == -1) return CI; + + // Otherwise, just add the offset. + int64_t OffsetV = cast(Offset)->getSExtValue(); + int64_t Dst = (DerivedToBase ? Src - OffsetV : Src + OffsetV); + return llvm::ConstantInt::get(CI->getType(), Dst, /*signed*/ true); + } + + // Otherwise, we have to form a constant select expression. + llvm::Constant *Null = llvm::Constant::getAllOnesValue(C->getType()); + + llvm::Constant *IsNull = + llvm::ConstantExpr::getICmp(llvm::ICmpInst::ICMP_EQ, C, Null); + + llvm::Constant *Dst; + if (DerivedToBase) + Dst = llvm::ConstantExpr::getNSWSub(C, Offset); + else + Dst = llvm::ConstantExpr::getNSWAdd(C, Offset); + + return llvm::ConstantExpr::getSelect(IsNull, Null, Dst); + } + + // The this-adjustment is left-shifted by 1 on ARM. + if (IsARM) { + int64_t OffsetV = cast(Offset)->getSExtValue(); + OffsetV <<= 1; + Offset = llvm::ConstantInt::get(Offset->getType(), OffsetV); + } + + llvm::ConstantStruct *CS = cast(C); + + llvm::Constant *Values[2] = { CS->getOperand(0), 0 }; + if (DerivedToBase) + Values[1] = llvm::ConstantExpr::getSub(CS->getOperand(1), Offset); + else + Values[1] = llvm::ConstantExpr::getAdd(CS->getOperand(1), Offset); + + return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2, + /*Packed=*/false); +} + + +llvm::Constant * +ItaniumCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) { + const llvm::Type *ptrdiff_t = getPtrDiffTy(); + + // Itanium C++ ABI 2.3: + // A NULL pointer is represented as -1. + if (MPT->isMemberDataPointer()) + return llvm::ConstantInt::get(ptrdiff_t, -1ULL, /*isSigned=*/true); + + llvm::Constant *Zero = llvm::ConstantInt::get(ptrdiff_t, 0); + llvm::Constant *Values[2] = { Zero, Zero }; + return llvm::ConstantStruct::get(CGM.getLLVMContext(), Values, 2, + /*Packed=*/false); +} + +llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const FieldDecl *FD) { + // Itanium C++ ABI 2.3: + // A pointer to data member is an offset from the base address of + // the class object containing it, represented as a ptrdiff_t + + QualType ClassType = getContext().getTypeDeclType(FD->getParent()); + const llvm::StructType *ClassLTy = + cast(CGM.getTypes().ConvertType(ClassType)); + + const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(FD->getParent()); + unsigned FieldNo = RL.getLLVMFieldNo(FD); + uint64_t Offset = + CGM.getTargetData().getStructLayout(ClassLTy)->getElementOffset(FieldNo); + + return llvm::ConstantInt::get(getPtrDiffTy(), Offset); +} + +llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { + assert(MD->isInstance() && "Member function must not be static!"); + MD = MD->getCanonicalDecl(); + + CodeGenTypes &Types = CGM.getTypes(); + const llvm::Type *ptrdiff_t = getPtrDiffTy(); + + // Get the function pointer (or index if this is a virtual function). + llvm::Constant *MemPtr[2]; + if (MD->isVirtual()) { + uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD); + + // FIXME: We shouldn't use / 8 here. + uint64_t PointerWidthInBytes = + getContext().Target.getPointerWidth(0) / 8; + uint64_t VTableOffset = (Index * PointerWidthInBytes); + + if (IsARM) { + // ARM C++ ABI 3.2.1: + // This ABI specifies that adj contains twice the this + // adjustment, plus 1 if the member function is virtual. The + // least significant bit of adj then makes exactly the same + // discrimination as the least significant bit of ptr does for + // Itanium. + MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset); + MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 1); + } else { + // Itanium C++ ABI 2.3: + // For a virtual function, [the pointer field] is 1 plus the + // virtual table offset (in bytes) of the function, + // represented as a ptrdiff_t. + MemPtr[0] = llvm::ConstantInt::get(ptrdiff_t, VTableOffset + 1); + MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); + } + } else { + const FunctionProtoType *FPT = MD->getType()->getAs(); + const llvm::Type *Ty; + // Check whether the function has a computable LLVM signature. + if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) { + // The function has a computable LLVM signature; use the correct type. + Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic()); + } else { + // Use an arbitrary non-function type to tell GetAddrOfFunction that the + // function type is incomplete. + Ty = ptrdiff_t; + } + + llvm::Constant *Addr = CGM.GetAddrOfFunction(MD, Ty); + MemPtr[0] = llvm::ConstantExpr::getPtrToInt(Addr, ptrdiff_t); + MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); + } + + return llvm::ConstantStruct::get(CGM.getLLVMContext(), + MemPtr, 2, /*Packed=*/false); +} + +/// The comparison algorithm is pretty easy: the member pointers are +/// the same if they're either bitwise identical *or* both null. +/// +/// ARM is different here only because null-ness is more complicated. +llvm::Value * +ItaniumCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, + llvm::Value *L, + llvm::Value *R, + const MemberPointerType *MPT, + bool Inequality) { + CGBuilderTy &Builder = CGF.Builder; + + llvm::ICmpInst::Predicate Eq; + llvm::Instruction::BinaryOps And, Or; + if (Inequality) { + Eq = llvm::ICmpInst::ICMP_NE; + And = llvm::Instruction::Or; + Or = llvm::Instruction::And; + } else { + Eq = llvm::ICmpInst::ICMP_EQ; + And = llvm::Instruction::And; + Or = llvm::Instruction::Or; + } + + // Member data pointers are easy because there's a unique null + // value, so it just comes down to bitwise equality. + if (MPT->isMemberDataPointer()) + return Builder.CreateICmp(Eq, L, R); + + // For member function pointers, the tautologies are more complex. + // The Itanium tautology is: + // (L == R) <==> (L.ptr == R.ptr && (L.ptr == 0 || L.adj == R.adj)) + // The ARM tautology is: + // (L == R) <==> (L.ptr == R.ptr && + // (L.adj == R.adj || + // (L.ptr == 0 && ((L.adj|R.adj) & 1) == 0))) + // The inequality tautologies have exactly the same structure, except + // applying De Morgan's laws. + + llvm::Value *LPtr = Builder.CreateExtractValue(L, 0, "lhs.memptr.ptr"); + llvm::Value *RPtr = Builder.CreateExtractValue(R, 0, "rhs.memptr.ptr"); + + // This condition tests whether L.ptr == R.ptr. This must always be + // true for equality to hold. + llvm::Value *PtrEq = Builder.CreateICmp(Eq, LPtr, RPtr, "cmp.ptr"); + + // This condition, together with the assumption that L.ptr == R.ptr, + // tests whether the pointers are both null. ARM imposes an extra + // condition. + llvm::Value *Zero = llvm::Constant::getNullValue(LPtr->getType()); + llvm::Value *EqZero = Builder.CreateICmp(Eq, LPtr, Zero, "cmp.ptr.null"); + + // This condition tests whether L.adj == R.adj. If this isn't + // true, the pointers are unequal unless they're both null. + llvm::Value *LAdj = Builder.CreateExtractValue(L, 1, "lhs.memptr.adj"); + llvm::Value *RAdj = Builder.CreateExtractValue(R, 1, "rhs.memptr.adj"); + llvm::Value *AdjEq = Builder.CreateICmp(Eq, LAdj, RAdj, "cmp.adj"); + + // Null member function pointers on ARM clear the low bit of Adj, + // so the zero condition has to check that neither low bit is set. + if (IsARM) { + llvm::Value *One = llvm::ConstantInt::get(LPtr->getType(), 1); + + // Compute (l.adj | r.adj) & 1 and test it against zero. + llvm::Value *OrAdj = Builder.CreateOr(LAdj, RAdj, "or.adj"); + llvm::Value *OrAdjAnd1 = Builder.CreateAnd(OrAdj, One); + llvm::Value *OrAdjAnd1EqZero = Builder.CreateICmp(Eq, OrAdjAnd1, Zero, + "cmp.or.adj"); + EqZero = Builder.CreateBinOp(And, EqZero, OrAdjAnd1EqZero); + } + + // Tie together all our conditions. + llvm::Value *Result = Builder.CreateBinOp(Or, EqZero, AdjEq); + Result = Builder.CreateBinOp(And, PtrEq, Result, + Inequality ? "memptr.ne" : "memptr.eq"); + return Result; +} + +llvm::Value * +ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, + llvm::Value *MemPtr, + const MemberPointerType *MPT) { + CGBuilderTy &Builder = CGF.Builder; + + /// For member data pointers, this is just a check against -1. + if (MPT->isMemberDataPointer()) { + assert(MemPtr->getType() == getPtrDiffTy()); + llvm::Value *NegativeOne = + llvm::Constant::getAllOnesValue(MemPtr->getType()); + return Builder.CreateICmpNE(MemPtr, NegativeOne, "memptr.tobool"); + } + + // In Itanium, a member function pointer is null if 'ptr' is null. + llvm::Value *Ptr = Builder.CreateExtractValue(MemPtr, 0, "memptr.ptr"); + + llvm::Constant *Zero = llvm::ConstantInt::get(Ptr->getType(), 0); + llvm::Value *Result = Builder.CreateICmpNE(Ptr, Zero, "memptr.tobool"); + + // In ARM, it's that, plus the low bit of 'adj' must be zero. + if (IsARM) { + llvm::Constant *One = llvm::ConstantInt::get(Ptr->getType(), 1); + llvm::Value *Adj = Builder.CreateExtractValue(MemPtr, 1, "memptr.adj"); + llvm::Value *VirtualBit = Builder.CreateAnd(Adj, One, "memptr.virtualbit"); + llvm::Value *IsNotVirtual = Builder.CreateICmpEQ(VirtualBit, Zero, + "memptr.notvirtual"); + Result = Builder.CreateAnd(Result, IsNotVirtual); + } + + return Result; +} + +/// The Itanium ABI requires non-zero initialization only for data +/// member pointers, for which '0' is a valid offset. +bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) { + return MPT->getPointeeType()->isFunctionType(); +} + +/// The generic ABI passes 'this', plus a VTT if it's initializing a +/// base subobject. +void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) { + ASTContext &Context = getContext(); + + // 'this' is already there. + + // Check if we need to add a VTT parameter (which has type void **). + if (Type == Ctor_Base && Ctor->getParent()->getNumVBases() != 0) + ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); +} + +/// The ARM ABI does the same as the Itanium ABI, but returns 'this'. +void ARMCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) { + ItaniumCXXABI::BuildConstructorSignature(Ctor, Type, ResTy, ArgTys); + ResTy = ArgTys[0]; +} + +/// The generic ABI passes 'this', plus a VTT if it's destroying a +/// base subobject. +void ItaniumCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, + CXXDtorType Type, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) { + ASTContext &Context = getContext(); + + // 'this' is already there. + + // Check if we need to add a VTT parameter (which has type void **). + if (Type == Dtor_Base && Dtor->getParent()->getNumVBases() != 0) + ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy)); +} + +/// The ARM ABI does the same as the Itanium ABI, but returns 'this' +/// for non-deleting destructors. +void ARMCXXABI::BuildDestructorSignature(const CXXDestructorDecl *Dtor, + CXXDtorType Type, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) { + ItaniumCXXABI::BuildDestructorSignature(Dtor, Type, ResTy, ArgTys); + + if (Type != Dtor_Deleting) + ResTy = ArgTys[0]; +} + +void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, + QualType &ResTy, + FunctionArgList &Params) { + /// Create the 'this' variable. + BuildThisParam(CGF, Params); + + const CXXMethodDecl *MD = cast(CGF.CurGD.getDecl()); + assert(MD->isInstance()); + + // Check if we need a VTT parameter as well. + if (CodeGenVTables::needsVTTParameter(CGF.CurGD)) { + ASTContext &Context = getContext(); + + // FIXME: avoid the fake decl + QualType T = Context.getPointerType(Context.VoidPtrTy); + ImplicitParamDecl *VTTDecl + = ImplicitParamDecl::Create(Context, 0, MD->getLocation(), + &Context.Idents.get("vtt"), T); + Params.push_back(std::make_pair(VTTDecl, VTTDecl->getType())); + getVTTDecl(CGF) = VTTDecl; + } +} + +void ARMCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, + QualType &ResTy, + FunctionArgList &Params) { + ItaniumCXXABI::BuildInstanceFunctionParams(CGF, ResTy, Params); + + // Return 'this' from certain constructors and destructors. + if (HasThisReturn(CGF.CurGD)) + ResTy = Params[0].second; +} + +void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { + /// Initialize the 'this' slot. + EmitThisParam(CGF); + + /// Initialize the 'vtt' slot if needed. + if (getVTTDecl(CGF)) { + getVTTValue(CGF) + = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(getVTTDecl(CGF)), + "vtt"); + } +} + +void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { + ItaniumCXXABI::EmitInstanceFunctionProlog(CGF); + + /// Initialize the return slot to 'this' at the start of the + /// function. + if (HasThisReturn(CGF.CurGD)) + CGF.Builder.CreateStore(CGF.LoadCXXThis(), CGF.ReturnValue); +} + +void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF, + RValue RV, QualType ResultType) { + if (!isa(CGF.CurGD.getDecl())) + return ItaniumCXXABI::EmitReturnFromThunk(CGF, RV, ResultType); + + // Destructor thunks in the ARM ABI have indeterminate results. + const llvm::Type *T = + cast(CGF.ReturnValue->getType())->getElementType(); + RValue Undef = RValue::get(llvm::UndefValue::get(T)); + return ItaniumCXXABI::EmitReturnFromThunk(CGF, Undef, ResultType); +} + +/************************** Array allocation cookies **************************/ + +bool ItaniumCXXABI::NeedsArrayCookie(QualType ElementType) { + ElementType = getContext().getBaseElementType(ElementType); + const RecordType *RT = ElementType->getAs(); + if (!RT) return false; + + const CXXRecordDecl *RD = cast(RT->getDecl()); + + // If the class has a non-trivial destructor, it always needs a cookie. + if (!RD->hasTrivialDestructor()) return true; + + // If the class's usual deallocation function takes two arguments, + // it needs a cookie. Otherwise we don't need a cookie. + const CXXMethodDecl *UsualDeallocationFunction = 0; + + // Usual deallocation functions of this form are always found on the + // class. + // + // FIXME: what exactly is this code supposed to do if there's an + // ambiguity? That's possible with using declarations. + DeclarationName OpName = + getContext().DeclarationNames.getCXXOperatorName(OO_Array_Delete); + DeclContext::lookup_const_iterator Op, OpEnd; + for (llvm::tie(Op, OpEnd) = RD->lookup(OpName); Op != OpEnd; ++Op) { + const CXXMethodDecl *Delete = + cast((*Op)->getUnderlyingDecl()); + + if (Delete->isUsualDeallocationFunction()) { + UsualDeallocationFunction = Delete; + break; + } + } + + // No usual deallocation function, we don't need a cookie. + if (!UsualDeallocationFunction) + return false; + + // The usual deallocation function doesn't take a size_t argument, + // so we don't need a cookie. + if (UsualDeallocationFunction->getNumParams() == 1) + return false; + + assert(UsualDeallocationFunction->getNumParams() == 2 && + "Unexpected deallocation function type!"); + return true; +} + +CharUnits ItaniumCXXABI::GetArrayCookieSize(QualType ElementType) { + if (!NeedsArrayCookie(ElementType)) + return CharUnits::Zero(); + + // Padding is the maximum of sizeof(size_t) and alignof(ElementType) + ASTContext &Ctx = getContext(); + return std::max(Ctx.getTypeSizeInChars(Ctx.getSizeType()), + Ctx.getTypeAlignInChars(ElementType)); +} + +llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, + llvm::Value *NewPtr, + llvm::Value *NumElements, + QualType ElementType) { + assert(NeedsArrayCookie(ElementType)); + + unsigned AS = cast(NewPtr->getType())->getAddressSpace(); + + ASTContext &Ctx = getContext(); + QualType SizeTy = Ctx.getSizeType(); + CharUnits SizeSize = Ctx.getTypeSizeInChars(SizeTy); + + // The size of the cookie. + CharUnits CookieSize = + std::max(SizeSize, Ctx.getTypeAlignInChars(ElementType)); + + // Compute an offset to the cookie. + llvm::Value *CookiePtr = NewPtr; + CharUnits CookieOffset = CookieSize - SizeSize; + if (!CookieOffset.isZero()) + CookiePtr = CGF.Builder.CreateConstInBoundsGEP1_64(CookiePtr, + CookieOffset.getQuantity()); + + // Write the number of elements into the appropriate slot. + llvm::Value *NumElementsPtr + = CGF.Builder.CreateBitCast(CookiePtr, + CGF.ConvertType(SizeTy)->getPointerTo(AS)); + CGF.Builder.CreateStore(NumElements, NumElementsPtr); + + // Finally, compute a pointer to the actual data buffer by skipping + // over the cookie completely. + return CGF.Builder.CreateConstInBoundsGEP1_64(NewPtr, + CookieSize.getQuantity()); +} + +void ItaniumCXXABI::ReadArrayCookie(CodeGenFunction &CGF, + llvm::Value *Ptr, + QualType ElementType, + llvm::Value *&NumElements, + llvm::Value *&AllocPtr, + CharUnits &CookieSize) { + // Derive a char* in the same address space as the pointer. + unsigned AS = cast(Ptr->getType())->getAddressSpace(); + const llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS); + + // If we don't need an array cookie, bail out early. + if (!NeedsArrayCookie(ElementType)) { + AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy); + NumElements = 0; + CookieSize = CharUnits::Zero(); + return; + } + + QualType SizeTy = getContext().getSizeType(); + CharUnits SizeSize = getContext().getTypeSizeInChars(SizeTy); + const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy); + + CookieSize + = std::max(SizeSize, getContext().getTypeAlignInChars(ElementType)); + + CharUnits NumElementsOffset = CookieSize - SizeSize; + + // Compute the allocated pointer. + AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy); + AllocPtr = CGF.Builder.CreateConstInBoundsGEP1_64(AllocPtr, + -CookieSize.getQuantity()); + + llvm::Value *NumElementsPtr = AllocPtr; + if (!NumElementsOffset.isZero()) + NumElementsPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(NumElementsPtr, + NumElementsOffset.getQuantity()); + NumElementsPtr = + CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo(AS)); + NumElements = CGF.Builder.CreateLoad(NumElementsPtr); +} + +CharUnits ARMCXXABI::GetArrayCookieSize(QualType ElementType) { + if (!NeedsArrayCookie(ElementType)) + return CharUnits::Zero(); + + // On ARM, the cookie is always: + // struct array_cookie { + // std::size_t element_size; // element_size != 0 + // std::size_t element_count; + // }; + // TODO: what should we do if the allocated type actually wants + // greater alignment? + return getContext().getTypeSizeInChars(getContext().getSizeType()) * 2; +} + +llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, + llvm::Value *NewPtr, + llvm::Value *NumElements, + QualType ElementType) { + assert(NeedsArrayCookie(ElementType)); + + // NewPtr is a char*. + + unsigned AS = cast(NewPtr->getType())->getAddressSpace(); + + ASTContext &Ctx = getContext(); + CharUnits SizeSize = Ctx.getTypeSizeInChars(Ctx.getSizeType()); + const llvm::IntegerType *SizeTy = + cast(CGF.ConvertType(Ctx.getSizeType())); + + // The cookie is always at the start of the buffer. + llvm::Value *CookiePtr = NewPtr; + + // The first element is the element size. + CookiePtr = CGF.Builder.CreateBitCast(CookiePtr, SizeTy->getPointerTo(AS)); + llvm::Value *ElementSize = llvm::ConstantInt::get(SizeTy, + Ctx.getTypeSizeInChars(ElementType).getQuantity()); + CGF.Builder.CreateStore(ElementSize, CookiePtr); + + // The second element is the element count. + CookiePtr = CGF.Builder.CreateConstInBoundsGEP1_32(CookiePtr, 1); + CGF.Builder.CreateStore(NumElements, CookiePtr); + + // Finally, compute a pointer to the actual data buffer by skipping + // over the cookie completely. + CharUnits CookieSize = 2 * SizeSize; + return CGF.Builder.CreateConstInBoundsGEP1_64(NewPtr, + CookieSize.getQuantity()); +} + +void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF, + llvm::Value *Ptr, + QualType ElementType, + llvm::Value *&NumElements, + llvm::Value *&AllocPtr, + CharUnits &CookieSize) { + // Derive a char* in the same address space as the pointer. + unsigned AS = cast(Ptr->getType())->getAddressSpace(); + const llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS); + + // If we don't need an array cookie, bail out early. + if (!NeedsArrayCookie(ElementType)) { + AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy); + NumElements = 0; + CookieSize = CharUnits::Zero(); + return; + } + + QualType SizeTy = getContext().getSizeType(); + CharUnits SizeSize = getContext().getTypeSizeInChars(SizeTy); + const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy); + + // The cookie size is always 2 * sizeof(size_t). + CookieSize = 2 * SizeSize; + CharUnits NumElementsOffset = CookieSize - SizeSize; + + // The allocated pointer is the input ptr, minus that amount. + AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy); + AllocPtr = CGF.Builder.CreateConstInBoundsGEP1_64(AllocPtr, + -CookieSize.getQuantity()); + + // The number of elements is at offset sizeof(size_t) relative to that. + llvm::Value *NumElementsPtr + = CGF.Builder.CreateConstInBoundsGEP1_64(AllocPtr, + SizeSize.getQuantity()); + NumElementsPtr = + CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo(AS)); + NumElements = CGF.Builder.CreateLoad(NumElementsPtr); +} + diff --git a/lib/CodeGen/Makefile b/lib/CodeGen/Makefile index 4b93524..6032dff 100644 --- a/lib/CodeGen/Makefile +++ b/lib/CodeGen/Makefile @@ -14,7 +14,6 @@ CLANG_LEVEL := ../.. LIBRARYNAME := clangCodeGen -BUILD_ARCHIVE = 1 include $(CLANG_LEVEL)/Makefile diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 30ee541..e198874 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -241,11 +241,11 @@ private: NestedNameSpecifier *Qualifier, DeclarationName Name, unsigned KnownArity); - void mangleCalledExpression(const Expr *E, unsigned KnownArity); - void mangleExpression(const Expr *E); + void mangleExpression(const Expr *E, unsigned Arity = UnknownArity); void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); + void mangleTemplateArgs(const ExplicitTemplateArgumentList &TemplateArgs); void mangleTemplateArgs(TemplateName Template, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -304,6 +304,10 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { return false; } + // Class members are always mangled. + if (D->getDeclContext()->isRecord()) + return true; + // C functions and "main" are not mangled. if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) return false; @@ -695,7 +699,11 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // a program to refer to the anonymous union, and there is therefore no // need to mangle its name. const FieldDecl *FD = FindFirstNamedDataMember(RD); - assert(FD && "Didn't find a named data member!"); + + // It's actually possible for various reasons for us to get here + // with an empty anonymous struct / union. Fortunately, it + // doesn't really matter what name we generate. + if (!FD) break; assert(FD->getIdentifier() && "Data member name isn't an identifier!"); mangleSourceName(FD->getIdentifier()); @@ -1016,24 +1024,21 @@ CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { // ::= da # delete[] case OO_Array_Delete: Out << "da"; break; // ::= ps # + (unary) - // ::= pl # + + // ::= pl # + (binary or unknown) case OO_Plus: - assert((Arity == 1 || Arity == 2) && "Invalid arity!"); Out << (Arity == 1? "ps" : "pl"); break; // ::= ng # - (unary) - // ::= mi # - + // ::= mi # - (binary or unknown) case OO_Minus: - assert((Arity == 1 || Arity == 2) && "Invalid arity!"); Out << (Arity == 1? "ng" : "mi"); break; // ::= ad # & (unary) - // ::= an # & + // ::= an # & (binary or unknown) case OO_Amp: - assert((Arity == 1 || Arity == 2) && "Invalid arity!"); Out << (Arity == 1? "ad" : "an"); break; // ::= de # * (unary) - // ::= ml # * + // ::= ml # * (binary or unknown) case OO_Star: - assert((Arity == 1 || Arity == 2) && "Invalid arity!"); + // Use binary when unknown. Out << (Arity == 1? "de" : "ml"); break; // ::= co # ~ case OO_Tilde: Out << "co"; break; @@ -1275,7 +1280,7 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, mangleType(Proto->getResultType()); if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) { - // ::= v # void + // ::= v # void Out << 'v'; return; } @@ -1536,25 +1541,6 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T, } -void CXXNameMangler::mangleCalledExpression(const Expr *E, unsigned Arity) { - if (E->getType() != getASTContext().OverloadTy) - mangleExpression(E); - // propagate arity to dependent overloads? - - llvm::PointerIntPair R - = OverloadExpr::find(const_cast(E)); - if (R.getInt()) - Out << "an"; // & - const OverloadExpr *Ovl = R.getPointer(); - if (const UnresolvedMemberExpr *ME = dyn_cast(Ovl)) { - mangleMemberExpr(ME->getBase(), ME->isArrow(), ME->getQualifier(), - ME->getMemberName(), Arity); - return; - } - - mangleUnresolvedName(Ovl->getQualifier(), Ovl->getName(), Arity); -} - /// Mangles a member expression. Implicit accesses are not handled, /// but that should be okay, because you shouldn't be able to /// make an implicit access in a function template declaration. @@ -1570,14 +1556,14 @@ void CXXNameMangler::mangleMemberExpr(const Expr *Base, mangleUnresolvedName(Qualifier, Member, Arity); } -void CXXNameMangler::mangleExpression(const Expr *E) { +void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { // ::= // ::= // ::= - // ::= cl * E # call + // ::= cl * E # call // ::= cv expression # conversion with one argument // ::= cv _ * E # conversion with a different number of arguments - // ::= st # sizeof (a type) + // ::= st # sizeof (a type) // ::= at # alignof (a type) // ::= // ::= @@ -1644,14 +1630,14 @@ void CXXNameMangler::mangleExpression(const Expr *E) { } case Expr::CXXDefaultArgExprClass: - mangleExpression(cast(E)->getExpr()); + mangleExpression(cast(E)->getExpr(), Arity); break; case Expr::CXXMemberCallExprClass: // fallthrough case Expr::CallExprClass: { const CallExpr *CE = cast(E); Out << "cl"; - mangleCalledExpression(CE->getCallee(), CE->getNumArgs()); + mangleExpression(CE->getCallee(), CE->getNumArgs()); for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I) mangleExpression(CE->getArg(I)); Out << 'E'; @@ -1682,7 +1668,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) { const MemberExpr *ME = cast(E); mangleMemberExpr(ME->getBase(), ME->isArrow(), ME->getQualifier(), ME->getMemberDecl()->getDeclName(), - UnknownArity); + Arity); break; } @@ -1690,7 +1676,9 @@ void CXXNameMangler::mangleExpression(const Expr *E) { const UnresolvedMemberExpr *ME = cast(E); mangleMemberExpr(ME->getBase(), ME->isArrow(), ME->getQualifier(), ME->getMemberName(), - UnknownArity); + Arity); + if (ME->hasExplicitTemplateArgs()) + mangleTemplateArgs(ME->getExplicitTemplateArgs()); break; } @@ -1699,7 +1687,9 @@ void CXXNameMangler::mangleExpression(const Expr *E) { = cast(E); mangleMemberExpr(ME->getBase(), ME->isArrow(), ME->getQualifier(), ME->getMember(), - UnknownArity); + Arity); + if (ME->hasExplicitTemplateArgs()) + mangleTemplateArgs(ME->getExplicitTemplateArgs()); break; } @@ -1708,7 +1698,9 @@ void CXXNameMangler::mangleExpression(const Expr *E) { // using something as close as possible to the original lookup // expression. const UnresolvedLookupExpr *ULE = cast(E); - mangleUnresolvedName(ULE->getQualifier(), ULE->getName(), UnknownArity); + mangleUnresolvedName(ULE->getQualifier(), ULE->getName(), Arity); + if (ULE->hasExplicitTemplateArgs()) + mangleTemplateArgs(ULE->getExplicitTemplateArgs()); break; } @@ -1821,13 +1813,13 @@ void CXXNameMangler::mangleExpression(const Expr *E) { const ConditionalOperator *CO = cast(E); mangleOperatorName(OO_Conditional, /*Arity=*/3); mangleExpression(CO->getCond()); - mangleExpression(CO->getLHS()); - mangleExpression(CO->getRHS()); + mangleExpression(CO->getLHS(), Arity); + mangleExpression(CO->getRHS(), Arity); break; } case Expr::ImplicitCastExprClass: { - mangleExpression(cast(E)->getSubExpr()); + mangleExpression(cast(E)->getSubExpr(), Arity); break; } @@ -1855,7 +1847,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) { } case Expr::ParenExprClass: - mangleExpression(cast(E)->getSubExpr()); + mangleExpression(cast(E)->getSubExpr(), Arity); break; case Expr::DeclRefExprClass: { @@ -1869,6 +1861,12 @@ void CXXNameMangler::mangleExpression(const Expr *E) { Out << 'E'; break; + case Decl::EnumConstant: { + const EnumConstantDecl *ED = cast(D); + mangleIntegerLiteral(ED->getType(), ED->getInitVal()); + break; + } + case Decl::NonTypeTemplateParm: { const NonTypeTemplateParmDecl *PD = cast(D); mangleTemplateParameter(PD->getIndex()); @@ -1897,27 +1895,23 @@ void CXXNameMangler::mangleExpression(const Expr *E) { } assert(QTy && "Qualifier was not type!"); - // ::= sr # dependent name + // ::= sr # dependent name + // ::= sr # dependent template-id Out << "sr"; mangleType(QualType(QTy, 0)); - - assert(DRE->getDeclName().getNameKind() == DeclarationName::Identifier && - "Unhandled decl name kind!"); - mangleSourceName(DRE->getDeclName().getAsIdentifierInfo()); + mangleUnqualifiedName(0, DRE->getDeclName(), Arity); + if (DRE->hasExplicitTemplateArgs()) + mangleTemplateArgs(DRE->getExplicitTemplateArgs()); break; } - case Expr::CXXBindReferenceExprClass: - mangleExpression(cast(E)->getSubExpr()); - break; - case Expr::CXXBindTemporaryExprClass: mangleExpression(cast(E)->getSubExpr()); break; case Expr::CXXExprWithTemporariesClass: - mangleExpression(cast(E)->getSubExpr()); + mangleExpression(cast(E)->getSubExpr(), Arity); break; case Expr::FloatingLiteralClass: { @@ -1974,13 +1968,10 @@ void CXXNameMangler::mangleExpression(const Expr *E) { } case Expr::StringLiteralClass: { - // Proposal from David Vandervoorde, 2010.06.30. - // I've sent a comment off asking whether this needs to also - // represent the length of the string. + // Revised proposal from David Vandervoorde, 2010.07.15. Out << 'L'; - const ConstantArrayType *T = cast(E->getType()); - QualType CharTy = T->getElementType().getUnqualifiedType(); - mangleType(CharTy); + assert(isa(E->getType())); + mangleType(E->getType()); Out << 'E'; break; } @@ -2035,6 +2026,15 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { } } +void CXXNameMangler::mangleTemplateArgs( + const ExplicitTemplateArgumentList &TemplateArgs) { + // ::= I + E + Out << 'I'; + for (unsigned I = 0, E = TemplateArgs.NumTemplateArgs; I != E; ++I) + mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[I].getArgument()); + Out << 'E'; +} + void CXXNameMangler::mangleTemplateArgs(TemplateName Template, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index da0fdb6..9407335 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -41,8 +41,6 @@ public: MicrosoftCXXNameMangler(MangleContext &C, llvm::SmallVectorImpl &Res) : Context(C), Out(Res) { } - llvm::raw_svector_ostream &getStream() { return Out; } - void mangle(const NamedDecl *D, llvm::StringRef Prefix = "?"); void mangleName(const NamedDecl *ND); void mangleFunctionEncoding(const FunctionDecl *FD); @@ -110,15 +108,43 @@ public: llvm::SmallVectorImpl &); }; -class MicrosoftCXXABI : public CXXABI { +class MicrosoftCXXABI : public CGCXXABI { MicrosoftMangleContext MangleCtx; public: MicrosoftCXXABI(CodeGenModule &CGM) - : MangleCtx(CGM.getContext(), CGM.getDiags()) {} + : CGCXXABI(CGM), MangleCtx(CGM.getContext(), CGM.getDiags()) {} MicrosoftMangleContext &getMangleContext() { return MangleCtx; } + + void BuildConstructorSignature(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) { + // 'this' is already in place + // TODO: 'for base' flag + } + + void BuildDestructorSignature(const CXXDestructorDecl *Ctor, + CXXDtorType Type, + CanQualType &ResTy, + llvm::SmallVectorImpl &ArgTys) { + // 'this' is already in place + // TODO: 'for base' flag + } + + void BuildInstanceFunctionParams(CodeGenFunction &CGF, + QualType &ResTy, + FunctionArgList &Params) { + BuildThisParam(CGF, Params); + // TODO: 'for base' flag + } + + void EmitInstanceFunctionProlog(CodeGenFunction &CGF) { + EmitThisParam(CGF); + // TODO: 'for base' flag + } }; } @@ -893,6 +919,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { switch (T->getCallConv()) { case CC_Default: case CC_C: Out << 'A'; break; + case CC_X86Pascal: Out << 'C'; break; case CC_X86ThisCall: Out << 'E'; break; case CC_X86StdCall: Out << 'G'; break; case CC_X86FastCall: Out << 'I'; break; @@ -1185,7 +1212,7 @@ void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, assert(false && "Can't yet mangle destructors!"); } -CXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) { +CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) { return new MicrosoftCXXABI(CGM); } diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index c65f203..4d221d4 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -36,14 +36,36 @@ static void AssignToArrayRange(CodeGen::CGBuilderTy &Builder, } } +static bool isAggregateTypeForABI(QualType T) { + return CodeGenFunction::hasAggregateLLVMType(T) || + T->isMemberFunctionPointerType(); +} + ABIInfo::~ABIInfo() {} +ASTContext &ABIInfo::getContext() const { + return CGT.getContext(); +} + +llvm::LLVMContext &ABIInfo::getVMContext() const { + return CGT.getLLVMContext(); +} + +const llvm::TargetData &ABIInfo::getTargetData() const { + return CGT.getTargetData(); +} + + void ABIArgInfo::dump() const { llvm::raw_ostream &OS = llvm::errs(); OS << "(ABIArgInfo Kind="; switch (TheKind) { case Direct: - OS << "Direct"; + OS << "Direct Type="; + if (const llvm::Type *Ty = getCoerceToType()) + Ty->print(OS); + else + OS << "null"; break; case Extend: OS << "Extend"; @@ -51,10 +73,6 @@ void ABIArgInfo::dump() const { case Ignore: OS << "Ignore"; break; - case Coerce: - OS << "Coerce Type="; - getCoerceToType()->print(OS); - break; case Indirect: OS << "Indirect Align=" << getIndirectAlign() << " Byal=" << getIndirectByVal(); @@ -129,7 +147,7 @@ static bool hasNonTrivialDestructorOrCopyConstructor(const RecordType *RT) { const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); if (!RD) return false; - + return !RD->hasTrivialDestructor() || !RD->hasTrivialCopyConstructor(); } @@ -162,7 +180,7 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { return 0; const Type *Found = 0; - + // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(), @@ -205,7 +223,7 @@ static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { FT = AT->getElementType(); } - if (!CodeGenFunction::hasAggregateLLVMType(FT)) { + if (!isAggregateTypeForABI(FT)) { Found = FT.getTypePtr(); } else { Found = isSingleElementStruct(FT, Context); @@ -272,23 +290,17 @@ namespace { /// self-consistent and sensible LLVM IR generation, but does not /// conform to any particular ABI. class DefaultABIInfo : public ABIInfo { - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext, - const llvm::Type *const *PrefTypes, - unsigned NumPrefTypes) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, - VMContext); +public: + DefaultABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} + + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType RetTy) const; + + virtual void computeInfo(CGFunctionInfo &FI) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) - it->info = classifyArgumentType(it->type, Context, VMContext); + it->info = classifyArgumentType(it->type); } virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -297,7 +309,8 @@ class DefaultABIInfo : public ABIInfo { class DefaultTargetCodeGenInfo : public TargetCodeGenInfo { public: - DefaultTargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {} + DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) + : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {} }; llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -305,10 +318,8 @@ llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, return 0; } -ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (CodeGenFunction::hasAggregateLLVMType(Ty)) +ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const { + if (isAggregateTypeForABI(Ty)) return ABIArgInfo::getIndirect(0); // Treat an enum type as its underlying type. @@ -322,10 +333,9 @@ ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty, //===----------------------------------------------------------------------===// // X86-32 ABI Implementation //===----------------------------------------------------------------------===// - + /// X86_32ABIInfo - The X86-32 ABI information. class X86_32ABIInfo : public ABIInfo { - ASTContext &Context; bool IsDarwinVectorABI; bool IsSmallStructInRegABI; @@ -337,41 +347,31 @@ class X86_32ABIInfo : public ABIInfo { /// getIndirectResult - Give a source type \arg Ty, return a suitable result /// such that the argument will be passed in memory. - ABIArgInfo getIndirectResult(QualType Ty, ASTContext &Context, - bool ByVal = true) const; + ABIArgInfo getIndirectResult(QualType Ty, bool ByVal = true) const; public: - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext, - const llvm::Type *const *PrefTypes, - unsigned NumPrefTypes) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, - VMContext); + + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType RetTy) const; + + virtual void computeInfo(CGFunctionInfo &FI) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) - it->info = classifyArgumentType(it->type, Context, VMContext); + it->info = classifyArgumentType(it->type); } virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const; - X86_32ABIInfo(ASTContext &Context, bool d, bool p) - : ABIInfo(), Context(Context), IsDarwinVectorABI(d), - IsSmallStructInRegABI(p) {} + X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p) + : ABIInfo(CGT), IsDarwinVectorABI(d), IsSmallStructInRegABI(p) {} }; class X86_32TargetCodeGenInfo : public TargetCodeGenInfo { public: - X86_32TargetCodeGenInfo(ASTContext &Context, bool d, bool p) - :TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {} + X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool d, bool p) + :TargetCodeGenInfo(new X86_32ABIInfo(CGT, d, p)) {} void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const; @@ -443,153 +443,172 @@ bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, return true; } -ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (RetTy->isVoidType()) { +ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); - } else if (const VectorType *VT = RetTy->getAs()) { + + if (const VectorType *VT = RetTy->getAs()) { // On Darwin, some vectors are returned in registers. if (IsDarwinVectorABI) { - uint64_t Size = Context.getTypeSize(RetTy); + uint64_t Size = getContext().getTypeSize(RetTy); // 128-bit vectors are a special case; they are returned in // registers and we need to make sure to pick a type the LLVM // backend will like. if (Size == 128) - return ABIArgInfo::getCoerce(llvm::VectorType::get( - llvm::Type::getInt64Ty(VMContext), 2)); + return ABIArgInfo::getDirect(llvm::VectorType::get( + llvm::Type::getInt64Ty(getVMContext()), 2)); // Always return in register if it fits in a general purpose // register, or if it is 64 bits and has a single element. if ((Size == 8 || Size == 16 || Size == 32) || (Size == 64 && VT->getNumElements() == 1)) - return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size)); + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), + Size)); return ABIArgInfo::getIndirect(0); } return ABIArgInfo::getDirect(); - } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { + } + + if (isAggregateTypeForABI(RetTy)) { if (const RecordType *RT = RetTy->getAs()) { // Structures with either a non-trivial destructor or a non-trivial // copy constructor are always indirect. if (hasNonTrivialDestructorOrCopyConstructor(RT)) return ABIArgInfo::getIndirect(0, /*ByVal=*/false); - + // Structures with flexible arrays are always indirect. if (RT->getDecl()->hasFlexibleArrayMember()) return ABIArgInfo::getIndirect(0); } - + // If specified, structs and unions are always indirect. if (!IsSmallStructInRegABI && !RetTy->isAnyComplexType()) return ABIArgInfo::getIndirect(0); // Classify "single element" structs as their element type. - if (const Type *SeltTy = isSingleElementStruct(RetTy, Context)) { + if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) { if (const BuiltinType *BT = SeltTy->getAs()) { if (BT->isIntegerType()) { // We need to use the size of the structure, padding // bit-fields can adjust that to be larger than the single // element type. - uint64_t Size = Context.getTypeSize(RetTy); - return ABIArgInfo::getCoerce( - llvm::IntegerType::get(VMContext, (unsigned) Size)); - } else if (BT->getKind() == BuiltinType::Float) { - assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) && + uint64_t Size = getContext().getTypeSize(RetTy); + return ABIArgInfo::getDirect( + llvm::IntegerType::get(getVMContext(), (unsigned)Size)); + } + + if (BT->getKind() == BuiltinType::Float) { + assert(getContext().getTypeSize(RetTy) == + getContext().getTypeSize(SeltTy) && "Unexpect single element structure size!"); - return ABIArgInfo::getCoerce(llvm::Type::getFloatTy(VMContext)); - } else if (BT->getKind() == BuiltinType::Double) { - assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) && + return ABIArgInfo::getDirect(llvm::Type::getFloatTy(getVMContext())); + } + + if (BT->getKind() == BuiltinType::Double) { + assert(getContext().getTypeSize(RetTy) == + getContext().getTypeSize(SeltTy) && "Unexpect single element structure size!"); - return ABIArgInfo::getCoerce(llvm::Type::getDoubleTy(VMContext)); + return ABIArgInfo::getDirect(llvm::Type::getDoubleTy(getVMContext())); } } else if (SeltTy->isPointerType()) { // FIXME: It would be really nice if this could come out as the proper // pointer type. - const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext); - return ABIArgInfo::getCoerce(PtrTy); + const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(getVMContext()); + return ABIArgInfo::getDirect(PtrTy); } else if (SeltTy->isVectorType()) { // 64- and 128-bit vectors are never returned in a // register when inside a structure. - uint64_t Size = Context.getTypeSize(RetTy); + uint64_t Size = getContext().getTypeSize(RetTy); if (Size == 64 || Size == 128) return ABIArgInfo::getIndirect(0); - return classifyReturnType(QualType(SeltTy, 0), Context, VMContext); + return classifyReturnType(QualType(SeltTy, 0)); } } // Small structures which are register sized are generally returned // in a register. - if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, Context)) { - uint64_t Size = Context.getTypeSize(RetTy); - return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size)); + if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, getContext())) { + uint64_t Size = getContext().getTypeSize(RetTy); + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),Size)); } return ABIArgInfo::getIndirect(0); - } else { - // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = RetTy->getAs()) - RetTy = EnumTy->getDecl()->getIntegerType(); - - return (RetTy->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } + + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = RetTy->getAs()) + RetTy = EnumTy->getDecl()->getIntegerType(); + + return (RetTy->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } -ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, - ASTContext &Context, - bool ByVal) const { +ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal) const { if (!ByVal) return ABIArgInfo::getIndirect(0, false); // Compute the byval alignment. We trust the back-end to honor the // minimum ABI alignment for byval, to make cleaner IR. const unsigned MinABIAlign = 4; - unsigned Align = Context.getTypeAlign(Ty) / 8; + unsigned Align = getContext().getTypeAlign(Ty) / 8; if (Align > MinABIAlign) return ABIArgInfo::getIndirect(Align); return ABIArgInfo::getIndirect(0); } -ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { +ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const { // FIXME: Set alignment on indirect arguments. - if (CodeGenFunction::hasAggregateLLVMType(Ty)) { + if (isAggregateTypeForABI(Ty)) { // Structures with flexible arrays are always indirect. if (const RecordType *RT = Ty->getAs()) { // Structures with either a non-trivial destructor or a non-trivial // copy constructor are always indirect. if (hasNonTrivialDestructorOrCopyConstructor(RT)) - return getIndirectResult(Ty, Context, /*ByVal=*/false); + return getIndirectResult(Ty, /*ByVal=*/false); if (RT->getDecl()->hasFlexibleArrayMember()) - return getIndirectResult(Ty, Context); + return getIndirectResult(Ty); } // Ignore empty structs. - if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0) + if (Ty->isStructureType() && getContext().getTypeSize(Ty) == 0) return ABIArgInfo::getIgnore(); // Expand small (<= 128-bit) record types when we know that the stack layout // of those arguments will match the struct. This is important because the // LLVM backend isn't smart enough to remove byval, which inhibits many // optimizations. - if (Context.getTypeSize(Ty) <= 4*32 && - canExpandIndirectArgument(Ty, Context)) + if (getContext().getTypeSize(Ty) <= 4*32 && + canExpandIndirectArgument(Ty, getContext())) return ABIArgInfo::getExpand(); - return getIndirectResult(Ty, Context); - } else { - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getDecl()->getIntegerType(); + return getIndirectResult(Ty); + } - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + if (const VectorType *VT = Ty->getAs()) { + // On Darwin, some vectors are passed in memory, we handle this by passing + // it as an i8/i16/i32/i64. + if (IsDarwinVectorABI) { + uint64_t Size = getContext().getTypeSize(Ty); + if ((Size == 8 || Size == 16 || Size == 32) || + (Size == 64 && VT->getNumElements() == 1)) + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), + Size)); + } + + return ABIArgInfo::getDirect(); } + + + if (const EnumType *EnumTy = Ty->getAs()) + Ty = EnumTy->getDecl()->getIntegerType(); + + return (Ty->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -637,7 +656,7 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable( const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); - + // 0-7 are the eight integer registers; the order is different // on Darwin (for EH), but the range is the same. // 8 is %eip. @@ -649,7 +668,7 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable( // platforms with 8-byte alignment for that type. llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16); AssignToArrayRange(Builder, Address, Sixteen8, 12, 16); - + } else { // 9 is %eflags, which doesn't get a size on Darwin for some // reason. @@ -673,9 +692,6 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable( namespace { /// X86_64ABIInfo - The X86_64 ABI information. class X86_64ABIInfo : public ABIInfo { - ASTContext &Context; - const llvm::TargetData &TD; - enum Class { Integer = 0, SSE, @@ -721,17 +737,13 @@ class X86_64ABIInfo : public ABIInfo { /// also be ComplexX87. void classify(QualType T, uint64_t OffsetBase, Class &Lo, Class &Hi) const; - /// getCoerceResult - Given a source type \arg Ty and an LLVM type - /// to coerce to, chose the best way to pass Ty in the same place - /// that \arg CoerceTo would be passed, but while keeping the - /// emitted code as simple as possible. - /// - /// FIXME: Note, this should be cleaned up to just take an enumeration of all - /// the ways we might want to pass things, instead of constructing an LLVM - /// type. This makes this code more explicit, and it makes it clearer that we - /// are also doing this for correctness in the case of passing scalar types. - ABIArgInfo getCoerceResult(QualType Ty, - const llvm::Type *CoerceTo) const; + const llvm::Type *Get16ByteVectorType(QualType Ty) const; + const llvm::Type *GetSSETypeAtOffset(const llvm::Type *IRType, + unsigned IROffset, QualType SourceTy, + unsigned SourceOffset) const; + const llvm::Type *GetINTEGERTypeAtOffset(const llvm::Type *IRType, + unsigned IROffset, QualType SourceTy, + unsigned SourceOffset) const; /// getIndirectResult - Give a source type \arg Ty, return a suitable result /// such that the argument will be returned in memory. @@ -741,23 +753,24 @@ class X86_64ABIInfo : public ABIInfo { /// such that the argument will be passed in memory. ABIArgInfo getIndirectResult(QualType Ty) const; - ABIArgInfo classifyReturnType(QualType RetTy, - llvm::LLVMContext &VMContext) const; + ABIArgInfo classifyReturnType(QualType RetTy) const; - ABIArgInfo classifyArgumentType(QualType Ty, - llvm::LLVMContext &VMContext, - unsigned &neededInt, - unsigned &neededSSE, - const llvm::Type *PrefType) const; + ABIArgInfo classifyArgumentType(QualType Ty, unsigned &neededInt, + unsigned &neededSSE) const; public: - X86_64ABIInfo(ASTContext &Ctx, const llvm::TargetData &td) - : Context(Ctx), TD(td) {} + X86_64ABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} + + virtual void computeInfo(CGFunctionInfo &FI) const; + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext, - const llvm::Type *const *PrefTypes, - unsigned NumPrefTypes) const; +/// WinX86_64ABIInfo - The Windows X86_64 ABI information. +class WinX86_64ABIInfo : public X86_64ABIInfo { +public: + WinX86_64ABIInfo(CodeGen::CodeGenTypes &CGT) : X86_64ABIInfo(CGT) {} virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const; @@ -765,8 +778,33 @@ public: class X86_64TargetCodeGenInfo : public TargetCodeGenInfo { public: - X86_64TargetCodeGenInfo(ASTContext &Ctx, const llvm::TargetData &TD) - : TargetCodeGenInfo(new X86_64ABIInfo(Ctx, TD)) {} + X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) + : TargetCodeGenInfo(new X86_64ABIInfo(CGT)) {} + + int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const { + return 7; + } + + bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const { + CodeGen::CGBuilderTy &Builder = CGF.Builder; + llvm::LLVMContext &Context = CGF.getLLVMContext(); + + const llvm::IntegerType *i8 = llvm::Type::getInt8Ty(Context); + llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); + + // 0-15 are the 16 integer registers. + // 16 is %rip. + AssignToArrayRange(Builder, Address, Eight8, 0, 16); + + return false; + } +}; + +class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo { +public: + WinX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) + : TargetCodeGenInfo(new WinX86_64ABIInfo(CGT)) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const { return 7; @@ -865,18 +903,18 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, // FIXME: _float128 and _Decimal128 are (SSE, SSEUp). return; } - + if (const EnumType *ET = Ty->getAs()) { // Classify the underlying integer type. classify(ET->getDecl()->getIntegerType(), OffsetBase, Lo, Hi); return; } - + if (Ty->hasPointerRepresentation()) { Current = Integer; return; } - + if (Ty->isMemberPointerType()) { if (Ty->isMemberFunctionPointerType()) Lo = Hi = Integer; @@ -884,9 +922,9 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Current = Integer; return; } - + if (const VectorType *VT = Ty->getAs()) { - uint64_t Size = Context.getTypeSize(VT); + uint64_t Size = getContext().getTypeSize(VT); if (Size == 32) { // gcc passes all <4 x char>, <2 x short>, <1 x int>, <1 x // float> as integer. @@ -904,7 +942,10 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, return; // gcc passes <1 x long long> as INTEGER. - if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::LongLong)) + if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::LongLong) || + VT->getElementType()->isSpecificBuiltinType(BuiltinType::ULongLong) || + VT->getElementType()->isSpecificBuiltinType(BuiltinType::Long) || + VT->getElementType()->isSpecificBuiltinType(BuiltinType::ULong)) Current = Integer; else Current = SSE; @@ -919,37 +960,37 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, } return; } - + if (const ComplexType *CT = Ty->getAs()) { - QualType ET = Context.getCanonicalType(CT->getElementType()); + QualType ET = getContext().getCanonicalType(CT->getElementType()); - uint64_t Size = Context.getTypeSize(Ty); + uint64_t Size = getContext().getTypeSize(Ty); if (ET->isIntegralOrEnumerationType()) { if (Size <= 64) Current = Integer; else if (Size <= 128) Lo = Hi = Integer; - } else if (ET == Context.FloatTy) + } else if (ET == getContext().FloatTy) Current = SSE; - else if (ET == Context.DoubleTy) + else if (ET == getContext().DoubleTy) Lo = Hi = SSE; - else if (ET == Context.LongDoubleTy) + else if (ET == getContext().LongDoubleTy) Current = ComplexX87; // If this complex type crosses an eightbyte boundary then it // should be split. uint64_t EB_Real = (OffsetBase) / 64; - uint64_t EB_Imag = (OffsetBase + Context.getTypeSize(ET)) / 64; + uint64_t EB_Imag = (OffsetBase + getContext().getTypeSize(ET)) / 64; if (Hi == NoClass && EB_Real != EB_Imag) Hi = Lo; - + return; } - - if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { + + if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) { // Arrays are treated like structures. - uint64_t Size = Context.getTypeSize(Ty); + uint64_t Size = getContext().getTypeSize(Ty); // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger // than two eightbytes, ..., it has class MEMORY. @@ -960,13 +1001,13 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, // fields, it has class MEMORY. // // Only need to check alignment of array base. - if (OffsetBase % Context.getTypeAlign(AT->getElementType())) + if (OffsetBase % getContext().getTypeAlign(AT->getElementType())) return; // Otherwise implement simplified merge. We could be smarter about // this, but it isn't worth it and would be harder to verify. Current = NoClass; - uint64_t EltSize = Context.getTypeSize(AT->getElementType()); + uint64_t EltSize = getContext().getTypeSize(AT->getElementType()); uint64_t ArraySize = AT->getSize().getZExtValue(); for (uint64_t i=0, Offset=OffsetBase; igetAs()) { - uint64_t Size = Context.getTypeSize(Ty); + uint64_t Size = getContext().getTypeSize(Ty); // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger // than two eightbytes, ..., it has class MEMORY. @@ -1004,7 +1045,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, if (RD->hasFlexibleArrayMember()) return; - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); // Reset Lo class, this will be recomputed. Current = NoClass; @@ -1031,10 +1072,6 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, if (Lo == Memory || Hi == Memory) break; } - - // If this record has no fields but isn't empty, classify as INTEGER. - if (RD->field_empty() && Size) - Current = Integer; } // Classify the fields one at a time, merging the results. @@ -1048,7 +1085,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, // fields, it has class MEMORY. // // Note, skip this test for bit-fields, see below. - if (!BitField && Offset % Context.getTypeAlign(i->getType())) { + if (!BitField && Offset % getContext().getTypeAlign(i->getType())) { Lo = Memory; return; } @@ -1070,7 +1107,8 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, continue; uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); - uint64_t Size = i->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + uint64_t Size = + i->getBitWidth()->EvaluateAsInt(getContext()).getZExtValue(); uint64_t EB_Lo = Offset / 64; uint64_t EB_Hi = (Offset + Size - 1) / 64; @@ -1110,52 +1148,10 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, } } -ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty, - const llvm::Type *CoerceTo) const { - if (CoerceTo->isIntegerTy(64) || isa(CoerceTo)) { - // Integer and pointer types will end up in a general purpose - // register. - - // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getDecl()->getIntegerType(); - - if (Ty->isIntegralOrEnumerationType() || Ty->hasPointerRepresentation()) - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - - // If this is a 8/16/32-bit structure that is passed as an int64, then it - // will be passed in the low 8/16/32-bits of a 64-bit GPR, which is the same - // as how an i8/i16/i32 is passed. Coerce to a i8/i16/i32 instead of a i64. - switch (Context.getTypeSizeInChars(Ty).getQuantity()) { - default: break; - case 1: CoerceTo = llvm::Type::getInt8Ty(CoerceTo->getContext()); break; - case 2: CoerceTo = llvm::Type::getInt16Ty(CoerceTo->getContext()); break; - case 4: CoerceTo = llvm::Type::getInt32Ty(CoerceTo->getContext()); break; - } - - } else if (CoerceTo->isDoubleTy()) { - assert(Ty.isCanonical() && "should always have a canonical type here"); - assert(!Ty.hasQualifiers() && "should never have a qualified type here"); - - // Float and double end up in a single SSE reg. - if (Ty == Context.FloatTy || Ty == Context.DoubleTy) - return ABIArgInfo::getDirect(); - - // If this is a 32-bit structure that is passed as a double, then it will be - // passed in the low 32-bits of the XMM register, which is the same as how a - // float is passed. Coerce to a float instead of a double. - if (Context.getTypeSizeInChars(Ty).getQuantity() == 4) - CoerceTo = llvm::Type::getFloatTy(CoerceTo->getContext()); - } - - return ABIArgInfo::getCoerce(CoerceTo); -} - ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const { // If this is a scalar LLVM value then assume LLVM will pass it in the right // place naturally. - if (!CodeGenFunction::hasAggregateLLVMType(Ty)) { + if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); @@ -1170,7 +1166,7 @@ ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const { ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty) const { // If this is a scalar LLVM value then assume LLVM will pass it in the right // place naturally. - if (!CodeGenFunction::hasAggregateLLVMType(Ty)) { + if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); @@ -1185,14 +1181,297 @@ ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty) const { // Compute the byval alignment. We trust the back-end to honor the // minimum ABI alignment for byval, to make cleaner IR. const unsigned MinABIAlign = 8; - unsigned Align = Context.getTypeAlign(Ty) / 8; + unsigned Align = getContext().getTypeAlign(Ty) / 8; if (Align > MinABIAlign) return ABIArgInfo::getIndirect(Align); return ABIArgInfo::getIndirect(0); } +/// Get16ByteVectorType - The ABI specifies that a value should be passed in an +/// full vector XMM register. Pick an LLVM IR type that will be passed as a +/// vector register. +const llvm::Type *X86_64ABIInfo::Get16ByteVectorType(QualType Ty) const { + const llvm::Type *IRType = CGT.ConvertTypeRecursive(Ty); + + // Wrapper structs that just contain vectors are passed just like vectors, + // strip them off if present. + const llvm::StructType *STy = dyn_cast(IRType); + while (STy && STy->getNumElements() == 1) { + IRType = STy->getElementType(0); + STy = dyn_cast(IRType); + } + + // If the preferred type is a 16-byte vector, prefer to pass it. + if (const llvm::VectorType *VT = dyn_cast(IRType)){ + const llvm::Type *EltTy = VT->getElementType(); + if (VT->getBitWidth() == 128 && + (EltTy->isFloatTy() || EltTy->isDoubleTy() || + EltTy->isIntegerTy(8) || EltTy->isIntegerTy(16) || + EltTy->isIntegerTy(32) || EltTy->isIntegerTy(64) || + EltTy->isIntegerTy(128))) + return VT; + } + + return llvm::VectorType::get(llvm::Type::getDoubleTy(getVMContext()), 2); +} + +/// BitsContainNoUserData - Return true if the specified [start,end) bit range +/// is known to either be off the end of the specified type or being in +/// alignment padding. The user type specified is known to be at most 128 bits +/// in size, and have passed through X86_64ABIInfo::classify with a successful +/// classification that put one of the two halves in the INTEGER class. +/// +/// It is conservatively correct to return false. +static bool BitsContainNoUserData(QualType Ty, unsigned StartBit, + unsigned EndBit, ASTContext &Context) { + // If the bytes being queried are off the end of the type, there is no user + // data hiding here. This handles analysis of builtins, vectors and other + // types that don't contain interesting padding. + unsigned TySize = (unsigned)Context.getTypeSize(Ty); + if (TySize <= StartBit) + return true; + + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { + unsigned EltSize = (unsigned)Context.getTypeSize(AT->getElementType()); + unsigned NumElts = (unsigned)AT->getSize().getZExtValue(); + + // Check each element to see if the element overlaps with the queried range. + for (unsigned i = 0; i != NumElts; ++i) { + // If the element is after the span we care about, then we're done.. + unsigned EltOffset = i*EltSize; + if (EltOffset >= EndBit) break; + + unsigned EltStart = EltOffset < StartBit ? StartBit-EltOffset :0; + if (!BitsContainNoUserData(AT->getElementType(), EltStart, + EndBit-EltOffset, Context)) + return false; + } + // If it overlaps no elements, then it is safe to process as padding. + return true; + } + + if (const RecordType *RT = Ty->getAs()) { + const RecordDecl *RD = RT->getDecl(); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // If this is a C++ record, check the bases first. + if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { + for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(), + e = CXXRD->bases_end(); i != e; ++i) { + assert(!i->isVirtual() && !i->getType()->isDependentType() && + "Unexpected base class!"); + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + + // If the base is after the span we care about, ignore it. + unsigned BaseOffset = (unsigned)Layout.getBaseClassOffset(Base); + if (BaseOffset >= EndBit) continue; + + unsigned BaseStart = BaseOffset < StartBit ? StartBit-BaseOffset :0; + if (!BitsContainNoUserData(i->getType(), BaseStart, + EndBit-BaseOffset, Context)) + return false; + } + } + + // Verify that no field has data that overlaps the region of interest. Yes + // this could be sped up a lot by being smarter about queried fields, + // however we're only looking at structs up to 16 bytes, so we don't care + // much. + unsigned idx = 0; + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i, ++idx) { + unsigned FieldOffset = (unsigned)Layout.getFieldOffset(idx); + + // If we found a field after the region we care about, then we're done. + if (FieldOffset >= EndBit) break; + + unsigned FieldStart = FieldOffset < StartBit ? StartBit-FieldOffset :0; + if (!BitsContainNoUserData(i->getType(), FieldStart, EndBit-FieldOffset, + Context)) + return false; + } + + // If nothing in this record overlapped the area of interest, then we're + // clean. + return true; + } + + return false; +} + +/// ContainsFloatAtOffset - Return true if the specified LLVM IR type has a +/// float member at the specified offset. For example, {int,{float}} has a +/// float at offset 4. It is conservatively correct for this routine to return +/// false. +static bool ContainsFloatAtOffset(const llvm::Type *IRType, unsigned IROffset, + const llvm::TargetData &TD) { + // Base case if we find a float. + if (IROffset == 0 && IRType->isFloatTy()) + return true; + + // If this is a struct, recurse into the field at the specified offset. + if (const llvm::StructType *STy = dyn_cast(IRType)) { + const llvm::StructLayout *SL = TD.getStructLayout(STy); + unsigned Elt = SL->getElementContainingOffset(IROffset); + IROffset -= SL->getElementOffset(Elt); + return ContainsFloatAtOffset(STy->getElementType(Elt), IROffset, TD); + } + + // If this is an array, recurse into the field at the specified offset. + if (const llvm::ArrayType *ATy = dyn_cast(IRType)) { + const llvm::Type *EltTy = ATy->getElementType(); + unsigned EltSize = TD.getTypeAllocSize(EltTy); + IROffset -= IROffset/EltSize*EltSize; + return ContainsFloatAtOffset(EltTy, IROffset, TD); + } + + return false; +} + + +/// GetSSETypeAtOffset - Return a type that will be passed by the backend in the +/// low 8 bytes of an XMM register, corresponding to the SSE class. +const llvm::Type *X86_64ABIInfo:: +GetSSETypeAtOffset(const llvm::Type *IRType, unsigned IROffset, + QualType SourceTy, unsigned SourceOffset) const { + // The only three choices we have are either double, <2 x float>, or float. We + // pass as float if the last 4 bytes is just padding. This happens for + // structs that contain 3 floats. + if (BitsContainNoUserData(SourceTy, SourceOffset*8+32, + SourceOffset*8+64, getContext())) + return llvm::Type::getFloatTy(getVMContext()); + + // We want to pass as <2 x float> if the LLVM IR type contains a float at + // offset+0 and offset+4. Walk the LLVM IR type to find out if this is the + // case. + if (ContainsFloatAtOffset(IRType, IROffset, getTargetData()) && + ContainsFloatAtOffset(IRType, IROffset+4, getTargetData())) + return llvm::VectorType::get(llvm::Type::getFloatTy(getVMContext()), 2); + + return llvm::Type::getDoubleTy(getVMContext()); +} + + +/// GetINTEGERTypeAtOffset - The ABI specifies that a value should be passed in +/// an 8-byte GPR. This means that we either have a scalar or we are talking +/// about the high or low part of an up-to-16-byte struct. This routine picks +/// the best LLVM IR type to represent this, which may be i64 or may be anything +/// else that the backend will pass in a GPR that works better (e.g. i8, %foo*, +/// etc). +/// +/// PrefType is an LLVM IR type that corresponds to (part of) the IR type for +/// the source type. IROffset is an offset in bytes into the LLVM IR type that +/// the 8-byte value references. PrefType may be null. +/// +/// SourceTy is the source level type for the entire argument. SourceOffset is +/// an offset into this that we're processing (which is always either 0 or 8). +/// +const llvm::Type *X86_64ABIInfo:: +GetINTEGERTypeAtOffset(const llvm::Type *IRType, unsigned IROffset, + QualType SourceTy, unsigned SourceOffset) const { + // If we're dealing with an un-offset LLVM IR type, then it means that we're + // returning an 8-byte unit starting with it. See if we can safely use it. + if (IROffset == 0) { + // Pointers and int64's always fill the 8-byte unit. + if (isa(IRType) || IRType->isIntegerTy(64)) + return IRType; + + // If we have a 1/2/4-byte integer, we can use it only if the rest of the + // goodness in the source type is just tail padding. This is allowed to + // kick in for struct {double,int} on the int, but not on + // struct{double,int,int} because we wouldn't return the second int. We + // have to do this analysis on the source type because we can't depend on + // unions being lowered a specific way etc. + if (IRType->isIntegerTy(8) || IRType->isIntegerTy(16) || + IRType->isIntegerTy(32)) { + unsigned BitWidth = cast(IRType)->getBitWidth(); + + if (BitsContainNoUserData(SourceTy, SourceOffset*8+BitWidth, + SourceOffset*8+64, getContext())) + return IRType; + } + } + + if (const llvm::StructType *STy = dyn_cast(IRType)) { + // If this is a struct, recurse into the field at the specified offset. + const llvm::StructLayout *SL = getTargetData().getStructLayout(STy); + if (IROffset < SL->getSizeInBytes()) { + unsigned FieldIdx = SL->getElementContainingOffset(IROffset); + IROffset -= SL->getElementOffset(FieldIdx); + + return GetINTEGERTypeAtOffset(STy->getElementType(FieldIdx), IROffset, + SourceTy, SourceOffset); + } + } + + if (const llvm::ArrayType *ATy = dyn_cast(IRType)) { + const llvm::Type *EltTy = ATy->getElementType(); + unsigned EltSize = getTargetData().getTypeAllocSize(EltTy); + unsigned EltOffset = IROffset/EltSize*EltSize; + return GetINTEGERTypeAtOffset(EltTy, IROffset-EltOffset, SourceTy, + SourceOffset); + } + + // Okay, we don't have any better idea of what to pass, so we pass this in an + // integer register that isn't too big to fit the rest of the struct. + unsigned TySizeInBytes = + (unsigned)getContext().getTypeSizeInChars(SourceTy).getQuantity(); + + assert(TySizeInBytes != SourceOffset && "Empty field?"); + + // It is always safe to classify this as an integer type up to i64 that + // isn't larger than the structure. + return llvm::IntegerType::get(getVMContext(), + std::min(TySizeInBytes-SourceOffset, 8U)*8); +} + + +/// GetX86_64ByValArgumentPair - Given a high and low type that can ideally +/// be used as elements of a two register pair to pass or return, return a +/// first class aggregate to represent them. For example, if the low part of +/// a by-value argument should be passed as i32* and the high part as float, +/// return {i32*, float}. +static const llvm::Type * +GetX86_64ByValArgumentPair(const llvm::Type *Lo, const llvm::Type *Hi, + const llvm::TargetData &TD) { + // In order to correctly satisfy the ABI, we need to the high part to start + // at offset 8. If the high and low parts we inferred are both 4-byte types + // (e.g. i32 and i32) then the resultant struct type ({i32,i32}) won't have + // the second element at offset 8. Check for this: + unsigned LoSize = (unsigned)TD.getTypeAllocSize(Lo); + unsigned HiAlign = TD.getABITypeAlignment(Hi); + unsigned HiStart = llvm::TargetData::RoundUpAlignment(LoSize, HiAlign); + assert(HiStart != 0 && HiStart <= 8 && "Invalid x86-64 argument pair!"); + + // To handle this, we have to increase the size of the low part so that the + // second element will start at an 8 byte offset. We can't increase the size + // of the second element because it might make us access off the end of the + // struct. + if (HiStart != 8) { + // There are only two sorts of types the ABI generation code can produce for + // the low part of a pair that aren't 8 bytes in size: float or i8/i16/i32. + // Promote these to a larger type. + if (Lo->isFloatTy()) + Lo = llvm::Type::getDoubleTy(Lo->getContext()); + else { + assert(Lo->isIntegerTy() && "Invalid/unknown lo type"); + Lo = llvm::Type::getInt64Ty(Lo->getContext()); + } + } + + const llvm::StructType *Result = + llvm::StructType::get(Lo->getContext(), Lo, Hi, NULL); + + + // Verify that the second element is at an 8-byte offset. + assert(TD.getStructLayout(Result)->getElementOffset(1) == 8 && + "Invalid x86-64 argument pair!"); + return Result; +} + ABIArgInfo X86_64ABIInfo:: -classifyReturnType(QualType RetTy, llvm::LLVMContext &VMContext) const { +classifyReturnType(QualType RetTy) const { // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; @@ -1200,13 +1479,18 @@ classifyReturnType(QualType RetTy, llvm::LLVMContext &VMContext) const { // Check some invariants. assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); - assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification."); assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); const llvm::Type *ResType = 0; switch (Lo) { case NoClass: - return ABIArgInfo::getIgnore(); + if (Hi == NoClass) + return ABIArgInfo::getIgnore(); + // If the low part is just padding, it takes no register, leave ResType + // null. + assert((Hi == SSE || Hi == Integer || Hi == X87Up) && + "Unknown missing lo part"); + break; case SSEUp: case X87Up: @@ -1220,30 +1504,47 @@ classifyReturnType(QualType RetTy, llvm::LLVMContext &VMContext) const { // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next // available register of the sequence %rax, %rdx is used. case Integer: - ResType = llvm::Type::getInt64Ty(VMContext); break; + ResType = GetINTEGERTypeAtOffset(CGT.ConvertTypeRecursive(RetTy), 0, + RetTy, 0); + + // If we have a sign or zero extended integer, make sure to return Extend + // so that the parameter gets the right LLVM IR attributes. + if (Hi == NoClass && isa(ResType)) { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = RetTy->getAs()) + RetTy = EnumTy->getDecl()->getIntegerType(); + + if (RetTy->isIntegralOrEnumerationType() && + RetTy->isPromotableIntegerType()) + return ABIArgInfo::getExtend(); + } + break; // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next // available SSE register of the sequence %xmm0, %xmm1 is used. case SSE: - ResType = llvm::Type::getDoubleTy(VMContext); break; + ResType = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy), 0, RetTy, 0); + break; // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is // returned on the X87 stack in %st0 as 80-bit x87 number. case X87: - ResType = llvm::Type::getX86_FP80Ty(VMContext); break; + ResType = llvm::Type::getX86_FP80Ty(getVMContext()); + break; // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real // part of the value is returned in %st0 and the imaginary part in // %st1. case ComplexX87: assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification."); - ResType = llvm::StructType::get(VMContext, - llvm::Type::getX86_FP80Ty(VMContext), - llvm::Type::getX86_FP80Ty(VMContext), + ResType = llvm::StructType::get(getVMContext(), + llvm::Type::getX86_FP80Ty(getVMContext()), + llvm::Type::getX86_FP80Ty(getVMContext()), NULL); break; } + const llvm::Type *HighPart = 0; switch (Hi) { // Memory was handled previously and X87 should // never occur as a hi class. @@ -1252,15 +1553,19 @@ classifyReturnType(QualType RetTy, llvm::LLVMContext &VMContext) const { assert(0 && "Invalid classification for hi word."); case ComplexX87: // Previously handled. - case NoClass: break; + case NoClass: + break; case Integer: - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getInt64Ty(VMContext), NULL); + HighPart = GetINTEGERTypeAtOffset(CGT.ConvertTypeRecursive(RetTy), + 8, RetTy, 8); + if (Lo == NoClass) // Return HighPart at offset 8 in memory. + return ABIArgInfo::getDirect(HighPart, 8); break; case SSE: - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getDoubleTy(VMContext), NULL); + HighPart = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy), 8, RetTy, 8); + if (Lo == NoClass) // Return HighPart at offset 8 in memory. + return ABIArgInfo::getDirect(HighPart, 8); break; // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte @@ -1269,7 +1574,7 @@ classifyReturnType(QualType RetTy, llvm::LLVMContext &VMContext) const { // SSEUP should always be preceeded by SSE, just widen. case SSEUp: assert(Lo == SSE && "Unexpected SSEUp classification."); - ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2); + ResType = Get16ByteVectorType(RetTy); break; // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is @@ -1279,51 +1584,32 @@ classifyReturnType(QualType RetTy, llvm::LLVMContext &VMContext) const { // anything. However, in some cases with unions it may not be // preceeded by X87. In such situations we follow gcc and pass the // extra bits in an SSE reg. - if (Lo != X87) - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getDoubleTy(VMContext), NULL); + if (Lo != X87) { + HighPart = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy), + 8, RetTy, 8); + if (Lo == NoClass) // Return HighPart at offset 8 in memory. + return ABIArgInfo::getDirect(HighPart, 8); + } break; } - - return getCoerceResult(RetTy, ResType); -} - -static const llvm::Type *Get8ByteTypeAtOffset(const llvm::Type *PrefType, - unsigned Offset, - const llvm::TargetData &TD) { - if (PrefType == 0) return 0; - - // Pointers are always 8-bytes at offset 0. - if (Offset == 0 && isa(PrefType)) - return PrefType; - - // TODO: 1/2/4/8 byte integers are also interesting, but we have to know that - // the "hole" is not used in the containing struct (just undef padding). - const llvm::StructType *STy = dyn_cast(PrefType); - if (STy == 0) return 0; - - // If this is a struct, recurse into the field at the specified offset. - const llvm::StructLayout *SL = TD.getStructLayout(STy); - if (Offset >= SL->getSizeInBytes()) return 0; - - unsigned FieldIdx = SL->getElementContainingOffset(Offset); - Offset -= SL->getElementOffset(FieldIdx); - return Get8ByteTypeAtOffset(STy->getElementType(FieldIdx), Offset, TD); + // If a high part was specified, merge it together with the low part. It is + // known to pass in the high eightbyte of the result. We do this by forming a + // first class struct aggregate with the high and low part: {low, high} + if (HighPart) + ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getTargetData()); + + return ABIArgInfo::getDirect(ResType); } -ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, - llvm::LLVMContext &VMContext, - unsigned &neededInt, - unsigned &neededSSE, - const llvm::Type *PrefType)const{ +ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt, + unsigned &neededSSE) const { X86_64ABIInfo::Class Lo, Hi; classify(Ty, 0, Lo, Hi); // Check some invariants. // FIXME: Enforce these by construction. assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); - assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification."); assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); neededInt = 0; @@ -1331,7 +1617,13 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, const llvm::Type *ResType = 0; switch (Lo) { case NoClass: - return ABIArgInfo::getIgnore(); + if (Hi == NoClass) + return ABIArgInfo::getIgnore(); + // If the low part is just padding, it takes no register, leave ResType + // null. + assert((Hi == SSE || Hi == Integer || Hi == X87Up) && + "Unknown missing lo part"); + break; // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument // on the stack. @@ -1351,16 +1643,23 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 // and %r9 is used. case Integer: - // It is always safe to classify this as an i64 argument. - ResType = llvm::Type::getInt64Ty(VMContext); ++neededInt; - - // If we can choose a better 8-byte type based on the preferred type, and if - // that type is still passed in a GPR, use it. - if (const llvm::Type *PrefTypeLo = Get8ByteTypeAtOffset(PrefType, 0, TD)) - if (isa(PrefTypeLo) || - isa(PrefTypeLo)) - ResType = PrefTypeLo; + + // Pick an 8-byte type based on the preferred type. + ResType = GetINTEGERTypeAtOffset(CGT.ConvertTypeRecursive(Ty), 0, Ty, 0); + + // If we have a sign or zero extended integer, make sure to return Extend + // so that the parameter gets the right LLVM IR attributes. + if (Hi == NoClass && isa(ResType)) { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs()) + Ty = EnumTy->getDecl()->getIntegerType(); + + if (Ty->isIntegralOrEnumerationType() && + Ty->isPromotableIntegerType()) + return ABIArgInfo::getExtend(); + } + break; // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next @@ -1368,10 +1667,11 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, // order from %xmm0 to %xmm7. case SSE: ++neededSSE; - ResType = llvm::Type::getDoubleTy(VMContext); + ResType = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(Ty), 0, Ty, 0); break; } + const llvm::Type *HighPart = 0; switch (Hi) { // Memory was handled previously, ComplexX87 and X87 should // never occur as hi classes, and X87Up must be preceed by X87, @@ -1383,49 +1683,49 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, break; case NoClass: break; - - case Integer: { - // It is always safe to classify this as an i64 argument. - const llvm::Type *HiType = llvm::Type::getInt64Ty(VMContext); + + case Integer: ++neededInt; + // Pick an 8-byte type based on the preferred type. + HighPart = GetINTEGERTypeAtOffset(CGT.ConvertTypeRecursive(Ty), 8, Ty, 8); - // If we can choose a better 8-byte type based on the preferred type, and if - // that type is still passed in a GPR, use it. - if (const llvm::Type *PrefTypeHi = Get8ByteTypeAtOffset(PrefType, 8, TD)) - if (isa(PrefTypeHi) || - isa(PrefTypeHi)) - HiType = PrefTypeHi; - - ResType = llvm::StructType::get(VMContext, ResType, HiType, NULL); + if (Lo == NoClass) // Pass HighPart at offset 8 in memory. + return ABIArgInfo::getDirect(HighPart, 8); break; - } // X87Up generally doesn't occur here (long double is passed in // memory), except in situations involving unions. case X87Up: case SSE: - ResType = llvm::StructType::get(VMContext, ResType, - llvm::Type::getDoubleTy(VMContext), NULL); + HighPart = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(Ty), 8, Ty, 8); + + if (Lo == NoClass) // Pass HighPart at offset 8 in memory. + return ABIArgInfo::getDirect(HighPart, 8); + ++neededSSE; break; // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the // eightbyte is passed in the upper half of the last used SSE - // register. + // register. This only happens when 128-bit vectors are passed. case SSEUp: - assert(Lo == SSE && "Unexpected SSEUp classification."); - ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2); + assert(Lo == SSE && "Unexpected SSEUp classification"); + ResType = Get16ByteVectorType(Ty); break; } - return getCoerceResult(Ty, ResType); + // If a high part was specified, merge it together with the low part. It is + // known to pass in the high eightbyte of the result. We do this by forming a + // first class struct aggregate with the high and low part: {low, high} + if (HighPart) + ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getTargetData()); + + return ABIArgInfo::getDirect(ResType); } -void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext, - const llvm::Type *const *PrefTypes, - unsigned NumPrefTypes) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), VMContext); +void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const { + + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); // Keep track of the number of assigned registers. unsigned freeIntRegs = 6, freeSSERegs = 8; @@ -1439,17 +1739,8 @@ void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context, // get assigned (in left-to-right order) for passing as follows... for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) { - // If the client specified a preferred IR type to use, pass it down to - // classifyArgumentType. - const llvm::Type *PrefType = 0; - if (NumPrefTypes) { - PrefType = *PrefTypes++; - --NumPrefTypes; - } - unsigned neededInt, neededSSE; - it->info = classifyArgumentType(it->type, VMContext, - neededInt, neededSSE, PrefType); + it->info = classifyArgumentType(it->type, neededInt, neededSSE); // AMD64-ABI 3.2.3p3: If there are no registers available for any // eightbyte of an argument, the whole argument is passed on the @@ -1527,9 +1818,9 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, // i8* reg_save_area; // }; unsigned neededInt, neededSSE; - + Ty = CGF.getContext().getCanonicalType(Ty); - ABIArgInfo AI = classifyArgumentType(Ty, VMContext, neededInt, neededSSE, 0); + ABIArgInfo AI = classifyArgumentType(Ty, neededInt, neededSSE); // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed // in the registers. If not go to step 7. @@ -1591,13 +1882,13 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, "reg_save_area"); if (neededInt && neededSSE) { // FIXME: Cleanup. - assert(AI.isCoerce() && "Unexpected ABI info for mixed regs"); + assert(AI.isDirect() && "Unexpected ABI info for mixed regs"); const llvm::StructType *ST = cast(AI.getCoerceToType()); llvm::Value *Tmp = CGF.CreateTempAlloca(ST); assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs"); const llvm::Type *TyLo = ST->getElementType(0); const llvm::Type *TyHi = ST->getElementType(1); - assert((TyLo->isFloatingPointTy() ^ TyHi->isFloatingPointTy()) && + assert((TyLo->isFPOrFPVectorTy() ^ TyHi->isFPOrFPVectorTy()) && "Unexpected ABI info for mixed regs"); const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo); const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi); @@ -1674,7 +1965,28 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, return ResAddr; } +llvm::Value *WinX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, + "ap"); + llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); + llvm::Type *PTy = + llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); + llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); + + uint64_t Offset = + llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 8); + llvm::Value *NextAddr = + Builder.CreateGEP(Addr, llvm::ConstantInt::get(CGF.Int32Ty, Offset), + "ap.next"); + Builder.CreateStore(NextAddr, VAListAddrAsBPP); + + return AddrTyped; +} //===----------------------------------------------------------------------===// // PIC16 ABI Implementation @@ -1683,23 +1995,18 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, namespace { class PIC16ABIInfo : public ABIInfo { - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; - - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext, - const llvm::Type *const *PrefTypes, - unsigned NumPrefTypes) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, - VMContext); +public: + PIC16ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} + + ABIArgInfo classifyReturnType(QualType RetTy) const; + + ABIArgInfo classifyArgumentType(QualType RetTy) const; + + virtual void computeInfo(CGFunctionInfo &FI) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) - it->info = classifyArgumentType(it->type, Context, VMContext); + it->info = classifyArgumentType(it->type); } virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -1708,14 +2015,13 @@ class PIC16ABIInfo : public ABIInfo { class PIC16TargetCodeGenInfo : public TargetCodeGenInfo { public: - PIC16TargetCodeGenInfo():TargetCodeGenInfo(new PIC16ABIInfo()) {} + PIC16TargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(new PIC16ABIInfo(CGT)) {} }; } -ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { +ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) { return ABIArgInfo::getIgnore(); } else { @@ -1723,9 +2029,7 @@ ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy, } } -ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { +ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty) const { return ABIArgInfo::getDirect(); } @@ -1759,13 +2063,15 @@ llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, namespace { class PPC32TargetCodeGenInfo : public DefaultTargetCodeGenInfo { public: + PPC32TargetCodeGenInfo(CodeGenTypes &CGT) : DefaultTargetCodeGenInfo(CGT) {} + int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const { // This is recovered from gcc output. return 1; // r1 is the dedicated stack pointer } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, - llvm::Value *Address) const; + llvm::Value *Address) const; }; } @@ -1809,7 +2115,7 @@ PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, // 113: sfp AssignToArrayRange(Builder, Address, Four8, 109, 113); - return false; + return false; } @@ -1831,23 +2137,15 @@ private: ABIKind Kind; public: - ARMABIInfo(ABIKind _Kind) : Kind(_Kind) {} + ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : ABIInfo(CGT), Kind(_Kind) {} private: ABIKind getABIKind() const { return Kind; } - ABIArgInfo classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMCOntext) const; - - ABIArgInfo classifyArgumentType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const; + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType RetTy) const; - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext, - const llvm::Type *const *PrefTypes, - unsigned NumPrefTypes) const; + virtual void computeInfo(CGFunctionInfo &FI) const; virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const; @@ -1855,8 +2153,8 @@ private: class ARMTargetCodeGenInfo : public TargetCodeGenInfo { public: - ARMTargetCodeGenInfo(ARMABIInfo::ABIKind K) - :TargetCodeGenInfo(new ARMABIInfo(K)) {} + ARMTargetCodeGenInfo(CodeGenTypes &CGT, ARMABIInfo::ABIKind K) + :TargetCodeGenInfo(new ARMABIInfo(CGT, K)) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const { return 13; @@ -1865,18 +2163,13 @@ public: } -void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext, - const llvm::Type *const *PrefTypes, - unsigned NumPrefTypes) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context, - VMContext); +void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) { - it->info = classifyArgumentType(it->type, Context, VMContext); - } + it != ie; ++it) + it->info = classifyArgumentType(it->type); - const llvm::Triple &Triple(Context.Target.getTriple()); + const llvm::Triple &Triple(getContext().Target.getTriple()); llvm::CallingConv::ID DefaultCC; if (Triple.getEnvironmentName() == "gnueabi" || Triple.getEnvironmentName() == "eabi") @@ -1901,10 +2194,8 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context, } } -ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (!CodeGenFunction::hasAggregateLLVMType(Ty)) { +ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const { + if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); @@ -1914,7 +2205,7 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, } // Ignore empty records. - if (isEmptyRecord(Context, Ty, true)) + if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); // Structures with either a non-trivial destructor or a non-trivial @@ -1927,21 +2218,21 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, // FIXME: This doesn't handle alignment > 64 bits. const llvm::Type* ElemTy; unsigned SizeRegs; - if (Context.getTypeAlign(Ty) > 32) { - ElemTy = llvm::Type::getInt64Ty(VMContext); - SizeRegs = (Context.getTypeSize(Ty) + 63) / 64; + if (getContext().getTypeAlign(Ty) > 32) { + ElemTy = llvm::Type::getInt64Ty(getVMContext()); + SizeRegs = (getContext().getTypeSize(Ty) + 63) / 64; } else { - ElemTy = llvm::Type::getInt32Ty(VMContext); - SizeRegs = (Context.getTypeSize(Ty) + 31) / 32; + ElemTy = llvm::Type::getInt32Ty(getVMContext()); + SizeRegs = (getContext().getTypeSize(Ty) + 31) / 32; } std::vector LLVMFields; LLVMFields.push_back(llvm::ArrayType::get(ElemTy, SizeRegs)); - const llvm::Type* STy = llvm::StructType::get(VMContext, LLVMFields, true); - return ABIArgInfo::getCoerce(STy); + const llvm::Type* STy = llvm::StructType::get(getVMContext(), LLVMFields, + true); + return ABIArgInfo::getDirect(STy); } -static bool isIntegerLikeType(QualType Ty, - ASTContext &Context, +static bool isIntegerLikeType(QualType Ty, ASTContext &Context, llvm::LLVMContext &VMContext) { // APCS, C Language Calling Conventions, Non-Simple Return Values: A structure // is called integer-like if its size is less than or equal to one word, and @@ -2011,7 +2302,7 @@ static bool isIntegerLikeType(QualType Ty, if (!isIntegerLikeType(FD->getType(), Context, VMContext)) return false; - + // Only allow at most one field in a structure. This doesn't match the // wording above, but follows gcc in situations with a field following an // empty structure. @@ -2026,13 +2317,11 @@ static bool isIntegerLikeType(QualType Ty, return true; } -ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { +ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); - if (!CodeGenFunction::hasAggregateLLVMType(RetTy)) { + if (!isAggregateTypeForABI(RetTy)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); @@ -2048,7 +2337,7 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, // Are we following APCS? if (getABIKind() == APCS) { - if (isEmptyRecord(Context, RetTy, false)) + if (isEmptyRecord(getContext(), RetTy, false)) return ABIArgInfo::getIgnore(); // Complex types are all returned as packed integers. @@ -2056,18 +2345,18 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, // FIXME: Consider using 2 x vector types if the back end handles them // correctly. if (RetTy->isAnyComplexType()) - return ABIArgInfo::getCoerce(llvm::IntegerType::get( - VMContext, Context.getTypeSize(RetTy))); + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), + getContext().getTypeSize(RetTy))); // Integer like structures are returned in r0. - if (isIntegerLikeType(RetTy, Context, VMContext)) { + if (isIntegerLikeType(RetTy, getContext(), getVMContext())) { // Return in the smallest viable integer type. - uint64_t Size = Context.getTypeSize(RetTy); + uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 8) - return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext)); + return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); if (Size <= 16) - return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext)); - return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext)); + return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); + return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); } // Otherwise return in memory. @@ -2076,19 +2365,19 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, // Otherwise this is an AAPCS variant. - if (isEmptyRecord(Context, RetTy, true)) + if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); // Aggregates <= 4 bytes are returned in r0; other aggregates // are returned indirectly. - uint64_t Size = Context.getTypeSize(RetTy); + uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 32) { // Return in the smallest viable integer type. if (Size <= 8) - return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext)); + return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); if (Size <= 16) - return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext)); - return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext)); + return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); + return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); } return ABIArgInfo::getIndirect(0); @@ -2118,21 +2407,19 @@ llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, return AddrTyped; } -ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (RetTy->isVoidType()) { +ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); - } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { + + if (isAggregateTypeForABI(RetTy)) return ABIArgInfo::getIndirect(0); - } else { - // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = RetTy->getAs()) - RetTy = EnumTy->getDecl()->getIntegerType(); - return (RetTy->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = RetTy->getAs()) + RetTy = EnumTy->getDecl()->getIntegerType(); + + return (RetTy->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } //===----------------------------------------------------------------------===// @@ -2142,23 +2429,19 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy, namespace { class SystemZABIInfo : public ABIInfo { - bool isPromotableIntegerType(QualType Ty) const; +public: + SystemZABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} - ABIArgInfo classifyReturnType(QualType RetTy, ASTContext &Context, - llvm::LLVMContext &VMContext) const; + bool isPromotableIntegerType(QualType Ty) const; - ABIArgInfo classifyArgumentType(QualType RetTy, ASTContext &Context, - llvm::LLVMContext &VMContext) const; + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType RetTy) const; - virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context, - llvm::LLVMContext &VMContext, - const llvm::Type *const *PrefTypes, - unsigned NumPrefTypes) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), - Context, VMContext); + virtual void computeInfo(CGFunctionInfo &FI) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) - it->info = classifyArgumentType(it->type, Context, VMContext); + it->info = classifyArgumentType(it->type); } virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -2167,7 +2450,8 @@ class SystemZABIInfo : public ABIInfo { class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { public: - SystemZTargetCodeGenInfo():TargetCodeGenInfo(new SystemZABIInfo()) {} + SystemZTargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(new SystemZABIInfo(CGT)) {} }; } @@ -2199,28 +2483,22 @@ llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, } -ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (RetTy->isVoidType()) { +ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); - } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) { + if (isAggregateTypeForABI(RetTy)) return ABIArgInfo::getIndirect(0); - } else { - return (isPromotableIntegerType(RetTy) ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } + + return (isPromotableIntegerType(RetTy) ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } -ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (CodeGenFunction::hasAggregateLLVMType(Ty)) { +ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const { + if (isAggregateTypeForABI(Ty)) return ABIArgInfo::getIndirect(0); - } else { - return (isPromotableIntegerType(Ty) ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } + + return (isPromotableIntegerType(Ty) ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } //===----------------------------------------------------------------------===// @@ -2231,7 +2509,8 @@ namespace { class MSP430TargetCodeGenInfo : public TargetCodeGenInfo { public: - MSP430TargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {} + MSP430TargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {} void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const; }; @@ -2270,14 +2549,15 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D, namespace { class MIPSTargetCodeGenInfo : public TargetCodeGenInfo { public: - MIPSTargetCodeGenInfo(): TargetCodeGenInfo(new DefaultABIInfo()) {} + MIPSTargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const { return 29; } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, - llvm::Value *Address) const; + llvm::Value *Address) const; }; } @@ -2315,7 +2595,7 @@ MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, } -const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const { +const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { if (TheTargetCodeGenInfo) return *TheTargetCodeGenInfo; @@ -2325,56 +2605,61 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const { const llvm::Triple &Triple = getContext().Target.getTriple(); switch (Triple.getArch()) { default: - return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo()); + return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo(Types)); case llvm::Triple::mips: case llvm::Triple::mipsel: - return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo()); + return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types)); case llvm::Triple::arm: case llvm::Triple::thumb: // FIXME: We want to know the float calling convention as well. if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0) return *(TheTargetCodeGenInfo = - new ARMTargetCodeGenInfo(ARMABIInfo::APCS)); + new ARMTargetCodeGenInfo(Types, ARMABIInfo::APCS)); return *(TheTargetCodeGenInfo = - new ARMTargetCodeGenInfo(ARMABIInfo::AAPCS)); + new ARMTargetCodeGenInfo(Types, ARMABIInfo::AAPCS)); case llvm::Triple::pic16: - return *(TheTargetCodeGenInfo = new PIC16TargetCodeGenInfo()); + return *(TheTargetCodeGenInfo = new PIC16TargetCodeGenInfo(Types)); case llvm::Triple::ppc: - return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo()); + return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo(Types)); case llvm::Triple::systemz: - return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo()); + return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo(Types)); case llvm::Triple::msp430: - return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo()); + return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo(Types)); case llvm::Triple::x86: switch (Triple.getOS()) { case llvm::Triple::Darwin: return *(TheTargetCodeGenInfo = - new X86_32TargetCodeGenInfo(Context, true, true)); + new X86_32TargetCodeGenInfo(Types, true, true)); case llvm::Triple::Cygwin: case llvm::Triple::MinGW32: - case llvm::Triple::MinGW64: case llvm::Triple::AuroraUX: case llvm::Triple::DragonFly: case llvm::Triple::FreeBSD: case llvm::Triple::OpenBSD: return *(TheTargetCodeGenInfo = - new X86_32TargetCodeGenInfo(Context, false, true)); + new X86_32TargetCodeGenInfo(Types, false, true)); default: return *(TheTargetCodeGenInfo = - new X86_32TargetCodeGenInfo(Context, false, false)); + new X86_32TargetCodeGenInfo(Types, false, false)); } case llvm::Triple::x86_64: - return *(TheTargetCodeGenInfo = - new X86_64TargetCodeGenInfo(Context, TheTargetData)); + switch (Triple.getOS()) { + case llvm::Triple::Win32: + case llvm::Triple::MinGW64: + case llvm::Triple::Cygwin: + return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types)); + default: + return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types)); + } } } diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h index f0a7824..9d4cf16 100644 --- a/lib/CodeGen/TargetInfo.h +++ b/lib/CodeGen/TargetInfo.h @@ -47,6 +47,16 @@ namespace clang { virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { } + /// Determines the size of struct _Unwind_Exception on this platform, + /// in 8-bit units. The Itanium ABI defines this as: + /// struct _Unwind_Exception { + /// uint64 exception_class; + /// _Unwind_Exception_Cleanup_Fn exception_cleanup; + /// uint64 private_1; + /// uint64 private_2; + /// }; + unsigned getSizeOfUnwindException() const { return 32; } + /// Controls whether __builtin_extend_pointer should sign-extend /// pointers to uint64_t or zero-extend them (the default). Has /// no effect for targets: diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index 282e9fe..c059afd 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -83,10 +83,6 @@ void Compilation::PrintJob(llvm::raw_ostream &OS, const Job &J, OS << '"'; } OS << Terminator; - } else if (const PipedJob *PJ = dyn_cast(&J)) { - for (PipedJob::const_iterator - it = PJ->begin(), ie = PJ->end(); it != ie; ++it) - PrintJob(OS, **it, (it + 1 != PJ->end()) ? " |\n" : "\n", Quote); } else { const JobList *Jobs = cast(&J); for (JobList::const_iterator @@ -190,14 +186,6 @@ int Compilation::ExecuteJob(const Job &J, const Command *&FailingCommand) const { if (const Command *C = dyn_cast(&J)) { return ExecuteCommand(*C, FailingCommand); - } else if (const PipedJob *PJ = dyn_cast(&J)) { - // Piped commands with a single job are easy. - if (PJ->size() == 1) - return ExecuteCommand(**PJ->begin(), FailingCommand); - - FailingCommand = *PJ->begin(); - getDriver().Diag(clang::diag::err_drv_unsupported_opt) << "-pipe"; - return 1; } else { const JobList *Jobs = cast(&J); for (JobList::const_iterator diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 2fc0a53..82f9134 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -25,6 +25,7 @@ #include "clang/Basic/Version.h" +#include "llvm/Config/config.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/PrettyStackTrace.h" @@ -39,13 +40,13 @@ using namespace clang::driver; using namespace clang; -Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir, +Driver::Driver(llvm::StringRef _ClangExecutable, llvm::StringRef _DefaultHostTriple, llvm::StringRef _DefaultImageName, bool IsProduction, bool CXXIsProduction, Diagnostic &_Diags) : Opts(createDriverOptTable()), Diags(_Diags), - Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple), + ClangExecutable(_ClangExecutable), DefaultHostTriple(_DefaultHostTriple), DefaultImageName(_DefaultImageName), DriverTitle("clang \"gcc-compatible\" driver"), Host(0), @@ -68,6 +69,10 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir, CCCUseClangCXX = false; } + llvm::sys::Path Executable(ClangExecutable); + Name = Executable.getBasename(); + Dir = Executable.getDirname(); + // Compute the path to the resource directory. llvm::sys::Path P(Dir); P.eraseComponent(); // Remove /bin from foo/bin @@ -75,11 +80,6 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir, P.appendComponent("clang"); P.appendComponent(CLANG_VERSION_STRING); ResourceDir = P.str(); - - // Save the original clang executable path. - P = Dir; - P.appendComponent(Name); - ClangExecutable = P.str(); } Driver::~Driver() { @@ -160,6 +160,16 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { DAL->append(*it); } + // Add a default value of -mlinker-version=, if one was given and the user + // didn't specify one. +#if defined(HOST_LINK_VERSION) + if (!Args.hasArg(options::OPT_mlinker_version_EQ)) { + DAL->AddJoinedArg(0, Opts->getOption(options::OPT_mlinker_version_EQ), + HOST_LINK_VERSION); + DAL->getLastArg(options::OPT_mlinker_version_EQ)->claim(); + } +#endif + return DAL; } @@ -176,13 +186,15 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { bool CCCPrintOptions = false, CCCPrintActions = false; const char **Start = argv + 1, **End = argv + argc; - const char *HostTriple = DefaultHostTriple.c_str(); InputArgList *Args = ParseArgStrings(Start, End); // -no-canonical-prefixes is used very early in main. Args->ClaimAllArgs(options::OPT_no_canonical_prefixes); + // Ignore -pipe. + Args->ClaimAllArgs(options::OPT_pipe); + // Extract -ccc args. // // FIXME: We need to figure out where this behavior should live. Most of it @@ -223,14 +235,16 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { Cur = Split.second; } } + // FIXME: We shouldn't overwrite the default host triple here, but we have + // nowhere else to put this currently. if (const Arg *A = Args->getLastArg(options::OPT_ccc_host_triple)) - HostTriple = A->getValue(*Args); + DefaultHostTriple = A->getValue(*Args); if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir)) - Dir = A->getValue(*Args); + Dir = InstalledDir = A->getValue(*Args); if (const Arg *A = Args->getLastArg(options::OPT_B)) PrefixDir = A->getValue(*Args); - Host = GetHostInfo(HostTriple); + Host = GetHostInfo(DefaultHostTriple.c_str()); // Perform the default argument translations. DerivedArgList *TranslatedArgs = TranslateInputArgs(*Args); @@ -248,14 +262,12 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { if (!HandleImmediateArgs(*C)) return C; - // Construct the list of abstract actions to perform for this compilation. We - // avoid passing a Compilation here simply to enforce the abstraction that - // pipelining is not host or toolchain dependent (other than the driver driver - // test). + // Construct the list of abstract actions to perform for this compilation. if (Host->useDriverDriver()) - BuildUniversalActions(C->getArgs(), C->getActions()); + BuildUniversalActions(C->getDefaultToolChain(), C->getArgs(), + C->getActions()); else - BuildActions(C->getArgs(), C->getActions()); + BuildActions(C->getDefaultToolChain(), C->getArgs(), C->getActions()); if (CCCPrintActions) { PrintActions(*C); @@ -525,7 +537,8 @@ static bool ContainsCompileAction(const Action *A) { return false; } -void Driver::BuildUniversalActions(const ArgList &Args, +void Driver::BuildUniversalActions(const ToolChain &TC, + const ArgList &Args, ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building universal build actions"); // Collect the list of architectures. Duplicates are allowed, but should only @@ -570,7 +583,7 @@ void Driver::BuildUniversalActions(const ArgList &Args, } ActionList SingleActions; - BuildActions(Args, SingleActions); + BuildActions(TC, Args, SingleActions); // Add in arch bindings for every top level action, as well as lipo and // dsymutil steps if needed. @@ -620,7 +633,8 @@ void Driver::BuildUniversalActions(const ArgList &Args, } } -void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { +void Driver::BuildActions(const ToolChain &TC, const ArgList &Args, + ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); // Start by constructing the list of inputs and their types. @@ -660,7 +674,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { // found. We use a host hook here because Darwin at least has its own // idea of what .s is. if (const char *Ext = strrchr(Value, '.')) - Ty = Host->lookupTypeForExtension(Ext + 1); + Ty = TC.LookupTypeForExtension(Ext + 1); if (Ty == types::TY_INVALID) Ty = types::TY_Object; @@ -885,16 +899,6 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, void Driver::BuildJobs(Compilation &C) const { llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); - bool SaveTemps = C.getArgs().hasArg(options::OPT_save_temps); - bool UsePipes = C.getArgs().hasArg(options::OPT_pipe); - - // FIXME: Pipes are forcibly disabled until we support executing them. - if (!CCCPrintBindings) - UsePipes = false; - - // -save-temps inhibits pipes. - if (SaveTemps && UsePipes) - Diag(clang::diag::warn_drv_pipe_ignored_with_save_temps); Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o); @@ -934,7 +938,6 @@ void Driver::BuildJobs(Compilation &C) const { InputInfo II; BuildJobsForAction(C, A, &C.getDefaultToolChain(), /*BoundArch*/0, - /*CanAcceptPipe*/ true, /*AtTopLevel*/ true, /*LinkingOutput*/ LinkingOutput, II); @@ -1032,17 +1035,11 @@ void Driver::BuildJobsForAction(Compilation &C, const Action *A, const ToolChain *TC, const char *BoundArch, - bool CanAcceptPipe, bool AtTopLevel, const char *LinkingOutput, InputInfo &Result) const { llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); - bool UsePipes = C.getArgs().hasArg(options::OPT_pipe); - // FIXME: Pipes are forcibly disabled until we support executing them. - if (!CCCPrintBindings) - UsePipes = false; - if (const InputAction *IA = dyn_cast(A)) { // FIXME: It would be nice to not claim this here; maybe the old scheme of // just using Args was better? @@ -1064,7 +1061,7 @@ void Driver::BuildJobsForAction(Compilation &C, TC = Host->CreateToolChain(C.getArgs(), BAA->getArchName()); BuildJobsForAction(C, *BAA->begin(), TC, BAA->getArchName(), - CanAcceptPipe, AtTopLevel, LinkingOutput, Result); + AtTopLevel, LinkingOutput, Result); return; } @@ -1074,7 +1071,6 @@ void Driver::BuildJobsForAction(Compilation &C, const Tool &T = SelectToolForJob(C, TC, JA, Inputs); // Only use pipes when there is exactly one input. - bool TryToUsePipeInput = Inputs->size() == 1 && T.acceptsPipedInput(); InputInfoList InputInfos; for (ActionList::const_iterator it = Inputs->begin(), ie = Inputs->end(); it != ie; ++it) { @@ -1087,33 +1083,11 @@ void Driver::BuildJobsForAction(Compilation &C, SubJobAtTopLevel = true; InputInfo II; - BuildJobsForAction(C, *it, TC, BoundArch, TryToUsePipeInput, + BuildJobsForAction(C, *it, TC, BoundArch, SubJobAtTopLevel, LinkingOutput, II); InputInfos.push_back(II); } - // Determine if we should output to a pipe. - bool OutputToPipe = false; - if (CanAcceptPipe && T.canPipeOutput()) { - // Some actions default to writing to a pipe if they are the top level phase - // and there was no user override. - // - // FIXME: Is there a better way to handle this? - if (AtTopLevel) { - if (isa(A) && !C.getArgs().hasArg(options::OPT_o)) - OutputToPipe = true; - } else if (UsePipes) - OutputToPipe = true; - } - - // Figure out where to put the job (pipes). - Job *Dest = &C.getJobs(); - if (InputInfos[0].isPipe()) { - assert(TryToUsePipeInput && "Unrequested pipe!"); - assert(InputInfos.size() == 1 && "Unexpected pipe with multiple inputs."); - Dest = &InputInfos[0].getPipe(); - } - // Always use the first input as the base input. const char *BaseInput = InputInfos[0].getBaseInput(); @@ -1122,22 +1096,9 @@ void Driver::BuildJobsForAction(Compilation &C, if (JA->getType() == types::TY_dSYM) BaseInput = InputInfos[0].getFilename(); - // Determine the place to write output to (nothing, pipe, or filename) and - // where to put the new job. + // Determine the place to write output to, if any. if (JA->getType() == types::TY_Nothing) { Result = InputInfo(A->getType(), BaseInput); - } else if (OutputToPipe) { - // Append to current piped job or create a new one as appropriate. - PipedJob *PJ = dyn_cast(Dest); - if (!PJ) { - PJ = new PipedJob(); - // FIXME: Temporary hack so that -ccc-print-bindings work until we have - // pipe support. Please remove later. - if (!CCCPrintBindings) - cast(Dest)->addJob(PJ); - Dest = PJ; - } - Result = InputInfo(PJ, A->getType(), BaseInput); } else { Result = InputInfo(GetNamedOutputPath(C, *JA, BaseInput, AtTopLevel), A->getType(), BaseInput); @@ -1153,7 +1114,7 @@ void Driver::BuildJobsForAction(Compilation &C, } llvm::errs() << "], output: " << Result.getAsString() << "\n"; } else { - T.ConstructJob(C, *JA, *Dest, Result, InputInfos, + T.ConstructJob(C, *JA, Result, InputInfos, C.getArgsForToolChain(TC, BoundArch), LinkingOutput); } } @@ -1169,6 +1130,10 @@ const char *Driver::GetNamedOutputPath(Compilation &C, return C.addResultFile(FinalOutput->getValue(C.getArgs())); } + // Default to writing to stdout? + if (AtTopLevel && isa(JA)) + return "-"; + // Output to a temporary file? if (!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps)) { std::string TmpName = @@ -1307,6 +1272,11 @@ const HostInfo *Driver::GetHostInfo(const char *TripleStr) const { return createMinixHostInfo(*this, Triple); case llvm::Triple::Linux: return createLinuxHostInfo(*this, Triple); + case llvm::Triple::Win32: + return createWindowsHostInfo(*this, Triple); + case llvm::Triple::MinGW32: + case llvm::Triple::MinGW64: + return createMinGWHostInfo(*this, Triple); default: return createUnknownHostInfo(*this, Triple); } diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp index 0636d9e..7c5e430 100644 --- a/lib/Driver/HostInfo.cpp +++ b/lib/Driver/HostInfo.cpp @@ -38,12 +38,6 @@ namespace { /// DarwinHostInfo - Darwin host information implementation. class DarwinHostInfo : public HostInfo { - /// Darwin version of host. - unsigned DarwinVersion[3]; - - /// GCC version to use on this host. - unsigned GCCVersion[3]; - /// Cache of tool chains we have created. mutable llvm::DenseMap ToolChains; @@ -53,37 +47,12 @@ public: virtual bool useDriverDriver() const; - virtual types::ID lookupTypeForExtension(const char *Ext) const { - types::ID Ty = types::lookupTypeForExtension(Ext); - - // Darwin always preprocesses assembly files (unless -x is used - // explicitly). - if (Ty == types::TY_PP_Asm) - return types::TY_Asm; - - return Ty; - } - virtual ToolChain *CreateToolChain(const ArgList &Args, const char *ArchName) const; }; DarwinHostInfo::DarwinHostInfo(const Driver &D, const llvm::Triple& Triple) : HostInfo(D, Triple) { - - assert(Triple.getArch() != llvm::Triple::UnknownArch && "Invalid arch!"); - assert(memcmp(&getOSName()[0], "darwin", 6) == 0 && - "Unknown Darwin platform."); - bool HadExtra; - if (!Driver::GetReleaseVersion(&getOSName()[6], - DarwinVersion[0], DarwinVersion[1], - DarwinVersion[2], HadExtra)) - D.Diag(clang::diag::err_drv_invalid_darwin_version) << getOSName(); - - // We can only call 4.2.1 for now. - GCCVersion[0] = 4; - GCCVersion[1] = 2; - GCCVersion[2] = 1; } DarwinHostInfo::~DarwinHostInfo() { @@ -147,11 +116,10 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args, const char *UseNewToolChain = ::getenv("CCC_ENABLE_NEW_DARWIN_TOOLCHAIN"); if (UseNewToolChain || Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) { - TC = new toolchains::DarwinClang(*this, TCTriple, DarwinVersion); + TC = new toolchains::DarwinClang(*this, TCTriple); } else if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { // We still use the legacy DarwinGCC toolchain on X86. - TC = new toolchains::DarwinGCC(*this, TCTriple, DarwinVersion, - GCCVersion); + TC = new toolchains::DarwinGCC(*this, TCTriple); } else TC = new toolchains::Darwin_Generic_GCC(*this, TCTriple); } @@ -170,15 +138,6 @@ public: virtual bool useDriverDriver() const; - virtual types::ID lookupTypeForExtension(const char *Ext) const { - types::ID Ty = types::lookupTypeForExtension(Ext); - - if (Ty == types::TY_PP_Asm) - return types::TY_Asm; - - return Ty; - } - virtual ToolChain *CreateToolChain(const ArgList &Args, const char *ArchName) const; }; @@ -212,10 +171,6 @@ public: virtual bool useDriverDriver() const; - virtual types::ID lookupTypeForExtension(const char *Ext) const { - return types::lookupTypeForExtension(Ext); - } - virtual ToolChain *CreateToolChain(const ArgList &Args, const char *ArchName) const; }; @@ -279,10 +234,6 @@ public: virtual bool useDriverDriver() const; - virtual types::ID lookupTypeForExtension(const char *Ext) const { - return types::lookupTypeForExtension(Ext); - } - virtual ToolChain *CreateToolChain(const ArgList &Args, const char *ArchName) const; }; @@ -330,10 +281,6 @@ public: virtual bool useDriverDriver() const; - virtual types::ID lookupTypeForExtension(const char *Ext) const { - return types::lookupTypeForExtension(Ext); - } - virtual ToolChain *CreateToolChain(const ArgList &Args, const char *ArchName) const; }; @@ -379,10 +326,6 @@ public: virtual bool useDriverDriver() const; - virtual types::ID lookupTypeForExtension(const char *Ext) const { - return types::lookupTypeForExtension(Ext); - } - virtual ToolChain *CreateToolChain(const ArgList &Args, const char *ArchName) const; }; @@ -399,19 +342,22 @@ bool FreeBSDHostInfo::useDriverDriver() const { ToolChain *FreeBSDHostInfo::CreateToolChain(const ArgList &Args, const char *ArchName) const { - bool Lib32 = false; - assert(!ArchName && "Unexpected arch name on platform without driver driver support."); - // On x86_64 we need to be able to compile 32-bits binaries as well. - // Compiling 64-bit binaries on i386 is not supported. We don't have a - // lib64. + // Automatically handle some instances of -m32/-m64 we know about. std::string Arch = getArchName(); ArchName = Arch.c_str(); - if (Args.hasArg(options::OPT_m32) && getArchName() == "x86_64") { - ArchName = "i386"; - Lib32 = true; + if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) { + if (Triple.getArch() == llvm::Triple::x86 || + Triple.getArch() == llvm::Triple::x86_64) { + ArchName = + (A->getOption().matches(options::OPT_m32)) ? "i386" : "x86_64"; + } else if (Triple.getArch() == llvm::Triple::ppc || + Triple.getArch() == llvm::Triple::ppc64) { + ArchName = + (A->getOption().matches(options::OPT_m32)) ? "powerpc" : "powerpc64"; + } } ToolChain *&TC = ToolChains[ArchName]; @@ -419,7 +365,7 @@ ToolChain *FreeBSDHostInfo::CreateToolChain(const ArgList &Args, llvm::Triple TCTriple(getTriple()); TCTriple.setArchName(ArchName); - TC = new toolchains::FreeBSD(*this, TCTriple, Lib32); + TC = new toolchains::FreeBSD(*this, TCTriple); } return TC; @@ -439,10 +385,6 @@ public: virtual bool useDriverDriver() const; - virtual types::ID lookupTypeForExtension(const char *Ext) const { - return types::lookupTypeForExtension(Ext); - } - virtual ToolChain *CreateToolChain(const ArgList &Args, const char *ArchName) const; }; @@ -491,10 +433,6 @@ public: virtual bool useDriverDriver() const; - virtual types::ID lookupTypeForExtension(const char *Ext) const { - return types::lookupTypeForExtension(Ext); - } - virtual ToolChain *CreateToolChain(const ArgList &Args, const char *ArchName) const; }; @@ -540,10 +478,6 @@ public: virtual bool useDriverDriver() const; - virtual types::ID lookupTypeForExtension(const char *Ext) const { - return types::lookupTypeForExtension(Ext); - } - virtual ToolChain *CreateToolChain(const ArgList &Args, const char *ArchName) const; }; @@ -591,8 +525,79 @@ ToolChain *LinuxHostInfo::CreateToolChain(const ArgList &Args, return TC; } +// Windows Host Info + +/// WindowsHostInfo - Host information to use on Microsoft Windows. +class WindowsHostInfo : public HostInfo { + /// Cache of tool chains we have created. + mutable llvm::StringMap ToolChains; + +public: + WindowsHostInfo(const Driver &D, const llvm::Triple& Triple); + ~WindowsHostInfo(); + + virtual bool useDriverDriver() const; + + virtual types::ID lookupTypeForExtension(const char *Ext) const { + return types::lookupTypeForExtension(Ext); + } + + virtual ToolChain *CreateToolChain(const ArgList &Args, + const char *ArchName) const; +}; + +WindowsHostInfo::WindowsHostInfo(const Driver &D, const llvm::Triple& Triple) + : HostInfo(D, Triple) { +} + +WindowsHostInfo::~WindowsHostInfo() { + for (llvm::StringMap::iterator + it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it) + delete it->second; +} + +bool WindowsHostInfo::useDriverDriver() const { + return false; +} + +ToolChain *WindowsHostInfo::CreateToolChain(const ArgList &Args, + const char *ArchName) const { + assert(!ArchName && + "Unexpected arch name on platform without driver driver support."); + + // Automatically handle some instances of -m32/-m64 we know about. + std::string Arch = getArchName(); + ArchName = Arch.c_str(); + if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) { + if (Triple.getArch() == llvm::Triple::x86 || + Triple.getArch() == llvm::Triple::x86_64) { + ArchName = + (A->getOption().matches(options::OPT_m32)) ? "i386" : "x86_64"; + } + } + + ToolChain *&TC = ToolChains[ArchName]; + if (!TC) { + llvm::Triple TCTriple(getTriple()); + TCTriple.setArchName(ArchName); + + TC = new toolchains::Windows(*this, TCTriple); + } + + return TC; } +// FIXME: This is a placeholder. +class MinGWHostInfo : public UnknownHostInfo { +public: + MinGWHostInfo(const Driver &D, const llvm::Triple& Triple); +}; + +MinGWHostInfo::MinGWHostInfo(const Driver &D, const llvm::Triple& Triple) + : UnknownHostInfo(D, Triple) {} + +} // end anon namespace + const HostInfo * clang::driver::createAuroraUXHostInfo(const Driver &D, const llvm::Triple& Triple){ @@ -642,6 +647,18 @@ clang::driver::createTCEHostInfo(const Driver &D, } const HostInfo * +clang::driver::createWindowsHostInfo(const Driver &D, + const llvm::Triple& Triple) { + return new WindowsHostInfo(D, Triple); +} + +const HostInfo * +clang::driver::createMinGWHostInfo(const Driver &D, + const llvm::Triple& Triple) { + return new MinGWHostInfo(D, Triple); +} + +const HostInfo * clang::driver::createUnknownHostInfo(const Driver &D, const llvm::Triple& Triple) { return new UnknownHostInfo(D, Triple); diff --git a/lib/Driver/InputInfo.h b/lib/Driver/InputInfo.h index c657bef..2a2f4b9 100644 --- a/lib/Driver/InputInfo.h +++ b/lib/Driver/InputInfo.h @@ -17,7 +17,6 @@ namespace clang { namespace driver { - class PipedJob; /// InputInfo - Wrapper for information about an input source. class InputInfo { @@ -37,7 +36,6 @@ class InputInfo { union { const char *Filename; const Arg *InputArg; - PipedJob *Pipe; } Data; Class Kind; types::ID Type; @@ -56,15 +54,10 @@ public: : Kind(InputArg), Type(_Type), BaseInput(_BaseInput) { Data.InputArg = _InputArg; } - InputInfo(PipedJob *_Pipe, types::ID _Type, const char *_BaseInput) - : Kind(Pipe), Type(_Type), BaseInput(_BaseInput) { - Data.Pipe = _Pipe; - } bool isNothing() const { return Kind == Nothing; } bool isFilename() const { return Kind == Filename; } bool isInputArg() const { return Kind == InputArg; } - bool isPipe() const { return Kind == Pipe; } types::ID getType() const { return Type; } const char *getBaseInput() const { return BaseInput; } @@ -76,17 +69,11 @@ public: assert(isInputArg() && "Invalid accessor."); return *Data.InputArg; } - PipedJob &getPipe() const { - assert(isPipe() && "Invalid accessor."); - return *Data.Pipe; - } /// getAsString - Return a string name for this input, for /// debugging. std::string getAsString() const { - if (isPipe()) - return "(pipe)"; - else if (isFilename()) + if (isFilename()) return std::string("\"") + getFilename() + '"'; else if (isInputArg()) return "(input arg)"; diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp index bfeb41a..fa7d060 100644 --- a/lib/Driver/Job.cpp +++ b/lib/Driver/Job.cpp @@ -21,13 +21,6 @@ Command::Command(const Action &_Source, const Tool &_Creator, { } -PipedJob::PipedJob() : Job(PipedJobClass) {} - -PipedJob::~PipedJob() { - for (iterator it = begin(), ie = end(); it != ie; ++it) - delete *it; -} - JobList::JobList() : Job(JobListClass) {} JobList::~JobList() { @@ -36,9 +29,6 @@ JobList::~JobList() { } void Job::addCommand(Command *C) { - if (PipedJob *PJ = dyn_cast(this)) - PJ->addCommand(C); - else - cast(this)->addJob(C); + cast(this)->addJob(C); } diff --git a/lib/Driver/Makefile b/lib/Driver/Makefile index 7bc340e..454ab86 100644 --- a/lib/Driver/Makefile +++ b/lib/Driver/Makefile @@ -9,6 +9,5 @@ CLANG_LEVEL := ../.. LIBRARYNAME := clangDriver -BUILD_ARCHIVE = 1 include $(CLANG_LEVEL)/Makefile diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp index 39530f2..3c36314 100644 --- a/lib/Driver/OptTable.cpp +++ b/lib/Driver/OptTable.cpp @@ -164,6 +164,8 @@ Option *OptTable::CreateOption(unsigned id) const { Opt->setLinkerInput(true); if (info.Flags & NoArgumentUnused) Opt->setNoArgumentUnused(true); + if (info.Flags & NoForward) + Opt->setNoForward(true); if (info.Flags & RenderAsInput) Opt->setNoOptAsInput(true); if (info.Flags & RenderJoined) { diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp index dd48af8..5396250 100644 --- a/lib/Driver/Option.cpp +++ b/lib/Driver/Option.cpp @@ -20,7 +20,7 @@ Option::Option(OptionClass _Kind, OptSpecifier _ID, const char *_Name, const OptionGroup *_Group, const Option *_Alias) : Kind(_Kind), ID(_ID.getID()), Name(_Name), Group(_Group), Alias(_Alias), Unsupported(false), LinkerInput(false), NoOptAsInput(false), - DriverOption(false), NoArgumentUnused(false) { + DriverOption(false), NoArgumentUnused(false), NoForward(false) { // Multi-level aliases are not supported, and alias options cannot // have groups. This just simplifies option tracking, it is not an diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 9fae67d..94c1c6b 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -10,8 +10,12 @@ #include "clang/Driver/ToolChain.h" #include "clang/Driver/Action.h" +#include "clang/Driver/Arg.h" +#include "clang/Driver/ArgList.h" #include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/HostInfo.h" +#include "clang/Driver/Options.h" using namespace clang::driver; @@ -34,3 +38,139 @@ std::string ToolChain::GetFilePath(const char *Name) const { std::string ToolChain::GetProgramPath(const char *Name, bool WantFile) const { return Host.getDriver().GetProgramPath(Name, *this, WantFile); } + +types::ID ToolChain::LookupTypeForExtension(const char *Ext) const { + return types::lookupTypeForExtension(Ext); +} + +/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targetting. +// +// FIXME: tblgen this. +static const char *getARMTargetCPU(const ArgList &Args, + const llvm::Triple &Triple) { + // FIXME: Warn on inconsistent use of -mcpu and -march. + + // If we have -mcpu=, use that. + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + return A->getValue(Args); + + llvm::StringRef MArch; + if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + // Otherwise, if we have -march= choose the base CPU for that arch. + MArch = A->getValue(Args); + } else { + // Otherwise, use the Arch from the triple. + MArch = Triple.getArchName(); + } + + if (MArch == "armv2" || MArch == "armv2a") + return "arm2"; + if (MArch == "armv3") + return "arm6"; + if (MArch == "armv3m") + return "arm7m"; + if (MArch == "armv4" || MArch == "armv4t") + return "arm7tdmi"; + if (MArch == "armv5" || MArch == "armv5t") + return "arm10tdmi"; + if (MArch == "armv5e" || MArch == "armv5te") + return "arm1026ejs"; + if (MArch == "armv5tej") + return "arm926ej-s"; + if (MArch == "armv6" || MArch == "armv6k") + return "arm1136jf-s"; + if (MArch == "armv6j") + return "arm1136j-s"; + if (MArch == "armv6z" || MArch == "armv6zk") + return "arm1176jzf-s"; + if (MArch == "armv6t2") + return "arm1156t2-s"; + if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a") + return "cortex-a8"; + if (MArch == "armv7r" || MArch == "armv7-r") + return "cortex-r4"; + if (MArch == "armv7m" || MArch == "armv7-m") + return "cortex-m3"; + if (MArch == "ep9312") + return "ep9312"; + if (MArch == "iwmmxt") + return "iwmmxt"; + if (MArch == "xscale") + return "xscale"; + + // If all else failed, return the most base CPU LLVM supports. + return "arm7tdmi"; +} + +/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular +/// CPU. +// +// FIXME: This is redundant with -mcpu, why does LLVM use this. +// FIXME: tblgen this, or kill it! +static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) { + if (CPU == "arm7tdmi" || CPU == "arm7tdmi-s" || CPU == "arm710t" || + CPU == "arm720t" || CPU == "arm9" || CPU == "arm9tdmi" || + CPU == "arm920" || CPU == "arm920t" || CPU == "arm922t" || + CPU == "arm940t" || CPU == "ep9312") + return "v4t"; + + if (CPU == "arm10tdmi" || CPU == "arm1020t") + return "v5"; + + if (CPU == "arm9e" || CPU == "arm926ej-s" || CPU == "arm946e-s" || + CPU == "arm966e-s" || CPU == "arm968e-s" || CPU == "arm10e" || + CPU == "arm1020e" || CPU == "arm1022e" || CPU == "xscale" || + CPU == "iwmmxt") + return "v5e"; + + if (CPU == "arm1136j-s" || CPU == "arm1136jf-s" || CPU == "arm1176jz-s" || + CPU == "arm1176jzf-s" || CPU == "mpcorenovfp" || CPU == "mpcore") + return "v6"; + + if (CPU == "arm1156t2-s" || CPU == "arm1156t2f-s") + return "v6t2"; + + if (CPU == "cortex-a8" || CPU == "cortex-a9") + return "v7"; + + return ""; +} + +std::string ToolChain::ComputeLLVMTriple(const ArgList &Args) const { + switch (getTriple().getArch()) { + default: + return getTripleString(); + + case llvm::Triple::arm: + case llvm::Triple::thumb: { + // FIXME: Factor into subclasses. + llvm::Triple Triple = getTriple(); + + // Thumb2 is the default for V7 on Darwin. + // + // FIXME: Thumb should just be another -target-feaure, not in the triple. + llvm::StringRef Suffix = + getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple)); + bool ThumbDefault = + (Suffix == "v7" && getTriple().getOS() == llvm::Triple::Darwin); + std::string ArchName = "arm"; + if (Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault)) + ArchName = "thumb"; + Triple.setArchName(ArchName + Suffix.str()); + + return Triple.getTriple(); + } + } +} + +std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args) const { + // Diagnose use of -mmacosx-version-min and -miphoneos-version-min on + // non-Darwin. + if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ, + options::OPT_miphoneos_version_min_EQ)) + getDriver().Diag(clang::diag::err_drv_clang_unsupported) + << A->getAsString(Args); + + return ComputeLLVMTriple(Args); +} + diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index a78d153..471c47d 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -18,7 +18,9 @@ #include "clang/Driver/OptTable.h" #include "clang/Driver/Option.h" #include "clang/Driver/Options.h" +#include "clang/Basic/Version.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -31,13 +33,30 @@ using namespace clang::driver::toolchains; /// Darwin - Darwin tool chain for i386 and x86_64. -Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple, - const unsigned (&_DarwinVersion)[3]) +Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple) : ToolChain(Host, Triple), TargetInitialized(false) { + // Compute the initial Darwin version based on the host. + bool HadExtra; + std::string OSName = Triple.getOSName(); + if (!Driver::GetReleaseVersion(&OSName[6], + DarwinVersion[0], DarwinVersion[1], + DarwinVersion[2], HadExtra)) + getDriver().Diag(clang::diag::err_drv_invalid_darwin_version) << OSName; + llvm::raw_string_ostream(MacosxVersionMin) - << "10." << std::max(0, (int)_DarwinVersion[0] - 4) << '.' - << _DarwinVersion[1]; + << "10." << std::max(0, (int)DarwinVersion[0] - 4) << '.' + << DarwinVersion[1]; +} + +types::ID Darwin::LookupTypeForExtension(const char *Ext) const { + types::ID Ty = types::lookupTypeForExtension(Ext); + + // Darwin always preprocesses assembly files (unless -x is used explicitly). + if (Ty == types::TY_PP_Asm) + return types::TY_Asm; + + return Ty; } // FIXME: Can we tablegen this? @@ -103,14 +122,13 @@ llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const { } } -DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, - const unsigned (&DarwinVersion)[3], - const unsigned (&_GCCVersion)[3]) - : Darwin(Host, Triple, DarwinVersion) +DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple) + : Darwin(Host, Triple) { - GCCVersion[0] = _GCCVersion[0]; - GCCVersion[1] = _GCCVersion[1]; - GCCVersion[2] = _GCCVersion[2]; + // We can only work with 4.2.1 currently. + GCCVersion[0] = 4; + GCCVersion[1] = 2; + GCCVersion[2] = 1; // Set up the tool chain paths to match gcc. ToolChainDir = "i686-apple-darwin"; @@ -174,7 +192,9 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, Path += ToolChainDir; getProgramPaths().push_back(Path); - getProgramPaths().push_back(getDriver().Dir); + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir) + getProgramPaths().push_back(getDriver().Dir); } Darwin::~Darwin() { @@ -184,6 +204,38 @@ Darwin::~Darwin() { delete it->second; } +std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args) const { + llvm::Triple Triple(ComputeLLVMTriple(Args)); + + // If the target isn't initialized (e.g., an unknown Darwin platform, return + // the default triple). + if (!isTargetInitialized()) + return Triple.getTriple(); + + unsigned Version[3]; + getTargetVersion(Version); + + // Mangle the target version into the OS triple component. For historical + // reasons that make little sense, the version passed here is the "darwin" + // version, which drops the 10 and offsets by 4. See inverse code when + // setting the OS version preprocessor define. + if (!isTargetIPhoneOS()) { + Version[0] = Version[1] + 4; + Version[1] = Version[2]; + Version[2] = 0; + } else { + // Use the environment to communicate that we are targetting iPhoneOS. + Triple.setEnvironmentName("iphoneos"); + } + + llvm::SmallString<16> Str; + llvm::raw_svector_ostream(Str) << "darwin" << Version[0] + << "." << Version[1] << "." << Version[2]; + Triple.setOSName(Str.str()); + + return Triple.getTriple(); +} + Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) @@ -245,7 +297,7 @@ void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir + "/x86_64")); } - + CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/" + ToolChainDir)); Tmp = getDriver().Dir + "/../lib/gcc/" + ToolChainDir; @@ -314,12 +366,13 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args, } } -DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple, - const unsigned (&DarwinVersion)[3]) - : Darwin(Host, Triple, DarwinVersion) +DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple) + : Darwin(Host, Triple) { // We expect 'as', 'ld', etc. to be adjacent to our install dir. - getProgramPaths().push_back(getDriver().Dir); + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir) + getProgramPaths().push_back(getDriver().Dir); } void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args, @@ -350,6 +403,39 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args, break; } P.appendComponent("4.2.1"); + + // Determine the arch specific GCC subdirectory. + const char *ArchSpecificDir = 0; + switch (getTriple().getArch()) { + default: + break; + case llvm::Triple::arm: + case llvm::Triple::thumb: { + std::string Triple = ComputeLLVMTriple(Args); + llvm::StringRef TripleStr = Triple; + if (TripleStr.startswith("armv5") || TripleStr.startswith("thumbv5")) + ArchSpecificDir = "v5"; + else if (TripleStr.startswith("armv6") || TripleStr.startswith("thumbv6")) + ArchSpecificDir = "v6"; + else if (TripleStr.startswith("armv7") || TripleStr.startswith("thumbv7")) + ArchSpecificDir = "v7"; + break; + } + case llvm::Triple::ppc64: + ArchSpecificDir = "ppc64"; + break; + case llvm::Triple::x86_64: + ArchSpecificDir = "x86_64"; + break; + } + + if (ArchSpecificDir) { + P.appendComponent(ArchSpecificDir); + if (P.exists()) + CmdArgs.push_back(Args.MakeArgString("-L" + P.str())); + P.eraseComponent(); + } + if (P.exists()) CmdArgs.push_back(Args.MakeArgString("-L" + P.str())); } @@ -415,18 +501,9 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, } } -DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, - const char *BoundArch) const { - DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); +void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { const OptTable &Opts = getDriver().getOpts(); - // FIXME: We really want to get out of the tool chain level argument - // translation business, as it makes the driver functionality much - // more opaque. For now, we follow gcc closely solely for the - // purpose of easily achieving feature parity & testability. Once we - // have something that works, we should reevaluate each translation - // and try to push it down into tool specific logic. - Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); Arg *iPhoneVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ); if (OSXVersion && iPhoneVersion) { @@ -462,17 +539,17 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, if (OSXTarget) { const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); - OSXVersion = DAL->MakeJoinedArg(0, O, OSXTarget); - DAL->append(OSXVersion); + OSXVersion = Args.MakeJoinedArg(0, O, OSXTarget); + Args.append(OSXVersion); } else if (iPhoneOSTarget) { const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); - iPhoneVersion = DAL->MakeJoinedArg(0, O, iPhoneOSTarget); - DAL->append(iPhoneVersion); + iPhoneVersion = Args.MakeJoinedArg(0, O, iPhoneOSTarget); + Args.append(iPhoneVersion); } else { // Otherwise, assume we are targeting OS X. const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); - OSXVersion = DAL->MakeJoinedArg(0, O, MacosxVersionMin); - DAL->append(OSXVersion); + OSXVersion = Args.MakeJoinedArg(0, O, MacosxVersionMin); + Args.append(OSXVersion); } } @@ -495,6 +572,19 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, << iPhoneVersion->getAsString(Args); } setTarget(iPhoneVersion, Major, Minor, Micro); +} + +DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, + const char *BoundArch) const { + DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + const OptTable &Opts = getDriver().getOpts(); + + // FIXME: We really want to get out of the tool chain level argument + // translation business, as it makes the driver functionality much + // more opaque. For now, we follow gcc closely solely for the + // purpose of easily achieving feature parity & testability. Once we + // have something that works, we should reevaluate each translation + // and try to push it down into tool specific logic. for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { @@ -673,6 +763,11 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, llvm_unreachable("invalid Darwin arch"); } + // Add an explicit version min argument for the deployment target. We do this + // after argument translation because -Xarch_ arguments may add a version min + // argument. + AddDeploymentTarget(*DAL); + return DAL; } @@ -709,13 +804,20 @@ bool Darwin::SupportsObjCGC() const { return !isTargetIPhoneOS(); } +std::string +Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args) const { + return ComputeLLVMTriple(Args); +} + /// Generic_GCC - A tool chain using the 'gcc' command to perform /// all subcommands; this relies on gcc translating the majority of /// command line options. Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple) : ToolChain(Host, Triple) { - getProgramPaths().push_back(getDriver().Dir); + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir.c_str()) + getProgramPaths().push_back(getDriver().Dir); } Generic_GCC::~Generic_GCC() { @@ -864,8 +966,16 @@ Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const { /// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly. -FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple, bool Lib32) +FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { + + // Determine if we are compiling 32-bit code on an x86_64 platform. + bool Lib32 = false; + if (Triple.getArch() == llvm::Triple::x86 && + llvm::Triple(getDriver().DefaultHostTriple).getArch() == + llvm::Triple::x86_64) + Lib32 = true; + getProgramPaths().push_back(getDriver().Dir + "/../libexec"); getProgramPaths().push_back("/usr/libexec"); if (Lib32) { @@ -936,7 +1046,9 @@ Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA) const { AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { - getProgramPaths().push_back(getDriver().Dir); + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir.c_str()) + getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); @@ -973,7 +1085,8 @@ Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const { Linux::Linux(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { - getFilePaths().push_back(getDriver().Dir + "/../lib/clang/1.0/"); + getFilePaths().push_back(getDriver().Dir + + "/../lib/clang/" CLANG_VERSION_STRING "/"); getFilePaths().push_back("/lib/"); getFilePaths().push_back("/usr/lib/"); @@ -994,13 +1107,35 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple& Triple) // list), but that's messy at best. } +Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA) const { + Action::ActionClass Key; + if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) + Key = Action::AnalyzeJobClass; + else + Key = JA.getKind(); + + Tool *&T = Tools[Key]; + if (!T) { + switch (Key) { + case Action::AssembleJobClass: + T = new tools::linuxtools::Assemble(*this); break; + default: + T = &Generic_GCC::SelectTool(C, JA); + } + } + + return *T; +} + /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { // Path mangling to find libexec - getProgramPaths().push_back(getDriver().Dir); + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir.c_str()) + getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); @@ -1028,3 +1163,57 @@ Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA) const { return *T; } + +Windows::Windows(const HostInfo &Host, const llvm::Triple& Triple) + : ToolChain(Host, Triple) { +} + +Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA) const { + Action::ActionClass Key; + if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) + Key = Action::AnalyzeJobClass; + else + Key = JA.getKind(); + + Tool *&T = Tools[Key]; + if (!T) { + switch (Key) { + case Action::InputClass: + case Action::BindArchClass: + case Action::LipoJobClass: + case Action::DsymutilJobClass: + assert(0 && "Invalid tool kind."); + case Action::PreprocessJobClass: + case Action::PrecompileJobClass: + case Action::AnalyzeJobClass: + case Action::CompileJobClass: + T = new tools::Clang(*this); break; + case Action::AssembleJobClass: + T = new tools::ClangAs(*this); break; + case Action::LinkJobClass: + T = new tools::visualstudio::Link(*this); break; + } + } + + return *T; +} + +bool Windows::IsIntegratedAssemblerDefault() const { + return true; +} + +bool Windows::IsUnwindTablesDefault() const { + // FIXME: Gross; we should probably have some separate target + // definition, possibly even reusing the one in clang. + return getArchName() == "x86_64"; +} + +const char *Windows::GetDefaultRelocationModel() const { + return "static"; +} + +const char *Windows::GetForcedPicModel() const { + if (getArchName() == "x86_64") + return "pic"; + return 0; +} diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 4bdd00f..d1f1556 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -42,6 +42,11 @@ public: /// Darwin - The base Darwin tool chain. class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain { +public: + /// The host version. + unsigned DarwinVersion[3]; + +private: mutable llvm::DenseMap Tools; /// Whether the information on the target has been initialized. @@ -61,11 +66,15 @@ class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain { /// initialized. std::string MacosxVersionMin; +private: + void AddDeploymentTarget(DerivedArgList &Args) const; + public: - Darwin(const HostInfo &Host, const llvm::Triple& Triple, - const unsigned (&DarwinVersion)[3]); + Darwin(const HostInfo &Host, const llvm::Triple& Triple); ~Darwin(); + std::string ComputeEffectiveClangTriple(const ArgList &Args) const; + /// @name Darwin Specific Toolchain API /// { @@ -144,17 +153,17 @@ public: /// @name ToolChain Implementation /// { + virtual types::ID LookupTypeForExtension(const char *Ext) const; + virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args, const char *BoundArch) const; virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; virtual bool IsBlocksDefault() const { - // Blocks default to on for OS X 10.6 and iPhoneOS 3.0 and beyond. - if (isTargetIPhoneOS()) - return !isIPhoneOSVersionLT(3); - else - return !isMacosxVersionLT(10, 6); + // Always allow blocks on Darwin; users interested in versioning are + // expected to use /usr/include/Blocks.h. + return true; } virtual bool IsIntegratedAssemblerDefault() const { #ifdef DISABLE_DEFAULT_INTEGRATED_ASSEMBLER @@ -201,8 +210,7 @@ public: /// DarwinClang - The Darwin toolchain used by Clang. class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin { public: - DarwinClang(const HostInfo &Host, const llvm::Triple& Triple, - const unsigned (&DarwinVersion)[3]); + DarwinClang(const HostInfo &Host, const llvm::Triple& Triple); /// @name Darwin ToolChain Implementation /// { @@ -225,9 +233,7 @@ class LLVM_LIBRARY_VISIBILITY DarwinGCC : public Darwin { std::string ToolChainDir; public: - DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, - const unsigned (&DarwinVersion)[3], - const unsigned (&GCCVersion)[3]); + DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple); /// @name Darwin ToolChain Implementation /// { @@ -247,6 +253,8 @@ public: Darwin_Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) {} + std::string ComputeEffectiveClangTriple(const ArgList &Args) const; + virtual const char *GetDefaultRelocationModel() const { return "pic"; } }; @@ -266,7 +274,7 @@ public: class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_GCC { public: - FreeBSD(const HostInfo &Host, const llvm::Triple& Triple, bool Lib32); + FreeBSD(const HostInfo &Host, const llvm::Triple& Triple); virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; }; @@ -288,6 +296,8 @@ public: class LLVM_LIBRARY_VISIBILITY Linux : public Generic_GCC { public: Linux(const HostInfo &Host, const llvm::Triple& Triple); + + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; }; @@ -309,6 +319,20 @@ private: }; +class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain { + mutable llvm::DenseMap Tools; + +public: + Windows(const HostInfo &Host, const llvm::Triple& Triple); + + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; + + virtual bool IsIntegratedAssemblerDefault() const; + virtual bool IsUnwindTablesDefault() const; + virtual const char *GetDefaultRelocationModel() const; + virtual const char *GetForcedPicModel() const; +}; + } // end namespace toolchains } // end namespace driver } // end namespace clang diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index f423d4e..8436561 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -105,10 +105,7 @@ void Clang::AddPreprocessingOptions(const Driver &D, // Determine the output location. const char *DepFile; if (Output.getType() == types::TY_Dependencies) { - if (Output.isPipe()) - DepFile = "-"; - else - DepFile = Output.getFilename(); + DepFile = Output.getFilename(); } else if (Arg *MF = Args.getLastArg(options::OPT_MF)) { DepFile = MF->getValue(Args); } else if (A->getOption().matches(options::OPT_M) || @@ -182,10 +179,8 @@ void Clang::AddPreprocessingOptions(const Driver &D, const Arg *A = it; if (A->getOption().matches(options::OPT_include)) { - // Use PCH if the user requested it, except for C++ (for now). + // Use PCH if the user requested it. bool UsePCH = D.CCCUsePCH; - if (types::isCXX(Inputs[0].getType())) - UsePCH = false; bool FoundPTH = false; bool FoundPCH = false; @@ -342,35 +337,6 @@ static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) { return ""; } -/// getLLVMTriple - Get the LLVM triple to use for a particular toolchain, which -/// may depend on command line arguments. -static std::string getLLVMTriple(const ToolChain &TC, const ArgList &Args) { - switch (TC.getTriple().getArch()) { - default: - return TC.getTripleString(); - - case llvm::Triple::arm: - case llvm::Triple::thumb: { - // FIXME: Factor into subclasses. - llvm::Triple Triple = TC.getTriple(); - - // Thumb2 is the default for V7 on Darwin. - // - // FIXME: Thumb should just be another -target-feaure, not in the triple. - llvm::StringRef Suffix = - getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple)); - bool ThumbDefault = - (Suffix == "v7" && TC.getTriple().getOS() == llvm::Triple::Darwin); - std::string ArchName = "arm"; - if (Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault)) - ArchName = "thumb"; - Triple.setArchName(ArchName + Suffix.str()); - - return Triple.getTriple(); - } - } -} - // FIXME: Move to target hook. static bool isSignedCharDefault(const llvm::Triple &Triple) { switch (Triple.getArch()) { @@ -633,6 +599,11 @@ void Clang::AddX86TargetArgs(const ArgList &Args, CPUName = "x86-64"; else if (getToolChain().getArchName() == "i386") CPUName = "i586"; + } else if (getToolChain().getOS().startswith("openbsd")) { + if (getToolChain().getArchName() == "x86_64") + CPUName = "x86-64"; + else if (getToolChain().getArchName() == "i386") + CPUName = "i486"; } else { if (getToolChain().getArchName() == "x86_64") CPUName = "x86-64"; @@ -694,57 +665,7 @@ static bool needsExceptions(const ArgList &Args, types::ID InputType, } } -/// getEffectiveClangTriple - Get the "effective" target triple, which is the -/// triple for the target but with the OS version potentially modified for -/// Darwin's -mmacosx-version-min. -static std::string getEffectiveClangTriple(const Driver &D, - const ToolChain &TC, - const ArgList &Args) { - llvm::Triple Triple(getLLVMTriple(TC, Args)); - - // Handle -mmacosx-version-min and -miphoneos-version-min. - if (Triple.getOS() != llvm::Triple::Darwin) { - // Diagnose use of -mmacosx-version-min and -miphoneos-version-min on - // non-Darwin. - if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ, - options::OPT_miphoneos_version_min_EQ)) - D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); - } else { - const toolchains::Darwin &DarwinTC( - reinterpret_cast(TC)); - - // If the target isn't initialized (e.g., an unknown Darwin platform, return - // the default triple). - if (!DarwinTC.isTargetInitialized()) - return Triple.getTriple(); - - unsigned Version[3]; - DarwinTC.getTargetVersion(Version); - - // Mangle the target version into the OS triple component. For historical - // reasons that make little sense, the version passed here is the "darwin" - // version, which drops the 10 and offsets by 4. See inverse code when - // setting the OS version preprocessor define. - if (!DarwinTC.isTargetIPhoneOS()) { - Version[0] = Version[1] + 4; - Version[1] = Version[2]; - Version[2] = 0; - } else { - // Use the environment to communicate that we are targetting iPhoneOS. - Triple.setEnvironmentName("iphoneos"); - } - - llvm::SmallString<16> Str; - llvm::raw_svector_ostream(Str) << "darwin" << Version[0] - << "." << Version[1] << "." << Version[2]; - Triple.setOSName(Str.str()); - } - - return Triple.getTriple(); -} - void Clang::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, @@ -763,10 +684,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Add the "effective" target triple. CmdArgs.push_back("-triple"); - std::string TripleStr = getEffectiveClangTriple(D, getToolChain(), Args); + std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); CmdArgs.push_back(Args.MakeArgString(TripleStr)); // Select the appropriate action. + bool IsRewriter = false; if (isa(JA)) { assert(JA.getType() == types::TY_Plist && "Invalid output type."); CmdArgs.push_back("-analyze"); @@ -786,11 +708,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_mno_relax_all, !IsOpt)) CmdArgs.push_back("-mrelax-all"); + + // When using an integrated assembler, we send -Wa, and -Xassembler options + // to -cc1. + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, + options::OPT_Xassembler); } else if (isa(JA)) { - // Use PCH if the user requested it, except for C++ (for now). + // Use PCH if the user requested it. bool UsePCH = D.CCCUsePCH; - if (types::isCXX(Inputs[0].getType())) - UsePCH = false; if (UsePCH) CmdArgs.push_back("-emit-pch"); @@ -813,6 +738,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-emit-pch"); } else if (JA.getType() == types::TY_RewrittenObjC) { CmdArgs.push_back("-rewrite-objc"); + IsRewriter = true; } else { assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!"); @@ -856,6 +782,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Do not enable the missing -dealloc check. // '-analyzer-check-objc-missing-dealloc', CmdArgs.push_back("-analyzer-check-objc-unused-ivars"); + CmdArgs.push_back("-analyzer-check-idempotent-operations"); } // Set the output format. The default is plist, for (lame) historical @@ -999,6 +926,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, break; } + // Pass the linker version in use. + if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { + CmdArgs.push_back("-target-linker-version"); + CmdArgs.push_back(A->getValue(Args)); + } + // -mno-omit-leaf-frame-pointer is default. if (Args.hasFlag(options::OPT_momit_leaf_frame_pointer, options::OPT_mno_omit_leaf_frame_pointer, false)) @@ -1029,6 +962,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } Args.AddAllArgs(CmdArgs, options::OPT_v); + Args.AddLastArg(CmdArgs, options::OPT_H); Args.AddLastArg(CmdArgs, options::OPT_P); Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); @@ -1201,10 +1135,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fno_show_column); Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch); Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); + Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits); Args.AddLastArg(CmdArgs, options::OPT_ftime_report); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); Args.AddLastArg(CmdArgs, options::OPT_fwrapv); Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings); + Args.AddLastArg(CmdArgs, options::OPT_funroll_loops); Args.AddLastArg(CmdArgs, options::OPT_pthread); @@ -1279,15 +1215,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().getTriple().getOS() == llvm::Triple::Win32)) CmdArgs.push_back("-fms-extensions"); + // -fborland-extensions=0 is default. + if (Args.hasFlag(options::OPT_fborland_extensions, + options::OPT_fno_borland_extensions, false)) + CmdArgs.push_back("-fborland-extensions"); + // -fgnu-keywords default varies depending on language; only pass if // specified. if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords, options::OPT_fno_gnu_keywords)) A->render(Args, CmdArgs); - // -fnext-runtime is default. + // -fnext-runtime defaults to on Darwin and when rewriting Objective-C, and is + // -the -cc1 default. + bool NeXTRuntimeIsDefault = + IsRewriter || getToolChain().getTriple().getOS() == llvm::Triple::Darwin; if (!Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime, - getToolChain().getTriple().getOS() == llvm::Triple::Darwin)) + NeXTRuntimeIsDefault)) CmdArgs.push_back("-fgnu-runtime"); // -fobjc-nonfragile-abi=0 is default. @@ -1389,7 +1333,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fdiagnostics-show-category"); CmdArgs.push_back(A->getValue(Args)); } - + // Color diagnostics are the default, unless the terminal doesn't support // them. if (Args.hasFlag(options::OPT_fcolor_diagnostics, @@ -1404,7 +1348,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag(options::OPT_fspell_checking, options::OPT_fno_spell_checking)) CmdArgs.push_back("-fno-spell-checking"); - + if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ)) A->render(Args, CmdArgs); @@ -1464,9 +1408,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Output.getType() == types::TY_Dependencies) { // Handled with other dependency code. - } else if (Output.isPipe()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back("-"); } else if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -1479,9 +1420,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &II = *it; CmdArgs.push_back("-x"); CmdArgs.push_back(types::getTypeName(II.getType())); - if (II.isPipe()) - CmdArgs.push_back("-"); - else if (II.isFilename()) + if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else II.getInputArg().renderAsInput(Args, CmdArgs); @@ -1489,7 +1428,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_undef); - std::string Exec = getToolChain().getDriver().getClangProgramPath(); + const char *Exec = getToolChain().getDriver().getClangProgramPath(); // Optionally embed the -cc1 level arguments into the debug info, for build // analysis. @@ -1498,7 +1437,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) (*it)->render(Args, OriginalArgs); - + llvm::SmallString<256> Flags; Flags += Exec; for (unsigned i = 0, e = OriginalArgs.size(); i != e; ++i) { @@ -1509,7 +1448,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Flags.str())); } - Dest.addCommand(new Command(JA, *this, Exec.c_str(), CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); // Explicitly warn that these options are unsupported, even though // we are allowing compilation to continue. @@ -1533,12 +1472,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; assert(Inputs.size() == 1 && "Unexpected number of inputs."); @@ -1551,7 +1488,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // Add the "effective" target triple. CmdArgs.push_back("-triple"); - std::string TripleStr = getEffectiveClangTriple(D, getToolChain(), Args); + std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); CmdArgs.push_back(Args.MakeArgString(TripleStr)); // Set the output mode, we currently only expect to be used as a real @@ -1581,19 +1518,14 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - if (Input.isPipe()) { - CmdArgs.push_back("-"); - } else { - assert(Input.isFilename() && "Invalid input."); - CmdArgs.push_back(Input.getFilename()); - } + assert(Input.isFilename() && "Invalid input."); + CmdArgs.push_back(Input.getFilename()); - std::string Exec = getToolChain().getDriver().getClangProgramPath(); - Dest.addCommand(new Command(JA, *this, Exec.c_str(), CmdArgs)); + const char *Exec = getToolChain().getDriver().getClangProgramPath(); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, @@ -1605,6 +1537,11 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; if (A->getOption().hasForwardToGCC()) { + // Don't forward any -g arguments to assembly steps. + if (isa(JA) && + A->getOption().matches(options::OPT_g_Group)) + continue; + // It is unfortunate that we have to claim here, as this means // we will basically never report anything interesting for // platforms using a generic gcc, even if we are just using gcc @@ -1640,10 +1577,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, else if (Arch == "x86_64" || Arch == "powerpc64") CmdArgs.push_back("-m64"); - if (Output.isPipe()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back("-"); - } else if (Output.isFilename()) { + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { @@ -1678,9 +1612,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(types::getTypeName(II.getType())); } - if (II.isPipe()) - CmdArgs.push_back("-"); - else if (II.isFilename()) + if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else // Don't render as input, we need gcc to do the translations. @@ -1690,7 +1622,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, const char *GCCName = getToolChain().getDriver().CCCGenericGCCName.c_str(); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void gcc::Preprocess::RenderExtraToolArgs(const JobAction &JA, @@ -2022,10 +1954,7 @@ void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args, it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; - if (II.isPipe()) - CmdArgs.push_back("-"); - else - CmdArgs.push_back(II.getFilename()); + CmdArgs.push_back(II.getFilename()); } Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA, @@ -2063,7 +1992,7 @@ void darwin::CC1::AddCPPArgs(const ArgList &Args, } void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, + const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2078,12 +2007,9 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-traditional-cpp"); ArgStringList OutputArgs; - if (Output.isFilename()) { - OutputArgs.push_back("-o"); - OutputArgs.push_back(Output.getFilename()); - } else { - assert(Output.isPipe() && "Unexpected CC1 output."); - } + assert(Output.isFilename() && "Unexpected CC1 output."); + OutputArgs.push_back("-o"); + OutputArgs.push_back(Output.getFilename()); if (Args.hasArg(options::OPT_E)) { AddCPPOptionsArgs(Args, CmdArgs, Inputs, OutputArgs); @@ -2097,11 +2023,11 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA, const char *CC1Name = getCC1Name(Inputs[0].getType()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(CC1Name)); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, + const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2133,9 +2059,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, ArgStringList OutputArgs; if (Output.getType() != types::TY_PCH) { OutputArgs.push_back("-o"); - if (Output.isPipe()) - OutputArgs.push_back("-"); - else if (Output.isNothing()) + if (Output.isNothing()) OutputArgs.push_back("/dev/null"); else OutputArgs.push_back(Output.getFilename()); @@ -2168,10 +2092,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, return; } - if (II.isPipe()) - CmdArgs.push_back("-"); - else - CmdArgs.push_back(II.getFilename()); + CmdArgs.push_back(II.getFilename()); } if (OutputArgsEarly) { @@ -2197,11 +2118,11 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, const char *CC1Name = getCC1Name(Inputs[0].getType()); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(CC1Name)); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, + const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2224,7 +2145,9 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, // Derived from asm spec. AddDarwinArch(Args, CmdArgs); - if (!getDarwinToolChain().isTargetIPhoneOS() || + // Use -force_cpusubtype_ALL on x86 by default. + if (getToolChain().getTriple().getArch() == llvm::Triple::x86 || + getToolChain().getTriple().getArch() == llvm::Triple::x86_64 || Args.hasArg(options::OPT_force__cpusubtype__ALL)) CmdArgs.push_back("-force_cpusubtype_ALL"); @@ -2241,18 +2164,14 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - if (Input.isPipe()) { - CmdArgs.push_back("-"); - } else { - assert(Input.isFilename() && "Invalid input."); - CmdArgs.push_back(Input.getFilename()); - } + assert(Input.isFilename() && "Invalid input."); + CmdArgs.push_back(Input.getFilename()); // asm_final spec is empty. const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::DarwinTool::AddDarwinArch(const ArgList &Args, @@ -2272,6 +2191,22 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); + unsigned Version[3] = { 0, 0, 0 }; + if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { + bool HadExtra; + if (!Driver::GetReleaseVersion(A->getValue(Args), Version[0], + Version[1], Version[2], HadExtra) || + HadExtra) + D.Diag(clang::diag::err_drv_invalid_version_number) + << A->getAsString(Args); + } + + // Newer linkers support -demangle, pass it if supported and not disabled by + // the user. + if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) { + CmdArgs.push_back("-demangle"); + } + // Derived from the "link" spec. Args.AddAllArgs(CmdArgs, options::OPT_static); if (!Args.hasArg(options::OPT_static)) @@ -2413,7 +2348,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, } void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, + const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2571,11 +2506,11 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, + const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2595,11 +2530,11 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("lipo")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, + const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2615,11 +2550,11 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("dsymutil")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, + const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2629,27 +2564,21 @@ void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_Xassembler); CmdArgs.push_back("-o"); - if (Output.isPipe()) - CmdArgs.push_back("-"); - else - CmdArgs.push_back(Output.getFilename()); + CmdArgs.push_back(Output.getFilename()); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; - if (II.isPipe()) - CmdArgs.push_back("-"); - else - CmdArgs.push_back(II.getFilename()); + CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("gas")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, + const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2676,10 +2605,7 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, } } - if (Output.isPipe()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back("-"); - } else if (Output.isFilename()) { + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { @@ -2721,9 +2647,7 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, D.Diag(clang::diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); - if (II.isPipe()) - CmdArgs.push_back("-"); - else if (II.isFilename()) + if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else II.getInputArg().renderAsInput(Args, CmdArgs); @@ -2751,11 +2675,11 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, + const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2765,27 +2689,21 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_Xassembler); CmdArgs.push_back("-o"); - if (Output.isPipe()) - CmdArgs.push_back("-"); - else - CmdArgs.push_back(Output.getFilename()); + CmdArgs.push_back(Output.getFilename()); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; - if (II.isPipe()) - CmdArgs.push_back("-"); - else - CmdArgs.push_back(II.getFilename()); + CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, + const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2811,10 +2729,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, } } - if (Output.isPipe()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back("-"); - } else if (Output.isFilename()) { + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { @@ -2838,7 +2753,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, if (Triple.substr(0, 6) == "x86_64") Triple.replace(0, 6, "amd64"); CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc-lib/" + Triple + - "/3.3.5")); + "/4.2.1")); Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); @@ -2854,9 +2769,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, D.Diag(clang::diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); - if (II.isPipe()) - CmdArgs.push_back("-"); - else if (II.isFilename()) + if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else II.getInputArg().renderAsInput(Args, CmdArgs); @@ -2864,6 +2777,11 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { + if (D.CCCIsCXX) { + CmdArgs.push_back("-lstdc++"); + CmdArgs.push_back("-lm"); + } + // FIXME: For some reason GCC passes -lgcc before adding // the default system libraries. Just mimic this for now. CmdArgs.push_back("-lgcc"); @@ -2887,11 +2805,11 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, + const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2913,27 +2831,21 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_Xassembler); CmdArgs.push_back("-o"); - if (Output.isPipe()) - CmdArgs.push_back("-"); - else - CmdArgs.push_back(Output.getFilename()); + CmdArgs.push_back(Output.getFilename()); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; - if (II.isPipe()) - CmdArgs.push_back("-"); - else - CmdArgs.push_back(II.getFilename()); + CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, + const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -2959,10 +2871,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("elf_i386_fbsd"); } - if (Output.isPipe()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back("-"); - } else if (Output.isFilename()) { + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { @@ -2989,6 +2898,10 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); + Args.AddAllArgs(CmdArgs, options::OPT_s); + Args.AddAllArgs(CmdArgs, options::OPT_t); + Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); + Args.AddAllArgs(CmdArgs, options::OPT_r); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { @@ -3000,9 +2913,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, D.Diag(clang::diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); - if (II.isPipe()) - CmdArgs.push_back("-"); - else if (II.isFilename()) + if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else II.getInputArg().renderAsInput(Args, CmdArgs); @@ -3053,51 +2964,79 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } +void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + // Add --32/--64 to make sure we get the format we want. + // This is incomplete + if (getToolChain().getArch() == llvm::Triple::x86) { + CmdArgs.push_back("--32"); + } else if (getToolChain().getArch() == llvm::Triple::x86_64) { + CmdArgs.push_back("--64"); + } else if (getToolChain().getArch() == llvm::Triple::arm) { + llvm::StringRef MArch = getToolChain().getArchName(); + if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a") + CmdArgs.push_back("-mfpu=neon"); + } + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, + options::OPT_Xassembler); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + for (InputInfoList::const_iterator + it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { + const InputInfo &II = *it; + CmdArgs.push_back(II.getFilename()); + } + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("as")); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); +} + + void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { ArgStringList CmdArgs; Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); - if (Output.isPipe()) - CmdArgs.push_back("-"); - else - CmdArgs.push_back(Output.getFilename()); + CmdArgs.push_back(Output.getFilename()); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; - if (II.isPipe()) - CmdArgs.push_back("-"); - else - CmdArgs.push_back(II.getFilename()); + CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("gas")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void minix::Link::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; - if (Output.isPipe()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back("-"); - } else if (Output.isFilename()) { + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { @@ -3123,9 +3062,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA, D.Diag(clang::diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); - if (II.isPipe()) - CmdArgs.push_back("-"); - else if (II.isFilename()) + if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else II.getInputArg().renderAsInput(Args, CmdArgs); @@ -3156,7 +3093,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("/usr/gnu/bin/gld")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } /// DragonFly Tools @@ -3164,7 +3101,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA, // For now, DragonFly Assemble does just about the same as for // FreeBSD, but this may change soon. void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, + const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -3179,30 +3116,24 @@ void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_Xassembler); CmdArgs.push_back("-o"); - if (Output.isPipe()) - CmdArgs.push_back("-"); - else - CmdArgs.push_back(Output.getFilename()); + CmdArgs.push_back(Output.getFilename()); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; - if (II.isPipe()) - CmdArgs.push_back("-"); - else - CmdArgs.push_back(II.getFilename()); + CmdArgs.push_back(II.getFilename()); } const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; @@ -3224,10 +3155,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("elf_i386"); } - if (Output.isPipe()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back("-"); - } else if (Output.isFilename()) { + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); } else { @@ -3265,9 +3193,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, D.Diag(clang::diag::err_drv_no_linker_llvm_support) << getToolChain().getTripleString(); - if (II.isPipe()) - CmdArgs.push_back("-"); - else if (II.isFilename()) + if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else II.getInputArg().renderAsInput(Args, CmdArgs); @@ -3293,6 +3219,11 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("/usr/lib"); } + if (D.CCCIsCXX) { + CmdArgs.push_back("-lstdc++"); + CmdArgs.push_back("-lm"); + } + if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-lgcc_pic"); } else { @@ -3328,5 +3259,46 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld")); - Dest.addCommand(new Command(JA, *this, Exec, CmdArgs)); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); +} + +void visualstudio::Link::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); + ArgStringList CmdArgs; + + if (Output.isFilename()) { + CmdArgs.push_back(Args.MakeArgString(std::string("-out:") + Output.getFilename())); + } else { + assert(Output.isNothing() && "Invalid output."); + } + + if (!Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nostartfiles)) { + CmdArgs.push_back("-defaultlib:libcmt"); + } + + CmdArgs.push_back("-nologo"); + + for (InputInfoList::const_iterator + it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { + const InputInfo &II = *it; + + // Don't try to pass LLVM inputs to visual studio linker. + if (II.getType() == types::TY_LLVM_BC) + D.Diag(clang::diag::err_drv_no_linker_llvm_support) + << getToolChain().getTripleString(); + + if (II.isFilename()) + CmdArgs.push_back(II.getFilename()); + else + II.getInputArg().renderAsInput(Args, CmdArgs); + } + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("link.exe")); + C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index 2a18103..b5defa4 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -41,14 +41,11 @@ namespace tools { public: Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasGoodDiagnostics() const { return true; } virtual bool hasIntegratedAssembler() const { return true; } virtual bool hasIntegratedCPP() const { return true; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -61,14 +58,11 @@ namespace tools { ClangAs(const ToolChain &TC) : Tool("clang::as", "clang integrated assembler", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasGoodDiagnostics() const { return true; } virtual bool hasIntegratedAssembler() const { return false; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -83,7 +77,6 @@ namespace gcc { const ToolChain &TC) : Tool(Name, ShortName, TC) {} virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -101,8 +94,6 @@ namespace gcc { Preprocess(const ToolChain &TC) : Common("gcc::Preprocess", "gcc preprocessor", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasGoodDiagnostics() const { return true; } virtual bool hasIntegratedCPP() const { return false; } @@ -115,8 +106,6 @@ namespace gcc { Precompile(const ToolChain &TC) : Common("gcc::Precompile", "gcc precompile", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return false; } virtual bool hasGoodDiagnostics() const { return true; } virtual bool hasIntegratedCPP() const { return true; } @@ -129,8 +118,6 @@ namespace gcc { Compile(const ToolChain &TC) : Common("gcc::Compile", "gcc frontend", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasGoodDiagnostics() const { return true; } virtual bool hasIntegratedCPP() const { return true; } @@ -143,8 +130,6 @@ namespace gcc { Assemble(const ToolChain &TC) : Common("gcc::Assemble", "assembler (via gcc)", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return false; } virtual bool hasIntegratedCPP() const { return false; } virtual void RenderExtraToolArgs(const JobAction &JA, @@ -156,8 +141,6 @@ namespace gcc { Link(const ToolChain &TC) : Common("gcc::Link", "linker (via gcc)", TC) {} - virtual bool acceptsPipedInput() const { return false; } - virtual bool canPipeOutput() const { return false; } virtual bool hasIntegratedCPP() const { return false; } virtual void RenderExtraToolArgs(const JobAction &JA, @@ -207,8 +190,6 @@ namespace darwin { CC1(const char *Name, const char *ShortName, const ToolChain &TC) : DarwinTool(Name, ShortName, TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasGoodDiagnostics() const { return true; } virtual bool hasIntegratedCPP() const { return true; } }; @@ -219,7 +200,6 @@ namespace darwin { "gcc preprocessor", TC) {} virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -231,7 +211,6 @@ namespace darwin { Compile(const ToolChain &TC) : CC1("darwin::Compile", "gcc frontend", TC) {} virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -243,12 +222,9 @@ namespace darwin { Assemble(const ToolChain &TC) : DarwinTool("darwin::Assemble", "assembler", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return false; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -261,12 +237,9 @@ namespace darwin { public: Link(const ToolChain &TC) : DarwinTool("darwin::Link", "linker", TC) {} - virtual bool acceptsPipedInput() const { return false; } - virtual bool canPipeOutput() const { return false; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -277,12 +250,9 @@ namespace darwin { public: Lipo(const ToolChain &TC) : DarwinTool("darwin::Lipo", "lipo", TC) {} - virtual bool acceptsPipedInput() const { return false; } - virtual bool canPipeOutput() const { return false; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -294,12 +264,9 @@ namespace darwin { Dsymutil(const ToolChain &TC) : DarwinTool("darwin::Dsymutil", "dsymutil", TC) {} - virtual bool acceptsPipedInput() const { return false; } - virtual bool canPipeOutput() const { return false; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -314,12 +281,9 @@ namespace openbsd { Assemble(const ToolChain &TC) : Tool("openbsd::Assemble", "assembler", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -329,12 +293,9 @@ namespace openbsd { public: Link(const ToolChain &TC) : Tool("openbsd::Link", "linker", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -349,12 +310,9 @@ namespace freebsd { Assemble(const ToolChain &TC) : Tool("freebsd::Assemble", "assembler", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -364,12 +322,9 @@ namespace freebsd { public: Link(const ToolChain &TC) : Tool("freebsd::Link", "linker", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -377,6 +332,22 @@ namespace freebsd { }; } // end namespace freebsd + /// linux -- Directly call GNU Binutils assembler and linker +namespace linuxtools { + class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { + public: + Assemble(const ToolChain &TC) : Tool("linux::Assemble", "assembler", + TC) {} + + virtual bool hasIntegratedCPP() const { return false; } + + virtual void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, + const char *LinkingOutput) const; + }; +} /// minix -- Directly call GNU Binutils assembler and linker namespace minix { class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { @@ -384,12 +355,9 @@ namespace minix { Assemble(const ToolChain &TC) : Tool("minix::Assemble", "assembler", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -399,12 +367,9 @@ namespace minix { public: Link(const ToolChain &TC) : Tool("minix::Link", "linker", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -419,12 +384,9 @@ namespace auroraux { Assemble(const ToolChain &TC) : Tool("auroraux::Assemble", "assembler", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -434,12 +396,9 @@ namespace auroraux { public: Link(const ToolChain &TC) : Tool("auroraux::Link", "linker", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -454,12 +413,9 @@ namespace dragonfly { Assemble(const ToolChain &TC) : Tool("dragonfly::Assemble", "assembler", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -469,12 +425,9 @@ namespace dragonfly { public: Link(const ToolChain &TC) : Tool("dragonfly::Link", "linker", TC) {} - virtual bool acceptsPipedInput() const { return true; } - virtual bool canPipeOutput() const { return true; } virtual bool hasIntegratedCPP() const { return false; } virtual void ConstructJob(Compilation &C, const JobAction &JA, - Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &TCArgs, @@ -482,6 +435,22 @@ namespace dragonfly { }; } // end namespace dragonfly + /// Visual studio tools. +namespace visualstudio { + class LLVM_LIBRARY_VISIBILITY Link : public Tool { + public: + Link(const ToolChain &TC) : Tool("visualstudio::Link", "linker", TC) {} + + virtual bool hasIntegratedCPP() const { return false; } + + virtual void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, + const char *LinkingOutput) const; + }; +} // end namespace visualstudio + } // end namespace toolchains } // end namespace driver } // end namespace clang diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 87b01d4..eb7f270 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -37,7 +37,7 @@ namespace { public: ASTPrinter(llvm::raw_ostream* o = NULL, bool Dump = false) - : Out(o? *o : llvm::errs()), Dump(Dump) { } + : Out(o? *o : llvm::outs()), Dump(Dump) { } virtual void HandleTranslationUnit(ASTContext &Context) { PrintingPolicy Policy = Context.PrintingPolicy; diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp index e916e20..b46212f 100644 --- a/lib/Frontend/ASTMerge.cpp +++ b/lib/Frontend/ASTMerge.cpp @@ -40,10 +40,16 @@ void ASTMergeAction::ExecuteAction() { &CI.getASTContext()); llvm::IntrusiveRefCntPtr Diags(&CI.getDiagnostics()); for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) { - ASTUnit *Unit = ASTUnit::LoadFromPCHFile(ASTFiles[I], Diags, false); + ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags, false); if (!Unit) continue; + // Reset the argument -> string function so that it has the AST + // context we want, since the Sema object created by + // LoadFromASTFile will override it. + CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument, + &CI.getASTContext()); + ASTImporter Importer(CI.getDiagnostics(), CI.getASTContext(), CI.getFileManager(), diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 88f0037..c76488b 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -12,10 +12,10 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/ASTUnit.h" -#include "clang/Frontend/PCHReader.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/TypeOrdering.h" #include "clang/AST/StmtVisitor.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" @@ -25,30 +25,294 @@ #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendOptions.h" +#include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/ASTWriter.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/System/Host.h" #include "llvm/System/Path.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Timer.h" +#include +#include +#include using namespace clang; +/// \brief After failing to build a precompiled preamble (due to +/// errors in the source that occurs in the preamble), the number of +/// reparses during which we'll skip even trying to precompile the +/// preamble. +const unsigned DefaultPreambleRebuildInterval = 5; + ASTUnit::ASTUnit(bool _MainFileIsAST) - : MainFileIsAST(_MainFileIsAST), ConcurrencyCheckValue(CheckUnlocked) { } + : CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST), + CompleteTranslationUnit(true), ConcurrencyCheckValue(CheckUnlocked), + PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0), + ShouldCacheCodeCompletionResults(false), + NumTopLevelDeclsAtLastCompletionCache(0), + CacheCodeCompletionCoolDown(0), + UnsafeToFree(false) { +} ASTUnit::~ASTUnit() { ConcurrencyCheckValue = CheckLocked; + CleanTemporaryFiles(); + if (!PreambleFile.empty()) + llvm::sys::Path(PreambleFile).eraseFromDisk(); + + // Free the buffers associated with remapped files. We are required to + // perform this operation here because we explicitly request that the + // compiler instance *not* free these buffers for each invocation of the + // parser. + if (Invocation.get()) { + PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts(); + for (PreprocessorOptions::remapped_file_buffer_iterator + FB = PPOpts.remapped_file_buffer_begin(), + FBEnd = PPOpts.remapped_file_buffer_end(); + FB != FBEnd; + ++FB) + delete FB->second; + } + + delete SavedMainFileBuffer; + delete PreambleBuffer; + + ClearCachedCompletionResults(); + + for (unsigned I = 0, N = Timers.size(); I != N; ++I) + delete Timers[I]; +} + +void ASTUnit::CleanTemporaryFiles() { for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) TemporaryFiles[I].eraseFromDisk(); + TemporaryFiles.clear(); +} + +/// \brief Determine the set of code-completion contexts in which this +/// declaration should be shown. +static unsigned getDeclShowContexts(NamedDecl *ND, + const LangOptions &LangOpts, + bool &IsNestedNameSpecifier) { + IsNestedNameSpecifier = false; + + if (isa(ND)) + ND = dyn_cast(ND->getUnderlyingDecl()); + if (!ND) + return 0; + + unsigned Contexts = 0; + if (isa(ND) || isa(ND) || + isa(ND) || isa(ND)) { + // Types can appear in these contexts. + if (LangOpts.CPlusPlus || !isa(ND)) + Contexts |= (1 << (CodeCompletionContext::CCC_TopLevel - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) + | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1)) + | (1 << (CodeCompletionContext::CCC_Statement - 1)) + | (1 << (CodeCompletionContext::CCC_Type - 1)); + + // In C++, types can appear in expressions contexts (for functional casts). + if (LangOpts.CPlusPlus) + Contexts |= (1 << (CodeCompletionContext::CCC_Expression - 1)); + + // In Objective-C, message sends can send interfaces. In Objective-C++, + // all types are available due to functional casts. + if (LangOpts.CPlusPlus || isa(ND)) + Contexts |= (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)); + + // Deal with tag names. + if (isa(ND)) { + Contexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1)); + + // Part of the nested-name-specifier in C++0x. + if (LangOpts.CPlusPlus0x) + IsNestedNameSpecifier = true; + } else if (RecordDecl *Record = dyn_cast(ND)) { + if (Record->isUnion()) + Contexts |= (1 << (CodeCompletionContext::CCC_UnionTag - 1)); + else + Contexts |= (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1)); + + if (LangOpts.CPlusPlus) + IsNestedNameSpecifier = true; + } else if (isa(ND) || isa(ND)) + IsNestedNameSpecifier = true; + } else if (isa(ND) || isa(ND)) { + // Values can appear in these contexts. + Contexts = (1 << (CodeCompletionContext::CCC_Statement - 1)) + | (1 << (CodeCompletionContext::CCC_Expression - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)); + } else if (isa(ND)) { + Contexts = (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1)); + } else if (isa(ND) || isa(ND)) { + Contexts = (1 << (CodeCompletionContext::CCC_Namespace - 1)); + + // Part of the nested-name-specifier. + IsNestedNameSpecifier = true; + } + + return Contexts; +} + +void ASTUnit::CacheCodeCompletionResults() { + if (!TheSema) + return; + + llvm::Timer *CachingTimer = 0; + if (TimerGroup.get()) { + CachingTimer = new llvm::Timer("Cache global code completions", + *TimerGroup); + CachingTimer->startTimer(); + Timers.push_back(CachingTimer); + } + + // Clear out the previous results. + ClearCachedCompletionResults(); + + // Gather the set of global code completions. + typedef CodeCompletionResult Result; + llvm::SmallVector Results; + TheSema->GatherGlobalCodeCompletions(Results); + + // Translate global code completions into cached completions. + llvm::DenseMap CompletionTypes; + + for (unsigned I = 0, N = Results.size(); I != N; ++I) { + switch (Results[I].Kind) { + case Result::RK_Declaration: { + bool IsNestedNameSpecifier = false; + CachedCodeCompletionResult CachedResult; + CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); + CachedResult.ShowInContexts = getDeclShowContexts(Results[I].Declaration, + Ctx->getLangOptions(), + IsNestedNameSpecifier); + CachedResult.Priority = Results[I].Priority; + CachedResult.Kind = Results[I].CursorKind; + CachedResult.Availability = Results[I].Availability; + + // Keep track of the type of this completion in an ASTContext-agnostic + // way. + QualType UsageType = getDeclUsageType(*Ctx, Results[I].Declaration); + if (UsageType.isNull()) { + CachedResult.TypeClass = STC_Void; + CachedResult.Type = 0; + } else { + CanQualType CanUsageType + = Ctx->getCanonicalType(UsageType.getUnqualifiedType()); + CachedResult.TypeClass = getSimplifiedTypeClass(CanUsageType); + + // Determine whether we have already seen this type. If so, we save + // ourselves the work of formatting the type string by using the + // temporary, CanQualType-based hash table to find the associated value. + unsigned &TypeValue = CompletionTypes[CanUsageType]; + if (TypeValue == 0) { + TypeValue = CompletionTypes.size(); + CachedCompletionTypes[QualType(CanUsageType).getAsString()] + = TypeValue; + } + + CachedResult.Type = TypeValue; + } + + CachedCompletionResults.push_back(CachedResult); + + /// Handle nested-name-specifiers in C++. + if (TheSema->Context.getLangOptions().CPlusPlus && + IsNestedNameSpecifier && !Results[I].StartsNestedNameSpecifier) { + // The contexts in which a nested-name-specifier can appear in C++. + unsigned NNSContexts + = (1 << (CodeCompletionContext::CCC_TopLevel - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) + | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1)) + | (1 << (CodeCompletionContext::CCC_Statement - 1)) + | (1 << (CodeCompletionContext::CCC_Expression - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)) + | (1 << (CodeCompletionContext::CCC_EnumTag - 1)) + | (1 << (CodeCompletionContext::CCC_UnionTag - 1)) + | (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1)) + | (1 << (CodeCompletionContext::CCC_Type - 1)) + | (1 << (CodeCompletionContext::CCC_PotentiallyQualifiedName - 1)); + + if (isa(Results[I].Declaration) || + isa(Results[I].Declaration)) + NNSContexts |= (1 << (CodeCompletionContext::CCC_Namespace - 1)); + + if (unsigned RemainingContexts + = NNSContexts & ~CachedResult.ShowInContexts) { + // If there any contexts where this completion can be a + // nested-name-specifier but isn't already an option, create a + // nested-name-specifier completion. + Results[I].StartsNestedNameSpecifier = true; + CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); + CachedResult.ShowInContexts = RemainingContexts; + CachedResult.Priority = CCP_NestedNameSpecifier; + CachedResult.TypeClass = STC_Void; + CachedResult.Type = 0; + CachedCompletionResults.push_back(CachedResult); + } + } + break; + } + + case Result::RK_Keyword: + case Result::RK_Pattern: + // Ignore keywords and patterns; we don't care, since they are so + // easily regenerated. + break; + + case Result::RK_Macro: { + CachedCodeCompletionResult CachedResult; + CachedResult.Completion = Results[I].CreateCodeCompletionString(*TheSema); + CachedResult.ShowInContexts + = (1 << (CodeCompletionContext::CCC_TopLevel - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCInterface - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCImplementation - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) + | (1 << (CodeCompletionContext::CCC_ClassStructUnion - 1)) + | (1 << (CodeCompletionContext::CCC_Statement - 1)) + | (1 << (CodeCompletionContext::CCC_Expression - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)) + | (1 << (CodeCompletionContext::CCC_MacroNameUse - 1)) + | (1 << (CodeCompletionContext::CCC_PreprocessorExpression - 1)); + + CachedResult.Priority = Results[I].Priority; + CachedResult.Kind = Results[I].CursorKind; + CachedResult.Availability = Results[I].Availability; + CachedResult.TypeClass = STC_Void; + CachedResult.Type = 0; + CachedCompletionResults.push_back(CachedResult); + break; + } + } + Results[I].Destroy(); + } + + if (CachingTimer) + CachingTimer->stopTimer(); + + // Make a note of the state when we performed this caching. + NumTopLevelDeclsAtLastCompletionCache = top_level_size(); + CacheCodeCompletionCoolDown = 15; +} + +void ASTUnit::ClearCachedCompletionResults() { + for (unsigned I = 0, N = CachedCompletionResults.size(); I != N; ++I) + delete CachedCompletionResults[I].Completion; + CachedCompletionResults.clear(); + CachedCompletionTypes.clear(); } namespace { -/// \brief Gathers information from PCHReader that will be used to initialize +/// \brief Gathers information from ASTReader that will be used to initialize /// a Preprocessor. -class PCHInfoCollector : public PCHReaderListener { +class ASTInfoCollector : public ASTReaderListener { LangOptions &LangOpt; HeaderSearch &HSI; std::string &TargetTriple; @@ -58,7 +322,7 @@ class PCHInfoCollector : public PCHReaderListener { unsigned NumHeaderInfos; public: - PCHInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI, + ASTInfoCollector(LangOptions &LangOpt, HeaderSearch &HSI, std::string &TargetTriple, std::string &Predefines, unsigned &Counter) : LangOpt(LangOpt), HSI(HSI), TargetTriple(TargetTriple), @@ -115,14 +379,19 @@ class CaptureDroppedDiagnostics { public: CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags, llvm::SmallVectorImpl &StoredDiags) - : Diags(Diags), Client(StoredDiags), PreviousClient(Diags.getClient()) + : Diags(Diags), Client(StoredDiags), PreviousClient(0) { - if (RequestCapture || Diags.getClient() == 0) + if (RequestCapture || Diags.getClient() == 0) { + PreviousClient = Diags.takeClient(); Diags.setClient(&Client); + } } ~CaptureDroppedDiagnostics() { - Diags.setClient(PreviousClient); + if (Diags.getClient() == &Client) { + Diags.takeClient(); + Diags.setClient(PreviousClient); + } } }; @@ -137,12 +406,12 @@ const std::string &ASTUnit::getOriginalSourceFileName() { return OriginalSourceFile; } -const std::string &ASTUnit::getPCHFileName() { - assert(isMainFileAST() && "Not an ASTUnit from a PCH file!"); - return static_cast(Ctx->getExternalSource())->getFileName(); +const std::string &ASTUnit::getASTFileName() { + assert(isMainFileAST() && "Not an ASTUnit from an AST file!"); + return static_cast(Ctx->getExternalSource())->getFileName(); } -ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, +ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, llvm::IntrusiveRefCntPtr Diags, bool OnlyLocalDecls, RemappedFile *RemappedFiles, @@ -156,13 +425,14 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, DiagnosticOptions DiagOpts; Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); } - + + AST->CaptureDiagnostics = CaptureDiagnostics; AST->OnlyLocalDecls = OnlyLocalDecls; AST->Diagnostics = Diags; AST->FileMgr.reset(new FileManager); AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics())); AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); - + // If requested, capture diagnostics in the ASTUnit. CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(), AST->StoredDiagnostics); @@ -194,34 +464,33 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, std::string Predefines; unsigned Counter; - llvm::OwningPtr Reader; - llvm::OwningPtr Source; + llvm::OwningPtr Reader; - Reader.reset(new PCHReader(AST->getSourceManager(), AST->getFileManager(), + Reader.reset(new ASTReader(AST->getSourceManager(), AST->getFileManager(), AST->getDiagnostics())); - Reader->setListener(new PCHInfoCollector(LangInfo, HeaderInfo, TargetTriple, + Reader->setListener(new ASTInfoCollector(LangInfo, HeaderInfo, TargetTriple, Predefines, Counter)); - switch (Reader->ReadPCH(Filename)) { - case PCHReader::Success: + switch (Reader->ReadAST(Filename)) { + case ASTReader::Success: break; - case PCHReader::Failure: - case PCHReader::IgnorePCH: + case ASTReader::Failure: + case ASTReader::IgnorePCH: AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch); return NULL; } AST->OriginalSourceFile = Reader->getOriginalSourceFile(); - // PCH loaded successfully. Now create the preprocessor. + // AST file loaded successfully. Now create the preprocessor. // Get information about the target being compiled for. // - // FIXME: This is broken, we should store the TargetOptions in the PCH. + // FIXME: This is broken, we should store the TargetOptions in the AST file. TargetOptions TargetOpts; TargetOpts.ABI = ""; - TargetOpts.CXXABI = "itanium"; + TargetOpts.CXXABI = ""; TargetOpts.CPU = ""; TargetOpts.Features.clear(); TargetOpts.Triple = TargetTriple; @@ -244,18 +513,26 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename, PP.getIdentifierTable(), PP.getSelectorTable(), PP.getBuiltinInfo(), - /* FreeMemory = */ false, /* size_reserve = */0)); ASTContext &Context = *AST->Ctx.get(); Reader->InitializeContext(Context); - // Attach the PCH reader to the AST context as an external AST + // Attach the AST reader to the AST context as an external AST // source, so that declarations will be deserialized from the - // PCH file as needed. - Source.reset(Reader.take()); + // AST file as needed. + ASTReader *ReaderPtr = Reader.get(); + llvm::OwningPtr Source(Reader.take()); Context.setExternalSource(Source); + // Create an AST consumer, even though it isn't used. + AST->Consumer.reset(new ASTConsumer); + + // Create a semantic analysis object and tell the AST reader about it. + AST->TheSema.reset(new Sema(PP, Context, *AST->Consumer)); + AST->TheSema->Initialize(); + ReaderPtr->InitializeSema(*AST->TheSema); + return AST.take(); } @@ -276,9 +553,12 @@ public: // fundamental problem in the parser right now. if (isa(D)) continue; - Unit.getTopLevelDecls().push_back(D); + Unit.addTopLevelDecl(D); } } + + // We're not interested in "interesting" decls. + void HandleInterestingDecl(DeclGroupRef) {} }; class TopLevelDeclTrackerAction : public ASTFrontendAction { @@ -294,37 +574,108 @@ public: TopLevelDeclTrackerAction(ASTUnit &_Unit) : Unit(_Unit) {} virtual bool hasCodeCompletionSupport() const { return false; } + virtual bool usesCompleteTranslationUnit() { + return Unit.isCompleteTranslationUnit(); + } }; -} +class PrecompilePreambleConsumer : public PCHGenerator { + ASTUnit &Unit; + std::vector TopLevelDecls; -ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, - llvm::IntrusiveRefCntPtr Diags, - bool OnlyLocalDecls, - bool CaptureDiagnostics) { - // Create the compiler instance to use for building the AST. - CompilerInstance Clang; - llvm::OwningPtr AST; - llvm::OwningPtr Act; +public: + PrecompilePreambleConsumer(ASTUnit &Unit, + const Preprocessor &PP, bool Chaining, + const char *isysroot, llvm::raw_ostream *Out) + : PCHGenerator(PP, Chaining, isysroot, Out), Unit(Unit) { } - if (!Diags.getPtr()) { - // No diagnostics engine was provided, so create our own diagnostics object - // with the default options. - DiagnosticOptions DiagOpts; - Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); + virtual void HandleTopLevelDecl(DeclGroupRef D) { + for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) { + Decl *D = *it; + // FIXME: Currently ObjC method declarations are incorrectly being + // reported as top-level declarations, even though their DeclContext + // is the containing ObjC @interface/@implementation. This is a + // fundamental problem in the parser right now. + if (isa(D)) + continue; + TopLevelDecls.push_back(D); + } } - - Clang.setInvocation(CI); - Clang.setDiagnostics(Diags.getPtr()); - Clang.setDiagnosticClient(Diags->getClient()); + virtual void HandleTranslationUnit(ASTContext &Ctx) { + PCHGenerator::HandleTranslationUnit(Ctx); + if (!Unit.getDiagnostics().hasErrorOccurred()) { + // Translate the top-level declarations we captured during + // parsing into declaration IDs in the precompiled + // preamble. This will allow us to deserialize those top-level + // declarations when requested. + for (unsigned I = 0, N = TopLevelDecls.size(); I != N; ++I) + Unit.addTopLevelDeclFromPreamble( + getWriter().getDeclID(TopLevelDecls[I])); + } + } +}; + +class PrecompilePreambleAction : public ASTFrontendAction { + ASTUnit &Unit; + +public: + explicit PrecompilePreambleAction(ASTUnit &Unit) : Unit(Unit) {} + + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef InFile) { + std::string Sysroot; + llvm::raw_ostream *OS = 0; + bool Chaining; + if (GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, + OS, Chaining)) + return 0; + + const char *isysroot = CI.getFrontendOpts().RelocatablePCH ? + Sysroot.c_str() : 0; + return new PrecompilePreambleConsumer(Unit, CI.getPreprocessor(), Chaining, + isysroot, OS); + } + + virtual bool hasCodeCompletionSupport() const { return false; } + virtual bool hasASTFileSupport() const { return false; } + virtual bool usesCompleteTranslationUnit() { return false; } +}; + +} +/// Parse the source file into a translation unit using the given compiler +/// invocation, replacing the current translation unit. +/// +/// \returns True if a failure occurred that causes the ASTUnit not to +/// contain any translation-unit information, false otherwise. +bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { + delete SavedMainFileBuffer; + SavedMainFileBuffer = 0; + + if (!Invocation.get()) { + delete OverrideMainBuffer; + return true; + } + + // Create the compiler instance to use for building the AST. + CompilerInstance Clang; + Clang.setInvocation(Invocation.take()); + OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; + + // Set up diagnostics, capturing any diagnostics that would + // otherwise be dropped. + Clang.setDiagnostics(&getDiagnostics()); + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, + getDiagnostics(), + StoredDiagnostics); + // Create the target instance. Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), Clang.getTargetOpts())); if (!Clang.hasTarget()) { - Clang.takeDiagnosticClient(); - return 0; + delete OverrideMainBuffer; + return true; } // Inform the target of the language options. @@ -332,7 +683,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); - + assert(Clang.getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST && @@ -340,53 +691,649 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR && "IR inputs not support here!"); - // Create the AST unit. - AST.reset(new ASTUnit(false)); - AST->Diagnostics = Diags; - AST->FileMgr.reset(new FileManager); - AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics())); - AST->OnlyLocalDecls = OnlyLocalDecls; - AST->OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; - - // Capture any diagnostics that would otherwise be dropped. - CaptureDroppedDiagnostics Capture(CaptureDiagnostics, - Clang.getDiagnostics(), - AST->StoredDiagnostics); + // Configure the various subsystems. + // FIXME: Should we retain the previous file manager? + FileMgr.reset(new FileManager); + SourceMgr.reset(new SourceManager(getDiagnostics())); + TheSema.reset(); + Ctx.reset(); + PP.reset(); + + // Clear out old caches and data. + TopLevelDecls.clear(); + CleanTemporaryFiles(); + PreprocessedEntitiesByFile.clear(); + + if (!OverrideMainBuffer) { + StoredDiagnostics.clear(); + TopLevelDeclsInPreamble.clear(); + } // Create a file manager object to provide access to and cache the filesystem. - Clang.setFileManager(&AST->getFileManager()); - + Clang.setFileManager(&getFileManager()); + // Create the source manager. - Clang.setSourceManager(&AST->getSourceManager()); - - Act.reset(new TopLevelDeclTrackerAction(*AST)); + Clang.setSourceManager(&getSourceManager()); + + // If the main file has been overridden due to the use of a preamble, + // make that override happen and introduce the preamble. + PreprocessorOptions &PreprocessorOpts = Clang.getPreprocessorOpts(); + std::string PriorImplicitPCHInclude; + if (OverrideMainBuffer) { + PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer); + PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); + PreprocessorOpts.PrecompiledPreambleBytes.second + = PreambleEndsAtStartOfLine; + PriorImplicitPCHInclude = PreprocessorOpts.ImplicitPCHInclude; + PreprocessorOpts.ImplicitPCHInclude = PreambleFile; + PreprocessorOpts.DisablePCHValidation = true; + + // Keep track of the override buffer; + SavedMainFileBuffer = OverrideMainBuffer; + + // The stored diagnostic has the old source manager in it; update + // the locations to refer into the new source manager. Since we've + // been careful to make sure that the source manager's state + // before and after are identical, so that we can reuse the source + // location itself. + for (unsigned I = 0, N = StoredDiagnostics.size(); I != N; ++I) { + FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), + getSourceManager()); + StoredDiagnostics[I].setLocation(Loc); + } + } else { + PreprocessorOpts.PrecompiledPreambleBytes.first = 0; + PreprocessorOpts.PrecompiledPreambleBytes.second = false; + } + + llvm::OwningPtr Act; + Act.reset(new TopLevelDeclTrackerAction(*this)); if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, Clang.getFrontendOpts().Inputs[0].first)) goto error; - + Act->Execute(); - + // Steal the created target, context, and preprocessor, and take back the // source and file managers. - AST->Ctx.reset(Clang.takeASTContext()); - AST->PP.reset(Clang.takePreprocessor()); + TheSema.reset(Clang.takeSema()); + Consumer.reset(Clang.takeASTConsumer()); + Ctx.reset(Clang.takeASTContext()); + PP.reset(Clang.takePreprocessor()); Clang.takeSourceManager(); Clang.takeFileManager(); - AST->Target.reset(Clang.takeTarget()); - + Target.reset(Clang.takeTarget()); + Act->EndSourceFile(); - Clang.takeDiagnosticClient(); - Clang.takeInvocation(); - - AST->Invocation.reset(Clang.takeInvocation()); - return AST.take(); + // Remove the overridden buffer we used for the preamble. + if (OverrideMainBuffer) { + PreprocessorOpts.eraseRemappedFile( + PreprocessorOpts.remapped_file_buffer_end() - 1); + PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude; + } + Invocation.reset(Clang.takeInvocation()); + + // If we were asked to cache code-completion results and don't have any + // results yet, do so now. + if (ShouldCacheCodeCompletionResults && CachedCompletionResults.empty()) + CacheCodeCompletionResults(); + + return false; + error: + // Remove the overridden buffer we used for the preamble. + if (OverrideMainBuffer) { + PreprocessorOpts.eraseRemappedFile( + PreprocessorOpts.remapped_file_buffer_end() - 1); + PreprocessorOpts.DisablePCHValidation = true; + PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude; + delete OverrideMainBuffer; + } + Clang.takeSourceManager(); Clang.takeFileManager(); - Clang.takeDiagnosticClient(); - return 0; + Invocation.reset(Clang.takeInvocation()); + return true; +} + +/// \brief Simple function to retrieve a path for a preamble precompiled header. +static std::string GetPreamblePCHPath() { + // FIXME: This is lame; sys::Path should provide this function (in particular, + // it should know how to find the temporary files dir). + // FIXME: This is really lame. I copied this code from the Driver! + std::string Error; + const char *TmpDir = ::getenv("TMPDIR"); + if (!TmpDir) + TmpDir = ::getenv("TEMP"); + if (!TmpDir) + TmpDir = ::getenv("TMP"); + if (!TmpDir) + TmpDir = "/tmp"; + llvm::sys::Path P(TmpDir); + P.appendComponent("preamble"); + P.appendSuffix("pch"); + if (P.createTemporaryFileOnDisk()) + return std::string(); + + return P.str(); +} + +/// \brief Compute the preamble for the main file, providing the source buffer +/// that corresponds to the main file along with a pair (bytes, start-of-line) +/// that describes the preamble. +std::pair > +ASTUnit::ComputePreamble(CompilerInvocation &Invocation, + unsigned MaxLines, bool &CreatedBuffer) { + FrontendOptions &FrontendOpts = Invocation.getFrontendOpts(); + PreprocessorOptions &PreprocessorOpts + = Invocation.getPreprocessorOpts(); + CreatedBuffer = false; + + // Try to determine if the main file has been remapped, either from the + // command line (to another file) or directly through the compiler invocation + // (to a memory buffer). + llvm::MemoryBuffer *Buffer = 0; + llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second); + if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) { + // Check whether there is a file-file remapping of the main file + for (PreprocessorOptions::remapped_file_iterator + M = PreprocessorOpts.remapped_file_begin(), + E = PreprocessorOpts.remapped_file_end(); + M != E; + ++M) { + llvm::sys::PathWithStatus MPath(M->first); + if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) { + if (MainFileStatus->uniqueID == MStatus->uniqueID) { + // We found a remapping. Try to load the resulting, remapped source. + if (CreatedBuffer) { + delete Buffer; + CreatedBuffer = false; + } + + Buffer = llvm::MemoryBuffer::getFile(M->second); + if (!Buffer) + return std::make_pair((llvm::MemoryBuffer*)0, + std::make_pair(0, true)); + CreatedBuffer = true; + + // Remove this remapping. We've captured the buffer already. + M = PreprocessorOpts.eraseRemappedFile(M); + E = PreprocessorOpts.remapped_file_end(); + if (M == E) + break; + } + } + } + + // Check whether there is a file-buffer remapping. It supercedes the + // file-file remapping. + for (PreprocessorOptions::remapped_file_buffer_iterator + M = PreprocessorOpts.remapped_file_buffer_begin(), + E = PreprocessorOpts.remapped_file_buffer_end(); + M != E; + ++M) { + llvm::sys::PathWithStatus MPath(M->first); + if (const llvm::sys::FileStatus *MStatus = MPath.getFileStatus()) { + if (MainFileStatus->uniqueID == MStatus->uniqueID) { + // We found a remapping. + if (CreatedBuffer) { + delete Buffer; + CreatedBuffer = false; + } + + Buffer = const_cast(M->second); + + // Remove this remapping. We've captured the buffer already. + M = PreprocessorOpts.eraseRemappedFile(M); + E = PreprocessorOpts.remapped_file_buffer_end(); + if (M == E) + break; + } + } + } + } + + // If the main source file was not remapped, load it now. + if (!Buffer) { + Buffer = llvm::MemoryBuffer::getFile(FrontendOpts.Inputs[0].second); + if (!Buffer) + return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true)); + + CreatedBuffer = true; + } + + return std::make_pair(Buffer, Lexer::ComputePreamble(Buffer, MaxLines)); +} + +static llvm::MemoryBuffer *CreatePaddedMainFileBuffer(llvm::MemoryBuffer *Old, + bool DeleteOld, + unsigned NewSize, + llvm::StringRef NewName) { + llvm::MemoryBuffer *Result + = llvm::MemoryBuffer::getNewUninitMemBuffer(NewSize, NewName); + memcpy(const_cast(Result->getBufferStart()), + Old->getBufferStart(), Old->getBufferSize()); + memset(const_cast(Result->getBufferStart()) + Old->getBufferSize(), + ' ', NewSize - Old->getBufferSize() - 1); + const_cast(Result->getBufferEnd())[-1] = '\n'; + + if (DeleteOld) + delete Old; + + return Result; +} + +/// \brief Attempt to build or re-use a precompiled preamble when (re-)parsing +/// the source file. +/// +/// This routine will compute the preamble of the main source file. If a +/// non-trivial preamble is found, it will precompile that preamble into a +/// precompiled header so that the precompiled preamble can be used to reduce +/// reparsing time. If a precompiled preamble has already been constructed, +/// this routine will determine if it is still valid and, if so, avoid +/// rebuilding the precompiled preamble. +/// +/// \param AllowRebuild When true (the default), this routine is +/// allowed to rebuild the precompiled preamble if it is found to be +/// out-of-date. +/// +/// \param MaxLines When non-zero, the maximum number of lines that +/// can occur within the preamble. +/// +/// \returns If the precompiled preamble can be used, returns a newly-allocated +/// buffer that should be used in place of the main file when doing so. +/// Otherwise, returns a NULL pointer. +llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( + CompilerInvocation PreambleInvocation, + bool AllowRebuild, + unsigned MaxLines) { + FrontendOptions &FrontendOpts = PreambleInvocation.getFrontendOpts(); + PreprocessorOptions &PreprocessorOpts + = PreambleInvocation.getPreprocessorOpts(); + + bool CreatedPreambleBuffer = false; + std::pair > NewPreamble + = ComputePreamble(PreambleInvocation, MaxLines, CreatedPreambleBuffer); + + if (!NewPreamble.second.first) { + // We couldn't find a preamble in the main source. Clear out the current + // preamble, if we have one. It's obviously no good any more. + Preamble.clear(); + if (!PreambleFile.empty()) { + llvm::sys::Path(PreambleFile).eraseFromDisk(); + PreambleFile.clear(); + } + if (CreatedPreambleBuffer) + delete NewPreamble.first; + + // The next time we actually see a preamble, precompile it. + PreambleRebuildCounter = 1; + return 0; + } + + if (!Preamble.empty()) { + // We've previously computed a preamble. Check whether we have the same + // preamble now that we did before, and that there's enough space in + // the main-file buffer within the precompiled preamble to fit the + // new main file. + if (Preamble.size() == NewPreamble.second.first && + PreambleEndsAtStartOfLine == NewPreamble.second.second && + NewPreamble.first->getBufferSize() < PreambleReservedSize-2 && + memcmp(&Preamble[0], NewPreamble.first->getBufferStart(), + NewPreamble.second.first) == 0) { + // The preamble has not changed. We may be able to re-use the precompiled + // preamble. + + // Check that none of the files used by the preamble have changed. + bool AnyFileChanged = false; + + // First, make a record of those files that have been overridden via + // remapping or unsaved_files. + llvm::StringMap > OverriddenFiles; + for (PreprocessorOptions::remapped_file_iterator + R = PreprocessorOpts.remapped_file_begin(), + REnd = PreprocessorOpts.remapped_file_end(); + !AnyFileChanged && R != REnd; + ++R) { + struct stat StatBuf; + if (stat(R->second.c_str(), &StatBuf)) { + // If we can't stat the file we're remapping to, assume that something + // horrible happened. + AnyFileChanged = true; + break; + } + + OverriddenFiles[R->first] = std::make_pair(StatBuf.st_size, + StatBuf.st_mtime); + } + for (PreprocessorOptions::remapped_file_buffer_iterator + R = PreprocessorOpts.remapped_file_buffer_begin(), + REnd = PreprocessorOpts.remapped_file_buffer_end(); + !AnyFileChanged && R != REnd; + ++R) { + // FIXME: Should we actually compare the contents of file->buffer + // remappings? + OverriddenFiles[R->first] = std::make_pair(R->second->getBufferSize(), + 0); + } + + // Check whether anything has changed. + for (llvm::StringMap >::iterator + F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end(); + !AnyFileChanged && F != FEnd; + ++F) { + llvm::StringMap >::iterator Overridden + = OverriddenFiles.find(F->first()); + if (Overridden != OverriddenFiles.end()) { + // This file was remapped; check whether the newly-mapped file + // matches up with the previous mapping. + if (Overridden->second != F->second) + AnyFileChanged = true; + continue; + } + + // The file was not remapped; check whether it has changed on disk. + struct stat StatBuf; + if (stat(F->first(), &StatBuf)) { + // If we can't stat the file, assume that something horrible happened. + AnyFileChanged = true; + } else if (StatBuf.st_size != F->second.first || + StatBuf.st_mtime != F->second.second) + AnyFileChanged = true; + } + + if (!AnyFileChanged) { + // Okay! We can re-use the precompiled preamble. + + // Set the state of the diagnostic object to mimic its state + // after parsing the preamble. + getDiagnostics().Reset(); + getDiagnostics().setNumWarnings(NumWarningsInPreamble); + if (StoredDiagnostics.size() > NumStoredDiagnosticsInPreamble) + StoredDiagnostics.erase( + StoredDiagnostics.begin() + NumStoredDiagnosticsInPreamble, + StoredDiagnostics.end()); + + // Create a version of the main file buffer that is padded to + // buffer size we reserved when creating the preamble. + return CreatePaddedMainFileBuffer(NewPreamble.first, + CreatedPreambleBuffer, + PreambleReservedSize, + FrontendOpts.Inputs[0].second); + } + } + + // If we aren't allowed to rebuild the precompiled preamble, just + // return now. + if (!AllowRebuild) + return 0; + + // We can't reuse the previously-computed preamble. Build a new one. + Preamble.clear(); + llvm::sys::Path(PreambleFile).eraseFromDisk(); + PreambleRebuildCounter = 1; + } else if (!AllowRebuild) { + // We aren't allowed to rebuild the precompiled preamble; just + // return now. + return 0; + } + + // If the preamble rebuild counter > 1, it's because we previously + // failed to build a preamble and we're not yet ready to try + // again. Decrement the counter and return a failure. + if (PreambleRebuildCounter > 1) { + --PreambleRebuildCounter; + return 0; + } + + // We did not previously compute a preamble, or it can't be reused anyway. + llvm::Timer *PreambleTimer = 0; + if (TimerGroup.get()) { + PreambleTimer = new llvm::Timer("Precompiling preamble", *TimerGroup); + PreambleTimer->startTimer(); + Timers.push_back(PreambleTimer); + } + + // Create a new buffer that stores the preamble. The buffer also contains + // extra space for the original contents of the file (which will be present + // when we actually parse the file) along with more room in case the file + // grows. + PreambleReservedSize = NewPreamble.first->getBufferSize(); + if (PreambleReservedSize < 4096) + PreambleReservedSize = 8191; + else + PreambleReservedSize *= 2; + + // Save the preamble text for later; we'll need to compare against it for + // subsequent reparses. + Preamble.assign(NewPreamble.first->getBufferStart(), + NewPreamble.first->getBufferStart() + + NewPreamble.second.first); + PreambleEndsAtStartOfLine = NewPreamble.second.second; + + delete PreambleBuffer; + PreambleBuffer + = llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize, + FrontendOpts.Inputs[0].second); + memcpy(const_cast(PreambleBuffer->getBufferStart()), + NewPreamble.first->getBufferStart(), Preamble.size()); + memset(const_cast(PreambleBuffer->getBufferStart()) + Preamble.size(), + ' ', PreambleReservedSize - Preamble.size() - 1); + const_cast(PreambleBuffer->getBufferEnd())[-1] = '\n'; + + // Remap the main source file to the preamble buffer. + llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].second); + PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer); + + // Tell the compiler invocation to generate a temporary precompiled header. + FrontendOpts.ProgramAction = frontend::GeneratePCH; + // FIXME: Set ChainedPCH unconditionally, once it is ready. + if (::getenv("LIBCLANG_CHAINING")) + FrontendOpts.ChainedPCH = true; + // FIXME: Generate the precompiled header into memory? + FrontendOpts.OutputFile = GetPreamblePCHPath(); + + // Create the compiler instance to use for building the precompiled preamble. + CompilerInstance Clang; + Clang.setInvocation(&PreambleInvocation); + OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; + + // Set up diagnostics, capturing all of the diagnostics produced. + Clang.setDiagnostics(&getDiagnostics()); + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, + getDiagnostics(), + StoredDiagnostics); + + // Create the target instance. + Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), + Clang.getTargetOpts())); + if (!Clang.hasTarget()) { + llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); + Preamble.clear(); + if (CreatedPreambleBuffer) + delete NewPreamble.first; + if (PreambleTimer) + PreambleTimer->stopTimer(); + PreambleRebuildCounter = DefaultPreambleRebuildInterval; + PreprocessorOpts.eraseRemappedFile( + PreprocessorOpts.remapped_file_buffer_end() - 1); + return 0; + } + + // Inform the target of the language options. + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); + + assert(Clang.getFrontendOpts().Inputs.size() == 1 && + "Invocation must have exactly one source file!"); + assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST && + "FIXME: AST inputs not yet supported here!"); + assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR && + "IR inputs not support here!"); + + // Clear out old caches and data. + StoredDiagnostics.clear(); + TopLevelDecls.clear(); + TopLevelDeclsInPreamble.clear(); + + // Create a file manager object to provide access to and cache the filesystem. + Clang.setFileManager(new FileManager); + + // Create the source manager. + Clang.setSourceManager(new SourceManager(getDiagnostics())); + + llvm::OwningPtr Act; + Act.reset(new PrecompilePreambleAction(*this)); + if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, + Clang.getFrontendOpts().Inputs[0].first)) { + Clang.takeInvocation(); + llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); + Preamble.clear(); + if (CreatedPreambleBuffer) + delete NewPreamble.first; + if (PreambleTimer) + PreambleTimer->stopTimer(); + PreambleRebuildCounter = DefaultPreambleRebuildInterval; + PreprocessorOpts.eraseRemappedFile( + PreprocessorOpts.remapped_file_buffer_end() - 1); + return 0; + } + + Act->Execute(); + Act->EndSourceFile(); + Clang.takeInvocation(); + + if (Diagnostics->hasErrorOccurred()) { + // There were errors parsing the preamble, so no precompiled header was + // generated. Forget that we even tried. + // FIXME: Should we leave a note for ourselves to try again? + llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); + Preamble.clear(); + if (CreatedPreambleBuffer) + delete NewPreamble.first; + if (PreambleTimer) + PreambleTimer->stopTimer(); + TopLevelDeclsInPreamble.clear(); + PreambleRebuildCounter = DefaultPreambleRebuildInterval; + PreprocessorOpts.eraseRemappedFile( + PreprocessorOpts.remapped_file_buffer_end() - 1); + return 0; + } + + // Keep track of the preamble we precompiled. + PreambleFile = FrontendOpts.OutputFile; + NumStoredDiagnosticsInPreamble = StoredDiagnostics.size(); + NumWarningsInPreamble = getDiagnostics().getNumWarnings(); + + // Keep track of all of the files that the source manager knows about, + // so we can verify whether they have changed or not. + FilesInPreamble.clear(); + SourceManager &SourceMgr = Clang.getSourceManager(); + const llvm::MemoryBuffer *MainFileBuffer + = SourceMgr.getBuffer(SourceMgr.getMainFileID()); + for (SourceManager::fileinfo_iterator F = SourceMgr.fileinfo_begin(), + FEnd = SourceMgr.fileinfo_end(); + F != FEnd; + ++F) { + const FileEntry *File = F->second->Entry; + if (!File || F->second->getRawBuffer() == MainFileBuffer) + continue; + + FilesInPreamble[File->getName()] + = std::make_pair(F->second->getSize(), File->getModificationTime()); + } + + if (PreambleTimer) + PreambleTimer->stopTimer(); + + PreambleRebuildCounter = 1; + PreprocessorOpts.eraseRemappedFile( + PreprocessorOpts.remapped_file_buffer_end() - 1); + return CreatePaddedMainFileBuffer(NewPreamble.first, + CreatedPreambleBuffer, + PreambleReservedSize, + FrontendOpts.Inputs[0].second); +} + +void ASTUnit::RealizeTopLevelDeclsFromPreamble() { + std::vector Resolved; + Resolved.reserve(TopLevelDeclsInPreamble.size()); + ExternalASTSource &Source = *getASTContext().getExternalSource(); + for (unsigned I = 0, N = TopLevelDeclsInPreamble.size(); I != N; ++I) { + // Resolve the declaration ID to an actual declaration, possibly + // deserializing the declaration in the process. + Decl *D = Source.GetExternalDecl(TopLevelDeclsInPreamble[I]); + if (D) + Resolved.push_back(D); + } + TopLevelDeclsInPreamble.clear(); + TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end()); +} + +unsigned ASTUnit::getMaxPCHLevel() const { + if (!getOnlyLocalDecls()) + return Decl::MaxPCHLevel; + + unsigned Result = 0; + if (isMainFileAST() || SavedMainFileBuffer) + ++Result; + return Result; +} + +ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, + llvm::IntrusiveRefCntPtr Diags, + bool OnlyLocalDecls, + bool CaptureDiagnostics, + bool PrecompilePreamble, + bool CompleteTranslationUnit, + bool CacheCodeCompletionResults) { + if (!Diags.getPtr()) { + // No diagnostics engine was provided, so create our own diagnostics object + // with the default options. + DiagnosticOptions DiagOpts; + Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); + } + + // Create the AST unit. + llvm::OwningPtr AST; + AST.reset(new ASTUnit(false)); + AST->Diagnostics = Diags; + AST->CaptureDiagnostics = CaptureDiagnostics; + AST->OnlyLocalDecls = OnlyLocalDecls; + AST->CompleteTranslationUnit = CompleteTranslationUnit; + AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; + AST->Invocation.reset(CI); + CI->getPreprocessorOpts().RetainRemappedFileBuffers = true; + + if (getenv("LIBCLANG_TIMING")) + AST->TimerGroup.reset( + new llvm::TimerGroup(CI->getFrontendOpts().Inputs[0].second)); + + + llvm::MemoryBuffer *OverrideMainBuffer = 0; + // FIXME: When C++ PCH is ready, allow use of it for a precompiled preamble. + if (PrecompilePreamble && !CI->getLangOpts().CPlusPlus) { + AST->PreambleRebuildCounter = 1; + OverrideMainBuffer + = AST->getMainBufferWithPrecompiledPreamble(*AST->Invocation); + } + + llvm::Timer *ParsingTimer = 0; + if (AST->TimerGroup.get()) { + ParsingTimer = new llvm::Timer("Initial parse", *AST->TimerGroup); + ParsingTimer->startTimer(); + AST->Timers.push_back(ParsingTimer); + } + + bool Failed = AST->Parse(OverrideMainBuffer); + if (ParsingTimer) + ParsingTimer->stopTimer(); + + return Failed? 0 : AST.take(); } ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, @@ -396,12 +1343,18 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, bool OnlyLocalDecls, RemappedFile *RemappedFiles, unsigned NumRemappedFiles, - bool CaptureDiagnostics) { + bool CaptureDiagnostics, + bool PrecompilePreamble, + bool CompleteTranslationUnit, + bool CacheCodeCompletionResults) { + bool CreatedDiagnosticsObject = false; + if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. DiagnosticOptions DiagOpts; Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); + CreatedDiagnosticsObject = true; } llvm::SmallVector Args; @@ -413,7 +1366,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, Args.push_back("-fsyntax-only"); // FIXME: We shouldn't have to pass in the path info. - driver::Driver TheDriver("clang", "/", llvm::sys::getHostTriple(), + driver::Driver TheDriver("clang", llvm::sys::getHostTriple(), "a.out", false, false, *Diags); // Don't check that inputs exist, they have been remapped. @@ -444,7 +1397,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, CompilerInvocation::CreateFromArgs(*CI, const_cast(CCArgs.data()), const_cast(CCArgs.data()) + - CCArgs.size(), + CCArgs.size(), *Diags); // Override any files that need remapping @@ -455,7 +1408,468 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, // Override the resources path. CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; - CI->getFrontendOpts().DisableFree = true; + CI->getFrontendOpts().DisableFree = false; return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls, - CaptureDiagnostics); + CaptureDiagnostics, PrecompilePreamble, + CompleteTranslationUnit, + CacheCodeCompletionResults); +} + +bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { + if (!Invocation.get()) + return true; + + llvm::Timer *ReparsingTimer = 0; + if (TimerGroup.get()) { + ReparsingTimer = new llvm::Timer("Reparse", *TimerGroup); + ReparsingTimer->startTimer(); + Timers.push_back(ReparsingTimer); + } + + // Remap files. + PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts(); + for (PreprocessorOptions::remapped_file_buffer_iterator + R = PPOpts.remapped_file_buffer_begin(), + REnd = PPOpts.remapped_file_buffer_end(); + R != REnd; + ++R) { + delete R->second; + } + Invocation->getPreprocessorOpts().clearRemappedFiles(); + for (unsigned I = 0; I != NumRemappedFiles; ++I) + Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, + RemappedFiles[I].second); + + // If we have a preamble file lying around, or if we might try to + // build a precompiled preamble, do so now. + llvm::MemoryBuffer *OverrideMainBuffer = 0; + if (!PreambleFile.empty() || PreambleRebuildCounter > 0) + OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(*Invocation); + + // Clear out the diagnostics state. + if (!OverrideMainBuffer) + getDiagnostics().Reset(); + + // Parse the sources + bool Result = Parse(OverrideMainBuffer); + if (ReparsingTimer) + ReparsingTimer->stopTimer(); + + if (ShouldCacheCodeCompletionResults) { + if (CacheCodeCompletionCoolDown > 0) + --CacheCodeCompletionCoolDown; + else if (top_level_size() != NumTopLevelDeclsAtLastCompletionCache) + CacheCodeCompletionResults(); + } + + return Result; +} + +//----------------------------------------------------------------------------// +// Code completion +//----------------------------------------------------------------------------// + +namespace { + /// \brief Code completion consumer that combines the cached code-completion + /// results from an ASTUnit with the code-completion results provided to it, + /// then passes the result on to + class AugmentedCodeCompleteConsumer : public CodeCompleteConsumer { + unsigned NormalContexts; + ASTUnit &AST; + CodeCompleteConsumer &Next; + + public: + AugmentedCodeCompleteConsumer(ASTUnit &AST, CodeCompleteConsumer &Next, + bool IncludeMacros, bool IncludeCodePatterns, + bool IncludeGlobals) + : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, IncludeGlobals, + Next.isOutputBinary()), AST(AST), Next(Next) + { + // Compute the set of contexts in which we will look when we don't have + // any information about the specific context. + NormalContexts + = (1 << (CodeCompletionContext::CCC_TopLevel - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCInterface - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCImplementation - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCIvarList - 1)) + | (1 << (CodeCompletionContext::CCC_Statement - 1)) + | (1 << (CodeCompletionContext::CCC_Expression - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCMessageReceiver - 1)) + | (1 << (CodeCompletionContext::CCC_MemberAccess - 1)) + | (1 << (CodeCompletionContext::CCC_ObjCProtocolName - 1)); + + if (AST.getASTContext().getLangOptions().CPlusPlus) + NormalContexts |= (1 << (CodeCompletionContext::CCC_EnumTag - 1)) + | (1 << (CodeCompletionContext::CCC_UnionTag - 1)) + | (1 << (CodeCompletionContext::CCC_ClassOrStructTag - 1)); + } + + virtual void ProcessCodeCompleteResults(Sema &S, + CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults); + + virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) { + Next.ProcessOverloadCandidates(S, CurrentArg, Candidates, NumCandidates); + } + }; +} + +/// \brief Helper function that computes which global names are hidden by the +/// local code-completion results. +void CalculateHiddenNames(const CodeCompletionContext &Context, + CodeCompletionResult *Results, + unsigned NumResults, + ASTContext &Ctx, + llvm::StringSet<> &HiddenNames) { + bool OnlyTagNames = false; + switch (Context.getKind()) { + case CodeCompletionContext::CCC_Other: + case CodeCompletionContext::CCC_TopLevel: + case CodeCompletionContext::CCC_ObjCInterface: + case CodeCompletionContext::CCC_ObjCImplementation: + case CodeCompletionContext::CCC_ObjCIvarList: + case CodeCompletionContext::CCC_ClassStructUnion: + case CodeCompletionContext::CCC_Statement: + case CodeCompletionContext::CCC_Expression: + case CodeCompletionContext::CCC_ObjCMessageReceiver: + case CodeCompletionContext::CCC_MemberAccess: + case CodeCompletionContext::CCC_Namespace: + case CodeCompletionContext::CCC_Type: + case CodeCompletionContext::CCC_Name: + case CodeCompletionContext::CCC_PotentiallyQualifiedName: + break; + + case CodeCompletionContext::CCC_EnumTag: + case CodeCompletionContext::CCC_UnionTag: + case CodeCompletionContext::CCC_ClassOrStructTag: + OnlyTagNames = true; + break; + + case CodeCompletionContext::CCC_ObjCProtocolName: + case CodeCompletionContext::CCC_MacroName: + case CodeCompletionContext::CCC_MacroNameUse: + case CodeCompletionContext::CCC_PreprocessorExpression: + case CodeCompletionContext::CCC_PreprocessorDirective: + case CodeCompletionContext::CCC_NaturalLanguage: + case CodeCompletionContext::CCC_SelectorName: + case CodeCompletionContext::CCC_TypeQualifiers: + // We're looking for nothing, or we're looking for names that cannot + // be hidden. + return; + } + + typedef CodeCompletionResult Result; + for (unsigned I = 0; I != NumResults; ++I) { + if (Results[I].Kind != Result::RK_Declaration) + continue; + + unsigned IDNS + = Results[I].Declaration->getUnderlyingDecl()->getIdentifierNamespace(); + + bool Hiding = false; + if (OnlyTagNames) + Hiding = (IDNS & Decl::IDNS_Tag); + else { + unsigned HiddenIDNS = (Decl::IDNS_Type | Decl::IDNS_Member | + Decl::IDNS_Namespace | Decl::IDNS_Ordinary | + Decl::IDNS_NonMemberOperator); + if (Ctx.getLangOptions().CPlusPlus) + HiddenIDNS |= Decl::IDNS_Tag; + Hiding = (IDNS & HiddenIDNS); + } + + if (!Hiding) + continue; + + DeclarationName Name = Results[I].Declaration->getDeclName(); + if (IdentifierInfo *Identifier = Name.getAsIdentifierInfo()) + HiddenNames.insert(Identifier->getName()); + else + HiddenNames.insert(Name.getAsString()); + } +} + + +void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, + CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults) { + // Merge the results we were given with the results we cached. + bool AddedResult = false; + unsigned InContexts + = (Context.getKind() == CodeCompletionContext::CCC_Other? NormalContexts + : (1 << (Context.getKind() - 1))); + + // Contains the set of names that are hidden by "local" completion results. + llvm::StringSet<> HiddenNames; + llvm::SmallVector StringsToDestroy; + typedef CodeCompletionResult Result; + llvm::SmallVector AllResults; + for (ASTUnit::cached_completion_iterator + C = AST.cached_completion_begin(), + CEnd = AST.cached_completion_end(); + C != CEnd; ++C) { + // If the context we are in matches any of the contexts we are + // interested in, we'll add this result. + if ((C->ShowInContexts & InContexts) == 0) + continue; + + // If we haven't added any results previously, do so now. + if (!AddedResult) { + CalculateHiddenNames(Context, Results, NumResults, S.Context, + HiddenNames); + AllResults.insert(AllResults.end(), Results, Results + NumResults); + AddedResult = true; + } + + // Determine whether this global completion result is hidden by a local + // completion result. If so, skip it. + if (C->Kind != CXCursor_MacroDefinition && + HiddenNames.count(C->Completion->getTypedText())) + continue; + + // Adjust priority based on similar type classes. + unsigned Priority = C->Priority; + CXCursorKind CursorKind = C->Kind; + CodeCompletionString *Completion = C->Completion; + if (!Context.getPreferredType().isNull()) { + if (C->Kind == CXCursor_MacroDefinition) { + Priority = getMacroUsagePriority(C->Completion->getTypedText(), + Context.getPreferredType()->isAnyPointerType()); + } else if (C->Type) { + CanQualType Expected + = S.Context.getCanonicalType( + Context.getPreferredType().getUnqualifiedType()); + SimplifiedTypeClass ExpectedSTC = getSimplifiedTypeClass(Expected); + if (ExpectedSTC == C->TypeClass) { + // We know this type is similar; check for an exact match. + llvm::StringMap &CachedCompletionTypes + = AST.getCachedCompletionTypes(); + llvm::StringMap::iterator Pos + = CachedCompletionTypes.find(QualType(Expected).getAsString()); + if (Pos != CachedCompletionTypes.end() && Pos->second == C->Type) + Priority /= CCF_ExactTypeMatch; + else + Priority /= CCF_SimilarTypeMatch; + } + } + } + + // Adjust the completion string, if required. + if (C->Kind == CXCursor_MacroDefinition && + Context.getKind() == CodeCompletionContext::CCC_MacroNameUse) { + // Create a new code-completion string that just contains the + // macro name, without its arguments. + Completion = new CodeCompletionString; + Completion->AddTypedTextChunk(C->Completion->getTypedText()); + StringsToDestroy.push_back(Completion); + CursorKind = CXCursor_NotImplemented; + Priority = CCP_CodePattern; + } + + AllResults.push_back(Result(Completion, Priority, CursorKind, + C->Availability)); + } + + // If we did not add any cached completion results, just forward the + // results we were given to the next consumer. + if (!AddedResult) { + Next.ProcessCodeCompleteResults(S, Context, Results, NumResults); + return; + } + + Next.ProcessCodeCompleteResults(S, Context, AllResults.data(), + AllResults.size()); + + for (unsigned I = 0, N = StringsToDestroy.size(); I != N; ++I) + delete StringsToDestroy[I]; +} + + + +void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, + RemappedFile *RemappedFiles, + unsigned NumRemappedFiles, + bool IncludeMacros, + bool IncludeCodePatterns, + CodeCompleteConsumer &Consumer, + Diagnostic &Diag, LangOptions &LangOpts, + SourceManager &SourceMgr, FileManager &FileMgr, + llvm::SmallVectorImpl &StoredDiagnostics, + llvm::SmallVectorImpl &OwnedBuffers) { + if (!Invocation.get()) + return; + + llvm::Timer *CompletionTimer = 0; + if (TimerGroup.get()) { + llvm::SmallString<128> TimerName; + llvm::raw_svector_ostream TimerNameOut(TimerName); + TimerNameOut << "Code completion @ " << File << ":" << Line << ":" + << Column; + CompletionTimer = new llvm::Timer(TimerNameOut.str(), *TimerGroup); + CompletionTimer->startTimer(); + Timers.push_back(CompletionTimer); + } + + CompilerInvocation CCInvocation(*Invocation); + FrontendOptions &FrontendOpts = CCInvocation.getFrontendOpts(); + PreprocessorOptions &PreprocessorOpts = CCInvocation.getPreprocessorOpts(); + + FrontendOpts.ShowMacrosInCodeCompletion + = IncludeMacros && CachedCompletionResults.empty(); + FrontendOpts.ShowCodePatternsInCodeCompletion = IncludeCodePatterns; + FrontendOpts.ShowGlobalSymbolsInCodeCompletion + = CachedCompletionResults.empty(); + FrontendOpts.CodeCompletionAt.FileName = File; + FrontendOpts.CodeCompletionAt.Line = Line; + FrontendOpts.CodeCompletionAt.Column = Column; + + // Turn on spell-checking when performing code completion. It leads + // to better results. + unsigned SpellChecking = CCInvocation.getLangOpts().SpellChecking; + CCInvocation.getLangOpts().SpellChecking = 1; + + // Set the language options appropriately. + LangOpts = CCInvocation.getLangOpts(); + + CompilerInstance Clang; + Clang.setInvocation(&CCInvocation); + OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; + + // Set up diagnostics, capturing any diagnostics produced. + Clang.setDiagnostics(&Diag); + CaptureDroppedDiagnostics Capture(true, + Clang.getDiagnostics(), + StoredDiagnostics); + + // Create the target instance. + Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), + Clang.getTargetOpts())); + if (!Clang.hasTarget()) { + Clang.takeInvocation(); + CCInvocation.getLangOpts().SpellChecking = SpellChecking; + return; + } + + // Inform the target of the language options. + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); + + assert(Clang.getFrontendOpts().Inputs.size() == 1 && + "Invocation must have exactly one source file!"); + assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST && + "FIXME: AST inputs not yet supported here!"); + assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR && + "IR inputs not support here!"); + + + // Use the source and file managers that we were given. + Clang.setFileManager(&FileMgr); + Clang.setSourceManager(&SourceMgr); + + // Remap files. + PreprocessorOpts.clearRemappedFiles(); + PreprocessorOpts.RetainRemappedFileBuffers = true; + for (unsigned I = 0; I != NumRemappedFiles; ++I) { + PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, + RemappedFiles[I].second); + OwnedBuffers.push_back(RemappedFiles[I].second); + } + + // Use the code completion consumer we were given, but adding any cached + // code-completion results. + AugmentedCodeCompleteConsumer + AugmentedConsumer(*this, Consumer, FrontendOpts.ShowMacrosInCodeCompletion, + FrontendOpts.ShowCodePatternsInCodeCompletion, + FrontendOpts.ShowGlobalSymbolsInCodeCompletion); + Clang.setCodeCompletionConsumer(&AugmentedConsumer); + + // If we have a precompiled preamble, try to use it. We only allow + // the use of the precompiled preamble if we're if the completion + // point is within the main file, after the end of the precompiled + // preamble. + llvm::MemoryBuffer *OverrideMainBuffer = 0; + if (!PreambleFile.empty()) { + using llvm::sys::FileStatus; + llvm::sys::PathWithStatus CompleteFilePath(File); + llvm::sys::PathWithStatus MainPath(OriginalSourceFile); + if (const FileStatus *CompleteFileStatus = CompleteFilePath.getFileStatus()) + if (const FileStatus *MainStatus = MainPath.getFileStatus()) + if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID()) + OverrideMainBuffer + = getMainBufferWithPrecompiledPreamble(CCInvocation, false, + Line - 1); + } + + // If the main file has been overridden due to the use of a preamble, + // make that override happen and introduce the preamble. + if (OverrideMainBuffer) { + PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer); + PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); + PreprocessorOpts.PrecompiledPreambleBytes.second + = PreambleEndsAtStartOfLine; + PreprocessorOpts.ImplicitPCHInclude = PreambleFile; + PreprocessorOpts.DisablePCHValidation = true; + + // The stored diagnostics have the old source manager. Copy them + // to our output set of stored diagnostics, updating the source + // manager to the one we were given. + for (unsigned I = 0, N = this->StoredDiagnostics.size(); I != N; ++I) { + StoredDiagnostics.push_back(this->StoredDiagnostics[I]); + FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), SourceMgr); + StoredDiagnostics[I].setLocation(Loc); + } + + OwnedBuffers.push_back(OverrideMainBuffer); + } else { + PreprocessorOpts.PrecompiledPreambleBytes.first = 0; + PreprocessorOpts.PrecompiledPreambleBytes.second = false; + } + + llvm::OwningPtr Act; + Act.reset(new SyntaxOnlyAction); + if (Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, + Clang.getFrontendOpts().Inputs[0].first)) { + Act->Execute(); + Act->EndSourceFile(); + } + + if (CompletionTimer) + CompletionTimer->stopTimer(); + + // Steal back our resources. + Clang.takeFileManager(); + Clang.takeSourceManager(); + Clang.takeInvocation(); + Clang.takeCodeCompletionConsumer(); + CCInvocation.getLangOpts().SpellChecking = SpellChecking; +} + +bool ASTUnit::Save(llvm::StringRef File) { + if (getDiagnostics().hasErrorOccurred()) + return true; + + // FIXME: Can we somehow regenerate the stat cache here, or do we need to + // unconditionally create a stat cache when we parse the file? + std::string ErrorInfo; + llvm::raw_fd_ostream Out(File.str().c_str(), ErrorInfo, + llvm::raw_fd_ostream::F_Binary); + if (!ErrorInfo.empty() || Out.has_error()) + return true; + + std::vector Buffer; + llvm::BitstreamWriter Stream(Buffer); + ASTWriter Writer(Stream); + Writer.WriteAST(getSema(), 0, 0); + + // Write the generated bitstream to "Out". + if (!Buffer.empty()) + Out.write((char *)&Buffer.front(), Buffer.size()); + Out.close(); + return Out.has_error(); } diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt index 8757e2c..5a31495 100644 --- a/lib/Frontend/CMakeLists.txt +++ b/lib/Frontend/CMakeLists.txt @@ -15,17 +15,9 @@ add_clang_library(clangFrontend FrontendAction.cpp FrontendActions.cpp FrontendOptions.cpp - GeneratePCH.cpp InitHeaderSearch.cpp InitPreprocessor.cpp LangStandards.cpp - PCHReader.cpp - PCHReaderDecl.cpp - PCHReaderStmt.cpp - PCHWriter.cpp - PCHWriterDecl.cpp - PCHWriterStmt.cpp - PrintParserCallbacks.cpp PrintPreprocessedOutput.cpp StmtXML.cpp TextDiagnosticBuffer.cpp diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp index a5fcebe..53f7362 100644 --- a/lib/Frontend/CacheTokens.cpp +++ b/lib/Frontend/CacheTokens.cpp @@ -311,14 +311,19 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) { // the next token. assert(!ParsingPreprocessorDirective); Offset HashOff = (Offset) Out.tell(); - EmitToken(Tok); // Get the next token. - L.LexFromRawLexer(Tok); + Token NextTok; + L.LexFromRawLexer(NextTok); - // If we see the start of line, then we had a null directive "#". - if (Tok.isAtStartOfLine()) + // If we see the start of line, then we had a null directive "#". In + // this case, discard both tokens. + if (NextTok.isAtStartOfLine()) goto NextToken; + + // The token is the start of a directive. Emit it. + EmitToken(Tok); + Tok = NextTok; // Did we see 'include'/'import'/'include_next'? if (Tok.isNot(tok::identifier)) { diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 5037c83..ce0b072 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/CompilerInstance.h" +#include "clang/Sema/Sema.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/Diagnostic.h" @@ -20,11 +21,11 @@ #include "clang/Lex/PTHManager.h" #include "clang/Frontend/ChainedDiagnosticClient.h" #include "clang/Frontend/FrontendAction.h" -#include "clang/Frontend/PCHReader.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Frontend/VerifyDiagnosticsClient.h" #include "clang/Frontend/Utils.h" +#include "clang/Serialization/ASTReader.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "llvm/LLVMContext.h" #include "llvm/Support/MemoryBuffer.h" @@ -37,7 +38,7 @@ using namespace clang; CompilerInstance::CompilerInstance() - : Invocation(new CompilerInvocation()), Reader(0) { + : Invocation(new CompilerInvocation()) { } CompilerInstance::~CompilerInstance() { @@ -55,10 +56,6 @@ void CompilerInstance::setDiagnostics(Diagnostic *Value) { Diagnostics = Value; } -void CompilerInstance::setDiagnosticClient(DiagnosticClient *Value) { - DiagClient.reset(Value); -} - void CompilerInstance::setTarget(TargetInfo *Value) { Target.reset(Value); } @@ -79,6 +76,10 @@ void CompilerInstance::setASTContext(ASTContext *Value) { Context.reset(Value); } +void CompilerInstance::setSema(Sema *S) { + TheSema.reset(S); +} + void CompilerInstance::setASTConsumer(ASTConsumer *Value) { Consumer.reset(Value); } @@ -126,14 +127,11 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, // Chain in a diagnostic client which will log the diagnostics. DiagnosticClient *Logger = new TextDiagnosticPrinter(*OS.take(), DiagOpts, /*OwnsOutputStream=*/true); - Diags.setClient(new ChainedDiagnosticClient(Diags.getClient(), Logger)); + Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger)); } void CompilerInstance::createDiagnostics(int Argc, char **Argv) { Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv); - - if (Diagnostics) - DiagClient.reset(Diagnostics->getClient()); } llvm::IntrusiveRefCntPtr @@ -150,22 +148,20 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, // bit of a problem. So, just create a text diagnostic printer // to complain about this problem, and pretend that the user // didn't try to use binary output. - DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts)); - Diags->setClient(DiagClient.take()); + Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); Diags->Report(diag::err_fe_stderr_binary); return Diags; } else { - DiagClient.reset(new BinaryDiagnosticSerializer(llvm::errs())); + Diags->setClient(new BinaryDiagnosticSerializer(llvm::errs())); } } else { - DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts)); + Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); } // Chain in -verify checker, if requested. if (Opts.VerifyDiagnostics) - DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take())); + Diags->setClient(new VerifyDiagnosticsClient(*Diags, Diags->takeClient())); - Diags->setClient(DiagClient.take()); if (!Opts.DumpBuildInformation.empty()) SetUpBuildDumpLog(Opts, Argc, Argv, *Diags); @@ -245,42 +241,48 @@ void CompilerInstance::createASTContext() { Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(), getTarget(), PP.getIdentifierTable(), PP.getSelectorTable(), PP.getBuiltinInfo(), - /*FreeMemory=*/ !getFrontendOpts().DisableFree, /*size_reserve=*/ 0)); } // ExternalASTSource -void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) { +void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, + bool DisablePCHValidation, + void *DeserializationListener){ llvm::OwningPtr Source; Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, - getPreprocessor(), getASTContext())); - // Remember the PCHReader, but in a non-owning way. - Reader = static_cast(Source.get()); + DisablePCHValidation, + getPreprocessor(), getASTContext(), + DeserializationListener)); getASTContext().setExternalSource(Source); } ExternalASTSource * CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, const std::string &Sysroot, + bool DisablePCHValidation, Preprocessor &PP, - ASTContext &Context) { - llvm::OwningPtr Reader; - Reader.reset(new PCHReader(PP, &Context, - Sysroot.empty() ? 0 : Sysroot.c_str())); - - switch (Reader->ReadPCH(Path)) { - case PCHReader::Success: + ASTContext &Context, + void *DeserializationListener) { + llvm::OwningPtr Reader; + Reader.reset(new ASTReader(PP, &Context, + Sysroot.empty() ? 0 : Sysroot.c_str(), + DisablePCHValidation)); + + Reader->setDeserializationListener( + static_cast(DeserializationListener)); + switch (Reader->ReadAST(Path)) { + case ASTReader::Success: // Set the predefines buffer as suggested by the PCH reader. Typically, the // predefines buffer will be empty. PP.setPredefines(Reader->getSuggestedPredefines()); return Reader.take(); - case PCHReader::Failure: + case ASTReader::Failure: // Unrecoverable failure: don't even try to process the input file. break; - case PCHReader::IgnorePCH: + case ASTReader::IgnorePCH: // No suitable PCH file could be found. Return an error. break; } @@ -290,17 +292,42 @@ CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path, // Code Completion +static bool EnableCodeCompletion(Preprocessor &PP, + const std::string &Filename, + unsigned Line, + unsigned Column) { + // Tell the source manager to chop off the given file at a specific + // line and column. + const FileEntry *Entry = PP.getFileManager().getFile(Filename); + if (!Entry) { + PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) + << Filename; + return true; + } + + // Truncate the named file at the given line/column. + PP.SetCodeCompletionPoint(Entry, Line, Column); + return false; +} + void CompilerInstance::createCodeCompletionConsumer() { const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt; - CompletionConsumer.reset( - createCodeCompletionConsumer(getPreprocessor(), - Loc.FileName, Loc.Line, Loc.Column, - getFrontendOpts().DebugCodeCompletionPrinter, - getFrontendOpts().ShowMacrosInCodeCompletion, + if (!CompletionConsumer) { + CompletionConsumer.reset( + createCodeCompletionConsumer(getPreprocessor(), + Loc.FileName, Loc.Line, Loc.Column, + getFrontendOpts().DebugCodeCompletionPrinter, + getFrontendOpts().ShowMacrosInCodeCompletion, getFrontendOpts().ShowCodePatternsInCodeCompletion, - llvm::outs())); - if (!CompletionConsumer) + getFrontendOpts().ShowGlobalSymbolsInCodeCompletion, + llvm::outs())); + if (!CompletionConsumer) + return; + } else if (EnableCodeCompletion(getPreprocessor(), Loc.FileName, + Loc.Line, Loc.Column)) { + CompletionConsumer.reset(); return; + } if (CompletionConsumer->isOutputBinary() && llvm::sys::Program::ChangeStdoutToBinary()) { @@ -321,24 +348,24 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, bool UseDebugPrinter, bool ShowMacros, bool ShowCodePatterns, + bool ShowGlobals, llvm::raw_ostream &OS) { - // Tell the source manager to chop off the given file at a specific - // line and column. - const FileEntry *Entry = PP.getFileManager().getFile(Filename); - if (!Entry) { - PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file) - << Filename; + if (EnableCodeCompletion(PP, Filename, Line, Column)) return 0; - } - - // Truncate the named file at the given line/column. - PP.SetCodeCompletionPoint(Entry, Line, Column); // Set up the creation routine for code-completion. if (UseDebugPrinter) - return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS); + return new PrintingCodeCompleteConsumer(ShowMacros, ShowCodePatterns, + ShowGlobals, OS); else - return new CIndexCodeCompleteConsumer(ShowMacros, ShowCodePatterns, OS); + return new CIndexCodeCompleteConsumer(ShowMacros, ShowCodePatterns, + ShowGlobals, OS); +} + +void CompilerInstance::createSema(bool CompleteTranslationUnit, + CodeCompleteConsumer *CompletionConsumer) { + TheSema.reset(new Sema(getPreprocessor(), getASTContext(), getASTConsumer(), + CompleteTranslationUnit, CompletionConsumer)); } // Output Files @@ -437,7 +464,7 @@ bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile, // Figure out where to get and map in the main file. if (InputFile != "-") { const FileEntry *File = FileMgr.getFile(InputFile); - if (File) SourceMgr.createMainFileID(File, SourceLocation()); + if (File) SourceMgr.createMainFileID(File); if (SourceMgr.getMainFileID().isInvalid()) { Diags.Report(diag::err_fe_error_reading) << InputFile; return false; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 418d25b..8c64483 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -18,11 +18,12 @@ #include "clang/Driver/Option.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/LangStandard.h" -#include "clang/Frontend/PCHReader.h" +#include "clang/Serialization/ASTReader.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/System/Host.h" #include "llvm/System/Path.h" @@ -112,8 +113,8 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-experimental-checks"); if (Opts.EnableExperimentalInternalChecks) Res.push_back("-analyzer-experimental-internal-checks"); - if (Opts.EnableIdempotentOperationChecker) - Res.push_back("-analyzer-idempotent-operation"); + if (Opts.IdempotentOps) + Res.push_back("-analyzer-check-idempotent-operations"); } static void CodeGenOptsToArgs(const CodeGenOptions &Opts, @@ -148,9 +149,12 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, // SimplifyLibCalls is only derived. // TimePasses is only derived. // UnitAtATime is unused. - // UnrollLoops is only derived. // Inlining is only derived. - + + // UnrollLoops is derived, but also accepts an option, no + // harm in pushing it back here. + if (Opts.UnrollLoops) + Res.push_back("-funroll-loops"); if (Opts.DataSections) Res.push_back("-fdata-sections"); if (Opts.FunctionSections) @@ -241,6 +245,8 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, Res.push_back("-fno-diagnostics-fixit-info"); if (Opts.ShowSourceRanges) Res.push_back("-fdiagnostics-print-source-range-info"); + if (Opts.ShowParseableFixits) + Res.push_back("-fdiagnostics-parseable-fixits"); if (Opts.ShowColors) Res.push_back("-fcolor-diagnostics"); if (Opts.VerifyDiagnostics) @@ -316,6 +322,7 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::ASTPrintXML: return "-ast-print-xml"; case frontend::ASTView: return "-ast-view"; case frontend::BoostCon: return "-boostcon"; + case frontend::CreateModule: return "-create-module"; case frontend::DumpRawTokens: return "-dump-raw-tokens"; case frontend::DumpTokens: return "-dump-tokens"; case frontend::EmitAssembly: return "-S"; @@ -329,10 +336,9 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::GeneratePCH: return "-emit-pch"; case frontend::GeneratePTH: return "-emit-pth"; case frontend::InitOnly: return "-init-only"; - case frontend::ParseNoop: return "-parse-noop"; - case frontend::ParsePrintCallbacks: return "-parse-print-callbacks"; case frontend::ParseSyntaxOnly: return "-fsyntax-only"; case frontend::PrintDeclContext: return "-print-decl-contexts"; + case frontend::PrintPreamble: return "-print-preamble"; case frontend::PrintPreprocessedInput: return "-E"; case frontend::RewriteMacros: return "-rewrite-macros"; case frontend::RewriteObjC: return "-rewrite-objc"; @@ -361,12 +367,16 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-code-completion-macros"); if (Opts.ShowCodePatternsInCodeCompletion) Res.push_back("-code-completion-patterns"); + if (!Opts.ShowGlobalSymbolsInCodeCompletion) + Res.push_back("-no-code-completion-globals"); if (Opts.ShowStats) Res.push_back("-print-stats"); if (Opts.ShowTimers) Res.push_back("-ftime-report"); if (Opts.ShowVersion) Res.push_back("-version"); + if (Opts.FixWhatYouCan) + Res.push_back("-fix-what-you-can"); bool NeedLang = false; for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) @@ -416,6 +426,10 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts, Res.push_back("-ast-merge"); Res.push_back(Opts.ASTMergeFiles[i]); } + for (unsigned i = 0, e = Opts.Modules.size(); i != e; ++i) { + Res.push_back("-import-module"); + Res.push_back(Opts.Modules[i]); + } for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i) { Res.push_back("-mllvm"); Res.push_back(Opts.LLVMArgs[i]); @@ -512,6 +526,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fgnu-keywords"); if (Opts.Microsoft) Res.push_back("-fms-extensions"); + if (Opts.Borland) + Res.push_back("-fborland-extensions"); if (Opts.ObjCNonFragileABI) Res.push_back("-fobjc-nonfragile-abi"); if (Opts.ObjCNonFragileABI2) @@ -676,6 +692,8 @@ static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts, else if (!Opts.ShowCPP && Opts.ShowMacros) Res.push_back("-dM"); + if (Opts.ShowHeaderIncludes) + Res.push_back("-H"); if (!Opts.ShowLineMarkers) Res.push_back("-P"); if (Opts.ShowComments) @@ -696,8 +714,14 @@ static void TargetOptsToArgs(const TargetOptions &Opts, Res.push_back("-target-abi"); Res.push_back(Opts.ABI); } - Res.push_back("-cxx-abi"); - Res.push_back(Opts.CXXABI); + if (!Opts.LinkerVersion.empty()) { + Res.push_back("-target-linker-version"); + Res.push_back(Opts.LinkerVersion); + } + if (!Opts.CXXABI.empty()) { + Res.push_back("-cxx-abi"); + Res.push_back(Opts.CXXABI); + } for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i) { Res.push_back("-target-feature"); Res.push_back(Opts.Features[i]); @@ -789,15 +813,15 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead); Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function); + Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG); Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks); Opts.EnableExperimentalInternalChecks = Args.hasArg(OPT_analyzer_experimental_internal_checks); - Opts.EnableIdempotentOperationChecker = - Args.hasArg(OPT_analyzer_idempotent_operation); Opts.TrimGraph = Args.hasArg(OPT_trim_egraph); Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags); Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 3, Diags); Opts.InlineCall = Args.hasArg(OPT_analyzer_inline_call); + Opts.IdempotentOps = Args.hasArg(OPT_analysis_WarnIdempotentOps); } static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, @@ -829,7 +853,8 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.OptimizeSize = Args.hasArg(OPT_Os); Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) || Args.hasArg(OPT_ffreestanding)); - Opts.UnrollLoops = (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize); + Opts.UnrollLoops = Args.hasArg(OPT_funroll_loops) || + (Opts.OptimizationLevel > 1 && !Opts.OptimizeSize); Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); @@ -838,6 +863,7 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass); Opts.DisableFPElim = Args.hasArg(OPT_mdisable_fp_elim); Opts.FloatABI = Args.getLastArgValue(OPT_mfloat_abi); + Opts.HiddenWeakVTables = Args.hasArg(OPT_fhidden_weak_vtables); Opts.LimitFloatPrecision = Args.getLastArgValue(OPT_mlimit_float_precision); Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); @@ -916,6 +942,7 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, << ShowCategory; Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); + Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits); Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary); Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags); @@ -985,14 +1012,12 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::GeneratePTH; break; case OPT_init_only: Opts.ProgramAction = frontend::InitOnly; break; - case OPT_parse_noop: - Opts.ProgramAction = frontend::ParseNoop; break; - case OPT_parse_print_callbacks: - Opts.ProgramAction = frontend::ParsePrintCallbacks; break; case OPT_fsyntax_only: Opts.ProgramAction = frontend::ParseSyntaxOnly; break; case OPT_print_decl_contexts: Opts.ProgramAction = frontend::PrintDeclContext; break; + case OPT_print_preamble: + Opts.ProgramAction = frontend::PrintPreamble; break; case OPT_E: Opts.ProgramAction = frontend::PrintPreprocessedInput; break; case OPT_rewrite_macros: @@ -1005,6 +1030,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::RunAnalysis; break; case OPT_Eonly: Opts.ProgramAction = frontend::RunPreprocessorOnly; break; + case OPT_create_module: + Opts.ProgramAction = frontend::CreateModule; break; } } @@ -1039,12 +1066,16 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ShowMacrosInCodeCompletion = Args.hasArg(OPT_code_completion_macros); Opts.ShowCodePatternsInCodeCompletion = Args.hasArg(OPT_code_completion_patterns); + Opts.ShowGlobalSymbolsInCodeCompletion + = !Args.hasArg(OPT_no_code_completion_globals); Opts.ShowStats = Args.hasArg(OPT_print_stats); Opts.ShowTimers = Args.hasArg(OPT_ftime_report); Opts.ShowVersion = Args.hasArg(OPT_version); Opts.ViewClassInheritance = Args.getLastArgValue(OPT_cxx_inheritance_view); Opts.ASTMergeFiles = Args.getAllArgValues(OPT_ast_merge); Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm); + Opts.FixWhatYouCan = Args.hasArg(OPT_fix_what_you_can); + Opts.Modules = Args.getAllArgValues(OPT_import_module); InputKind DashX = IK_None; if (const Arg *A = Args.getLastArg(OPT_x)) { @@ -1123,7 +1154,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { for (arg_iterator it = Args.filtered_begin(OPT_I, OPT_F), ie = Args.filtered_end(); it != ie; ++it) Opts.AddPath((*it)->getValue(Args), frontend::Angled, true, - /*IsFramework=*/ (*it)->getOption().matches(OPT_F)); + /*IsFramework=*/ (*it)->getOption().matches(OPT_F), true); // Add -iprefix/-iwith-prefix/-iwithprefixbefore options. llvm::StringRef Prefix = ""; // FIXME: This isn't the correct default prefix. @@ -1135,21 +1166,22 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { Prefix = A->getValue(Args); else if (A->getOption().matches(OPT_iwithprefix)) Opts.AddPath(Prefix.str() + A->getValue(Args), - frontend::System, false, false); + frontend::System, false, false, true); else Opts.AddPath(Prefix.str() + A->getValue(Args), - frontend::Angled, false, false); + frontend::Angled, false, false, true); } for (arg_iterator it = Args.filtered_begin(OPT_idirafter), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::After, true, false); + Opts.AddPath((*it)->getValue(Args), frontend::After, true, false, true); for (arg_iterator it = Args.filtered_begin(OPT_iquote), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false); - for (arg_iterator it = Args.filtered_begin(OPT_isystem), + Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false, true); + for (arg_iterator it = Args.filtered_begin(OPT_isystem, OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::System, true, false); + Opts.AddPath((*it)->getValue(Args), frontend::System, true, false, + (*it)->getOption().matches(OPT_iwithsysroot)); // FIXME: Need options for the various environment variables! } @@ -1287,6 +1319,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, !Opts.AsmPreprocessor); Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); Opts.Microsoft = Args.hasArg(OPT_fms_extensions); + Opts.Borland = Args.hasArg(OPT_fborland_extensions); Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); Opts.ConstStrings = Args.hasArg(OPT_Wwrite_strings); if (Args.hasArg(OPT_fno_lax_vector_conversions)) @@ -1360,6 +1393,24 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.TokenCache = Opts.ImplicitPTHInclude; Opts.UsePredefines = !Args.hasArg(OPT_undef); Opts.DetailedRecord = Args.hasArg(OPT_detailed_preprocessing_record); + Opts.DisablePCHValidation = Args.hasArg(OPT_fno_validate_pch); + + if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { + llvm::StringRef Value(A->getValue(Args)); + size_t Comma = Value.find(','); + unsigned Bytes = 0; + unsigned EndOfLine = 0; + + if (Comma == llvm::StringRef::npos || + Value.substr(0, Comma).getAsInteger(10, Bytes) || + Value.substr(Comma + 1).getAsInteger(10, EndOfLine)) + Diags.Report(diag::err_drv_preamble_format); + else { + Opts.PrecompiledPreambleBytes.first = Bytes; + Opts.PrecompiledPreambleBytes.second = (EndOfLine != 0); + } + } + // Add macros from the command line. for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U), ie = Args.filtered_end(); it != ie; ++it) { @@ -1379,7 +1430,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, // PCH is handled specially, we need to extra the original include path. if (A->getOption().matches(OPT_include_pch)) { std::string OriginalFile = - PCHReader::getOriginalSourceFile(A->getValue(Args), Diags); + ASTReader::getOriginalSourceFile(A->getValue(Args), Diags); if (OriginalFile.empty()) continue; @@ -1411,10 +1462,11 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, ArgList &Args) { using namespace cc1options; Opts.ShowCPP = !Args.hasArg(OPT_dM); - Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD); - Opts.ShowLineMarkers = !Args.hasArg(OPT_P); Opts.ShowComments = Args.hasArg(OPT_C); + Opts.ShowHeaderIncludes = Args.hasArg(OPT_H); + Opts.ShowLineMarkers = !Args.hasArg(OPT_P); Opts.ShowMacroComments = Args.hasArg(OPT_CC); + Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD); } static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { @@ -1422,16 +1474,13 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { Opts.ABI = Args.getLastArgValue(OPT_target_abi); Opts.CXXABI = Args.getLastArgValue(OPT_cxx_abi); Opts.CPU = Args.getLastArgValue(OPT_target_cpu); - Opts.Triple = Args.getLastArgValue(OPT_triple); Opts.Features = Args.getAllArgValues(OPT_target_feature); + Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version); + Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple)); // Use the host triple if unspecified. if (Opts.Triple.empty()) Opts.Triple = llvm::sys::getHostTriple(); - - // Use the Itanium C++ ABI if unspecified. - if (Opts.CXXABI.empty()) - Opts.CXXABI = "itanium"; } // diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp index 14aee35..cdff807 100644 --- a/lib/Frontend/DependencyFile.cpp +++ b/lib/Frontend/DependencyFile.cpp @@ -53,7 +53,6 @@ public: virtual void EndOfMainFile() { OutputDependencyFile(); - OS->flush(); delete OS; OS = 0; } diff --git a/lib/Frontend/DiagChecker.cpp b/lib/Frontend/DiagChecker.cpp index a50cc99..66d7ed7 100644 --- a/lib/Frontend/DiagChecker.cpp +++ b/lib/Frontend/DiagChecker.cpp @@ -13,7 +13,7 @@ #include "clang/Frontend/Utils.h" #include "clang/Frontend/TextDiagnosticBuffer.h" -#include "clang/Sema/ParseAST.h" +#include "clang/Parse/ParseAST.h" #include "clang/AST/ASTConsumer.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index dbbf69c..b244c5c 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -8,13 +8,14 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/FrontendAction.h" +#include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" -#include "clang/Sema/ParseAST.h" +#include "clang/Parse/ParseAST.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Timer.h" #include "llvm/Support/ErrorHandling.h" @@ -50,7 +51,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, llvm::IntrusiveRefCntPtr Diags(&CI.getDiagnostics()); std::string Error; - ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, Diags); + ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags); if (!AST) goto failure; @@ -112,18 +113,21 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!usesPreprocessorOnly()) { CI.createASTContext(); - /// Use PCH? If so, we want the PCHReader active before the consumer - /// is created, because the consumer might be interested in the reader - /// (e.g. the PCH writer for chaining). + llvm::OwningPtr Consumer(CreateASTConsumer(CI, Filename)); + + /// Use PCH? if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { assert(hasPCHSupport() && "This action does not have PCH support!"); CI.createPCHExternalASTSource( - CI.getPreprocessorOpts().ImplicitPCHInclude); + CI.getPreprocessorOpts().ImplicitPCHInclude, + CI.getPreprocessorOpts().DisablePCHValidation, + CI.getInvocation().getFrontendOpts().ChainedPCH? + Consumer->GetASTDeserializationListener() : 0); if (!CI.getASTContext().getExternalSource()) goto failure; } - CI.setASTConsumer(CreateASTConsumer(CI, Filename)); + CI.setASTConsumer(Consumer.take()); if (!CI.hasASTConsumer()) goto failure; } @@ -192,12 +196,16 @@ void FrontendAction::EndSourceFile() { // FIXME: There is more per-file stuff we could just drop here? if (CI.getFrontendOpts().DisableFree) { CI.takeASTConsumer(); - if (!isCurrentFileAST()) + if (!isCurrentFileAST()) { + CI.takeSema(); CI.takeASTContext(); + } } else { - CI.setASTConsumer(0); - if (!isCurrentFileAST()) + if (!isCurrentFileAST()) { + CI.setSema(0); CI.setASTContext(0); + } + CI.setASTConsumer(0); } // Inform the preprocessor we are done. @@ -221,6 +229,7 @@ void FrontendAction::EndSourceFile() { CI.getDiagnosticClient().EndSourceFile(); if (isCurrentFileAST()) { + CI.takeSema(); CI.takeASTContext(); CI.takePreprocessor(); CI.takeSourceManager(); @@ -249,9 +258,10 @@ void ASTFrontendAction::ExecuteAction() { if (CI.hasCodeCompletionConsumer()) CompletionConsumer = &CI.getCodeCompletionConsumer(); - ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(), - CI.getFrontendOpts().ShowStats, - usesCompleteTranslationUnit(), CompletionConsumer); + if (!CI.hasSema()) + CI.createSema(usesCompleteTranslationUnit(), CompletionConsumer); + + ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats); } ASTConsumer * diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 3a53dee..5bc6506 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -18,7 +18,9 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/Utils.h" +#include "clang/Serialization/ASTWriter.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -69,22 +71,35 @@ ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI, ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { - const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot; - if (CI.getFrontendOpts().RelocatablePCH && - Sysroot.empty()) { - CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot); + std::string Sysroot; + llvm::raw_ostream *OS = 0; + bool Chaining; + if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OS, Chaining)) return 0; + + const char *isysroot = CI.getFrontendOpts().RelocatablePCH ? + Sysroot.c_str() : 0; + return new PCHGenerator(CI.getPreprocessor(), Chaining, isysroot, OS); +} + +bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI, + llvm::StringRef InFile, + std::string &Sysroot, + llvm::raw_ostream *&OS, + bool &Chaining) { + Sysroot = CI.getHeaderSearchOpts().Sysroot; + if (CI.getFrontendOpts().RelocatablePCH && Sysroot.empty()) { + CI.getDiagnostics().Report(diag::err_relocatable_without_isysroot); + return true; } - llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile); + OS = CI.createDefaultOutputFile(true, InFile); if (!OS) - return 0; + return true; - PCHReader *Chain = CI.getInvocation().getFrontendOpts().ChainedPCH ? - CI.getPCHReader() : 0; - const char *isysroot = CI.getFrontendOpts().RelocatablePCH ? - Sysroot.c_str() : 0; - return CreatePCHGenerator(CI.getPreprocessor(), OS, Chain, isysroot); + Chaining = CI.getInvocation().getFrontendOpts().ChainedPCH && + !CI.getPreprocessorOpts().ImplicitPCHInclude.empty(); + return false; } ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI, @@ -146,15 +161,6 @@ void GeneratePTHAction::ExecuteAction() { CacheTokens(CI.getPreprocessor(), OS); } -void ParseOnlyAction::ExecuteAction() { - Preprocessor &PP = getCompilerInstance().getPreprocessor(); - llvm::OwningPtr PA(new MinimalAction(PP)); - - Parser P(PP, *PA); - PP.EnterMainSourceFile(); - P.ParseTranslationUnit(); -} - void PreprocessOnlyAction::ExecuteAction() { Preprocessor &PP = getCompilerInstance().getPreprocessor(); @@ -169,19 +175,6 @@ void PreprocessOnlyAction::ExecuteAction() { } while (Tok.isNot(tok::eof)); } -void PrintParseAction::ExecuteAction() { - CompilerInstance &CI = getCompilerInstance(); - Preprocessor &PP = getCompilerInstance().getPreprocessor(); - llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile()); - if (!OS) return; - - llvm::OwningPtr PA(CreatePrintParserActionsAction(PP, OS)); - - Parser P(PP, *PA); - PP.EnterMainSourceFile(); - P.ParseTranslationUnit(); -} - void PrintPreprocessedAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); // Output file needs to be set to 'Binary', to avoid converting Unix style @@ -192,3 +185,32 @@ void PrintPreprocessedAction::ExecuteAction() { DoPrintPreprocessedInput(CI.getPreprocessor(), OS, CI.getPreprocessorOutputOpts()); } + +void PrintPreambleAction::ExecuteAction() { + switch (getCurrentFileKind()) { + case IK_C: + case IK_CXX: + case IK_ObjC: + case IK_ObjCXX: + case IK_OpenCL: + break; + + case IK_None: + case IK_Asm: + case IK_PreprocessedC: + case IK_PreprocessedCXX: + case IK_PreprocessedObjC: + case IK_PreprocessedObjCXX: + case IK_AST: + case IK_LLVM_IR: + // We can't do anything with these. + return; + } + + llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getFile(getCurrentFile()); + if (Buffer) { + unsigned Preamble = Lexer::ComputePreamble(Buffer).first; + llvm::outs().write(Buffer->getBufferStart(), Preamble); + delete Buffer; + } +} diff --git a/lib/Frontend/GeneratePCH.cpp b/lib/Frontend/GeneratePCH.cpp deleted file mode 100644 index 2f3df94..0000000 --- a/lib/Frontend/GeneratePCH.cpp +++ /dev/null @@ -1,83 +0,0 @@ -//===--- GeneratePCH.cpp - AST Consumer for PCH Generation ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the CreatePCHGenerate function, which creates an -// ASTConsume that generates a PCH file. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/ASTConsumers.h" -#include "clang/Frontend/PCHWriter.h" -#include "clang/Sema/SemaConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Basic/FileManager.h" -#include "llvm/Bitcode/BitstreamWriter.h" -#include "llvm/Support/raw_ostream.h" -#include - -using namespace clang; - -namespace { - class PCHGenerator : public SemaConsumer { - const Preprocessor &PP; - const char *isysroot; - llvm::raw_ostream *Out; - Sema *SemaPtr; - MemorizeStatCalls *StatCalls; // owned by the FileManager - std::vector Buffer; - llvm::BitstreamWriter Stream; - PCHWriter Writer; - - public: - PCHGenerator(const Preprocessor &PP, PCHReader *Chain, - const char *isysroot, llvm::raw_ostream *Out); - virtual void InitializeSema(Sema &S) { SemaPtr = &S; } - virtual void HandleTranslationUnit(ASTContext &Ctx); - }; -} - -PCHGenerator::PCHGenerator(const Preprocessor &PP, - PCHReader *Chain, - const char *isysroot, - llvm::raw_ostream *OS) - : PP(PP), isysroot(isysroot), Out(OS), SemaPtr(0), StatCalls(0), - Stream(Buffer), Writer(Stream, Chain) { - - // Install a stat() listener to keep track of all of the stat() - // calls. - StatCalls = new MemorizeStatCalls; - PP.getFileManager().addStatCache(StatCalls, /*AtBeginning=*/true); -} - -void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { - if (PP.getDiagnostics().hasErrorOccurred()) - return; - - // Emit the PCH file - assert(SemaPtr && "No Sema?"); - Writer.WritePCH(*SemaPtr, StatCalls, isysroot); - - // Write the generated bitstream to "Out". - Out->write((char *)&Buffer.front(), Buffer.size()); - - // Make sure it hits disk now. - Out->flush(); - - // Free up some memory, in case the process is kept alive. - Buffer.clear(); -} - -ASTConsumer *clang::CreatePCHGenerator(const Preprocessor &PP, - llvm::raw_ostream *OS, - PCHReader *Chain, - const char *isysroot) { - return new PCHGenerator(PP, Chain, isysroot, OS); -} diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index d640d42..df91713 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -1,4 +1,4 @@ -//===--- InitHeaderSearch.cpp - Initialize header search paths ----------*-===// +//===--- InitHeaderSearch.cpp - Initialize header search paths ------------===// // // The LLVM Compiler Infrastructure // @@ -195,6 +195,8 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, System, true, false, false); AddPath(Base + "/" + Arch + "/" + Version + "/include/c++", System, true, false, false); + AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch, + System, true, false, false); AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward", System, true, false, false); } @@ -323,9 +325,19 @@ static bool getSystemRegistryString(const char*, const char*, char*, size_t) { // Get Visual Studio installation directory. static bool getVisualStudioDir(std::string &path) { + // First check the environment variables that vsvars32.bat sets. + const char* vcinstalldir = getenv("VCINSTALLDIR"); + if(vcinstalldir) { + char *p = const_cast(strstr(vcinstalldir, "\\VC")); + if (p) + *p = '\0'; + path = vcinstalldir; + return(true); + } + char vsIDEInstallDir[256]; char vsExpressIDEInstallDir[256]; - // Try the Windows registry first. + // Then try the windows registry. bool hasVCDir = getSystemRegistryString( "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION", "InstallDir", vsIDEInstallDir, sizeof(vsIDEInstallDir) - 1); @@ -440,7 +452,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, if (getVisualStudioDir(VSDir)) { AddPath(VSDir + "\\VC\\include", System, false, false, false); if (getWindowsSDKDir(WindowsSDKDir)) - AddPath(WindowsSDKDir, System, false, false, false); + AddPath(WindowsSDKDir + "\\include", System, false, false, false); else AddPath(VSDir + "\\VC\\PlatformSDK\\Include", System, false, false, false); @@ -510,7 +522,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, AddPath("/boot/develop/headers/glibc", System, true, false, false); AddPath("/boot/develop/headers/posix", System, true, false, false); AddPath("/boot/develop/headers", System, true, false, false); - break; + break; case llvm::Triple::MinGW64: case llvm::Triple::MinGW32: AddPath("c:/mingw/include", System, true, false, false); @@ -549,12 +561,16 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { System, true, false, false); break; case llvm::Triple::MinGW64: + // Try gcc 4.5.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.5.0"); // Try gcc 4.4.0 AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.4.0"); // Try gcc 4.3.0 AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.3.0"); // Fall through. case llvm::Triple::MinGW32: + // Try gcc 4.5.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0"); // Try gcc 4.4.0 AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0"); // Try gcc 4.3.0 @@ -716,6 +732,11 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.3/include/g++-v4", "x86_64-pc-linux-gnu", "32", "", triple); + + // Gentoo amd64 llvm-gcc trunk + AddGnuCPlusPlusIncludePaths( + "/usr/lib/llvm-gcc-4.2-9999/include/c++/4.2.1", + "x86_64-pc-linux-gnu", "", "", triple); break; case llvm::Triple::FreeBSD: @@ -723,6 +744,17 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { // FreeBSD 7.3 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple); break; + case llvm::Triple::NetBSD: + AddGnuCPlusPlusIncludePaths("/usr/include/g++", "", "", "", triple); + break; + case llvm::Triple::OpenBSD: { + std::string t = triple.getTriple(); + if (t.substr(0, 6) == "x86_64") + t.replace(0, 6, "amd64"); + AddGnuCPlusPlusIncludePaths("/usr/include/g++", + t, "", "", triple); + break; + } case llvm::Triple::Minix: AddGnuCPlusPlusIncludePaths("/usr/gnu/include/c++/4.4.3", "", "", "", triple); @@ -889,7 +921,7 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) { const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i]; Init.AddPath(E.Path, E.Group, false, E.IsUserSupplied, E.IsFramework, - false); + !E.IsSysRootRelative); } // Add entries from CPATH and friends. diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 889b6e5..0d07192 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -169,10 +169,11 @@ static void DefineTypeSize(llvm::StringRef MacroName, unsigned TypeWidth, llvm::StringRef ValSuffix, bool isSigned, MacroBuilder& Builder) { long long MaxVal; - if (isSigned) - MaxVal = (1LL << (TypeWidth - 1)) - 1; - else - MaxVal = ~0LL >> (64-TypeWidth); + if (isSigned) { + assert(TypeWidth != 1); + MaxVal = ~0ULL >> (65-TypeWidth); + } else + MaxVal = ~0ULL >> (64-TypeWidth); Builder.defineMacro(MacroName, llvm::Twine(MaxVal) + ValSuffix); } @@ -318,7 +319,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__cplusplus"); else // C++ [cpp.predefined]p1: - // The name_ _cplusplusis defined to the value199711Lwhen compiling a + // The name_ _cplusplusis defined to the value 199711L when compiling a // C++ translation unit. Builder.defineMacro("__cplusplus", "199711L"); Builder.defineMacro("__private_extern__", "extern"); @@ -339,9 +340,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // Since we define wchar_t in C++ mode. Builder.defineMacro("_WCHAR_T_DEFINED"); Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED"); - // FIXME: This should be temporary until we have a __pragma - // solution, to avoid some errors flagged in VC++ headers. - Builder.defineMacro("_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES", "0"); + Builder.append("class type_info;"); } } @@ -477,7 +476,7 @@ static void InitializeFileRemapping(Diagnostic &Diags, FileManager &FileMgr, const PreprocessorOptions &InitOpts) { // Remap files in the source manager (with buffers). - for (PreprocessorOptions::remapped_file_buffer_iterator + for (PreprocessorOptions::const_remapped_file_buffer_iterator Remap = InitOpts.remapped_file_buffer_begin(), RemapEnd = InitOpts.remapped_file_buffer_end(); Remap != RemapEnd; @@ -489,19 +488,21 @@ static void InitializeFileRemapping(Diagnostic &Diags, if (!FromFile) { Diags.Report(diag::err_fe_remap_missing_from_file) << Remap->first; - delete Remap->second; + if (!InitOpts.RetainRemappedFileBuffers) + delete Remap->second; continue; } // Override the contents of the "from" file with the contents of // the "to" file. - SourceMgr.overrideFileContents(FromFile, Remap->second); + SourceMgr.overrideFileContents(FromFile, Remap->second, + InitOpts.RetainRemappedFileBuffers); } // Remap files in the source manager (with other files). - for (PreprocessorOptions::remapped_file_iterator - Remap = InitOpts.remapped_file_begin(), - RemapEnd = InitOpts.remapped_file_end(); + for (PreprocessorOptions::const_remapped_file_iterator + Remap = InitOpts.remapped_file_begin(), + RemapEnd = InitOpts.remapped_file_end(); Remap != RemapEnd; ++Remap) { // Find the file that we're mapping to. @@ -596,6 +597,10 @@ void clang::InitializePreprocessor(Preprocessor &PP, if (!PP.getLangOptions().AsmPreprocessor) Builder.append("# 1 \"\" 2"); + // Instruct the preprocessor to skip the preamble. + PP.setSkipMainFilePreamble(InitOpts.PrecompiledPreambleBytes.first, + InitOpts.PrecompiledPreambleBytes.second); + // Copy PredefinedBuffer into the Preprocessor. PP.setPredefines(Predefines.str()); diff --git a/lib/Frontend/Makefile b/lib/Frontend/Makefile index 3eb4bc9..3c13ad6 100644 --- a/lib/Frontend/Makefile +++ b/lib/Frontend/Makefile @@ -9,7 +9,6 @@ CLANG_LEVEL := ../.. LIBRARYNAME := clangFrontend -BUILD_ARCHIVE = 1 include $(CLANG_LEVEL)/Makefile diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp deleted file mode 100644 index 00aee49..0000000 --- a/lib/Frontend/PCHReader.cpp +++ /dev/null @@ -1,3469 +0,0 @@ -//===--- PCHReader.cpp - Precompiled Headers Reader -------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the PCHReader class, which reads a precompiled header. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/PCHReader.h" -#include "clang/Frontend/FrontendDiagnostic.h" -#include "clang/Frontend/PCHDeserializationListener.h" -#include "clang/Frontend/Utils.h" -#include "../Sema/Sema.h" // FIXME: move Sema headers elsewhere -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Expr.h" -#include "clang/AST/Type.h" -#include "clang/AST/TypeLocVisitor.h" -#include "clang/Lex/MacroInfo.h" -#include "clang/Lex/PreprocessingRecord.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Basic/OnDiskHashTable.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/SourceManagerInternals.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/Version.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Bitcode/BitstreamReader.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/System/Path.h" -#include -#include -#include -#include -using namespace clang; - -//===----------------------------------------------------------------------===// -// PCH reader validator implementation -//===----------------------------------------------------------------------===// - -PCHReaderListener::~PCHReaderListener() {} - -bool -PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { - const LangOptions &PPLangOpts = PP.getLangOptions(); -#define PARSE_LANGOPT_BENIGN(Option) -#define PARSE_LANGOPT_IMPORTANT(Option, DiagID) \ - if (PPLangOpts.Option != LangOpts.Option) { \ - Reader.Diag(DiagID) << LangOpts.Option << PPLangOpts.Option; \ - return true; \ - } - - PARSE_LANGOPT_BENIGN(Trigraphs); - PARSE_LANGOPT_BENIGN(BCPLComment); - PARSE_LANGOPT_BENIGN(DollarIdents); - PARSE_LANGOPT_BENIGN(AsmPreprocessor); - PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions); - PARSE_LANGOPT_IMPORTANT(GNUKeywords, diag::warn_pch_gnu_keywords); - PARSE_LANGOPT_BENIGN(ImplicitInt); - PARSE_LANGOPT_BENIGN(Digraphs); - PARSE_LANGOPT_BENIGN(HexFloats); - PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99); - PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions); - PARSE_LANGOPT_IMPORTANT(CPlusPlus, diag::warn_pch_cplusplus); - PARSE_LANGOPT_IMPORTANT(CPlusPlus0x, diag::warn_pch_cplusplus0x); - PARSE_LANGOPT_BENIGN(CXXOperatorName); - PARSE_LANGOPT_IMPORTANT(ObjC1, diag::warn_pch_objective_c); - PARSE_LANGOPT_IMPORTANT(ObjC2, diag::warn_pch_objective_c2); - PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI, diag::warn_pch_nonfragile_abi); - PARSE_LANGOPT_IMPORTANT(ObjCNonFragileABI2, diag::warn_pch_nonfragile_abi2); - PARSE_LANGOPT_IMPORTANT(NoConstantCFStrings, - diag::warn_pch_no_constant_cfstrings); - PARSE_LANGOPT_BENIGN(PascalStrings); - PARSE_LANGOPT_BENIGN(WritableStrings); - PARSE_LANGOPT_IMPORTANT(LaxVectorConversions, - diag::warn_pch_lax_vector_conversions); - PARSE_LANGOPT_IMPORTANT(AltiVec, diag::warn_pch_altivec); - PARSE_LANGOPT_IMPORTANT(Exceptions, diag::warn_pch_exceptions); - PARSE_LANGOPT_IMPORTANT(SjLjExceptions, diag::warn_pch_sjlj_exceptions); - PARSE_LANGOPT_IMPORTANT(NeXTRuntime, diag::warn_pch_objc_runtime); - PARSE_LANGOPT_IMPORTANT(Freestanding, diag::warn_pch_freestanding); - PARSE_LANGOPT_IMPORTANT(NoBuiltin, diag::warn_pch_builtins); - PARSE_LANGOPT_IMPORTANT(ThreadsafeStatics, - diag::warn_pch_thread_safe_statics); - PARSE_LANGOPT_IMPORTANT(POSIXThreads, diag::warn_pch_posix_threads); - PARSE_LANGOPT_IMPORTANT(Blocks, diag::warn_pch_blocks); - PARSE_LANGOPT_BENIGN(EmitAllDecls); - PARSE_LANGOPT_IMPORTANT(MathErrno, diag::warn_pch_math_errno); - PARSE_LANGOPT_BENIGN(getSignedOverflowBehavior()); - PARSE_LANGOPT_IMPORTANT(HeinousExtensions, - diag::warn_pch_heinous_extensions); - // FIXME: Most of the options below are benign if the macro wasn't - // used. Unfortunately, this means that a PCH compiled without - // optimization can't be used with optimization turned on, even - // though the only thing that changes is whether __OPTIMIZE__ was - // defined... but if __OPTIMIZE__ never showed up in the header, it - // doesn't matter. We could consider making this some special kind - // of check. - PARSE_LANGOPT_IMPORTANT(Optimize, diag::warn_pch_optimize); - PARSE_LANGOPT_IMPORTANT(OptimizeSize, diag::warn_pch_optimize_size); - PARSE_LANGOPT_IMPORTANT(Static, diag::warn_pch_static); - PARSE_LANGOPT_IMPORTANT(PICLevel, diag::warn_pch_pic_level); - PARSE_LANGOPT_IMPORTANT(GNUInline, diag::warn_pch_gnu_inline); - PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline); - PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control); - PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed); - PARSE_LANGOPT_IMPORTANT(ShortWChar, diag::warn_pch_short_wchar); - if ((PPLangOpts.getGCMode() != 0) != (LangOpts.getGCMode() != 0)) { - Reader.Diag(diag::warn_pch_gc_mode) - << LangOpts.getGCMode() << PPLangOpts.getGCMode(); - return true; - } - PARSE_LANGOPT_BENIGN(getVisibilityMode()); - PARSE_LANGOPT_IMPORTANT(getStackProtectorMode(), - diag::warn_pch_stack_protector); - PARSE_LANGOPT_BENIGN(InstantiationDepth); - PARSE_LANGOPT_IMPORTANT(OpenCL, diag::warn_pch_opencl); - PARSE_LANGOPT_BENIGN(CatchUndefined); - PARSE_LANGOPT_IMPORTANT(ElideConstructors, diag::warn_pch_elide_constructors); - PARSE_LANGOPT_BENIGN(SpellChecking); -#undef PARSE_LANGOPT_IMPORTANT -#undef PARSE_LANGOPT_BENIGN - - return false; -} - -bool PCHValidator::ReadTargetTriple(llvm::StringRef Triple) { - if (Triple == PP.getTargetInfo().getTriple().str()) - return false; - - Reader.Diag(diag::warn_pch_target_triple) - << Triple << PP.getTargetInfo().getTriple().str(); - return true; -} - -struct EmptyStringRef { - bool operator ()(llvm::StringRef r) const { return r.empty(); } -}; -struct EmptyBlock { - bool operator ()(const PCHPredefinesBlock &r) const { return r.Data.empty(); } -}; - -static bool EqualConcatenations(llvm::SmallVector L, - PCHPredefinesBlocks R) { - // First, sum up the lengths. - unsigned LL = 0, RL = 0; - for (unsigned I = 0, N = L.size(); I != N; ++I) { - LL += L[I].size(); - } - for (unsigned I = 0, N = R.size(); I != N; ++I) { - RL += R[I].Data.size(); - } - if (LL != RL) - return false; - if (LL == 0 && RL == 0) - return true; - - // Kick out empty parts, they confuse the algorithm below. - L.erase(std::remove_if(L.begin(), L.end(), EmptyStringRef()), L.end()); - R.erase(std::remove_if(R.begin(), R.end(), EmptyBlock()), R.end()); - - // Do it the hard way. At this point, both vectors must be non-empty. - llvm::StringRef LR = L[0], RR = R[0].Data; - unsigned LI = 0, RI = 0, LN = L.size(), RN = R.size(); - for (;;) { - // Compare the current pieces. - if (LR.size() == RR.size()) { - // If they're the same length, it's pretty easy. - if (LR != RR) - return false; - // Both pieces are done, advance. - ++LI; - ++RI; - // If either string is done, they're both done, since they're the same - // length. - if (LI == LN) { - assert(RI == RN && "Strings not the same length after all?"); - return true; - } - LR = L[LI]; - RR = R[RI].Data; - } else if (LR.size() < RR.size()) { - // Right piece is longer. - if (!RR.startswith(LR)) - return false; - ++LI; - assert(LI != LN && "Strings not the same length after all?"); - RR = RR.substr(LR.size()); - LR = L[LI]; - } else { - // Left piece is longer. - if (!LR.startswith(RR)) - return false; - ++RI; - assert(RI != RN && "Strings not the same length after all?"); - LR = LR.substr(RR.size()); - RR = R[RI].Data; - } - } -} - -static std::pair -FindMacro(const PCHPredefinesBlocks &Buffers, llvm::StringRef MacroDef) { - std::pair Res; - for (unsigned I = 0, N = Buffers.size(); I != N; ++I) { - Res.second = Buffers[I].Data.find(MacroDef); - if (Res.second != llvm::StringRef::npos) { - Res.first = Buffers[I].BufferID; - break; - } - } - return Res; -} - -bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, - llvm::StringRef OriginalFileName, - std::string &SuggestedPredefines) { - // We are in the context of an implicit include, so the predefines buffer will - // have a #include entry for the PCH file itself (as normalized by the - // preprocessor initialization). Find it and skip over it in the checking - // below. - llvm::SmallString<256> PCHInclude; - PCHInclude += "#include \""; - PCHInclude += NormalizeDashIncludePath(OriginalFileName); - PCHInclude += "\"\n"; - std::pair Split = - llvm::StringRef(PP.getPredefines()).split(PCHInclude.str()); - llvm::StringRef Left = Split.first, Right = Split.second; - if (Left == PP.getPredefines()) { - Error("Missing PCH include entry!"); - return true; - } - - // If the concatenation of all the PCH buffers is equal to the adjusted - // command line, we're done. - // We build a SmallVector of the command line here, because we'll eventually - // need to support an arbitrary amount of pieces anyway (when we have chained - // PCH reading). - llvm::SmallVector CommandLine; - CommandLine.push_back(Left); - CommandLine.push_back(Right); - if (EqualConcatenations(CommandLine, Buffers)) - return false; - - SourceManager &SourceMgr = PP.getSourceManager(); - - // The predefines buffers are different. Determine what the differences are, - // and whether they require us to reject the PCH file. - llvm::SmallVector PCHLines; - for (unsigned I = 0, N = Buffers.size(); I != N; ++I) - Buffers[I].Data.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); - - llvm::SmallVector CmdLineLines; - Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); - Right.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); - - // Sort both sets of predefined buffer lines, since we allow some extra - // definitions and they may appear at any point in the output. - std::sort(CmdLineLines.begin(), CmdLineLines.end()); - std::sort(PCHLines.begin(), PCHLines.end()); - - // Determine which predefines that were used to build the PCH file are missing - // from the command line. - std::vector MissingPredefines; - std::set_difference(PCHLines.begin(), PCHLines.end(), - CmdLineLines.begin(), CmdLineLines.end(), - std::back_inserter(MissingPredefines)); - - bool MissingDefines = false; - bool ConflictingDefines = false; - for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) { - llvm::StringRef Missing = MissingPredefines[I]; - if (!Missing.startswith("#define ")) { - Reader.Diag(diag::warn_pch_compiler_options_mismatch); - return true; - } - - // This is a macro definition. Determine the name of the macro we're - // defining. - std::string::size_type StartOfMacroName = strlen("#define "); - std::string::size_type EndOfMacroName - = Missing.find_first_of("( \n\r", StartOfMacroName); - assert(EndOfMacroName != std::string::npos && - "Couldn't find the end of the macro name"); - llvm::StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName); - - // Determine whether this macro was given a different definition on the - // command line. - std::string MacroDefStart = "#define " + MacroName.str(); - std::string::size_type MacroDefLen = MacroDefStart.size(); - llvm::SmallVector::iterator ConflictPos - = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(), - MacroDefStart); - for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) { - if (!ConflictPos->startswith(MacroDefStart)) { - // Different macro; we're done. - ConflictPos = CmdLineLines.end(); - break; - } - - assert(ConflictPos->size() > MacroDefLen && - "Invalid #define in predefines buffer?"); - if ((*ConflictPos)[MacroDefLen] != ' ' && - (*ConflictPos)[MacroDefLen] != '(') - continue; // Longer macro name; keep trying. - - // We found a conflicting macro definition. - break; - } - - if (ConflictPos != CmdLineLines.end()) { - Reader.Diag(diag::warn_cmdline_conflicting_macro_def) - << MacroName; - - // Show the definition of this macro within the PCH file. - std::pair MacroLoc = - FindMacro(Buffers, Missing); - assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!"); - SourceLocation PCHMissingLoc = - SourceMgr.getLocForStartOfFile(MacroLoc.first) - .getFileLocWithOffset(MacroLoc.second); - Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName; - - ConflictingDefines = true; - continue; - } - - // If the macro doesn't conflict, then we'll just pick up the macro - // definition from the PCH file. Warn the user that they made a mistake. - if (ConflictingDefines) - continue; // Don't complain if there are already conflicting defs - - if (!MissingDefines) { - Reader.Diag(diag::warn_cmdline_missing_macro_defs); - MissingDefines = true; - } - - // Show the definition of this macro within the PCH file. - std::pair MacroLoc = - FindMacro(Buffers, Missing); - assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!"); - SourceLocation PCHMissingLoc = - SourceMgr.getLocForStartOfFile(MacroLoc.first) - .getFileLocWithOffset(MacroLoc.second); - Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch); - } - - if (ConflictingDefines) - return true; - - // Determine what predefines were introduced based on command-line - // parameters that were not present when building the PCH - // file. Extra #defines are okay, so long as the identifiers being - // defined were not used within the precompiled header. - std::vector ExtraPredefines; - std::set_difference(CmdLineLines.begin(), CmdLineLines.end(), - PCHLines.begin(), PCHLines.end(), - std::back_inserter(ExtraPredefines)); - for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) { - llvm::StringRef &Extra = ExtraPredefines[I]; - if (!Extra.startswith("#define ")) { - Reader.Diag(diag::warn_pch_compiler_options_mismatch); - return true; - } - - // This is an extra macro definition. Determine the name of the - // macro we're defining. - std::string::size_type StartOfMacroName = strlen("#define "); - std::string::size_type EndOfMacroName - = Extra.find_first_of("( \n\r", StartOfMacroName); - assert(EndOfMacroName != std::string::npos && - "Couldn't find the end of the macro name"); - llvm::StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName); - - // Check whether this name was used somewhere in the PCH file. If - // so, defining it as a macro could change behavior, so we reject - // the PCH file. - if (IdentifierInfo *II = Reader.get(MacroName)) { - Reader.Diag(diag::warn_macro_name_used_in_pch) << II; - return true; - } - - // Add this definition to the suggested predefines buffer. - SuggestedPredefines += Extra; - SuggestedPredefines += '\n'; - } - - // If we get here, it's because the predefines buffer had compatible - // contents. Accept the PCH file. - return false; -} - -void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI, - unsigned ID) { - PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID); - ++NumHeaderInfos; -} - -void PCHValidator::ReadCounter(unsigned Value) { - PP.setCounterValue(Value); -} - -//===----------------------------------------------------------------------===// -// PCH reader implementation -//===----------------------------------------------------------------------===// - -PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context, - const char *isysroot) - : Listener(new PCHValidator(PP, *this)), DeserializationListener(0), - SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), - Diags(PP.getDiagnostics()), SemaObj(0), PP(&PP), Context(Context), - StatCache(0), Consumer(0), IdentifierTableData(0), IdentifierLookupTable(0), - IdentifierOffsets(0), - MethodPoolLookupTable(0), MethodPoolLookupTableData(0), - TotalSelectorsInMethodPool(0), SelectorOffsets(0), - TotalNumSelectors(0), MacroDefinitionOffsets(0), - NumPreallocatedPreprocessingEntities(0), - isysroot(isysroot), NumStatHits(0), NumStatMisses(0), - NumSLocEntriesRead(0), NumStatementsRead(0), - NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0), - NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0), - CurrentlyLoadingTypeOrDecl(0) { - RelocatablePCH = false; -} - -PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr, - Diagnostic &Diags, const char *isysroot) - : DeserializationListener(0), SourceMgr(SourceMgr), FileMgr(FileMgr), - Diags(Diags), SemaObj(0), PP(0), Context(0), StatCache(0), Consumer(0), - IdentifierTableData(0), IdentifierLookupTable(0), - IdentifierOffsets(0), - MethodPoolLookupTable(0), MethodPoolLookupTableData(0), - TotalSelectorsInMethodPool(0), SelectorOffsets(0), - TotalNumSelectors(0), MacroDefinitionOffsets(0), - NumPreallocatedPreprocessingEntities(0), - isysroot(isysroot), NumStatHits(0), NumStatMisses(0), - NumSLocEntriesRead(0), NumStatementsRead(0), - NumMacrosRead(0), NumMethodPoolSelectorsRead(0), NumMethodPoolMisses(0), - NumLexicalDeclContextsRead(0), NumVisibleDeclContextsRead(0), - CurrentlyLoadingTypeOrDecl(0) { - RelocatablePCH = false; -} - -PCHReader::~PCHReader() {} - - -namespace { -class PCHMethodPoolLookupTrait { - PCHReader &Reader; - -public: - typedef std::pair data_type; - - typedef Selector external_key_type; - typedef external_key_type internal_key_type; - - explicit PCHMethodPoolLookupTrait(PCHReader &Reader) : Reader(Reader) { } - - static bool EqualKey(const internal_key_type& a, - const internal_key_type& b) { - return a == b; - } - - static unsigned ComputeHash(Selector Sel) { - unsigned N = Sel.getNumArgs(); - if (N == 0) - ++N; - unsigned R = 5381; - for (unsigned I = 0; I != N; ++I) - if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) - R = llvm::HashString(II->getName(), R); - return R; - } - - // This hopefully will just get inlined and removed by the optimizer. - static const internal_key_type& - GetInternalKey(const external_key_type& x) { return x; } - - static std::pair - ReadKeyDataLength(const unsigned char*& d) { - using namespace clang::io; - unsigned KeyLen = ReadUnalignedLE16(d); - unsigned DataLen = ReadUnalignedLE16(d); - return std::make_pair(KeyLen, DataLen); - } - - internal_key_type ReadKey(const unsigned char* d, unsigned) { - using namespace clang::io; - SelectorTable &SelTable = Reader.getContext()->Selectors; - unsigned N = ReadUnalignedLE16(d); - IdentifierInfo *FirstII - = Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d)); - if (N == 0) - return SelTable.getNullarySelector(FirstII); - else if (N == 1) - return SelTable.getUnarySelector(FirstII); - - llvm::SmallVector Args; - Args.push_back(FirstII); - for (unsigned I = 1; I != N; ++I) - Args.push_back(Reader.DecodeIdentifierInfo(ReadUnalignedLE32(d))); - - return SelTable.getSelector(N, Args.data()); - } - - data_type ReadData(Selector, const unsigned char* d, unsigned DataLen) { - using namespace clang::io; - unsigned NumInstanceMethods = ReadUnalignedLE16(d); - unsigned NumFactoryMethods = ReadUnalignedLE16(d); - - data_type Result; - - // Load instance methods - ObjCMethodList *Prev = 0; - for (unsigned I = 0; I != NumInstanceMethods; ++I) { - ObjCMethodDecl *Method - = cast(Reader.GetDecl(ReadUnalignedLE32(d))); - if (!Result.first.Method) { - // This is the first method, which is the easy case. - Result.first.Method = Method; - Prev = &Result.first; - continue; - } - - ObjCMethodList *Mem = - Reader.getSema()->BumpAlloc.Allocate(); - Prev->Next = new (Mem) ObjCMethodList(Method, 0); - Prev = Prev->Next; - } - - // Load factory methods - Prev = 0; - for (unsigned I = 0; I != NumFactoryMethods; ++I) { - ObjCMethodDecl *Method - = cast(Reader.GetDecl(ReadUnalignedLE32(d))); - if (!Result.second.Method) { - // This is the first method, which is the easy case. - Result.second.Method = Method; - Prev = &Result.second; - continue; - } - - ObjCMethodList *Mem = - Reader.getSema()->BumpAlloc.Allocate(); - Prev->Next = new (Mem) ObjCMethodList(Method, 0); - Prev = Prev->Next; - } - - return Result; - } -}; - -} // end anonymous namespace - -/// \brief The on-disk hash table used for the global method pool. -typedef OnDiskChainedHashTable - PCHMethodPoolLookupTable; - -namespace { -class PCHIdentifierLookupTrait { - PCHReader &Reader; - - // If we know the IdentifierInfo in advance, it is here and we will - // not build a new one. Used when deserializing information about an - // identifier that was constructed before the PCH file was read. - IdentifierInfo *KnownII; - -public: - typedef IdentifierInfo * data_type; - - typedef const std::pair external_key_type; - - typedef external_key_type internal_key_type; - - explicit PCHIdentifierLookupTrait(PCHReader &Reader, IdentifierInfo *II = 0) - : Reader(Reader), KnownII(II) { } - - static bool EqualKey(const internal_key_type& a, - const internal_key_type& b) { - return (a.second == b.second) ? memcmp(a.first, b.first, a.second) == 0 - : false; - } - - static unsigned ComputeHash(const internal_key_type& a) { - return llvm::HashString(llvm::StringRef(a.first, a.second)); - } - - // This hopefully will just get inlined and removed by the optimizer. - static const internal_key_type& - GetInternalKey(const external_key_type& x) { return x; } - - static std::pair - ReadKeyDataLength(const unsigned char*& d) { - using namespace clang::io; - unsigned DataLen = ReadUnalignedLE16(d); - unsigned KeyLen = ReadUnalignedLE16(d); - return std::make_pair(KeyLen, DataLen); - } - - static std::pair - ReadKey(const unsigned char* d, unsigned n) { - assert(n >= 2 && d[n-1] == '\0'); - return std::make_pair((const char*) d, n-1); - } - - IdentifierInfo *ReadData(const internal_key_type& k, - const unsigned char* d, - unsigned DataLen) { - using namespace clang::io; - pch::IdentID ID = ReadUnalignedLE32(d); - bool IsInteresting = ID & 0x01; - - // Wipe out the "is interesting" bit. - ID = ID >> 1; - - if (!IsInteresting) { - // For unintersting identifiers, just build the IdentifierInfo - // and associate it with the persistent ID. - IdentifierInfo *II = KnownII; - if (!II) - II = &Reader.getIdentifierTable().CreateIdentifierInfo( - k.first, k.first + k.second); - Reader.SetIdentifierInfo(ID, II); - return II; - } - - unsigned Bits = ReadUnalignedLE16(d); - bool CPlusPlusOperatorKeyword = Bits & 0x01; - Bits >>= 1; - bool Poisoned = Bits & 0x01; - Bits >>= 1; - bool ExtensionToken = Bits & 0x01; - Bits >>= 1; - bool hasMacroDefinition = Bits & 0x01; - Bits >>= 1; - unsigned ObjCOrBuiltinID = Bits & 0x3FF; - Bits >>= 10; - - assert(Bits == 0 && "Extra bits in the identifier?"); - DataLen -= 6; - - // Build the IdentifierInfo itself and link the identifier ID with - // the new IdentifierInfo. - IdentifierInfo *II = KnownII; - if (!II) - II = &Reader.getIdentifierTable().CreateIdentifierInfo( - k.first, k.first + k.second); - Reader.SetIdentifierInfo(ID, II); - - // Set or check the various bits in the IdentifierInfo structure. - // FIXME: Load token IDs lazily, too? - II->setObjCOrBuiltinID(ObjCOrBuiltinID); - assert(II->isExtensionToken() == ExtensionToken && - "Incorrect extension token flag"); - (void)ExtensionToken; - II->setIsPoisoned(Poisoned); - assert(II->isCPlusPlusOperatorKeyword() == CPlusPlusOperatorKeyword && - "Incorrect C++ operator keyword flag"); - (void)CPlusPlusOperatorKeyword; - - // If this identifier is a macro, deserialize the macro - // definition. - if (hasMacroDefinition) { - uint32_t Offset = ReadUnalignedLE32(d); - Reader.ReadMacroRecord(Offset); - DataLen -= 4; - } - - // Read all of the declarations visible at global scope with this - // name. - if (Reader.getContext() == 0) return II; - if (DataLen > 0) { - llvm::SmallVector DeclIDs; - for (; DataLen > 0; DataLen -= 4) - DeclIDs.push_back(ReadUnalignedLE32(d)); - Reader.SetGloballyVisibleDecls(II, DeclIDs); - } - - return II; - } -}; - -} // end anonymous namespace - -/// \brief The on-disk hash table used to contain information about -/// all of the identifiers in the program. -typedef OnDiskChainedHashTable - PCHIdentifierLookupTable; - -void PCHReader::Error(const char *Msg) { - Diag(diag::err_fe_pch_malformed) << Msg; -} - -/// \brief Check the contents of the concatenation of all predefines buffers in -/// the PCH chain against the contents of the predefines buffer of the current -/// compiler invocation. -/// -/// The contents should be the same. If not, then some command-line option -/// changed the preprocessor state and we must probably reject the PCH file. -/// -/// \returns true if there was a mismatch (in which case the PCH file -/// should be ignored), or false otherwise. -bool PCHReader::CheckPredefinesBuffers() { - if (Listener) - return Listener->ReadPredefinesBuffer(PCHPredefinesBuffers, - ActualOriginalFileName, - SuggestedPredefines); - return false; -} - -//===----------------------------------------------------------------------===// -// Source Manager Deserialization -//===----------------------------------------------------------------------===// - -/// \brief Read the line table in the source manager block. -/// \returns true if ther was an error. -bool PCHReader::ParseLineTable(llvm::SmallVectorImpl &Record) { - unsigned Idx = 0; - LineTableInfo &LineTable = SourceMgr.getLineTable(); - - // Parse the file names - std::map FileIDs; - for (int I = 0, N = Record[Idx++]; I != N; ++I) { - // Extract the file name - unsigned FilenameLen = Record[Idx++]; - std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen); - Idx += FilenameLen; - MaybeAddSystemRootToFilename(Filename); - FileIDs[I] = LineTable.getLineTableFilenameID(Filename.c_str(), - Filename.size()); - } - - // Parse the line entries - std::vector Entries; - while (Idx < Record.size()) { - int FID = Record[Idx++]; - - // Extract the line entries - unsigned NumEntries = Record[Idx++]; - assert(NumEntries && "Numentries is 00000"); - Entries.clear(); - Entries.reserve(NumEntries); - for (unsigned I = 0; I != NumEntries; ++I) { - unsigned FileOffset = Record[Idx++]; - unsigned LineNo = Record[Idx++]; - int FilenameID = FileIDs[Record[Idx++]]; - SrcMgr::CharacteristicKind FileKind - = (SrcMgr::CharacteristicKind)Record[Idx++]; - unsigned IncludeOffset = Record[Idx++]; - Entries.push_back(LineEntry::get(FileOffset, LineNo, FilenameID, - FileKind, IncludeOffset)); - } - LineTable.AddEntry(FID, Entries); - } - - return false; -} - -namespace { - -class PCHStatData { -public: - const bool hasStat; - const ino_t ino; - const dev_t dev; - const mode_t mode; - const time_t mtime; - const off_t size; - - PCHStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s) - : hasStat(true), ino(i), dev(d), mode(mo), mtime(m), size(s) {} - - PCHStatData() - : hasStat(false), ino(0), dev(0), mode(0), mtime(0), size(0) {} -}; - -class PCHStatLookupTrait { - public: - typedef const char *external_key_type; - typedef const char *internal_key_type; - - typedef PCHStatData data_type; - - static unsigned ComputeHash(const char *path) { - return llvm::HashString(path); - } - - static internal_key_type GetInternalKey(const char *path) { return path; } - - static bool EqualKey(internal_key_type a, internal_key_type b) { - return strcmp(a, b) == 0; - } - - static std::pair - ReadKeyDataLength(const unsigned char*& d) { - unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d); - unsigned DataLen = (unsigned) *d++; - return std::make_pair(KeyLen + 1, DataLen); - } - - static internal_key_type ReadKey(const unsigned char *d, unsigned) { - return (const char *)d; - } - - static data_type ReadData(const internal_key_type, const unsigned char *d, - unsigned /*DataLen*/) { - using namespace clang::io; - - if (*d++ == 1) - return data_type(); - - ino_t ino = (ino_t) ReadUnalignedLE32(d); - dev_t dev = (dev_t) ReadUnalignedLE32(d); - mode_t mode = (mode_t) ReadUnalignedLE16(d); - time_t mtime = (time_t) ReadUnalignedLE64(d); - off_t size = (off_t) ReadUnalignedLE64(d); - return data_type(ino, dev, mode, mtime, size); - } -}; - -/// \brief stat() cache for precompiled headers. -/// -/// This cache is very similar to the stat cache used by pretokenized -/// headers. -class PCHStatCache : public StatSysCallCache { - typedef OnDiskChainedHashTable CacheTy; - CacheTy *Cache; - - unsigned &NumStatHits, &NumStatMisses; -public: - PCHStatCache(const unsigned char *Buckets, - const unsigned char *Base, - unsigned &NumStatHits, - unsigned &NumStatMisses) - : Cache(0), NumStatHits(NumStatHits), NumStatMisses(NumStatMisses) { - Cache = CacheTy::Create(Buckets, Base); - } - - ~PCHStatCache() { delete Cache; } - - int stat(const char *path, struct stat *buf) { - // Do the lookup for the file's data in the PCH file. - CacheTy::iterator I = Cache->find(path); - - // If we don't get a hit in the PCH file just forward to 'stat'. - if (I == Cache->end()) { - ++NumStatMisses; - return StatSysCallCache::stat(path, buf); - } - - ++NumStatHits; - PCHStatData Data = *I; - - if (!Data.hasStat) - return 1; - - buf->st_ino = Data.ino; - buf->st_dev = Data.dev; - buf->st_mtime = Data.mtime; - buf->st_mode = Data.mode; - buf->st_size = Data.size; - return 0; - } -}; -} // end anonymous namespace - - -/// \brief Read the source manager block -PCHReader::PCHReadResult PCHReader::ReadSourceManagerBlock() { - using namespace SrcMgr; - - // Set the source-location entry cursor to the current position in - // the stream. This cursor will be used to read the contents of the - // source manager block initially, and then lazily read - // source-location entries as needed. - SLocEntryCursor = Stream; - - // The stream itself is going to skip over the source manager block. - if (Stream.SkipBlock()) { - Error("malformed block record in PCH file"); - return Failure; - } - - // Enter the source manager block. - if (SLocEntryCursor.EnterSubBlock(pch::SOURCE_MANAGER_BLOCK_ID)) { - Error("malformed source manager block record in PCH file"); - return Failure; - } - - RecordData Record; - while (true) { - unsigned Code = SLocEntryCursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) { - if (SLocEntryCursor.ReadBlockEnd()) { - Error("error at end of Source Manager block in PCH file"); - return Failure; - } - return Success; - } - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - // No known subblocks, always skip them. - SLocEntryCursor.ReadSubBlockID(); - if (SLocEntryCursor.SkipBlock()) { - Error("malformed block record in PCH file"); - return Failure; - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - SLocEntryCursor.ReadAbbrevRecord(); - continue; - } - - // Read a record. - const char *BlobStart; - unsigned BlobLen; - Record.clear(); - switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { - default: // Default behavior: ignore. - break; - - case pch::SM_LINE_TABLE: - if (ParseLineTable(Record)) - return Failure; - break; - - case pch::SM_SLOC_FILE_ENTRY: - case pch::SM_SLOC_BUFFER_ENTRY: - case pch::SM_SLOC_INSTANTIATION_ENTRY: - // Once we hit one of the source location entries, we're done. - return Success; - } - } -} - -/// \brief Read in the source location entry with the given ID. -PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) { - if (ID == 0) - return Success; - - if (ID > TotalNumSLocEntries) { - Error("source location entry ID out-of-range for PCH file"); - return Failure; - } - - ++NumSLocEntriesRead; - SLocEntryCursor.JumpToBit(SLocOffsets[ID - 1]); - unsigned Code = SLocEntryCursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK || - Code == llvm::bitc::ENTER_SUBBLOCK || - Code == llvm::bitc::DEFINE_ABBREV) { - Error("incorrectly-formatted source location entry in PCH file"); - return Failure; - } - - RecordData Record; - const char *BlobStart; - unsigned BlobLen; - switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { - default: - Error("incorrectly-formatted source location entry in PCH file"); - return Failure; - - case pch::SM_SLOC_FILE_ENTRY: { - std::string Filename(BlobStart, BlobStart + BlobLen); - MaybeAddSystemRootToFilename(Filename); - const FileEntry *File = FileMgr.getFile(Filename); - if (File == 0) { - std::string ErrorStr = "could not find file '"; - ErrorStr += Filename; - ErrorStr += "' referenced by PCH file"; - Error(ErrorStr.c_str()); - return Failure; - } - - if (Record.size() < 10) { - Error("source location entry is incorrect"); - return Failure; - } - - if ((off_t)Record[4] != File->getSize() -#if !defined(LLVM_ON_WIN32) - // In our regression testing, the Windows file system seems to - // have inconsistent modification times that sometimes - // erroneously trigger this error-handling path. - || (time_t)Record[5] != File->getModificationTime() -#endif - ) { - Diag(diag::err_fe_pch_file_modified) - << Filename; - return Failure; - } - - FileID FID = SourceMgr.createFileID(File, - SourceLocation::getFromRawEncoding(Record[1]), - (SrcMgr::CharacteristicKind)Record[2], - ID, Record[0]); - if (Record[3]) - const_cast(SourceMgr.getSLocEntry(FID).getFile()) - .setHasLineDirectives(); - - // Reconstruct header-search information for this file. - HeaderFileInfo HFI; - HFI.isImport = Record[6]; - HFI.DirInfo = Record[7]; - HFI.NumIncludes = Record[8]; - HFI.ControllingMacroID = Record[9]; - if (Listener) - Listener->ReadHeaderFileInfo(HFI, File->getUID()); - break; - } - - case pch::SM_SLOC_BUFFER_ENTRY: { - const char *Name = BlobStart; - unsigned Offset = Record[0]; - unsigned Code = SLocEntryCursor.ReadCode(); - Record.clear(); - unsigned RecCode - = SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen); - - if (RecCode != pch::SM_SLOC_BUFFER_BLOB) { - Error("PCH record has invalid code"); - return Failure; - } - - llvm::MemoryBuffer *Buffer - = llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(BlobStart, BlobLen - 1), - Name); - FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, Offset); - - if (strcmp(Name, "") == 0) { - PCHPredefinesBlock Block = { - BufferID, - llvm::StringRef(BlobStart, BlobLen - 1) - }; - PCHPredefinesBuffers.push_back(Block); - } - - break; - } - - case pch::SM_SLOC_INSTANTIATION_ENTRY: { - SourceLocation SpellingLoc - = SourceLocation::getFromRawEncoding(Record[1]); - SourceMgr.createInstantiationLoc(SpellingLoc, - SourceLocation::getFromRawEncoding(Record[2]), - SourceLocation::getFromRawEncoding(Record[3]), - Record[4], - ID, - Record[0]); - break; - } - } - - return Success; -} - -/// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the -/// specified cursor. Read the abbreviations that are at the top of the block -/// and then leave the cursor pointing into the block. -bool PCHReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, - unsigned BlockID) { - if (Cursor.EnterSubBlock(BlockID)) { - Error("malformed block record in PCH file"); - return Failure; - } - - while (true) { - unsigned Code = Cursor.ReadCode(); - - // We expect all abbrevs to be at the start of the block. - if (Code != llvm::bitc::DEFINE_ABBREV) - return false; - Cursor.ReadAbbrevRecord(); - } -} - -void PCHReader::ReadMacroRecord(uint64_t Offset) { - assert(PP && "Forgot to set Preprocessor ?"); - - // Keep track of where we are in the stream, then jump back there - // after reading this macro. - SavedStreamPosition SavedPosition(Stream); - - Stream.JumpToBit(Offset); - RecordData Record; - llvm::SmallVector MacroArgs; - MacroInfo *Macro = 0; - - while (true) { - unsigned Code = Stream.ReadCode(); - switch (Code) { - case llvm::bitc::END_BLOCK: - return; - - case llvm::bitc::ENTER_SUBBLOCK: - // No known subblocks, always skip them. - Stream.ReadSubBlockID(); - if (Stream.SkipBlock()) { - Error("malformed block record in PCH file"); - return; - } - continue; - - case llvm::bitc::DEFINE_ABBREV: - Stream.ReadAbbrevRecord(); - continue; - default: break; - } - - // Read a record. - Record.clear(); - pch::PreprocessorRecordTypes RecType = - (pch::PreprocessorRecordTypes)Stream.ReadRecord(Code, Record); - switch (RecType) { - case pch::PP_MACRO_OBJECT_LIKE: - case pch::PP_MACRO_FUNCTION_LIKE: { - // If we already have a macro, that means that we've hit the end - // of the definition of the macro we were looking for. We're - // done. - if (Macro) - return; - - IdentifierInfo *II = DecodeIdentifierInfo(Record[0]); - if (II == 0) { - Error("macro must have a name in PCH file"); - return; - } - SourceLocation Loc = SourceLocation::getFromRawEncoding(Record[1]); - bool isUsed = Record[2]; - - MacroInfo *MI = PP->AllocateMacroInfo(Loc); - MI->setIsUsed(isUsed); - - unsigned NextIndex = 3; - if (RecType == pch::PP_MACRO_FUNCTION_LIKE) { - // Decode function-like macro info. - bool isC99VarArgs = Record[3]; - bool isGNUVarArgs = Record[4]; - MacroArgs.clear(); - unsigned NumArgs = Record[5]; - NextIndex = 6 + NumArgs; - for (unsigned i = 0; i != NumArgs; ++i) - MacroArgs.push_back(DecodeIdentifierInfo(Record[6+i])); - - // Install function-like macro info. - MI->setIsFunctionLike(); - if (isC99VarArgs) MI->setIsC99Varargs(); - if (isGNUVarArgs) MI->setIsGNUVarargs(); - MI->setArgumentList(MacroArgs.data(), MacroArgs.size(), - PP->getPreprocessorAllocator()); - } - - // Finally, install the macro. - PP->setMacroInfo(II, MI); - - // Remember that we saw this macro last so that we add the tokens that - // form its body to it. - Macro = MI; - - if (NextIndex + 1 == Record.size() && PP->getPreprocessingRecord()) { - // We have a macro definition. Load it now. - PP->getPreprocessingRecord()->RegisterMacroDefinition(Macro, - getMacroDefinition(Record[NextIndex])); - } - - ++NumMacrosRead; - break; - } - - case pch::PP_TOKEN: { - // If we see a TOKEN before a PP_MACRO_*, then the file is - // erroneous, just pretend we didn't see this. - if (Macro == 0) break; - - Token Tok; - Tok.startToken(); - Tok.setLocation(SourceLocation::getFromRawEncoding(Record[0])); - Tok.setLength(Record[1]); - if (IdentifierInfo *II = DecodeIdentifierInfo(Record[2])) - Tok.setIdentifierInfo(II); - Tok.setKind((tok::TokenKind)Record[3]); - Tok.setFlag((Token::TokenFlags)Record[4]); - Macro->AddTokenToBody(Tok); - break; - } - - case pch::PP_MACRO_INSTANTIATION: { - // If we already have a macro, that means that we've hit the end - // of the definition of the macro we were looking for. We're - // done. - if (Macro) - return; - - if (!PP->getPreprocessingRecord()) { - Error("missing preprocessing record in PCH file"); - return; - } - - PreprocessingRecord &PPRec = *PP->getPreprocessingRecord(); - if (PPRec.getPreprocessedEntity(Record[0])) - return; - - MacroInstantiation *MI - = new (PPRec) MacroInstantiation(DecodeIdentifierInfo(Record[3]), - SourceRange( - SourceLocation::getFromRawEncoding(Record[1]), - SourceLocation::getFromRawEncoding(Record[2])), - getMacroDefinition(Record[4])); - PPRec.SetPreallocatedEntity(Record[0], MI); - return; - } - - case pch::PP_MACRO_DEFINITION: { - // If we already have a macro, that means that we've hit the end - // of the definition of the macro we were looking for. We're - // done. - if (Macro) - return; - - if (!PP->getPreprocessingRecord()) { - Error("missing preprocessing record in PCH file"); - return; - } - - PreprocessingRecord &PPRec = *PP->getPreprocessingRecord(); - if (PPRec.getPreprocessedEntity(Record[0])) - return; - - if (Record[1] >= MacroDefinitionsLoaded.size()) { - Error("out-of-bounds macro definition record"); - return; - } - - MacroDefinition *MD - = new (PPRec) MacroDefinition(DecodeIdentifierInfo(Record[4]), - SourceLocation::getFromRawEncoding(Record[5]), - SourceRange( - SourceLocation::getFromRawEncoding(Record[2]), - SourceLocation::getFromRawEncoding(Record[3]))); - PPRec.SetPreallocatedEntity(Record[0], MD); - MacroDefinitionsLoaded[Record[1]] = MD; - return; - } - } - } -} - -void PCHReader::ReadDefinedMacros() { - // If there was no preprocessor block, do nothing. - if (!MacroCursor.getBitStreamReader()) - return; - - llvm::BitstreamCursor Cursor = MacroCursor; - if (Cursor.EnterSubBlock(pch::PREPROCESSOR_BLOCK_ID)) { - Error("malformed preprocessor block record in PCH file"); - return; - } - - RecordData Record; - while (true) { - unsigned Code = Cursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) { - if (Cursor.ReadBlockEnd()) - Error("error at end of preprocessor block in PCH file"); - return; - } - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - // No known subblocks, always skip them. - Cursor.ReadSubBlockID(); - if (Cursor.SkipBlock()) { - Error("malformed block record in PCH file"); - return; - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Cursor.ReadAbbrevRecord(); - continue; - } - - // Read a record. - const char *BlobStart; - unsigned BlobLen; - Record.clear(); - switch (Cursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { - default: // Default behavior: ignore. - break; - - case pch::PP_MACRO_OBJECT_LIKE: - case pch::PP_MACRO_FUNCTION_LIKE: - DecodeIdentifierInfo(Record[0]); - break; - - case pch::PP_TOKEN: - // Ignore tokens. - break; - - case pch::PP_MACRO_INSTANTIATION: - case pch::PP_MACRO_DEFINITION: - // Read the macro record. - ReadMacroRecord(Cursor.GetCurrentBitNo()); - break; - } - } -} - -MacroDefinition *PCHReader::getMacroDefinition(pch::IdentID ID) { - if (ID == 0 || ID >= MacroDefinitionsLoaded.size()) - return 0; - - if (!MacroDefinitionsLoaded[ID]) - ReadMacroRecord(MacroDefinitionOffsets[ID]); - - return MacroDefinitionsLoaded[ID]; -} - -/// \brief If we are loading a relocatable PCH file, and the filename is -/// not an absolute path, add the system root to the beginning of the file -/// name. -void PCHReader::MaybeAddSystemRootToFilename(std::string &Filename) { - // If this is not a relocatable PCH file, there's nothing to do. - if (!RelocatablePCH) - return; - - if (Filename.empty() || llvm::sys::Path(Filename).isAbsolute()) - return; - - if (isysroot == 0) { - // If no system root was given, default to '/' - Filename.insert(Filename.begin(), '/'); - return; - } - - unsigned Length = strlen(isysroot); - if (isysroot[Length - 1] != '/') - Filename.insert(Filename.begin(), '/'); - - Filename.insert(Filename.begin(), isysroot, isysroot + Length); -} - -PCHReader::PCHReadResult -PCHReader::ReadPCHBlock() { - if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) { - Error("malformed block record in PCH file"); - return Failure; - } - - // Read all of the records and blocks for the PCH file. - RecordData Record; - while (!Stream.AtEndOfStream()) { - unsigned Code = Stream.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) { - if (Stream.ReadBlockEnd()) { - Error("error at end of module block in PCH file"); - return Failure; - } - - return Success; - } - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - switch (Stream.ReadSubBlockID()) { - case pch::DECLTYPES_BLOCK_ID: - // We lazily load the decls block, but we want to set up the - // DeclsCursor cursor to point into it. Clone our current bitcode - // cursor to it, enter the block and read the abbrevs in that block. - // With the main cursor, we just skip over it. - DeclsCursor = Stream; - if (Stream.SkipBlock() || // Skip with the main cursor. - // Read the abbrevs. - ReadBlockAbbrevs(DeclsCursor, pch::DECLTYPES_BLOCK_ID)) { - Error("malformed block record in PCH file"); - return Failure; - } - break; - - case pch::PREPROCESSOR_BLOCK_ID: - MacroCursor = Stream; - if (PP) - PP->setExternalSource(this); - - if (Stream.SkipBlock()) { - Error("malformed block record in PCH file"); - return Failure; - } - break; - - case pch::SOURCE_MANAGER_BLOCK_ID: - switch (ReadSourceManagerBlock()) { - case Success: - break; - - case Failure: - Error("malformed source manager block in PCH file"); - return Failure; - - case IgnorePCH: - return IgnorePCH; - } - break; - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Stream.ReadAbbrevRecord(); - continue; - } - - // Read and process a record. - Record.clear(); - const char *BlobStart = 0; - unsigned BlobLen = 0; - switch ((pch::PCHRecordTypes)Stream.ReadRecord(Code, Record, - &BlobStart, &BlobLen)) { - default: // Default behavior: ignore. - break; - - case pch::TYPE_OFFSET: - if (!TypesLoaded.empty()) { - Error("duplicate TYPE_OFFSET record in PCH file"); - return Failure; - } - TypeOffsets = (const uint32_t *)BlobStart; - TypesLoaded.resize(Record[0]); - break; - - case pch::DECL_OFFSET: - if (!DeclsLoaded.empty()) { - Error("duplicate DECL_OFFSET record in PCH file"); - return Failure; - } - DeclOffsets = (const uint32_t *)BlobStart; - DeclsLoaded.resize(Record[0]); - break; - - case pch::LANGUAGE_OPTIONS: - if (ParseLanguageOptions(Record)) - return IgnorePCH; - break; - - case pch::METADATA: { - if (Record[0] != pch::VERSION_MAJOR) { - Diag(Record[0] < pch::VERSION_MAJOR? diag::warn_pch_version_too_old - : diag::warn_pch_version_too_new); - return IgnorePCH; - } - - RelocatablePCH = Record[4]; - if (Listener) { - std::string TargetTriple(BlobStart, BlobLen); - if (Listener->ReadTargetTriple(TargetTriple)) - return IgnorePCH; - } - break; - } - - case pch::IDENTIFIER_TABLE: - IdentifierTableData = BlobStart; - if (Record[0]) { - IdentifierLookupTable - = PCHIdentifierLookupTable::Create( - (const unsigned char *)IdentifierTableData + Record[0], - (const unsigned char *)IdentifierTableData, - PCHIdentifierLookupTrait(*this)); - if (PP) - PP->getIdentifierTable().setExternalIdentifierLookup(this); - } - break; - - case pch::IDENTIFIER_OFFSET: - if (!IdentifiersLoaded.empty()) { - Error("duplicate IDENTIFIER_OFFSET record in PCH file"); - return Failure; - } - IdentifierOffsets = (const uint32_t *)BlobStart; - IdentifiersLoaded.resize(Record[0]); - if (PP) - PP->getHeaderSearchInfo().SetExternalLookup(this); - break; - - case pch::EXTERNAL_DEFINITIONS: - if (!ExternalDefinitions.empty()) { - Error("duplicate EXTERNAL_DEFINITIONS record in PCH file"); - return Failure; - } - ExternalDefinitions.swap(Record); - break; - - case pch::SPECIAL_TYPES: - SpecialTypes.swap(Record); - break; - - case pch::STATISTICS: - TotalNumStatements = Record[0]; - TotalNumMacros = Record[1]; - TotalLexicalDeclContexts = Record[2]; - TotalVisibleDeclContexts = Record[3]; - break; - - case pch::TENTATIVE_DEFINITIONS: - if (!TentativeDefinitions.empty()) { - Error("duplicate TENTATIVE_DEFINITIONS record in PCH file"); - return Failure; - } - TentativeDefinitions.swap(Record); - break; - - case pch::UNUSED_STATIC_FUNCS: - if (!UnusedStaticFuncs.empty()) { - Error("duplicate UNUSED_STATIC_FUNCS record in PCH file"); - return Failure; - } - UnusedStaticFuncs.swap(Record); - break; - - case pch::LOCALLY_SCOPED_EXTERNAL_DECLS: - if (!LocallyScopedExternalDecls.empty()) { - Error("duplicate LOCALLY_SCOPED_EXTERNAL_DECLS record in PCH file"); - return Failure; - } - LocallyScopedExternalDecls.swap(Record); - break; - - case pch::SELECTOR_OFFSETS: - SelectorOffsets = (const uint32_t *)BlobStart; - TotalNumSelectors = Record[0]; - SelectorsLoaded.resize(TotalNumSelectors); - break; - - case pch::METHOD_POOL: - MethodPoolLookupTableData = (const unsigned char *)BlobStart; - if (Record[0]) - MethodPoolLookupTable - = PCHMethodPoolLookupTable::Create( - MethodPoolLookupTableData + Record[0], - MethodPoolLookupTableData, - PCHMethodPoolLookupTrait(*this)); - TotalSelectorsInMethodPool = Record[1]; - break; - - case pch::PP_COUNTER_VALUE: - if (!Record.empty() && Listener) - Listener->ReadCounter(Record[0]); - break; - - case pch::SOURCE_LOCATION_OFFSETS: - SLocOffsets = (const uint32_t *)BlobStart; - TotalNumSLocEntries = Record[0]; - SourceMgr.PreallocateSLocEntries(this, TotalNumSLocEntries, Record[1]); - break; - - case pch::SOURCE_LOCATION_PRELOADS: - for (unsigned I = 0, N = Record.size(); I != N; ++I) { - PCHReadResult Result = ReadSLocEntryRecord(Record[I]); - if (Result != Success) - return Result; - } - break; - - case pch::STAT_CACHE: { - PCHStatCache *MyStatCache = - new PCHStatCache((const unsigned char *)BlobStart + Record[0], - (const unsigned char *)BlobStart, - NumStatHits, NumStatMisses); - FileMgr.addStatCache(MyStatCache); - StatCache = MyStatCache; - break; - } - - case pch::EXT_VECTOR_DECLS: - if (!ExtVectorDecls.empty()) { - Error("duplicate EXT_VECTOR_DECLS record in PCH file"); - return Failure; - } - ExtVectorDecls.swap(Record); - break; - - case pch::VTABLE_USES: - if (!VTableUses.empty()) { - Error("duplicate VTABLE_USES record in PCH file"); - return Failure; - } - VTableUses.swap(Record); - break; - - case pch::DYNAMIC_CLASSES: - if (!DynamicClasses.empty()) { - Error("duplicate DYNAMIC_CLASSES record in PCH file"); - return Failure; - } - DynamicClasses.swap(Record); - break; - - case pch::ORIGINAL_FILE_NAME: - ActualOriginalFileName.assign(BlobStart, BlobLen); - OriginalFileName = ActualOriginalFileName; - MaybeAddSystemRootToFilename(OriginalFileName); - break; - - case pch::VERSION_CONTROL_BRANCH_REVISION: { - const std::string &CurBranch = getClangFullRepositoryVersion(); - llvm::StringRef PCHBranch(BlobStart, BlobLen); - if (llvm::StringRef(CurBranch) != PCHBranch) { - Diag(diag::warn_pch_different_branch) << PCHBranch << CurBranch; - return IgnorePCH; - } - break; - } - - case pch::MACRO_DEFINITION_OFFSETS: - MacroDefinitionOffsets = (const uint32_t *)BlobStart; - if (PP) { - if (!PP->getPreprocessingRecord()) - PP->createPreprocessingRecord(); - PP->getPreprocessingRecord()->SetExternalSource(*this, Record[0]); - } else { - NumPreallocatedPreprocessingEntities = Record[0]; - } - - MacroDefinitionsLoaded.resize(Record[1]); - break; - } - } - Error("premature end of bitstream in PCH file"); - return Failure; -} - -PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) { - // Set the PCH file name. - this->FileName = FileName; - - // Open the PCH file. - // - // FIXME: This shouldn't be here, we should just take a raw_ostream. - std::string ErrStr; - Buffer.reset(llvm::MemoryBuffer::getFileOrSTDIN(FileName, &ErrStr)); - if (!Buffer) { - Error(ErrStr.c_str()); - return IgnorePCH; - } - - // Initialize the stream - StreamFile.init((const unsigned char *)Buffer->getBufferStart(), - (const unsigned char *)Buffer->getBufferEnd()); - Stream.init(StreamFile); - - // Sniff for the signature. - if (Stream.Read(8) != 'C' || - Stream.Read(8) != 'P' || - Stream.Read(8) != 'C' || - Stream.Read(8) != 'H') { - Diag(diag::err_not_a_pch_file) << FileName; - return Failure; - } - - while (!Stream.AtEndOfStream()) { - unsigned Code = Stream.ReadCode(); - - if (Code != llvm::bitc::ENTER_SUBBLOCK) { - Error("invalid record at top-level of PCH file"); - return Failure; - } - - unsigned BlockID = Stream.ReadSubBlockID(); - - // We only know the PCH subblock ID. - switch (BlockID) { - case llvm::bitc::BLOCKINFO_BLOCK_ID: - if (Stream.ReadBlockInfoBlock()) { - Error("malformed BlockInfoBlock in PCH file"); - return Failure; - } - break; - case pch::PCH_BLOCK_ID: - switch (ReadPCHBlock()) { - case Success: - break; - - case Failure: - return Failure; - - case IgnorePCH: - // FIXME: We could consider reading through to the end of this - // PCH block, skipping subblocks, to see if there are other - // PCH blocks elsewhere. - - // Clear out any preallocated source location entries, so that - // the source manager does not try to resolve them later. - SourceMgr.ClearPreallocatedSLocEntries(); - - // Remove the stat cache. - if (StatCache) - FileMgr.removeStatCache((PCHStatCache*)StatCache); - - return IgnorePCH; - } - break; - default: - if (Stream.SkipBlock()) { - Error("malformed block record in PCH file"); - return Failure; - } - break; - } - } - - // Check the predefines buffer. - if (CheckPredefinesBuffers()) - return IgnorePCH; - - if (PP) { - // Initialization of keywords and pragmas occurs before the - // PCH file is read, so there may be some identifiers that were - // loaded into the IdentifierTable before we intercepted the - // creation of identifiers. Iterate through the list of known - // identifiers and determine whether we have to establish - // preprocessor definitions or top-level identifier declaration - // chains for those identifiers. - // - // We copy the IdentifierInfo pointers to a small vector first, - // since de-serializing declarations or macro definitions can add - // new entries into the identifier table, invalidating the - // iterators. - llvm::SmallVector Identifiers; - for (IdentifierTable::iterator Id = PP->getIdentifierTable().begin(), - IdEnd = PP->getIdentifierTable().end(); - Id != IdEnd; ++Id) - Identifiers.push_back(Id->second); - PCHIdentifierLookupTable *IdTable - = (PCHIdentifierLookupTable *)IdentifierLookupTable; - for (unsigned I = 0, N = Identifiers.size(); I != N; ++I) { - IdentifierInfo *II = Identifiers[I]; - // Look in the on-disk hash table for an entry for - PCHIdentifierLookupTrait Info(*this, II); - std::pair Key(II->getNameStart(), II->getLength()); - PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key, &Info); - if (Pos == IdTable->end()) - continue; - - // Dereferencing the iterator has the effect of populating the - // IdentifierInfo node with the various declarations it needs. - (void)*Pos; - } - } - - if (Context) - InitializeContext(*Context); - - return Success; -} - -void PCHReader::setPreprocessor(Preprocessor &pp) { - PP = &pp; - - if (NumPreallocatedPreprocessingEntities) { - if (!PP->getPreprocessingRecord()) - PP->createPreprocessingRecord(); - PP->getPreprocessingRecord()->SetExternalSource(*this, - NumPreallocatedPreprocessingEntities); - NumPreallocatedPreprocessingEntities = 0; - } -} - -void PCHReader::InitializeContext(ASTContext &Ctx) { - Context = &Ctx; - assert(Context && "Passed null context!"); - - assert(PP && "Forgot to set Preprocessor ?"); - PP->getIdentifierTable().setExternalIdentifierLookup(this); - PP->getHeaderSearchInfo().SetExternalLookup(this); - PP->setExternalSource(this); - - // Load the translation unit declaration - GetTranslationUnitDecl(); - - // Load the special types. - Context->setBuiltinVaListType( - GetType(SpecialTypes[pch::SPECIAL_TYPE_BUILTIN_VA_LIST])); - if (unsigned Id = SpecialTypes[pch::SPECIAL_TYPE_OBJC_ID]) - Context->setObjCIdType(GetType(Id)); - if (unsigned Sel = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SELECTOR]) - Context->setObjCSelType(GetType(Sel)); - if (unsigned Proto = SpecialTypes[pch::SPECIAL_TYPE_OBJC_PROTOCOL]) - Context->setObjCProtoType(GetType(Proto)); - if (unsigned Class = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS]) - Context->setObjCClassType(GetType(Class)); - - if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_CF_CONSTANT_STRING]) - Context->setCFConstantStringType(GetType(String)); - if (unsigned FastEnum - = SpecialTypes[pch::SPECIAL_TYPE_OBJC_FAST_ENUMERATION_STATE]) - Context->setObjCFastEnumerationStateType(GetType(FastEnum)); - if (unsigned File = SpecialTypes[pch::SPECIAL_TYPE_FILE]) { - QualType FileType = GetType(File); - if (FileType.isNull()) { - Error("FILE type is NULL"); - return; - } - if (const TypedefType *Typedef = FileType->getAs()) - Context->setFILEDecl(Typedef->getDecl()); - else { - const TagType *Tag = FileType->getAs(); - if (!Tag) { - Error("Invalid FILE type in PCH file"); - return; - } - Context->setFILEDecl(Tag->getDecl()); - } - } - if (unsigned Jmp_buf = SpecialTypes[pch::SPECIAL_TYPE_jmp_buf]) { - QualType Jmp_bufType = GetType(Jmp_buf); - if (Jmp_bufType.isNull()) { - Error("jmp_bug type is NULL"); - return; - } - if (const TypedefType *Typedef = Jmp_bufType->getAs()) - Context->setjmp_bufDecl(Typedef->getDecl()); - else { - const TagType *Tag = Jmp_bufType->getAs(); - if (!Tag) { - Error("Invalid jmp_bug type in PCH file"); - return; - } - Context->setjmp_bufDecl(Tag->getDecl()); - } - } - if (unsigned Sigjmp_buf = SpecialTypes[pch::SPECIAL_TYPE_sigjmp_buf]) { - QualType Sigjmp_bufType = GetType(Sigjmp_buf); - if (Sigjmp_bufType.isNull()) { - Error("sigjmp_buf type is NULL"); - return; - } - if (const TypedefType *Typedef = Sigjmp_bufType->getAs()) - Context->setsigjmp_bufDecl(Typedef->getDecl()); - else { - const TagType *Tag = Sigjmp_bufType->getAs(); - assert(Tag && "Invalid sigjmp_buf type in PCH file"); - Context->setsigjmp_bufDecl(Tag->getDecl()); - } - } - if (unsigned ObjCIdRedef - = SpecialTypes[pch::SPECIAL_TYPE_OBJC_ID_REDEFINITION]) - Context->ObjCIdRedefinitionType = GetType(ObjCIdRedef); - if (unsigned ObjCClassRedef - = SpecialTypes[pch::SPECIAL_TYPE_OBJC_CLASS_REDEFINITION]) - Context->ObjCClassRedefinitionType = GetType(ObjCClassRedef); - if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_DESCRIPTOR]) - Context->setBlockDescriptorType(GetType(String)); - if (unsigned String - = SpecialTypes[pch::SPECIAL_TYPE_BLOCK_EXTENDED_DESCRIPTOR]) - Context->setBlockDescriptorExtendedType(GetType(String)); - if (unsigned ObjCSelRedef - = SpecialTypes[pch::SPECIAL_TYPE_OBJC_SEL_REDEFINITION]) - Context->ObjCSelRedefinitionType = GetType(ObjCSelRedef); - if (unsigned String = SpecialTypes[pch::SPECIAL_TYPE_NS_CONSTANT_STRING]) - Context->setNSConstantStringType(GetType(String)); - - if (SpecialTypes[pch::SPECIAL_TYPE_INT128_INSTALLED]) - Context->setInt128Installed(); -} - -/// \brief Retrieve the name of the original source file name -/// directly from the PCH file, without actually loading the PCH -/// file. -std::string PCHReader::getOriginalSourceFile(const std::string &PCHFileName, - Diagnostic &Diags) { - // Open the PCH file. - std::string ErrStr; - llvm::OwningPtr Buffer; - Buffer.reset(llvm::MemoryBuffer::getFile(PCHFileName.c_str(), &ErrStr)); - if (!Buffer) { - Diags.Report(diag::err_fe_unable_to_read_pch_file) << ErrStr; - return std::string(); - } - - // Initialize the stream - llvm::BitstreamReader StreamFile; - llvm::BitstreamCursor Stream; - StreamFile.init((const unsigned char *)Buffer->getBufferStart(), - (const unsigned char *)Buffer->getBufferEnd()); - Stream.init(StreamFile); - - // Sniff for the signature. - if (Stream.Read(8) != 'C' || - Stream.Read(8) != 'P' || - Stream.Read(8) != 'C' || - Stream.Read(8) != 'H') { - Diags.Report(diag::err_fe_not_a_pch_file) << PCHFileName; - return std::string(); - } - - RecordData Record; - while (!Stream.AtEndOfStream()) { - unsigned Code = Stream.ReadCode(); - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - unsigned BlockID = Stream.ReadSubBlockID(); - - // We only know the PCH subblock ID. - switch (BlockID) { - case pch::PCH_BLOCK_ID: - if (Stream.EnterSubBlock(pch::PCH_BLOCK_ID)) { - Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName; - return std::string(); - } - break; - - default: - if (Stream.SkipBlock()) { - Diags.Report(diag::err_fe_pch_malformed_block) << PCHFileName; - return std::string(); - } - break; - } - continue; - } - - if (Code == llvm::bitc::END_BLOCK) { - if (Stream.ReadBlockEnd()) { - Diags.Report(diag::err_fe_pch_error_at_end_block) << PCHFileName; - return std::string(); - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Stream.ReadAbbrevRecord(); - continue; - } - - Record.clear(); - const char *BlobStart = 0; - unsigned BlobLen = 0; - if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) - == pch::ORIGINAL_FILE_NAME) - return std::string(BlobStart, BlobLen); - } - - return std::string(); -} - -/// \brief Parse the record that corresponds to a LangOptions data -/// structure. -/// -/// This routine compares the language options used to generate the -/// PCH file against the language options set for the current -/// compilation. For each option, we classify differences between the -/// two compiler states as either "benign" or "important". Benign -/// differences don't matter, and we accept them without complaint -/// (and without modifying the language options). Differences between -/// the states for important options cause the PCH file to be -/// unusable, so we emit a warning and return true to indicate that -/// there was an error. -/// -/// \returns true if the PCH file is unacceptable, false otherwise. -bool PCHReader::ParseLanguageOptions( - const llvm::SmallVectorImpl &Record) { - if (Listener) { - LangOptions LangOpts; - - #define PARSE_LANGOPT(Option) \ - LangOpts.Option = Record[Idx]; \ - ++Idx - - unsigned Idx = 0; - PARSE_LANGOPT(Trigraphs); - PARSE_LANGOPT(BCPLComment); - PARSE_LANGOPT(DollarIdents); - PARSE_LANGOPT(AsmPreprocessor); - PARSE_LANGOPT(GNUMode); - PARSE_LANGOPT(GNUKeywords); - PARSE_LANGOPT(ImplicitInt); - PARSE_LANGOPT(Digraphs); - PARSE_LANGOPT(HexFloats); - PARSE_LANGOPT(C99); - PARSE_LANGOPT(Microsoft); - PARSE_LANGOPT(CPlusPlus); - PARSE_LANGOPT(CPlusPlus0x); - PARSE_LANGOPT(CXXOperatorNames); - PARSE_LANGOPT(ObjC1); - PARSE_LANGOPT(ObjC2); - PARSE_LANGOPT(ObjCNonFragileABI); - PARSE_LANGOPT(ObjCNonFragileABI2); - PARSE_LANGOPT(NoConstantCFStrings); - PARSE_LANGOPT(PascalStrings); - PARSE_LANGOPT(WritableStrings); - PARSE_LANGOPT(LaxVectorConversions); - PARSE_LANGOPT(AltiVec); - PARSE_LANGOPT(Exceptions); - PARSE_LANGOPT(SjLjExceptions); - PARSE_LANGOPT(NeXTRuntime); - PARSE_LANGOPT(Freestanding); - PARSE_LANGOPT(NoBuiltin); - PARSE_LANGOPT(ThreadsafeStatics); - PARSE_LANGOPT(POSIXThreads); - PARSE_LANGOPT(Blocks); - PARSE_LANGOPT(EmitAllDecls); - PARSE_LANGOPT(MathErrno); - LangOpts.setSignedOverflowBehavior((LangOptions::SignedOverflowBehaviorTy) - Record[Idx++]); - PARSE_LANGOPT(HeinousExtensions); - PARSE_LANGOPT(Optimize); - PARSE_LANGOPT(OptimizeSize); - PARSE_LANGOPT(Static); - PARSE_LANGOPT(PICLevel); - PARSE_LANGOPT(GNUInline); - PARSE_LANGOPT(NoInline); - PARSE_LANGOPT(AccessControl); - PARSE_LANGOPT(CharIsSigned); - PARSE_LANGOPT(ShortWChar); - LangOpts.setGCMode((LangOptions::GCMode)Record[Idx++]); - LangOpts.setVisibilityMode((LangOptions::VisibilityMode)Record[Idx++]); - LangOpts.setStackProtectorMode((LangOptions::StackProtectorMode) - Record[Idx++]); - PARSE_LANGOPT(InstantiationDepth); - PARSE_LANGOPT(OpenCL); - PARSE_LANGOPT(CatchUndefined); - // FIXME: Missing ElideConstructors?! - #undef PARSE_LANGOPT - - return Listener->ReadLanguageOptions(LangOpts); - } - - return false; -} - -void PCHReader::ReadPreprocessedEntities() { - ReadDefinedMacros(); -} - -/// \brief Read and return the type at the given offset. -/// -/// This routine actually reads the record corresponding to the type -/// at the given offset in the bitstream. It is a helper routine for -/// GetType, which deals with reading type IDs. -QualType PCHReader::ReadTypeRecord(uint64_t Offset) { - // Keep track of where we are in the stream, then jump back there - // after reading this type. - SavedStreamPosition SavedPosition(DeclsCursor); - - ReadingKindTracker ReadingKind(Read_Type, *this); - - // Note that we are loading a type record. - LoadingTypeOrDecl Loading(*this); - - DeclsCursor.JumpToBit(Offset); - RecordData Record; - unsigned Code = DeclsCursor.ReadCode(); - switch ((pch::TypeCode)DeclsCursor.ReadRecord(Code, Record)) { - case pch::TYPE_EXT_QUAL: { - if (Record.size() != 2) { - Error("Incorrect encoding of extended qualifier type"); - return QualType(); - } - QualType Base = GetType(Record[0]); - Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[1]); - return Context->getQualifiedType(Base, Quals); - } - - case pch::TYPE_COMPLEX: { - if (Record.size() != 1) { - Error("Incorrect encoding of complex type"); - return QualType(); - } - QualType ElemType = GetType(Record[0]); - return Context->getComplexType(ElemType); - } - - case pch::TYPE_POINTER: { - if (Record.size() != 1) { - Error("Incorrect encoding of pointer type"); - return QualType(); - } - QualType PointeeType = GetType(Record[0]); - return Context->getPointerType(PointeeType); - } - - case pch::TYPE_BLOCK_POINTER: { - if (Record.size() != 1) { - Error("Incorrect encoding of block pointer type"); - return QualType(); - } - QualType PointeeType = GetType(Record[0]); - return Context->getBlockPointerType(PointeeType); - } - - case pch::TYPE_LVALUE_REFERENCE: { - if (Record.size() != 1) { - Error("Incorrect encoding of lvalue reference type"); - return QualType(); - } - QualType PointeeType = GetType(Record[0]); - return Context->getLValueReferenceType(PointeeType); - } - - case pch::TYPE_RVALUE_REFERENCE: { - if (Record.size() != 1) { - Error("Incorrect encoding of rvalue reference type"); - return QualType(); - } - QualType PointeeType = GetType(Record[0]); - return Context->getRValueReferenceType(PointeeType); - } - - case pch::TYPE_MEMBER_POINTER: { - if (Record.size() != 2) { - Error("Incorrect encoding of member pointer type"); - return QualType(); - } - QualType PointeeType = GetType(Record[0]); - QualType ClassType = GetType(Record[1]); - return Context->getMemberPointerType(PointeeType, ClassType.getTypePtr()); - } - - case pch::TYPE_CONSTANT_ARRAY: { - QualType ElementType = GetType(Record[0]); - ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; - unsigned IndexTypeQuals = Record[2]; - unsigned Idx = 3; - llvm::APInt Size = ReadAPInt(Record, Idx); - return Context->getConstantArrayType(ElementType, Size, - ASM, IndexTypeQuals); - } - - case pch::TYPE_INCOMPLETE_ARRAY: { - QualType ElementType = GetType(Record[0]); - ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; - unsigned IndexTypeQuals = Record[2]; - return Context->getIncompleteArrayType(ElementType, ASM, IndexTypeQuals); - } - - case pch::TYPE_VARIABLE_ARRAY: { - QualType ElementType = GetType(Record[0]); - ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; - unsigned IndexTypeQuals = Record[2]; - SourceLocation LBLoc = SourceLocation::getFromRawEncoding(Record[3]); - SourceLocation RBLoc = SourceLocation::getFromRawEncoding(Record[4]); - return Context->getVariableArrayType(ElementType, ReadExpr(), - ASM, IndexTypeQuals, - SourceRange(LBLoc, RBLoc)); - } - - case pch::TYPE_VECTOR: { - if (Record.size() != 3) { - Error("incorrect encoding of vector type in PCH file"); - return QualType(); - } - - QualType ElementType = GetType(Record[0]); - unsigned NumElements = Record[1]; - unsigned AltiVecSpec = Record[2]; - return Context->getVectorType(ElementType, NumElements, - (VectorType::AltiVecSpecific)AltiVecSpec); - } - - case pch::TYPE_EXT_VECTOR: { - if (Record.size() != 3) { - Error("incorrect encoding of extended vector type in PCH file"); - return QualType(); - } - - QualType ElementType = GetType(Record[0]); - unsigned NumElements = Record[1]; - return Context->getExtVectorType(ElementType, NumElements); - } - - case pch::TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 4) { - Error("incorrect encoding of no-proto function type"); - return QualType(); - } - QualType ResultType = GetType(Record[0]); - FunctionType::ExtInfo Info(Record[1], Record[2], (CallingConv)Record[3]); - return Context->getFunctionNoProtoType(ResultType, Info); - } - - case pch::TYPE_FUNCTION_PROTO: { - QualType ResultType = GetType(Record[0]); - bool NoReturn = Record[1]; - unsigned RegParm = Record[2]; - CallingConv CallConv = (CallingConv)Record[3]; - unsigned Idx = 4; - unsigned NumParams = Record[Idx++]; - llvm::SmallVector ParamTypes; - for (unsigned I = 0; I != NumParams; ++I) - ParamTypes.push_back(GetType(Record[Idx++])); - bool isVariadic = Record[Idx++]; - unsigned Quals = Record[Idx++]; - bool hasExceptionSpec = Record[Idx++]; - bool hasAnyExceptionSpec = Record[Idx++]; - unsigned NumExceptions = Record[Idx++]; - llvm::SmallVector Exceptions; - for (unsigned I = 0; I != NumExceptions; ++I) - Exceptions.push_back(GetType(Record[Idx++])); - return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams, - isVariadic, Quals, hasExceptionSpec, - hasAnyExceptionSpec, NumExceptions, - Exceptions.data(), - FunctionType::ExtInfo(NoReturn, RegParm, - CallConv)); - } - - case pch::TYPE_UNRESOLVED_USING: - return Context->getTypeDeclType( - cast(GetDecl(Record[0]))); - - case pch::TYPE_TYPEDEF: { - if (Record.size() != 2) { - Error("incorrect encoding of typedef type"); - return QualType(); - } - TypedefDecl *Decl = cast(GetDecl(Record[0])); - QualType Canonical = GetType(Record[1]); - return Context->getTypedefType(Decl, Canonical); - } - - case pch::TYPE_TYPEOF_EXPR: - return Context->getTypeOfExprType(ReadExpr()); - - case pch::TYPE_TYPEOF: { - if (Record.size() != 1) { - Error("incorrect encoding of typeof(type) in PCH file"); - return QualType(); - } - QualType UnderlyingType = GetType(Record[0]); - return Context->getTypeOfType(UnderlyingType); - } - - case pch::TYPE_DECLTYPE: - return Context->getDecltypeType(ReadExpr()); - - case pch::TYPE_RECORD: { - if (Record.size() != 2) { - Error("incorrect encoding of record type"); - return QualType(); - } - bool IsDependent = Record[0]; - QualType T = Context->getRecordType(cast(GetDecl(Record[1]))); - T->Dependent = IsDependent; - return T; - } - - case pch::TYPE_ENUM: { - if (Record.size() != 2) { - Error("incorrect encoding of enum type"); - return QualType(); - } - bool IsDependent = Record[0]; - QualType T = Context->getEnumType(cast(GetDecl(Record[1]))); - T->Dependent = IsDependent; - return T; - } - - case pch::TYPE_ELABORATED: { - unsigned Idx = 0; - ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx); - QualType NamedType = GetType(Record[Idx++]); - return Context->getElaboratedType(Keyword, NNS, NamedType); - } - - case pch::TYPE_OBJC_INTERFACE: { - unsigned Idx = 0; - ObjCInterfaceDecl *ItfD = cast(GetDecl(Record[Idx++])); - return Context->getObjCInterfaceType(ItfD); - } - - case pch::TYPE_OBJC_OBJECT: { - unsigned Idx = 0; - QualType Base = GetType(Record[Idx++]); - unsigned NumProtos = Record[Idx++]; - llvm::SmallVector Protos; - for (unsigned I = 0; I != NumProtos; ++I) - Protos.push_back(cast(GetDecl(Record[Idx++]))); - return Context->getObjCObjectType(Base, Protos.data(), NumProtos); - } - - case pch::TYPE_OBJC_OBJECT_POINTER: { - unsigned Idx = 0; - QualType Pointee = GetType(Record[Idx++]); - return Context->getObjCObjectPointerType(Pointee); - } - - case pch::TYPE_SUBST_TEMPLATE_TYPE_PARM: { - unsigned Idx = 0; - QualType Parm = GetType(Record[Idx++]); - QualType Replacement = GetType(Record[Idx++]); - return - Context->getSubstTemplateTypeParmType(cast(Parm), - Replacement); - } - - case pch::TYPE_INJECTED_CLASS_NAME: { - CXXRecordDecl *D = cast(GetDecl(Record[0])); - QualType TST = GetType(Record[1]); // probably derivable - // FIXME: ASTContext::getInjectedClassNameType is not currently suitable - // for PCH reading, too much interdependencies. - return - QualType(new (*Context, TypeAlignment) InjectedClassNameType(D, TST), 0); - } - - case pch::TYPE_TEMPLATE_TYPE_PARM: { - unsigned Idx = 0; - unsigned Depth = Record[Idx++]; - unsigned Index = Record[Idx++]; - bool Pack = Record[Idx++]; - IdentifierInfo *Name = GetIdentifierInfo(Record, Idx); - return Context->getTemplateTypeParmType(Depth, Index, Pack, Name); - } - - case pch::TYPE_DEPENDENT_NAME: { - unsigned Idx = 0; - ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx); - const IdentifierInfo *Name = this->GetIdentifierInfo(Record, Idx); - QualType Canon = GetType(Record[Idx++]); - return Context->getDependentNameType(Keyword, NNS, Name, Canon); - } - - case pch::TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION: { - unsigned Idx = 0; - ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx); - const IdentifierInfo *Name = this->GetIdentifierInfo(Record, Idx); - unsigned NumArgs = Record[Idx++]; - llvm::SmallVector Args; - Args.reserve(NumArgs); - while (NumArgs--) - Args.push_back(ReadTemplateArgument(Record, Idx)); - return Context->getDependentTemplateSpecializationType(Keyword, NNS, Name, - Args.size(), Args.data()); - } - - case pch::TYPE_DEPENDENT_SIZED_ARRAY: { - unsigned Idx = 0; - - // ArrayType - QualType ElementType = GetType(Record[Idx++]); - ArrayType::ArraySizeModifier ASM - = (ArrayType::ArraySizeModifier)Record[Idx++]; - unsigned IndexTypeQuals = Record[Idx++]; - - // DependentSizedArrayType - Expr *NumElts = ReadExpr(); - SourceRange Brackets = ReadSourceRange(Record, Idx); - - return Context->getDependentSizedArrayType(ElementType, NumElts, ASM, - IndexTypeQuals, Brackets); - } - - case pch::TYPE_TEMPLATE_SPECIALIZATION: { - unsigned Idx = 0; - bool IsDependent = Record[Idx++]; - TemplateName Name = ReadTemplateName(Record, Idx); - llvm::SmallVector Args; - ReadTemplateArgumentList(Args, Record, Idx); - QualType Canon = GetType(Record[Idx++]); - QualType T; - if (Canon.isNull()) - T = Context->getCanonicalTemplateSpecializationType(Name, Args.data(), - Args.size()); - else - T = Context->getTemplateSpecializationType(Name, Args.data(), - Args.size(), Canon); - T->Dependent = IsDependent; - return T; - } - } - // Suppress a GCC warning - return QualType(); -} - -namespace { - -class TypeLocReader : public TypeLocVisitor { - PCHReader &Reader; - const PCHReader::RecordData &Record; - unsigned &Idx; - -public: - TypeLocReader(PCHReader &Reader, const PCHReader::RecordData &Record, - unsigned &Idx) - : Reader(Reader), Record(Record), Idx(Idx) { } - - // We want compile-time assurance that we've enumerated all of - // these, so unfortunately we have to declare them first, then - // define them out-of-line. -#define ABSTRACT_TYPELOC(CLASS, PARENT) -#define TYPELOC(CLASS, PARENT) \ - void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); -#include "clang/AST/TypeLocNodes.def" - - void VisitFunctionTypeLoc(FunctionTypeLoc); - void VisitArrayTypeLoc(ArrayTypeLoc); -}; - -} - -void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { - // nothing to do -} -void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { - TL.setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - if (TL.needsExtraLocalData()) { - TL.setWrittenTypeSpec(static_cast(Record[Idx++])); - TL.setWrittenSignSpec(static_cast(Record[Idx++])); - TL.setWrittenWidthSpec(static_cast(Record[Idx++])); - TL.setModeAttr(Record[Idx++]); - } -} -void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) { - TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { - TL.setCaretLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { - TL.setAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { - TL.setAmpAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { - TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) { - TL.setLBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setRBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - if (Record[Idx++]) - TL.setSizeExpr(Reader.ReadExpr()); - else - TL.setSizeExpr(0); -} -void TypeLocReader::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { - VisitArrayTypeLoc(TL); -} -void TypeLocReader::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { - VisitArrayTypeLoc(TL); -} -void TypeLocReader::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { - VisitArrayTypeLoc(TL); -} -void TypeLocReader::VisitDependentSizedArrayTypeLoc( - DependentSizedArrayTypeLoc TL) { - VisitArrayTypeLoc(TL); -} -void TypeLocReader::VisitDependentSizedExtVectorTypeLoc( - DependentSizedExtVectorTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { - TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { - TL.setArg(i, cast_or_null(Reader.GetDecl(Record[Idx++]))); - } -} -void TypeLocReader::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { - VisitFunctionTypeLoc(TL); -} -void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { - VisitFunctionTypeLoc(TL); -} -void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { - TL.setTypeofLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { - TL.setTypeofLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setUnderlyingTInfo(Reader.GetTypeSourceInfo(Record, Idx)); -} -void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( - SubstTemplateTypeParmTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitTemplateSpecializationTypeLoc( - TemplateSpecializationTypeLoc TL) { - TL.setTemplateNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) - TL.setArgLocInfo(i, - Reader.GetTemplateArgumentLocInfo(TL.getTypePtr()->getArg(i).getKind(), - Record, Idx)); -} -void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { - TL.setKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setQualifierRange(Reader.ReadSourceRange(Record, Idx)); -} -void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { - TL.setKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setQualifierRange(Reader.ReadSourceRange(Record, Idx)); - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc( - DependentTemplateSpecializationTypeLoc TL) { - TL.setKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setQualifierRange(Reader.ReadSourceRange(Record, Idx)); - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) - TL.setArgLocInfo(I, - Reader.GetTemplateArgumentLocInfo(TL.getTypePtr()->getArg(I).getKind(), - Record, Idx)); -} -void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { - TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { - TL.setHasBaseTypeAsWritten(Record[Idx++]); - TL.setLAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TL.setRAngleLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) - TL.setProtocolLoc(i, SourceLocation::getFromRawEncoding(Record[Idx++])); -} -void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { - TL.setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -TypeSourceInfo *PCHReader::GetTypeSourceInfo(const RecordData &Record, - unsigned &Idx) { - QualType InfoTy = GetType(Record[Idx++]); - if (InfoTy.isNull()) - return 0; - - TypeSourceInfo *TInfo = getContext()->CreateTypeSourceInfo(InfoTy); - TypeLocReader TLR(*this, Record, Idx); - for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) - TLR.Visit(TL); - return TInfo; -} - -QualType PCHReader::GetType(pch::TypeID ID) { - unsigned FastQuals = ID & Qualifiers::FastMask; - unsigned Index = ID >> Qualifiers::FastWidth; - - if (Index < pch::NUM_PREDEF_TYPE_IDS) { - QualType T; - switch ((pch::PredefinedTypeIDs)Index) { - case pch::PREDEF_TYPE_NULL_ID: return QualType(); - case pch::PREDEF_TYPE_VOID_ID: T = Context->VoidTy; break; - case pch::PREDEF_TYPE_BOOL_ID: T = Context->BoolTy; break; - - case pch::PREDEF_TYPE_CHAR_U_ID: - case pch::PREDEF_TYPE_CHAR_S_ID: - // FIXME: Check that the signedness of CharTy is correct! - T = Context->CharTy; - break; - - case pch::PREDEF_TYPE_UCHAR_ID: T = Context->UnsignedCharTy; break; - case pch::PREDEF_TYPE_USHORT_ID: T = Context->UnsignedShortTy; break; - case pch::PREDEF_TYPE_UINT_ID: T = Context->UnsignedIntTy; break; - case pch::PREDEF_TYPE_ULONG_ID: T = Context->UnsignedLongTy; break; - case pch::PREDEF_TYPE_ULONGLONG_ID: T = Context->UnsignedLongLongTy; break; - case pch::PREDEF_TYPE_UINT128_ID: T = Context->UnsignedInt128Ty; break; - case pch::PREDEF_TYPE_SCHAR_ID: T = Context->SignedCharTy; break; - case pch::PREDEF_TYPE_WCHAR_ID: T = Context->WCharTy; break; - case pch::PREDEF_TYPE_SHORT_ID: T = Context->ShortTy; break; - case pch::PREDEF_TYPE_INT_ID: T = Context->IntTy; break; - case pch::PREDEF_TYPE_LONG_ID: T = Context->LongTy; break; - case pch::PREDEF_TYPE_LONGLONG_ID: T = Context->LongLongTy; break; - case pch::PREDEF_TYPE_INT128_ID: T = Context->Int128Ty; break; - case pch::PREDEF_TYPE_FLOAT_ID: T = Context->FloatTy; break; - case pch::PREDEF_TYPE_DOUBLE_ID: T = Context->DoubleTy; break; - case pch::PREDEF_TYPE_LONGDOUBLE_ID: T = Context->LongDoubleTy; break; - case pch::PREDEF_TYPE_OVERLOAD_ID: T = Context->OverloadTy; break; - case pch::PREDEF_TYPE_DEPENDENT_ID: T = Context->DependentTy; break; - case pch::PREDEF_TYPE_NULLPTR_ID: T = Context->NullPtrTy; break; - case pch::PREDEF_TYPE_CHAR16_ID: T = Context->Char16Ty; break; - case pch::PREDEF_TYPE_CHAR32_ID: T = Context->Char32Ty; break; - case pch::PREDEF_TYPE_OBJC_ID: T = Context->ObjCBuiltinIdTy; break; - case pch::PREDEF_TYPE_OBJC_CLASS: T = Context->ObjCBuiltinClassTy; break; - case pch::PREDEF_TYPE_OBJC_SEL: T = Context->ObjCBuiltinSelTy; break; - } - - assert(!T.isNull() && "Unknown predefined type"); - return T.withFastQualifiers(FastQuals); - } - - Index -= pch::NUM_PREDEF_TYPE_IDS; - //assert(Index < TypesLoaded.size() && "Type index out-of-range"); - if (TypesLoaded[Index].isNull()) { - TypesLoaded[Index] = ReadTypeRecord(TypeOffsets[Index]); - TypesLoaded[Index]->setFromPCH(); - if (DeserializationListener) - DeserializationListener->TypeRead(ID, TypesLoaded[Index]); - } - - return TypesLoaded[Index].withFastQualifiers(FastQuals); -} - -TemplateArgumentLocInfo -PCHReader::GetTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, - const RecordData &Record, - unsigned &Index) { - switch (Kind) { - case TemplateArgument::Expression: - return ReadExpr(); - case TemplateArgument::Type: - return GetTypeSourceInfo(Record, Index); - case TemplateArgument::Template: { - SourceRange QualifierRange = ReadSourceRange(Record, Index); - SourceLocation TemplateNameLoc = ReadSourceLocation(Record, Index); - return TemplateArgumentLocInfo(QualifierRange, TemplateNameLoc); - } - case TemplateArgument::Null: - case TemplateArgument::Integral: - case TemplateArgument::Declaration: - case TemplateArgument::Pack: - return TemplateArgumentLocInfo(); - } - llvm_unreachable("unexpected template argument loc"); - return TemplateArgumentLocInfo(); -} - -TemplateArgumentLoc -PCHReader::ReadTemplateArgumentLoc(const RecordData &Record, unsigned &Index) { - TemplateArgument Arg = ReadTemplateArgument(Record, Index); - - if (Arg.getKind() == TemplateArgument::Expression) { - if (Record[Index++]) // bool InfoHasSameExpr. - return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo(Arg.getAsExpr())); - } - return TemplateArgumentLoc(Arg, GetTemplateArgumentLocInfo(Arg.getKind(), - Record, Index)); -} - -Decl *PCHReader::GetExternalDecl(uint32_t ID) { - return GetDecl(ID); -} - -TranslationUnitDecl *PCHReader::GetTranslationUnitDecl() { - if (!DeclsLoaded[0]) { - ReadDeclRecord(DeclOffsets[0], 0); - if (DeserializationListener) - DeserializationListener->DeclRead(0, DeclsLoaded[0]); - } - - return cast(DeclsLoaded[0]); -} - -Decl *PCHReader::GetDecl(pch::DeclID ID) { - if (ID == 0) - return 0; - - if (ID > DeclsLoaded.size()) { - Error("declaration ID out-of-range for PCH file"); - return 0; - } - - unsigned Index = ID - 1; - if (!DeclsLoaded[Index]) { - ReadDeclRecord(DeclOffsets[Index], Index); - if (DeserializationListener) - DeserializationListener->DeclRead(ID, DeclsLoaded[Index]); - } - - return DeclsLoaded[Index]; -} - -/// \brief Resolve the offset of a statement into a statement. -/// -/// This operation will read a new statement from the external -/// source each time it is called, and is meant to be used via a -/// LazyOffsetPtr (which is used by Decls for the body of functions, etc). -Stmt *PCHReader::GetExternalDeclStmt(uint64_t Offset) { - // Since we know tha this statement is part of a decl, make sure to use the - // decl cursor to read it. - DeclsCursor.JumpToBit(Offset); - return ReadStmtFromStream(DeclsCursor); -} - -bool PCHReader::FindExternalLexicalDecls(const DeclContext *DC, - llvm::SmallVectorImpl &Decls) { - assert(DC->hasExternalLexicalStorage() && - "DeclContext has no lexical decls in storage"); - - uint64_t Offset = DeclContextOffsets[DC].first; - if (Offset == 0) { - Error("DeclContext has no lexical decls in storage"); - return true; - } - - // Keep track of where we are in the stream, then jump back there - // after reading this context. - SavedStreamPosition SavedPosition(DeclsCursor); - - // Load the record containing all of the declarations lexically in - // this context. - DeclsCursor.JumpToBit(Offset); - RecordData Record; - unsigned Code = DeclsCursor.ReadCode(); - unsigned RecCode = DeclsCursor.ReadRecord(Code, Record); - if (RecCode != pch::DECL_CONTEXT_LEXICAL) { - Error("Expected lexical block"); - return true; - } - - // Load all of the declaration IDs - for (RecordData::iterator I = Record.begin(), E = Record.end(); I != E; ++I) - Decls.push_back(GetDecl(*I)); - ++NumLexicalDeclContextsRead; - return false; -} - -DeclContext::lookup_result -PCHReader::FindExternalVisibleDeclsByName(const DeclContext *DC, - DeclarationName Name) { - assert(DC->hasExternalVisibleStorage() && - "DeclContext has no visible decls in storage"); - uint64_t Offset = DeclContextOffsets[DC].second; - if (Offset == 0) { - Error("DeclContext has no visible decls in storage"); - return DeclContext::lookup_result(DeclContext::lookup_iterator(), - DeclContext::lookup_iterator()); - } - - // Keep track of where we are in the stream, then jump back there - // after reading this context. - SavedStreamPosition SavedPosition(DeclsCursor); - - // Load the record containing all of the declarations visible in - // this context. - DeclsCursor.JumpToBit(Offset); - RecordData Record; - unsigned Code = DeclsCursor.ReadCode(); - unsigned RecCode = DeclsCursor.ReadRecord(Code, Record); - if (RecCode != pch::DECL_CONTEXT_VISIBLE) { - Error("Expected visible block"); - return DeclContext::lookup_result(DeclContext::lookup_iterator(), - DeclContext::lookup_iterator()); - } - - llvm::SmallVector Decls; - if (Record.empty()) { - SetExternalVisibleDecls(DC, Decls); - return DeclContext::lookup_result(DeclContext::lookup_iterator(), - DeclContext::lookup_iterator()); - } - - unsigned Idx = 0; - while (Idx < Record.size()) { - Decls.push_back(VisibleDeclaration()); - Decls.back().Name = ReadDeclarationName(Record, Idx); - - unsigned Size = Record[Idx++]; - llvm::SmallVector &LoadedDecls = Decls.back().Declarations; - LoadedDecls.reserve(Size); - for (unsigned I = 0; I < Size; ++I) - LoadedDecls.push_back(Record[Idx++]); - } - - ++NumVisibleDeclContextsRead; - - SetExternalVisibleDecls(DC, Decls); - return const_cast(DC)->lookup(Name); -} - -void PCHReader::PassInterestingDeclsToConsumer() { - assert(Consumer); - while (!InterestingDecls.empty()) { - DeclGroupRef DG(InterestingDecls.front()); - InterestingDecls.pop_front(); - Consumer->HandleTopLevelDecl(DG); - } -} - -void PCHReader::StartTranslationUnit(ASTConsumer *Consumer) { - this->Consumer = Consumer; - - if (!Consumer) - return; - - for (unsigned I = 0, N = ExternalDefinitions.size(); I != N; ++I) { - // Force deserialization of this decl, which will cause it to be queued for - // passing to the consumer. - GetDecl(ExternalDefinitions[I]); - } - - PassInterestingDeclsToConsumer(); -} - -void PCHReader::PrintStats() { - std::fprintf(stderr, "*** PCH Statistics:\n"); - - unsigned NumTypesLoaded - = TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(), - QualType()); - unsigned NumDeclsLoaded - = DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(), - (Decl *)0); - unsigned NumIdentifiersLoaded - = IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(), - IdentifiersLoaded.end(), - (IdentifierInfo *)0); - unsigned NumSelectorsLoaded - = SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(), - SelectorsLoaded.end(), - Selector()); - - std::fprintf(stderr, " %u stat cache hits\n", NumStatHits); - std::fprintf(stderr, " %u stat cache misses\n", NumStatMisses); - if (TotalNumSLocEntries) - std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n", - NumSLocEntriesRead, TotalNumSLocEntries, - ((float)NumSLocEntriesRead/TotalNumSLocEntries * 100)); - if (!TypesLoaded.empty()) - std::fprintf(stderr, " %u/%u types read (%f%%)\n", - NumTypesLoaded, (unsigned)TypesLoaded.size(), - ((float)NumTypesLoaded/TypesLoaded.size() * 100)); - if (!DeclsLoaded.empty()) - std::fprintf(stderr, " %u/%u declarations read (%f%%)\n", - NumDeclsLoaded, (unsigned)DeclsLoaded.size(), - ((float)NumDeclsLoaded/DeclsLoaded.size() * 100)); - if (!IdentifiersLoaded.empty()) - std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n", - NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(), - ((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100)); - if (TotalNumSelectors) - std::fprintf(stderr, " %u/%u selectors read (%f%%)\n", - NumSelectorsLoaded, TotalNumSelectors, - ((float)NumSelectorsLoaded/TotalNumSelectors * 100)); - if (TotalNumStatements) - std::fprintf(stderr, " %u/%u statements read (%f%%)\n", - NumStatementsRead, TotalNumStatements, - ((float)NumStatementsRead/TotalNumStatements * 100)); - if (TotalNumMacros) - std::fprintf(stderr, " %u/%u macros read (%f%%)\n", - NumMacrosRead, TotalNumMacros, - ((float)NumMacrosRead/TotalNumMacros * 100)); - if (TotalLexicalDeclContexts) - std::fprintf(stderr, " %u/%u lexical declcontexts read (%f%%)\n", - NumLexicalDeclContextsRead, TotalLexicalDeclContexts, - ((float)NumLexicalDeclContextsRead/TotalLexicalDeclContexts - * 100)); - if (TotalVisibleDeclContexts) - std::fprintf(stderr, " %u/%u visible declcontexts read (%f%%)\n", - NumVisibleDeclContextsRead, TotalVisibleDeclContexts, - ((float)NumVisibleDeclContextsRead/TotalVisibleDeclContexts - * 100)); - if (TotalSelectorsInMethodPool) { - std::fprintf(stderr, " %u/%u method pool entries read (%f%%)\n", - NumMethodPoolSelectorsRead, TotalSelectorsInMethodPool, - ((float)NumMethodPoolSelectorsRead/TotalSelectorsInMethodPool - * 100)); - std::fprintf(stderr, " %u method pool misses\n", NumMethodPoolMisses); - } - std::fprintf(stderr, "\n"); -} - -void PCHReader::InitializeSema(Sema &S) { - SemaObj = &S; - S.ExternalSource = this; - - // Makes sure any declarations that were deserialized "too early" - // still get added to the identifier's declaration chains. - for (unsigned I = 0, N = PreloadedDecls.size(); I != N; ++I) { - SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(PreloadedDecls[I])); - SemaObj->IdResolver.AddDecl(PreloadedDecls[I]); - } - PreloadedDecls.clear(); - - // If there were any tentative definitions, deserialize them and add - // them to Sema's list of tentative definitions. - for (unsigned I = 0, N = TentativeDefinitions.size(); I != N; ++I) { - VarDecl *Var = cast(GetDecl(TentativeDefinitions[I])); - SemaObj->TentativeDefinitions.push_back(Var); - } - - // If there were any unused static functions, deserialize them and add to - // Sema's list of unused static functions. - for (unsigned I = 0, N = UnusedStaticFuncs.size(); I != N; ++I) { - FunctionDecl *FD = cast(GetDecl(UnusedStaticFuncs[I])); - SemaObj->UnusedStaticFuncs.push_back(FD); - } - - // If there were any locally-scoped external declarations, - // deserialize them and add them to Sema's table of locally-scoped - // external declarations. - for (unsigned I = 0, N = LocallyScopedExternalDecls.size(); I != N; ++I) { - NamedDecl *D = cast(GetDecl(LocallyScopedExternalDecls[I])); - SemaObj->LocallyScopedExternalDecls[D->getDeclName()] = D; - } - - // If there were any ext_vector type declarations, deserialize them - // and add them to Sema's vector of such declarations. - for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) - SemaObj->ExtVectorDecls.push_back( - cast(GetDecl(ExtVectorDecls[I]))); - - // FIXME: Do VTable uses and dynamic classes deserialize too much ? - // Can we cut them down before writing them ? - - // If there were any VTable uses, deserialize the information and add it - // to Sema's vector and map of VTable uses. - unsigned Idx = 0; - for (unsigned I = 0, N = VTableUses[Idx++]; I != N; ++I) { - CXXRecordDecl *Class = cast(GetDecl(VTableUses[Idx++])); - SourceLocation Loc = ReadSourceLocation(VTableUses, Idx); - bool DefinitionRequired = VTableUses[Idx++]; - SemaObj->VTableUses.push_back(std::make_pair(Class, Loc)); - SemaObj->VTablesUsed[Class] = DefinitionRequired; - } - - // If there were any dynamic classes declarations, deserialize them - // and add them to Sema's vector of such declarations. - for (unsigned I = 0, N = DynamicClasses.size(); I != N; ++I) - SemaObj->DynamicClasses.push_back( - cast(GetDecl(DynamicClasses[I]))); -} - -IdentifierInfo* PCHReader::get(const char *NameStart, const char *NameEnd) { - // Try to find this name within our on-disk hash table - PCHIdentifierLookupTable *IdTable - = (PCHIdentifierLookupTable *)IdentifierLookupTable; - std::pair Key(NameStart, NameEnd - NameStart); - PCHIdentifierLookupTable::iterator Pos = IdTable->find(Key); - if (Pos == IdTable->end()) - return 0; - - // Dereferencing the iterator has the effect of building the - // IdentifierInfo node and populating it with the various - // declarations it needs. - return *Pos; -} - -std::pair -PCHReader::ReadMethodPool(Selector Sel) { - if (!MethodPoolLookupTable) - return std::pair(); - - // Try to find this selector within our on-disk hash table. - PCHMethodPoolLookupTable *PoolTable - = (PCHMethodPoolLookupTable*)MethodPoolLookupTable; - PCHMethodPoolLookupTable::iterator Pos = PoolTable->find(Sel); - if (Pos == PoolTable->end()) { - ++NumMethodPoolMisses; - return std::pair();; - } - - ++NumMethodPoolSelectorsRead; - return *Pos; -} - -void PCHReader::SetIdentifierInfo(unsigned ID, IdentifierInfo *II) { - assert(ID && "Non-zero identifier ID required"); - assert(ID <= IdentifiersLoaded.size() && "identifier ID out of range"); - IdentifiersLoaded[ID - 1] = II; -} - -/// \brief Set the globally-visible declarations associated with the given -/// identifier. -/// -/// If the PCH reader is currently in a state where the given declaration IDs -/// cannot safely be resolved, they are queued until it is safe to resolve -/// them. -/// -/// \param II an IdentifierInfo that refers to one or more globally-visible -/// declarations. -/// -/// \param DeclIDs the set of declaration IDs with the name @p II that are -/// visible at global scope. -/// -/// \param Nonrecursive should be true to indicate that the caller knows that -/// this call is non-recursive, and therefore the globally-visible declarations -/// will not be placed onto the pending queue. -void -PCHReader::SetGloballyVisibleDecls(IdentifierInfo *II, - const llvm::SmallVectorImpl &DeclIDs, - bool Nonrecursive) { - if (CurrentlyLoadingTypeOrDecl && !Nonrecursive) { - PendingIdentifierInfos.push_back(PendingIdentifierInfo()); - PendingIdentifierInfo &PII = PendingIdentifierInfos.back(); - PII.II = II; - for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) - PII.DeclIDs.push_back(DeclIDs[I]); - return; - } - - for (unsigned I = 0, N = DeclIDs.size(); I != N; ++I) { - NamedDecl *D = cast(GetDecl(DeclIDs[I])); - if (SemaObj) { - // Introduce this declaration into the translation-unit scope - // and add it to the declaration chain for this identifier, so - // that (unqualified) name lookup will find it. - SemaObj->TUScope->AddDecl(Action::DeclPtrTy::make(D)); - SemaObj->IdResolver.AddDeclToIdentifierChain(II, D); - } else { - // Queue this declaration so that it will be added to the - // translation unit scope and identifier's declaration chain - // once a Sema object is known. - PreloadedDecls.push_back(D); - } - } -} - -IdentifierInfo *PCHReader::DecodeIdentifierInfo(unsigned ID) { - if (ID == 0) - return 0; - - if (!IdentifierTableData || IdentifiersLoaded.empty()) { - Error("no identifier table in PCH file"); - return 0; - } - - assert(PP && "Forgot to set Preprocessor ?"); - if (!IdentifiersLoaded[ID - 1]) { - uint32_t Offset = IdentifierOffsets[ID - 1]; - const char *Str = IdentifierTableData + Offset; - - // All of the strings in the PCH file are preceded by a 16-bit - // length. Extract that 16-bit length to avoid having to execute - // strlen(). - // NOTE: 'StrLenPtr' is an 'unsigned char*' so that we load bytes as - // unsigned integers. This is important to avoid integer overflow when - // we cast them to 'unsigned'. - const unsigned char *StrLenPtr = (const unsigned char*) Str - 2; - unsigned StrLen = (((unsigned) StrLenPtr[0]) - | (((unsigned) StrLenPtr[1]) << 8)) - 1; - IdentifiersLoaded[ID - 1] - = &PP->getIdentifierTable().get(Str, StrLen); - } - - return IdentifiersLoaded[ID - 1]; -} - -void PCHReader::ReadSLocEntry(unsigned ID) { - ReadSLocEntryRecord(ID); -} - -Selector PCHReader::DecodeSelector(unsigned ID) { - if (ID == 0) - return Selector(); - - if (!MethodPoolLookupTableData) - return Selector(); - - if (ID > TotalNumSelectors) { - Error("selector ID out of range in PCH file"); - return Selector(); - } - - unsigned Index = ID - 1; - if (SelectorsLoaded[Index].getAsOpaquePtr() == 0) { - // Load this selector from the selector table. - // FIXME: endianness portability issues with SelectorOffsets table - PCHMethodPoolLookupTrait Trait(*this); - SelectorsLoaded[Index] - = Trait.ReadKey(MethodPoolLookupTableData + SelectorOffsets[Index], 0); - } - - return SelectorsLoaded[Index]; -} - -Selector PCHReader::GetExternalSelector(uint32_t ID) { - return DecodeSelector(ID); -} - -uint32_t PCHReader::GetNumExternalSelectors() { - return TotalNumSelectors + 1; -} - -DeclarationName -PCHReader::ReadDeclarationName(const RecordData &Record, unsigned &Idx) { - DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++]; - switch (Kind) { - case DeclarationName::Identifier: - return DeclarationName(GetIdentifierInfo(Record, Idx)); - - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - return DeclarationName(GetSelector(Record, Idx)); - - case DeclarationName::CXXConstructorName: - return Context->DeclarationNames.getCXXConstructorName( - Context->getCanonicalType(GetType(Record[Idx++]))); - - case DeclarationName::CXXDestructorName: - return Context->DeclarationNames.getCXXDestructorName( - Context->getCanonicalType(GetType(Record[Idx++]))); - - case DeclarationName::CXXConversionFunctionName: - return Context->DeclarationNames.getCXXConversionFunctionName( - Context->getCanonicalType(GetType(Record[Idx++]))); - - case DeclarationName::CXXOperatorName: - return Context->DeclarationNames.getCXXOperatorName( - (OverloadedOperatorKind)Record[Idx++]); - - case DeclarationName::CXXLiteralOperatorName: - return Context->DeclarationNames.getCXXLiteralOperatorName( - GetIdentifierInfo(Record, Idx)); - - case DeclarationName::CXXUsingDirective: - return DeclarationName::getUsingDirectiveName(); - } - - // Required to silence GCC warning - return DeclarationName(); -} - -TemplateName -PCHReader::ReadTemplateName(const RecordData &Record, unsigned &Idx) { - TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++]; - switch (Kind) { - case TemplateName::Template: - return TemplateName(cast_or_null(GetDecl(Record[Idx++]))); - - case TemplateName::OverloadedTemplate: { - unsigned size = Record[Idx++]; - UnresolvedSet<8> Decls; - while (size--) - Decls.addDecl(cast(GetDecl(Record[Idx++]))); - - return Context->getOverloadedTemplateName(Decls.begin(), Decls.end()); - } - - case TemplateName::QualifiedTemplate: { - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx); - bool hasTemplKeyword = Record[Idx++]; - TemplateDecl *Template = cast(GetDecl(Record[Idx++])); - return Context->getQualifiedTemplateName(NNS, hasTemplKeyword, Template); - } - - case TemplateName::DependentTemplate: { - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(Record, Idx); - if (Record[Idx++]) // isIdentifier - return Context->getDependentTemplateName(NNS, - GetIdentifierInfo(Record, Idx)); - return Context->getDependentTemplateName(NNS, - (OverloadedOperatorKind)Record[Idx++]); - } - } - - assert(0 && "Unhandled template name kind!"); - return TemplateName(); -} - -TemplateArgument -PCHReader::ReadTemplateArgument(const RecordData &Record, unsigned &Idx) { - switch ((TemplateArgument::ArgKind)Record[Idx++]) { - case TemplateArgument::Null: - return TemplateArgument(); - case TemplateArgument::Type: - return TemplateArgument(GetType(Record[Idx++])); - case TemplateArgument::Declaration: - return TemplateArgument(GetDecl(Record[Idx++])); - case TemplateArgument::Integral: { - llvm::APSInt Value = ReadAPSInt(Record, Idx); - QualType T = GetType(Record[Idx++]); - return TemplateArgument(Value, T); - } - case TemplateArgument::Template: - return TemplateArgument(ReadTemplateName(Record, Idx)); - case TemplateArgument::Expression: - return TemplateArgument(ReadExpr()); - case TemplateArgument::Pack: { - unsigned NumArgs = Record[Idx++]; - llvm::SmallVector Args; - Args.reserve(NumArgs); - while (NumArgs--) - Args.push_back(ReadTemplateArgument(Record, Idx)); - TemplateArgument TemplArg; - TemplArg.setArgumentPack(Args.data(), Args.size(), /*CopyArgs=*/true); - return TemplArg; - } - } - - assert(0 && "Unhandled template argument kind!"); - return TemplateArgument(); -} - -TemplateParameterList * -PCHReader::ReadTemplateParameterList(const RecordData &Record, unsigned &Idx) { - SourceLocation TemplateLoc = ReadSourceLocation(Record, Idx); - SourceLocation LAngleLoc = ReadSourceLocation(Record, Idx); - SourceLocation RAngleLoc = ReadSourceLocation(Record, Idx); - - unsigned NumParams = Record[Idx++]; - llvm::SmallVector Params; - Params.reserve(NumParams); - while (NumParams--) - Params.push_back(cast(GetDecl(Record[Idx++]))); - - TemplateParameterList* TemplateParams = - TemplateParameterList::Create(*Context, TemplateLoc, LAngleLoc, - Params.data(), Params.size(), RAngleLoc); - return TemplateParams; -} - -void -PCHReader:: -ReadTemplateArgumentList(llvm::SmallVector &TemplArgs, - const RecordData &Record, unsigned &Idx) { - unsigned NumTemplateArgs = Record[Idx++]; - TemplArgs.reserve(NumTemplateArgs); - while (NumTemplateArgs--) - TemplArgs.push_back(ReadTemplateArgument(Record, Idx)); -} - -/// \brief Read a UnresolvedSet structure. -void PCHReader::ReadUnresolvedSet(UnresolvedSetImpl &Set, - const RecordData &Record, unsigned &Idx) { - unsigned NumDecls = Record[Idx++]; - while (NumDecls--) { - NamedDecl *D = cast(GetDecl(Record[Idx++])); - AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; - Set.addDecl(D, AS); - } -} - -CXXBaseSpecifier -PCHReader::ReadCXXBaseSpecifier(const RecordData &Record, unsigned &Idx) { - bool isVirtual = static_cast(Record[Idx++]); - bool isBaseOfClass = static_cast(Record[Idx++]); - AccessSpecifier AS = static_cast(Record[Idx++]); - QualType T = GetType(Record[Idx++]); - SourceRange Range = ReadSourceRange(Record, Idx); - return CXXBaseSpecifier(Range, isVirtual, isBaseOfClass, AS, T); -} - -NestedNameSpecifier * -PCHReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) { - unsigned N = Record[Idx++]; - NestedNameSpecifier *NNS = 0, *Prev = 0; - for (unsigned I = 0; I != N; ++I) { - NestedNameSpecifier::SpecifierKind Kind - = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; - switch (Kind) { - case NestedNameSpecifier::Identifier: { - IdentifierInfo *II = GetIdentifierInfo(Record, Idx); - NNS = NestedNameSpecifier::Create(*Context, Prev, II); - break; - } - - case NestedNameSpecifier::Namespace: { - NamespaceDecl *NS = cast(GetDecl(Record[Idx++])); - NNS = NestedNameSpecifier::Create(*Context, Prev, NS); - break; - } - - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: { - Type *T = GetType(Record[Idx++]).getTypePtr(); - bool Template = Record[Idx++]; - NNS = NestedNameSpecifier::Create(*Context, Prev, Template, T); - break; - } - - case NestedNameSpecifier::Global: { - NNS = NestedNameSpecifier::GlobalSpecifier(*Context); - // No associated value, and there can't be a prefix. - break; - } - } - Prev = NNS; - } - return NNS; -} - -SourceRange -PCHReader::ReadSourceRange(const RecordData &Record, unsigned &Idx) { - SourceLocation beg = SourceLocation::getFromRawEncoding(Record[Idx++]); - SourceLocation end = SourceLocation::getFromRawEncoding(Record[Idx++]); - return SourceRange(beg, end); -} - -/// \brief Read an integral value -llvm::APInt PCHReader::ReadAPInt(const RecordData &Record, unsigned &Idx) { - unsigned BitWidth = Record[Idx++]; - unsigned NumWords = llvm::APInt::getNumWords(BitWidth); - llvm::APInt Result(BitWidth, NumWords, &Record[Idx]); - Idx += NumWords; - return Result; -} - -/// \brief Read a signed integral value -llvm::APSInt PCHReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) { - bool isUnsigned = Record[Idx++]; - return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned); -} - -/// \brief Read a floating-point value -llvm::APFloat PCHReader::ReadAPFloat(const RecordData &Record, unsigned &Idx) { - return llvm::APFloat(ReadAPInt(Record, Idx)); -} - -// \brief Read a string -std::string PCHReader::ReadString(const RecordData &Record, unsigned &Idx) { - unsigned Len = Record[Idx++]; - std::string Result(Record.data() + Idx, Record.data() + Idx + Len); - Idx += Len; - return Result; -} - -CXXTemporary *PCHReader::ReadCXXTemporary(const RecordData &Record, - unsigned &Idx) { - CXXDestructorDecl *Decl = cast(GetDecl(Record[Idx++])); - return CXXTemporary::Create(*Context, Decl); -} - -DiagnosticBuilder PCHReader::Diag(unsigned DiagID) { - return Diag(SourceLocation(), DiagID); -} - -DiagnosticBuilder PCHReader::Diag(SourceLocation Loc, unsigned DiagID) { - return Diags.Report(FullSourceLoc(Loc, SourceMgr), DiagID); -} - -/// \brief Retrieve the identifier table associated with the -/// preprocessor. -IdentifierTable &PCHReader::getIdentifierTable() { - assert(PP && "Forgot to set Preprocessor ?"); - return PP->getIdentifierTable(); -} - -/// \brief Record that the given ID maps to the given switch-case -/// statement. -void PCHReader::RecordSwitchCaseID(SwitchCase *SC, unsigned ID) { - assert(SwitchCaseStmts[ID] == 0 && "Already have a SwitchCase with this ID"); - SwitchCaseStmts[ID] = SC; -} - -/// \brief Retrieve the switch-case statement with the given ID. -SwitchCase *PCHReader::getSwitchCaseWithID(unsigned ID) { - assert(SwitchCaseStmts[ID] != 0 && "No SwitchCase with this ID"); - return SwitchCaseStmts[ID]; -} - -/// \brief Record that the given label statement has been -/// deserialized and has the given ID. -void PCHReader::RecordLabelStmt(LabelStmt *S, unsigned ID) { - assert(LabelStmts.find(ID) == LabelStmts.end() && - "Deserialized label twice"); - LabelStmts[ID] = S; - - // If we've already seen any goto statements that point to this - // label, resolve them now. - typedef std::multimap::iterator GotoIter; - std::pair Gotos = UnresolvedGotoStmts.equal_range(ID); - for (GotoIter Goto = Gotos.first; Goto != Gotos.second; ++Goto) - Goto->second->setLabel(S); - UnresolvedGotoStmts.erase(Gotos.first, Gotos.second); - - // If we've already seen any address-label statements that point to - // this label, resolve them now. - typedef std::multimap::iterator AddrLabelIter; - std::pair AddrLabels - = UnresolvedAddrLabelExprs.equal_range(ID); - for (AddrLabelIter AddrLabel = AddrLabels.first; - AddrLabel != AddrLabels.second; ++AddrLabel) - AddrLabel->second->setLabel(S); - UnresolvedAddrLabelExprs.erase(AddrLabels.first, AddrLabels.second); -} - -/// \brief Set the label of the given statement to the label -/// identified by ID. -/// -/// Depending on the order in which the label and other statements -/// referencing that label occur, this operation may complete -/// immediately (updating the statement) or it may queue the -/// statement to be back-patched later. -void PCHReader::SetLabelOf(GotoStmt *S, unsigned ID) { - std::map::iterator Label = LabelStmts.find(ID); - if (Label != LabelStmts.end()) { - // We've already seen this label, so set the label of the goto and - // we're done. - S->setLabel(Label->second); - } else { - // We haven't seen this label yet, so add this goto to the set of - // unresolved goto statements. - UnresolvedGotoStmts.insert(std::make_pair(ID, S)); - } -} - -/// \brief Set the label of the given expression to the label -/// identified by ID. -/// -/// Depending on the order in which the label and other statements -/// referencing that label occur, this operation may complete -/// immediately (updating the statement) or it may queue the -/// statement to be back-patched later. -void PCHReader::SetLabelOf(AddrLabelExpr *S, unsigned ID) { - std::map::iterator Label = LabelStmts.find(ID); - if (Label != LabelStmts.end()) { - // We've already seen this label, so set the label of the - // label-address expression and we're done. - S->setLabel(Label->second); - } else { - // We haven't seen this label yet, so add this label-address - // expression to the set of unresolved label-address expressions. - UnresolvedAddrLabelExprs.insert(std::make_pair(ID, S)); - } -} - - -PCHReader::LoadingTypeOrDecl::LoadingTypeOrDecl(PCHReader &Reader) - : Reader(Reader), Parent(Reader.CurrentlyLoadingTypeOrDecl) { - Reader.CurrentlyLoadingTypeOrDecl = this; -} - -PCHReader::LoadingTypeOrDecl::~LoadingTypeOrDecl() { - if (!Parent) { - // If any identifiers with corresponding top-level declarations have - // been loaded, load those declarations now. - while (!Reader.PendingIdentifierInfos.empty()) { - Reader.SetGloballyVisibleDecls(Reader.PendingIdentifierInfos.front().II, - Reader.PendingIdentifierInfos.front().DeclIDs, - true); - Reader.PendingIdentifierInfos.pop_front(); - } - - // We are not in recursive loading, so it's safe to pass the "interesting" - // decls to the consumer. - if (Reader.Consumer) - Reader.PassInterestingDeclsToConsumer(); - } - - Reader.CurrentlyLoadingTypeOrDecl = Parent; -} diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp deleted file mode 100644 index 742f0e4..0000000 --- a/lib/Frontend/PCHReaderDecl.cpp +++ /dev/null @@ -1,1484 +0,0 @@ -//===--- PCHReaderDecl.cpp - Decl Deserialization ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the PCHReader::ReadDeclRecord method, which is the -// entrypoint for loading a decl. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/PCHReader.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/DeclGroup.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/Expr.h" -using namespace clang; - - -//===----------------------------------------------------------------------===// -// Declaration deserialization -//===----------------------------------------------------------------------===// - -namespace clang { - class PCHDeclReader : public DeclVisitor { - PCHReader &Reader; - const PCHReader::RecordData &Record; - unsigned &Idx; - pch::TypeID TypeIDForTypeDecl; - - public: - PCHDeclReader(PCHReader &Reader, const PCHReader::RecordData &Record, - unsigned &Idx) - : Reader(Reader), Record(Record), Idx(Idx), TypeIDForTypeDecl(0) { } - - void Visit(Decl *D); - - void VisitDecl(Decl *D); - void VisitTranslationUnitDecl(TranslationUnitDecl *TU); - void VisitNamedDecl(NamedDecl *ND); - void VisitNamespaceDecl(NamespaceDecl *D); - void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); - void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); - void VisitTypeDecl(TypeDecl *TD); - void VisitTypedefDecl(TypedefDecl *TD); - void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); - void VisitTagDecl(TagDecl *TD); - void VisitEnumDecl(EnumDecl *ED); - void VisitRecordDecl(RecordDecl *RD); - void VisitCXXRecordDecl(CXXRecordDecl *D); - void VisitClassTemplateSpecializationDecl( - ClassTemplateSpecializationDecl *D); - void VisitClassTemplatePartialSpecializationDecl( - ClassTemplatePartialSpecializationDecl *D); - void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); - void VisitValueDecl(ValueDecl *VD); - void VisitEnumConstantDecl(EnumConstantDecl *ECD); - void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); - void VisitDeclaratorDecl(DeclaratorDecl *DD); - void VisitFunctionDecl(FunctionDecl *FD); - void VisitCXXMethodDecl(CXXMethodDecl *D); - void VisitCXXConstructorDecl(CXXConstructorDecl *D); - void VisitCXXDestructorDecl(CXXDestructorDecl *D); - void VisitCXXConversionDecl(CXXConversionDecl *D); - void VisitFieldDecl(FieldDecl *FD); - void VisitVarDecl(VarDecl *VD); - void VisitImplicitParamDecl(ImplicitParamDecl *PD); - void VisitParmVarDecl(ParmVarDecl *PD); - void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); - void VisitTemplateDecl(TemplateDecl *D); - void VisitClassTemplateDecl(ClassTemplateDecl *D); - void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); - void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); - void VisitUsingDecl(UsingDecl *D); - void VisitUsingShadowDecl(UsingShadowDecl *D); - void VisitLinkageSpecDecl(LinkageSpecDecl *D); - void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD); - void VisitAccessSpecDecl(AccessSpecDecl *D); - void VisitFriendDecl(FriendDecl *D); - void VisitFriendTemplateDecl(FriendTemplateDecl *D); - void VisitStaticAssertDecl(StaticAssertDecl *D); - void VisitBlockDecl(BlockDecl *BD); - - std::pair VisitDeclContext(DeclContext *DC); - - // FIXME: Reorder according to DeclNodes.td? - void VisitObjCMethodDecl(ObjCMethodDecl *D); - void VisitObjCContainerDecl(ObjCContainerDecl *D); - void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); - void VisitObjCIvarDecl(ObjCIvarDecl *D); - void VisitObjCProtocolDecl(ObjCProtocolDecl *D); - void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D); - void VisitObjCClassDecl(ObjCClassDecl *D); - void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); - void VisitObjCCategoryDecl(ObjCCategoryDecl *D); - void VisitObjCImplDecl(ObjCImplDecl *D); - void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); - void VisitObjCImplementationDecl(ObjCImplementationDecl *D); - void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); - void VisitObjCPropertyDecl(ObjCPropertyDecl *D); - void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); - }; -} - -void PCHDeclReader::Visit(Decl *D) { - DeclVisitor::Visit(D); - - if (TypeDecl *TD = dyn_cast(D)) { - // if we have a fully initialized TypeDecl, we can safely read its type now. - TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtr()); - } else if (FunctionDecl *FD = dyn_cast(D)) { - // FunctionDecl's body was written last after all other Stmts/Exprs. - if (Record[Idx++]) - FD->setLazyBody(Reader.getDeclsCursor().GetCurrentBitNo()); - } -} - -void PCHDeclReader::VisitDecl(Decl *D) { - D->setDeclContext(cast_or_null(Reader.GetDecl(Record[Idx++]))); - D->setLexicalDeclContext( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - D->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); - D->setInvalidDecl(Record[Idx++]); - if (Record[Idx++]) - D->initAttrs(Reader.ReadAttributes()); - D->setImplicit(Record[Idx++]); - D->setUsed(Record[Idx++]); - D->setAccess((AccessSpecifier)Record[Idx++]); - D->setPCHLevel(Record[Idx++] + 1); -} - -void PCHDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { - VisitDecl(TU); - TU->setAnonymousNamespace( - cast_or_null(Reader.GetDecl(Record[Idx++]))); -} - -void PCHDeclReader::VisitNamedDecl(NamedDecl *ND) { - VisitDecl(ND); - ND->setDeclName(Reader.ReadDeclarationName(Record, Idx)); -} - -void PCHDeclReader::VisitTypeDecl(TypeDecl *TD) { - VisitNamedDecl(TD); - // Delay type reading until after we have fully initialized the decl. - TypeIDForTypeDecl = Record[Idx++]; -} - -void PCHDeclReader::VisitTypedefDecl(TypedefDecl *TD) { - VisitTypeDecl(TD); - TD->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); -} - -void PCHDeclReader::VisitTagDecl(TagDecl *TD) { - VisitTypeDecl(TD); - TD->IdentifierNamespace = Record[Idx++]; - TD->setPreviousDeclaration( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - TD->setTagKind((TagDecl::TagKind)Record[Idx++]); - TD->setDefinition(Record[Idx++]); - TD->setEmbeddedInDeclarator(Record[Idx++]); - TD->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - TD->setTagKeywordLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - // FIXME: maybe read optional qualifier and its range. - TD->setTypedefForAnonDecl( - cast_or_null(Reader.GetDecl(Record[Idx++]))); -} - -void PCHDeclReader::VisitEnumDecl(EnumDecl *ED) { - VisitTagDecl(ED); - ED->setIntegerType(Reader.GetType(Record[Idx++])); - ED->setPromotionType(Reader.GetType(Record[Idx++])); - ED->setNumPositiveBits(Record[Idx++]); - ED->setNumNegativeBits(Record[Idx++]); - ED->setInstantiationOfMemberEnum( - cast_or_null(Reader.GetDecl(Record[Idx++]))); -} - -void PCHDeclReader::VisitRecordDecl(RecordDecl *RD) { - VisitTagDecl(RD); - RD->setHasFlexibleArrayMember(Record[Idx++]); - RD->setAnonymousStructOrUnion(Record[Idx++]); - RD->setHasObjectMember(Record[Idx++]); -} - -void PCHDeclReader::VisitValueDecl(ValueDecl *VD) { - VisitNamedDecl(VD); - VD->setType(Reader.GetType(Record[Idx++])); -} - -void PCHDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { - VisitValueDecl(ECD); - if (Record[Idx++]) - ECD->setInitExpr(Reader.ReadExpr()); - ECD->setInitVal(Reader.ReadAPSInt(Record, Idx)); -} - -void PCHDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) { - VisitValueDecl(DD); - TypeSourceInfo *TInfo = Reader.GetTypeSourceInfo(Record, Idx); - if (TInfo) - DD->setTypeSourceInfo(TInfo); - // FIXME: read optional qualifier and its range. -} - -void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { - VisitDeclaratorDecl(FD); - - FD->IdentifierNamespace = Record[Idx++]; - switch ((FunctionDecl::TemplatedKind)Record[Idx++]) { - default: assert(false && "Unhandled TemplatedKind!"); - break; - case FunctionDecl::TK_NonTemplate: - break; - case FunctionDecl::TK_FunctionTemplate: - FD->setDescribedFunctionTemplate( - cast(Reader.GetDecl(Record[Idx++]))); - break; - case FunctionDecl::TK_MemberSpecialization: { - FunctionDecl *InstFD = cast(Reader.GetDecl(Record[Idx++])); - TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++]; - SourceLocation POI = Reader.ReadSourceLocation(Record, Idx); - FD->setInstantiationOfMemberFunction(InstFD, TSK); - FD->getMemberSpecializationInfo()->setPointOfInstantiation(POI); - break; - } - case FunctionDecl::TK_FunctionTemplateSpecialization: { - FunctionTemplateDecl *Template - = cast(Reader.GetDecl(Record[Idx++])); - TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++]; - - // Template arguments. - llvm::SmallVector TemplArgs; - Reader.ReadTemplateArgumentList(TemplArgs, Record, Idx); - - // Template args as written. - llvm::SmallVector TemplArgLocs; - SourceLocation LAngleLoc, RAngleLoc; - if (Record[Idx++]) { // TemplateArgumentsAsWritten != 0 - unsigned NumTemplateArgLocs = Record[Idx++]; - TemplArgLocs.reserve(NumTemplateArgLocs); - for (unsigned i=0; i != NumTemplateArgLocs; ++i) - TemplArgLocs.push_back(Reader.ReadTemplateArgumentLoc(Record, Idx)); - - LAngleLoc = Reader.ReadSourceLocation(Record, Idx); - RAngleLoc = Reader.ReadSourceLocation(Record, Idx); - } - - SourceLocation POI = Reader.ReadSourceLocation(Record, Idx); - - FD->setFunctionTemplateSpecialization(Template, TemplArgs.size(), - TemplArgs.data(), TSK, - TemplArgLocs.size(), - TemplArgLocs.data(), - LAngleLoc, RAngleLoc, POI); - break; - } - case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { - // Templates. - UnresolvedSet<8> TemplDecls; - unsigned NumTemplates = Record[Idx++]; - while (NumTemplates--) - TemplDecls.addDecl(cast(Reader.GetDecl(Record[Idx++]))); - - // Templates args. - TemplateArgumentListInfo TemplArgs; - unsigned NumArgs = Record[Idx++]; - while (NumArgs--) - TemplArgs.addArgument(Reader.ReadTemplateArgumentLoc(Record, Idx)); - TemplArgs.setLAngleLoc(Reader.ReadSourceLocation(Record, Idx)); - TemplArgs.setRAngleLoc(Reader.ReadSourceLocation(Record, Idx)); - - FD->setDependentTemplateSpecialization(*Reader.getContext(), - TemplDecls, TemplArgs); - break; - } - } - - // FunctionDecl's body is handled last at PCHReaderDecl::Visit, - // after everything else is read. - - // Avoid side effects and invariant checking of FunctionDecl's - // setPreviousDeclaration. - FD->redeclarable_base::setPreviousDeclaration( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - FD->setStorageClass((FunctionDecl::StorageClass)Record[Idx++]); - FD->setStorageClassAsWritten((FunctionDecl::StorageClass)Record[Idx++]); - FD->setInlineSpecified(Record[Idx++]); - FD->setVirtualAsWritten(Record[Idx++]); - FD->setPure(Record[Idx++]); - FD->setHasInheritedPrototype(Record[Idx++]); - FD->setHasWrittenPrototype(Record[Idx++]); - FD->setDeleted(Record[Idx++]); - FD->setTrivial(Record[Idx++]); - FD->setCopyAssignment(Record[Idx++]); - FD->setHasImplicitReturnZero(Record[Idx++]); - FD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); - - // Read in the parameters. - unsigned NumParams = Record[Idx++]; - llvm::SmallVector Params; - Params.reserve(NumParams); - for (unsigned I = 0; I != NumParams; ++I) - Params.push_back(cast(Reader.GetDecl(Record[Idx++]))); - FD->setParams(Params.data(), NumParams); -} - -void PCHDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { - VisitNamedDecl(MD); - if (Record[Idx++]) { - // In practice, this won't be executed (since method definitions - // don't occur in header files). - MD->setBody(Reader.ReadStmt()); - MD->setSelfDecl(cast(Reader.GetDecl(Record[Idx++]))); - MD->setCmdDecl(cast(Reader.GetDecl(Record[Idx++]))); - } - MD->setInstanceMethod(Record[Idx++]); - MD->setVariadic(Record[Idx++]); - MD->setSynthesized(Record[Idx++]); - MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]); - MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]); - MD->setNumSelectorArgs(unsigned(Record[Idx++])); - MD->setResultType(Reader.GetType(Record[Idx++])); - MD->setResultTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); - MD->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - unsigned NumParams = Record[Idx++]; - llvm::SmallVector Params; - Params.reserve(NumParams); - for (unsigned I = 0; I != NumParams; ++I) - Params.push_back(cast(Reader.GetDecl(Record[Idx++]))); - MD->setMethodParams(*Reader.getContext(), Params.data(), NumParams, - NumParams); -} - -void PCHDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) { - VisitNamedDecl(CD); - SourceLocation A = SourceLocation::getFromRawEncoding(Record[Idx++]); - SourceLocation B = SourceLocation::getFromRawEncoding(Record[Idx++]); - CD->setAtEndRange(SourceRange(A, B)); -} - -void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) { - VisitObjCContainerDecl(ID); - ID->setTypeForDecl(Reader.GetType(Record[Idx++]).getTypePtr()); - ID->setSuperClass(cast_or_null - (Reader.GetDecl(Record[Idx++]))); - unsigned NumProtocols = Record[Idx++]; - llvm::SmallVector Protocols; - Protocols.reserve(NumProtocols); - for (unsigned I = 0; I != NumProtocols; ++I) - Protocols.push_back(cast(Reader.GetDecl(Record[Idx++]))); - llvm::SmallVector ProtoLocs; - ProtoLocs.reserve(NumProtocols); - for (unsigned I = 0; I != NumProtocols; ++I) - ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); - ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(), - *Reader.getContext()); - unsigned NumIvars = Record[Idx++]; - llvm::SmallVector IVars; - IVars.reserve(NumIvars); - for (unsigned I = 0; I != NumIvars; ++I) - IVars.push_back(cast(Reader.GetDecl(Record[Idx++]))); - ID->setCategoryList( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - ID->setForwardDecl(Record[Idx++]); - ID->setImplicitInterfaceDecl(Record[Idx++]); - ID->setClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - ID->setSuperClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - ID->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHDeclReader::VisitObjCIvarDecl(ObjCIvarDecl *IVD) { - VisitFieldDecl(IVD); - IVD->setAccessControl((ObjCIvarDecl::AccessControl)Record[Idx++]); -} - -void PCHDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) { - VisitObjCContainerDecl(PD); - PD->setForwardDecl(Record[Idx++]); - PD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); - unsigned NumProtoRefs = Record[Idx++]; - llvm::SmallVector ProtoRefs; - ProtoRefs.reserve(NumProtoRefs); - for (unsigned I = 0; I != NumProtoRefs; ++I) - ProtoRefs.push_back(cast(Reader.GetDecl(Record[Idx++]))); - llvm::SmallVector ProtoLocs; - ProtoLocs.reserve(NumProtoRefs); - for (unsigned I = 0; I != NumProtoRefs; ++I) - ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); - PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), - *Reader.getContext()); -} - -void PCHDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) { - VisitFieldDecl(FD); -} - -void PCHDeclReader::VisitObjCClassDecl(ObjCClassDecl *CD) { - VisitDecl(CD); - unsigned NumClassRefs = Record[Idx++]; - llvm::SmallVector ClassRefs; - ClassRefs.reserve(NumClassRefs); - for (unsigned I = 0; I != NumClassRefs; ++I) - ClassRefs.push_back(cast(Reader.GetDecl(Record[Idx++]))); - llvm::SmallVector SLocs; - SLocs.reserve(NumClassRefs); - for (unsigned I = 0; I != NumClassRefs; ++I) - SLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); - CD->setClassList(*Reader.getContext(), ClassRefs.data(), SLocs.data(), - NumClassRefs); -} - -void PCHDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) { - VisitDecl(FPD); - unsigned NumProtoRefs = Record[Idx++]; - llvm::SmallVector ProtoRefs; - ProtoRefs.reserve(NumProtoRefs); - for (unsigned I = 0; I != NumProtoRefs; ++I) - ProtoRefs.push_back(cast(Reader.GetDecl(Record[Idx++]))); - llvm::SmallVector ProtoLocs; - ProtoLocs.reserve(NumProtoRefs); - for (unsigned I = 0; I != NumProtoRefs; ++I) - ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); - FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), - *Reader.getContext()); -} - -void PCHDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) { - VisitObjCContainerDecl(CD); - CD->setClassInterface(cast(Reader.GetDecl(Record[Idx++]))); - unsigned NumProtoRefs = Record[Idx++]; - llvm::SmallVector ProtoRefs; - ProtoRefs.reserve(NumProtoRefs); - for (unsigned I = 0; I != NumProtoRefs; ++I) - ProtoRefs.push_back(cast(Reader.GetDecl(Record[Idx++]))); - llvm::SmallVector ProtoLocs; - ProtoLocs.reserve(NumProtoRefs); - for (unsigned I = 0; I != NumProtoRefs; ++I) - ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++])); - CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), - *Reader.getContext()); - CD->setNextClassCategory(cast_or_null(Reader.GetDecl(Record[Idx++]))); - CD->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - CD->setCategoryNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) { - VisitNamedDecl(CAD); - CAD->setClassInterface(cast(Reader.GetDecl(Record[Idx++]))); -} - -void PCHDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { - VisitNamedDecl(D); - D->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - D->setType(Reader.GetTypeSourceInfo(Record, Idx)); - // FIXME: stable encoding - D->setPropertyAttributes( - (ObjCPropertyDecl::PropertyAttributeKind)Record[Idx++]); - D->setPropertyAttributesAsWritten( - (ObjCPropertyDecl::PropertyAttributeKind)Record[Idx++]); - // FIXME: stable encoding - D->setPropertyImplementation( - (ObjCPropertyDecl::PropertyControl)Record[Idx++]); - D->setGetterName(Reader.ReadDeclarationName(Record, Idx).getObjCSelector()); - D->setSetterName(Reader.ReadDeclarationName(Record, Idx).getObjCSelector()); - D->setGetterMethodDecl( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - D->setSetterMethodDecl( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - D->setPropertyIvarDecl( - cast_or_null(Reader.GetDecl(Record[Idx++]))); -} - -void PCHDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) { - VisitObjCContainerDecl(D); - D->setClassInterface( - cast_or_null(Reader.GetDecl(Record[Idx++]))); -} - -void PCHDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { - VisitObjCImplDecl(D); - D->setIdentifier(Reader.GetIdentifierInfo(Record, Idx)); -} - -void PCHDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { - VisitObjCImplDecl(D); - D->setSuperClass( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - // FIXME. Add reading of IvarInitializers and NumIvarInitializers. -} - - -void PCHDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { - VisitDecl(D); - D->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - D->setPropertyDecl( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - D->setPropertyIvarDecl( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - // FIXME. read GetterCXXConstructor and SetterCXXAssignment -} - -void PCHDeclReader::VisitFieldDecl(FieldDecl *FD) { - VisitDeclaratorDecl(FD); - FD->setMutable(Record[Idx++]); - if (Record[Idx++]) - FD->setBitWidth(Reader.ReadExpr()); - if (!FD->getDeclName()) { - FieldDecl *Tmpl = cast_or_null(Reader.GetDecl(Record[Idx++])); - if (Tmpl) - Reader.getContext()->setInstantiatedFromUnnamedFieldDecl(FD, Tmpl); - } -} - -void PCHDeclReader::VisitVarDecl(VarDecl *VD) { - VisitDeclaratorDecl(VD); - VD->setStorageClass((VarDecl::StorageClass)Record[Idx++]); - VD->setStorageClassAsWritten((VarDecl::StorageClass)Record[Idx++]); - VD->setThreadSpecified(Record[Idx++]); - VD->setCXXDirectInitializer(Record[Idx++]); - VD->setDeclaredInCondition(Record[Idx++]); - VD->setExceptionVariable(Record[Idx++]); - VD->setNRVOVariable(Record[Idx++]); - VD->setPreviousDeclaration( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - if (Record[Idx++]) - VD->setInit(Reader.ReadExpr()); - - if (Record[Idx++]) { // HasMemberSpecializationInfo. - VarDecl *Tmpl = cast(Reader.GetDecl(Record[Idx++])); - TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++]; - SourceLocation POI = Reader.ReadSourceLocation(Record, Idx); - Reader.getContext()->setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI); - } -} - -void PCHDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) { - VisitVarDecl(PD); -} - -void PCHDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { - VisitVarDecl(PD); - PD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]); - PD->setHasInheritedDefaultArg(Record[Idx++]); - if (Record[Idx++]) // hasUninstantiatedDefaultArg. - PD->setUninstantiatedDefaultArg(Reader.ReadExpr()); -} - -void PCHDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) { - VisitDecl(AD); - AD->setAsmString(cast(Reader.ReadExpr())); -} - -void PCHDeclReader::VisitBlockDecl(BlockDecl *BD) { - VisitDecl(BD); - BD->setBody(cast_or_null(Reader.ReadStmt())); - BD->setSignatureAsWritten(Reader.GetTypeSourceInfo(Record, Idx)); - unsigned NumParams = Record[Idx++]; - llvm::SmallVector Params; - Params.reserve(NumParams); - for (unsigned I = 0; I != NumParams; ++I) - Params.push_back(cast(Reader.GetDecl(Record[Idx++]))); - BD->setParams(Params.data(), NumParams); -} - -void PCHDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) { - VisitDecl(D); - D->setLanguage((LinkageSpecDecl::LanguageIDs)Record[Idx++]); - D->setHasBraces(Record[Idx++]); -} - -void PCHDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { - VisitNamedDecl(D); - D->setLBracLoc(Reader.ReadSourceLocation(Record, Idx)); - D->setRBracLoc(Reader.ReadSourceLocation(Record, Idx)); - D->setNextNamespace( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - - bool IsOriginal = Record[Idx++]; - D->OrigOrAnonNamespace.setInt(IsOriginal); - D->OrigOrAnonNamespace.setPointer( - cast_or_null(Reader.GetDecl(Record[Idx++]))); -} - -void PCHDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { - VisitNamedDecl(D); - - D->setAliasLoc(Reader.ReadSourceLocation(Record, Idx)); - D->setQualifierRange(Reader.ReadSourceRange(Record, Idx)); - D->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx)); - D->setTargetNameLoc(Reader.ReadSourceLocation(Record, Idx)); - D->setAliasedNamespace(cast(Reader.GetDecl(Record[Idx++]))); -} - -void PCHDeclReader::VisitUsingDecl(UsingDecl *D) { - VisitNamedDecl(D); - D->setUsingLocation(Reader.ReadSourceLocation(Record, Idx)); - D->setNestedNameRange(Reader.ReadSourceRange(Record, Idx)); - D->setTargetNestedNameDecl(Reader.ReadNestedNameSpecifier(Record, Idx)); - - // FIXME: It would probably be more efficient to read these into a vector - // and then re-cosntruct the shadow decl set over that vector since it - // would avoid existence checks. - unsigned NumShadows = Record[Idx++]; - for(unsigned I = 0; I != NumShadows; ++I) { - // Avoid invariant checking of UsingDecl::addShadowDecl, the decl may still - // be initializing. - D->Shadows.insert(cast(Reader.GetDecl(Record[Idx++]))); - } - D->setTypeName(Record[Idx++]); - NamedDecl *Pattern = cast_or_null(Reader.GetDecl(Record[Idx++])); - if (Pattern) - Reader.getContext()->setInstantiatedFromUsingDecl(D, Pattern); -} - -void PCHDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) { - VisitNamedDecl(D); - D->setTargetDecl(cast(Reader.GetDecl(Record[Idx++]))); - D->setUsingDecl(cast(Reader.GetDecl(Record[Idx++]))); - UsingShadowDecl *Pattern - = cast_or_null(Reader.GetDecl(Record[Idx++])); - if (Pattern) - Reader.getContext()->setInstantiatedFromUsingShadowDecl(D, Pattern); -} - -void PCHDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { - VisitNamedDecl(D); - D->setNamespaceKeyLocation(Reader.ReadSourceLocation(Record, Idx)); - D->setQualifierRange(Reader.ReadSourceRange(Record, Idx)); - D->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx)); - D->setIdentLocation(Reader.ReadSourceLocation(Record, Idx)); - D->setNominatedNamespace(cast(Reader.GetDecl(Record[Idx++]))); - D->setCommonAncestor(cast_or_null( - Reader.GetDecl(Record[Idx++]))); -} - -void PCHDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { - VisitValueDecl(D); - D->setTargetNestedNameRange(Reader.ReadSourceRange(Record, Idx)); - D->setUsingLoc(Reader.ReadSourceLocation(Record, Idx)); - D->setTargetNestedNameSpecifier(Reader.ReadNestedNameSpecifier(Record, Idx)); -} - -void PCHDeclReader::VisitUnresolvedUsingTypenameDecl( - UnresolvedUsingTypenameDecl *D) { - VisitTypeDecl(D); - D->setTargetNestedNameRange(Reader.ReadSourceRange(Record, Idx)); - D->setUsingLoc(Reader.ReadSourceLocation(Record, Idx)); - D->setTypenameLoc(Reader.ReadSourceLocation(Record, Idx)); - D->setTargetNestedNameSpecifier(Reader.ReadNestedNameSpecifier(Record, Idx)); -} - -void PCHDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) { - ASTContext &C = *Reader.getContext(); - - // We need to allocate the DefinitionData struct ahead of VisitRecordDecl - // so that the other CXXRecordDecls can get a pointer even when the owner - // is still initializing. - bool OwnsDefinitionData = false; - enum DataOwnership { Data_NoDefData, Data_Owner, Data_NotOwner }; - switch ((DataOwnership)Record[Idx++]) { - default: - assert(0 && "Out of sync with PCHDeclWriter or messed up reading"); - case Data_NoDefData: - break; - case Data_Owner: - OwnsDefinitionData = true; - D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D); - break; - case Data_NotOwner: - D->DefinitionData - = cast(Reader.GetDecl(Record[Idx++]))->DefinitionData; - break; - } - - VisitRecordDecl(D); - - if (OwnsDefinitionData) { - assert(D->DefinitionData); - struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData; - - Data.UserDeclaredConstructor = Record[Idx++]; - Data.UserDeclaredCopyConstructor = Record[Idx++]; - Data.UserDeclaredCopyAssignment = Record[Idx++]; - Data.UserDeclaredDestructor = Record[Idx++]; - Data.Aggregate = Record[Idx++]; - Data.PlainOldData = Record[Idx++]; - Data.Empty = Record[Idx++]; - Data.Polymorphic = Record[Idx++]; - Data.Abstract = Record[Idx++]; - Data.HasTrivialConstructor = Record[Idx++]; - Data.HasTrivialCopyConstructor = Record[Idx++]; - Data.HasTrivialCopyAssignment = Record[Idx++]; - Data.HasTrivialDestructor = Record[Idx++]; - Data.ComputedVisibleConversions = Record[Idx++]; - Data.DeclaredDefaultConstructor = Record[Idx++]; - Data.DeclaredCopyConstructor = Record[Idx++]; - Data.DeclaredCopyAssignment = Record[Idx++]; - Data.DeclaredDestructor = Record[Idx++]; - - // setBases() is unsuitable since it may try to iterate the bases of an - // unitialized base. - Data.NumBases = Record[Idx++]; - Data.Bases = new(C) CXXBaseSpecifier [Data.NumBases]; - for (unsigned i = 0; i != Data.NumBases; ++i) - Data.Bases[i] = Reader.ReadCXXBaseSpecifier(Record, Idx); - - // FIXME: Make VBases lazily computed when needed to avoid storing them. - Data.NumVBases = Record[Idx++]; - Data.VBases = new(C) CXXBaseSpecifier [Data.NumVBases]; - for (unsigned i = 0; i != Data.NumVBases; ++i) - Data.VBases[i] = Reader.ReadCXXBaseSpecifier(Record, Idx); - - Reader.ReadUnresolvedSet(Data.Conversions, Record, Idx); - Reader.ReadUnresolvedSet(Data.VisibleConversions, Record, Idx); - assert(Data.Definition && "Data.Definition should be already set!"); - Data.FirstFriend - = cast_or_null(Reader.GetDecl(Record[Idx++])); - } - - enum CXXRecKind { - CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization - }; - switch ((CXXRecKind)Record[Idx++]) { - default: - assert(false && "Out of sync with PCHDeclWriter::VisitCXXRecordDecl?"); - case CXXRecNotTemplate: - break; - case CXXRecTemplate: - D->setDescribedClassTemplate( - cast(Reader.GetDecl(Record[Idx++]))); - break; - case CXXRecMemberSpecialization: { - CXXRecordDecl *RD = cast(Reader.GetDecl(Record[Idx++])); - TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++]; - SourceLocation POI = Reader.ReadSourceLocation(Record, Idx); - D->setInstantiationOfMemberClass(RD, TSK); - D->getMemberSpecializationInfo()->setPointOfInstantiation(POI); - break; - } - } -} - -void PCHDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) { - VisitFunctionDecl(D); - unsigned NumOverridenMethods = Record[Idx++]; - while (NumOverridenMethods--) { - CXXMethodDecl *MD = cast(Reader.GetDecl(Record[Idx++])); - // Avoid invariant checking of CXXMethodDecl::addOverriddenMethod, - // MD may be initializing. - Reader.getContext()->addOverriddenMethod(D, MD); - } -} - -void PCHDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) { - VisitCXXMethodDecl(D); - - D->IsExplicitSpecified = Record[Idx++]; - D->ImplicitlyDefined = Record[Idx++]; - - unsigned NumInitializers = Record[Idx++]; - D->NumBaseOrMemberInitializers = NumInitializers; - if (NumInitializers) { - ASTContext &C = *Reader.getContext(); - - D->BaseOrMemberInitializers - = new (C) CXXBaseOrMemberInitializer*[NumInitializers]; - for (unsigned i=0; i != NumInitializers; ++i) { - TypeSourceInfo *BaseClassInfo = 0; - bool IsBaseVirtual = false; - FieldDecl *Member = 0; - - bool IsBaseInitializer = Record[Idx++]; - if (IsBaseInitializer) { - BaseClassInfo = Reader.GetTypeSourceInfo(Record, Idx); - IsBaseVirtual = Record[Idx++]; - } else { - Member = cast(Reader.GetDecl(Record[Idx++])); - } - SourceLocation MemberLoc = Reader.ReadSourceLocation(Record, Idx); - Expr *Init = Reader.ReadExpr(); - FieldDecl *AnonUnionMember - = cast_or_null(Reader.GetDecl(Record[Idx++])); - SourceLocation LParenLoc = Reader.ReadSourceLocation(Record, Idx); - SourceLocation RParenLoc = Reader.ReadSourceLocation(Record, Idx); - bool IsWritten = Record[Idx++]; - unsigned SourceOrderOrNumArrayIndices; - llvm::SmallVector Indices; - if (IsWritten) { - SourceOrderOrNumArrayIndices = Record[Idx++]; - } else { - SourceOrderOrNumArrayIndices = Record[Idx++]; - Indices.reserve(SourceOrderOrNumArrayIndices); - for (unsigned i=0; i != SourceOrderOrNumArrayIndices; ++i) - Indices.push_back(cast(Reader.GetDecl(Record[Idx++]))); - } - - CXXBaseOrMemberInitializer *BOMInit; - if (IsBaseInitializer) { - BOMInit = new (C) CXXBaseOrMemberInitializer(C, BaseClassInfo, - IsBaseVirtual, LParenLoc, - Init, RParenLoc); - } else if (IsWritten) { - BOMInit = new (C) CXXBaseOrMemberInitializer(C, Member, MemberLoc, - LParenLoc, Init, RParenLoc); - } else { - BOMInit = CXXBaseOrMemberInitializer::Create(C, Member, MemberLoc, - LParenLoc, Init, RParenLoc, - Indices.data(), - Indices.size()); - } - - BOMInit->setAnonUnionMember(AnonUnionMember); - D->BaseOrMemberInitializers[i] = BOMInit; - } - } -} - -void PCHDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) { - VisitCXXMethodDecl(D); - - D->ImplicitlyDefined = Record[Idx++]; - D->OperatorDelete = cast_or_null(Reader.GetDecl(Record[Idx++])); -} - -void PCHDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) { - VisitCXXMethodDecl(D); - D->IsExplicitSpecified = Record[Idx++]; -} - -void PCHDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) { - VisitDecl(D); - D->setColonLoc(Reader.ReadSourceLocation(Record, Idx)); -} - -void PCHDeclReader::VisitFriendDecl(FriendDecl *D) { - VisitDecl(D); - if (Record[Idx++]) - D->Friend = Reader.GetTypeSourceInfo(Record, Idx); - else - D->Friend = cast(Reader.GetDecl(Record[Idx++])); - D->NextFriend = cast_or_null(Reader.GetDecl(Record[Idx++])); - D->FriendLoc = Reader.ReadSourceLocation(Record, Idx); -} - -void PCHDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) { - assert(false && "cannot read FriendTemplateDecl"); -} - -void PCHDeclReader::VisitTemplateDecl(TemplateDecl *D) { - VisitNamedDecl(D); - - NamedDecl *TemplatedDecl - = cast_or_null(Reader.GetDecl(Record[Idx++])); - TemplateParameterList* TemplateParams - = Reader.ReadTemplateParameterList(Record, Idx); - D->init(TemplatedDecl, TemplateParams); -} - -void PCHDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { - VisitTemplateDecl(D); - - D->IdentifierNamespace = Record[Idx++]; - ClassTemplateDecl *PrevDecl = - cast_or_null(Reader.GetDecl(Record[Idx++])); - D->setPreviousDeclaration(PrevDecl); - if (PrevDecl == 0) { - // This ClassTemplateDecl owns a CommonPtr; read it. - - // FoldingSets are filled in VisitClassTemplateSpecializationDecl. - unsigned size = Record[Idx++]; - while (size--) - cast(Reader.GetDecl(Record[Idx++])); - - size = Record[Idx++]; - while (size--) - cast( - Reader.GetDecl(Record[Idx++])); - - // InjectedClassNameType is computed. - - if (ClassTemplateDecl *CTD - = cast_or_null(Reader.GetDecl(Record[Idx++]))) { - D->setInstantiatedFromMemberTemplate(CTD); - if (Record[Idx++]) - D->setMemberSpecialization(); - } - } -} - -void PCHDeclReader::VisitClassTemplateSpecializationDecl( - ClassTemplateSpecializationDecl *D) { - VisitCXXRecordDecl(D); - - if (Decl *InstD = Reader.GetDecl(Record[Idx++])) { - if (ClassTemplateDecl *CTD = dyn_cast(InstD)) { - D->setInstantiationOf(CTD); - } else { - llvm::SmallVector TemplArgs; - Reader.ReadTemplateArgumentList(TemplArgs, Record, Idx); - D->setInstantiationOf(cast(InstD), - TemplArgs.data(), TemplArgs.size()); - } - } - - // Explicit info. - if (TypeSourceInfo *TyInfo = Reader.GetTypeSourceInfo(Record, Idx)) { - D->setTypeAsWritten(TyInfo); - D->setExternLoc(Reader.ReadSourceLocation(Record, Idx)); - D->setTemplateKeywordLoc(Reader.ReadSourceLocation(Record, Idx)); - } - - llvm::SmallVector TemplArgs; - Reader.ReadTemplateArgumentList(TemplArgs, Record, Idx); - D->initTemplateArgs(TemplArgs.data(), TemplArgs.size()); - SourceLocation POI = Reader.ReadSourceLocation(Record, Idx); - if (POI.isValid()) - D->setPointOfInstantiation(POI); - D->setSpecializationKind((TemplateSpecializationKind)Record[Idx++]); - - if (Record[Idx++]) { // IsKeptInFoldingSet. - ClassTemplateDecl *CanonPattern - = cast(Reader.GetDecl(Record[Idx++])); - if (ClassTemplatePartialSpecializationDecl *Partial - = dyn_cast(D)) { - CanonPattern->getPartialSpecializations().InsertNode(Partial); - } else { - CanonPattern->getSpecializations().InsertNode(D); - } - } -} - -void PCHDeclReader::VisitClassTemplatePartialSpecializationDecl( - ClassTemplatePartialSpecializationDecl *D) { - VisitClassTemplateSpecializationDecl(D); - - D->initTemplateParameters(Reader.ReadTemplateParameterList(Record, Idx)); - - TemplateArgumentListInfo ArgInfos; - unsigned NumArgs = Record[Idx++]; - while (NumArgs--) - ArgInfos.addArgument(Reader.ReadTemplateArgumentLoc(Record, Idx)); - D->initTemplateArgsAsWritten(ArgInfos); - - D->setSequenceNumber(Record[Idx++]); - - // These are read/set from/to the first declaration. - if (D->getPreviousDeclaration() == 0) { - D->setInstantiatedFromMember( - cast_or_null( - Reader.GetDecl(Record[Idx++]))); - if (Record[Idx++]) - D->setMemberSpecialization(); - } -} - -void PCHDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { - VisitTemplateDecl(D); - - D->IdentifierNamespace = Record[Idx++]; - FunctionTemplateDecl *PrevDecl = - cast_or_null(Reader.GetDecl(Record[Idx++])); - D->setPreviousDeclaration(PrevDecl); - if (PrevDecl == 0) { - // This FunctionTemplateDecl owns a CommonPtr; read it. - - // Read the function specialization declarations. - // FunctionTemplateDecl's FunctionTemplateSpecializationInfos are filled - // through the specialized FunctionDecl's setFunctionTemplateSpecialization. - unsigned NumSpecs = Record[Idx++]; - while (NumSpecs--) - Reader.GetDecl(Record[Idx++]); - - if (FunctionTemplateDecl *CTD - = cast_or_null(Reader.GetDecl(Record[Idx++]))) { - D->setInstantiatedFromMemberTemplate(CTD); - if (Record[Idx++]) - D->setMemberSpecialization(); - } - } -} - -void PCHDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { - VisitTypeDecl(D); - - D->setDeclaredWithTypename(Record[Idx++]); - D->setParameterPack(Record[Idx++]); - - bool Inherited = Record[Idx++]; - TypeSourceInfo *DefArg = Reader.GetTypeSourceInfo(Record, Idx); - D->setDefaultArgument(DefArg, Inherited); -} - -void PCHDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { - VisitVarDecl(D); - // TemplateParmPosition. - D->setDepth(Record[Idx++]); - D->setPosition(Record[Idx++]); - // Rest of NonTypeTemplateParmDecl. - if (Record[Idx++]) { - Expr *DefArg = Reader.ReadExpr(); - bool Inherited = Record[Idx++]; - D->setDefaultArgument(DefArg, Inherited); - } -} - -void PCHDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { - VisitTemplateDecl(D); - // TemplateParmPosition. - D->setDepth(Record[Idx++]); - D->setPosition(Record[Idx++]); - // Rest of TemplateTemplateParmDecl. - TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(Record, Idx); - bool IsInherited = Record[Idx++]; - D->setDefaultArgument(Arg, IsInherited); -} - -void PCHDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) { - assert(false && "cannot read StaticAssertDecl"); -} - -std::pair -PCHDeclReader::VisitDeclContext(DeclContext *DC) { - uint64_t LexicalOffset = Record[Idx++]; - uint64_t VisibleOffset = Record[Idx++]; - return std::make_pair(LexicalOffset, VisibleOffset); -} - -//===----------------------------------------------------------------------===// -// Attribute Reading -//===----------------------------------------------------------------------===// - -/// \brief Reads attributes from the current stream position. -Attr *PCHReader::ReadAttributes() { - unsigned Code = DeclsCursor.ReadCode(); - assert(Code == llvm::bitc::UNABBREV_RECORD && - "Expected unabbreviated record"); (void)Code; - - RecordData Record; - unsigned Idx = 0; - unsigned RecCode = DeclsCursor.ReadRecord(Code, Record); - assert(RecCode == pch::DECL_ATTR && "Expected attribute record"); - (void)RecCode; - -#define SIMPLE_ATTR(Name) \ - case attr::Name: \ - New = ::new (*Context) Name##Attr(); \ - break - -#define STRING_ATTR(Name) \ - case attr::Name: \ - New = ::new (*Context) Name##Attr(*Context, ReadString(Record, Idx)); \ - break - -#define UNSIGNED_ATTR(Name) \ - case attr::Name: \ - New = ::new (*Context) Name##Attr(Record[Idx++]); \ - break - - Attr *Attrs = 0; - while (Idx < Record.size()) { - Attr *New = 0; - attr::Kind Kind = (attr::Kind)Record[Idx++]; - bool IsInherited = Record[Idx++]; - - switch (Kind) { - default: - assert(0 && "Unknown attribute!"); - break; - STRING_ATTR(Alias); - SIMPLE_ATTR(AlignMac68k); - UNSIGNED_ATTR(Aligned); - SIMPLE_ATTR(AlwaysInline); - SIMPLE_ATTR(AnalyzerNoReturn); - STRING_ATTR(Annotate); - STRING_ATTR(AsmLabel); - SIMPLE_ATTR(BaseCheck); - - case attr::Blocks: - New = ::new (*Context) BlocksAttr( - (BlocksAttr::BlocksAttrTypes)Record[Idx++]); - break; - - SIMPLE_ATTR(CDecl); - - case attr::Cleanup: - New = ::new (*Context) CleanupAttr( - cast(GetDecl(Record[Idx++]))); - break; - - SIMPLE_ATTR(Const); - UNSIGNED_ATTR(Constructor); - SIMPLE_ATTR(DLLExport); - SIMPLE_ATTR(DLLImport); - SIMPLE_ATTR(Deprecated); - UNSIGNED_ATTR(Destructor); - SIMPLE_ATTR(FastCall); - SIMPLE_ATTR(Final); - - case attr::Format: { - std::string Type = ReadString(Record, Idx); - unsigned FormatIdx = Record[Idx++]; - unsigned FirstArg = Record[Idx++]; - New = ::new (*Context) FormatAttr(*Context, Type, FormatIdx, FirstArg); - break; - } - - case attr::FormatArg: { - unsigned FormatIdx = Record[Idx++]; - New = ::new (*Context) FormatArgAttr(FormatIdx); - break; - } - - case attr::Sentinel: { - int sentinel = Record[Idx++]; - int nullPos = Record[Idx++]; - New = ::new (*Context) SentinelAttr(sentinel, nullPos); - break; - } - - SIMPLE_ATTR(GNUInline); - SIMPLE_ATTR(Hiding); - - case attr::IBAction: - New = ::new (*Context) IBActionAttr(); - break; - - case attr::IBOutlet: - New = ::new (*Context) IBOutletAttr(); - break; - - case attr::IBOutletCollection: { - ObjCInterfaceDecl *D = - cast_or_null(GetDecl(Record[Idx++])); - New = ::new (*Context) IBOutletCollectionAttr(D); - break; - } - - SIMPLE_ATTR(Malloc); - SIMPLE_ATTR(NoDebug); - SIMPLE_ATTR(NoInline); - SIMPLE_ATTR(NoReturn); - SIMPLE_ATTR(NoThrow); - - case attr::NonNull: { - unsigned Size = Record[Idx++]; - llvm::SmallVector ArgNums; - ArgNums.insert(ArgNums.end(), &Record[Idx], &Record[Idx] + Size); - Idx += Size; - New = ::new (*Context) NonNullAttr(*Context, ArgNums.data(), Size); - break; - } - - case attr::ReqdWorkGroupSize: { - unsigned X = Record[Idx++]; - unsigned Y = Record[Idx++]; - unsigned Z = Record[Idx++]; - New = ::new (*Context) ReqdWorkGroupSizeAttr(X, Y, Z); - break; - } - - SIMPLE_ATTR(ObjCException); - SIMPLE_ATTR(ObjCNSObject); - SIMPLE_ATTR(CFReturnsNotRetained); - SIMPLE_ATTR(CFReturnsRetained); - SIMPLE_ATTR(NSReturnsNotRetained); - SIMPLE_ATTR(NSReturnsRetained); - SIMPLE_ATTR(Overloadable); - SIMPLE_ATTR(Override); - SIMPLE_ATTR(Packed); - UNSIGNED_ATTR(MaxFieldAlignment); - SIMPLE_ATTR(Pure); - UNSIGNED_ATTR(Regparm); - STRING_ATTR(Section); - SIMPLE_ATTR(StdCall); - SIMPLE_ATTR(ThisCall); - SIMPLE_ATTR(TransparentUnion); - SIMPLE_ATTR(Unavailable); - SIMPLE_ATTR(Unused); - SIMPLE_ATTR(Used); - - case attr::Visibility: - New = ::new (*Context) VisibilityAttr( - (VisibilityAttr::VisibilityTypes)Record[Idx++]); - break; - - SIMPLE_ATTR(WarnUnusedResult); - SIMPLE_ATTR(Weak); - SIMPLE_ATTR(WeakRef); - SIMPLE_ATTR(WeakImport); - } - - assert(New && "Unable to decode attribute?"); - New->setInherited(IsInherited); - New->setNext(Attrs); - Attrs = New; - } -#undef UNSIGNED_ATTR -#undef STRING_ATTR -#undef SIMPLE_ATTR - - // The list of attributes was built backwards. Reverse the list - // before returning it. - Attr *PrevAttr = 0, *NextAttr = 0; - while (Attrs) { - NextAttr = Attrs->getNext(); - Attrs->setNext(PrevAttr); - PrevAttr = Attrs; - Attrs = NextAttr; - } - - return PrevAttr; -} - -//===----------------------------------------------------------------------===// -// PCHReader Implementation -//===----------------------------------------------------------------------===// - -/// \brief Note that we have loaded the declaration with the given -/// Index. -/// -/// This routine notes that this declaration has already been loaded, -/// so that future GetDecl calls will return this declaration rather -/// than trying to load a new declaration. -inline void PCHReader::LoadedDecl(unsigned Index, Decl *D) { - assert(!DeclsLoaded[Index] && "Decl loaded twice?"); - DeclsLoaded[Index] = D; -} - - -/// \brief Determine whether the consumer will be interested in seeing -/// this declaration (via HandleTopLevelDecl). -/// -/// This routine should return true for anything that might affect -/// code generation, e.g., inline function definitions, Objective-C -/// declarations with metadata, etc. -static bool isConsumerInterestedIn(Decl *D) { - if (isa(D)) - return true; - if (VarDecl *Var = dyn_cast(D)) - return Var->isFileVarDecl() && Var->getInit(); - if (FunctionDecl *Func = dyn_cast(D)) - return Func->isThisDeclarationADefinition(); - return isa(D); -} - -/// \brief Read the declaration at the given offset from the PCH file. -Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { - // Keep track of where we are in the stream, then jump back there - // after reading this declaration. - SavedStreamPosition SavedPosition(DeclsCursor); - - ReadingKindTracker ReadingKind(Read_Decl, *this); - - // Note that we are loading a declaration record. - LoadingTypeOrDecl Loading(*this); - - DeclsCursor.JumpToBit(Offset); - RecordData Record; - unsigned Code = DeclsCursor.ReadCode(); - unsigned Idx = 0; - PCHDeclReader Reader(*this, Record, Idx); - - Decl *D = 0; - switch ((pch::DeclCode)DeclsCursor.ReadRecord(Code, Record)) { - case pch::DECL_ATTR: - case pch::DECL_CONTEXT_LEXICAL: - case pch::DECL_CONTEXT_VISIBLE: - assert(false && "Record cannot be de-serialized with ReadDeclRecord"); - break; - case pch::DECL_TRANSLATION_UNIT: - assert(Index == 0 && "Translation unit must be at index 0"); - D = Context->getTranslationUnitDecl(); - break; - case pch::DECL_TYPEDEF: - D = TypedefDecl::Create(*Context, 0, SourceLocation(), 0, 0); - break; - case pch::DECL_ENUM: - D = EnumDecl::Create(*Context, Decl::EmptyShell()); - break; - case pch::DECL_RECORD: - D = RecordDecl::Create(*Context, Decl::EmptyShell()); - break; - case pch::DECL_ENUM_CONSTANT: - D = EnumConstantDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), - 0, llvm::APSInt()); - break; - case pch::DECL_FUNCTION: - D = FunctionDecl::Create(*Context, 0, SourceLocation(), DeclarationName(), - QualType(), 0); - break; - case pch::DECL_LINKAGE_SPEC: - D = LinkageSpecDecl::Create(*Context, 0, SourceLocation(), - (LinkageSpecDecl::LanguageIDs)0, - false); - break; - case pch::DECL_NAMESPACE: - D = NamespaceDecl::Create(*Context, 0, SourceLocation(), 0); - break; - case pch::DECL_NAMESPACE_ALIAS: - D = NamespaceAliasDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), 0, SourceRange(), 0, - SourceLocation(), 0); - break; - case pch::DECL_USING: - D = UsingDecl::Create(*Context, 0, SourceLocation(), SourceRange(), - SourceLocation(), 0, DeclarationName(), false); - break; - case pch::DECL_USING_SHADOW: - D = UsingShadowDecl::Create(*Context, 0, SourceLocation(), 0, 0); - break; - case pch::DECL_USING_DIRECTIVE: - D = UsingDirectiveDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), SourceRange(), 0, - SourceLocation(), 0, 0); - break; - case pch::DECL_UNRESOLVED_USING_VALUE: - D = UnresolvedUsingValueDecl::Create(*Context, 0, SourceLocation(), - SourceRange(), 0, SourceLocation(), - DeclarationName()); - break; - case pch::DECL_UNRESOLVED_USING_TYPENAME: - D = UnresolvedUsingTypenameDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), SourceRange(), - 0, SourceLocation(), - DeclarationName()); - break; - case pch::DECL_CXX_RECORD: - D = CXXRecordDecl::Create(*Context, Decl::EmptyShell()); - break; - case pch::DECL_CXX_METHOD: - D = CXXMethodDecl::Create(*Context, 0, SourceLocation(), DeclarationName(), - QualType(), 0); - break; - case pch::DECL_CXX_CONSTRUCTOR: - D = CXXConstructorDecl::Create(*Context, Decl::EmptyShell()); - break; - case pch::DECL_CXX_DESTRUCTOR: - D = CXXDestructorDecl::Create(*Context, Decl::EmptyShell()); - break; - case pch::DECL_CXX_CONVERSION: - D = CXXConversionDecl::Create(*Context, Decl::EmptyShell()); - break; - case pch::DECL_ACCESS_SPEC: - D = AccessSpecDecl::Create(*Context, AS_none, 0, SourceLocation(), - SourceLocation()); - break; - case pch::DECL_FRIEND: - D = FriendDecl::Create(*Context, Decl::EmptyShell()); - break; - case pch::DECL_FRIEND_TEMPLATE: - assert(false && "cannot read FriendTemplateDecl"); - break; - case pch::DECL_CLASS_TEMPLATE: - D = ClassTemplateDecl::Create(*Context, 0, SourceLocation(), - DeclarationName(), 0, 0, 0); - break; - case pch::DECL_CLASS_TEMPLATE_SPECIALIZATION: - D = ClassTemplateSpecializationDecl::Create(*Context, Decl::EmptyShell()); - break; - case pch::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION: - D = ClassTemplatePartialSpecializationDecl::Create(*Context, - Decl::EmptyShell()); - break; - case pch::DECL_FUNCTION_TEMPLATE: - D = FunctionTemplateDecl::Create(*Context, 0, SourceLocation(), - DeclarationName(), 0, 0); - break; - case pch::DECL_TEMPLATE_TYPE_PARM: - D = TemplateTypeParmDecl::Create(*Context, Decl::EmptyShell()); - break; - case pch::DECL_NON_TYPE_TEMPLATE_PARM: - D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0,0,0, - QualType(),0); - break; - case pch::DECL_TEMPLATE_TEMPLATE_PARM: - D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(),0,0,0,0); - break; - case pch::DECL_STATIC_ASSERT: - assert(false && "cannot read StaticAssertDecl"); - break; - - case pch::DECL_OBJC_METHOD: - D = ObjCMethodDecl::Create(*Context, SourceLocation(), SourceLocation(), - Selector(), QualType(), 0, 0); - break; - case pch::DECL_OBJC_INTERFACE: - D = ObjCInterfaceDecl::Create(*Context, 0, SourceLocation(), 0); - break; - case pch::DECL_OBJC_IVAR: - D = ObjCIvarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, - ObjCIvarDecl::None); - break; - case pch::DECL_OBJC_PROTOCOL: - D = ObjCProtocolDecl::Create(*Context, 0, SourceLocation(), 0); - break; - case pch::DECL_OBJC_AT_DEFS_FIELD: - D = ObjCAtDefsFieldDecl::Create(*Context, 0, SourceLocation(), 0, - QualType(), 0); - break; - case pch::DECL_OBJC_CLASS: - D = ObjCClassDecl::Create(*Context, 0, SourceLocation()); - break; - case pch::DECL_OBJC_FORWARD_PROTOCOL: - D = ObjCForwardProtocolDecl::Create(*Context, 0, SourceLocation()); - break; - case pch::DECL_OBJC_CATEGORY: - D = ObjCCategoryDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), SourceLocation(), 0); - break; - case pch::DECL_OBJC_CATEGORY_IMPL: - D = ObjCCategoryImplDecl::Create(*Context, 0, SourceLocation(), 0, 0); - break; - case pch::DECL_OBJC_IMPLEMENTATION: - D = ObjCImplementationDecl::Create(*Context, 0, SourceLocation(), 0, 0); - break; - case pch::DECL_OBJC_COMPATIBLE_ALIAS: - D = ObjCCompatibleAliasDecl::Create(*Context, 0, SourceLocation(), 0, 0); - break; - case pch::DECL_OBJC_PROPERTY: - D = ObjCPropertyDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(), - 0); - break; - case pch::DECL_OBJC_PROPERTY_IMPL: - D = ObjCPropertyImplDecl::Create(*Context, 0, SourceLocation(), - SourceLocation(), 0, - ObjCPropertyImplDecl::Dynamic, 0); - break; - case pch::DECL_FIELD: - D = FieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, 0, - false); - break; - case pch::DECL_VAR: - D = VarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, - VarDecl::None, VarDecl::None); - break; - - case pch::DECL_IMPLICIT_PARAM: - D = ImplicitParamDecl::Create(*Context, 0, SourceLocation(), 0, QualType()); - break; - - case pch::DECL_PARM_VAR: - D = ParmVarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, - VarDecl::None, VarDecl::None, 0); - break; - case pch::DECL_FILE_SCOPE_ASM: - D = FileScopeAsmDecl::Create(*Context, 0, SourceLocation(), 0); - break; - case pch::DECL_BLOCK: - D = BlockDecl::Create(*Context, 0, SourceLocation()); - break; - } - - assert(D && "Unknown declaration reading PCH file"); - LoadedDecl(Index, D); - Reader.Visit(D); - - // If this declaration is also a declaration context, get the - // offsets for its tables of lexical and visible declarations. - if (DeclContext *DC = dyn_cast(D)) { - std::pair Offsets = Reader.VisitDeclContext(DC); - if (Offsets.first || Offsets.second) { - DC->setHasExternalLexicalStorage(Offsets.first != 0); - DC->setHasExternalVisibleStorage(Offsets.second != 0); - DeclContextOffsets[DC] = Offsets; - } - } - assert(Idx == Record.size()); - - // If we have deserialized a declaration that has a definition the - // AST consumer might need to know about, queue it. - // We don't pass it to the consumer immediately because we may be in recursive - // loading, and some declarations may still be initializing. - if (isConsumerInterestedIn(D)) - InterestingDecls.push_back(D); - - return D; -} diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp deleted file mode 100644 index ace62d7..0000000 --- a/lib/Frontend/PCHReaderStmt.cpp +++ /dev/null @@ -1,1727 +0,0 @@ -//===--- PCHReaderStmt.cpp - Stmt/Expr Deserialization ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Statement/expression deserialization. This implements the -// PCHReader::ReadStmt method. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/PCHReader.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/StmtVisitor.h" -using namespace clang; - -namespace clang { - - class PCHStmtReader : public StmtVisitor { - PCHReader &Reader; - const PCHReader::RecordData &Record; - unsigned &Idx; - - public: - PCHStmtReader(PCHReader &Reader, const PCHReader::RecordData &Record, - unsigned &Idx) - : Reader(Reader), Record(Record), Idx(Idx) { } - - /// \brief The number of record fields required for the Stmt class - /// itself. - static const unsigned NumStmtFields = 0; - - /// \brief The number of record fields required for the Expr class - /// itself. - static const unsigned NumExprFields = NumStmtFields + 3; - - /// \brief Read and initialize a ExplicitTemplateArgumentList structure. - void ReadExplicitTemplateArgumentList(ExplicitTemplateArgumentList &ArgList, - unsigned NumTemplateArgs); - - void VisitStmt(Stmt *S); - void VisitNullStmt(NullStmt *S); - void VisitCompoundStmt(CompoundStmt *S); - void VisitSwitchCase(SwitchCase *S); - void VisitCaseStmt(CaseStmt *S); - void VisitDefaultStmt(DefaultStmt *S); - void VisitLabelStmt(LabelStmt *S); - void VisitIfStmt(IfStmt *S); - void VisitSwitchStmt(SwitchStmt *S); - void VisitWhileStmt(WhileStmt *S); - void VisitDoStmt(DoStmt *S); - void VisitForStmt(ForStmt *S); - void VisitGotoStmt(GotoStmt *S); - void VisitIndirectGotoStmt(IndirectGotoStmt *S); - void VisitContinueStmt(ContinueStmt *S); - void VisitBreakStmt(BreakStmt *S); - void VisitReturnStmt(ReturnStmt *S); - void VisitDeclStmt(DeclStmt *S); - void VisitAsmStmt(AsmStmt *S); - void VisitExpr(Expr *E); - void VisitPredefinedExpr(PredefinedExpr *E); - void VisitDeclRefExpr(DeclRefExpr *E); - void VisitIntegerLiteral(IntegerLiteral *E); - void VisitFloatingLiteral(FloatingLiteral *E); - void VisitImaginaryLiteral(ImaginaryLiteral *E); - void VisitStringLiteral(StringLiteral *E); - void VisitCharacterLiteral(CharacterLiteral *E); - void VisitParenExpr(ParenExpr *E); - void VisitParenListExpr(ParenListExpr *E); - void VisitUnaryOperator(UnaryOperator *E); - void VisitOffsetOfExpr(OffsetOfExpr *E); - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); - void VisitArraySubscriptExpr(ArraySubscriptExpr *E); - void VisitCallExpr(CallExpr *E); - void VisitMemberExpr(MemberExpr *E); - void VisitCastExpr(CastExpr *E); - void VisitBinaryOperator(BinaryOperator *E); - void VisitCompoundAssignOperator(CompoundAssignOperator *E); - void VisitConditionalOperator(ConditionalOperator *E); - void VisitImplicitCastExpr(ImplicitCastExpr *E); - void VisitExplicitCastExpr(ExplicitCastExpr *E); - void VisitCStyleCastExpr(CStyleCastExpr *E); - void VisitCompoundLiteralExpr(CompoundLiteralExpr *E); - void VisitExtVectorElementExpr(ExtVectorElementExpr *E); - void VisitInitListExpr(InitListExpr *E); - void VisitDesignatedInitExpr(DesignatedInitExpr *E); - void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E); - void VisitVAArgExpr(VAArgExpr *E); - void VisitAddrLabelExpr(AddrLabelExpr *E); - void VisitStmtExpr(StmtExpr *E); - void VisitTypesCompatibleExpr(TypesCompatibleExpr *E); - void VisitChooseExpr(ChooseExpr *E); - void VisitGNUNullExpr(GNUNullExpr *E); - void VisitShuffleVectorExpr(ShuffleVectorExpr *E); - void VisitBlockExpr(BlockExpr *E); - void VisitBlockDeclRefExpr(BlockDeclRefExpr *E); - void VisitObjCStringLiteral(ObjCStringLiteral *E); - void VisitObjCEncodeExpr(ObjCEncodeExpr *E); - void VisitObjCSelectorExpr(ObjCSelectorExpr *E); - void VisitObjCProtocolExpr(ObjCProtocolExpr *E); - void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E); - void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E); - void VisitObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *E); - void VisitObjCMessageExpr(ObjCMessageExpr *E); - void VisitObjCSuperExpr(ObjCSuperExpr *E); - void VisitObjCIsaExpr(ObjCIsaExpr *E); - - void VisitObjCForCollectionStmt(ObjCForCollectionStmt *); - void VisitObjCAtCatchStmt(ObjCAtCatchStmt *); - void VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *); - void VisitObjCAtTryStmt(ObjCAtTryStmt *); - void VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *); - void VisitObjCAtThrowStmt(ObjCAtThrowStmt *); - - void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); - void VisitCXXConstructExpr(CXXConstructExpr *E); - void VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E); - void VisitCXXNamedCastExpr(CXXNamedCastExpr *E); - void VisitCXXStaticCastExpr(CXXStaticCastExpr *E); - void VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E); - void VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E); - void VisitCXXConstCastExpr(CXXConstCastExpr *E); - void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E); - void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); - void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); - void VisitCXXTypeidExpr(CXXTypeidExpr *E); - void VisitCXXThisExpr(CXXThisExpr *E); - void VisitCXXThrowExpr(CXXThrowExpr *E); - void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E); - void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); - void VisitCXXBindReferenceExpr(CXXBindReferenceExpr *E); - - void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E); - void VisitCXXNewExpr(CXXNewExpr *E); - void VisitCXXDeleteExpr(CXXDeleteExpr *E); - void VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E); - - void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E); - - void VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E); - void VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E); - void VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E); - - void VisitOverloadExpr(OverloadExpr *E); - void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E); - void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E); - - void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E); - }; -} - -void PCHStmtReader:: -ReadExplicitTemplateArgumentList(ExplicitTemplateArgumentList &ArgList, - unsigned NumTemplateArgs) { - TemplateArgumentListInfo ArgInfo; - ArgInfo.setLAngleLoc(Reader.ReadSourceLocation(Record, Idx)); - ArgInfo.setRAngleLoc(Reader.ReadSourceLocation(Record, Idx)); - for (unsigned i = 0; i != NumTemplateArgs; ++i) - ArgInfo.addArgument(Reader.ReadTemplateArgumentLoc(Record, Idx)); - ArgList.initializeFrom(ArgInfo); -} - -void PCHStmtReader::VisitStmt(Stmt *S) { - assert(Idx == NumStmtFields && "Incorrect statement field count"); -} - -void PCHStmtReader::VisitNullStmt(NullStmt *S) { - VisitStmt(S); - S->setSemiLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitCompoundStmt(CompoundStmt *S) { - VisitStmt(S); - llvm::SmallVector Stmts; - unsigned NumStmts = Record[Idx++]; - while (NumStmts--) - Stmts.push_back(Reader.ReadSubStmt()); - S->setStmts(*Reader.getContext(), Stmts.data(), Stmts.size()); - S->setLBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setRBracLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitSwitchCase(SwitchCase *S) { - VisitStmt(S); - Reader.RecordSwitchCaseID(S, Record[Idx++]); -} - -void PCHStmtReader::VisitCaseStmt(CaseStmt *S) { - VisitSwitchCase(S); - S->setLHS(Reader.ReadSubExpr()); - S->setRHS(Reader.ReadSubExpr()); - S->setSubStmt(Reader.ReadSubStmt()); - S->setCaseLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setEllipsisLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitDefaultStmt(DefaultStmt *S) { - VisitSwitchCase(S); - S->setSubStmt(Reader.ReadSubStmt()); - S->setDefaultLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitLabelStmt(LabelStmt *S) { - VisitStmt(S); - S->setID(Reader.GetIdentifierInfo(Record, Idx)); - S->setSubStmt(Reader.ReadSubStmt()); - S->setIdentLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - Reader.RecordLabelStmt(S, Record[Idx++]); -} - -void PCHStmtReader::VisitIfStmt(IfStmt *S) { - VisitStmt(S); - S->setConditionVariable(*Reader.getContext(), - cast_or_null(Reader.GetDecl(Record[Idx++]))); - S->setCond(Reader.ReadSubExpr()); - S->setThen(Reader.ReadSubStmt()); - S->setElse(Reader.ReadSubStmt()); - S->setIfLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setElseLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitSwitchStmt(SwitchStmt *S) { - VisitStmt(S); - S->setConditionVariable(*Reader.getContext(), - cast_or_null(Reader.GetDecl(Record[Idx++]))); - S->setCond(Reader.ReadSubExpr()); - S->setBody(Reader.ReadSubStmt()); - S->setSwitchLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - SwitchCase *PrevSC = 0; - for (unsigned N = Record.size(); Idx != N; ++Idx) { - SwitchCase *SC = Reader.getSwitchCaseWithID(Record[Idx]); - if (PrevSC) - PrevSC->setNextSwitchCase(SC); - else - S->setSwitchCaseList(SC); - - // Retain this SwitchCase, since SwitchStmt::addSwitchCase() would - // normally retain it (but we aren't calling addSwitchCase). - SC->Retain(); - PrevSC = SC; - } -} - -void PCHStmtReader::VisitWhileStmt(WhileStmt *S) { - VisitStmt(S); - S->setConditionVariable(*Reader.getContext(), - cast_or_null(Reader.GetDecl(Record[Idx++]))); - S->setCond(Reader.ReadSubExpr()); - S->setBody(Reader.ReadSubStmt()); - S->setWhileLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitDoStmt(DoStmt *S) { - VisitStmt(S); - S->setCond(Reader.ReadSubExpr()); - S->setBody(Reader.ReadSubStmt()); - S->setDoLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setWhileLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitForStmt(ForStmt *S) { - VisitStmt(S); - S->setInit(Reader.ReadSubStmt()); - S->setCond(Reader.ReadSubExpr()); - S->setConditionVariable(*Reader.getContext(), - cast_or_null(Reader.GetDecl(Record[Idx++]))); - S->setInc(Reader.ReadSubExpr()); - S->setBody(Reader.ReadSubStmt()); - S->setForLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitGotoStmt(GotoStmt *S) { - VisitStmt(S); - Reader.SetLabelOf(S, Record[Idx++]); - S->setGotoLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setLabelLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitIndirectGotoStmt(IndirectGotoStmt *S) { - VisitStmt(S); - S->setGotoLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setStarLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setTarget(Reader.ReadSubExpr()); -} - -void PCHStmtReader::VisitContinueStmt(ContinueStmt *S) { - VisitStmt(S); - S->setContinueLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitBreakStmt(BreakStmt *S) { - VisitStmt(S); - S->setBreakLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitReturnStmt(ReturnStmt *S) { - VisitStmt(S); - S->setRetValue(Reader.ReadSubExpr()); - S->setReturnLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setNRVOCandidate(cast_or_null(Reader.GetDecl(Record[Idx++]))); -} - -void PCHStmtReader::VisitDeclStmt(DeclStmt *S) { - VisitStmt(S); - S->setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - - if (Idx + 1 == Record.size()) { - // Single declaration - S->setDeclGroup(DeclGroupRef(Reader.GetDecl(Record[Idx++]))); - } else { - llvm::SmallVector Decls; - Decls.reserve(Record.size() - Idx); - for (unsigned N = Record.size(); Idx != N; ++Idx) - Decls.push_back(Reader.GetDecl(Record[Idx])); - S->setDeclGroup(DeclGroupRef(DeclGroup::Create(*Reader.getContext(), - Decls.data(), - Decls.size()))); - } -} - -void PCHStmtReader::VisitAsmStmt(AsmStmt *S) { - VisitStmt(S); - unsigned NumOutputs = Record[Idx++]; - unsigned NumInputs = Record[Idx++]; - unsigned NumClobbers = Record[Idx++]; - S->setAsmLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setVolatile(Record[Idx++]); - S->setSimple(Record[Idx++]); - S->setMSAsm(Record[Idx++]); - - S->setAsmString(cast_or_null(Reader.ReadSubStmt())); - - // Outputs and inputs - llvm::SmallVector Names; - llvm::SmallVector Constraints; - llvm::SmallVector Exprs; - for (unsigned I = 0, N = NumOutputs + NumInputs; I != N; ++I) { - Names.push_back(Reader.GetIdentifierInfo(Record, Idx)); - Constraints.push_back(cast_or_null(Reader.ReadSubStmt())); - Exprs.push_back(Reader.ReadSubStmt()); - } - - // Constraints - llvm::SmallVector Clobbers; - for (unsigned I = 0; I != NumClobbers; ++I) - Clobbers.push_back(cast_or_null(Reader.ReadSubStmt())); - - S->setOutputsAndInputsAndClobbers(*Reader.getContext(), - Names.data(), Constraints.data(), - Exprs.data(), NumOutputs, NumInputs, - Clobbers.data(), NumClobbers); -} - -void PCHStmtReader::VisitExpr(Expr *E) { - VisitStmt(E); - E->setType(Reader.GetType(Record[Idx++])); - E->setTypeDependent(Record[Idx++]); - E->setValueDependent(Record[Idx++]); - assert(Idx == NumExprFields && "Incorrect expression field count"); -} - -void PCHStmtReader::VisitPredefinedExpr(PredefinedExpr *E) { - VisitExpr(E); - E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setIdentType((PredefinedExpr::IdentType)Record[Idx++]); -} - -void PCHStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { - VisitExpr(E); - - bool HasQualifier = Record[Idx++]; - unsigned NumTemplateArgs = Record[Idx++]; - - E->DecoratedD.setInt((HasQualifier? DeclRefExpr::HasQualifierFlag : 0) | - (NumTemplateArgs ? DeclRefExpr::HasExplicitTemplateArgumentListFlag : 0)); - - if (HasQualifier) { - E->getNameQualifier()->NNS = Reader.ReadNestedNameSpecifier(Record, Idx); - E->getNameQualifier()->Range = Reader.ReadSourceRange(Record, Idx); - } - - if (NumTemplateArgs) - ReadExplicitTemplateArgumentList(*E->getExplicitTemplateArgumentList(), - NumTemplateArgs); - - E->setDecl(cast(Reader.GetDecl(Record[Idx++]))); - E->setLocation(Reader.ReadSourceLocation(Record, Idx)); -} - -void PCHStmtReader::VisitIntegerLiteral(IntegerLiteral *E) { - VisitExpr(E); - E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setValue(Reader.ReadAPInt(Record, Idx)); -} - -void PCHStmtReader::VisitFloatingLiteral(FloatingLiteral *E) { - VisitExpr(E); - E->setValue(Reader.ReadAPFloat(Record, Idx)); - E->setExact(Record[Idx++]); - E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitImaginaryLiteral(ImaginaryLiteral *E) { - VisitExpr(E); - E->setSubExpr(Reader.ReadSubExpr()); -} - -void PCHStmtReader::VisitStringLiteral(StringLiteral *E) { - VisitExpr(E); - unsigned Len = Record[Idx++]; - assert(Record[Idx] == E->getNumConcatenated() && - "Wrong number of concatenated tokens!"); - ++Idx; - E->setWide(Record[Idx++]); - - // Read string data - llvm::SmallString<16> Str(&Record[Idx], &Record[Idx] + Len); - E->setString(*Reader.getContext(), Str.str()); - Idx += Len; - - // Read source locations - for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I) - E->setStrTokenLoc(I, SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitCharacterLiteral(CharacterLiteral *E) { - VisitExpr(E); - E->setValue(Record[Idx++]); - E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setWide(Record[Idx++]); -} - -void PCHStmtReader::VisitParenExpr(ParenExpr *E) { - VisitExpr(E); - E->setLParen(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParen(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setSubExpr(Reader.ReadSubExpr()); -} - -void PCHStmtReader::VisitParenListExpr(ParenListExpr *E) { - VisitExpr(E); - unsigned NumExprs = Record[Idx++]; - E->Exprs = new (*Reader.getContext()) Stmt*[NumExprs]; - for (unsigned i = 0; i != NumExprs; ++i) - E->Exprs[i] = Reader.ReadSubStmt(); - E->NumExprs = NumExprs; - E->LParenLoc = Reader.ReadSourceLocation(Record, Idx); - E->RParenLoc = Reader.ReadSourceLocation(Record, Idx); -} - -void PCHStmtReader::VisitUnaryOperator(UnaryOperator *E) { - VisitExpr(E); - E->setSubExpr(Reader.ReadSubExpr()); - E->setOpcode((UnaryOperator::Opcode)Record[Idx++]); - E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { - typedef OffsetOfExpr::OffsetOfNode Node; - VisitExpr(E); - assert(E->getNumComponents() == Record[Idx]); - ++Idx; - assert(E->getNumExpressions() == Record[Idx]); - ++Idx; - E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); - for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { - Node::Kind Kind = static_cast(Record[Idx++]); - SourceLocation Start = SourceLocation::getFromRawEncoding(Record[Idx++]); - SourceLocation End = SourceLocation::getFromRawEncoding(Record[Idx++]); - switch (Kind) { - case Node::Array: - E->setComponent(I, Node(Start, Record[Idx++], End)); - break; - - case Node::Field: - E->setComponent(I, - Node(Start, - dyn_cast_or_null(Reader.GetDecl(Record[Idx++])), - End)); - break; - - case Node::Identifier: - E->setComponent(I, Node(Start, Reader.GetIdentifier(Record[Idx++]), End)); - break; - - case Node::Base: - // FIXME: Implement this! - llvm_unreachable("PCH for offsetof(base-specifier) not implemented"); - break; - } - } - - for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I) - E->setIndexExpr(I, Reader.ReadSubExpr()); -} - -void PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { - VisitExpr(E); - E->setSizeof(Record[Idx++]); - if (Record[Idx] == 0) { - E->setArgument(Reader.ReadSubExpr()); - ++Idx; - } else { - E->setArgument(Reader.GetTypeSourceInfo(Record, Idx)); - } - E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { - VisitExpr(E); - E->setLHS(Reader.ReadSubExpr()); - E->setRHS(Reader.ReadSubExpr()); - E->setRBracketLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitCallExpr(CallExpr *E) { - VisitExpr(E); - E->setNumArgs(*Reader.getContext(), Record[Idx++]); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setCallee(Reader.ReadSubExpr()); - for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) - E->setArg(I, Reader.ReadSubExpr()); -} - -void PCHStmtReader::VisitMemberExpr(MemberExpr *E) { - // Don't call VisitExpr, this is fully initialized at creation. - assert(E->getStmtClass() == Stmt::MemberExprClass && - "It's a subclass, we must advance Idx!"); -} - -void PCHStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) { - VisitExpr(E); - E->setBase(Reader.ReadSubExpr()); - E->setIsaMemberLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setArrow(Record[Idx++]); -} - -void PCHStmtReader::VisitCastExpr(CastExpr *E) { - VisitExpr(E); - E->setSubExpr(Reader.ReadSubExpr()); - E->setCastKind((CastExpr::CastKind)Record[Idx++]); - CXXBaseSpecifierArray &BasePath = E->getBasePath(); - unsigned NumBaseSpecs = Record[Idx++]; - while (NumBaseSpecs--) { - // FIXME: These gets leaked. - CXXBaseSpecifier *BaseSpec = new (*Reader.getContext()) CXXBaseSpecifier; - *BaseSpec = Reader.ReadCXXBaseSpecifier(Record, Idx); - BasePath.push_back(BaseSpec); - } -} - -void PCHStmtReader::VisitBinaryOperator(BinaryOperator *E) { - VisitExpr(E); - E->setLHS(Reader.ReadSubExpr()); - E->setRHS(Reader.ReadSubExpr()); - E->setOpcode((BinaryOperator::Opcode)Record[Idx++]); - E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) { - VisitBinaryOperator(E); - E->setComputationLHSType(Reader.GetType(Record[Idx++])); - E->setComputationResultType(Reader.GetType(Record[Idx++])); -} - -void PCHStmtReader::VisitConditionalOperator(ConditionalOperator *E) { - VisitExpr(E); - E->setCond(Reader.ReadSubExpr()); - E->setLHS(Reader.ReadSubExpr()); - E->setRHS(Reader.ReadSubExpr()); - E->setQuestionLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) { - VisitCastExpr(E); - E->setLvalueCast(Record[Idx++]); -} - -void PCHStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) { - VisitCastExpr(E); - E->setTypeInfoAsWritten(Reader.GetTypeSourceInfo(Record, Idx)); -} - -void PCHStmtReader::VisitCStyleCastExpr(CStyleCastExpr *E) { - VisitExplicitCastExpr(E); - E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { - VisitExpr(E); - E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); - E->setInitializer(Reader.ReadSubExpr()); - E->setFileScope(Record[Idx++]); -} - -void PCHStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { - VisitExpr(E); - E->setBase(Reader.ReadSubExpr()); - E->setAccessor(Reader.GetIdentifierInfo(Record, Idx)); - E->setAccessorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitInitListExpr(InitListExpr *E) { - VisitExpr(E); - unsigned NumInits = Record[Idx++]; - E->reserveInits(*Reader.getContext(), NumInits); - for (unsigned I = 0; I != NumInits; ++I) - E->updateInit(*Reader.getContext(), I, Reader.ReadSubExpr()); - E->setSyntacticForm(cast_or_null(Reader.ReadSubStmt())); - E->setLBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRBraceLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setInitializedFieldInUnion( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - E->sawArrayRangeDesignator(Record[Idx++]); -} - -void PCHStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) { - typedef DesignatedInitExpr::Designator Designator; - - VisitExpr(E); - unsigned NumSubExprs = Record[Idx++]; - assert(NumSubExprs == E->getNumSubExprs() && "Wrong number of subexprs"); - for (unsigned I = 0; I != NumSubExprs; ++I) - E->setSubExpr(I, Reader.ReadSubExpr()); - E->setEqualOrColonLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setGNUSyntax(Record[Idx++]); - - llvm::SmallVector Designators; - while (Idx < Record.size()) { - switch ((pch::DesignatorTypes)Record[Idx++]) { - case pch::DESIG_FIELD_DECL: { - FieldDecl *Field = cast(Reader.GetDecl(Record[Idx++])); - SourceLocation DotLoc - = SourceLocation::getFromRawEncoding(Record[Idx++]); - SourceLocation FieldLoc - = SourceLocation::getFromRawEncoding(Record[Idx++]); - Designators.push_back(Designator(Field->getIdentifier(), DotLoc, - FieldLoc)); - Designators.back().setField(Field); - break; - } - - case pch::DESIG_FIELD_NAME: { - const IdentifierInfo *Name = Reader.GetIdentifierInfo(Record, Idx); - SourceLocation DotLoc - = SourceLocation::getFromRawEncoding(Record[Idx++]); - SourceLocation FieldLoc - = SourceLocation::getFromRawEncoding(Record[Idx++]); - Designators.push_back(Designator(Name, DotLoc, FieldLoc)); - break; - } - - case pch::DESIG_ARRAY: { - unsigned Index = Record[Idx++]; - SourceLocation LBracketLoc - = SourceLocation::getFromRawEncoding(Record[Idx++]); - SourceLocation RBracketLoc - = SourceLocation::getFromRawEncoding(Record[Idx++]); - Designators.push_back(Designator(Index, LBracketLoc, RBracketLoc)); - break; - } - - case pch::DESIG_ARRAY_RANGE: { - unsigned Index = Record[Idx++]; - SourceLocation LBracketLoc - = SourceLocation::getFromRawEncoding(Record[Idx++]); - SourceLocation EllipsisLoc - = SourceLocation::getFromRawEncoding(Record[Idx++]); - SourceLocation RBracketLoc - = SourceLocation::getFromRawEncoding(Record[Idx++]); - Designators.push_back(Designator(Index, LBracketLoc, EllipsisLoc, - RBracketLoc)); - break; - } - } - } - E->setDesignators(*Reader.getContext(), - Designators.data(), Designators.size()); -} - -void PCHStmtReader::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { - VisitExpr(E); -} - -void PCHStmtReader::VisitVAArgExpr(VAArgExpr *E) { - VisitExpr(E); - E->setSubExpr(Reader.ReadSubExpr()); - E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) { - VisitExpr(E); - E->setAmpAmpLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setLabelLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - Reader.SetLabelOf(E, Record[Idx++]); -} - -void PCHStmtReader::VisitStmtExpr(StmtExpr *E) { - VisitExpr(E); - E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setSubStmt(cast_or_null(Reader.ReadSubStmt())); -} - -void PCHStmtReader::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) { - VisitExpr(E); - E->setArgType1(Reader.GetType(Record[Idx++])); - E->setArgType2(Reader.GetType(Record[Idx++])); - E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitChooseExpr(ChooseExpr *E) { - VisitExpr(E); - E->setCond(Reader.ReadSubExpr()); - E->setLHS(Reader.ReadSubExpr()); - E->setRHS(Reader.ReadSubExpr()); - E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitGNUNullExpr(GNUNullExpr *E) { - VisitExpr(E); - E->setTokenLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { - VisitExpr(E); - llvm::SmallVector Exprs; - unsigned NumExprs = Record[Idx++]; - while (NumExprs--) - Exprs.push_back(Reader.ReadSubExpr()); - E->setExprs(*Reader.getContext(), Exprs.data(), Exprs.size()); - E->setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitBlockExpr(BlockExpr *E) { - VisitExpr(E); - E->setBlockDecl(cast_or_null(Reader.GetDecl(Record[Idx++]))); - E->setHasBlockDeclRefExprs(Record[Idx++]); -} - -void PCHStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { - VisitExpr(E); - E->setDecl(cast(Reader.GetDecl(Record[Idx++]))); - E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setByRef(Record[Idx++]); - E->setConstQualAdded(Record[Idx++]); - E->setCopyConstructorExpr(Reader.ReadSubExpr()); -} - -//===----------------------------------------------------------------------===// -// Objective-C Expressions and Statements - -void PCHStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) { - VisitExpr(E); - E->setString(cast(Reader.ReadSubStmt())); - E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { - VisitExpr(E); - E->setEncodedTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); - E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) { - VisitExpr(E); - E->setSelector(Reader.GetSelector(Record, Idx)); - E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitObjCProtocolExpr(ObjCProtocolExpr *E) { - VisitExpr(E); - E->setProtocol(cast(Reader.GetDecl(Record[Idx++]))); - E->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { - VisitExpr(E); - E->setDecl(cast(Reader.GetDecl(Record[Idx++]))); - E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setBase(Reader.ReadSubExpr()); - E->setIsArrow(Record[Idx++]); - E->setIsFreeIvar(Record[Idx++]); -} - -void PCHStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { - VisitExpr(E); - E->setProperty(cast(Reader.GetDecl(Record[Idx++]))); - E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setBase(Reader.ReadSubExpr()); -} - -void PCHStmtReader::VisitObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *E) { - VisitExpr(E); - E->setGetterMethod( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - E->setSetterMethod( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - E->setInterfaceDecl( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - E->setBase(Reader.ReadSubExpr()); - E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setClassLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) { - VisitExpr(E); - assert(Record[Idx] == E->getNumArgs()); - ++Idx; - ObjCMessageExpr::ReceiverKind Kind - = static_cast(Record[Idx++]); - switch (Kind) { - case ObjCMessageExpr::Instance: - E->setInstanceReceiver(Reader.ReadSubExpr()); - break; - - case ObjCMessageExpr::Class: - E->setClassReceiver(Reader.GetTypeSourceInfo(Record, Idx)); - break; - - case ObjCMessageExpr::SuperClass: - case ObjCMessageExpr::SuperInstance: { - QualType T = Reader.GetType(Record[Idx++]); - SourceLocation SuperLoc = SourceLocation::getFromRawEncoding(Record[Idx++]); - E->setSuper(SuperLoc, T, Kind == ObjCMessageExpr::SuperInstance); - break; - } - } - - assert(Kind == E->getReceiverKind()); - - if (Record[Idx++]) - E->setMethodDecl(cast_or_null(Reader.GetDecl(Record[Idx++]))); - else - E->setSelector(Reader.GetSelector(Record, Idx)); - - E->setLeftLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRightLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - - for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) - E->setArg(I, Reader.ReadSubExpr()); -} - -void PCHStmtReader::VisitObjCSuperExpr(ObjCSuperExpr *E) { - VisitExpr(E); - E->setLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { - VisitStmt(S); - S->setElement(Reader.ReadSubStmt()); - S->setCollection(Reader.ReadSubExpr()); - S->setBody(Reader.ReadSubStmt()); - S->setForLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { - VisitStmt(S); - S->setCatchBody(Reader.ReadSubStmt()); - S->setCatchParamDecl(cast_or_null(Reader.GetDecl(Record[Idx++]))); - S->setAtCatchLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - S->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { - VisitStmt(S); - S->setFinallyBody(Reader.ReadSubStmt()); - S->setAtFinallyLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { - VisitStmt(S); - assert(Record[Idx] == S->getNumCatchStmts()); - ++Idx; - bool HasFinally = Record[Idx++]; - S->setTryBody(Reader.ReadSubStmt()); - for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) - S->setCatchStmt(I, cast_or_null(Reader.ReadSubStmt())); - - if (HasFinally) - S->setFinallyStmt(Reader.ReadSubStmt()); - S->setAtTryLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { - VisitStmt(S); - S->setSynchExpr(Reader.ReadSubStmt()); - S->setSynchBody(Reader.ReadSubStmt()); - S->setAtSynchronizedLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { - VisitStmt(S); - S->setThrowExpr(Reader.ReadSubStmt()); - S->setThrowLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -//===----------------------------------------------------------------------===// -// C++ Expressions and Statements - -void PCHStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { - VisitCallExpr(E); - E->setOperator((OverloadedOperatorKind)Record[Idx++]); -} - -void PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { - VisitExpr(E); - E->NumArgs = Record[Idx++]; - if (E->NumArgs) - E->Args = new (*Reader.getContext()) Stmt*[E->NumArgs]; - for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) - E->setArg(I, Reader.ReadSubExpr()); - E->setConstructor(cast(Reader.GetDecl(Record[Idx++]))); - E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setElidable(Record[Idx++]); - E->setRequiresZeroInitialization(Record[Idx++]); - E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]); -} - -void PCHStmtReader::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) { - VisitCXXConstructExpr(E); - E->TyBeginLoc = Reader.ReadSourceLocation(Record, Idx); - E->RParenLoc = Reader.ReadSourceLocation(Record, Idx); -} - -void PCHStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { - VisitExplicitCastExpr(E); - E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) { - return VisitCXXNamedCastExpr(E); -} - -void PCHStmtReader::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) { - return VisitCXXNamedCastExpr(E); -} - -void PCHStmtReader::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) { - return VisitCXXNamedCastExpr(E); -} - -void PCHStmtReader::VisitCXXConstCastExpr(CXXConstCastExpr *E) { - return VisitCXXNamedCastExpr(E); -} - -void PCHStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) { - VisitExplicitCastExpr(E); - E->setTypeBeginLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { - VisitExpr(E); - E->setValue(Record[Idx++]); - E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { - VisitExpr(E); - E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitCXXTypeidExpr(CXXTypeidExpr *E) { - VisitExpr(E); - E->setSourceRange(Reader.ReadSourceRange(Record, Idx)); - if (E->isTypeOperand()) { // typeid(int) - E->setTypeOperandSourceInfo(Reader.GetTypeSourceInfo(Record, Idx)); - return; - } - - // typeid(42+2) - E->setExprOperand(Reader.ReadSubExpr()); -} - -void PCHStmtReader::VisitCXXThisExpr(CXXThisExpr *E) { - VisitExpr(E); - E->setLocation(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setImplicit(Record[Idx++]); -} - -void PCHStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) { - VisitExpr(E); - E->setThrowLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setSubExpr(Reader.ReadSubExpr()); -} - -void PCHStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { - VisitExpr(E); - - assert(Record[Idx] == E->Param.getInt() && "We messed up at creation ?"); - ++Idx; // HasOtherExprStored and SubExpr was handled during creation. - E->Param.setPointer(cast(Reader.GetDecl(Record[Idx++]))); - E->Loc = Reader.ReadSourceLocation(Record, Idx); -} - -void PCHStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { - VisitExpr(E); - E->setTemporary(Reader.ReadCXXTemporary(Record, Idx)); - E->setSubExpr(Reader.ReadSubExpr()); -} - -void PCHStmtReader::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *E) { - VisitExpr(E); - E->SubExpr = Reader.ReadSubExpr(); - E->ExtendsLifetime = Record[Idx++]; - E->RequiresTemporaryCopy = Record[Idx++]; -} - -void PCHStmtReader::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) { - VisitExpr(E); - E->setTypeBeginLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitCXXNewExpr(CXXNewExpr *E) { - VisitExpr(E); - E->setGlobalNew(Record[Idx++]); - E->setHasInitializer(Record[Idx++]); - bool isArray = Record[Idx++]; - unsigned NumPlacementArgs = Record[Idx++]; - unsigned NumCtorArgs = Record[Idx++]; - E->setOperatorNew(cast_or_null(Reader.GetDecl(Record[Idx++]))); - E->setOperatorDelete( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - E->setConstructor( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - SourceRange TypeIdParens; - TypeIdParens.setBegin(SourceLocation::getFromRawEncoding(Record[Idx++])); - TypeIdParens.setEnd(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->TypeIdParens = TypeIdParens; - E->setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - E->setEndLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); - - E->AllocateArgsArray(*Reader.getContext(), isArray, NumPlacementArgs, - NumCtorArgs); - - // Install all the subexpressions. - for (CXXNewExpr::raw_arg_iterator I = E->raw_arg_begin(),e = E->raw_arg_end(); - I != e; ++I) - *I = Reader.ReadSubStmt(); -} - -void PCHStmtReader::VisitCXXDeleteExpr(CXXDeleteExpr *E) { - VisitExpr(E); - E->setGlobalDelete(Record[Idx++]); - E->setArrayForm(Record[Idx++]); - E->setOperatorDelete( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - E->setArgument(Reader.ReadSubExpr()); - E->setStartLoc(SourceLocation::getFromRawEncoding(Record[Idx++])); -} - -void PCHStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { - VisitExpr(E); - - E->setBase(Reader.ReadSubExpr()); - E->setArrow(Record[Idx++]); - E->setOperatorLoc(Reader.ReadSourceLocation(Record, Idx)); - E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx)); - E->setQualifierRange(Reader.ReadSourceRange(Record, Idx)); - E->setScopeTypeInfo(Reader.GetTypeSourceInfo(Record, Idx)); - E->setColonColonLoc(Reader.ReadSourceLocation(Record, Idx)); - E->setTildeLoc(Reader.ReadSourceLocation(Record, Idx)); - - IdentifierInfo *II = Reader.GetIdentifierInfo(Record, Idx); - if (II) - E->setDestroyedType(II, Reader.ReadSourceLocation(Record, Idx)); - else - E->setDestroyedType(Reader.GetTypeSourceInfo(Record, Idx)); -} - -void PCHStmtReader::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { - VisitExpr(E); - unsigned NumTemps = Record[Idx++]; - if (NumTemps) { - E->setNumTemporaries(*Reader.getContext(), NumTemps); - for (unsigned i = 0; i != NumTemps; ++i) - E->setTemporary(i, Reader.ReadCXXTemporary(Record, Idx)); - } - E->setSubExpr(Reader.ReadSubExpr()); -} - -void -PCHStmtReader::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){ - VisitExpr(E); - - unsigned NumTemplateArgs = Record[Idx++]; - assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgs() && - "Read wrong record during creation ?"); - if (E->hasExplicitTemplateArgs()) - ReadExplicitTemplateArgumentList(*E->getExplicitTemplateArgumentList(), - NumTemplateArgs); - - E->setBase(Reader.ReadSubExpr()); - E->setBaseType(Reader.GetType(Record[Idx++])); - E->setArrow(Record[Idx++]); - E->setOperatorLoc(Reader.ReadSourceLocation(Record, Idx)); - E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx)); - E->setQualifierRange(Reader.ReadSourceRange(Record, Idx)); - E->setFirstQualifierFoundInScope( - cast_or_null(Reader.GetDecl(Record[Idx++]))); - E->setMember(Reader.ReadDeclarationName(Record, Idx)); - E->setMemberLoc(Reader.ReadSourceLocation(Record, Idx)); -} - -void -PCHStmtReader::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { - VisitExpr(E); - - unsigned NumTemplateArgs = Record[Idx++]; - assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgs() && - "Read wrong record during creation ?"); - if (E->hasExplicitTemplateArgs()) - ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(), - NumTemplateArgs); - - E->setDeclName(Reader.ReadDeclarationName(Record, Idx)); - E->setLocation(Reader.ReadSourceLocation(Record, Idx)); - E->setQualifierRange(Reader.ReadSourceRange(Record, Idx)); - E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx)); -} - -void -PCHStmtReader::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) { - VisitExpr(E); - assert(Record[Idx] == E->arg_size() && "Read wrong record during creation ?"); - ++Idx; // NumArgs; - for (unsigned I = 0, N = E->arg_size(); I != N; ++I) - E->setArg(I, Reader.ReadSubExpr()); - E->setTypeBeginLoc(Reader.ReadSourceLocation(Record, Idx)); - E->setTypeAsWritten(Reader.GetType(Record[Idx++])); - E->setLParenLoc(Reader.ReadSourceLocation(Record, Idx)); - E->setRParenLoc(Reader.ReadSourceLocation(Record, Idx)); -} - -void PCHStmtReader::VisitOverloadExpr(OverloadExpr *E) { - VisitExpr(E); - - unsigned NumTemplateArgs = Record[Idx++]; - assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgs() && - "Read wrong record during creation ?"); - if (E->hasExplicitTemplateArgs()) - ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(), - NumTemplateArgs); - - unsigned NumDecls = Record[Idx++]; - UnresolvedSet<8> Decls; - for (unsigned i = 0; i != NumDecls; ++i) { - NamedDecl *D = cast(Reader.GetDecl(Record[Idx++])); - AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; - Decls.addDecl(D, AS); - } - E->initializeResults(*Reader.getContext(), Decls.begin(), Decls.end()); - - E->setName(Reader.ReadDeclarationName(Record, Idx)); - E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx)); - E->setQualifierRange(Reader.ReadSourceRange(Record, Idx)); - E->setNameLoc(Reader.ReadSourceLocation(Record, Idx)); -} - -void PCHStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { - VisitOverloadExpr(E); - E->setArrow(Record[Idx++]); - E->setHasUnresolvedUsing(Record[Idx++]); - E->setBase(Reader.ReadSubExpr()); - E->setBaseType(Reader.GetType(Record[Idx++])); - E->setOperatorLoc(Reader.ReadSourceLocation(Record, Idx)); -} - -void PCHStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { - VisitOverloadExpr(E); - E->setRequiresADL(Record[Idx++]); - E->setOverloaded(Record[Idx++]); - E->setNamingClass(cast_or_null(Reader.GetDecl(Record[Idx++]))); -} - -void PCHStmtReader::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { - VisitExpr(E); - E->UTT = (UnaryTypeTrait)Record[Idx++]; - SourceRange Range = Reader.ReadSourceRange(Record, Idx); - E->Loc = Range.getBegin(); - E->RParen = Range.getEnd(); - E->QueriedType = Reader.GetType(Record[Idx++]); -} - -Stmt *PCHReader::ReadStmt() { - switch (ReadingKind) { - case Read_Decl: - case Read_Type: - // Read a statement from the current DeclCursor. - return ReadStmtFromStream(DeclsCursor); - case Read_Stmt: - return ReadSubStmt(); - } - - llvm_unreachable("ReadingKind not set ?"); - return 0; -} - -Expr *PCHReader::ReadExpr() { - return cast_or_null(ReadStmt()); -} - -Expr *PCHReader::ReadSubExpr() { - return cast_or_null(ReadSubStmt()); -} - -// Within the bitstream, expressions are stored in Reverse Polish -// Notation, with each of the subexpressions preceding the -// expression they are stored in. Subexpressions are stored from last to first. -// To evaluate expressions, we continue reading expressions and placing them on -// the stack, with expressions having operands removing those operands from the -// stack. Evaluation terminates when we see a STMT_STOP record, and -// the single remaining expression on the stack is our result. -Stmt *PCHReader::ReadStmtFromStream(llvm::BitstreamCursor &Cursor) { - - ReadingKindTracker ReadingKind(Read_Stmt, *this); - -#ifndef NDEBUG - unsigned PrevNumStmts = StmtStack.size(); -#endif - - RecordData Record; - unsigned Idx; - PCHStmtReader Reader(*this, Record, Idx); - Stmt::EmptyShell Empty; - - while (true) { - unsigned Code = Cursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK) { - if (Cursor.ReadBlockEnd()) { - Error("error at end of block in PCH file"); - return 0; - } - break; - } - - if (Code == llvm::bitc::ENTER_SUBBLOCK) { - // No known subblocks, always skip them. - Cursor.ReadSubBlockID(); - if (Cursor.SkipBlock()) { - Error("malformed block record in PCH file"); - return 0; - } - continue; - } - - if (Code == llvm::bitc::DEFINE_ABBREV) { - Cursor.ReadAbbrevRecord(); - continue; - } - - Stmt *S = 0; - Idx = 0; - Record.clear(); - bool Finished = false; - switch ((pch::StmtCode)Cursor.ReadRecord(Code, Record)) { - case pch::STMT_STOP: - Finished = true; - break; - - case pch::STMT_NULL_PTR: - S = 0; - break; - - case pch::STMT_NULL: - S = new (Context) NullStmt(Empty); - break; - - case pch::STMT_COMPOUND: - S = new (Context) CompoundStmt(Empty); - break; - - case pch::STMT_CASE: - S = new (Context) CaseStmt(Empty); - break; - - case pch::STMT_DEFAULT: - S = new (Context) DefaultStmt(Empty); - break; - - case pch::STMT_LABEL: - S = new (Context) LabelStmt(Empty); - break; - - case pch::STMT_IF: - S = new (Context) IfStmt(Empty); - break; - - case pch::STMT_SWITCH: - S = new (Context) SwitchStmt(Empty); - break; - - case pch::STMT_WHILE: - S = new (Context) WhileStmt(Empty); - break; - - case pch::STMT_DO: - S = new (Context) DoStmt(Empty); - break; - - case pch::STMT_FOR: - S = new (Context) ForStmt(Empty); - break; - - case pch::STMT_GOTO: - S = new (Context) GotoStmt(Empty); - break; - - case pch::STMT_INDIRECT_GOTO: - S = new (Context) IndirectGotoStmt(Empty); - break; - - case pch::STMT_CONTINUE: - S = new (Context) ContinueStmt(Empty); - break; - - case pch::STMT_BREAK: - S = new (Context) BreakStmt(Empty); - break; - - case pch::STMT_RETURN: - S = new (Context) ReturnStmt(Empty); - break; - - case pch::STMT_DECL: - S = new (Context) DeclStmt(Empty); - break; - - case pch::STMT_ASM: - S = new (Context) AsmStmt(Empty); - break; - - case pch::EXPR_PREDEFINED: - S = new (Context) PredefinedExpr(Empty); - break; - - case pch::EXPR_DECL_REF: - S = DeclRefExpr::CreateEmpty(*Context, - /*HasQualifier=*/Record[PCHStmtReader::NumExprFields], - /*NumTemplateArgs=*/Record[PCHStmtReader::NumExprFields + 1]); - break; - - case pch::EXPR_INTEGER_LITERAL: - S = new (Context) IntegerLiteral(Empty); - break; - - case pch::EXPR_FLOATING_LITERAL: - S = new (Context) FloatingLiteral(Empty); - break; - - case pch::EXPR_IMAGINARY_LITERAL: - S = new (Context) ImaginaryLiteral(Empty); - break; - - case pch::EXPR_STRING_LITERAL: - S = StringLiteral::CreateEmpty(*Context, - Record[PCHStmtReader::NumExprFields + 1]); - break; - - case pch::EXPR_CHARACTER_LITERAL: - S = new (Context) CharacterLiteral(Empty); - break; - - case pch::EXPR_PAREN: - S = new (Context) ParenExpr(Empty); - break; - - case pch::EXPR_PAREN_LIST: - S = new (Context) ParenListExpr(Empty); - break; - - case pch::EXPR_UNARY_OPERATOR: - S = new (Context) UnaryOperator(Empty); - break; - - case pch::EXPR_OFFSETOF: - S = OffsetOfExpr::CreateEmpty(*Context, - Record[PCHStmtReader::NumExprFields], - Record[PCHStmtReader::NumExprFields + 1]); - break; - - case pch::EXPR_SIZEOF_ALIGN_OF: - S = new (Context) SizeOfAlignOfExpr(Empty); - break; - - case pch::EXPR_ARRAY_SUBSCRIPT: - S = new (Context) ArraySubscriptExpr(Empty); - break; - - case pch::EXPR_CALL: - S = new (Context) CallExpr(*Context, Stmt::CallExprClass, Empty); - break; - - case pch::EXPR_MEMBER: { - // We load everything here and fully initialize it at creation. - // That way we can use MemberExpr::Create and don't have to duplicate its - // logic with a MemberExpr::CreateEmpty. - - assert(Idx == 0); - NestedNameSpecifier *NNS = 0; - SourceRange QualifierRange; - if (Record[Idx++]) { // HasQualifier. - NNS = ReadNestedNameSpecifier(Record, Idx); - QualifierRange = ReadSourceRange(Record, Idx); - } - - TemplateArgumentListInfo ArgInfo; - unsigned NumTemplateArgs = Record[Idx++]; - if (NumTemplateArgs) { - ArgInfo.setLAngleLoc(ReadSourceLocation(Record, Idx)); - ArgInfo.setRAngleLoc(ReadSourceLocation(Record, Idx)); - for (unsigned i = 0; i != NumTemplateArgs; ++i) - ArgInfo.addArgument(ReadTemplateArgumentLoc(Record, Idx)); - } - - NamedDecl *FoundD = cast_or_null(GetDecl(Record[Idx++])); - AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; - DeclAccessPair FoundDecl = DeclAccessPair::make(FoundD, AS); - - QualType T = GetType(Record[Idx++]); - Expr *Base = ReadSubExpr(); - ValueDecl *MemberD = cast(GetDecl(Record[Idx++])); - SourceLocation MemberLoc = ReadSourceLocation(Record, Idx); - bool IsArrow = Record[Idx++]; - - S = MemberExpr::Create(*Context, Base, IsArrow, NNS, QualifierRange, - MemberD, FoundDecl, MemberLoc, - NumTemplateArgs ? &ArgInfo : 0, T); - break; - } - - case pch::EXPR_BINARY_OPERATOR: - S = new (Context) BinaryOperator(Empty); - break; - - case pch::EXPR_COMPOUND_ASSIGN_OPERATOR: - S = new (Context) CompoundAssignOperator(Empty); - break; - - case pch::EXPR_CONDITIONAL_OPERATOR: - S = new (Context) ConditionalOperator(Empty); - break; - - case pch::EXPR_IMPLICIT_CAST: - S = new (Context) ImplicitCastExpr(Empty); - break; - - case pch::EXPR_CSTYLE_CAST: - S = new (Context) CStyleCastExpr(Empty); - break; - - case pch::EXPR_COMPOUND_LITERAL: - S = new (Context) CompoundLiteralExpr(Empty); - break; - - case pch::EXPR_EXT_VECTOR_ELEMENT: - S = new (Context) ExtVectorElementExpr(Empty); - break; - - case pch::EXPR_INIT_LIST: - S = new (Context) InitListExpr(*getContext(), Empty); - break; - - case pch::EXPR_DESIGNATED_INIT: - S = DesignatedInitExpr::CreateEmpty(*Context, - Record[PCHStmtReader::NumExprFields] - 1); - - break; - - case pch::EXPR_IMPLICIT_VALUE_INIT: - S = new (Context) ImplicitValueInitExpr(Empty); - break; - - case pch::EXPR_VA_ARG: - S = new (Context) VAArgExpr(Empty); - break; - - case pch::EXPR_ADDR_LABEL: - S = new (Context) AddrLabelExpr(Empty); - break; - - case pch::EXPR_STMT: - S = new (Context) StmtExpr(Empty); - break; - - case pch::EXPR_TYPES_COMPATIBLE: - S = new (Context) TypesCompatibleExpr(Empty); - break; - - case pch::EXPR_CHOOSE: - S = new (Context) ChooseExpr(Empty); - break; - - case pch::EXPR_GNU_NULL: - S = new (Context) GNUNullExpr(Empty); - break; - - case pch::EXPR_SHUFFLE_VECTOR: - S = new (Context) ShuffleVectorExpr(Empty); - break; - - case pch::EXPR_BLOCK: - S = new (Context) BlockExpr(Empty); - break; - - case pch::EXPR_BLOCK_DECL_REF: - S = new (Context) BlockDeclRefExpr(Empty); - break; - - case pch::EXPR_OBJC_STRING_LITERAL: - S = new (Context) ObjCStringLiteral(Empty); - break; - case pch::EXPR_OBJC_ENCODE: - S = new (Context) ObjCEncodeExpr(Empty); - break; - case pch::EXPR_OBJC_SELECTOR_EXPR: - S = new (Context) ObjCSelectorExpr(Empty); - break; - case pch::EXPR_OBJC_PROTOCOL_EXPR: - S = new (Context) ObjCProtocolExpr(Empty); - break; - case pch::EXPR_OBJC_IVAR_REF_EXPR: - S = new (Context) ObjCIvarRefExpr(Empty); - break; - case pch::EXPR_OBJC_PROPERTY_REF_EXPR: - S = new (Context) ObjCPropertyRefExpr(Empty); - break; - case pch::EXPR_OBJC_KVC_REF_EXPR: - S = new (Context) ObjCImplicitSetterGetterRefExpr(Empty); - break; - case pch::EXPR_OBJC_MESSAGE_EXPR: - S = ObjCMessageExpr::CreateEmpty(*Context, - Record[PCHStmtReader::NumExprFields]); - break; - case pch::EXPR_OBJC_SUPER_EXPR: - S = new (Context) ObjCSuperExpr(Empty); - break; - case pch::EXPR_OBJC_ISA: - S = new (Context) ObjCIsaExpr(Empty); - break; - case pch::STMT_OBJC_FOR_COLLECTION: - S = new (Context) ObjCForCollectionStmt(Empty); - break; - case pch::STMT_OBJC_CATCH: - S = new (Context) ObjCAtCatchStmt(Empty); - break; - case pch::STMT_OBJC_FINALLY: - S = new (Context) ObjCAtFinallyStmt(Empty); - break; - case pch::STMT_OBJC_AT_TRY: - S = ObjCAtTryStmt::CreateEmpty(*Context, - Record[PCHStmtReader::NumStmtFields], - Record[PCHStmtReader::NumStmtFields + 1]); - break; - case pch::STMT_OBJC_AT_SYNCHRONIZED: - S = new (Context) ObjCAtSynchronizedStmt(Empty); - break; - case pch::STMT_OBJC_AT_THROW: - S = new (Context) ObjCAtThrowStmt(Empty); - break; - - case pch::EXPR_CXX_OPERATOR_CALL: - S = new (Context) CXXOperatorCallExpr(*Context, Empty); - break; - - case pch::EXPR_CXX_MEMBER_CALL: - S = new (Context) CXXMemberCallExpr(*Context, Empty); - break; - - case pch::EXPR_CXX_CONSTRUCT: - S = new (Context) CXXConstructExpr(Empty); - break; - - case pch::EXPR_CXX_TEMPORARY_OBJECT: - S = new (Context) CXXTemporaryObjectExpr(Empty); - break; - - case pch::EXPR_CXX_STATIC_CAST: - S = new (Context) CXXStaticCastExpr(Empty); - break; - - case pch::EXPR_CXX_DYNAMIC_CAST: - S = new (Context) CXXDynamicCastExpr(Empty); - break; - - case pch::EXPR_CXX_REINTERPRET_CAST: - S = new (Context) CXXReinterpretCastExpr(Empty); - break; - - case pch::EXPR_CXX_CONST_CAST: - S = new (Context) CXXConstCastExpr(Empty); - break; - - case pch::EXPR_CXX_FUNCTIONAL_CAST: - S = new (Context) CXXFunctionalCastExpr(Empty); - break; - - case pch::EXPR_CXX_BOOL_LITERAL: - S = new (Context) CXXBoolLiteralExpr(Empty); - break; - - case pch::EXPR_CXX_NULL_PTR_LITERAL: - S = new (Context) CXXNullPtrLiteralExpr(Empty); - break; - case pch::EXPR_CXX_TYPEID_EXPR: - S = new (Context) CXXTypeidExpr(Empty, true); - break; - case pch::EXPR_CXX_TYPEID_TYPE: - S = new (Context) CXXTypeidExpr(Empty, false); - break; - case pch::EXPR_CXX_THIS: - S = new (Context) CXXThisExpr(Empty); - break; - case pch::EXPR_CXX_THROW: - S = new (Context) CXXThrowExpr(Empty); - break; - case pch::EXPR_CXX_DEFAULT_ARG: { - bool HasOtherExprStored = Record[PCHStmtReader::NumExprFields]; - if (HasOtherExprStored) { - Expr *SubExpr = ReadSubExpr(); - S = CXXDefaultArgExpr::Create(*Context, SourceLocation(), 0, SubExpr); - } else - S = new (Context) CXXDefaultArgExpr(Empty); - break; - } - case pch::EXPR_CXX_BIND_TEMPORARY: - S = new (Context) CXXBindTemporaryExpr(Empty); - break; - case pch::EXPR_CXX_BIND_REFERENCE: - S = new (Context) CXXBindReferenceExpr(Empty); - break; - - case pch::EXPR_CXX_SCALAR_VALUE_INIT: - S = new (Context) CXXScalarValueInitExpr(Empty); - break; - case pch::EXPR_CXX_NEW: - S = new (Context) CXXNewExpr(Empty); - break; - case pch::EXPR_CXX_DELETE: - S = new (Context) CXXDeleteExpr(Empty); - break; - case pch::EXPR_CXX_PSEUDO_DESTRUCTOR: - S = new (Context) CXXPseudoDestructorExpr(Empty); - break; - - case pch::EXPR_CXX_EXPR_WITH_TEMPORARIES: - S = new (Context) CXXExprWithTemporaries(Empty); - break; - - case pch::EXPR_CXX_DEPENDENT_SCOPE_MEMBER: - S = CXXDependentScopeMemberExpr::CreateEmpty(*Context, - /*NumTemplateArgs=*/Record[PCHStmtReader::NumExprFields]); - break; - - case pch::EXPR_CXX_DEPENDENT_SCOPE_DECL_REF: - S = DependentScopeDeclRefExpr::CreateEmpty(*Context, - /*NumTemplateArgs=*/Record[PCHStmtReader::NumExprFields]); - break; - - case pch::EXPR_CXX_UNRESOLVED_CONSTRUCT: - S = CXXUnresolvedConstructExpr::CreateEmpty(*Context, - /*NumArgs=*/Record[PCHStmtReader::NumExprFields]); - break; - - case pch::EXPR_CXX_UNRESOLVED_MEMBER: - S = UnresolvedMemberExpr::CreateEmpty(*Context, - /*NumTemplateArgs=*/Record[PCHStmtReader::NumExprFields]); - break; - - case pch::EXPR_CXX_UNRESOLVED_LOOKUP: - S = UnresolvedLookupExpr::CreateEmpty(*Context, - /*NumTemplateArgs=*/Record[PCHStmtReader::NumExprFields]); - break; - - case pch::EXPR_CXX_UNARY_TYPE_TRAIT: - S = new (Context) UnaryTypeTraitExpr(Empty); - break; - } - - // We hit a STMT_STOP, so we're done with this expression. - if (Finished) - break; - - ++NumStatementsRead; - - if (S) - Reader.Visit(S); - - assert(Idx == Record.size() && "Invalid deserialization of statement"); - StmtStack.push_back(S); - } - -#ifndef NDEBUG - assert(StmtStack.size() > PrevNumStmts && "Read too many sub stmts!"); - assert(StmtStack.size() == PrevNumStmts + 1 && "Extra expressions on stack!"); -#endif - - return StmtStack.pop_back_val(); -} diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp deleted file mode 100644 index 093c1e3..0000000 --- a/lib/Frontend/PCHWriter.cpp +++ /dev/null @@ -1,2748 +0,0 @@ -//===--- PCHWriter.cpp - Precompiled Headers Writer -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the PCHWriter class, which writes a precompiled header. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/PCHWriter.h" -#include "../Sema/Sema.h" // FIXME: move header into include/clang/Sema -#include "../Sema/IdentifierResolver.h" // FIXME: move header -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclContextInternals.h" -#include "clang/AST/Expr.h" -#include "clang/AST/Type.h" -#include "clang/AST/TypeLocVisitor.h" -#include "clang/Frontend/PCHReader.h" -#include "clang/Lex/MacroInfo.h" -#include "clang/Lex/PreprocessingRecord.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Basic/FileManager.h" -#include "clang/Basic/OnDiskHashTable.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/SourceManagerInternals.h" -#include "clang/Basic/TargetInfo.h" -#include "clang/Basic/Version.h" -#include "llvm/ADT/APFloat.h" -#include "llvm/ADT/APInt.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Bitcode/BitstreamWriter.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/System/Path.h" -#include -using namespace clang; - -//===----------------------------------------------------------------------===// -// Type serialization -//===----------------------------------------------------------------------===// - -namespace { - class PCHTypeWriter { - PCHWriter &Writer; - PCHWriter::RecordData &Record; - - public: - /// \brief Type code that corresponds to the record generated. - pch::TypeCode Code; - - PCHTypeWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) - : Writer(Writer), Record(Record), Code(pch::TYPE_EXT_QUAL) { } - - void VisitArrayType(const ArrayType *T); - void VisitFunctionType(const FunctionType *T); - void VisitTagType(const TagType *T); - -#define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T); -#define ABSTRACT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.def" - }; -} - -void PCHTypeWriter::VisitBuiltinType(const BuiltinType *T) { - assert(false && "Built-in types are never serialized"); -} - -void PCHTypeWriter::VisitComplexType(const ComplexType *T) { - Writer.AddTypeRef(T->getElementType(), Record); - Code = pch::TYPE_COMPLEX; -} - -void PCHTypeWriter::VisitPointerType(const PointerType *T) { - Writer.AddTypeRef(T->getPointeeType(), Record); - Code = pch::TYPE_POINTER; -} - -void PCHTypeWriter::VisitBlockPointerType(const BlockPointerType *T) { - Writer.AddTypeRef(T->getPointeeType(), Record); - Code = pch::TYPE_BLOCK_POINTER; -} - -void PCHTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) { - Writer.AddTypeRef(T->getPointeeType(), Record); - Code = pch::TYPE_LVALUE_REFERENCE; -} - -void PCHTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) { - Writer.AddTypeRef(T->getPointeeType(), Record); - Code = pch::TYPE_RVALUE_REFERENCE; -} - -void PCHTypeWriter::VisitMemberPointerType(const MemberPointerType *T) { - Writer.AddTypeRef(T->getPointeeType(), Record); - Writer.AddTypeRef(QualType(T->getClass(), 0), Record); - Code = pch::TYPE_MEMBER_POINTER; -} - -void PCHTypeWriter::VisitArrayType(const ArrayType *T) { - Writer.AddTypeRef(T->getElementType(), Record); - Record.push_back(T->getSizeModifier()); // FIXME: stable values - Record.push_back(T->getIndexTypeCVRQualifiers()); // FIXME: stable values -} - -void PCHTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) { - VisitArrayType(T); - Writer.AddAPInt(T->getSize(), Record); - Code = pch::TYPE_CONSTANT_ARRAY; -} - -void PCHTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) { - VisitArrayType(T); - Code = pch::TYPE_INCOMPLETE_ARRAY; -} - -void PCHTypeWriter::VisitVariableArrayType(const VariableArrayType *T) { - VisitArrayType(T); - Writer.AddSourceLocation(T->getLBracketLoc(), Record); - Writer.AddSourceLocation(T->getRBracketLoc(), Record); - Writer.AddStmt(T->getSizeExpr()); - Code = pch::TYPE_VARIABLE_ARRAY; -} - -void PCHTypeWriter::VisitVectorType(const VectorType *T) { - Writer.AddTypeRef(T->getElementType(), Record); - Record.push_back(T->getNumElements()); - Record.push_back(T->getAltiVecSpecific()); - Code = pch::TYPE_VECTOR; -} - -void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) { - VisitVectorType(T); - Code = pch::TYPE_EXT_VECTOR; -} - -void PCHTypeWriter::VisitFunctionType(const FunctionType *T) { - Writer.AddTypeRef(T->getResultType(), Record); - FunctionType::ExtInfo C = T->getExtInfo(); - Record.push_back(C.getNoReturn()); - Record.push_back(C.getRegParm()); - // FIXME: need to stabilize encoding of calling convention... - Record.push_back(C.getCC()); -} - -void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { - VisitFunctionType(T); - Code = pch::TYPE_FUNCTION_NO_PROTO; -} - -void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { - VisitFunctionType(T); - Record.push_back(T->getNumArgs()); - for (unsigned I = 0, N = T->getNumArgs(); I != N; ++I) - Writer.AddTypeRef(T->getArgType(I), Record); - Record.push_back(T->isVariadic()); - Record.push_back(T->getTypeQuals()); - Record.push_back(T->hasExceptionSpec()); - Record.push_back(T->hasAnyExceptionSpec()); - Record.push_back(T->getNumExceptions()); - for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) - Writer.AddTypeRef(T->getExceptionType(I), Record); - Code = pch::TYPE_FUNCTION_PROTO; -} - -void PCHTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { - Writer.AddDeclRef(T->getDecl(), Record); - Code = pch::TYPE_UNRESOLVED_USING; -} - -void PCHTypeWriter::VisitTypedefType(const TypedefType *T) { - Writer.AddDeclRef(T->getDecl(), Record); - assert(!T->isCanonicalUnqualified() && "Invalid typedef ?"); - Writer.AddTypeRef(T->getCanonicalTypeInternal(), Record); - Code = pch::TYPE_TYPEDEF; -} - -void PCHTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) { - Writer.AddStmt(T->getUnderlyingExpr()); - Code = pch::TYPE_TYPEOF_EXPR; -} - -void PCHTypeWriter::VisitTypeOfType(const TypeOfType *T) { - Writer.AddTypeRef(T->getUnderlyingType(), Record); - Code = pch::TYPE_TYPEOF; -} - -void PCHTypeWriter::VisitDecltypeType(const DecltypeType *T) { - Writer.AddStmt(T->getUnderlyingExpr()); - Code = pch::TYPE_DECLTYPE; -} - -void PCHTypeWriter::VisitTagType(const TagType *T) { - Record.push_back(T->isDependentType()); - Writer.AddDeclRef(T->getDecl(), Record); - assert(!T->isBeingDefined() && - "Cannot serialize in the middle of a type definition"); -} - -void PCHTypeWriter::VisitRecordType(const RecordType *T) { - VisitTagType(T); - Code = pch::TYPE_RECORD; -} - -void PCHTypeWriter::VisitEnumType(const EnumType *T) { - VisitTagType(T); - Code = pch::TYPE_ENUM; -} - -void -PCHTypeWriter::VisitSubstTemplateTypeParmType( - const SubstTemplateTypeParmType *T) { - Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record); - Writer.AddTypeRef(T->getReplacementType(), Record); - Code = pch::TYPE_SUBST_TEMPLATE_TYPE_PARM; -} - -void -PCHTypeWriter::VisitTemplateSpecializationType( - const TemplateSpecializationType *T) { - Record.push_back(T->isDependentType()); - Writer.AddTemplateName(T->getTemplateName(), Record); - Record.push_back(T->getNumArgs()); - for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end(); - ArgI != ArgE; ++ArgI) - Writer.AddTemplateArgument(*ArgI, Record); - Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType() - : T->getCanonicalTypeInternal(), - Record); - Code = pch::TYPE_TEMPLATE_SPECIALIZATION; -} - -void -PCHTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) { - VisitArrayType(T); - Writer.AddStmt(T->getSizeExpr()); - Writer.AddSourceRange(T->getBracketsRange(), Record); - Code = pch::TYPE_DEPENDENT_SIZED_ARRAY; -} - -void -PCHTypeWriter::VisitDependentSizedExtVectorType( - const DependentSizedExtVectorType *T) { - // FIXME: Serialize this type (C++ only) - assert(false && "Cannot serialize dependent sized extended vector types"); -} - -void -PCHTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) { - Record.push_back(T->getDepth()); - Record.push_back(T->getIndex()); - Record.push_back(T->isParameterPack()); - Writer.AddIdentifierRef(T->getName(), Record); - Code = pch::TYPE_TEMPLATE_TYPE_PARM; -} - -void -PCHTypeWriter::VisitDependentNameType(const DependentNameType *T) { - Record.push_back(T->getKeyword()); - Writer.AddNestedNameSpecifier(T->getQualifier(), Record); - Writer.AddIdentifierRef(T->getIdentifier(), Record); - Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType() - : T->getCanonicalTypeInternal(), - Record); - Code = pch::TYPE_DEPENDENT_NAME; -} - -void -PCHTypeWriter::VisitDependentTemplateSpecializationType( - const DependentTemplateSpecializationType *T) { - Record.push_back(T->getKeyword()); - Writer.AddNestedNameSpecifier(T->getQualifier(), Record); - Writer.AddIdentifierRef(T->getIdentifier(), Record); - Record.push_back(T->getNumArgs()); - for (DependentTemplateSpecializationType::iterator - I = T->begin(), E = T->end(); I != E; ++I) - Writer.AddTemplateArgument(*I, Record); - Code = pch::TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION; -} - -void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) { - Record.push_back(T->getKeyword()); - Writer.AddNestedNameSpecifier(T->getQualifier(), Record); - Writer.AddTypeRef(T->getNamedType(), Record); - Code = pch::TYPE_ELABORATED; -} - -void PCHTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) { - Writer.AddDeclRef(T->getDecl(), Record); - Writer.AddTypeRef(T->getInjectedSpecializationType(), Record); - Code = pch::TYPE_INJECTED_CLASS_NAME; -} - -void PCHTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { - Writer.AddDeclRef(T->getDecl(), Record); - Code = pch::TYPE_OBJC_INTERFACE; -} - -void PCHTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) { - Writer.AddTypeRef(T->getBaseType(), Record); - Record.push_back(T->getNumProtocols()); - for (ObjCObjectType::qual_iterator I = T->qual_begin(), - E = T->qual_end(); I != E; ++I) - Writer.AddDeclRef(*I, Record); - Code = pch::TYPE_OBJC_OBJECT; -} - -void -PCHTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { - Writer.AddTypeRef(T->getPointeeType(), Record); - Code = pch::TYPE_OBJC_OBJECT_POINTER; -} - -namespace { - -class TypeLocWriter : public TypeLocVisitor { - PCHWriter &Writer; - PCHWriter::RecordData &Record; - -public: - TypeLocWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) - : Writer(Writer), Record(Record) { } - -#define ABSTRACT_TYPELOC(CLASS, PARENT) -#define TYPELOC(CLASS, PARENT) \ - void Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc); -#include "clang/AST/TypeLocNodes.def" - - void VisitArrayTypeLoc(ArrayTypeLoc TyLoc); - void VisitFunctionTypeLoc(FunctionTypeLoc TyLoc); -}; - -} - -void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { - // nothing to do -} -void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { - Writer.AddSourceLocation(TL.getBuiltinLoc(), Record); - if (TL.needsExtraLocalData()) { - Record.push_back(TL.getWrittenTypeSpec()); - Record.push_back(TL.getWrittenSignSpec()); - Record.push_back(TL.getWrittenWidthSpec()); - Record.push_back(TL.hasModeAttr()); - } -} -void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitPointerTypeLoc(PointerTypeLoc TL) { - Writer.AddSourceLocation(TL.getStarLoc(), Record); -} -void TypeLocWriter::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { - Writer.AddSourceLocation(TL.getCaretLoc(), Record); -} -void TypeLocWriter::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { - Writer.AddSourceLocation(TL.getAmpLoc(), Record); -} -void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { - Writer.AddSourceLocation(TL.getAmpAmpLoc(), Record); -} -void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { - Writer.AddSourceLocation(TL.getStarLoc(), Record); -} -void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) { - Writer.AddSourceLocation(TL.getLBracketLoc(), Record); - Writer.AddSourceLocation(TL.getRBracketLoc(), Record); - Record.push_back(TL.getSizeExpr() ? 1 : 0); - if (TL.getSizeExpr()) - Writer.AddStmt(TL.getSizeExpr()); -} -void TypeLocWriter::VisitConstantArrayTypeLoc(ConstantArrayTypeLoc TL) { - VisitArrayTypeLoc(TL); -} -void TypeLocWriter::VisitIncompleteArrayTypeLoc(IncompleteArrayTypeLoc TL) { - VisitArrayTypeLoc(TL); -} -void TypeLocWriter::VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) { - VisitArrayTypeLoc(TL); -} -void TypeLocWriter::VisitDependentSizedArrayTypeLoc( - DependentSizedArrayTypeLoc TL) { - VisitArrayTypeLoc(TL); -} -void TypeLocWriter::VisitDependentSizedExtVectorTypeLoc( - DependentSizedExtVectorTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitVectorTypeLoc(VectorTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { - Writer.AddSourceLocation(TL.getLParenLoc(), Record); - Writer.AddSourceLocation(TL.getRParenLoc(), Record); - for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) - Writer.AddDeclRef(TL.getArg(i), Record); -} -void TypeLocWriter::VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) { - VisitFunctionTypeLoc(TL); -} -void TypeLocWriter::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { - VisitFunctionTypeLoc(TL); -} -void TypeLocWriter::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitTypedefTypeLoc(TypedefTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { - Writer.AddSourceLocation(TL.getTypeofLoc(), Record); - Writer.AddSourceLocation(TL.getLParenLoc(), Record); - Writer.AddSourceLocation(TL.getRParenLoc(), Record); -} -void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { - Writer.AddSourceLocation(TL.getTypeofLoc(), Record); - Writer.AddSourceLocation(TL.getLParenLoc(), Record); - Writer.AddSourceLocation(TL.getRParenLoc(), Record); - Writer.AddTypeSourceInfo(TL.getUnderlyingTInfo(), Record); -} -void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitRecordTypeLoc(RecordTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitEnumTypeLoc(EnumTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc( - SubstTemplateTypeParmTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitTemplateSpecializationTypeLoc( - TemplateSpecializationTypeLoc TL) { - Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record); - Writer.AddSourceLocation(TL.getLAngleLoc(), Record); - Writer.AddSourceLocation(TL.getRAngleLoc(), Record); - for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) - Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(i).getArgument().getKind(), - TL.getArgLoc(i).getLocInfo(), Record); -} -void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { - Writer.AddSourceLocation(TL.getKeywordLoc(), Record); - Writer.AddSourceRange(TL.getQualifierRange(), Record); -} -void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { - Writer.AddSourceLocation(TL.getKeywordLoc(), Record); - Writer.AddSourceRange(TL.getQualifierRange(), Record); - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc( - DependentTemplateSpecializationTypeLoc TL) { - Writer.AddSourceLocation(TL.getKeywordLoc(), Record); - Writer.AddSourceRange(TL.getQualifierRange(), Record); - Writer.AddSourceLocation(TL.getNameLoc(), Record); - Writer.AddSourceLocation(TL.getLAngleLoc(), Record); - Writer.AddSourceLocation(TL.getRAngleLoc(), Record); - for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) - Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(I).getArgument().getKind(), - TL.getArgLoc(I).getLocInfo(), Record); -} -void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { - Writer.AddSourceLocation(TL.getNameLoc(), Record); -} -void TypeLocWriter::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { - Record.push_back(TL.hasBaseTypeAsWritten()); - Writer.AddSourceLocation(TL.getLAngleLoc(), Record); - Writer.AddSourceLocation(TL.getRAngleLoc(), Record); - for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) - Writer.AddSourceLocation(TL.getProtocolLoc(i), Record); -} -void TypeLocWriter::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { - Writer.AddSourceLocation(TL.getStarLoc(), Record); -} - -//===----------------------------------------------------------------------===// -// PCHWriter Implementation -//===----------------------------------------------------------------------===// - -static void EmitBlockID(unsigned ID, const char *Name, - llvm::BitstreamWriter &Stream, - PCHWriter::RecordData &Record) { - Record.clear(); - Record.push_back(ID); - Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record); - - // Emit the block name if present. - if (Name == 0 || Name[0] == 0) return; - Record.clear(); - while (*Name) - Record.push_back(*Name++); - Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME, Record); -} - -static void EmitRecordID(unsigned ID, const char *Name, - llvm::BitstreamWriter &Stream, - PCHWriter::RecordData &Record) { - Record.clear(); - Record.push_back(ID); - while (*Name) - Record.push_back(*Name++); - Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record); -} - -static void AddStmtsExprs(llvm::BitstreamWriter &Stream, - PCHWriter::RecordData &Record) { -#define RECORD(X) EmitRecordID(pch::X, #X, Stream, Record) - RECORD(STMT_STOP); - RECORD(STMT_NULL_PTR); - RECORD(STMT_NULL); - RECORD(STMT_COMPOUND); - RECORD(STMT_CASE); - RECORD(STMT_DEFAULT); - RECORD(STMT_LABEL); - RECORD(STMT_IF); - RECORD(STMT_SWITCH); - RECORD(STMT_WHILE); - RECORD(STMT_DO); - RECORD(STMT_FOR); - RECORD(STMT_GOTO); - RECORD(STMT_INDIRECT_GOTO); - RECORD(STMT_CONTINUE); - RECORD(STMT_BREAK); - RECORD(STMT_RETURN); - RECORD(STMT_DECL); - RECORD(STMT_ASM); - RECORD(EXPR_PREDEFINED); - RECORD(EXPR_DECL_REF); - RECORD(EXPR_INTEGER_LITERAL); - RECORD(EXPR_FLOATING_LITERAL); - RECORD(EXPR_IMAGINARY_LITERAL); - RECORD(EXPR_STRING_LITERAL); - RECORD(EXPR_CHARACTER_LITERAL); - RECORD(EXPR_PAREN); - RECORD(EXPR_UNARY_OPERATOR); - RECORD(EXPR_SIZEOF_ALIGN_OF); - RECORD(EXPR_ARRAY_SUBSCRIPT); - RECORD(EXPR_CALL); - RECORD(EXPR_MEMBER); - RECORD(EXPR_BINARY_OPERATOR); - RECORD(EXPR_COMPOUND_ASSIGN_OPERATOR); - RECORD(EXPR_CONDITIONAL_OPERATOR); - RECORD(EXPR_IMPLICIT_CAST); - RECORD(EXPR_CSTYLE_CAST); - RECORD(EXPR_COMPOUND_LITERAL); - RECORD(EXPR_EXT_VECTOR_ELEMENT); - RECORD(EXPR_INIT_LIST); - RECORD(EXPR_DESIGNATED_INIT); - RECORD(EXPR_IMPLICIT_VALUE_INIT); - RECORD(EXPR_VA_ARG); - RECORD(EXPR_ADDR_LABEL); - RECORD(EXPR_STMT); - RECORD(EXPR_TYPES_COMPATIBLE); - RECORD(EXPR_CHOOSE); - RECORD(EXPR_GNU_NULL); - RECORD(EXPR_SHUFFLE_VECTOR); - RECORD(EXPR_BLOCK); - RECORD(EXPR_BLOCK_DECL_REF); - RECORD(EXPR_OBJC_STRING_LITERAL); - RECORD(EXPR_OBJC_ENCODE); - RECORD(EXPR_OBJC_SELECTOR_EXPR); - RECORD(EXPR_OBJC_PROTOCOL_EXPR); - RECORD(EXPR_OBJC_IVAR_REF_EXPR); - RECORD(EXPR_OBJC_PROPERTY_REF_EXPR); - RECORD(EXPR_OBJC_KVC_REF_EXPR); - RECORD(EXPR_OBJC_MESSAGE_EXPR); - RECORD(EXPR_OBJC_SUPER_EXPR); - RECORD(STMT_OBJC_FOR_COLLECTION); - RECORD(STMT_OBJC_CATCH); - RECORD(STMT_OBJC_FINALLY); - RECORD(STMT_OBJC_AT_TRY); - RECORD(STMT_OBJC_AT_SYNCHRONIZED); - RECORD(STMT_OBJC_AT_THROW); - RECORD(EXPR_CXX_OPERATOR_CALL); - RECORD(EXPR_CXX_CONSTRUCT); - RECORD(EXPR_CXX_STATIC_CAST); - RECORD(EXPR_CXX_DYNAMIC_CAST); - RECORD(EXPR_CXX_REINTERPRET_CAST); - RECORD(EXPR_CXX_CONST_CAST); - RECORD(EXPR_CXX_FUNCTIONAL_CAST); - RECORD(EXPR_CXX_BOOL_LITERAL); - RECORD(EXPR_CXX_NULL_PTR_LITERAL); -#undef RECORD -} - -void PCHWriter::WriteBlockInfoBlock() { - RecordData Record; - Stream.EnterSubblock(llvm::bitc::BLOCKINFO_BLOCK_ID, 3); - -#define BLOCK(X) EmitBlockID(pch::X ## _ID, #X, Stream, Record) -#define RECORD(X) EmitRecordID(pch::X, #X, Stream, Record) - - // PCH Top-Level Block. - BLOCK(PCH_BLOCK); - RECORD(ORIGINAL_FILE_NAME); - RECORD(TYPE_OFFSET); - RECORD(DECL_OFFSET); - RECORD(LANGUAGE_OPTIONS); - RECORD(METADATA); - RECORD(IDENTIFIER_OFFSET); - RECORD(IDENTIFIER_TABLE); - RECORD(EXTERNAL_DEFINITIONS); - RECORD(SPECIAL_TYPES); - RECORD(STATISTICS); - RECORD(TENTATIVE_DEFINITIONS); - RECORD(UNUSED_STATIC_FUNCS); - RECORD(LOCALLY_SCOPED_EXTERNAL_DECLS); - RECORD(SELECTOR_OFFSETS); - RECORD(METHOD_POOL); - RECORD(PP_COUNTER_VALUE); - RECORD(SOURCE_LOCATION_OFFSETS); - RECORD(SOURCE_LOCATION_PRELOADS); - RECORD(STAT_CACHE); - RECORD(EXT_VECTOR_DECLS); - RECORD(VERSION_CONTROL_BRANCH_REVISION); - RECORD(UNUSED_STATIC_FUNCS); - RECORD(MACRO_DEFINITION_OFFSETS); - RECORD(CHAINED_METADATA); - - // SourceManager Block. - BLOCK(SOURCE_MANAGER_BLOCK); - RECORD(SM_SLOC_FILE_ENTRY); - RECORD(SM_SLOC_BUFFER_ENTRY); - RECORD(SM_SLOC_BUFFER_BLOB); - RECORD(SM_SLOC_INSTANTIATION_ENTRY); - RECORD(SM_LINE_TABLE); - - // Preprocessor Block. - BLOCK(PREPROCESSOR_BLOCK); - RECORD(PP_MACRO_OBJECT_LIKE); - RECORD(PP_MACRO_FUNCTION_LIKE); - RECORD(PP_TOKEN); - RECORD(PP_MACRO_INSTANTIATION); - RECORD(PP_MACRO_DEFINITION); - - // Decls and Types block. - BLOCK(DECLTYPES_BLOCK); - RECORD(TYPE_EXT_QUAL); - RECORD(TYPE_COMPLEX); - RECORD(TYPE_POINTER); - RECORD(TYPE_BLOCK_POINTER); - RECORD(TYPE_LVALUE_REFERENCE); - RECORD(TYPE_RVALUE_REFERENCE); - RECORD(TYPE_MEMBER_POINTER); - RECORD(TYPE_CONSTANT_ARRAY); - RECORD(TYPE_INCOMPLETE_ARRAY); - RECORD(TYPE_VARIABLE_ARRAY); - RECORD(TYPE_VECTOR); - RECORD(TYPE_EXT_VECTOR); - RECORD(TYPE_FUNCTION_PROTO); - RECORD(TYPE_FUNCTION_NO_PROTO); - RECORD(TYPE_TYPEDEF); - RECORD(TYPE_TYPEOF_EXPR); - RECORD(TYPE_TYPEOF); - RECORD(TYPE_RECORD); - RECORD(TYPE_ENUM); - RECORD(TYPE_OBJC_INTERFACE); - RECORD(TYPE_OBJC_OBJECT); - RECORD(TYPE_OBJC_OBJECT_POINTER); - RECORD(DECL_ATTR); - RECORD(DECL_TRANSLATION_UNIT); - RECORD(DECL_TYPEDEF); - RECORD(DECL_ENUM); - RECORD(DECL_RECORD); - RECORD(DECL_ENUM_CONSTANT); - RECORD(DECL_FUNCTION); - RECORD(DECL_OBJC_METHOD); - RECORD(DECL_OBJC_INTERFACE); - RECORD(DECL_OBJC_PROTOCOL); - RECORD(DECL_OBJC_IVAR); - RECORD(DECL_OBJC_AT_DEFS_FIELD); - RECORD(DECL_OBJC_CLASS); - RECORD(DECL_OBJC_FORWARD_PROTOCOL); - RECORD(DECL_OBJC_CATEGORY); - RECORD(DECL_OBJC_CATEGORY_IMPL); - RECORD(DECL_OBJC_IMPLEMENTATION); - RECORD(DECL_OBJC_COMPATIBLE_ALIAS); - RECORD(DECL_OBJC_PROPERTY); - RECORD(DECL_OBJC_PROPERTY_IMPL); - RECORD(DECL_FIELD); - RECORD(DECL_VAR); - RECORD(DECL_IMPLICIT_PARAM); - RECORD(DECL_PARM_VAR); - RECORD(DECL_FILE_SCOPE_ASM); - RECORD(DECL_BLOCK); - RECORD(DECL_CONTEXT_LEXICAL); - RECORD(DECL_CONTEXT_VISIBLE); - // Statements and Exprs can occur in the Decls and Types block. - AddStmtsExprs(Stream, Record); -#undef RECORD -#undef BLOCK - Stream.ExitBlock(); -} - -/// \brief Adjusts the given filename to only write out the portion of the -/// filename that is not part of the system root directory. -/// -/// \param Filename the file name to adjust. -/// -/// \param isysroot When non-NULL, the PCH file is a relocatable PCH file and -/// the returned filename will be adjusted by this system root. -/// -/// \returns either the original filename (if it needs no adjustment) or the -/// adjusted filename (which points into the @p Filename parameter). -static const char * -adjustFilenameForRelocatablePCH(const char *Filename, const char *isysroot) { - assert(Filename && "No file name to adjust?"); - - if (!isysroot) - return Filename; - - // Verify that the filename and the system root have the same prefix. - unsigned Pos = 0; - for (; Filename[Pos] && isysroot[Pos]; ++Pos) - if (Filename[Pos] != isysroot[Pos]) - return Filename; // Prefixes don't match. - - // We hit the end of the filename before we hit the end of the system root. - if (!Filename[Pos]) - return Filename; - - // If the file name has a '/' at the current position, skip over the '/'. - // We distinguish sysroot-based includes from absolute includes by the - // absence of '/' at the beginning of sysroot-based includes. - if (Filename[Pos] == '/') - ++Pos; - - return Filename + Pos; -} - -/// \brief Write the PCH metadata (e.g., i686-apple-darwin9). -void PCHWriter::WriteMetadata(ASTContext &Context, const char *isysroot) { - using namespace llvm; - - // Metadata - const TargetInfo &Target = Context.Target; - BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev(); - MetaAbbrev->Add(BitCodeAbbrevOp( - Chain ? pch::CHAINED_METADATA : pch::METADATA)); - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH major - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // PCH minor - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable - // Target triple or chained PCH name - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev); - - RecordData Record; - Record.push_back(Chain ? pch::CHAINED_METADATA : pch::METADATA); - Record.push_back(pch::VERSION_MAJOR); - Record.push_back(pch::VERSION_MINOR); - Record.push_back(CLANG_VERSION_MAJOR); - Record.push_back(CLANG_VERSION_MINOR); - Record.push_back(isysroot != 0); - // FIXME: This writes the absolute path for chained headers. - const std::string &BlobStr = Chain ? Chain->getFileName() : Target.getTriple().getTriple(); - Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, BlobStr); - - // Original file name - SourceManager &SM = Context.getSourceManager(); - if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { - BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev(); - FileAbbrev->Add(BitCodeAbbrevOp(pch::ORIGINAL_FILE_NAME)); - FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name - unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev); - - llvm::sys::Path MainFilePath(MainFile->getName()); - - MainFilePath.makeAbsolute(); - - const char *MainFileNameStr = MainFilePath.c_str(); - MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr, - isysroot); - RecordData Record; - Record.push_back(pch::ORIGINAL_FILE_NAME); - Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr); - } - - // Repository branch/version information. - BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev(); - RepoAbbrev->Add(BitCodeAbbrevOp(pch::VERSION_CONTROL_BRANCH_REVISION)); - RepoAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag - unsigned RepoAbbrevCode = Stream.EmitAbbrev(RepoAbbrev); - Record.clear(); - Record.push_back(pch::VERSION_CONTROL_BRANCH_REVISION); - Stream.EmitRecordWithBlob(RepoAbbrevCode, Record, - getClangFullRepositoryVersion()); -} - -/// \brief Write the LangOptions structure. -void PCHWriter::WriteLanguageOptions(const LangOptions &LangOpts) { - RecordData Record; - Record.push_back(LangOpts.Trigraphs); - Record.push_back(LangOpts.BCPLComment); // BCPL-style '//' comments. - Record.push_back(LangOpts.DollarIdents); // '$' allowed in identifiers. - Record.push_back(LangOpts.AsmPreprocessor); // Preprocessor in asm mode. - Record.push_back(LangOpts.GNUMode); // True in gnu99 mode false in c99 mode (etc) - Record.push_back(LangOpts.GNUKeywords); // Allow GNU-extension keywords - Record.push_back(LangOpts.ImplicitInt); // C89 implicit 'int'. - Record.push_back(LangOpts.Digraphs); // C94, C99 and C++ - Record.push_back(LangOpts.HexFloats); // C99 Hexadecimal float constants. - Record.push_back(LangOpts.C99); // C99 Support - Record.push_back(LangOpts.Microsoft); // Microsoft extensions. - Record.push_back(LangOpts.CPlusPlus); // C++ Support - Record.push_back(LangOpts.CPlusPlus0x); // C++0x Support - Record.push_back(LangOpts.CXXOperatorNames); // Treat C++ operator names as keywords. - - Record.push_back(LangOpts.ObjC1); // Objective-C 1 support enabled. - Record.push_back(LangOpts.ObjC2); // Objective-C 2 support enabled. - Record.push_back(LangOpts.ObjCNonFragileABI); // Objective-C - // modern abi enabled. - Record.push_back(LangOpts.ObjCNonFragileABI2); // Objective-C enhanced - // modern abi enabled. - Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled.. - - Record.push_back(LangOpts.PascalStrings); // Allow Pascal strings - Record.push_back(LangOpts.WritableStrings); // Allow writable strings - Record.push_back(LangOpts.LaxVectorConversions); - Record.push_back(LangOpts.AltiVec); - Record.push_back(LangOpts.Exceptions); // Support exception handling. - Record.push_back(LangOpts.SjLjExceptions); - - Record.push_back(LangOpts.NeXTRuntime); // Use NeXT runtime. - Record.push_back(LangOpts.Freestanding); // Freestanding implementation - Record.push_back(LangOpts.NoBuiltin); // Do not use builtin functions (-fno-builtin) - - // Whether static initializers are protected by locks. - Record.push_back(LangOpts.ThreadsafeStatics); - Record.push_back(LangOpts.POSIXThreads); - Record.push_back(LangOpts.Blocks); // block extension to C - Record.push_back(LangOpts.EmitAllDecls); // Emit all declarations, even if - // they are unused. - Record.push_back(LangOpts.MathErrno); // Math functions must respect errno - // (modulo the platform support). - - Record.push_back(LangOpts.getSignedOverflowBehavior()); - Record.push_back(LangOpts.HeinousExtensions); - - Record.push_back(LangOpts.Optimize); // Whether __OPTIMIZE__ should be defined. - Record.push_back(LangOpts.OptimizeSize); // Whether __OPTIMIZE_SIZE__ should be - // defined. - Record.push_back(LangOpts.Static); // Should __STATIC__ be defined (as - // opposed to __DYNAMIC__). - Record.push_back(LangOpts.PICLevel); // The value for __PIC__, if non-zero. - - Record.push_back(LangOpts.GNUInline); // Should GNU inline semantics be - // used (instead of C99 semantics). - Record.push_back(LangOpts.NoInline); // Should __NO_INLINE__ be defined. - Record.push_back(LangOpts.AccessControl); // Whether C++ access control should - // be enabled. - Record.push_back(LangOpts.CharIsSigned); // Whether char is a signed or - // unsigned type - Record.push_back(LangOpts.ShortWChar); // force wchar_t to be unsigned short - Record.push_back(LangOpts.getGCMode()); - Record.push_back(LangOpts.getVisibilityMode()); - Record.push_back(LangOpts.getStackProtectorMode()); - Record.push_back(LangOpts.InstantiationDepth); - Record.push_back(LangOpts.OpenCL); - Record.push_back(LangOpts.CatchUndefined); - Record.push_back(LangOpts.ElideConstructors); - Record.push_back(LangOpts.SpellChecking); - Stream.EmitRecord(pch::LANGUAGE_OPTIONS, Record); -} - -//===----------------------------------------------------------------------===// -// stat cache Serialization -//===----------------------------------------------------------------------===// - -namespace { -// Trait used for the on-disk hash table of stat cache results. -class PCHStatCacheTrait { -public: - typedef const char * key_type; - typedef key_type key_type_ref; - - typedef std::pair data_type; - typedef const data_type& data_type_ref; - - static unsigned ComputeHash(const char *path) { - return llvm::HashString(path); - } - - std::pair - EmitKeyDataLength(llvm::raw_ostream& Out, const char *path, - data_type_ref Data) { - unsigned StrLen = strlen(path); - clang::io::Emit16(Out, StrLen); - unsigned DataLen = 1; // result value - if (Data.first == 0) - DataLen += 4 + 4 + 2 + 8 + 8; - clang::io::Emit8(Out, DataLen); - return std::make_pair(StrLen + 1, DataLen); - } - - void EmitKey(llvm::raw_ostream& Out, const char *path, unsigned KeyLen) { - Out.write(path, KeyLen); - } - - void EmitData(llvm::raw_ostream& Out, key_type_ref, - data_type_ref Data, unsigned DataLen) { - using namespace clang::io; - uint64_t Start = Out.tell(); (void)Start; - - // Result of stat() - Emit8(Out, Data.first? 1 : 0); - - if (Data.first == 0) { - Emit32(Out, (uint32_t) Data.second.st_ino); - Emit32(Out, (uint32_t) Data.second.st_dev); - Emit16(Out, (uint16_t) Data.second.st_mode); - Emit64(Out, (uint64_t) Data.second.st_mtime); - Emit64(Out, (uint64_t) Data.second.st_size); - } - - assert(Out.tell() - Start == DataLen && "Wrong data length"); - } -}; -} // end anonymous namespace - -/// \brief Write the stat() system call cache to the PCH file. -void PCHWriter::WriteStatCache(MemorizeStatCalls &StatCalls) { - // Build the on-disk hash table containing information about every - // stat() call. - OnDiskChainedHashTableGenerator Generator; - unsigned NumStatEntries = 0; - for (MemorizeStatCalls::iterator Stat = StatCalls.begin(), - StatEnd = StatCalls.end(); - Stat != StatEnd; ++Stat, ++NumStatEntries) { - const char *Filename = Stat->first(); - Generator.insert(Filename, Stat->second); - } - - // Create the on-disk hash table in a buffer. - llvm::SmallString<4096> StatCacheData; - uint32_t BucketOffset; - { - llvm::raw_svector_ostream Out(StatCacheData); - // Make sure that no bucket is at offset 0 - clang::io::Emit32(Out, 0); - BucketOffset = Generator.Emit(Out); - } - - // Create a blob abbreviation - using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(pch::STAT_CACHE)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned StatCacheAbbrev = Stream.EmitAbbrev(Abbrev); - - // Write the stat cache - RecordData Record; - Record.push_back(pch::STAT_CACHE); - Record.push_back(BucketOffset); - Record.push_back(NumStatEntries); - Stream.EmitRecordWithBlob(StatCacheAbbrev, Record, StatCacheData.str()); -} - -//===----------------------------------------------------------------------===// -// Source Manager Serialization -//===----------------------------------------------------------------------===// - -/// \brief Create an abbreviation for the SLocEntry that refers to a -/// file. -static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { - using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_FILE_ENTRY)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives - // FileEntry fields. - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time - // HeaderFileInfo fields. - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isImport - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // DirInfo - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumIncludes - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // ControllingMacro - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name - return Stream.EmitAbbrev(Abbrev); -} - -/// \brief Create an abbreviation for the SLocEntry that refers to a -/// buffer. -static unsigned CreateSLocBufferAbbrev(llvm::BitstreamWriter &Stream) { - using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_BUFFER_ENTRY)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Include location - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Buffer name blob - return Stream.EmitAbbrev(Abbrev); -} - -/// \brief Create an abbreviation for the SLocEntry that refers to a -/// buffer's blob. -static unsigned CreateSLocBufferBlobAbbrev(llvm::BitstreamWriter &Stream) { - using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_BUFFER_BLOB)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Blob - return Stream.EmitAbbrev(Abbrev); -} - -/// \brief Create an abbreviation for the SLocEntry that refers to an -/// buffer. -static unsigned CreateSLocInstantiationAbbrev(llvm::BitstreamWriter &Stream) { - using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(pch::SM_SLOC_INSTANTIATION_ENTRY)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Offset - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Spelling location - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Start location - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // End location - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Token length - return Stream.EmitAbbrev(Abbrev); -} - -/// \brief Writes the block containing the serialized form of the -/// source manager. -/// -/// TODO: We should probably use an on-disk hash table (stored in a -/// blob), indexed based on the file name, so that we only create -/// entries for files that we actually need. In the common case (no -/// errors), we probably won't have to create file entries for any of -/// the files in the AST. -void PCHWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, - const Preprocessor &PP, - const char *isysroot) { - RecordData Record; - - // Enter the source manager block. - Stream.EnterSubblock(pch::SOURCE_MANAGER_BLOCK_ID, 3); - - // Abbreviations for the various kinds of source-location entries. - unsigned SLocFileAbbrv = CreateSLocFileAbbrev(Stream); - unsigned SLocBufferAbbrv = CreateSLocBufferAbbrev(Stream); - unsigned SLocBufferBlobAbbrv = CreateSLocBufferBlobAbbrev(Stream); - unsigned SLocInstantiationAbbrv = CreateSLocInstantiationAbbrev(Stream); - - // Write the line table. - if (SourceMgr.hasLineTable()) { - LineTableInfo &LineTable = SourceMgr.getLineTable(); - - // Emit the file names - Record.push_back(LineTable.getNumFilenames()); - for (unsigned I = 0, N = LineTable.getNumFilenames(); I != N; ++I) { - // Emit the file name - const char *Filename = LineTable.getFilename(I); - Filename = adjustFilenameForRelocatablePCH(Filename, isysroot); - unsigned FilenameLen = Filename? strlen(Filename) : 0; - Record.push_back(FilenameLen); - if (FilenameLen) - Record.insert(Record.end(), Filename, Filename + FilenameLen); - } - - // Emit the line entries - for (LineTableInfo::iterator L = LineTable.begin(), LEnd = LineTable.end(); - L != LEnd; ++L) { - // Emit the file ID - Record.push_back(L->first); - - // Emit the line entries - Record.push_back(L->second.size()); - for (std::vector::iterator LE = L->second.begin(), - LEEnd = L->second.end(); - LE != LEEnd; ++LE) { - Record.push_back(LE->FileOffset); - Record.push_back(LE->LineNo); - Record.push_back(LE->FilenameID); - Record.push_back((unsigned)LE->FileKind); - Record.push_back(LE->IncludeOffset); - } - } - Stream.EmitRecord(pch::SM_LINE_TABLE, Record); - } - - // Write out the source location entry table. We skip the first - // entry, which is always the same dummy entry. - std::vector SLocEntryOffsets; - RecordData PreloadSLocs; - SLocEntryOffsets.reserve(SourceMgr.sloc_entry_size() - 1); - for (unsigned I = 1, N = SourceMgr.sloc_entry_size(); I != N; ++I) { - // Get this source location entry. - const SrcMgr::SLocEntry *SLoc = &SourceMgr.getSLocEntry(I); - - // Record the offset of this source-location entry. - SLocEntryOffsets.push_back(Stream.GetCurrentBitNo()); - - // Figure out which record code to use. - unsigned Code; - if (SLoc->isFile()) { - if (SLoc->getFile().getContentCache()->Entry) - Code = pch::SM_SLOC_FILE_ENTRY; - else - Code = pch::SM_SLOC_BUFFER_ENTRY; - } else - Code = pch::SM_SLOC_INSTANTIATION_ENTRY; - Record.clear(); - Record.push_back(Code); - - Record.push_back(SLoc->getOffset()); - if (SLoc->isFile()) { - const SrcMgr::FileInfo &File = SLoc->getFile(); - Record.push_back(File.getIncludeLoc().getRawEncoding()); - Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding - Record.push_back(File.hasLineDirectives()); - - const SrcMgr::ContentCache *Content = File.getContentCache(); - if (Content->Entry) { - // The source location entry is a file. The blob associated - // with this entry is the file name. - - // Emit size/modification time for this file. - Record.push_back(Content->Entry->getSize()); - Record.push_back(Content->Entry->getModificationTime()); - - // Emit header-search information associated with this file. - HeaderFileInfo HFI; - HeaderSearch &HS = PP.getHeaderSearchInfo(); - if (Content->Entry->getUID() < HS.header_file_size()) - HFI = HS.header_file_begin()[Content->Entry->getUID()]; - Record.push_back(HFI.isImport); - Record.push_back(HFI.DirInfo); - Record.push_back(HFI.NumIncludes); - AddIdentifierRef(HFI.ControllingMacro, Record); - - // Turn the file name into an absolute path, if it isn't already. - const char *Filename = Content->Entry->getName(); - llvm::sys::Path FilePath(Filename, strlen(Filename)); - FilePath.makeAbsolute(); - Filename = FilePath.c_str(); - - Filename = adjustFilenameForRelocatablePCH(Filename, isysroot); - Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename); - - // FIXME: For now, preload all file source locations, so that - // we get the appropriate File entries in the reader. This is - // a temporary measure. - PreloadSLocs.push_back(SLocEntryOffsets.size()); - } else { - // The source location entry is a buffer. The blob associated - // with this entry contains the contents of the buffer. - - // We add one to the size so that we capture the trailing NULL - // that is required by llvm::MemoryBuffer::getMemBuffer (on - // the reader side). - const llvm::MemoryBuffer *Buffer - = Content->getBuffer(PP.getDiagnostics(), PP.getSourceManager()); - const char *Name = Buffer->getBufferIdentifier(); - Stream.EmitRecordWithBlob(SLocBufferAbbrv, Record, - llvm::StringRef(Name, strlen(Name) + 1)); - Record.clear(); - Record.push_back(pch::SM_SLOC_BUFFER_BLOB); - Stream.EmitRecordWithBlob(SLocBufferBlobAbbrv, Record, - llvm::StringRef(Buffer->getBufferStart(), - Buffer->getBufferSize() + 1)); - - if (strcmp(Name, "") == 0) - PreloadSLocs.push_back(SLocEntryOffsets.size()); - } - } else { - // The source location entry is an instantiation. - const SrcMgr::InstantiationInfo &Inst = SLoc->getInstantiation(); - Record.push_back(Inst.getSpellingLoc().getRawEncoding()); - Record.push_back(Inst.getInstantiationLocStart().getRawEncoding()); - Record.push_back(Inst.getInstantiationLocEnd().getRawEncoding()); - - // Compute the token length for this macro expansion. - unsigned NextOffset = SourceMgr.getNextOffset(); - if (I + 1 != N) - NextOffset = SourceMgr.getSLocEntry(I + 1).getOffset(); - Record.push_back(NextOffset - SLoc->getOffset() - 1); - Stream.EmitRecordWithAbbrev(SLocInstantiationAbbrv, Record); - } - } - - Stream.ExitBlock(); - - if (SLocEntryOffsets.empty()) - return; - - // Write the source-location offsets table into the PCH block. This - // table is used for lazily loading source-location information. - using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(pch::SOURCE_LOCATION_OFFSETS)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // next offset - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets - unsigned SLocOffsetsAbbrev = Stream.EmitAbbrev(Abbrev); - - Record.clear(); - Record.push_back(pch::SOURCE_LOCATION_OFFSETS); - Record.push_back(SLocEntryOffsets.size()); - Record.push_back(SourceMgr.getNextOffset()); - Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, - (const char *)&SLocEntryOffsets.front(), - SLocEntryOffsets.size()*sizeof(SLocEntryOffsets[0])); - - // Write the source location entry preloads array, telling the PCH - // reader which source locations entries it should load eagerly. - Stream.EmitRecord(pch::SOURCE_LOCATION_PRELOADS, PreloadSLocs); -} - -//===----------------------------------------------------------------------===// -// Preprocessor Serialization -//===----------------------------------------------------------------------===// - -/// \brief Writes the block containing the serialized form of the -/// preprocessor. -/// -void PCHWriter::WritePreprocessor(const Preprocessor &PP) { - RecordData Record; - - // If the preprocessor __COUNTER__ value has been bumped, remember it. - if (PP.getCounterValue() != 0) { - Record.push_back(PP.getCounterValue()); - Stream.EmitRecord(pch::PP_COUNTER_VALUE, Record); - Record.clear(); - } - - // Enter the preprocessor block. - Stream.EnterSubblock(pch::PREPROCESSOR_BLOCK_ID, 2); - - // If the PCH file contains __DATE__ or __TIME__ emit a warning about this. - // FIXME: use diagnostics subsystem for localization etc. - if (PP.SawDateOrTime()) - fprintf(stderr, "warning: precompiled header used __DATE__ or __TIME__.\n"); - - // Loop over all the macro definitions that are live at the end of the file, - // emitting each to the PP section. - PreprocessingRecord *PPRec = PP.getPreprocessingRecord(); - for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); - I != E; ++I) { - // FIXME: This emits macros in hash table order, we should do it in a stable - // order so that output is reproducible. - MacroInfo *MI = I->second; - - // Don't emit builtin macros like __LINE__ to the PCH file unless they have - // been redefined by the header (in which case they are not isBuiltinMacro). - if (MI->isBuiltinMacro()) - continue; - - AddIdentifierRef(I->first, Record); - MacroOffsets[I->first] = Stream.GetCurrentBitNo(); - Record.push_back(MI->getDefinitionLoc().getRawEncoding()); - Record.push_back(MI->isUsed()); - - unsigned Code; - if (MI->isObjectLike()) { - Code = pch::PP_MACRO_OBJECT_LIKE; - } else { - Code = pch::PP_MACRO_FUNCTION_LIKE; - - Record.push_back(MI->isC99Varargs()); - Record.push_back(MI->isGNUVarargs()); - Record.push_back(MI->getNumArgs()); - for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end(); - I != E; ++I) - AddIdentifierRef(*I, Record); - } - - // If we have a detailed preprocessing record, record the macro definition - // ID that corresponds to this macro. - if (PPRec) - Record.push_back(getMacroDefinitionID(PPRec->findMacroDefinition(MI))); - - Stream.EmitRecord(Code, Record); - Record.clear(); - - // Emit the tokens array. - for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) { - // Note that we know that the preprocessor does not have any annotation - // tokens in it because they are created by the parser, and thus can't be - // in a macro definition. - const Token &Tok = MI->getReplacementToken(TokNo); - - Record.push_back(Tok.getLocation().getRawEncoding()); - Record.push_back(Tok.getLength()); - - // FIXME: When reading literal tokens, reconstruct the literal pointer if - // it is needed. - AddIdentifierRef(Tok.getIdentifierInfo(), Record); - - // FIXME: Should translate token kind to a stable encoding. - Record.push_back(Tok.getKind()); - // FIXME: Should translate token flags to a stable encoding. - Record.push_back(Tok.getFlags()); - - Stream.EmitRecord(pch::PP_TOKEN, Record); - Record.clear(); - } - ++NumMacros; - } - - // If the preprocessor has a preprocessing record, emit it. - unsigned NumPreprocessingRecords = 0; - if (PPRec) { - for (PreprocessingRecord::iterator E = PPRec->begin(), EEnd = PPRec->end(); - E != EEnd; ++E) { - Record.clear(); - - if (MacroInstantiation *MI = dyn_cast(*E)) { - Record.push_back(NumPreprocessingRecords++); - AddSourceLocation(MI->getSourceRange().getBegin(), Record); - AddSourceLocation(MI->getSourceRange().getEnd(), Record); - AddIdentifierRef(MI->getName(), Record); - Record.push_back(getMacroDefinitionID(MI->getDefinition())); - Stream.EmitRecord(pch::PP_MACRO_INSTANTIATION, Record); - continue; - } - - if (MacroDefinition *MD = dyn_cast(*E)) { - // Record this macro definition's location. - pch::IdentID ID = getMacroDefinitionID(MD); - if (ID != MacroDefinitionOffsets.size()) { - if (ID > MacroDefinitionOffsets.size()) - MacroDefinitionOffsets.resize(ID + 1); - - MacroDefinitionOffsets[ID] = Stream.GetCurrentBitNo(); - } else - MacroDefinitionOffsets.push_back(Stream.GetCurrentBitNo()); - - Record.push_back(NumPreprocessingRecords++); - Record.push_back(ID); - AddSourceLocation(MD->getSourceRange().getBegin(), Record); - AddSourceLocation(MD->getSourceRange().getEnd(), Record); - AddIdentifierRef(MD->getName(), Record); - AddSourceLocation(MD->getLocation(), Record); - Stream.EmitRecord(pch::PP_MACRO_DEFINITION, Record); - continue; - } - } - } - - Stream.ExitBlock(); - - // Write the offsets table for the preprocessing record. - if (NumPreprocessingRecords > 0) { - // Write the offsets table for identifier IDs. - using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(pch::MACRO_DEFINITION_OFFSETS)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of records - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macro defs - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned MacroDefOffsetAbbrev = Stream.EmitAbbrev(Abbrev); - - Record.clear(); - Record.push_back(pch::MACRO_DEFINITION_OFFSETS); - Record.push_back(NumPreprocessingRecords); - Record.push_back(MacroDefinitionOffsets.size()); - Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record, - (const char *)&MacroDefinitionOffsets.front(), - MacroDefinitionOffsets.size() * sizeof(uint32_t)); - } -} - -//===----------------------------------------------------------------------===// -// Type Serialization -//===----------------------------------------------------------------------===// - -/// \brief Write the representation of a type to the PCH stream. -void PCHWriter::WriteType(QualType T) { - pch::TypeID &ID = TypeIDs[T]; - if (ID == 0) // we haven't seen this type before. - ID = NextTypeID++; - - // Record the offset for this type. - if (TypeOffsets.size() == ID - pch::NUM_PREDEF_TYPE_IDS) - TypeOffsets.push_back(Stream.GetCurrentBitNo()); - else if (TypeOffsets.size() < ID - pch::NUM_PREDEF_TYPE_IDS) { - TypeOffsets.resize(ID + 1 - pch::NUM_PREDEF_TYPE_IDS); - TypeOffsets[ID - pch::NUM_PREDEF_TYPE_IDS] = Stream.GetCurrentBitNo(); - } - - RecordData Record; - - // Emit the type's representation. - PCHTypeWriter W(*this, Record); - - if (T.hasLocalNonFastQualifiers()) { - Qualifiers Qs = T.getLocalQualifiers(); - AddTypeRef(T.getLocalUnqualifiedType(), Record); - Record.push_back(Qs.getAsOpaqueValue()); - W.Code = pch::TYPE_EXT_QUAL; - } else { - switch (T->getTypeClass()) { - // For all of the concrete, non-dependent types, call the - // appropriate visitor function. -#define TYPE(Class, Base) \ - case Type::Class: W.Visit##Class##Type(cast(T)); break; -#define ABSTRACT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.def" - } - } - - // Emit the serialized record. - Stream.EmitRecord(W.Code, Record); - - // Flush any expressions that were written as part of this type. - FlushStmts(); -} - -//===----------------------------------------------------------------------===// -// Declaration Serialization -//===----------------------------------------------------------------------===// - -/// \brief Write the block containing all of the declaration IDs -/// lexically declared within the given DeclContext. -/// -/// \returns the offset of the DECL_CONTEXT_LEXICAL block within the -/// bistream, or 0 if no block was written. -uint64_t PCHWriter::WriteDeclContextLexicalBlock(ASTContext &Context, - DeclContext *DC) { - if (DC->decls_empty()) - return 0; - - uint64_t Offset = Stream.GetCurrentBitNo(); - RecordData Record; - for (DeclContext::decl_iterator D = DC->decls_begin(), DEnd = DC->decls_end(); - D != DEnd; ++D) - AddDeclRef(*D, Record); - - ++NumLexicalDeclContexts; - Stream.EmitRecord(pch::DECL_CONTEXT_LEXICAL, Record); - return Offset; -} - -/// \brief Write the block containing all of the declaration IDs -/// visible from the given DeclContext. -/// -/// \returns the offset of the DECL_CONTEXT_VISIBLE block within the -/// bistream, or 0 if no block was written. -uint64_t PCHWriter::WriteDeclContextVisibleBlock(ASTContext &Context, - DeclContext *DC) { - if (DC->getPrimaryContext() != DC) - return 0; - - // Since there is no name lookup into functions or methods, don't bother to - // build a visible-declarations table for these entities. - if (DC->isFunctionOrMethod()) - return 0; - - // If not in C++, we perform name lookup for the translation unit via the - // IdentifierInfo chains, don't bother to build a visible-declarations table. - // FIXME: In C++ we need the visible declarations in order to "see" the - // friend declarations, is there a way to do this without writing the table ? - if (DC->isTranslationUnit() && !Context.getLangOptions().CPlusPlus) - return 0; - - // Force the DeclContext to build a its name-lookup table. - DC->lookup(DeclarationName()); - - // Serialize the contents of the mapping used for lookup. Note that, - // although we have two very different code paths, the serialized - // representation is the same for both cases: a declaration name, - // followed by a size, followed by references to the visible - // declarations that have that name. - uint64_t Offset = Stream.GetCurrentBitNo(); - RecordData Record; - StoredDeclsMap *Map = static_cast(DC->getLookupPtr()); - if (!Map) - return 0; - - for (StoredDeclsMap::iterator D = Map->begin(), DEnd = Map->end(); - D != DEnd; ++D) { - AddDeclarationName(D->first, Record); - DeclContext::lookup_result Result = D->second.getLookupResult(Context); - Record.push_back(Result.second - Result.first); - for (; Result.first != Result.second; ++Result.first) - AddDeclRef(*Result.first, Record); - } - - if (Record.size() == 0) - return 0; - - Stream.EmitRecord(pch::DECL_CONTEXT_VISIBLE, Record); - ++NumVisibleDeclContexts; - return Offset; -} - -//===----------------------------------------------------------------------===// -// Global Method Pool and Selector Serialization -//===----------------------------------------------------------------------===// - -namespace { -// Trait used for the on-disk hash table used in the method pool. -class PCHMethodPoolTrait { - PCHWriter &Writer; - -public: - typedef Selector key_type; - typedef key_type key_type_ref; - - typedef std::pair data_type; - typedef const data_type& data_type_ref; - - explicit PCHMethodPoolTrait(PCHWriter &Writer) : Writer(Writer) { } - - static unsigned ComputeHash(Selector Sel) { - unsigned N = Sel.getNumArgs(); - if (N == 0) - ++N; - unsigned R = 5381; - for (unsigned I = 0; I != N; ++I) - if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I)) - R = llvm::HashString(II->getName(), R); - return R; - } - - std::pair - EmitKeyDataLength(llvm::raw_ostream& Out, Selector Sel, - data_type_ref Methods) { - unsigned KeyLen = 2 + (Sel.getNumArgs()? Sel.getNumArgs() * 4 : 4); - clang::io::Emit16(Out, KeyLen); - unsigned DataLen = 2 + 2; // 2 bytes for each of the method counts - for (const ObjCMethodList *Method = &Methods.first; Method; - Method = Method->Next) - if (Method->Method) - DataLen += 4; - for (const ObjCMethodList *Method = &Methods.second; Method; - Method = Method->Next) - if (Method->Method) - DataLen += 4; - clang::io::Emit16(Out, DataLen); - return std::make_pair(KeyLen, DataLen); - } - - void EmitKey(llvm::raw_ostream& Out, Selector Sel, unsigned) { - uint64_t Start = Out.tell(); - assert((Start >> 32) == 0 && "Selector key offset too large"); - Writer.SetSelectorOffset(Sel, Start); - unsigned N = Sel.getNumArgs(); - clang::io::Emit16(Out, N); - if (N == 0) - N = 1; - for (unsigned I = 0; I != N; ++I) - clang::io::Emit32(Out, - Writer.getIdentifierRef(Sel.getIdentifierInfoForSlot(I))); - } - - void EmitData(llvm::raw_ostream& Out, key_type_ref, - data_type_ref Methods, unsigned DataLen) { - uint64_t Start = Out.tell(); (void)Start; - unsigned NumInstanceMethods = 0; - for (const ObjCMethodList *Method = &Methods.first; Method; - Method = Method->Next) - if (Method->Method) - ++NumInstanceMethods; - - unsigned NumFactoryMethods = 0; - for (const ObjCMethodList *Method = &Methods.second; Method; - Method = Method->Next) - if (Method->Method) - ++NumFactoryMethods; - - clang::io::Emit16(Out, NumInstanceMethods); - clang::io::Emit16(Out, NumFactoryMethods); - for (const ObjCMethodList *Method = &Methods.first; Method; - Method = Method->Next) - if (Method->Method) - clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); - for (const ObjCMethodList *Method = &Methods.second; Method; - Method = Method->Next) - if (Method->Method) - clang::io::Emit32(Out, Writer.getDeclID(Method->Method)); - - assert(Out.tell() - Start == DataLen && "Data length is wrong"); - } -}; -} // end anonymous namespace - -/// \brief Write the method pool into the PCH file. -/// -/// The method pool contains both instance and factory methods, stored -/// in an on-disk hash table indexed by the selector. -void PCHWriter::WriteMethodPool(Sema &SemaRef) { - using namespace llvm; - - // Create and write out the blob that contains the instance and - // factor method pools. - bool Empty = true; - { - OnDiskChainedHashTableGenerator Generator; - - // Create the on-disk hash table representation. Start by - // iterating through the instance method pool. - PCHMethodPoolTrait::key_type Key; - unsigned NumSelectorsInMethodPool = 0; - for (llvm::DenseMap::iterator - Instance = SemaRef.InstanceMethodPool.begin(), - InstanceEnd = SemaRef.InstanceMethodPool.end(); - Instance != InstanceEnd; ++Instance) { - // Check whether there is a factory method with the same - // selector. - llvm::DenseMap::iterator Factory - = SemaRef.FactoryMethodPool.find(Instance->first); - - if (Factory == SemaRef.FactoryMethodPool.end()) - Generator.insert(Instance->first, - std::make_pair(Instance->second, - ObjCMethodList())); - else - Generator.insert(Instance->first, - std::make_pair(Instance->second, Factory->second)); - - ++NumSelectorsInMethodPool; - Empty = false; - } - - // Now iterate through the factory method pool, to pick up any - // selectors that weren't already in the instance method pool. - for (llvm::DenseMap::iterator - Factory = SemaRef.FactoryMethodPool.begin(), - FactoryEnd = SemaRef.FactoryMethodPool.end(); - Factory != FactoryEnd; ++Factory) { - // Check whether there is an instance method with the same - // selector. If so, there is no work to do here. - llvm::DenseMap::iterator Instance - = SemaRef.InstanceMethodPool.find(Factory->first); - - if (Instance == SemaRef.InstanceMethodPool.end()) { - Generator.insert(Factory->first, - std::make_pair(ObjCMethodList(), Factory->second)); - ++NumSelectorsInMethodPool; - } - - Empty = false; - } - - if (Empty && SelectorOffsets.empty()) - return; - - // Create the on-disk hash table in a buffer. - llvm::SmallString<4096> MethodPool; - uint32_t BucketOffset; - SelectorOffsets.resize(SelVector.size()); - { - PCHMethodPoolTrait Trait(*this); - llvm::raw_svector_ostream Out(MethodPool); - // Make sure that no bucket is at offset 0 - clang::io::Emit32(Out, 0); - BucketOffset = Generator.Emit(Out, Trait); - - // For every selector that we have seen but which was not - // written into the hash table, write the selector itself and - // record it's offset. - for (unsigned I = 0, N = SelVector.size(); I != N; ++I) - if (SelectorOffsets[I] == 0) - Trait.EmitKey(Out, SelVector[I], 0); - } - - // Create a blob abbreviation - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(pch::METHOD_POOL)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned MethodPoolAbbrev = Stream.EmitAbbrev(Abbrev); - - // Write the method pool - RecordData Record; - Record.push_back(pch::METHOD_POOL); - Record.push_back(BucketOffset); - Record.push_back(NumSelectorsInMethodPool); - Stream.EmitRecordWithBlob(MethodPoolAbbrev, Record, MethodPool.str()); - - // Create a blob abbreviation for the selector table offsets. - Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(pch::SELECTOR_OFFSETS)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // index - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned SelectorOffsetAbbrev = Stream.EmitAbbrev(Abbrev); - - // Write the selector offsets table. - Record.clear(); - Record.push_back(pch::SELECTOR_OFFSETS); - Record.push_back(SelectorOffsets.size()); - Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record, - (const char *)&SelectorOffsets.front(), - SelectorOffsets.size() * 4); - } -} - -//===----------------------------------------------------------------------===// -// Identifier Table Serialization -//===----------------------------------------------------------------------===// - -namespace { -class PCHIdentifierTableTrait { - PCHWriter &Writer; - Preprocessor &PP; - - /// \brief Determines whether this is an "interesting" identifier - /// that needs a full IdentifierInfo structure written into the hash - /// table. - static bool isInterestingIdentifier(const IdentifierInfo *II) { - return II->isPoisoned() || - II->isExtensionToken() || - II->hasMacroDefinition() || - II->getObjCOrBuiltinID() || - II->getFETokenInfo(); - } - -public: - typedef const IdentifierInfo* key_type; - typedef key_type key_type_ref; - - typedef pch::IdentID data_type; - typedef data_type data_type_ref; - - PCHIdentifierTableTrait(PCHWriter &Writer, Preprocessor &PP) - : Writer(Writer), PP(PP) { } - - static unsigned ComputeHash(const IdentifierInfo* II) { - return llvm::HashString(II->getName()); - } - - std::pair - EmitKeyDataLength(llvm::raw_ostream& Out, const IdentifierInfo* II, - pch::IdentID ID) { - unsigned KeyLen = II->getLength() + 1; - unsigned DataLen = 4; // 4 bytes for the persistent ID << 1 - if (isInterestingIdentifier(II)) { - DataLen += 2; // 2 bytes for builtin ID, flags - if (II->hasMacroDefinition() && - !PP.getMacroInfo(const_cast(II))->isBuiltinMacro()) - DataLen += 4; - for (IdentifierResolver::iterator D = IdentifierResolver::begin(II), - DEnd = IdentifierResolver::end(); - D != DEnd; ++D) - DataLen += sizeof(pch::DeclID); - } - clang::io::Emit16(Out, DataLen); - // We emit the key length after the data length so that every - // string is preceded by a 16-bit length. This matches the PTH - // format for storing identifiers. - clang::io::Emit16(Out, KeyLen); - return std::make_pair(KeyLen, DataLen); - } - - void EmitKey(llvm::raw_ostream& Out, const IdentifierInfo* II, - unsigned KeyLen) { - // Record the location of the key data. This is used when generating - // the mapping from persistent IDs to strings. - Writer.SetIdentifierOffset(II, Out.tell()); - Out.write(II->getNameStart(), KeyLen); - } - - void EmitData(llvm::raw_ostream& Out, const IdentifierInfo* II, - pch::IdentID ID, unsigned) { - if (!isInterestingIdentifier(II)) { - clang::io::Emit32(Out, ID << 1); - return; - } - - clang::io::Emit32(Out, (ID << 1) | 0x01); - uint32_t Bits = 0; - bool hasMacroDefinition = - II->hasMacroDefinition() && - !PP.getMacroInfo(const_cast(II))->isBuiltinMacro(); - Bits = (uint32_t)II->getObjCOrBuiltinID(); - Bits = (Bits << 1) | unsigned(hasMacroDefinition); - Bits = (Bits << 1) | unsigned(II->isExtensionToken()); - Bits = (Bits << 1) | unsigned(II->isPoisoned()); - Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword()); - clang::io::Emit16(Out, Bits); - - if (hasMacroDefinition) - clang::io::Emit32(Out, Writer.getMacroOffset(II)); - - // Emit the declaration IDs in reverse order, because the - // IdentifierResolver provides the declarations as they would be - // visible (e.g., the function "stat" would come before the struct - // "stat"), but IdentifierResolver::AddDeclToIdentifierChain() - // adds declarations to the end of the list (so we need to see the - // struct "status" before the function "status"). - llvm::SmallVector Decls(IdentifierResolver::begin(II), - IdentifierResolver::end()); - for (llvm::SmallVector::reverse_iterator D = Decls.rbegin(), - DEnd = Decls.rend(); - D != DEnd; ++D) - clang::io::Emit32(Out, Writer.getDeclID(*D)); - } -}; -} // end anonymous namespace - -/// \brief Write the identifier table into the PCH file. -/// -/// The identifier table consists of a blob containing string data -/// (the actual identifiers themselves) and a separate "offsets" index -/// that maps identifier IDs to locations within the blob. -void PCHWriter::WriteIdentifierTable(Preprocessor &PP) { - using namespace llvm; - - // Create and write out the blob that contains the identifier - // strings. - { - OnDiskChainedHashTableGenerator Generator; - - // Look for any identifiers that were named while processing the - // headers, but are otherwise not needed. We add these to the hash - // table to enable checking of the predefines buffer in the case - // where the user adds new macro definitions when building the PCH - // file. - for (IdentifierTable::iterator ID = PP.getIdentifierTable().begin(), - IDEnd = PP.getIdentifierTable().end(); - ID != IDEnd; ++ID) - getIdentifierRef(ID->second); - - // Create the on-disk hash table representation. - IdentifierOffsets.resize(IdentifierIDs.size()); - for (llvm::DenseMap::iterator - ID = IdentifierIDs.begin(), IDEnd = IdentifierIDs.end(); - ID != IDEnd; ++ID) { - assert(ID->first && "NULL identifier in identifier table"); - Generator.insert(ID->first, ID->second); - } - - // Create the on-disk hash table in a buffer. - llvm::SmallString<4096> IdentifierTable; - uint32_t BucketOffset; - { - PCHIdentifierTableTrait Trait(*this, PP); - llvm::raw_svector_ostream Out(IdentifierTable); - // Make sure that no bucket is at offset 0 - clang::io::Emit32(Out, 0); - BucketOffset = Generator.Emit(Out, Trait); - } - - // Create a blob abbreviation - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(pch::IDENTIFIER_TABLE)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned IDTableAbbrev = Stream.EmitAbbrev(Abbrev); - - // Write the identifier table - RecordData Record; - Record.push_back(pch::IDENTIFIER_TABLE); - Record.push_back(BucketOffset); - Stream.EmitRecordWithBlob(IDTableAbbrev, Record, IdentifierTable.str()); - } - - // Write the offsets table for identifier IDs. - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(pch::IDENTIFIER_OFFSET)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of identifiers - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned IdentifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev); - - RecordData Record; - Record.push_back(pch::IDENTIFIER_OFFSET); - Record.push_back(IdentifierOffsets.size()); - Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record, - (const char *)&IdentifierOffsets.front(), - IdentifierOffsets.size() * sizeof(uint32_t)); -} - -//===----------------------------------------------------------------------===// -// General Serialization Routines -//===----------------------------------------------------------------------===// - -/// \brief Write a record containing the given attributes. -void PCHWriter::WriteAttributeRecord(const Attr *Attr) { - RecordData Record; - for (; Attr; Attr = Attr->getNext()) { - Record.push_back(Attr->getKind()); // FIXME: stable encoding, target attrs - Record.push_back(Attr->isInherited()); - switch (Attr->getKind()) { - default: - assert(0 && "Does not support PCH writing for this attribute yet!"); - break; - case attr::Alias: - AddString(cast(Attr)->getAliasee(), Record); - break; - - case attr::AlignMac68k: - break; - - case attr::Aligned: - Record.push_back(cast(Attr)->getAlignment()); - break; - - case attr::AlwaysInline: - break; - - case attr::AnalyzerNoReturn: - break; - - case attr::Annotate: - AddString(cast(Attr)->getAnnotation(), Record); - break; - - case attr::AsmLabel: - AddString(cast(Attr)->getLabel(), Record); - break; - - case attr::BaseCheck: - break; - - case attr::Blocks: - Record.push_back(cast(Attr)->getType()); // FIXME: stable - break; - - case attr::CDecl: - break; - - case attr::Cleanup: - AddDeclRef(cast(Attr)->getFunctionDecl(), Record); - break; - - case attr::Const: - break; - - case attr::Constructor: - Record.push_back(cast(Attr)->getPriority()); - break; - - case attr::DLLExport: - case attr::DLLImport: - case attr::Deprecated: - break; - - case attr::Destructor: - Record.push_back(cast(Attr)->getPriority()); - break; - - case attr::FastCall: - case attr::Final: - break; - - case attr::Format: { - const FormatAttr *Format = cast(Attr); - AddString(Format->getType(), Record); - Record.push_back(Format->getFormatIdx()); - Record.push_back(Format->getFirstArg()); - break; - } - - case attr::FormatArg: { - const FormatArgAttr *Format = cast(Attr); - Record.push_back(Format->getFormatIdx()); - break; - } - - case attr::Sentinel : { - const SentinelAttr *Sentinel = cast(Attr); - Record.push_back(Sentinel->getSentinel()); - Record.push_back(Sentinel->getNullPos()); - break; - } - - case attr::GNUInline: - case attr::Hiding: - case attr::IBAction: - case attr::IBOutlet: - case attr::Malloc: - case attr::NoDebug: - case attr::NoInline: - case attr::NoReturn: - case attr::NoThrow: - break; - - case attr::IBOutletCollection: { - const IBOutletCollectionAttr *ICA = cast(Attr); - AddDeclRef(ICA->getClass(), Record); - break; - } - - case attr::NonNull: { - const NonNullAttr *NonNull = cast(Attr); - Record.push_back(NonNull->size()); - Record.insert(Record.end(), NonNull->begin(), NonNull->end()); - break; - } - - case attr::CFReturnsNotRetained: - case attr::CFReturnsRetained: - case attr::NSReturnsNotRetained: - case attr::NSReturnsRetained: - case attr::ObjCException: - case attr::ObjCNSObject: - case attr::Overloadable: - case attr::Override: - break; - - case attr::MaxFieldAlignment: - Record.push_back(cast(Attr)->getAlignment()); - break; - - case attr::Packed: - break; - - case attr::Pure: - break; - - case attr::Regparm: - Record.push_back(cast(Attr)->getNumParams()); - break; - - case attr::ReqdWorkGroupSize: - Record.push_back(cast(Attr)->getXDim()); - Record.push_back(cast(Attr)->getYDim()); - Record.push_back(cast(Attr)->getZDim()); - break; - - case attr::Section: - AddString(cast(Attr)->getName(), Record); - break; - - case attr::StdCall: - case attr::TransparentUnion: - case attr::Unavailable: - case attr::Unused: - case attr::Used: - break; - - case attr::Visibility: - // FIXME: stable encoding - Record.push_back(cast(Attr)->getVisibility()); - break; - - case attr::WarnUnusedResult: - case attr::Weak: - case attr::WeakRef: - case attr::WeakImport: - break; - } - } - - Stream.EmitRecord(pch::DECL_ATTR, Record); -} - -void PCHWriter::AddString(const std::string &Str, RecordData &Record) { - Record.push_back(Str.size()); - Record.insert(Record.end(), Str.begin(), Str.end()); -} - -/// \brief Note that the identifier II occurs at the given offset -/// within the identifier table. -void PCHWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) { - IdentifierOffsets[IdentifierIDs[II] - 1] = Offset; -} - -/// \brief Note that the selector Sel occurs at the given offset -/// within the method pool/selector table. -void PCHWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) { - unsigned ID = SelectorIDs[Sel]; - assert(ID && "Unknown selector"); - SelectorOffsets[ID - 1] = Offset; -} - -PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream, PCHReader *Chain) - : Stream(Stream), Chain(Chain), NextTypeID(pch::NUM_PREDEF_TYPE_IDS), - CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0), - NumLexicalDeclContexts(0), NumVisibleDeclContexts(0) { - if (Chain) - Chain->setDeserializationListener(this); -} - -void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls, - const char *isysroot) { - // Emit the file header. - Stream.Emit((unsigned)'C', 8); - Stream.Emit((unsigned)'P', 8); - Stream.Emit((unsigned)'C', 8); - Stream.Emit((unsigned)'H', 8); - - WriteBlockInfoBlock(); - - if (Chain) - WritePCHChain(SemaRef, StatCalls, isysroot); - else - WritePCHCore(SemaRef, StatCalls, isysroot); -} - -void PCHWriter::WritePCHCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, - const char *isysroot) { - using namespace llvm; - - ASTContext &Context = SemaRef.Context; - Preprocessor &PP = SemaRef.PP; - - // The translation unit is the first declaration we'll emit. - DeclIDs[Context.getTranslationUnitDecl()] = 1; - DeclTypesToEmit.push(Context.getTranslationUnitDecl()); - - // Make sure that we emit IdentifierInfos (and any attached - // declarations) for builtins. - { - IdentifierTable &Table = PP.getIdentifierTable(); - llvm::SmallVector BuiltinNames; - Context.BuiltinInfo.GetBuiltinNames(BuiltinNames, - Context.getLangOptions().NoBuiltin); - for (unsigned I = 0, N = BuiltinNames.size(); I != N; ++I) - getIdentifierRef(&Table.get(BuiltinNames[I])); - } - - // Build a record containing all of the tentative definitions in this file, in - // TentativeDefinitions order. Generally, this record will be empty for - // headers. - RecordData TentativeDefinitions; - for (unsigned i = 0, e = SemaRef.TentativeDefinitions.size(); i != e; ++i) { - AddDeclRef(SemaRef.TentativeDefinitions[i], TentativeDefinitions); - } - - // Build a record containing all of the static unused functions in this file. - RecordData UnusedStaticFuncs; - for (unsigned i=0, e = SemaRef.UnusedStaticFuncs.size(); i !=e; ++i) - AddDeclRef(SemaRef.UnusedStaticFuncs[i], UnusedStaticFuncs); - - // Build a record containing all of the locally-scoped external - // declarations in this header file. Generally, this record will be - // empty. - RecordData LocallyScopedExternalDecls; - // FIXME: This is filling in the PCH file in densemap order which is - // nondeterminstic! - for (llvm::DenseMap::iterator - TD = SemaRef.LocallyScopedExternalDecls.begin(), - TDEnd = SemaRef.LocallyScopedExternalDecls.end(); - TD != TDEnd; ++TD) - AddDeclRef(TD->second, LocallyScopedExternalDecls); - - // Build a record containing all of the ext_vector declarations. - RecordData ExtVectorDecls; - for (unsigned I = 0, N = SemaRef.ExtVectorDecls.size(); I != N; ++I) - AddDeclRef(SemaRef.ExtVectorDecls[I], ExtVectorDecls); - - // Build a record containing all of the VTable uses information. - RecordData VTableUses; - VTableUses.push_back(SemaRef.VTableUses.size()); - for (unsigned I = 0, N = SemaRef.VTableUses.size(); I != N; ++I) { - AddDeclRef(SemaRef.VTableUses[I].first, VTableUses); - AddSourceLocation(SemaRef.VTableUses[I].second, VTableUses); - VTableUses.push_back(SemaRef.VTablesUsed[SemaRef.VTableUses[I].first]); - } - - // Build a record containing all of dynamic classes declarations. - RecordData DynamicClasses; - for (unsigned I = 0, N = SemaRef.DynamicClasses.size(); I != N; ++I) - AddDeclRef(SemaRef.DynamicClasses[I], DynamicClasses); - - // Write the remaining PCH contents. - RecordData Record; - Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5); - WriteMetadata(Context, isysroot); - WriteLanguageOptions(Context.getLangOptions()); - if (StatCalls && !isysroot) - WriteStatCache(*StatCalls); - WriteSourceManagerBlock(Context.getSourceManager(), PP, isysroot); - // Write the record of special types. - Record.clear(); - - AddTypeRef(Context.getBuiltinVaListType(), Record); - AddTypeRef(Context.getObjCIdType(), Record); - AddTypeRef(Context.getObjCSelType(), Record); - AddTypeRef(Context.getObjCProtoType(), Record); - AddTypeRef(Context.getObjCClassType(), Record); - AddTypeRef(Context.getRawCFConstantStringType(), Record); - AddTypeRef(Context.getRawObjCFastEnumerationStateType(), Record); - AddTypeRef(Context.getFILEType(), Record); - AddTypeRef(Context.getjmp_bufType(), Record); - AddTypeRef(Context.getsigjmp_bufType(), Record); - AddTypeRef(Context.ObjCIdRedefinitionType, Record); - AddTypeRef(Context.ObjCClassRedefinitionType, Record); - AddTypeRef(Context.getRawBlockdescriptorType(), Record); - AddTypeRef(Context.getRawBlockdescriptorExtendedType(), Record); - AddTypeRef(Context.ObjCSelRedefinitionType, Record); - AddTypeRef(Context.getRawNSConstantStringType(), Record); - Record.push_back(Context.isInt128Installed()); - Stream.EmitRecord(pch::SPECIAL_TYPES, Record); - - // Keep writing types and declarations until all types and - // declarations have been written. - Stream.EnterSubblock(pch::DECLTYPES_BLOCK_ID, 3); - WriteDeclsBlockAbbrevs(); - while (!DeclTypesToEmit.empty()) { - DeclOrType DOT = DeclTypesToEmit.front(); - DeclTypesToEmit.pop(); - if (DOT.isType()) - WriteType(DOT.getType()); - else - WriteDecl(Context, DOT.getDecl()); - } - Stream.ExitBlock(); - - WritePreprocessor(PP); - WriteMethodPool(SemaRef); - WriteIdentifierTable(PP); - - // Write the type offsets array - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(pch::TYPE_OFFSET)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of types - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // types block - unsigned TypeOffsetAbbrev = Stream.EmitAbbrev(Abbrev); - Record.clear(); - Record.push_back(pch::TYPE_OFFSET); - Record.push_back(TypeOffsets.size()); - Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, - (const char *)&TypeOffsets.front(), - TypeOffsets.size() * sizeof(TypeOffsets[0])); - - // Write the declaration offsets array - Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(pch::DECL_OFFSET)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of declarations - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // declarations block - unsigned DeclOffsetAbbrev = Stream.EmitAbbrev(Abbrev); - Record.clear(); - Record.push_back(pch::DECL_OFFSET); - Record.push_back(DeclOffsets.size()); - Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, - (const char *)&DeclOffsets.front(), - DeclOffsets.size() * sizeof(DeclOffsets[0])); - - // Write the record containing external, unnamed definitions. - if (!ExternalDefinitions.empty()) - Stream.EmitRecord(pch::EXTERNAL_DEFINITIONS, ExternalDefinitions); - - // Write the record containing tentative definitions. - if (!TentativeDefinitions.empty()) - Stream.EmitRecord(pch::TENTATIVE_DEFINITIONS, TentativeDefinitions); - - // Write the record containing unused static functions. - if (!UnusedStaticFuncs.empty()) - Stream.EmitRecord(pch::UNUSED_STATIC_FUNCS, UnusedStaticFuncs); - - // Write the record containing locally-scoped external definitions. - if (!LocallyScopedExternalDecls.empty()) - Stream.EmitRecord(pch::LOCALLY_SCOPED_EXTERNAL_DECLS, - LocallyScopedExternalDecls); - - // Write the record containing ext_vector type names. - if (!ExtVectorDecls.empty()) - Stream.EmitRecord(pch::EXT_VECTOR_DECLS, ExtVectorDecls); - - // Write the record containing VTable uses information. - if (!VTableUses.empty()) - Stream.EmitRecord(pch::VTABLE_USES, VTableUses); - - // Write the record containing dynamic classes declarations. - if (!DynamicClasses.empty()) - Stream.EmitRecord(pch::DYNAMIC_CLASSES, DynamicClasses); - - // Some simple statistics - Record.clear(); - Record.push_back(NumStatements); - Record.push_back(NumMacros); - Record.push_back(NumLexicalDeclContexts); - Record.push_back(NumVisibleDeclContexts); - Stream.EmitRecord(pch::STATISTICS, Record); - Stream.ExitBlock(); -} - -void PCHWriter::WritePCHChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, - const char *isysroot) { - using namespace llvm; - - ASTContext &Context = SemaRef.Context; - Preprocessor &PP = SemaRef.PP; - (void)PP; - - RecordData Record; - Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5); - WriteMetadata(Context, isysroot); - // FIXME: StatCache - // FIXME: Source manager block - - // The special types are in the chained PCH. - - // We don't start with the translation unit, but with its decls that - // don't come from the other PCH. - const TranslationUnitDecl *TU = Context.getTranslationUnitDecl(); - // FIXME: We don't want to iterate over everything here, because it needlessly - // deserializes the entire original PCH. Instead we only want to iterate over - // the stuff that's already there. - // All in good time, though. - for (DeclContext::decl_iterator I = TU->decls_begin(), E = TU->decls_end(); - I != E; ++I) { - if ((*I)->getPCHLevel() == 0) { - (*I)->dump(); - DeclTypesToEmit.push(*I); - } - } - - Stream.EnterSubblock(pch::DECLTYPES_BLOCK_ID, 3); - WriteDeclsBlockAbbrevs(); - while (!DeclTypesToEmit.empty()) { - DeclOrType DOT = DeclTypesToEmit.front(); - DeclTypesToEmit.pop(); - if (DOT.isType()) - WriteType(DOT.getType()); - else - WriteDecl(Context, DOT.getDecl()); - } - Stream.ExitBlock(); - - // FIXME: Preprocessor - // FIXME: Method pool - // FIXME: Identifier table - // FIXME: Type offsets - // FIXME: Declaration offsets - // FIXME: External unnamed definitions - // FIXME: Tentative definitions - // FIXME: Unused static functions - // FIXME: Locally-scoped external definitions - // FIXME: ext_vector type names - // FIXME: Dynamic classes declarations - // FIXME: Statistics - Stream.ExitBlock(); -} - -void PCHWriter::AddSourceLocation(SourceLocation Loc, RecordData &Record) { - Record.push_back(Loc.getRawEncoding()); -} - -void PCHWriter::AddSourceRange(SourceRange Range, RecordData &Record) { - AddSourceLocation(Range.getBegin(), Record); - AddSourceLocation(Range.getEnd(), Record); -} - -void PCHWriter::AddAPInt(const llvm::APInt &Value, RecordData &Record) { - Record.push_back(Value.getBitWidth()); - unsigned N = Value.getNumWords(); - const uint64_t* Words = Value.getRawData(); - for (unsigned I = 0; I != N; ++I) - Record.push_back(Words[I]); -} - -void PCHWriter::AddAPSInt(const llvm::APSInt &Value, RecordData &Record) { - Record.push_back(Value.isUnsigned()); - AddAPInt(Value, Record); -} - -void PCHWriter::AddAPFloat(const llvm::APFloat &Value, RecordData &Record) { - AddAPInt(Value.bitcastToAPInt(), Record); -} - -void PCHWriter::AddIdentifierRef(const IdentifierInfo *II, RecordData &Record) { - Record.push_back(getIdentifierRef(II)); -} - -pch::IdentID PCHWriter::getIdentifierRef(const IdentifierInfo *II) { - if (II == 0) - return 0; - - pch::IdentID &ID = IdentifierIDs[II]; - if (ID == 0) - ID = IdentifierIDs.size(); - return ID; -} - -pch::IdentID PCHWriter::getMacroDefinitionID(MacroDefinition *MD) { - if (MD == 0) - return 0; - - pch::IdentID &ID = MacroDefinitions[MD]; - if (ID == 0) - ID = MacroDefinitions.size(); - return ID; -} - -void PCHWriter::AddSelectorRef(const Selector SelRef, RecordData &Record) { - if (SelRef.getAsOpaquePtr() == 0) { - Record.push_back(0); - return; - } - - pch::SelectorID &SID = SelectorIDs[SelRef]; - if (SID == 0) { - SID = SelectorIDs.size(); - SelVector.push_back(SelRef); - } - Record.push_back(SID); -} - -void PCHWriter::AddCXXTemporary(const CXXTemporary *Temp, RecordData &Record) { - AddDeclRef(Temp->getDestructor(), Record); -} - -void PCHWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, - const TemplateArgumentLocInfo &Arg, - RecordData &Record) { - switch (Kind) { - case TemplateArgument::Expression: - AddStmt(Arg.getAsExpr()); - break; - case TemplateArgument::Type: - AddTypeSourceInfo(Arg.getAsTypeSourceInfo(), Record); - break; - case TemplateArgument::Template: - AddSourceRange(Arg.getTemplateQualifierRange(), Record); - AddSourceLocation(Arg.getTemplateNameLoc(), Record); - break; - case TemplateArgument::Null: - case TemplateArgument::Integral: - case TemplateArgument::Declaration: - case TemplateArgument::Pack: - break; - } -} - -void PCHWriter::AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, - RecordData &Record) { - AddTemplateArgument(Arg.getArgument(), Record); - - if (Arg.getArgument().getKind() == TemplateArgument::Expression) { - bool InfoHasSameExpr - = Arg.getArgument().getAsExpr() == Arg.getLocInfo().getAsExpr(); - Record.push_back(InfoHasSameExpr); - if (InfoHasSameExpr) - return; // Avoid storing the same expr twice. - } - AddTemplateArgumentLocInfo(Arg.getArgument().getKind(), Arg.getLocInfo(), - Record); -} - -void PCHWriter::AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordData &Record) { - if (TInfo == 0) { - AddTypeRef(QualType(), Record); - return; - } - - AddTypeRef(TInfo->getType(), Record); - TypeLocWriter TLW(*this, Record); - for (TypeLoc TL = TInfo->getTypeLoc(); !TL.isNull(); TL = TL.getNextTypeLoc()) - TLW.Visit(TL); -} - -void PCHWriter::AddTypeRef(QualType T, RecordData &Record) { - if (T.isNull()) { - Record.push_back(pch::PREDEF_TYPE_NULL_ID); - return; - } - - unsigned FastQuals = T.getLocalFastQualifiers(); - T.removeFastQualifiers(); - - if (T.hasLocalNonFastQualifiers()) { - pch::TypeID &ID = TypeIDs[T]; - if (ID == 0) { - // We haven't seen these qualifiers applied to this type before. - // Assign it a new ID. This is the only time we enqueue a - // qualified type, and it has no CV qualifiers. - ID = NextTypeID++; - DeclTypesToEmit.push(T); - } - - // Encode the type qualifiers in the type reference. - Record.push_back((ID << Qualifiers::FastWidth) | FastQuals); - return; - } - - assert(!T.hasLocalQualifiers()); - - if (const BuiltinType *BT = dyn_cast(T.getTypePtr())) { - pch::TypeID ID = 0; - switch (BT->getKind()) { - case BuiltinType::Void: ID = pch::PREDEF_TYPE_VOID_ID; break; - case BuiltinType::Bool: ID = pch::PREDEF_TYPE_BOOL_ID; break; - case BuiltinType::Char_U: ID = pch::PREDEF_TYPE_CHAR_U_ID; break; - case BuiltinType::UChar: ID = pch::PREDEF_TYPE_UCHAR_ID; break; - case BuiltinType::UShort: ID = pch::PREDEF_TYPE_USHORT_ID; break; - case BuiltinType::UInt: ID = pch::PREDEF_TYPE_UINT_ID; break; - case BuiltinType::ULong: ID = pch::PREDEF_TYPE_ULONG_ID; break; - case BuiltinType::ULongLong: ID = pch::PREDEF_TYPE_ULONGLONG_ID; break; - case BuiltinType::UInt128: ID = pch::PREDEF_TYPE_UINT128_ID; break; - case BuiltinType::Char_S: ID = pch::PREDEF_TYPE_CHAR_S_ID; break; - case BuiltinType::SChar: ID = pch::PREDEF_TYPE_SCHAR_ID; break; - case BuiltinType::WChar: ID = pch::PREDEF_TYPE_WCHAR_ID; break; - case BuiltinType::Short: ID = pch::PREDEF_TYPE_SHORT_ID; break; - case BuiltinType::Int: ID = pch::PREDEF_TYPE_INT_ID; break; - case BuiltinType::Long: ID = pch::PREDEF_TYPE_LONG_ID; break; - case BuiltinType::LongLong: ID = pch::PREDEF_TYPE_LONGLONG_ID; break; - case BuiltinType::Int128: ID = pch::PREDEF_TYPE_INT128_ID; break; - case BuiltinType::Float: ID = pch::PREDEF_TYPE_FLOAT_ID; break; - case BuiltinType::Double: ID = pch::PREDEF_TYPE_DOUBLE_ID; break; - case BuiltinType::LongDouble: ID = pch::PREDEF_TYPE_LONGDOUBLE_ID; break; - case BuiltinType::NullPtr: ID = pch::PREDEF_TYPE_NULLPTR_ID; break; - case BuiltinType::Char16: ID = pch::PREDEF_TYPE_CHAR16_ID; break; - case BuiltinType::Char32: ID = pch::PREDEF_TYPE_CHAR32_ID; break; - case BuiltinType::Overload: ID = pch::PREDEF_TYPE_OVERLOAD_ID; break; - case BuiltinType::Dependent: ID = pch::PREDEF_TYPE_DEPENDENT_ID; break; - case BuiltinType::ObjCId: ID = pch::PREDEF_TYPE_OBJC_ID; break; - case BuiltinType::ObjCClass: ID = pch::PREDEF_TYPE_OBJC_CLASS; break; - case BuiltinType::ObjCSel: ID = pch::PREDEF_TYPE_OBJC_SEL; break; - case BuiltinType::UndeducedAuto: - assert(0 && "Should not see undeduced auto here"); - break; - } - - Record.push_back((ID << Qualifiers::FastWidth) | FastQuals); - return; - } - - pch::TypeID &ID = TypeIDs[T]; - if (ID == 0) { - // We haven't seen this type before. Assign it a new ID and put it - // into the queue of types to emit. - ID = NextTypeID++; - DeclTypesToEmit.push(T); - } - - // Encode the type qualifiers in the type reference. - Record.push_back((ID << Qualifiers::FastWidth) | FastQuals); -} - -void PCHWriter::AddDeclRef(const Decl *D, RecordData &Record) { - if (D == 0) { - Record.push_back(0); - return; - } - - pch::DeclID &ID = DeclIDs[D]; - if (ID == 0) { - // We haven't seen this declaration before. Give it a new ID and - // enqueue it in the list of declarations to emit. - ID = DeclIDs.size(); - DeclTypesToEmit.push(const_cast(D)); - } - - Record.push_back(ID); -} - -pch::DeclID PCHWriter::getDeclID(const Decl *D) { - if (D == 0) - return 0; - - assert(DeclIDs.find(D) != DeclIDs.end() && "Declaration not emitted!"); - return DeclIDs[D]; -} - -void PCHWriter::AddDeclarationName(DeclarationName Name, RecordData &Record) { - // FIXME: Emit a stable enum for NameKind. 0 = Identifier etc. - Record.push_back(Name.getNameKind()); - switch (Name.getNameKind()) { - case DeclarationName::Identifier: - AddIdentifierRef(Name.getAsIdentifierInfo(), Record); - break; - - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - AddSelectorRef(Name.getObjCSelector(), Record); - break; - - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - AddTypeRef(Name.getCXXNameType(), Record); - break; - - case DeclarationName::CXXOperatorName: - Record.push_back(Name.getCXXOverloadedOperator()); - break; - - case DeclarationName::CXXLiteralOperatorName: - AddIdentifierRef(Name.getCXXLiteralIdentifier(), Record); - break; - - case DeclarationName::CXXUsingDirective: - // No extra data to emit - break; - } -} - -void PCHWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS, - RecordData &Record) { - // Nested name specifiers usually aren't too long. I think that 8 would - // typically accomodate the vast majority. - llvm::SmallVector NestedNames; - - // Push each of the NNS's onto a stack for serialization in reverse order. - while (NNS) { - NestedNames.push_back(NNS); - NNS = NNS->getPrefix(); - } - - Record.push_back(NestedNames.size()); - while(!NestedNames.empty()) { - NNS = NestedNames.pop_back_val(); - NestedNameSpecifier::SpecifierKind Kind = NNS->getKind(); - Record.push_back(Kind); - switch (Kind) { - case NestedNameSpecifier::Identifier: - AddIdentifierRef(NNS->getAsIdentifier(), Record); - break; - - case NestedNameSpecifier::Namespace: - AddDeclRef(NNS->getAsNamespace(), Record); - break; - - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: - AddTypeRef(QualType(NNS->getAsType(), 0), Record); - Record.push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate); - break; - - case NestedNameSpecifier::Global: - // Don't need to write an associated value. - break; - } - } -} - -void PCHWriter::AddTemplateName(TemplateName Name, RecordData &Record) { - TemplateName::NameKind Kind = Name.getKind(); - Record.push_back(Kind); - switch (Kind) { - case TemplateName::Template: - AddDeclRef(Name.getAsTemplateDecl(), Record); - break; - - case TemplateName::OverloadedTemplate: { - OverloadedTemplateStorage *OvT = Name.getAsOverloadedTemplate(); - Record.push_back(OvT->size()); - for (OverloadedTemplateStorage::iterator I = OvT->begin(), E = OvT->end(); - I != E; ++I) - AddDeclRef(*I, Record); - break; - } - - case TemplateName::QualifiedTemplate: { - QualifiedTemplateName *QualT = Name.getAsQualifiedTemplateName(); - AddNestedNameSpecifier(QualT->getQualifier(), Record); - Record.push_back(QualT->hasTemplateKeyword()); - AddDeclRef(QualT->getTemplateDecl(), Record); - break; - } - - case TemplateName::DependentTemplate: { - DependentTemplateName *DepT = Name.getAsDependentTemplateName(); - AddNestedNameSpecifier(DepT->getQualifier(), Record); - Record.push_back(DepT->isIdentifier()); - if (DepT->isIdentifier()) - AddIdentifierRef(DepT->getIdentifier(), Record); - else - Record.push_back(DepT->getOperator()); - break; - } - } -} - -void PCHWriter::AddTemplateArgument(const TemplateArgument &Arg, - RecordData &Record) { - Record.push_back(Arg.getKind()); - switch (Arg.getKind()) { - case TemplateArgument::Null: - break; - case TemplateArgument::Type: - AddTypeRef(Arg.getAsType(), Record); - break; - case TemplateArgument::Declaration: - AddDeclRef(Arg.getAsDecl(), Record); - break; - case TemplateArgument::Integral: - AddAPSInt(*Arg.getAsIntegral(), Record); - AddTypeRef(Arg.getIntegralType(), Record); - break; - case TemplateArgument::Template: - AddTemplateName(Arg.getAsTemplate(), Record); - break; - case TemplateArgument::Expression: - AddStmt(Arg.getAsExpr()); - break; - case TemplateArgument::Pack: - Record.push_back(Arg.pack_size()); - for (TemplateArgument::pack_iterator I=Arg.pack_begin(), E=Arg.pack_end(); - I != E; ++I) - AddTemplateArgument(*I, Record); - break; - } -} - -void -PCHWriter::AddTemplateParameterList(const TemplateParameterList *TemplateParams, - RecordData &Record) { - assert(TemplateParams && "No TemplateParams!"); - AddSourceLocation(TemplateParams->getTemplateLoc(), Record); - AddSourceLocation(TemplateParams->getLAngleLoc(), Record); - AddSourceLocation(TemplateParams->getRAngleLoc(), Record); - Record.push_back(TemplateParams->size()); - for (TemplateParameterList::const_iterator - P = TemplateParams->begin(), PEnd = TemplateParams->end(); - P != PEnd; ++P) - AddDeclRef(*P, Record); -} - -/// \brief Emit a template argument list. -void -PCHWriter::AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs, - RecordData &Record) { - assert(TemplateArgs && "No TemplateArgs!"); - Record.push_back(TemplateArgs->flat_size()); - for (int i=0, e = TemplateArgs->flat_size(); i != e; ++i) - AddTemplateArgument(TemplateArgs->get(i), Record); -} - - -void -PCHWriter::AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordData &Record) { - Record.push_back(Set.size()); - for (UnresolvedSetImpl::const_iterator - I = Set.begin(), E = Set.end(); I != E; ++I) { - AddDeclRef(I.getDecl(), Record); - Record.push_back(I.getAccess()); - } -} - -void PCHWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base, - RecordData &Record) { - Record.push_back(Base.isVirtual()); - Record.push_back(Base.isBaseOfClass()); - Record.push_back(Base.getAccessSpecifierAsWritten()); - AddTypeRef(Base.getType(), Record); - AddSourceRange(Base.getSourceRange(), Record); -} - -void PCHWriter::TypeRead(pch::TypeID ID, QualType T) { -} - -void PCHWriter::DeclRead(pch::DeclID ID, const Decl *D) { -} - diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp deleted file mode 100644 index bc4452e..0000000 --- a/lib/Frontend/PCHWriterDecl.cpp +++ /dev/null @@ -1,1172 +0,0 @@ -//===--- PCHWriterDecl.cpp - Declaration Serialization --------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements serialization for Declarations. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/PCHWriter.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/Expr.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Bitcode/BitstreamWriter.h" -#include "llvm/Support/ErrorHandling.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// Declaration serialization -//===----------------------------------------------------------------------===// - -namespace clang { - class PCHDeclWriter : public DeclVisitor { - - PCHWriter &Writer; - ASTContext &Context; - PCHWriter::RecordData &Record; - - public: - pch::DeclCode Code; - unsigned AbbrevToUse; - - PCHDeclWriter(PCHWriter &Writer, ASTContext &Context, - PCHWriter::RecordData &Record) - : Writer(Writer), Context(Context), Record(Record) { - } - - void Visit(Decl *D); - - void VisitDecl(Decl *D); - void VisitTranslationUnitDecl(TranslationUnitDecl *D); - void VisitNamedDecl(NamedDecl *D); - void VisitNamespaceDecl(NamespaceDecl *D); - void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); - void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); - void VisitTypeDecl(TypeDecl *D); - void VisitTypedefDecl(TypedefDecl *D); - void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); - void VisitTagDecl(TagDecl *D); - void VisitEnumDecl(EnumDecl *D); - void VisitRecordDecl(RecordDecl *D); - void VisitCXXRecordDecl(CXXRecordDecl *D); - void VisitClassTemplateSpecializationDecl( - ClassTemplateSpecializationDecl *D); - void VisitClassTemplatePartialSpecializationDecl( - ClassTemplatePartialSpecializationDecl *D); - void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); - void VisitValueDecl(ValueDecl *D); - void VisitEnumConstantDecl(EnumConstantDecl *D); - void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); - void VisitDeclaratorDecl(DeclaratorDecl *D); - void VisitFunctionDecl(FunctionDecl *D); - void VisitCXXMethodDecl(CXXMethodDecl *D); - void VisitCXXConstructorDecl(CXXConstructorDecl *D); - void VisitCXXDestructorDecl(CXXDestructorDecl *D); - void VisitCXXConversionDecl(CXXConversionDecl *D); - void VisitFieldDecl(FieldDecl *D); - void VisitVarDecl(VarDecl *D); - void VisitImplicitParamDecl(ImplicitParamDecl *D); - void VisitParmVarDecl(ParmVarDecl *D); - void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); - void VisitTemplateDecl(TemplateDecl *D); - void VisitClassTemplateDecl(ClassTemplateDecl *D); - void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); - void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); - void VisitUsingDecl(UsingDecl *D); - void VisitUsingShadowDecl(UsingShadowDecl *D); - void VisitLinkageSpecDecl(LinkageSpecDecl *D); - void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); - void VisitAccessSpecDecl(AccessSpecDecl *D); - void VisitFriendDecl(FriendDecl *D); - void VisitFriendTemplateDecl(FriendTemplateDecl *D); - void VisitStaticAssertDecl(StaticAssertDecl *D); - void VisitBlockDecl(BlockDecl *D); - - void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, - uint64_t VisibleOffset); - - - // FIXME: Put in the same order is DeclNodes.td? - void VisitObjCMethodDecl(ObjCMethodDecl *D); - void VisitObjCContainerDecl(ObjCContainerDecl *D); - void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); - void VisitObjCIvarDecl(ObjCIvarDecl *D); - void VisitObjCProtocolDecl(ObjCProtocolDecl *D); - void VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D); - void VisitObjCClassDecl(ObjCClassDecl *D); - void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); - void VisitObjCCategoryDecl(ObjCCategoryDecl *D); - void VisitObjCImplDecl(ObjCImplDecl *D); - void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); - void VisitObjCImplementationDecl(ObjCImplementationDecl *D); - void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); - void VisitObjCPropertyDecl(ObjCPropertyDecl *D); - void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); - }; -} - -void PCHDeclWriter::Visit(Decl *D) { - DeclVisitor::Visit(D); - - // Handle FunctionDecl's body here and write it after all other Stmts/Exprs - // have been written. We want it last because we will not read it back when - // retrieving it from the PCH, we'll just lazily set the offset. - if (FunctionDecl *FD = dyn_cast(D)) { - Record.push_back(FD->isThisDeclarationADefinition()); - if (FD->isThisDeclarationADefinition()) - Writer.AddStmt(FD->getBody()); - } -} - -void PCHDeclWriter::VisitDecl(Decl *D) { - Writer.AddDeclRef(cast_or_null(D->getDeclContext()), Record); - Writer.AddDeclRef(cast_or_null(D->getLexicalDeclContext()), Record); - Writer.AddSourceLocation(D->getLocation(), Record); - Record.push_back(D->isInvalidDecl()); - Record.push_back(D->hasAttrs()); - Record.push_back(D->isImplicit()); - Record.push_back(D->isUsed(false)); - Record.push_back(D->getAccess()); - Record.push_back(D->getPCHLevel()); -} - -void PCHDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { - VisitDecl(D); - Writer.AddDeclRef(D->getAnonymousNamespace(), Record); - Code = pch::DECL_TRANSLATION_UNIT; -} - -void PCHDeclWriter::VisitNamedDecl(NamedDecl *D) { - VisitDecl(D); - Writer.AddDeclarationName(D->getDeclName(), Record); -} - -void PCHDeclWriter::VisitTypeDecl(TypeDecl *D) { - VisitNamedDecl(D); - Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); -} - -void PCHDeclWriter::VisitTypedefDecl(TypedefDecl *D) { - VisitTypeDecl(D); - Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); - Code = pch::DECL_TYPEDEF; -} - -void PCHDeclWriter::VisitTagDecl(TagDecl *D) { - VisitTypeDecl(D); - Record.push_back(D->getIdentifierNamespace()); - Writer.AddDeclRef(D->getPreviousDeclaration(), Record); - Record.push_back((unsigned)D->getTagKind()); // FIXME: stable encoding - Record.push_back(D->isDefinition()); - Record.push_back(D->isEmbeddedInDeclarator()); - Writer.AddSourceLocation(D->getRBraceLoc(), Record); - Writer.AddSourceLocation(D->getTagKeywordLoc(), Record); - // FIXME: maybe write optional qualifier and its range. - Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record); -} - -void PCHDeclWriter::VisitEnumDecl(EnumDecl *D) { - VisitTagDecl(D); - Writer.AddTypeRef(D->getIntegerType(), Record); - Writer.AddTypeRef(D->getPromotionType(), Record); - Record.push_back(D->getNumPositiveBits()); - Record.push_back(D->getNumNegativeBits()); - Writer.AddDeclRef(D->getInstantiatedFromMemberEnum(), Record); - Code = pch::DECL_ENUM; -} - -void PCHDeclWriter::VisitRecordDecl(RecordDecl *D) { - VisitTagDecl(D); - Record.push_back(D->hasFlexibleArrayMember()); - Record.push_back(D->isAnonymousStructOrUnion()); - Record.push_back(D->hasObjectMember()); - Code = pch::DECL_RECORD; -} - -void PCHDeclWriter::VisitValueDecl(ValueDecl *D) { - VisitNamedDecl(D); - Writer.AddTypeRef(D->getType(), Record); -} - -void PCHDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { - VisitValueDecl(D); - Record.push_back(D->getInitExpr()? 1 : 0); - if (D->getInitExpr()) - Writer.AddStmt(D->getInitExpr()); - Writer.AddAPSInt(D->getInitVal(), Record); - Code = pch::DECL_ENUM_CONSTANT; -} - -void PCHDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { - VisitValueDecl(D); - Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); - // FIXME: write optional qualifier and its range. -} - -void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { - VisitDeclaratorDecl(D); - - Record.push_back(D->getIdentifierNamespace()); - Record.push_back(D->getTemplatedKind()); - switch (D->getTemplatedKind()) { - default: assert(false && "Unhandled TemplatedKind!"); - break; - case FunctionDecl::TK_NonTemplate: - break; - case FunctionDecl::TK_FunctionTemplate: - Writer.AddDeclRef(D->getDescribedFunctionTemplate(), Record); - break; - case FunctionDecl::TK_MemberSpecialization: { - MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo(); - Writer.AddDeclRef(MemberInfo->getInstantiatedFrom(), Record); - Record.push_back(MemberInfo->getTemplateSpecializationKind()); - Writer.AddSourceLocation(MemberInfo->getPointOfInstantiation(), Record); - break; - } - case FunctionDecl::TK_FunctionTemplateSpecialization: { - FunctionTemplateSpecializationInfo * - FTSInfo = D->getTemplateSpecializationInfo(); - // We want it canonical to guarantee that it has a Common*. - Writer.AddDeclRef(FTSInfo->getTemplate()->getCanonicalDecl(), Record); - Record.push_back(FTSInfo->getTemplateSpecializationKind()); - - // Template arguments. - Writer.AddTemplateArgumentList(FTSInfo->TemplateArguments, Record); - - // Template args as written. - Record.push_back(FTSInfo->TemplateArgumentsAsWritten != 0); - if (FTSInfo->TemplateArgumentsAsWritten) { - Record.push_back(FTSInfo->TemplateArgumentsAsWritten->size()); - for (int i=0, e = FTSInfo->TemplateArgumentsAsWritten->size(); i!=e; ++i) - Writer.AddTemplateArgumentLoc((*FTSInfo->TemplateArgumentsAsWritten)[i], - Record); - Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->getLAngleLoc(), - Record); - Writer.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->getRAngleLoc(), - Record); - } - - Writer.AddSourceLocation(FTSInfo->getPointOfInstantiation(), Record); - break; - } - case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { - DependentFunctionTemplateSpecializationInfo * - DFTSInfo = D->getDependentSpecializationInfo(); - - // Templates. - Record.push_back(DFTSInfo->getNumTemplates()); - for (int i=0, e = DFTSInfo->getNumTemplates(); i != e; ++i) - Writer.AddDeclRef(DFTSInfo->getTemplate(i), Record); - - // Templates args. - Record.push_back(DFTSInfo->getNumTemplateArgs()); - for (int i=0, e = DFTSInfo->getNumTemplateArgs(); i != e; ++i) - Writer.AddTemplateArgumentLoc(DFTSInfo->getTemplateArg(i), Record); - Writer.AddSourceLocation(DFTSInfo->getLAngleLoc(), Record); - Writer.AddSourceLocation(DFTSInfo->getRAngleLoc(), Record); - break; - } - } - - // FunctionDecl's body is handled last at PCHWriterDecl::Visit, - // after everything else is written. - - Writer.AddDeclRef(D->getPreviousDeclaration(), Record); - Record.push_back(D->getStorageClass()); // FIXME: stable encoding - Record.push_back(D->getStorageClassAsWritten()); - Record.push_back(D->isInlineSpecified()); - Record.push_back(D->isVirtualAsWritten()); - Record.push_back(D->isPure()); - Record.push_back(D->hasInheritedPrototype()); - Record.push_back(D->hasWrittenPrototype()); - Record.push_back(D->isDeleted()); - Record.push_back(D->isTrivial()); - Record.push_back(D->isCopyAssignment()); - Record.push_back(D->hasImplicitReturnZero()); - Writer.AddSourceLocation(D->getLocEnd(), Record); - - Record.push_back(D->param_size()); - for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); - P != PEnd; ++P) - Writer.AddDeclRef(*P, Record); - Code = pch::DECL_FUNCTION; -} - -void PCHDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { - VisitNamedDecl(D); - // FIXME: convert to LazyStmtPtr? - // Unlike C/C++, method bodies will never be in header files. - Record.push_back(D->getBody() != 0); - if (D->getBody() != 0) { - Writer.AddStmt(D->getBody()); - Writer.AddDeclRef(D->getSelfDecl(), Record); - Writer.AddDeclRef(D->getCmdDecl(), Record); - } - Record.push_back(D->isInstanceMethod()); - Record.push_back(D->isVariadic()); - Record.push_back(D->isSynthesized()); - // FIXME: stable encoding for @required/@optional - Record.push_back(D->getImplementationControl()); - // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway - Record.push_back(D->getObjCDeclQualifier()); - Record.push_back(D->getNumSelectorArgs()); - Writer.AddTypeRef(D->getResultType(), Record); - Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record); - Writer.AddSourceLocation(D->getLocEnd(), Record); - Record.push_back(D->param_size()); - for (ObjCMethodDecl::param_iterator P = D->param_begin(), - PEnd = D->param_end(); P != PEnd; ++P) - Writer.AddDeclRef(*P, Record); - Code = pch::DECL_OBJC_METHOD; -} - -void PCHDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) { - VisitNamedDecl(D); - Writer.AddSourceRange(D->getAtEndRange(), Record); - // Abstract class (no need to define a stable pch::DECL code). -} - -void PCHDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { - VisitObjCContainerDecl(D); - Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); - Writer.AddDeclRef(D->getSuperClass(), Record); - Record.push_back(D->protocol_size()); - for (ObjCInterfaceDecl::protocol_iterator P = D->protocol_begin(), - PEnd = D->protocol_end(); - P != PEnd; ++P) - Writer.AddDeclRef(*P, Record); - for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(), - PLEnd = D->protocol_loc_end(); - PL != PLEnd; ++PL) - Writer.AddSourceLocation(*PL, Record); - Record.push_back(D->ivar_size()); - for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(), - IEnd = D->ivar_end(); I != IEnd; ++I) - Writer.AddDeclRef(*I, Record); - Writer.AddDeclRef(D->getCategoryList(), Record); - Record.push_back(D->isForwardDecl()); - Record.push_back(D->isImplicitInterfaceDecl()); - Writer.AddSourceLocation(D->getClassLoc(), Record); - Writer.AddSourceLocation(D->getSuperClassLoc(), Record); - Writer.AddSourceLocation(D->getLocEnd(), Record); - Code = pch::DECL_OBJC_INTERFACE; -} - -void PCHDeclWriter::VisitObjCIvarDecl(ObjCIvarDecl *D) { - VisitFieldDecl(D); - // FIXME: stable encoding for @public/@private/@protected/@package - Record.push_back(D->getAccessControl()); - Code = pch::DECL_OBJC_IVAR; -} - -void PCHDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { - VisitObjCContainerDecl(D); - Record.push_back(D->isForwardDecl()); - Writer.AddSourceLocation(D->getLocEnd(), Record); - Record.push_back(D->protocol_size()); - for (ObjCProtocolDecl::protocol_iterator - I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) - Writer.AddDeclRef(*I, Record); - for (ObjCProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(), - PLEnd = D->protocol_loc_end(); - PL != PLEnd; ++PL) - Writer.AddSourceLocation(*PL, Record); - Code = pch::DECL_OBJC_PROTOCOL; -} - -void PCHDeclWriter::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) { - VisitFieldDecl(D); - Code = pch::DECL_OBJC_AT_DEFS_FIELD; -} - -void PCHDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) { - VisitDecl(D); - Record.push_back(D->size()); - for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I) - Writer.AddDeclRef(I->getInterface(), Record); - for (ObjCClassDecl::iterator I = D->begin(), IEnd = D->end(); I != IEnd; ++I) - Writer.AddSourceLocation(I->getLocation(), Record); - Code = pch::DECL_OBJC_CLASS; -} - -void PCHDeclWriter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { - VisitDecl(D); - Record.push_back(D->protocol_size()); - for (ObjCForwardProtocolDecl::protocol_iterator - I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) - Writer.AddDeclRef(*I, Record); - for (ObjCForwardProtocolDecl::protocol_loc_iterator - PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end(); - PL != PLEnd; ++PL) - Writer.AddSourceLocation(*PL, Record); - Code = pch::DECL_OBJC_FORWARD_PROTOCOL; -} - -void PCHDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { - VisitObjCContainerDecl(D); - Writer.AddDeclRef(D->getClassInterface(), Record); - Record.push_back(D->protocol_size()); - for (ObjCCategoryDecl::protocol_iterator - I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I) - Writer.AddDeclRef(*I, Record); - for (ObjCCategoryDecl::protocol_loc_iterator - PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end(); - PL != PLEnd; ++PL) - Writer.AddSourceLocation(*PL, Record); - Writer.AddDeclRef(D->getNextClassCategory(), Record); - Writer.AddSourceLocation(D->getAtLoc(), Record); - Writer.AddSourceLocation(D->getCategoryNameLoc(), Record); - Code = pch::DECL_OBJC_CATEGORY; -} - -void PCHDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) { - VisitNamedDecl(D); - Writer.AddDeclRef(D->getClassInterface(), Record); - Code = pch::DECL_OBJC_COMPATIBLE_ALIAS; -} - -void PCHDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { - VisitNamedDecl(D); - Writer.AddSourceLocation(D->getAtLoc(), Record); - Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); - // FIXME: stable encoding - Record.push_back((unsigned)D->getPropertyAttributes()); - Record.push_back((unsigned)D->getPropertyAttributesAsWritten()); - // FIXME: stable encoding - Record.push_back((unsigned)D->getPropertyImplementation()); - Writer.AddDeclarationName(D->getGetterName(), Record); - Writer.AddDeclarationName(D->getSetterName(), Record); - Writer.AddDeclRef(D->getGetterMethodDecl(), Record); - Writer.AddDeclRef(D->getSetterMethodDecl(), Record); - Writer.AddDeclRef(D->getPropertyIvarDecl(), Record); - Code = pch::DECL_OBJC_PROPERTY; -} - -void PCHDeclWriter::VisitObjCImplDecl(ObjCImplDecl *D) { - VisitObjCContainerDecl(D); - Writer.AddDeclRef(D->getClassInterface(), Record); - // Abstract class (no need to define a stable pch::DECL code). -} - -void PCHDeclWriter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { - VisitObjCImplDecl(D); - Writer.AddIdentifierRef(D->getIdentifier(), Record); - Code = pch::DECL_OBJC_CATEGORY_IMPL; -} - -void PCHDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { - VisitObjCImplDecl(D); - Writer.AddDeclRef(D->getSuperClass(), Record); - // FIXME add writing of IvarInitializers and NumIvarInitializers. - Code = pch::DECL_OBJC_IMPLEMENTATION; -} - -void PCHDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { - VisitDecl(D); - Writer.AddSourceLocation(D->getLocStart(), Record); - Writer.AddDeclRef(D->getPropertyDecl(), Record); - Writer.AddDeclRef(D->getPropertyIvarDecl(), Record); - // FIXME. write GetterCXXConstructor and SetterCXXAssignment. - Code = pch::DECL_OBJC_PROPERTY_IMPL; -} - -void PCHDeclWriter::VisitFieldDecl(FieldDecl *D) { - VisitDeclaratorDecl(D); - Record.push_back(D->isMutable()); - Record.push_back(D->getBitWidth()? 1 : 0); - if (D->getBitWidth()) - Writer.AddStmt(D->getBitWidth()); - if (!D->getDeclName()) - Writer.AddDeclRef(Context.getInstantiatedFromUnnamedFieldDecl(D), Record); - Code = pch::DECL_FIELD; -} - -void PCHDeclWriter::VisitVarDecl(VarDecl *D) { - VisitDeclaratorDecl(D); - Record.push_back(D->getStorageClass()); // FIXME: stable encoding - Record.push_back(D->getStorageClassAsWritten()); - Record.push_back(D->isThreadSpecified()); - Record.push_back(D->hasCXXDirectInitializer()); - Record.push_back(D->isDeclaredInCondition()); - Record.push_back(D->isExceptionVariable()); - Record.push_back(D->isNRVOVariable()); - Writer.AddDeclRef(D->getPreviousDeclaration(), Record); - Record.push_back(D->getInit() ? 1 : 0); - if (D->getInit()) - Writer.AddStmt(D->getInit()); - - MemberSpecializationInfo *SpecInfo - = D->isStaticDataMember() ? D->getMemberSpecializationInfo() : 0; - Record.push_back(SpecInfo != 0); - if (SpecInfo) { - Writer.AddDeclRef(SpecInfo->getInstantiatedFrom(), Record); - Record.push_back(SpecInfo->getTemplateSpecializationKind()); - Writer.AddSourceLocation(SpecInfo->getPointOfInstantiation(), Record); - } - - Code = pch::DECL_VAR; -} - -void PCHDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) { - VisitVarDecl(D); - Code = pch::DECL_IMPLICIT_PARAM; -} - -void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { - VisitVarDecl(D); - Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding - Record.push_back(D->hasInheritedDefaultArg()); - Record.push_back(D->hasUninstantiatedDefaultArg()); - if (D->hasUninstantiatedDefaultArg()) - Writer.AddStmt(D->getUninstantiatedDefaultArg()); - Code = pch::DECL_PARM_VAR; - - // If the assumptions about the DECL_PARM_VAR abbrev are true, use it. Here - // we dynamically check for the properties that we optimize for, but don't - // know are true of all PARM_VAR_DECLs. - if (!D->getTypeSourceInfo() && - !D->hasAttrs() && - !D->isImplicit() && - !D->isUsed(false) && - D->getAccess() == AS_none && - D->getPCHLevel() == 0 && - D->getStorageClass() == 0 && - !D->hasCXXDirectInitializer() && // Can params have this ever? - D->getObjCDeclQualifier() == 0 && - !D->hasInheritedDefaultArg() && - D->getInit() == 0 && - !D->hasUninstantiatedDefaultArg()) // No default expr. - AbbrevToUse = Writer.getParmVarDeclAbbrev(); - - // Check things we know are true of *every* PARM_VAR_DECL, which is more than - // just us assuming it. - assert(!D->isInvalidDecl() && "Shouldn't emit invalid decls"); - assert(!D->isThreadSpecified() && "PARM_VAR_DECL can't be __thread"); - assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private"); - assert(!D->isDeclaredInCondition() && "PARM_VAR_DECL can't be in condition"); - assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var"); - assert(D->getPreviousDeclaration() == 0 && "PARM_VAR_DECL can't be redecl"); - assert(!D->isStaticDataMember() && - "PARM_VAR_DECL can't be static data member"); -} - -void PCHDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { - VisitDecl(D); - Writer.AddStmt(D->getAsmString()); - Code = pch::DECL_FILE_SCOPE_ASM; -} - -void PCHDeclWriter::VisitBlockDecl(BlockDecl *D) { - VisitDecl(D); - Writer.AddStmt(D->getBody()); - Writer.AddTypeSourceInfo(D->getSignatureAsWritten(), Record); - Record.push_back(D->param_size()); - for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); - P != PEnd; ++P) - Writer.AddDeclRef(*P, Record); - Code = pch::DECL_BLOCK; -} - -void PCHDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { - VisitDecl(D); - // FIXME: It might be nice to serialize the brace locations for this - // declaration, which don't seem to be readily available in the AST. - Record.push_back(D->getLanguage()); - Record.push_back(D->hasBraces()); - Code = pch::DECL_LINKAGE_SPEC; -} - -void PCHDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { - VisitNamedDecl(D); - Writer.AddSourceLocation(D->getLBracLoc(), Record); - Writer.AddSourceLocation(D->getRBracLoc(), Record); - Writer.AddDeclRef(D->getNextNamespace(), Record); - - // Only write one reference--original or anonymous - Record.push_back(D->isOriginalNamespace()); - if (D->isOriginalNamespace()) - Writer.AddDeclRef(D->getAnonymousNamespace(), Record); - else - Writer.AddDeclRef(D->getOriginalNamespace(), Record); - Code = pch::DECL_NAMESPACE; -} - -void PCHDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { - VisitNamedDecl(D); - Writer.AddSourceLocation(D->getAliasLoc(), Record); - Writer.AddSourceRange(D->getQualifierRange(), Record); - Writer.AddNestedNameSpecifier(D->getQualifier(), Record); - Writer.AddSourceLocation(D->getTargetNameLoc(), Record); - Writer.AddDeclRef(D->getNamespace(), Record); - Code = pch::DECL_NAMESPACE_ALIAS; -} - -void PCHDeclWriter::VisitUsingDecl(UsingDecl *D) { - VisitNamedDecl(D); - Writer.AddSourceRange(D->getNestedNameRange(), Record); - Writer.AddSourceLocation(D->getUsingLocation(), Record); - Writer.AddNestedNameSpecifier(D->getTargetNestedNameDecl(), Record); - Record.push_back(D->getNumShadowDecls()); - for (UsingDecl::shadow_iterator P = D->shadow_begin(), - PEnd = D->shadow_end(); P != PEnd; ++P) - Writer.AddDeclRef(*P, Record); - Record.push_back(D->isTypeName()); - Writer.AddDeclRef(Context.getInstantiatedFromUsingDecl(D), Record); - Code = pch::DECL_USING; -} - -void PCHDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) { - VisitNamedDecl(D); - Writer.AddDeclRef(D->getTargetDecl(), Record); - Writer.AddDeclRef(D->getUsingDecl(), Record); - Writer.AddDeclRef(Context.getInstantiatedFromUsingShadowDecl(D), Record); - Code = pch::DECL_USING_SHADOW; -} - -void PCHDeclWriter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { - VisitNamedDecl(D); - Writer.AddSourceLocation(D->getNamespaceKeyLocation(), Record); - Writer.AddSourceRange(D->getQualifierRange(), Record); - Writer.AddNestedNameSpecifier(D->getQualifier(), Record); - Writer.AddSourceLocation(D->getIdentLocation(), Record); - Writer.AddDeclRef(D->getNominatedNamespace(), Record); - Writer.AddDeclRef(dyn_cast(D->getCommonAncestor()), Record); - Code = pch::DECL_USING_DIRECTIVE; -} - -void PCHDeclWriter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { - VisitValueDecl(D); - Writer.AddSourceRange(D->getTargetNestedNameRange(), Record); - Writer.AddSourceLocation(D->getUsingLoc(), Record); - Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record); - Code = pch::DECL_UNRESOLVED_USING_VALUE; -} - -void PCHDeclWriter::VisitUnresolvedUsingTypenameDecl( - UnresolvedUsingTypenameDecl *D) { - VisitTypeDecl(D); - Writer.AddSourceRange(D->getTargetNestedNameRange(), Record); - Writer.AddSourceLocation(D->getUsingLoc(), Record); - Writer.AddSourceLocation(D->getTypenameLoc(), Record); - Writer.AddNestedNameSpecifier(D->getTargetNestedNameSpecifier(), Record); - Code = pch::DECL_UNRESOLVED_USING_TYPENAME; -} - -void PCHDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { - // See comments at PCHDeclReader::VisitCXXRecordDecl about why this happens - // before VisitRecordDecl. - enum { Data_NoDefData, Data_Owner, Data_NotOwner }; - bool OwnsDefinitionData = false; - if (D->DefinitionData) { - assert(D->DefinitionData->Definition && - "DefinitionData don't point to a definition decl!"); - OwnsDefinitionData = D->DefinitionData->Definition == D; - if (OwnsDefinitionData) { - Record.push_back(Data_Owner); - } else { - Record.push_back(Data_NotOwner); - Writer.AddDeclRef(D->DefinitionData->Definition, Record); - } - } else - Record.push_back(Data_NoDefData); - - VisitRecordDecl(D); - - if (OwnsDefinitionData) { - assert(D->DefinitionData); - struct CXXRecordDecl::DefinitionData &Data = *D->DefinitionData; - - Record.push_back(Data.UserDeclaredConstructor); - Record.push_back(Data.UserDeclaredCopyConstructor); - Record.push_back(Data.UserDeclaredCopyAssignment); - Record.push_back(Data.UserDeclaredDestructor); - Record.push_back(Data.Aggregate); - Record.push_back(Data.PlainOldData); - Record.push_back(Data.Empty); - Record.push_back(Data.Polymorphic); - Record.push_back(Data.Abstract); - Record.push_back(Data.HasTrivialConstructor); - Record.push_back(Data.HasTrivialCopyConstructor); - Record.push_back(Data.HasTrivialCopyAssignment); - Record.push_back(Data.HasTrivialDestructor); - Record.push_back(Data.ComputedVisibleConversions); - Record.push_back(Data.DeclaredDefaultConstructor); - Record.push_back(Data.DeclaredCopyConstructor); - Record.push_back(Data.DeclaredCopyAssignment); - Record.push_back(Data.DeclaredDestructor); - - Record.push_back(D->getNumBases()); - for (CXXRecordDecl::base_class_iterator I = D->bases_begin(), - E = D->bases_end(); I != E; ++I) - Writer.AddCXXBaseSpecifier(*I, Record); - - // FIXME: Make VBases lazily computed when needed to avoid storing them. - Record.push_back(D->getNumVBases()); - for (CXXRecordDecl::base_class_iterator I = D->vbases_begin(), - E = D->vbases_end(); I != E; ++I) - Writer.AddCXXBaseSpecifier(*I, Record); - - Writer.AddUnresolvedSet(Data.Conversions, Record); - Writer.AddUnresolvedSet(Data.VisibleConversions, Record); - // Data.Definition is written at the top. - Writer.AddDeclRef(Data.FirstFriend, Record); - } - - enum { - CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization - }; - if (ClassTemplateDecl *TemplD = D->getDescribedClassTemplate()) { - Record.push_back(CXXRecTemplate); - Writer.AddDeclRef(TemplD, Record); - } else if (MemberSpecializationInfo *MSInfo - = D->getMemberSpecializationInfo()) { - Record.push_back(CXXRecMemberSpecialization); - Writer.AddDeclRef(MSInfo->getInstantiatedFrom(), Record); - Record.push_back(MSInfo->getTemplateSpecializationKind()); - Writer.AddSourceLocation(MSInfo->getPointOfInstantiation(), Record); - } else { - Record.push_back(CXXRecNotTemplate); - } - - Code = pch::DECL_CXX_RECORD; -} - -void PCHDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) { - VisitFunctionDecl(D); - Record.push_back(D->size_overridden_methods()); - for (CXXMethodDecl::method_iterator - I = D->begin_overridden_methods(), E = D->end_overridden_methods(); - I != E; ++I) - Writer.AddDeclRef(*I, Record); - Code = pch::DECL_CXX_METHOD; -} - -void PCHDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { - VisitCXXMethodDecl(D); - - Record.push_back(D->IsExplicitSpecified); - Record.push_back(D->ImplicitlyDefined); - - Record.push_back(D->NumBaseOrMemberInitializers); - for (unsigned i=0; i != D->NumBaseOrMemberInitializers; ++i) { - CXXBaseOrMemberInitializer *Init = D->BaseOrMemberInitializers[i]; - - Record.push_back(Init->isBaseInitializer()); - if (Init->isBaseInitializer()) { - Writer.AddTypeSourceInfo(Init->getBaseClassInfo(), Record); - Record.push_back(Init->isBaseVirtual()); - } else { - Writer.AddDeclRef(Init->getMember(), Record); - } - Writer.AddSourceLocation(Init->getMemberLocation(), Record); - Writer.AddStmt(Init->getInit()); - Writer.AddDeclRef(Init->getAnonUnionMember(), Record); - Writer.AddSourceLocation(Init->getLParenLoc(), Record); - Writer.AddSourceLocation(Init->getRParenLoc(), Record); - Record.push_back(Init->isWritten()); - if (Init->isWritten()) { - Record.push_back(Init->getSourceOrder()); - } else { - Record.push_back(Init->getNumArrayIndices()); - for (unsigned i=0, e=Init->getNumArrayIndices(); i != e; ++i) - Writer.AddDeclRef(Init->getArrayIndex(i), Record); - } - } - - Code = pch::DECL_CXX_CONSTRUCTOR; -} - -void PCHDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) { - VisitCXXMethodDecl(D); - - Record.push_back(D->ImplicitlyDefined); - Writer.AddDeclRef(D->OperatorDelete, Record); - - Code = pch::DECL_CXX_DESTRUCTOR; -} - -void PCHDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) { - VisitCXXMethodDecl(D); - Record.push_back(D->IsExplicitSpecified); - Code = pch::DECL_CXX_CONVERSION; -} - -void PCHDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) { - VisitDecl(D); - Writer.AddSourceLocation(D->getColonLoc(), Record); - Code = pch::DECL_ACCESS_SPEC; -} - -void PCHDeclWriter::VisitFriendDecl(FriendDecl *D) { - VisitDecl(D); - Record.push_back(D->Friend.is()); - if (D->Friend.is()) - Writer.AddTypeSourceInfo(D->Friend.get(), Record); - else - Writer.AddDeclRef(D->Friend.get(), Record); - Writer.AddDeclRef(D->NextFriend, Record); - Writer.AddSourceLocation(D->FriendLoc, Record); - Code = pch::DECL_FRIEND; -} - -void PCHDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) { - assert(false && "cannot write FriendTemplateDecl"); -} - -void PCHDeclWriter::VisitTemplateDecl(TemplateDecl *D) { - VisitNamedDecl(D); - - Writer.AddDeclRef(D->getTemplatedDecl(), Record); - Writer.AddTemplateParameterList(D->getTemplateParameters(), Record); -} - -static bool IsKeptInFoldingSet(ClassTemplateSpecializationDecl *D) { - return D->getTypeForDecl()->getAsCXXRecordDecl() == D; -} - -void PCHDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) { - VisitTemplateDecl(D); - - Record.push_back(D->getIdentifierNamespace()); - Writer.AddDeclRef(D->getPreviousDeclaration(), Record); - if (D->getPreviousDeclaration() == 0) { - // This ClassTemplateDecl owns the CommonPtr; write it. - assert(D->isCanonicalDecl()); - - typedef llvm::FoldingSet CTSDSetTy; - CTSDSetTy &CTSDSet = D->getSpecializations(); - Record.push_back(CTSDSet.size()); - for (CTSDSetTy::iterator I=CTSDSet.begin(), E = CTSDSet.end(); I!=E; ++I) { - assert(IsKeptInFoldingSet(&*I)); - Writer.AddDeclRef(&*I, Record); - } - - typedef llvm::FoldingSet CTPSDSetTy; - CTPSDSetTy &CTPSDSet = D->getPartialSpecializations(); - Record.push_back(CTPSDSet.size()); - for (CTPSDSetTy::iterator I=CTPSDSet.begin(), E=CTPSDSet.end(); I!=E; ++I) { - assert(IsKeptInFoldingSet(&*I)); - Writer.AddDeclRef(&*I, Record); - } - - // InjectedClassNameType is computed, no need to write it. - - Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record); - if (D->getInstantiatedFromMemberTemplate()) - Record.push_back(D->isMemberSpecialization()); - } - Code = pch::DECL_CLASS_TEMPLATE; -} - -void PCHDeclWriter::VisitClassTemplateSpecializationDecl( - ClassTemplateSpecializationDecl *D) { - VisitCXXRecordDecl(D); - - llvm::PointerUnion InstFrom - = D->getSpecializedTemplateOrPartial(); - if (InstFrom.is()) { - Writer.AddDeclRef(InstFrom.get(), Record); - } else { - Writer.AddDeclRef(InstFrom.get(), - Record); - Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record); - } - - // Explicit info. - Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record); - if (D->getTypeAsWritten()) { - Writer.AddSourceLocation(D->getExternLoc(), Record); - Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record); - } - - Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record); - Writer.AddSourceLocation(D->getPointOfInstantiation(), Record); - Record.push_back(D->getSpecializationKind()); - - bool IsInInFoldingSet = IsKeptInFoldingSet(D); - Record.push_back(IsInInFoldingSet); - if (IsInInFoldingSet) { - // When reading, we'll add it to the folding set of this one. - Writer.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl(), Record); - } - - Code = pch::DECL_CLASS_TEMPLATE_SPECIALIZATION; -} - -void PCHDeclWriter::VisitClassTemplatePartialSpecializationDecl( - ClassTemplatePartialSpecializationDecl *D) { - VisitClassTemplateSpecializationDecl(D); - - Writer.AddTemplateParameterList(D->getTemplateParameters(), Record); - - Record.push_back(D->getNumTemplateArgsAsWritten()); - for (int i = 0, e = D->getNumTemplateArgsAsWritten(); i != e; ++i) - Writer.AddTemplateArgumentLoc(D->getTemplateArgsAsWritten()[i], Record); - - Record.push_back(D->getSequenceNumber()); - - // These are read/set from/to the first declaration. - if (D->getPreviousDeclaration() == 0) { - Writer.AddDeclRef(D->getInstantiatedFromMember(), Record); - Record.push_back(D->isMemberSpecialization()); - } - - Code = pch::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION; -} - -void PCHDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { - VisitTemplateDecl(D); - - Record.push_back(D->getIdentifierNamespace()); - Writer.AddDeclRef(D->getPreviousDeclaration(), Record); - if (D->getPreviousDeclaration() == 0) { - // This FunctionTemplateDecl owns the CommonPtr; write it. - - // Write the function specialization declarations. - Record.push_back(D->getSpecializations().size()); - for (llvm::FoldingSet::iterator - I = D->getSpecializations().begin(), - E = D->getSpecializations().end() ; I != E; ++I) - Writer.AddDeclRef(I->Function, Record); - - Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record); - if (D->getInstantiatedFromMemberTemplate()) - Record.push_back(D->isMemberSpecialization()); - } - Code = pch::DECL_FUNCTION_TEMPLATE; -} - -void PCHDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { - VisitTypeDecl(D); - - Record.push_back(D->wasDeclaredWithTypename()); - Record.push_back(D->isParameterPack()); - Record.push_back(D->defaultArgumentWasInherited()); - Writer.AddTypeSourceInfo(D->getDefaultArgumentInfo(), Record); - - Code = pch::DECL_TEMPLATE_TYPE_PARM; -} - -void PCHDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { - VisitVarDecl(D); - // TemplateParmPosition. - Record.push_back(D->getDepth()); - Record.push_back(D->getPosition()); - // Rest of NonTypeTemplateParmDecl. - Record.push_back(D->getDefaultArgument() != 0); - if (D->getDefaultArgument()) { - Writer.AddStmt(D->getDefaultArgument()); - Record.push_back(D->defaultArgumentWasInherited()); - } - Code = pch::DECL_NON_TYPE_TEMPLATE_PARM; -} - -void PCHDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { - VisitTemplateDecl(D); - // TemplateParmPosition. - Record.push_back(D->getDepth()); - Record.push_back(D->getPosition()); - // Rest of TemplateTemplateParmDecl. - Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record); - Record.push_back(D->defaultArgumentWasInherited()); - Code = pch::DECL_TEMPLATE_TEMPLATE_PARM; -} - -void PCHDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) { - assert(false && "cannot write StaticAssertDecl"); -} - -/// \brief Emit the DeclContext part of a declaration context decl. -/// -/// \param LexicalOffset the offset at which the DECL_CONTEXT_LEXICAL -/// block for this declaration context is stored. May be 0 to indicate -/// that there are no declarations stored within this context. -/// -/// \param VisibleOffset the offset at which the DECL_CONTEXT_VISIBLE -/// block for this declaration context is stored. May be 0 to indicate -/// that there are no declarations visible from this context. Note -/// that this value will not be emitted for non-primary declaration -/// contexts. -void PCHDeclWriter::VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset, - uint64_t VisibleOffset) { - Record.push_back(LexicalOffset); - Record.push_back(VisibleOffset); -} - - -//===----------------------------------------------------------------------===// -// PCHWriter Implementation -//===----------------------------------------------------------------------===// - -void PCHWriter::WriteDeclsBlockAbbrevs() { - using namespace llvm; - // Abbreviation for DECL_PARM_VAR. - BitCodeAbbrev *Abv = new BitCodeAbbrev(); - Abv->Add(BitCodeAbbrevOp(pch::DECL_PARM_VAR)); - - // Decl - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LexicalDeclContext - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location - Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?) - Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs - Abv->Add(BitCodeAbbrevOp(0)); // isImplicit - Abv->Add(BitCodeAbbrevOp(0)); // isUsed - Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier - Abv->Add(BitCodeAbbrevOp(0)); // PCH level - - // NamedDecl - Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name - // ValueDecl - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type - // DeclaratorDecl - Abv->Add(BitCodeAbbrevOp(pch::PREDEF_TYPE_NULL_ID)); // InfoType - // VarDecl - Abv->Add(BitCodeAbbrevOp(0)); // StorageClass - Abv->Add(BitCodeAbbrevOp(0)); // StorageClassAsWritten - Abv->Add(BitCodeAbbrevOp(0)); // isThreadSpecified - Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer - Abv->Add(BitCodeAbbrevOp(0)); // isDeclaredInCondition - Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable - Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable - Abv->Add(BitCodeAbbrevOp(0)); // PrevDecl - Abv->Add(BitCodeAbbrevOp(0)); // HasInit - Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo - // ParmVarDecl - Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier - Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg - Abv->Add(BitCodeAbbrevOp(0)); // HasUninstantiatedDefaultArg - - ParmVarDeclAbbrev = Stream.EmitAbbrev(Abv); -} - -/// isRequiredDecl - Check if this is a "required" Decl, which must be seen by -/// consumers of the AST. -/// -/// Such decls will always be deserialized from the PCH file, so we would like -/// this to be as restrictive as possible. Currently the predicate is driven by -/// code generation requirements, if other clients have a different notion of -/// what is "required" then we may have to consider an alternate scheme where -/// clients can iterate over the top-level decls and get information on them, -/// without necessary deserializing them. We could explicitly require such -/// clients to use a separate API call to "realize" the decl. This should be -/// relatively painless since they would presumably only do it for top-level -/// decls. -// -// FIXME: This predicate is essentially IRgen's predicate to determine whether a -// declaration can be deferred. Merge them somehow. -static bool isRequiredDecl(const Decl *D, ASTContext &Context) { - // File scoped assembly must be seen. - if (isa(D)) - return true; - - // Otherwise if this isn't a function or a file scoped variable it doesn't - // need to be seen. - if (const VarDecl *VD = dyn_cast(D)) { - if (!VD->isFileVarDecl()) - return false; - } else if (!isa(D)) - return false; - - // Aliases and used decls must be seen. - if (D->hasAttr() || D->hasAttr()) - return true; - - if (const FunctionDecl *FD = dyn_cast(D)) { - // Forward declarations don't need to be seen. - if (!FD->isThisDeclarationADefinition()) - return false; - - // Constructors and destructors must be seen. - if (FD->hasAttr() || FD->hasAttr()) - return true; - - // Otherwise, this is required unless it is static. - // - // FIXME: Inlines. - return FD->getStorageClass() != FunctionDecl::Static; - } else { - const VarDecl *VD = cast(D); - - // In C++, this doesn't need to be seen if it is marked "extern". - if (Context.getLangOptions().CPlusPlus && !VD->getInit() && - (VD->getStorageClass() == VarDecl::Extern || - VD->isExternC())) - return false; - - // In C, this doesn't need to be seen unless it is a definition. - if (!Context.getLangOptions().CPlusPlus && !VD->getInit()) - return false; - - // Otherwise, this is required unless it is static. - return VD->getStorageClass() != VarDecl::Static; - } -} - -void PCHWriter::WriteDecl(ASTContext &Context, Decl *D) { - RecordData Record; - PCHDeclWriter W(*this, Context, Record); - - // If this declaration is also a DeclContext, write blocks for the - // declarations that lexically stored inside its context and those - // declarations that are visible from its context. These blocks - // are written before the declaration itself so that we can put - // their offsets into the record for the declaration. - uint64_t LexicalOffset = 0; - uint64_t VisibleOffset = 0; - DeclContext *DC = dyn_cast(D); - if (DC) { - LexicalOffset = WriteDeclContextLexicalBlock(Context, DC); - VisibleOffset = WriteDeclContextVisibleBlock(Context, DC); - } - - // Determine the ID for this declaration - pch::DeclID &ID = DeclIDs[D]; - if (ID == 0) - ID = DeclIDs.size(); - - unsigned Index = ID - 1; - - // Record the offset for this declaration - if (DeclOffsets.size() == Index) - DeclOffsets.push_back(Stream.GetCurrentBitNo()); - else if (DeclOffsets.size() < Index) { - DeclOffsets.resize(Index+1); - DeclOffsets[Index] = Stream.GetCurrentBitNo(); - } - - // Build and emit a record for this declaration - Record.clear(); - W.Code = (pch::DeclCode)0; - W.AbbrevToUse = 0; - W.Visit(D); - if (DC) W.VisitDeclContext(DC, LexicalOffset, VisibleOffset); - - if (!W.Code) - llvm::report_fatal_error(llvm::StringRef("unexpected declaration kind '") + - D->getDeclKindName() + "'"); - Stream.EmitRecord(W.Code, Record, W.AbbrevToUse); - - // If the declaration had any attributes, write them now. - if (D->hasAttrs()) - WriteAttributeRecord(D->getAttrs()); - - // Flush any expressions that were written as part of this declaration. - FlushStmts(); - - // Note "external" declarations so that we can add them to a record in the - // PCH file later. - // - // FIXME: This should be renamed, the predicate is much more complicated. - if (isRequiredDecl(D, Context)) - ExternalDefinitions.push_back(Index + 1); -} diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp deleted file mode 100644 index 7537728..0000000 --- a/lib/Frontend/PCHWriterStmt.cpp +++ /dev/null @@ -1,1345 +0,0 @@ -//===--- PCHWriterStmt.cpp - Statement and Expression Serialization -------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements serialization for Statements and Expressions. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/PCHWriter.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/StmtVisitor.h" -#include "llvm/Bitcode/BitstreamWriter.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// Statement/expression serialization -//===----------------------------------------------------------------------===// - -namespace clang { - class PCHStmtWriter : public StmtVisitor { - PCHWriter &Writer; - PCHWriter::RecordData &Record; - - public: - pch::StmtCode Code; - - PCHStmtWriter(PCHWriter &Writer, PCHWriter::RecordData &Record) - : Writer(Writer), Record(Record) { } - - void - AddExplicitTemplateArgumentList(const ExplicitTemplateArgumentList &Args); - - void VisitStmt(Stmt *S); - void VisitNullStmt(NullStmt *S); - void VisitCompoundStmt(CompoundStmt *S); - void VisitSwitchCase(SwitchCase *S); - void VisitCaseStmt(CaseStmt *S); - void VisitDefaultStmt(DefaultStmt *S); - void VisitLabelStmt(LabelStmt *S); - void VisitIfStmt(IfStmt *S); - void VisitSwitchStmt(SwitchStmt *S); - void VisitWhileStmt(WhileStmt *S); - void VisitDoStmt(DoStmt *S); - void VisitForStmt(ForStmt *S); - void VisitGotoStmt(GotoStmt *S); - void VisitIndirectGotoStmt(IndirectGotoStmt *S); - void VisitContinueStmt(ContinueStmt *S); - void VisitBreakStmt(BreakStmt *S); - void VisitReturnStmt(ReturnStmt *S); - void VisitDeclStmt(DeclStmt *S); - void VisitAsmStmt(AsmStmt *S); - void VisitExpr(Expr *E); - void VisitPredefinedExpr(PredefinedExpr *E); - void VisitDeclRefExpr(DeclRefExpr *E); - void VisitIntegerLiteral(IntegerLiteral *E); - void VisitFloatingLiteral(FloatingLiteral *E); - void VisitImaginaryLiteral(ImaginaryLiteral *E); - void VisitStringLiteral(StringLiteral *E); - void VisitCharacterLiteral(CharacterLiteral *E); - void VisitParenExpr(ParenExpr *E); - void VisitParenListExpr(ParenListExpr *E); - void VisitUnaryOperator(UnaryOperator *E); - void VisitOffsetOfExpr(OffsetOfExpr *E); - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); - void VisitArraySubscriptExpr(ArraySubscriptExpr *E); - void VisitCallExpr(CallExpr *E); - void VisitMemberExpr(MemberExpr *E); - void VisitCastExpr(CastExpr *E); - void VisitBinaryOperator(BinaryOperator *E); - void VisitCompoundAssignOperator(CompoundAssignOperator *E); - void VisitConditionalOperator(ConditionalOperator *E); - void VisitImplicitCastExpr(ImplicitCastExpr *E); - void VisitExplicitCastExpr(ExplicitCastExpr *E); - void VisitCStyleCastExpr(CStyleCastExpr *E); - void VisitCompoundLiteralExpr(CompoundLiteralExpr *E); - void VisitExtVectorElementExpr(ExtVectorElementExpr *E); - void VisitInitListExpr(InitListExpr *E); - void VisitDesignatedInitExpr(DesignatedInitExpr *E); - void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E); - void VisitVAArgExpr(VAArgExpr *E); - void VisitAddrLabelExpr(AddrLabelExpr *E); - void VisitStmtExpr(StmtExpr *E); - void VisitTypesCompatibleExpr(TypesCompatibleExpr *E); - void VisitChooseExpr(ChooseExpr *E); - void VisitGNUNullExpr(GNUNullExpr *E); - void VisitShuffleVectorExpr(ShuffleVectorExpr *E); - void VisitBlockExpr(BlockExpr *E); - void VisitBlockDeclRefExpr(BlockDeclRefExpr *E); - - // Objective-C Expressions - void VisitObjCStringLiteral(ObjCStringLiteral *E); - void VisitObjCEncodeExpr(ObjCEncodeExpr *E); - void VisitObjCSelectorExpr(ObjCSelectorExpr *E); - void VisitObjCProtocolExpr(ObjCProtocolExpr *E); - void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E); - void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E); - void VisitObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *E); - void VisitObjCMessageExpr(ObjCMessageExpr *E); - void VisitObjCSuperExpr(ObjCSuperExpr *E); - void VisitObjCIsaExpr(ObjCIsaExpr *E); - - // Objective-C Statements - void VisitObjCForCollectionStmt(ObjCForCollectionStmt *); - void VisitObjCAtCatchStmt(ObjCAtCatchStmt *); - void VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *); - void VisitObjCAtTryStmt(ObjCAtTryStmt *); - void VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *); - void VisitObjCAtThrowStmt(ObjCAtThrowStmt *); - - // C++ Statements - void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); - void VisitCXXMemberCallExpr(CXXMemberCallExpr *E); - void VisitCXXConstructExpr(CXXConstructExpr *E); - void VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E); - void VisitCXXNamedCastExpr(CXXNamedCastExpr *E); - void VisitCXXStaticCastExpr(CXXStaticCastExpr *E); - void VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E); - void VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E); - void VisitCXXConstCastExpr(CXXConstCastExpr *E); - void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E); - void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); - void VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); - void VisitCXXTypeidExpr(CXXTypeidExpr *E); - void VisitCXXThisExpr(CXXThisExpr *E); - void VisitCXXThrowExpr(CXXThrowExpr *E); - void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E); - void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); - void VisitCXXBindReferenceExpr(CXXBindReferenceExpr *E); - - void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E); - void VisitCXXNewExpr(CXXNewExpr *E); - void VisitCXXDeleteExpr(CXXDeleteExpr *E); - void VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E); - - void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E); - void VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E); - void VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E); - void VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E); - - void VisitOverloadExpr(OverloadExpr *E); - void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E); - void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E); - - void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E); - }; -} - -void PCHStmtWriter:: -AddExplicitTemplateArgumentList(const ExplicitTemplateArgumentList &Args) { - Writer.AddSourceLocation(Args.LAngleLoc, Record); - Writer.AddSourceLocation(Args.RAngleLoc, Record); - for (unsigned i=0; i != Args.NumTemplateArgs; ++i) - Writer.AddTemplateArgumentLoc(Args.getTemplateArgs()[i], Record); -} - -void PCHStmtWriter::VisitStmt(Stmt *S) { -} - -void PCHStmtWriter::VisitNullStmt(NullStmt *S) { - VisitStmt(S); - Writer.AddSourceLocation(S->getSemiLoc(), Record); - Code = pch::STMT_NULL; -} - -void PCHStmtWriter::VisitCompoundStmt(CompoundStmt *S) { - VisitStmt(S); - Record.push_back(S->size()); - for (CompoundStmt::body_iterator CS = S->body_begin(), CSEnd = S->body_end(); - CS != CSEnd; ++CS) - Writer.AddStmt(*CS); - Writer.AddSourceLocation(S->getLBracLoc(), Record); - Writer.AddSourceLocation(S->getRBracLoc(), Record); - Code = pch::STMT_COMPOUND; -} - -void PCHStmtWriter::VisitSwitchCase(SwitchCase *S) { - VisitStmt(S); - Record.push_back(Writer.getSwitchCaseID(S)); -} - -void PCHStmtWriter::VisitCaseStmt(CaseStmt *S) { - VisitSwitchCase(S); - Writer.AddStmt(S->getLHS()); - Writer.AddStmt(S->getRHS()); - Writer.AddStmt(S->getSubStmt()); - Writer.AddSourceLocation(S->getCaseLoc(), Record); - Writer.AddSourceLocation(S->getEllipsisLoc(), Record); - Writer.AddSourceLocation(S->getColonLoc(), Record); - Code = pch::STMT_CASE; -} - -void PCHStmtWriter::VisitDefaultStmt(DefaultStmt *S) { - VisitSwitchCase(S); - Writer.AddStmt(S->getSubStmt()); - Writer.AddSourceLocation(S->getDefaultLoc(), Record); - Writer.AddSourceLocation(S->getColonLoc(), Record); - Code = pch::STMT_DEFAULT; -} - -void PCHStmtWriter::VisitLabelStmt(LabelStmt *S) { - VisitStmt(S); - Writer.AddIdentifierRef(S->getID(), Record); - Writer.AddStmt(S->getSubStmt()); - Writer.AddSourceLocation(S->getIdentLoc(), Record); - Record.push_back(Writer.GetLabelID(S)); - Code = pch::STMT_LABEL; -} - -void PCHStmtWriter::VisitIfStmt(IfStmt *S) { - VisitStmt(S); - Writer.AddDeclRef(S->getConditionVariable(), Record); - Writer.AddStmt(S->getCond()); - Writer.AddStmt(S->getThen()); - Writer.AddStmt(S->getElse()); - Writer.AddSourceLocation(S->getIfLoc(), Record); - Writer.AddSourceLocation(S->getElseLoc(), Record); - Code = pch::STMT_IF; -} - -void PCHStmtWriter::VisitSwitchStmt(SwitchStmt *S) { - VisitStmt(S); - Writer.AddDeclRef(S->getConditionVariable(), Record); - Writer.AddStmt(S->getCond()); - Writer.AddStmt(S->getBody()); - Writer.AddSourceLocation(S->getSwitchLoc(), Record); - for (SwitchCase *SC = S->getSwitchCaseList(); SC; - SC = SC->getNextSwitchCase()) - Record.push_back(Writer.RecordSwitchCaseID(SC)); - Code = pch::STMT_SWITCH; -} - -void PCHStmtWriter::VisitWhileStmt(WhileStmt *S) { - VisitStmt(S); - Writer.AddDeclRef(S->getConditionVariable(), Record); - Writer.AddStmt(S->getCond()); - Writer.AddStmt(S->getBody()); - Writer.AddSourceLocation(S->getWhileLoc(), Record); - Code = pch::STMT_WHILE; -} - -void PCHStmtWriter::VisitDoStmt(DoStmt *S) { - VisitStmt(S); - Writer.AddStmt(S->getCond()); - Writer.AddStmt(S->getBody()); - Writer.AddSourceLocation(S->getDoLoc(), Record); - Writer.AddSourceLocation(S->getWhileLoc(), Record); - Writer.AddSourceLocation(S->getRParenLoc(), Record); - Code = pch::STMT_DO; -} - -void PCHStmtWriter::VisitForStmt(ForStmt *S) { - VisitStmt(S); - Writer.AddStmt(S->getInit()); - Writer.AddStmt(S->getCond()); - Writer.AddDeclRef(S->getConditionVariable(), Record); - Writer.AddStmt(S->getInc()); - Writer.AddStmt(S->getBody()); - Writer.AddSourceLocation(S->getForLoc(), Record); - Writer.AddSourceLocation(S->getLParenLoc(), Record); - Writer.AddSourceLocation(S->getRParenLoc(), Record); - Code = pch::STMT_FOR; -} - -void PCHStmtWriter::VisitGotoStmt(GotoStmt *S) { - VisitStmt(S); - Record.push_back(Writer.GetLabelID(S->getLabel())); - Writer.AddSourceLocation(S->getGotoLoc(), Record); - Writer.AddSourceLocation(S->getLabelLoc(), Record); - Code = pch::STMT_GOTO; -} - -void PCHStmtWriter::VisitIndirectGotoStmt(IndirectGotoStmt *S) { - VisitStmt(S); - Writer.AddSourceLocation(S->getGotoLoc(), Record); - Writer.AddSourceLocation(S->getStarLoc(), Record); - Writer.AddStmt(S->getTarget()); - Code = pch::STMT_INDIRECT_GOTO; -} - -void PCHStmtWriter::VisitContinueStmt(ContinueStmt *S) { - VisitStmt(S); - Writer.AddSourceLocation(S->getContinueLoc(), Record); - Code = pch::STMT_CONTINUE; -} - -void PCHStmtWriter::VisitBreakStmt(BreakStmt *S) { - VisitStmt(S); - Writer.AddSourceLocation(S->getBreakLoc(), Record); - Code = pch::STMT_BREAK; -} - -void PCHStmtWriter::VisitReturnStmt(ReturnStmt *S) { - VisitStmt(S); - Writer.AddStmt(S->getRetValue()); - Writer.AddSourceLocation(S->getReturnLoc(), Record); - Writer.AddDeclRef(S->getNRVOCandidate(), Record); - Code = pch::STMT_RETURN; -} - -void PCHStmtWriter::VisitDeclStmt(DeclStmt *S) { - VisitStmt(S); - Writer.AddSourceLocation(S->getStartLoc(), Record); - Writer.AddSourceLocation(S->getEndLoc(), Record); - DeclGroupRef DG = S->getDeclGroup(); - for (DeclGroupRef::iterator D = DG.begin(), DEnd = DG.end(); D != DEnd; ++D) - Writer.AddDeclRef(*D, Record); - Code = pch::STMT_DECL; -} - -void PCHStmtWriter::VisitAsmStmt(AsmStmt *S) { - VisitStmt(S); - Record.push_back(S->getNumOutputs()); - Record.push_back(S->getNumInputs()); - Record.push_back(S->getNumClobbers()); - Writer.AddSourceLocation(S->getAsmLoc(), Record); - Writer.AddSourceLocation(S->getRParenLoc(), Record); - Record.push_back(S->isVolatile()); - Record.push_back(S->isSimple()); - Record.push_back(S->isMSAsm()); - Writer.AddStmt(S->getAsmString()); - - // Outputs - for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) { - Writer.AddIdentifierRef(S->getOutputIdentifier(I), Record); - Writer.AddStmt(S->getOutputConstraintLiteral(I)); - Writer.AddStmt(S->getOutputExpr(I)); - } - - // Inputs - for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) { - Writer.AddIdentifierRef(S->getInputIdentifier(I), Record); - Writer.AddStmt(S->getInputConstraintLiteral(I)); - Writer.AddStmt(S->getInputExpr(I)); - } - - // Clobbers - for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) - Writer.AddStmt(S->getClobber(I)); - - Code = pch::STMT_ASM; -} - -void PCHStmtWriter::VisitExpr(Expr *E) { - VisitStmt(E); - Writer.AddTypeRef(E->getType(), Record); - Record.push_back(E->isTypeDependent()); - Record.push_back(E->isValueDependent()); -} - -void PCHStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) { - VisitExpr(E); - Writer.AddSourceLocation(E->getLocation(), Record); - Record.push_back(E->getIdentType()); // FIXME: stable encoding - Code = pch::EXPR_PREDEFINED; -} - -void PCHStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) { - VisitExpr(E); - - Record.push_back(E->hasQualifier()); - unsigned NumTemplateArgs = E->getNumTemplateArgs(); - assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgumentList() && - "Template args list with no args ?"); - Record.push_back(NumTemplateArgs); - - if (E->hasQualifier()) { - Writer.AddNestedNameSpecifier(E->getQualifier(), Record); - Writer.AddSourceRange(E->getQualifierRange(), Record); - } - - if (NumTemplateArgs) - AddExplicitTemplateArgumentList(*E->getExplicitTemplateArgumentList()); - - Writer.AddDeclRef(E->getDecl(), Record); - Writer.AddSourceLocation(E->getLocation(), Record); - Code = pch::EXPR_DECL_REF; -} - -void PCHStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) { - VisitExpr(E); - Writer.AddSourceLocation(E->getLocation(), Record); - Writer.AddAPInt(E->getValue(), Record); - Code = pch::EXPR_INTEGER_LITERAL; -} - -void PCHStmtWriter::VisitFloatingLiteral(FloatingLiteral *E) { - VisitExpr(E); - Writer.AddAPFloat(E->getValue(), Record); - Record.push_back(E->isExact()); - Writer.AddSourceLocation(E->getLocation(), Record); - Code = pch::EXPR_FLOATING_LITERAL; -} - -void PCHStmtWriter::VisitImaginaryLiteral(ImaginaryLiteral *E) { - VisitExpr(E); - Writer.AddStmt(E->getSubExpr()); - Code = pch::EXPR_IMAGINARY_LITERAL; -} - -void PCHStmtWriter::VisitStringLiteral(StringLiteral *E) { - VisitExpr(E); - Record.push_back(E->getByteLength()); - Record.push_back(E->getNumConcatenated()); - Record.push_back(E->isWide()); - // FIXME: String data should be stored as a blob at the end of the - // StringLiteral. However, we can't do so now because we have no - // provision for coping with abbreviations when we're jumping around - // the PCH file during deserialization. - Record.insert(Record.end(), - E->getStrData(), E->getStrData() + E->getByteLength()); - for (unsigned I = 0, N = E->getNumConcatenated(); I != N; ++I) - Writer.AddSourceLocation(E->getStrTokenLoc(I), Record); - Code = pch::EXPR_STRING_LITERAL; -} - -void PCHStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) { - VisitExpr(E); - Record.push_back(E->getValue()); - Writer.AddSourceLocation(E->getLocation(), Record); - Record.push_back(E->isWide()); - Code = pch::EXPR_CHARACTER_LITERAL; -} - -void PCHStmtWriter::VisitParenExpr(ParenExpr *E) { - VisitExpr(E); - Writer.AddSourceLocation(E->getLParen(), Record); - Writer.AddSourceLocation(E->getRParen(), Record); - Writer.AddStmt(E->getSubExpr()); - Code = pch::EXPR_PAREN; -} - -void PCHStmtWriter::VisitParenListExpr(ParenListExpr *E) { - VisitExpr(E); - Record.push_back(E->NumExprs); - for (unsigned i=0; i != E->NumExprs; ++i) - Writer.AddStmt(E->Exprs[i]); - Writer.AddSourceLocation(E->LParenLoc, Record); - Writer.AddSourceLocation(E->RParenLoc, Record); - Code = pch::EXPR_PAREN_LIST; -} - -void PCHStmtWriter::VisitUnaryOperator(UnaryOperator *E) { - VisitExpr(E); - Writer.AddStmt(E->getSubExpr()); - Record.push_back(E->getOpcode()); // FIXME: stable encoding - Writer.AddSourceLocation(E->getOperatorLoc(), Record); - Code = pch::EXPR_UNARY_OPERATOR; -} - -void PCHStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) { - VisitExpr(E); - Record.push_back(E->getNumComponents()); - Record.push_back(E->getNumExpressions()); - Writer.AddSourceLocation(E->getOperatorLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record); - for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { - const OffsetOfExpr::OffsetOfNode &ON = E->getComponent(I); - Record.push_back(ON.getKind()); // FIXME: Stable encoding - Writer.AddSourceLocation(ON.getRange().getBegin(), Record); - Writer.AddSourceLocation(ON.getRange().getEnd(), Record); - switch (ON.getKind()) { - case OffsetOfExpr::OffsetOfNode::Array: - Record.push_back(ON.getArrayExprIndex()); - break; - - case OffsetOfExpr::OffsetOfNode::Field: - Writer.AddDeclRef(ON.getField(), Record); - break; - - case OffsetOfExpr::OffsetOfNode::Identifier: - Writer.AddIdentifierRef(ON.getFieldName(), Record); - break; - - case OffsetOfExpr::OffsetOfNode::Base: - // FIXME: Implement this! - llvm_unreachable("PCH for offsetof(base-specifier) not implemented"); - break; - } - } - for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I) - Writer.AddStmt(E->getIndexExpr(I)); - Code = pch::EXPR_OFFSETOF; -} - -void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { - VisitExpr(E); - Record.push_back(E->isSizeOf()); - if (E->isArgumentType()) - Writer.AddTypeSourceInfo(E->getArgumentTypeInfo(), Record); - else { - Record.push_back(0); - Writer.AddStmt(E->getArgumentExpr()); - } - Writer.AddSourceLocation(E->getOperatorLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_SIZEOF_ALIGN_OF; -} - -void PCHStmtWriter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { - VisitExpr(E); - Writer.AddStmt(E->getLHS()); - Writer.AddStmt(E->getRHS()); - Writer.AddSourceLocation(E->getRBracketLoc(), Record); - Code = pch::EXPR_ARRAY_SUBSCRIPT; -} - -void PCHStmtWriter::VisitCallExpr(CallExpr *E) { - VisitExpr(E); - Record.push_back(E->getNumArgs()); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Writer.AddStmt(E->getCallee()); - for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end(); - Arg != ArgEnd; ++Arg) - Writer.AddStmt(*Arg); - Code = pch::EXPR_CALL; -} - -void PCHStmtWriter::VisitMemberExpr(MemberExpr *E) { - // Don't call VisitExpr, we'll write everything here. - - Record.push_back(E->hasQualifier()); - if (E->hasQualifier()) { - Writer.AddNestedNameSpecifier(E->getQualifier(), Record); - Writer.AddSourceRange(E->getQualifierRange(), Record); - } - - unsigned NumTemplateArgs = E->getNumTemplateArgs(); - assert((NumTemplateArgs != 0) == E->hasExplicitTemplateArgumentList() && - "Template args list with no args ?"); - Record.push_back(NumTemplateArgs); - if (NumTemplateArgs) { - Writer.AddSourceLocation(E->getLAngleLoc(), Record); - Writer.AddSourceLocation(E->getRAngleLoc(), Record); - for (unsigned i=0; i != NumTemplateArgs; ++i) - Writer.AddTemplateArgumentLoc(E->getTemplateArgs()[i], Record); - } - - DeclAccessPair FoundDecl = E->getFoundDecl(); - Writer.AddDeclRef(FoundDecl.getDecl(), Record); - Record.push_back(FoundDecl.getAccess()); - - Writer.AddTypeRef(E->getType(), Record); - Writer.AddStmt(E->getBase()); - Writer.AddDeclRef(E->getMemberDecl(), Record); - Writer.AddSourceLocation(E->getMemberLoc(), Record); - Record.push_back(E->isArrow()); - Code = pch::EXPR_MEMBER; -} - -void PCHStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) { - VisitExpr(E); - Writer.AddStmt(E->getBase()); - Writer.AddSourceLocation(E->getIsaMemberLoc(), Record); - Record.push_back(E->isArrow()); - Code = pch::EXPR_OBJC_ISA; -} - -void PCHStmtWriter::VisitCastExpr(CastExpr *E) { - VisitExpr(E); - Writer.AddStmt(E->getSubExpr()); - Record.push_back(E->getCastKind()); // FIXME: stable encoding - CXXBaseSpecifierArray &BasePath = E->getBasePath(); - Record.push_back(BasePath.size()); - for (CXXBaseSpecifierArray::iterator I = BasePath.begin(), E = BasePath.end(); - I != E; ++I) - Writer.AddCXXBaseSpecifier(**I, Record); -} - -void PCHStmtWriter::VisitBinaryOperator(BinaryOperator *E) { - VisitExpr(E); - Writer.AddStmt(E->getLHS()); - Writer.AddStmt(E->getRHS()); - Record.push_back(E->getOpcode()); // FIXME: stable encoding - Writer.AddSourceLocation(E->getOperatorLoc(), Record); - Code = pch::EXPR_BINARY_OPERATOR; -} - -void PCHStmtWriter::VisitCompoundAssignOperator(CompoundAssignOperator *E) { - VisitBinaryOperator(E); - Writer.AddTypeRef(E->getComputationLHSType(), Record); - Writer.AddTypeRef(E->getComputationResultType(), Record); - Code = pch::EXPR_COMPOUND_ASSIGN_OPERATOR; -} - -void PCHStmtWriter::VisitConditionalOperator(ConditionalOperator *E) { - VisitExpr(E); - Writer.AddStmt(E->getCond()); - Writer.AddStmt(E->getLHS()); - Writer.AddStmt(E->getRHS()); - Writer.AddSourceLocation(E->getQuestionLoc(), Record); - Writer.AddSourceLocation(E->getColonLoc(), Record); - Code = pch::EXPR_CONDITIONAL_OPERATOR; -} - -void PCHStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) { - VisitCastExpr(E); - Record.push_back(E->isLvalueCast()); - Code = pch::EXPR_IMPLICIT_CAST; -} - -void PCHStmtWriter::VisitExplicitCastExpr(ExplicitCastExpr *E) { - VisitCastExpr(E); - Writer.AddTypeSourceInfo(E->getTypeInfoAsWritten(), Record); -} - -void PCHStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) { - VisitExplicitCastExpr(E); - Writer.AddSourceLocation(E->getLParenLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_CSTYLE_CAST; -} - -void PCHStmtWriter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { - VisitExpr(E); - Writer.AddSourceLocation(E->getLParenLoc(), Record); - Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record); - Writer.AddStmt(E->getInitializer()); - Record.push_back(E->isFileScope()); - Code = pch::EXPR_COMPOUND_LITERAL; -} - -void PCHStmtWriter::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { - VisitExpr(E); - Writer.AddStmt(E->getBase()); - Writer.AddIdentifierRef(&E->getAccessor(), Record); - Writer.AddSourceLocation(E->getAccessorLoc(), Record); - Code = pch::EXPR_EXT_VECTOR_ELEMENT; -} - -void PCHStmtWriter::VisitInitListExpr(InitListExpr *E) { - VisitExpr(E); - Record.push_back(E->getNumInits()); - for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) - Writer.AddStmt(E->getInit(I)); - Writer.AddStmt(E->getSyntacticForm()); - Writer.AddSourceLocation(E->getLBraceLoc(), Record); - Writer.AddSourceLocation(E->getRBraceLoc(), Record); - Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record); - Record.push_back(E->hadArrayRangeDesignator()); - Code = pch::EXPR_INIT_LIST; -} - -void PCHStmtWriter::VisitDesignatedInitExpr(DesignatedInitExpr *E) { - VisitExpr(E); - Record.push_back(E->getNumSubExprs()); - for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) - Writer.AddStmt(E->getSubExpr(I)); - Writer.AddSourceLocation(E->getEqualOrColonLoc(), Record); - Record.push_back(E->usesGNUSyntax()); - for (DesignatedInitExpr::designators_iterator D = E->designators_begin(), - DEnd = E->designators_end(); - D != DEnd; ++D) { - if (D->isFieldDesignator()) { - if (FieldDecl *Field = D->getField()) { - Record.push_back(pch::DESIG_FIELD_DECL); - Writer.AddDeclRef(Field, Record); - } else { - Record.push_back(pch::DESIG_FIELD_NAME); - Writer.AddIdentifierRef(D->getFieldName(), Record); - } - Writer.AddSourceLocation(D->getDotLoc(), Record); - Writer.AddSourceLocation(D->getFieldLoc(), Record); - } else if (D->isArrayDesignator()) { - Record.push_back(pch::DESIG_ARRAY); - Record.push_back(D->getFirstExprIndex()); - Writer.AddSourceLocation(D->getLBracketLoc(), Record); - Writer.AddSourceLocation(D->getRBracketLoc(), Record); - } else { - assert(D->isArrayRangeDesignator() && "Unknown designator"); - Record.push_back(pch::DESIG_ARRAY_RANGE); - Record.push_back(D->getFirstExprIndex()); - Writer.AddSourceLocation(D->getLBracketLoc(), Record); - Writer.AddSourceLocation(D->getEllipsisLoc(), Record); - Writer.AddSourceLocation(D->getRBracketLoc(), Record); - } - } - Code = pch::EXPR_DESIGNATED_INIT; -} - -void PCHStmtWriter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { - VisitExpr(E); - Code = pch::EXPR_IMPLICIT_VALUE_INIT; -} - -void PCHStmtWriter::VisitVAArgExpr(VAArgExpr *E) { - VisitExpr(E); - Writer.AddStmt(E->getSubExpr()); - Writer.AddSourceLocation(E->getBuiltinLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_VA_ARG; -} - -void PCHStmtWriter::VisitAddrLabelExpr(AddrLabelExpr *E) { - VisitExpr(E); - Writer.AddSourceLocation(E->getAmpAmpLoc(), Record); - Writer.AddSourceLocation(E->getLabelLoc(), Record); - Record.push_back(Writer.GetLabelID(E->getLabel())); - Code = pch::EXPR_ADDR_LABEL; -} - -void PCHStmtWriter::VisitStmtExpr(StmtExpr *E) { - VisitExpr(E); - Writer.AddStmt(E->getSubStmt()); - Writer.AddSourceLocation(E->getLParenLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_STMT; -} - -void PCHStmtWriter::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) { - VisitExpr(E); - Writer.AddTypeRef(E->getArgType1(), Record); - Writer.AddTypeRef(E->getArgType2(), Record); - Writer.AddSourceLocation(E->getBuiltinLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_TYPES_COMPATIBLE; -} - -void PCHStmtWriter::VisitChooseExpr(ChooseExpr *E) { - VisitExpr(E); - Writer.AddStmt(E->getCond()); - Writer.AddStmt(E->getLHS()); - Writer.AddStmt(E->getRHS()); - Writer.AddSourceLocation(E->getBuiltinLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_CHOOSE; -} - -void PCHStmtWriter::VisitGNUNullExpr(GNUNullExpr *E) { - VisitExpr(E); - Writer.AddSourceLocation(E->getTokenLocation(), Record); - Code = pch::EXPR_GNU_NULL; -} - -void PCHStmtWriter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { - VisitExpr(E); - Record.push_back(E->getNumSubExprs()); - for (unsigned I = 0, N = E->getNumSubExprs(); I != N; ++I) - Writer.AddStmt(E->getExpr(I)); - Writer.AddSourceLocation(E->getBuiltinLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_SHUFFLE_VECTOR; -} - -void PCHStmtWriter::VisitBlockExpr(BlockExpr *E) { - VisitExpr(E); - Writer.AddDeclRef(E->getBlockDecl(), Record); - Record.push_back(E->hasBlockDeclRefExprs()); - Code = pch::EXPR_BLOCK; -} - -void PCHStmtWriter::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { - VisitExpr(E); - Writer.AddDeclRef(E->getDecl(), Record); - Writer.AddSourceLocation(E->getLocation(), Record); - Record.push_back(E->isByRef()); - Record.push_back(E->isConstQualAdded()); - Writer.AddStmt(E->getCopyConstructorExpr()); - Code = pch::EXPR_BLOCK_DECL_REF; -} - -//===----------------------------------------------------------------------===// -// Objective-C Expressions and Statements. -//===----------------------------------------------------------------------===// - -void PCHStmtWriter::VisitObjCStringLiteral(ObjCStringLiteral *E) { - VisitExpr(E); - Writer.AddStmt(E->getString()); - Writer.AddSourceLocation(E->getAtLoc(), Record); - Code = pch::EXPR_OBJC_STRING_LITERAL; -} - -void PCHStmtWriter::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { - VisitExpr(E); - Writer.AddTypeSourceInfo(E->getEncodedTypeSourceInfo(), Record); - Writer.AddSourceLocation(E->getAtLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_OBJC_ENCODE; -} - -void PCHStmtWriter::VisitObjCSelectorExpr(ObjCSelectorExpr *E) { - VisitExpr(E); - Writer.AddSelectorRef(E->getSelector(), Record); - Writer.AddSourceLocation(E->getAtLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_OBJC_SELECTOR_EXPR; -} - -void PCHStmtWriter::VisitObjCProtocolExpr(ObjCProtocolExpr *E) { - VisitExpr(E); - Writer.AddDeclRef(E->getProtocol(), Record); - Writer.AddSourceLocation(E->getAtLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_OBJC_PROTOCOL_EXPR; -} - -void PCHStmtWriter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { - VisitExpr(E); - Writer.AddDeclRef(E->getDecl(), Record); - Writer.AddSourceLocation(E->getLocation(), Record); - Writer.AddStmt(E->getBase()); - Record.push_back(E->isArrow()); - Record.push_back(E->isFreeIvar()); - Code = pch::EXPR_OBJC_IVAR_REF_EXPR; -} - -void PCHStmtWriter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { - VisitExpr(E); - Writer.AddDeclRef(E->getProperty(), Record); - Writer.AddSourceLocation(E->getLocation(), Record); - Writer.AddStmt(E->getBase()); - Code = pch::EXPR_OBJC_PROPERTY_REF_EXPR; -} - -void PCHStmtWriter::VisitObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *E) { - VisitExpr(E); - Writer.AddDeclRef(E->getGetterMethod(), Record); - Writer.AddDeclRef(E->getSetterMethod(), Record); - - // NOTE: InterfaceDecl and Base are mutually exclusive. - Writer.AddDeclRef(E->getInterfaceDecl(), Record); - Writer.AddStmt(E->getBase()); - Writer.AddSourceLocation(E->getLocation(), Record); - Writer.AddSourceLocation(E->getClassLoc(), Record); - Code = pch::EXPR_OBJC_KVC_REF_EXPR; -} - -void PCHStmtWriter::VisitObjCMessageExpr(ObjCMessageExpr *E) { - VisitExpr(E); - Record.push_back(E->getNumArgs()); - Record.push_back((unsigned)E->getReceiverKind()); // FIXME: stable encoding - switch (E->getReceiverKind()) { - case ObjCMessageExpr::Instance: - Writer.AddStmt(E->getInstanceReceiver()); - break; - - case ObjCMessageExpr::Class: - Writer.AddTypeSourceInfo(E->getClassReceiverTypeInfo(), Record); - break; - - case ObjCMessageExpr::SuperClass: - case ObjCMessageExpr::SuperInstance: - Writer.AddTypeRef(E->getSuperType(), Record); - Writer.AddSourceLocation(E->getSuperLoc(), Record); - break; - } - - if (E->getMethodDecl()) { - Record.push_back(1); - Writer.AddDeclRef(E->getMethodDecl(), Record); - } else { - Record.push_back(0); - Writer.AddSelectorRef(E->getSelector(), Record); - } - - Writer.AddSourceLocation(E->getLeftLoc(), Record); - Writer.AddSourceLocation(E->getRightLoc(), Record); - - for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end(); - Arg != ArgEnd; ++Arg) - Writer.AddStmt(*Arg); - Code = pch::EXPR_OBJC_MESSAGE_EXPR; -} - -void PCHStmtWriter::VisitObjCSuperExpr(ObjCSuperExpr *E) { - VisitExpr(E); - Writer.AddSourceLocation(E->getLoc(), Record); - Code = pch::EXPR_OBJC_SUPER_EXPR; -} - -void PCHStmtWriter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { - VisitStmt(S); - Writer.AddStmt(S->getElement()); - Writer.AddStmt(S->getCollection()); - Writer.AddStmt(S->getBody()); - Writer.AddSourceLocation(S->getForLoc(), Record); - Writer.AddSourceLocation(S->getRParenLoc(), Record); - Code = pch::STMT_OBJC_FOR_COLLECTION; -} - -void PCHStmtWriter::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { - Writer.AddStmt(S->getCatchBody()); - Writer.AddDeclRef(S->getCatchParamDecl(), Record); - Writer.AddSourceLocation(S->getAtCatchLoc(), Record); - Writer.AddSourceLocation(S->getRParenLoc(), Record); - Code = pch::STMT_OBJC_CATCH; -} - -void PCHStmtWriter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { - Writer.AddStmt(S->getFinallyBody()); - Writer.AddSourceLocation(S->getAtFinallyLoc(), Record); - Code = pch::STMT_OBJC_FINALLY; -} - -void PCHStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { - Record.push_back(S->getNumCatchStmts()); - Record.push_back(S->getFinallyStmt() != 0); - Writer.AddStmt(S->getTryBody()); - for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) - Writer.AddStmt(S->getCatchStmt(I)); - if (S->getFinallyStmt()) - Writer.AddStmt(S->getFinallyStmt()); - Writer.AddSourceLocation(S->getAtTryLoc(), Record); - Code = pch::STMT_OBJC_AT_TRY; -} - -void PCHStmtWriter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { - Writer.AddStmt(S->getSynchExpr()); - Writer.AddStmt(S->getSynchBody()); - Writer.AddSourceLocation(S->getAtSynchronizedLoc(), Record); - Code = pch::STMT_OBJC_AT_SYNCHRONIZED; -} - -void PCHStmtWriter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { - Writer.AddStmt(S->getThrowExpr()); - Writer.AddSourceLocation(S->getThrowLoc(), Record); - Code = pch::STMT_OBJC_AT_THROW; -} - -//===----------------------------------------------------------------------===// -// C++ Expressions and Statements. -//===----------------------------------------------------------------------===// - -void PCHStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { - VisitCallExpr(E); - Record.push_back(E->getOperator()); - Code = pch::EXPR_CXX_OPERATOR_CALL; -} - -void PCHStmtWriter::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { - VisitCallExpr(E); - Code = pch::EXPR_CXX_MEMBER_CALL; -} - -void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) { - VisitExpr(E); - Record.push_back(E->getNumArgs()); - for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) - Writer.AddStmt(E->getArg(I)); - Writer.AddDeclRef(E->getConstructor(), Record); - Writer.AddSourceLocation(E->getLocation(), Record); - Record.push_back(E->isElidable()); - Record.push_back(E->requiresZeroInitialization()); - Record.push_back(E->getConstructionKind()); // FIXME: stable encoding - Code = pch::EXPR_CXX_CONSTRUCT; -} - -void PCHStmtWriter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) { - VisitCXXConstructExpr(E); - Writer.AddSourceLocation(E->getTypeBeginLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_CXX_TEMPORARY_OBJECT; -} - -void PCHStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { - VisitExplicitCastExpr(E); - Writer.AddSourceLocation(E->getOperatorLoc(), Record); -} - -void PCHStmtWriter::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) { - VisitCXXNamedCastExpr(E); - Code = pch::EXPR_CXX_STATIC_CAST; -} - -void PCHStmtWriter::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) { - VisitCXXNamedCastExpr(E); - Code = pch::EXPR_CXX_DYNAMIC_CAST; -} - -void PCHStmtWriter::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) { - VisitCXXNamedCastExpr(E); - Code = pch::EXPR_CXX_REINTERPRET_CAST; -} - -void PCHStmtWriter::VisitCXXConstCastExpr(CXXConstCastExpr *E) { - VisitCXXNamedCastExpr(E); - Code = pch::EXPR_CXX_CONST_CAST; -} - -void PCHStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) { - VisitExplicitCastExpr(E); - Writer.AddSourceLocation(E->getTypeBeginLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_CXX_FUNCTIONAL_CAST; -} - -void PCHStmtWriter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { - VisitExpr(E); - Record.push_back(E->getValue()); - Writer.AddSourceLocation(E->getLocation(), Record); - Code = pch::EXPR_CXX_BOOL_LITERAL; -} - -void PCHStmtWriter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { - VisitExpr(E); - Writer.AddSourceLocation(E->getLocation(), Record); - Code = pch::EXPR_CXX_NULL_PTR_LITERAL; -} - -void PCHStmtWriter::VisitCXXTypeidExpr(CXXTypeidExpr *E) { - VisitExpr(E); - Writer.AddSourceRange(E->getSourceRange(), Record); - if (E->isTypeOperand()) { - Writer.AddTypeSourceInfo(E->getTypeOperandSourceInfo(), Record); - Code = pch::EXPR_CXX_TYPEID_TYPE; - } else { - Writer.AddStmt(E->getExprOperand()); - Code = pch::EXPR_CXX_TYPEID_EXPR; - } -} - -void PCHStmtWriter::VisitCXXThisExpr(CXXThisExpr *E) { - VisitExpr(E); - Writer.AddSourceLocation(E->getLocation(), Record); - Record.push_back(E->isImplicit()); - Code = pch::EXPR_CXX_THIS; -} - -void PCHStmtWriter::VisitCXXThrowExpr(CXXThrowExpr *E) { - VisitExpr(E); - Writer.AddSourceLocation(E->getThrowLoc(), Record); - Writer.AddStmt(E->getSubExpr()); - Code = pch::EXPR_CXX_THROW; -} - -void PCHStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { - VisitExpr(E); - - bool HasOtherExprStored = E->Param.getInt(); - // Store these first, the reader reads them before creation. - Record.push_back(HasOtherExprStored); - if (HasOtherExprStored) - Writer.AddStmt(E->getExpr()); - Writer.AddDeclRef(E->getParam(), Record); - Writer.AddSourceLocation(E->getUsedLocation(), Record); - - Code = pch::EXPR_CXX_DEFAULT_ARG; -} - -void PCHStmtWriter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { - VisitExpr(E); - Writer.AddCXXTemporary(E->getTemporary(), Record); - Writer.AddStmt(E->getSubExpr()); - Code = pch::EXPR_CXX_BIND_TEMPORARY; -} - -void PCHStmtWriter::VisitCXXBindReferenceExpr(CXXBindReferenceExpr *E) { - VisitExpr(E); - Writer.AddStmt(E->getSubExpr()); - Record.push_back(E->extendsLifetime()); - Record.push_back(E->requiresTemporaryCopy()); - Code = pch::EXPR_CXX_BIND_REFERENCE; -} - -void PCHStmtWriter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) { - VisitExpr(E); - Writer.AddSourceLocation(E->getTypeBeginLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_CXX_SCALAR_VALUE_INIT; -} - -void PCHStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) { - VisitExpr(E); - Record.push_back(E->isGlobalNew()); - Record.push_back(E->hasInitializer()); - Record.push_back(E->isArray()); - Record.push_back(E->getNumPlacementArgs()); - Record.push_back(E->getNumConstructorArgs()); - Writer.AddDeclRef(E->getOperatorNew(), Record); - Writer.AddDeclRef(E->getOperatorDelete(), Record); - Writer.AddDeclRef(E->getConstructor(), Record); - Writer.AddSourceRange(E->getTypeIdParens(), Record); - Writer.AddSourceLocation(E->getStartLoc(), Record); - Writer.AddSourceLocation(E->getEndLoc(), Record); - for (CXXNewExpr::arg_iterator I = E->raw_arg_begin(), e = E->raw_arg_end(); - I != e; ++I) - Writer.AddStmt(*I); - - Code = pch::EXPR_CXX_NEW; -} - -void PCHStmtWriter::VisitCXXDeleteExpr(CXXDeleteExpr *E) { - VisitExpr(E); - Record.push_back(E->isGlobalDelete()); - Record.push_back(E->isArrayForm()); - Writer.AddDeclRef(E->getOperatorDelete(), Record); - Writer.AddStmt(E->getArgument()); - Writer.AddSourceLocation(E->getSourceRange().getBegin(), Record); - - Code = pch::EXPR_CXX_DELETE; -} - -void PCHStmtWriter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { - VisitExpr(E); - - Writer.AddStmt(E->getBase()); - Record.push_back(E->isArrow()); - Writer.AddSourceLocation(E->getOperatorLoc(), Record); - Writer.AddNestedNameSpecifier(E->getQualifier(), Record); - Writer.AddSourceRange(E->getQualifierRange(), Record); - Writer.AddTypeSourceInfo(E->getScopeTypeInfo(), Record); - Writer.AddSourceLocation(E->getColonColonLoc(), Record); - Writer.AddSourceLocation(E->getTildeLoc(), Record); - - // PseudoDestructorTypeStorage. - Writer.AddIdentifierRef(E->getDestroyedTypeIdentifier(), Record); - if (E->getDestroyedTypeIdentifier()) - Writer.AddSourceLocation(E->getDestroyedTypeLoc(), Record); - else - Writer.AddTypeSourceInfo(E->getDestroyedTypeInfo(), Record); - - Code = pch::EXPR_CXX_PSEUDO_DESTRUCTOR; -} - -void PCHStmtWriter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { - VisitExpr(E); - Record.push_back(E->getNumTemporaries()); - for (unsigned i = 0, e = E->getNumTemporaries(); i != e; ++i) - Writer.AddCXXTemporary(E->getTemporary(i), Record); - - Writer.AddStmt(E->getSubExpr()); - Code = pch::EXPR_CXX_EXPR_WITH_TEMPORARIES; -} - -void -PCHStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){ - VisitExpr(E); - - // Don't emit anything here, NumTemplateArgs must be emitted first. - - if (E->hasExplicitTemplateArgs()) { - const ExplicitTemplateArgumentList &Args - = *E->getExplicitTemplateArgumentList(); - assert(Args.NumTemplateArgs && - "Num of template args was zero! PCH reading will mess up!"); - Record.push_back(Args.NumTemplateArgs); - AddExplicitTemplateArgumentList(Args); - } else { - Record.push_back(0); - } - - if (!E->isImplicitAccess()) - Writer.AddStmt(E->getBase()); - else - Writer.AddStmt(0); - Writer.AddTypeRef(E->getBaseType(), Record); - Record.push_back(E->isArrow()); - Writer.AddSourceLocation(E->getOperatorLoc(), Record); - Writer.AddNestedNameSpecifier(E->getQualifier(), Record); - Writer.AddSourceRange(E->getQualifierRange(), Record); - Writer.AddDeclRef(E->getFirstQualifierFoundInScope(), Record); - Writer.AddDeclarationName(E->getMember(), Record); - Writer.AddSourceLocation(E->getMemberLoc(), Record); - Code = pch::EXPR_CXX_DEPENDENT_SCOPE_MEMBER; -} - -void -PCHStmtWriter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { - VisitExpr(E); - - // Don't emit anything here, NumTemplateArgs must be emitted first. - - if (E->hasExplicitTemplateArgs()) { - const ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs(); - assert(Args.NumTemplateArgs && - "Num of template args was zero! PCH reading will mess up!"); - Record.push_back(Args.NumTemplateArgs); - AddExplicitTemplateArgumentList(Args); - } else { - Record.push_back(0); - } - - Writer.AddDeclarationName(E->getDeclName(), Record); - Writer.AddSourceLocation(E->getLocation(), Record); - Writer.AddSourceRange(E->getQualifierRange(), Record); - Writer.AddNestedNameSpecifier(E->getQualifier(), Record); - Code = pch::EXPR_CXX_DEPENDENT_SCOPE_DECL_REF; -} - -void -PCHStmtWriter::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) { - VisitExpr(E); - Record.push_back(E->arg_size()); - for (CXXUnresolvedConstructExpr::arg_iterator - ArgI = E->arg_begin(), ArgE = E->arg_end(); ArgI != ArgE; ++ArgI) - Writer.AddStmt(*ArgI); - Writer.AddSourceLocation(E->getTypeBeginLoc(), Record); - Writer.AddTypeRef(E->getTypeAsWritten(), Record); - Writer.AddSourceLocation(E->getLParenLoc(), Record); - Writer.AddSourceLocation(E->getRParenLoc(), Record); - Code = pch::EXPR_CXX_UNRESOLVED_CONSTRUCT; -} - -void PCHStmtWriter::VisitOverloadExpr(OverloadExpr *E) { - VisitExpr(E); - - // Don't emit anything here, NumTemplateArgs must be emitted first. - - if (E->hasExplicitTemplateArgs()) { - const ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs(); - assert(Args.NumTemplateArgs && - "Num of template args was zero! PCH reading will mess up!"); - Record.push_back(Args.NumTemplateArgs); - AddExplicitTemplateArgumentList(Args); - } else { - Record.push_back(0); - } - - Record.push_back(E->getNumDecls()); - for (OverloadExpr::decls_iterator - OvI = E->decls_begin(), OvE = E->decls_end(); OvI != OvE; ++OvI) { - Writer.AddDeclRef(OvI.getDecl(), Record); - Record.push_back(OvI.getAccess()); - } - - Writer.AddDeclarationName(E->getName(), Record); - Writer.AddNestedNameSpecifier(E->getQualifier(), Record); - Writer.AddSourceRange(E->getQualifierRange(), Record); - Writer.AddSourceLocation(E->getNameLoc(), Record); -} - -void PCHStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { - VisitOverloadExpr(E); - Record.push_back(E->isArrow()); - Record.push_back(E->hasUnresolvedUsing()); - Writer.AddStmt(!E->isImplicitAccess() ? E->getBase() : 0); - Writer.AddTypeRef(E->getBaseType(), Record); - Writer.AddSourceLocation(E->getOperatorLoc(), Record); - Code = pch::EXPR_CXX_UNRESOLVED_MEMBER; -} - -void PCHStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { - VisitOverloadExpr(E); - Record.push_back(E->requiresADL()); - Record.push_back(E->isOverloaded()); - Writer.AddDeclRef(E->getNamingClass(), Record); - Code = pch::EXPR_CXX_UNRESOLVED_LOOKUP; -} - -void PCHStmtWriter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { - VisitExpr(E); - Record.push_back(E->getTrait()); - Writer.AddSourceRange(E->getSourceRange(), Record); - Writer.AddTypeRef(E->getQueriedType(), Record); - Code = pch::EXPR_CXX_UNARY_TYPE_TRAIT; -} - -//===----------------------------------------------------------------------===// -// PCHWriter Implementation -//===----------------------------------------------------------------------===// - -unsigned PCHWriter::RecordSwitchCaseID(SwitchCase *S) { - assert(SwitchCaseIDs.find(S) == SwitchCaseIDs.end() && - "SwitchCase recorded twice"); - unsigned NextID = SwitchCaseIDs.size(); - SwitchCaseIDs[S] = NextID; - return NextID; -} - -unsigned PCHWriter::getSwitchCaseID(SwitchCase *S) { - assert(SwitchCaseIDs.find(S) != SwitchCaseIDs.end() && - "SwitchCase hasn't been seen yet"); - return SwitchCaseIDs[S]; -} - -/// \brief Retrieve the ID for the given label statement, which may -/// or may not have been emitted yet. -unsigned PCHWriter::GetLabelID(LabelStmt *S) { - std::map::iterator Pos = LabelIDs.find(S); - if (Pos != LabelIDs.end()) - return Pos->second; - - unsigned NextID = LabelIDs.size(); - LabelIDs[S] = NextID; - return NextID; -} - -/// \brief Write the given substatement or subexpression to the -/// bitstream. -void PCHWriter::WriteSubStmt(Stmt *S) { - RecordData Record; - PCHStmtWriter Writer(*this, Record); - ++NumStatements; - - if (!S) { - Stream.EmitRecord(pch::STMT_NULL_PTR, Record); - return; - } - - // Redirect PCHWriter::AddStmt to collect sub stmts. - llvm::SmallVector SubStmts; - CollectedStmts = &SubStmts; - - Writer.Code = pch::STMT_NULL_PTR; - Writer.Visit(S); - -#ifndef NDEBUG - if (Writer.Code == pch::STMT_NULL_PTR) { - SourceManager &SrcMgr - = DeclIDs.begin()->first->getASTContext().getSourceManager(); - S->dump(SrcMgr); - assert(0 && "Unhandled sub statement writing PCH file"); - } -#endif - - // Revert PCHWriter::AddStmt. - CollectedStmts = &StmtsToEmit; - - // Write the sub stmts in reverse order, last to first. When reading them back - // we will read them in correct order by "pop"ing them from the Stmts stack. - // This simplifies reading and allows to store a variable number of sub stmts - // without knowing it in advance. - while (!SubStmts.empty()) - WriteSubStmt(SubStmts.pop_back_val()); - - Stream.EmitRecord(Writer.Code, Record); -} - -/// \brief Flush all of the statements that have been added to the -/// queue via AddStmt(). -void PCHWriter::FlushStmts() { - RecordData Record; - - for (unsigned I = 0, N = StmtsToEmit.size(); I != N; ++I) { - WriteSubStmt(StmtsToEmit[I]); - - assert(N == StmtsToEmit.size() && - "Substatement writen via AddStmt rather than WriteSubStmt!"); - - // Note that we are at the end of a full expression. Any - // expression records that follow this one are part of a different - // expression. - Stream.EmitRecord(pch::STMT_STOP, Record); - } - - StmtsToEmit.clear(); -} diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp deleted file mode 100644 index 9220677..0000000 --- a/lib/Frontend/PrintParserCallbacks.cpp +++ /dev/null @@ -1,852 +0,0 @@ -//===--- PrintParserActions.cpp - Implement -parse-print-callbacks mode ---===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This code simply runs the preprocessor on the input file and prints out the -// result. This is the traditional behavior of the -E option. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/Utils.h" -#include "clang/Parse/Action.h" -#include "clang/Parse/DeclSpec.h" -#include "llvm/Support/raw_ostream.h" -using namespace clang; - -namespace { - class ParserPrintActions : public MinimalAction { - llvm::raw_ostream& Out; - - public: - ParserPrintActions(Preprocessor &PP, llvm::raw_ostream& OS) - : MinimalAction(PP), Out(OS) {} - - // Printing Functions which also must call MinimalAction - - /// ActOnDeclarator - This callback is invoked when a declarator is parsed - /// and 'Init' specifies the initializer if any. This is for things like: - /// "int X = 4" or "typedef int foo". - virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) { - Out << __FUNCTION__ << " "; - if (IdentifierInfo *II = D.getIdentifier()) { - Out << "'" << II->getName() << "'"; - } else { - Out << ""; - } - Out << "\n"; - - // Pass up to EmptyActions so that the symbol table is maintained right. - return MinimalAction::ActOnDeclarator(S, D); - } - /// ActOnPopScope - This callback is called immediately before the specified - /// scope is popped and deleted. - virtual void ActOnPopScope(SourceLocation Loc, Scope *S) { - Out << __FUNCTION__ << "\n"; - return MinimalAction::ActOnPopScope(Loc, S); - } - - /// ActOnTranslationUnitScope - This callback is called once, immediately - /// after creating the translation unit scope (in Parser::Initialize). - virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { - Out << __FUNCTION__ << "\n"; - MinimalAction::ActOnTranslationUnitScope(Loc, S); - } - - - Action::DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, - SourceLocation ClassLoc, - IdentifierInfo *SuperName, - SourceLocation SuperLoc, - const DeclPtrTy *ProtoRefs, - unsigned NumProtocols, - const SourceLocation *ProtoLocs, - SourceLocation EndProtoLoc, - AttributeList *AttrList) { - Out << __FUNCTION__ << "\n"; - return MinimalAction::ActOnStartClassInterface(AtInterfaceLoc, - ClassName, ClassLoc, - SuperName, SuperLoc, - ProtoRefs, NumProtocols, - ProtoLocs, EndProtoLoc, - AttrList); - } - - /// ActOnForwardClassDeclaration - - /// Scope will always be top level file scope. - Action::DeclPtrTy ActOnForwardClassDeclaration(SourceLocation AtClassLoc, - IdentifierInfo **IdentList, - SourceLocation *IdentLocs, - unsigned NumElts) { - Out << __FUNCTION__ << "\n"; - return MinimalAction::ActOnForwardClassDeclaration(AtClassLoc, IdentList, - IdentLocs, NumElts); - } - - // Pure Printing - - /// ActOnParamDeclarator - This callback is invoked when a parameter - /// declarator is parsed. This callback only occurs for functions - /// with prototypes. S is the function prototype scope for the - /// parameters (C++ [basic.scope.proto]). - virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D) { - Out << __FUNCTION__ << " "; - if (IdentifierInfo *II = D.getIdentifier()) { - Out << "'" << II->getName() << "'"; - } else { - Out << ""; - } - Out << "\n"; - return DeclPtrTy(); - } - - /// AddInitializerToDecl - This action is called immediately after - /// ParseDeclarator (when an initializer is present). The code is factored - /// this way to make sure we are able to handle the following: - /// void func() { int xx = xx; } - /// This allows ActOnDeclarator to register "xx" prior to parsing the - /// initializer. The declaration above should still result in a warning, - /// since the reference to "xx" is uninitialized. - virtual void AddInitializerToDecl(DeclPtrTy Dcl, ExprArg Init) { - Out << __FUNCTION__ << "\n"; - } - - /// FinalizeDeclaratorGroup - After a sequence of declarators are parsed, - /// this gives the actions implementation a chance to process the group as - /// a whole. - virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec& DS, - DeclPtrTy *Group, - unsigned NumDecls) { - Out << __FUNCTION__ << "\n"; - return DeclGroupPtrTy(); - } - - /// ActOnStartOfFunctionDef - This is called at the start of a function - /// definition, instead of calling ActOnDeclarator. The Declarator includes - /// information about formal arguments that are part of this function. - virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope, - Declarator &D){ - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } - - /// ActOnStartOfFunctionDef - This is called at the start of a function - /// definition, after the FunctionDecl has already been created. - virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } - - virtual void ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { - Out << __FUNCTION__ << "\n"; - } - - /// ActOnFunctionDefBody - This is called when a function body has completed - /// parsing. Decl is the DeclTy returned by ParseStartOfFunctionDef. - virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body) { - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } - - virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc, - ExprArg AsmString) { - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } - - /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with - /// no declarator (e.g. "struct foo;") is parsed. - virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, - DeclSpec &DS) { - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } - - /// ActOnLinkageSpec - Parsed a C++ linkage-specification that - /// contained braces. Lang/StrSize contains the language string that - /// was parsed at location Loc. Decls/NumDecls provides the - /// declarations parsed inside the linkage specification. - virtual DeclPtrTy ActOnLinkageSpec(SourceLocation Loc, - SourceLocation LBrace, - SourceLocation RBrace, const char *Lang, - unsigned StrSize, - DeclPtrTy *Decls, unsigned NumDecls) { - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } - - /// ActOnLinkageSpec - Parsed a C++ linkage-specification without - /// braces. Lang/StrSize contains the language string that was - /// parsed at location Loc. D is the declaration parsed. - virtual DeclPtrTy ActOnLinkageSpec(SourceLocation Loc, const char *Lang, - unsigned StrSize, DeclPtrTy D) { - return DeclPtrTy(); - } - - //===------------------------------------------------------------------===// - // Type Parsing Callbacks. - //===------------------------------------------------------------------===// - - virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) { - Out << __FUNCTION__ << "\n"; - return TypeResult(); - } - - virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, CXXScopeSpec &SS, - IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr, AccessSpecifier AS, - MultiTemplateParamsArg TemplateParameterLists, - bool &OwnedDecl, bool &IsDependent) { - // TagType is an instance of DeclSpec::TST, indicating what kind of tag this - // is (struct/union/enum/class). - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } - - /// Act on @defs() element found when parsing a structure. ClassName is the - /// name of the referenced class. - virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, - IdentifierInfo *ClassName, - llvm::SmallVectorImpl &Decls) { - Out << __FUNCTION__ << "\n"; - } - - virtual DeclPtrTy ActOnField(Scope *S, DeclPtrTy TagD, - SourceLocation DeclStart, - Declarator &D, ExprTy *BitfieldWidth) { - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } - - virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart, - DeclPtrTy IntfDecl, - Declarator &D, ExprTy *BitfieldWidth, - tok::ObjCKeywordKind visibility) { - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } - - virtual void ActOnFields(Scope* S, SourceLocation RecLoc, DeclPtrTy TagDecl, - DeclPtrTy *Fields, unsigned NumFields, - SourceLocation LBrac, SourceLocation RBrac, - AttributeList *AttrList) { - Out << __FUNCTION__ << "\n"; - } - - virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl, - DeclPtrTy LastEnumConstant, - SourceLocation IdLoc,IdentifierInfo *Id, - SourceLocation EqualLoc, ExprTy *Val) { - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } - - virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, - SourceLocation RBraceLoc, DeclPtrTy EnumDecl, - DeclPtrTy *Elements, unsigned NumElements, - Scope *S, AttributeList *AttrList) { - Out << __FUNCTION__ << "\n"; - } - - //===------------------------------------------------------------------===// - // Statement Parsing Callbacks. - //===------------------------------------------------------------------===// - - virtual OwningStmtResult ActOnNullStmt(SourceLocation SemiLoc) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - virtual OwningStmtResult ActOnCompoundStmt(SourceLocation L, - SourceLocation R, - MultiStmtArg Elts, - bool isStmtExpr) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - virtual OwningStmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, - SourceLocation StartLoc, - SourceLocation EndLoc) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - virtual OwningStmtResult ActOnExprStmt(FullExprArg Expr) { - Out << __FUNCTION__ << "\n"; - return OwningStmtResult(*this, Expr->release()); - } - - /// ActOnCaseStmt - Note that this handles the GNU 'case 1 ... 4' extension, - /// which can specify an RHS value. - virtual OwningStmtResult ActOnCaseStmt(SourceLocation CaseLoc, - ExprArg LHSVal, - SourceLocation DotDotDotLoc, - ExprArg RHSVal, - SourceLocation ColonLoc) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, - SourceLocation ColonLoc, - StmtArg SubStmt, Scope *CurScope){ - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - virtual OwningStmtResult ActOnLabelStmt(SourceLocation IdentLoc, - IdentifierInfo *II, - SourceLocation ColonLoc, - StmtArg SubStmt) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, - FullExprArg CondVal, DeclPtrTy CondVar, - StmtArg ThenVal, - SourceLocation ElseLoc, - StmtArg ElseVal) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - virtual OwningStmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, - ExprArg Cond, - DeclPtrTy CondVar) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, - StmtArg Switch, - StmtArg Body) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, - FullExprArg Cond, DeclPtrTy CondVar, - StmtArg Body) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, - SourceLocation WhileLoc, - SourceLocation LPLoc, ExprArg Cond, - SourceLocation RPLoc){ - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc, - SourceLocation LParenLoc, - StmtArg First, FullExprArg Second, - DeclPtrTy SecondVar, - FullExprArg Third, - SourceLocation RParenLoc, - StmtArg Body) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - virtual OwningStmtResult ActOnObjCForCollectionStmt( - SourceLocation ForColLoc, - SourceLocation LParenLoc, - StmtArg First, ExprArg Second, - SourceLocation RParenLoc, StmtArg Body) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - virtual OwningStmtResult ActOnGotoStmt(SourceLocation GotoLoc, - SourceLocation LabelLoc, - IdentifierInfo *LabelII) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - virtual OwningStmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, - SourceLocation StarLoc, - ExprArg DestExp) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - virtual OwningStmtResult ActOnContinueStmt(SourceLocation ContinueLoc, - Scope *CurScope) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - virtual OwningStmtResult ActOnBreakStmt(SourceLocation GotoLoc, - Scope *CurScope) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc, - ExprArg RetValExp) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc, - bool IsSimple, - bool IsVolatile, - unsigned NumOutputs, - unsigned NumInputs, - IdentifierInfo **Names, - MultiExprArg Constraints, - MultiExprArg Exprs, - ExprArg AsmString, - MultiExprArg Clobbers, - SourceLocation RParenLoc, - bool MSAsm) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - // Objective-c statements - virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, - SourceLocation RParen, - DeclPtrTy Parm, - StmtArg Body) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, - StmtArg Body) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, - StmtArg Try, - MultiStmtArg CatchStmts, - StmtArg Finally) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, - ExprArg Throw, - Scope *CurScope) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, - ExprArg SynchExpr, - StmtArg SynchBody) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - // C++ Statements - virtual DeclPtrTy ActOnExceptionDeclarator(Scope *S, Declarator &D) { - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } - - virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, - DeclPtrTy ExceptionDecl, - StmtArg HandlerBlock) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc, - StmtArg TryBlock, - MultiStmtArg Handlers) { - Out << __FUNCTION__ << "\n"; - return StmtEmpty(); - } - - //===------------------------------------------------------------------===// - // Expression Parsing Callbacks. - //===------------------------------------------------------------------===// - - // Primary Expressions. - - /// ActOnIdentifierExpr - Parse an identifier in expression context. - /// 'HasTrailingLParen' indicates whether or not the identifier has a '(' - /// token immediately after it. - virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, - IdentifierInfo &II, - bool HasTrailingLParen, - const CXXScopeSpec *SS, - bool isAddressOfOperand) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr( - Scope *S, SourceLocation OperatorLoc, - OverloadedOperatorKind Op, - bool HasTrailingLParen, const CXXScopeSpec &SS, - bool isAddressOfOperand) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnCXXConversionFunctionExpr( - Scope *S, SourceLocation OperatorLoc, - TypeTy *Type, bool HasTrailingLParen, - const CXXScopeSpec &SS,bool isAddressOfOperand) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc, - tok::TokenKind Kind) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnCharacterConstant(const Token &) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnNumericConstant(const Token &) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - /// ActOnStringLiteral - The specified tokens were lexed as pasted string - /// fragments (e.g. "foo" "bar" L"baz"). - virtual OwningExprResult ActOnStringLiteral(const Token *Toks, - unsigned NumToks) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, - ExprArg Val) { - Out << __FUNCTION__ << "\n"; - return move(Val); // Default impl returns operand. - } - - // Postfix Expressions. - virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, - tok::TokenKind Kind, - ExprArg Input) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - virtual OwningExprResult ActOnArraySubscriptExpr(Scope *S, ExprArg Base, - SourceLocation LLoc, - ExprArg Idx, - SourceLocation RLoc) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - SourceLocation MemberLoc, - IdentifierInfo &Member, - DeclPtrTy ImplDecl, - const CXXScopeSpec *SS=0) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnCallExpr(Scope *S, ExprArg Fn, - SourceLocation LParenLoc, - MultiExprArg Args, - SourceLocation *CommaLocs, - SourceLocation RParenLoc) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - // Unary Operators. 'Tok' is the token for the operator. - virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, - tok::TokenKind Op, ExprArg Input) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - virtual OwningExprResult - ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, - void *TyOrEx, const SourceRange &ArgRange) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParen, - TypeTy *Ty, - SourceLocation RParen, - ExprArg Op) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc, - MultiExprArg InitList, - SourceLocation RParenLoc) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, - TypeTy *Ty, SourceLocation RParenLoc, - ExprArg Op) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, - tok::TokenKind Kind, - ExprArg LHS, ExprArg RHS) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null - /// in the case of a the GNU conditional expr extension. - virtual OwningExprResult ActOnConditionalOp(SourceLocation QuestionLoc, - SourceLocation ColonLoc, - ExprArg Cond, ExprArg LHS, - ExprArg RHS) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - //===--------------------- GNU Extension Expressions ------------------===// - - virtual OwningExprResult ActOnAddrLabel(SourceLocation OpLoc, - SourceLocation LabLoc, - IdentifierInfo *LabelII) {// "&&foo" - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnStmtExpr(SourceLocation LPLoc, - StmtArg SubStmt, - SourceLocation RPLoc) { // "({..})" - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S, - SourceLocation BuiltinLoc, - SourceLocation TypeLoc, - TypeTy *Arg1, - OffsetOfComponent *CompPtr, - unsigned NumComponents, - SourceLocation RParenLoc) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - // __builtin_types_compatible_p(type1, type2) - virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, - TypeTy *arg1,TypeTy *arg2, - SourceLocation RPLoc) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - // __builtin_choose_expr(constExpr, expr1, expr2) - virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, - ExprArg cond, ExprArg expr1, - ExprArg expr2, - SourceLocation RPLoc) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - // __builtin_va_arg(expr, type) - virtual OwningExprResult ActOnVAArg(SourceLocation BuiltinLoc, - ExprArg expr, TypeTy *type, - SourceLocation RPLoc) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnGNUNullExpr(SourceLocation TokenLoc) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope) { - Out << __FUNCTION__ << "\n"; - } - - virtual void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { - Out << __FUNCTION__ << "\n"; - } - - virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) { - Out << __FUNCTION__ << "\n"; - } - - virtual OwningExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, - StmtArg Body, - Scope *CurScope) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc, - IdentifierInfo *Ident, - SourceLocation LBrace, - AttributeList *AttrList) { - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } - - virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace) { - Out << __FUNCTION__ << "\n"; - return; - } - -#if 0 - // FIXME: AttrList should be deleted by this function, but the definition - // would have to be available. - virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope, - SourceLocation UsingLoc, - SourceLocation NamespcLoc, - const CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *NamespcName, - AttributeList *AttrList) { - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } -#endif - - virtual void ActOnParamDefaultArgument(DeclPtrTy param, - SourceLocation EqualLoc, - ExprArg defarg) { - Out << __FUNCTION__ << "\n"; - } - - virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param, - SourceLocation EqualLoc, - SourceLocation ArgLoc) { - Out << __FUNCTION__ << "\n"; - } - - virtual void ActOnParamDefaultArgumentError(DeclPtrTy param) { - Out << __FUNCTION__ << "\n"; - } - - virtual void AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, - SourceLocation LParenLoc, - MultiExprArg Exprs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc) { - Out << __FUNCTION__ << "\n"; - return; - } - - virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S, - DeclPtrTy Method) { - Out << __FUNCTION__ << "\n"; - } - - virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param) { - Out << __FUNCTION__ << "\n"; - } - - virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, - DeclPtrTy Method) { - Out << __FUNCTION__ << "\n"; - } - - virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc, - ExprArg AssertExpr, - ExprArg AssertMessageExpr) { - Out << __FUNCTION__ << "\n"; - return DeclPtrTy(); - } - - virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc, - tok::TokenKind Kind, - SourceLocation LAngleBracketLoc, - TypeTy *Ty, - SourceLocation RAngleBracketLoc, - SourceLocation LParenLoc, - ExprArg Op, - SourceLocation RParenLoc) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc, - SourceLocation LParenLoc, - bool isType, void *TyOrExpr, - SourceLocation RParenLoc) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnCXXThis(SourceLocation ThisLoc) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, - tok::TokenKind Kind) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnCXXThrow(SourceLocation OpLoc, ExprArg Op) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange, - TypeTy *TypeRep, - SourceLocation LParenLoc, - MultiExprArg Exprs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnCXXConditionDeclarationExpr(Scope *S, - SourceLocation StartLoc, - Declarator &D, - SourceLocation EqualLoc, - ExprArg AssignExprVal) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnCXXNew(SourceLocation StartLoc, - bool UseGlobal, - SourceLocation PlacementLParen, - MultiExprArg PlacementArgs, - SourceLocation PlacementRParen, - SourceRange TypeIdParens, - Declarator &D, - SourceLocation ConstructorLParen, - MultiExprArg ConstructorArgs, - SourceLocation ConstructorRParen) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc, - bool UseGlobal, bool ArrayForm, - ExprArg Operand) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - - virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT, - SourceLocation KWLoc, - SourceLocation LParen, - TypeTy *Ty, - SourceLocation RParen) { - Out << __FUNCTION__ << "\n"; - return ExprEmpty(); - } - }; -} - -MinimalAction *clang::CreatePrintParserActionsAction(Preprocessor &PP, - llvm::raw_ostream* OS) { - return new ParserPrintActions(PP, *OS); -} diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 73bca9a..cfaf8a2 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -85,6 +85,10 @@ public: llvm::raw_ostream &OS; private: unsigned CurLine; + + /// The current include nesting level, used by header include dumping (-H). + unsigned CurrentIncludeDepth; + bool EmittedTokensOnThisLine; bool EmittedMacroOnThisLine; SrcMgr::CharacteristicKind FileType; @@ -92,19 +96,22 @@ private: bool Initialized; bool DisableLineMarkers; bool DumpDefines; + bool DumpHeaderIncludes; bool UseLineDirective; + bool HasProcessedPredefines; public: PrintPPOutputPPCallbacks(Preprocessor &pp, llvm::raw_ostream &os, - bool lineMarkers, bool defines) + bool lineMarkers, bool defines, bool headers) : PP(pp), SM(PP.getSourceManager()), ConcatInfo(PP), OS(os), DisableLineMarkers(lineMarkers), - DumpDefines(defines) { - CurLine = 0; + DumpDefines(defines), DumpHeaderIncludes(headers) { + CurLine = CurrentIncludeDepth = 0; CurFilename += ""; EmittedTokensOnThisLine = false; EmittedMacroOnThisLine = false; FileType = SrcMgr::C_User; Initialized = false; + HasProcessedPredefines = false; // If we're in microsoft mode, use normal #line instead of line markers. UseLineDirective = PP.getLangOptions().Microsoft; @@ -137,6 +144,9 @@ public: /// MacroDefined - This hook is called whenever a macro definition is seen. void MacroDefined(const IdentifierInfo *II, const MacroInfo *MI); + /// MacroUndefined - This hook is called whenever a macro #undef is seen. + void MacroUndefined(SourceLocation Loc, const IdentifierInfo *II, + const MacroInfo *MI); }; } // end anonymous namespace @@ -216,7 +226,7 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, PresumedLoc UserLoc = SourceMgr.getPresumedLoc(Loc); unsigned NewLine = UserLoc.getLine(); - + if (Reason == PPCallbacks::EnterFile) { SourceLocation IncludeLoc = SourceMgr.getPresumedLoc(Loc).getIncludeLoc(); if (IncludeLoc.isValid()) @@ -228,16 +238,41 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, // directive and emits a bunch of spaces that aren't needed. Emulate this // strange behavior. } + + // Adjust the current include depth. + if (Reason == PPCallbacks::EnterFile) { + ++CurrentIncludeDepth; + } else { + if (CurrentIncludeDepth) + --CurrentIncludeDepth; + + // We track when we are done with the predefines by watching for the first + // place where we drop back to a nesting depth of 0. + if (CurrentIncludeDepth == 0 && !HasProcessedPredefines) + HasProcessedPredefines = true; + } CurLine = NewLine; - if (DisableLineMarkers) return; - CurFilename.clear(); CurFilename += UserLoc.getFilename(); Lexer::Stringify(CurFilename); FileType = NewFileType; + // Dump the header include information, if enabled and we are past the + // predefines buffer. + if (DumpHeaderIncludes && HasProcessedPredefines && + Reason == PPCallbacks::EnterFile) { + llvm::SmallString<256> Msg; + llvm::raw_svector_ostream OS(Msg); + for (unsigned i = 0; i != CurrentIncludeDepth; ++i) + OS << '.'; + OS << ' ' << CurFilename << '\n'; + llvm::errs() << OS.str(); + } + + if (DisableLineMarkers) return; + if (!Initialized) { WriteLineInfo(CurLine); Initialized = true; @@ -280,6 +315,16 @@ void PrintPPOutputPPCallbacks::MacroDefined(const IdentifierInfo *II, EmittedMacroOnThisLine = true; } +void PrintPPOutputPPCallbacks::MacroUndefined(SourceLocation Loc, + const IdentifierInfo *II, + const MacroInfo *MI) { + // Only print out macro definitions in -dD mode. + if (!DumpDefines) return; + + MoveToLine(Loc); + OS << "#undef " << II->getName(); + EmittedMacroOnThisLine = true; +} void PrintPPOutputPPCallbacks::PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, @@ -516,7 +561,7 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, llvm::raw_ostream *OS, PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks(PP, *OS, !Opts.ShowLineMarkers, - Opts.ShowMacros); + Opts.ShowMacros, Opts.ShowHeaderIncludes); PP.AddPragmaHandler(new UnknownPragmaHandler("#pragma", Callbacks)); PP.AddPragmaHandler("GCC", new UnknownPragmaHandler("#pragma GCC", Callbacks)); diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp index 21dc0ba..b660734 100644 --- a/lib/Frontend/StmtXML.cpp +++ b/lib/Frontend/StmtXML.cpp @@ -32,7 +32,8 @@ namespace { void addSpecialAttribute(const char* pName, StringLiteral* Str) { - Doc.addAttribute(pName, Doc.escapeString(Str->getStrData(), Str->getByteLength())); + Doc.addAttribute(pName, Doc.escapeString(Str->getString().data(), + Str->getString().size())); } void addSpecialAttribute(const char* pName, SizeOfAlignOfExpr* S) { @@ -261,7 +262,6 @@ const char *StmtXML::getOpcodeStr(UnaryOperator::Opcode Op) { case UnaryOperator::Real: return "__real"; case UnaryOperator::Imag: return "__imag"; case UnaryOperator::Extension: return "__extension__"; - case UnaryOperator::OffsetOf: return "__builtin_offsetof"; } } diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 1b5b7e2..1e453a0 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -447,11 +447,11 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, if (NumHints && DiagOpts->ShowFixits) { for (const FixItHint *Hint = Hints, *LastHint = Hints + NumHints; Hint != LastHint; ++Hint) { - if (Hint->InsertionLoc.isValid()) { + if (!Hint->CodeToInsert.empty()) { // We have an insertion hint. Determine whether the inserted // code is on the same line as the caret. std::pair HintLocInfo - = SM.getDecomposedInstantiationLoc(Hint->InsertionLoc); + = SM.getDecomposedInstantiationLoc(Hint->RemoveRange.getBegin()); if (SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) == SM.getLineNumber(FID, FileOffset)) { // Insert the new code into the line just below the code @@ -537,6 +537,48 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, if (DiagOpts->ShowColors) OS.resetColor(); } + + if (DiagOpts->ShowParseableFixits) { + + // We follow FixItRewriter's example in not (yet) handling + // fix-its in macros. + bool BadApples = false; + for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) { + if (Hint->RemoveRange.isInvalid() || + Hint->RemoveRange.getBegin().isMacroID() || + Hint->RemoveRange.getEnd().isMacroID()) { + BadApples = true; + break; + } + } + + if (!BadApples) { + for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) { + + SourceLocation B = Hint->RemoveRange.getBegin(); + SourceLocation E = Hint->RemoveRange.getEnd(); + + std::pair BInfo = SM.getDecomposedLoc(B); + std::pair EInfo = SM.getDecomposedLoc(E); + + // Adjust for token ranges. + if (Hint->RemoveRange.isTokenRange()) + EInfo.second += Lexer::MeasureTokenLength(E, SM, *LangOpts); + + // We specifically do not do word-wrapping or tab-expansion here, + // because this is supposed to be easy to parse. + OS << "fix-it:\""; + OS.write_escaped(SM.getPresumedLoc(B).getFilename()); + OS << "\":{" << SM.getLineNumber(BInfo.first, BInfo.second) + << ':' << SM.getColumnNumber(BInfo.first, BInfo.second) + << '-' << SM.getLineNumber(EInfo.first, EInfo.second) + << ':' << SM.getColumnNumber(EInfo.first, EInfo.second) + << "}:\""; + OS.write_escaped(Hint->CodeToInsert); + OS << "\"\n"; + } + } + } } /// \brief Skip over whitespace in the string, starting at the given diff --git a/lib/Frontend/VerifyDiagnosticsClient.cpp b/lib/Frontend/VerifyDiagnosticsClient.cpp index ae36481..31eb28f 100644 --- a/lib/Frontend/VerifyDiagnosticsClient.cpp +++ b/lib/Frontend/VerifyDiagnosticsClient.cpp @@ -171,13 +171,12 @@ public: : Begin(Begin), End(End), C(Begin), P(Begin), PEnd(NULL) { } // Return true if string literal is next. - bool Next(const std::string &S) { - std::string::size_type LEN = S.length(); + bool Next(llvm::StringRef S) { P = C; - PEnd = C + LEN; + PEnd = C + S.size(); if (PEnd > End) return false; - return !memcmp(P, S.c_str(), LEN); + return !memcmp(P, S.data(), S.size()); } // Return true if number is next. @@ -198,9 +197,9 @@ public: // Return true if string literal is found. // When true, P marks begin-position of S in content. - bool Search(const std::string &S) { + bool Search(llvm::StringRef S) { P = std::search(C, End, S.begin(), S.end()); - PEnd = P + S.length(); + PEnd = P + S.size(); return P != End; } @@ -484,7 +483,7 @@ void VerifyDiagnosticsClient::CheckDiagnostics() { ExpectedData ED; // Ensure any diagnostics go to the primary client. - DiagnosticClient *CurClient = Diags.getClient(); + DiagnosticClient *CurClient = Diags.takeClient(); Diags.setClient(PrimaryClient.get()); // If we have a preprocessor, scan the source for expected diagnostic @@ -507,6 +506,7 @@ void VerifyDiagnosticsClient::CheckDiagnostics() { "note", false)); } + Diags.takeClient(); Diags.setClient(CurClient); // Reset the buffer, we have processed all the diagnostics in it. diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt new file mode 100644 index 0000000..26c9fc7 --- /dev/null +++ b/lib/FrontendTool/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_NO_RTTI 1) + +add_clang_library(clangFrontendTool + ExecuteCompilerInvocation.cpp + ) diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp new file mode 100644 index 0000000..63c6287 --- /dev/null +++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -0,0 +1,155 @@ +//===--- ExecuteCompilerInvocation.cpp ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file holds ExecuteCompilerInvocation(). It is split into its own file to +// minimize the impact of pulling in essentially everything else in Clang. +// +//===----------------------------------------------------------------------===// + +#include "clang/FrontendTool/Utils.h" +#include "clang/Checker/FrontendActions.h" +#include "clang/CodeGen/CodeGenAction.h" +#include "clang/Driver/CC1Options.h" +#include "clang/Driver/OptTable.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendPluginRegistry.h" +#include "clang/Rewrite/FrontendActions.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/System/DynamicLibrary.h" +using namespace clang; + +static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { + using namespace clang::frontend; + + switch (CI.getFrontendOpts().ProgramAction) { + default: + llvm_unreachable("Invalid program action!"); + + case ASTDump: return new ASTDumpAction(); + case ASTPrint: return new ASTPrintAction(); + case ASTPrintXML: return new ASTPrintXMLAction(); + case ASTView: return new ASTViewAction(); + case BoostCon: return new BoostConAction(); + case CreateModule: return 0; + case DumpRawTokens: return new DumpRawTokensAction(); + case DumpTokens: return new DumpTokensAction(); + case EmitAssembly: return new EmitAssemblyAction(); + case EmitBC: return new EmitBCAction(); + case EmitHTML: return new HTMLPrintAction(); + case EmitLLVM: return new EmitLLVMAction(); + case EmitLLVMOnly: return new EmitLLVMOnlyAction(); + case EmitCodeGenOnly: return new EmitCodeGenOnlyAction(); + case EmitObj: return new EmitObjAction(); + case FixIt: return new FixItAction(); + case GeneratePCH: return new GeneratePCHAction(); + case GeneratePTH: return new GeneratePTHAction(); + case InheritanceView: return new InheritanceViewAction(); + case InitOnly: return new InitOnlyAction(); + case ParseSyntaxOnly: return new SyntaxOnlyAction(); + + case PluginAction: { + for (FrontendPluginRegistry::iterator it = + FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); + it != ie; ++it) { + if (it->getName() == CI.getFrontendOpts().ActionName) { + llvm::OwningPtr P(it->instantiate()); + if (!P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs)) + return 0; + return P.take(); + } + } + + CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name) + << CI.getFrontendOpts().ActionName; + return 0; + } + + case PrintDeclContext: return new DeclContextPrintAction(); + case PrintPreamble: return new PrintPreambleAction(); + case PrintPreprocessedInput: return new PrintPreprocessedAction(); + case RewriteMacros: return new RewriteMacrosAction(); + case RewriteObjC: return new RewriteObjCAction(); + case RewriteTest: return new RewriteTestAction(); + case RunAnalysis: return new AnalysisAction(); + case RunPreprocessorOnly: return new PreprocessOnlyAction(); + } +} + +static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { + // Create the underlying action. + FrontendAction *Act = CreateFrontendBaseAction(CI); + if (!Act) + return 0; + + // If there are any AST files to merge, create a frontend action + // adaptor to perform the merge. + if (!CI.getFrontendOpts().ASTMergeFiles.empty()) + Act = new ASTMergeAction(Act, &CI.getFrontendOpts().ASTMergeFiles[0], + CI.getFrontendOpts().ASTMergeFiles.size()); + + return Act; +} + +bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { + // Honor -help. + if (Clang->getFrontendOpts().ShowHelp) { + llvm::OwningPtr Opts(driver::createCC1OptTable()); + Opts->PrintHelp(llvm::outs(), "clang -cc1", + "LLVM 'Clang' Compiler: http://clang.llvm.org"); + return 0; + } + + // Honor -version. + // + // FIXME: Use a better -version message? + if (Clang->getFrontendOpts().ShowVersion) { + llvm::cl::PrintVersionMessage(); + return 0; + } + + // Honor -mllvm. + // + // FIXME: Remove this, one day. + if (!Clang->getFrontendOpts().LLVMArgs.empty()) { + unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size(); + const char **Args = new const char*[NumArgs + 2]; + Args[0] = "clang (LLVM option parsing)"; + for (unsigned i = 0; i != NumArgs; ++i) + Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str(); + Args[NumArgs + 1] = 0; + llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast(Args)); + } + + // Load any requested plugins. + for (unsigned i = 0, + e = Clang->getFrontendOpts().Plugins.size(); i != e; ++i) { + const std::string &Path = Clang->getFrontendOpts().Plugins[i]; + std::string Error; + if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error)) + Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin) + << Path << Error; + } + + // If there were errors in processing arguments, don't do anything else. + bool Success = false; + if (!Clang->getDiagnostics().getNumErrors()) { + // Create and execute the frontend action. + llvm::OwningPtr Act(CreateFrontendAction(*Clang)); + if (Act) { + Success = Clang->ExecuteAction(*Act); + if (Clang->getFrontendOpts().DisableFree) + Act.take(); + } + } + + return Success; +} diff --git a/lib/FrontendTool/Makefile b/lib/FrontendTool/Makefile new file mode 100644 index 0000000..c43213f --- /dev/null +++ b/lib/FrontendTool/Makefile @@ -0,0 +1,13 @@ +##===- clang/lib/FrontendTool/Makefile ---------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../.. +LIBRARYNAME := clangFrontendTool + +include $(CLANG_LEVEL)/Makefile diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt index 97a99d6..a1b5f50 100644 --- a/lib/Headers/CMakeLists.txt +++ b/lib/Headers/CMakeLists.txt @@ -1,12 +1,15 @@ set(files altivec.h + avxintrin.h emmintrin.h float.h + immintrin.h iso646.h limits.h mm_malloc.h mmintrin.h pmmintrin.h + smmintrin.h stdarg.h stdbool.h stddef.h diff --git a/lib/Headers/Makefile b/lib/Headers/Makefile index ebb8384..d75b1a2 100644 --- a/lib/Headers/Makefile +++ b/lib/Headers/Makefile @@ -38,6 +38,7 @@ all-local:: $(OBJHEADERS) PROJ_headers := $(DESTDIR)$(PROJ_prefix)/lib/clang/$(CLANG_VERSION)/include INSTHEADERS := $(addprefix $(PROJ_headers)/, $(HEADERS)) +INSTHEADERS += $(PROJ_headers)/arm_neon.h $(PROJ_headers): $(Verb) $(MKDIR) $@ diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h index d3d5ad9..89bd259 100644 --- a/lib/Headers/altivec.h +++ b/lib/Headers/altivec.h @@ -45,18 +45,30 @@ vec_perm(vector signed char a, vector signed char b, vector unsigned char c); static vector unsigned char __ATTRS_o_ai vec_perm(vector unsigned char a, vector unsigned char b, vector unsigned char c); +static vector bool char __ATTRS_o_ai +vec_perm(vector bool char a, vector bool char b, vector unsigned char c); + static vector short __ATTRS_o_ai vec_perm(vector short a, vector short b, vector unsigned char c); static vector unsigned short __ATTRS_o_ai vec_perm(vector unsigned short a, vector unsigned short b, vector unsigned char c); +static vector bool short __ATTRS_o_ai +vec_perm(vector bool short a, vector bool short b, vector unsigned char c); + +static vector pixel __ATTRS_o_ai +vec_perm(vector pixel a, vector pixel b, vector unsigned char c); + static vector int __ATTRS_o_ai vec_perm(vector int a, vector int b, vector unsigned char c); static vector unsigned int __ATTRS_o_ai vec_perm(vector unsigned int a, vector unsigned int b, vector unsigned char c); +static vector bool int __ATTRS_o_ai +vec_perm(vector bool int a, vector bool int b, vector unsigned char c); + static vector float __ATTRS_o_ai vec_perm(vector float a, vector float b, vector unsigned char c); @@ -123,36 +135,108 @@ vec_add(vector signed char a, vector signed char b) return a + b; } +static vector signed char __ATTRS_o_ai +vec_add(vector bool char a, vector signed char b) +{ + return (vector signed char)a + b; +} + +static vector signed char __ATTRS_o_ai +vec_add(vector signed char a, vector bool char b) +{ + return a + (vector signed char)b; +} + static vector unsigned char __ATTRS_o_ai vec_add(vector unsigned char a, vector unsigned char b) { return a + b; } +static vector unsigned char __ATTRS_o_ai +vec_add(vector bool char a, vector unsigned char b) +{ + return (vector unsigned char)a + b; +} + +static vector unsigned char __ATTRS_o_ai +vec_add(vector unsigned char a, vector bool char b) +{ + return a + (vector unsigned char)b; +} + static vector short __ATTRS_o_ai vec_add(vector short a, vector short b) { return a + b; } +static vector short __ATTRS_o_ai +vec_add(vector bool short a, vector short b) +{ + return (vector short)a + b; +} + +static vector short __ATTRS_o_ai +vec_add(vector short a, vector bool short b) +{ + return a + (vector short)b; +} + static vector unsigned short __ATTRS_o_ai vec_add(vector unsigned short a, vector unsigned short b) { return a + b; } +static vector unsigned short __ATTRS_o_ai +vec_add(vector bool short a, vector unsigned short b) +{ + return (vector unsigned short)a + b; +} + +static vector unsigned short __ATTRS_o_ai +vec_add(vector unsigned short a, vector bool short b) +{ + return a + (vector unsigned short)b; +} + static vector int __ATTRS_o_ai vec_add(vector int a, vector int b) { return a + b; } +static vector int __ATTRS_o_ai +vec_add(vector bool int a, vector int b) +{ + return (vector int)a + b; +} + +static vector int __ATTRS_o_ai +vec_add(vector int a, vector bool int b) +{ + return a + (vector int)b; +} + static vector unsigned int __ATTRS_o_ai vec_add(vector unsigned int a, vector unsigned int b) { return a + b; } +static vector unsigned int __ATTRS_o_ai +vec_add(vector bool int a, vector unsigned int b) +{ + return (vector unsigned int)a + b; +} + +static vector unsigned int __ATTRS_o_ai +vec_add(vector unsigned int a, vector bool int b) +{ + return a + (vector unsigned int)b; +} + static vector float __ATTRS_o_ai vec_add(vector float a, vector float b) { @@ -169,12 +253,36 @@ vec_vaddubm(vector signed char a, vector signed char b) return a + b; } +static vector signed char __ATTRS_o_ai +vec_vaddubm(vector bool char a, vector signed char b) +{ + return (vector signed char)a + b; +} + +static vector signed char __ATTRS_o_ai +vec_vaddubm(vector signed char a, vector bool char b) +{ + return a + (vector signed char)b; +} + static vector unsigned char __ATTRS_o_ai vec_vaddubm(vector unsigned char a, vector unsigned char b) { return a + b; } +static vector unsigned char __ATTRS_o_ai +vec_vaddubm(vector bool char a, vector unsigned char b) +{ + return (vector unsigned char)a + b; +} + +static vector unsigned char __ATTRS_o_ai +vec_vaddubm(vector unsigned char a, vector bool char b) +{ + return a + (vector unsigned char)b; +} + /* vec_vadduhm */ #define __builtin_altivec_vadduhm vec_vadduhm @@ -185,12 +293,36 @@ vec_vadduhm(vector short a, vector short b) return a + b; } +static vector short __ATTRS_o_ai +vec_vadduhm(vector bool short a, vector short b) +{ + return (vector short)a + b; +} + +static vector short __ATTRS_o_ai +vec_vadduhm(vector short a, vector bool short b) +{ + return a + (vector short)b; +} + static vector unsigned short __ATTRS_o_ai vec_vadduhm(vector unsigned short a, vector unsigned short b) { return a + b; } +static vector unsigned short __ATTRS_o_ai +vec_vadduhm(vector bool short a, vector unsigned short b) +{ + return (vector unsigned short)a + b; +} + +static vector unsigned short __ATTRS_o_ai +vec_vadduhm(vector unsigned short a, vector bool short b) +{ + return a + (vector unsigned short)b; +} + /* vec_vadduwm */ #define __builtin_altivec_vadduwm vec_vadduwm @@ -201,12 +333,36 @@ vec_vadduwm(vector int a, vector int b) return a + b; } +static vector int __ATTRS_o_ai +vec_vadduwm(vector bool int a, vector int b) +{ + return (vector int)a + b; +} + +static vector int __ATTRS_o_ai +vec_vadduwm(vector int a, vector bool int b) +{ + return a + (vector int)b; +} + static vector unsigned int __ATTRS_o_ai vec_vadduwm(vector unsigned int a, vector unsigned int b) { return a + b; } +static vector unsigned int __ATTRS_o_ai +vec_vadduwm(vector bool int a, vector unsigned int b) +{ + return (vector unsigned int)a + b; +} + +static vector unsigned int __ATTRS_o_ai +vec_vadduwm(vector unsigned int a, vector bool int b) +{ + return a + (vector unsigned int)b; +} + /* vec_vaddfp */ #define __builtin_altivec_vaddfp vec_vaddfp @@ -241,84 +397,228 @@ vec_adds(vector signed char a, vector signed char b) return __builtin_altivec_vaddsbs(a, b); } +static vector signed char __ATTRS_o_ai +vec_adds(vector bool char a, vector signed char b) +{ + return __builtin_altivec_vaddsbs((vector signed char)a, b); +} + +static vector signed char __ATTRS_o_ai +vec_adds(vector signed char a, vector bool char b) +{ + return __builtin_altivec_vaddsbs(a, (vector signed char)b); +} + static vector unsigned char __ATTRS_o_ai vec_adds(vector unsigned char a, vector unsigned char b) { return __builtin_altivec_vaddubs(a, b); } +static vector unsigned char __ATTRS_o_ai +vec_adds(vector bool char a, vector unsigned char b) +{ + return __builtin_altivec_vaddubs((vector unsigned char)a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_adds(vector unsigned char a, vector bool char b) +{ + return __builtin_altivec_vaddubs(a, (vector unsigned char)b); +} + static vector short __ATTRS_o_ai vec_adds(vector short a, vector short b) { return __builtin_altivec_vaddshs(a, b); } +static vector short __ATTRS_o_ai +vec_adds(vector bool short a, vector short b) +{ + return __builtin_altivec_vaddshs((vector short)a, b); +} + +static vector short __ATTRS_o_ai +vec_adds(vector short a, vector bool short b) +{ + return __builtin_altivec_vaddshs(a, (vector short)b); +} + static vector unsigned short __ATTRS_o_ai vec_adds(vector unsigned short a, vector unsigned short b) { return __builtin_altivec_vadduhs(a, b); } +static vector unsigned short __ATTRS_o_ai +vec_adds(vector bool short a, vector unsigned short b) +{ + return __builtin_altivec_vadduhs((vector unsigned short)a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_adds(vector unsigned short a, vector bool short b) +{ + return __builtin_altivec_vadduhs(a, (vector unsigned short)b); +} + static vector int __ATTRS_o_ai vec_adds(vector int a, vector int b) { return __builtin_altivec_vaddsws(a, b); } +static vector int __ATTRS_o_ai +vec_adds(vector bool int a, vector int b) +{ + return __builtin_altivec_vaddsws((vector int)a, b); +} + +static vector int __ATTRS_o_ai +vec_adds(vector int a, vector bool int b) +{ + return __builtin_altivec_vaddsws(a, (vector int)b); +} + static vector unsigned int __ATTRS_o_ai vec_adds(vector unsigned int a, vector unsigned int b) { return __builtin_altivec_vadduws(a, b); } +static vector unsigned int __ATTRS_o_ai +vec_adds(vector bool int a, vector unsigned int b) +{ + return __builtin_altivec_vadduws((vector unsigned int)a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_adds(vector unsigned int a, vector bool int b) +{ + return __builtin_altivec_vadduws(a, (vector unsigned int)b); +} + /* vec_vaddsbs */ -static vector signed char __attribute__((__always_inline__)) +static vector signed char __ATTRS_o_ai vec_vaddsbs(vector signed char a, vector signed char b) { return __builtin_altivec_vaddsbs(a, b); } +static vector signed char __ATTRS_o_ai +vec_vaddsbs(vector bool char a, vector signed char b) +{ + return __builtin_altivec_vaddsbs((vector signed char)a, b); +} + +static vector signed char __ATTRS_o_ai +vec_vaddsbs(vector signed char a, vector bool char b) +{ + return __builtin_altivec_vaddsbs(a, (vector signed char)b); +} + /* vec_vaddubs */ -static vector unsigned char __attribute__((__always_inline__)) +static vector unsigned char __ATTRS_o_ai vec_vaddubs(vector unsigned char a, vector unsigned char b) { return __builtin_altivec_vaddubs(a, b); } +static vector unsigned char __ATTRS_o_ai +vec_vaddubs(vector bool char a, vector unsigned char b) +{ + return __builtin_altivec_vaddubs((vector unsigned char)a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vaddubs(vector unsigned char a, vector bool char b) +{ + return __builtin_altivec_vaddubs(a, (vector unsigned char)b); +} + /* vec_vaddshs */ -static vector short __attribute__((__always_inline__)) +static vector short __ATTRS_o_ai vec_vaddshs(vector short a, vector short b) { return __builtin_altivec_vaddshs(a, b); } +static vector short __ATTRS_o_ai +vec_vaddshs(vector bool short a, vector short b) +{ + return __builtin_altivec_vaddshs((vector short)a, b); +} + +static vector short __ATTRS_o_ai +vec_vaddshs(vector short a, vector bool short b) +{ + return __builtin_altivec_vaddshs(a, (vector short)b); +} + /* vec_vadduhs */ -static vector unsigned short __attribute__((__always_inline__)) +static vector unsigned short __ATTRS_o_ai vec_vadduhs(vector unsigned short a, vector unsigned short b) { return __builtin_altivec_vadduhs(a, b); } +static vector unsigned short __ATTRS_o_ai +vec_vadduhs(vector bool short a, vector unsigned short b) +{ + return __builtin_altivec_vadduhs((vector unsigned short)a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vadduhs(vector unsigned short a, vector bool short b) +{ + return __builtin_altivec_vadduhs(a, (vector unsigned short)b); +} + /* vec_vaddsws */ -static vector int __attribute__((__always_inline__)) +static vector int __ATTRS_o_ai vec_vaddsws(vector int a, vector int b) { return __builtin_altivec_vaddsws(a, b); } +static vector int __ATTRS_o_ai +vec_vaddsws(vector bool int a, vector int b) +{ + return __builtin_altivec_vaddsws((vector int)a, b); +} + +static vector int __ATTRS_o_ai +vec_vaddsws(vector int a, vector bool int b) +{ + return __builtin_altivec_vaddsws(a, (vector int)b); +} + /* vec_vadduws */ -static vector unsigned int __attribute__((__always_inline__)) +static vector unsigned int __ATTRS_o_ai vec_vadduws(vector unsigned int a, vector unsigned int b) { return __builtin_altivec_vadduws(a, b); } +static vector unsigned int __ATTRS_o_ai +vec_vadduws(vector bool int a, vector unsigned int b) +{ + return __builtin_altivec_vadduws((vector unsigned int)a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_vadduws(vector unsigned int a, vector bool int b) +{ + return __builtin_altivec_vadduws(a, (vector unsigned int)b); +} + /* vec_and */ #define __builtin_altivec_vand vec_and @@ -329,5538 +629,9504 @@ vec_and(vector signed char a, vector signed char b) return a & b; } +static vector signed char __ATTRS_o_ai +vec_and(vector bool char a, vector signed char b) +{ + return (vector signed char)a & b; +} + +static vector signed char __ATTRS_o_ai +vec_and(vector signed char a, vector bool char b) +{ + return a & (vector signed char)b; +} + static vector unsigned char __ATTRS_o_ai vec_and(vector unsigned char a, vector unsigned char b) { return a & b; } -static vector short __ATTRS_o_ai -vec_and(vector short a, vector short b) +static vector unsigned char __ATTRS_o_ai +vec_and(vector bool char a, vector unsigned char b) { - return a & b; + return (vector unsigned char)a & b; } -static vector unsigned short __ATTRS_o_ai -vec_and(vector unsigned short a, vector unsigned short b) +static vector unsigned char __ATTRS_o_ai +vec_and(vector unsigned char a, vector bool char b) { - return a & b; + return a & (vector unsigned char)b; } -static vector int __ATTRS_o_ai -vec_and(vector int a, vector int b) +static vector bool char __ATTRS_o_ai +vec_and(vector bool char a, vector bool char b) { return a & b; } -static vector unsigned int __ATTRS_o_ai -vec_and(vector unsigned int a, vector unsigned int b) +static vector short __ATTRS_o_ai +vec_and(vector short a, vector short b) { return a & b; } -static vector float __ATTRS_o_ai -vec_and(vector float a, vector float b) +static vector short __ATTRS_o_ai +vec_and(vector bool short a, vector short b) { - vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b; - return (vector float)res; + return (vector short)a & b; } -/* vec_vand */ - -static vector signed char __ATTRS_o_ai -vec_vand(vector signed char a, vector signed char b) +static vector short __ATTRS_o_ai +vec_and(vector short a, vector bool short b) { - return a & b; + return a & (vector short)b; } -static vector unsigned char __ATTRS_o_ai -vec_vand(vector unsigned char a, vector unsigned char b) +static vector unsigned short __ATTRS_o_ai +vec_and(vector unsigned short a, vector unsigned short b) { return a & b; } -static vector short __ATTRS_o_ai -vec_vand(vector short a, vector short b) +static vector unsigned short __ATTRS_o_ai +vec_and(vector bool short a, vector unsigned short b) { - return a & b; + return (vector unsigned short)a & b; } static vector unsigned short __ATTRS_o_ai -vec_vand(vector unsigned short a, vector unsigned short b) +vec_and(vector unsigned short a, vector bool short b) +{ + return a & (vector unsigned short)b; +} + +static vector bool short __ATTRS_o_ai +vec_and(vector bool short a, vector bool short b) { return a & b; } static vector int __ATTRS_o_ai -vec_vand(vector int a, vector int b) +vec_and(vector int a, vector int b) { return a & b; } -static vector unsigned int __ATTRS_o_ai -vec_vand(vector unsigned int a, vector unsigned int b) +static vector int __ATTRS_o_ai +vec_and(vector bool int a, vector int b) { - return a & b; + return (vector int)a & b; } -static vector float __ATTRS_o_ai -vec_vand(vector float a, vector float b) +static vector int __ATTRS_o_ai +vec_and(vector int a, vector bool int b) { - vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b; - return (vector float)res; + return a & (vector int)b; } -/* vec_andc */ - -#define __builtin_altivec_vandc vec_andc - -static vector signed char __ATTRS_o_ai -vec_andc(vector signed char a, vector signed char b) +static vector unsigned int __ATTRS_o_ai +vec_and(vector unsigned int a, vector unsigned int b) { - return a & ~b; + return a & b; } -static vector unsigned char __ATTRS_o_ai -vec_andc(vector unsigned char a, vector unsigned char b) +static vector unsigned int __ATTRS_o_ai +vec_and(vector bool int a, vector unsigned int b) { - return a & ~b; + return (vector unsigned int)a & b; } -static vector short __ATTRS_o_ai -vec_andc(vector short a, vector short b) +static vector unsigned int __ATTRS_o_ai +vec_and(vector unsigned int a, vector bool int b) { - return a & ~b; + return a & (vector unsigned int)b; } -static vector unsigned short __ATTRS_o_ai -vec_andc(vector unsigned short a, vector unsigned short b) +static vector bool int __ATTRS_o_ai +vec_and(vector bool int a, vector bool int b) { - return a & ~b; + return a & b; } -static vector int __ATTRS_o_ai -vec_andc(vector int a, vector int b) +static vector float __ATTRS_o_ai +vec_and(vector float a, vector float b) { - return a & ~b; + vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b; + return (vector float)res; } -static vector unsigned int __ATTRS_o_ai -vec_andc(vector unsigned int a, vector unsigned int b) +static vector float __ATTRS_o_ai +vec_and(vector bool int a, vector float b) { - return a & ~b; + vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b; + return (vector float)res; } static vector float __ATTRS_o_ai -vec_andc(vector float a, vector float b) +vec_and(vector float a, vector bool int b) { - vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b; + vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b; return (vector float)res; } -/* vec_vandc */ +/* vec_vand */ static vector signed char __ATTRS_o_ai -vec_vandc(vector signed char a, vector signed char b) +vec_vand(vector signed char a, vector signed char b) { - return a & ~b; + return a & b; } -static vector unsigned char __ATTRS_o_ai -vec_vandc(vector unsigned char a, vector unsigned char b) +static vector signed char __ATTRS_o_ai +vec_vand(vector bool char a, vector signed char b) { - return a & ~b; + return (vector signed char)a & b; } -static vector short __ATTRS_o_ai -vec_vandc(vector short a, vector short b) +static vector signed char __ATTRS_o_ai +vec_vand(vector signed char a, vector bool char b) { - return a & ~b; + return a & (vector signed char)b; } -static vector unsigned short __ATTRS_o_ai -vec_vandc(vector unsigned short a, vector unsigned short b) +static vector unsigned char __ATTRS_o_ai +vec_vand(vector unsigned char a, vector unsigned char b) { - return a & ~b; + return a & b; } -static vector int __ATTRS_o_ai -vec_vandc(vector int a, vector int b) +static vector unsigned char __ATTRS_o_ai +vec_vand(vector bool char a, vector unsigned char b) { - return a & ~b; + return (vector unsigned char)a & b; } -static vector unsigned int __ATTRS_o_ai -vec_vandc(vector unsigned int a, vector unsigned int b) +static vector unsigned char __ATTRS_o_ai +vec_vand(vector unsigned char a, vector bool char b) { - return a & ~b; + return a & (vector unsigned char)b; } -static vector float __ATTRS_o_ai -vec_vandc(vector float a, vector float b) +static vector bool char __ATTRS_o_ai +vec_vand(vector bool char a, vector bool char b) { - vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b; - return (vector float)res; + return a & b; } -/* vec_avg */ - -static vector signed char __ATTRS_o_ai -vec_avg(vector signed char a, vector signed char b) +static vector short __ATTRS_o_ai +vec_vand(vector short a, vector short b) { - return __builtin_altivec_vavgsb(a, b); + return a & b; } -static vector unsigned char __ATTRS_o_ai -vec_avg(vector unsigned char a, vector unsigned char b) +static vector short __ATTRS_o_ai +vec_vand(vector bool short a, vector short b) { - return __builtin_altivec_vavgub(a, b); + return (vector short)a & b; } static vector short __ATTRS_o_ai -vec_avg(vector short a, vector short b) +vec_vand(vector short a, vector bool short b) { - return __builtin_altivec_vavgsh(a, b); + return a & (vector short)b; } static vector unsigned short __ATTRS_o_ai -vec_avg(vector unsigned short a, vector unsigned short b) +vec_vand(vector unsigned short a, vector unsigned short b) { - return __builtin_altivec_vavguh(a, b); + return a & b; } -static vector int __ATTRS_o_ai -vec_avg(vector int a, vector int b) +static vector unsigned short __ATTRS_o_ai +vec_vand(vector bool short a, vector unsigned short b) { - return __builtin_altivec_vavgsw(a, b); + return (vector unsigned short)a & b; } -static vector unsigned int __ATTRS_o_ai -vec_avg(vector unsigned int a, vector unsigned int b) +static vector unsigned short __ATTRS_o_ai +vec_vand(vector unsigned short a, vector bool short b) { - return __builtin_altivec_vavguw(a, b); + return a & (vector unsigned short)b; } -/* vec_vavgsb */ - -static vector signed char __attribute__((__always_inline__)) -vec_vavgsb(vector signed char a, vector signed char b) +static vector bool short __ATTRS_o_ai +vec_vand(vector bool short a, vector bool short b) { - return __builtin_altivec_vavgsb(a, b); + return a & b; } -/* vec_vavgub */ - -static vector unsigned char __attribute__((__always_inline__)) -vec_vavgub(vector unsigned char a, vector unsigned char b) +static vector int __ATTRS_o_ai +vec_vand(vector int a, vector int b) { - return __builtin_altivec_vavgub(a, b); + return a & b; } -/* vec_vavgsh */ - -static vector short __attribute__((__always_inline__)) -vec_vavgsh(vector short a, vector short b) +static vector int __ATTRS_o_ai +vec_vand(vector bool int a, vector int b) { - return __builtin_altivec_vavgsh(a, b); + return (vector int)a & b; } -/* vec_vavguh */ - -static vector unsigned short __attribute__((__always_inline__)) -vec_vavguh(vector unsigned short a, vector unsigned short b) +static vector int __ATTRS_o_ai +vec_vand(vector int a, vector bool int b) { - return __builtin_altivec_vavguh(a, b); + return a & (vector int)b; } -/* vec_vavgsw */ - -static vector int __attribute__((__always_inline__)) -vec_vavgsw(vector int a, vector int b) +static vector unsigned int __ATTRS_o_ai +vec_vand(vector unsigned int a, vector unsigned int b) { - return __builtin_altivec_vavgsw(a, b); + return a & b; } -/* vec_vavguw */ - -static vector unsigned int __attribute__((__always_inline__)) -vec_vavguw(vector unsigned int a, vector unsigned int b) +static vector unsigned int __ATTRS_o_ai +vec_vand(vector bool int a, vector unsigned int b) { - return __builtin_altivec_vavguw(a, b); + return (vector unsigned int)a & b; } -/* vec_ceil */ - -static vector float __attribute__((__always_inline__)) -vec_ceil(vector float a) +static vector unsigned int __ATTRS_o_ai +vec_vand(vector unsigned int a, vector bool int b) { - return __builtin_altivec_vrfip(a); + return a & (vector unsigned int)b; } -/* vec_vrfip */ - -static vector float __attribute__((__always_inline__)) -vec_vrfip(vector float a) +static vector bool int __ATTRS_o_ai +vec_vand(vector bool int a, vector bool int b) { - return __builtin_altivec_vrfip(a); + return a & b; } -/* vec_cmpb */ - -static vector int __attribute__((__always_inline__)) -vec_cmpb(vector float a, vector float b) +static vector float __ATTRS_o_ai +vec_vand(vector float a, vector float b) { - return __builtin_altivec_vcmpbfp(a, b); + vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b; + return (vector float)res; } -/* vec_vcmpbfp */ - -static vector int __attribute__((__always_inline__)) -vec_vcmpbfp(vector float a, vector float b) +static vector float __ATTRS_o_ai +vec_vand(vector bool int a, vector float b) { - return __builtin_altivec_vcmpbfp(a, b); + vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b; + return (vector float)res; } -/* vec_cmpeq */ - -static vector /*bool*/ char __ATTRS_o_ai -vec_cmpeq(vector signed char a, vector signed char b) +static vector float __ATTRS_o_ai +vec_vand(vector float a, vector bool int b) { - return __builtin_altivec_vcmpequb((vector char)a, (vector char)b); + vector unsigned int res = (vector unsigned int)a & (vector unsigned int)b; + return (vector float)res; } -static vector /*bool*/ char __ATTRS_o_ai -vec_cmpeq(vector unsigned char a, vector unsigned char b) +/* vec_andc */ + +#define __builtin_altivec_vandc vec_andc + +static vector signed char __ATTRS_o_ai +vec_andc(vector signed char a, vector signed char b) { - return __builtin_altivec_vcmpequb((vector char)a, (vector char)b); + return a & ~b; } -static vector /*bool*/ short __ATTRS_o_ai -vec_cmpeq(vector short a, vector short b) +static vector signed char __ATTRS_o_ai +vec_andc(vector bool char a, vector signed char b) { - return __builtin_altivec_vcmpequh(a, b); + return (vector signed char)a & ~b; } -static vector /*bool*/ short __ATTRS_o_ai -vec_cmpeq(vector unsigned short a, vector unsigned short b) +static vector signed char __ATTRS_o_ai +vec_andc(vector signed char a, vector bool char b) { - return __builtin_altivec_vcmpequh((vector short)a, (vector short)b); + return a & ~(vector signed char)b; } -static vector /*bool*/ int __ATTRS_o_ai -vec_cmpeq(vector int a, vector int b) +static vector unsigned char __ATTRS_o_ai +vec_andc(vector unsigned char a, vector unsigned char b) { - return __builtin_altivec_vcmpequw(a, b); + return a & ~b; } -static vector /*bool*/ int __ATTRS_o_ai -vec_cmpeq(vector unsigned int a, vector unsigned int b) +static vector unsigned char __ATTRS_o_ai +vec_andc(vector bool char a, vector unsigned char b) { - return __builtin_altivec_vcmpequw((vector int)a, (vector int)b); + return (vector unsigned char)a & ~b; } -static vector /*bool*/ int __ATTRS_o_ai -vec_cmpeq(vector float a, vector float b) +static vector unsigned char __ATTRS_o_ai +vec_andc(vector unsigned char a, vector bool char b) { - return __builtin_altivec_vcmpeqfp(a, b); + return a & ~(vector unsigned char)b; } -/* vec_cmpge */ - -static vector /*bool*/ int __attribute__((__always_inline__)) -vec_cmpge(vector float a, vector float b) +static vector bool char __ATTRS_o_ai +vec_andc(vector bool char a, vector bool char b) { - return __builtin_altivec_vcmpgefp(a, b); + return a & ~b; } -/* vec_vcmpgefp */ - -static vector /*bool*/ int __attribute__((__always_inline__)) -vec_vcmpgefp(vector float a, vector float b) +static vector short __ATTRS_o_ai +vec_andc(vector short a, vector short b) { - return __builtin_altivec_vcmpgefp(a, b); + return a & ~b; } -/* vec_cmpgt */ - -static vector /*bool*/ char __ATTRS_o_ai -vec_cmpgt(vector signed char a, vector signed char b) +static vector short __ATTRS_o_ai +vec_andc(vector bool short a, vector short b) { - return __builtin_altivec_vcmpgtsb(a, b); + return (vector short)a & ~b; } -static vector /*bool*/ char __ATTRS_o_ai -vec_cmpgt(vector unsigned char a, vector unsigned char b) +static vector short __ATTRS_o_ai +vec_andc(vector short a, vector bool short b) { - return __builtin_altivec_vcmpgtub(a, b); + return a & ~(vector short)b; } -static vector /*bool*/ short __ATTRS_o_ai -vec_cmpgt(vector short a, vector short b) +static vector unsigned short __ATTRS_o_ai +vec_andc(vector unsigned short a, vector unsigned short b) { - return __builtin_altivec_vcmpgtsh(a, b); + return a & ~b; } -static vector /*bool*/ short __ATTRS_o_ai -vec_cmpgt(vector unsigned short a, vector unsigned short b) +static vector unsigned short __ATTRS_o_ai +vec_andc(vector bool short a, vector unsigned short b) { - return __builtin_altivec_vcmpgtuh(a, b); + return (vector unsigned short)a & ~b; } -static vector /*bool*/ int __ATTRS_o_ai -vec_cmpgt(vector int a, vector int b) +static vector unsigned short __ATTRS_o_ai +vec_andc(vector unsigned short a, vector bool short b) { - return __builtin_altivec_vcmpgtsw(a, b); + return a & ~(vector unsigned short)b; } -static vector /*bool*/ int __ATTRS_o_ai -vec_cmpgt(vector unsigned int a, vector unsigned int b) +static vector bool short __ATTRS_o_ai +vec_andc(vector bool short a, vector bool short b) { - return __builtin_altivec_vcmpgtuw(a, b); + return a & ~b; } -static vector /*bool*/ int __ATTRS_o_ai -vec_cmpgt(vector float a, vector float b) +static vector int __ATTRS_o_ai +vec_andc(vector int a, vector int b) { - return __builtin_altivec_vcmpgtfp(a, b); + return a & ~b; } -/* vec_vcmpgtsb */ - -static vector /*bool*/ char __attribute__((__always_inline__)) -vec_vcmpgtsb(vector signed char a, vector signed char b) +static vector int __ATTRS_o_ai +vec_andc(vector bool int a, vector int b) { - return __builtin_altivec_vcmpgtsb(a, b); + return (vector int)a & ~b; } -/* vec_vcmpgtub */ - -static vector /*bool*/ char __attribute__((__always_inline__)) -vec_vcmpgtub(vector unsigned char a, vector unsigned char b) +static vector int __ATTRS_o_ai +vec_andc(vector int a, vector bool int b) { - return __builtin_altivec_vcmpgtub(a, b); + return a & ~(vector int)b; } -/* vec_vcmpgtsh */ - -static vector /*bool*/ short __attribute__((__always_inline__)) -vec_vcmpgtsh(vector short a, vector short b) +static vector unsigned int __ATTRS_o_ai +vec_andc(vector unsigned int a, vector unsigned int b) { - return __builtin_altivec_vcmpgtsh(a, b); + return a & ~b; } -/* vec_vcmpgtuh */ - -static vector /*bool*/ short __attribute__((__always_inline__)) -vec_vcmpgtuh(vector unsigned short a, vector unsigned short b) +static vector unsigned int __ATTRS_o_ai +vec_andc(vector bool int a, vector unsigned int b) { - return __builtin_altivec_vcmpgtuh(a, b); + return (vector unsigned int)a & ~b; } -/* vec_vcmpgtsw */ - -static vector /*bool*/ int __attribute__((__always_inline__)) -vec_vcmpgtsw(vector int a, vector int b) +static vector unsigned int __ATTRS_o_ai +vec_andc(vector unsigned int a, vector bool int b) { - return __builtin_altivec_vcmpgtsw(a, b); + return a & ~(vector unsigned int)b; } -/* vec_vcmpgtuw */ - -static vector /*bool*/ int __attribute__((__always_inline__)) -vec_vcmpgtuw(vector unsigned int a, vector unsigned int b) +static vector bool int __ATTRS_o_ai +vec_andc(vector bool int a, vector bool int b) { - return __builtin_altivec_vcmpgtuw(a, b); + return a & ~b; } -/* vec_vcmpgtfp */ +static vector float __ATTRS_o_ai +vec_andc(vector float a, vector float b) +{ + vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b; + return (vector float)res; +} -static vector /*bool*/ int __attribute__((__always_inline__)) -vec_vcmpgtfp(vector float a, vector float b) +static vector float __ATTRS_o_ai +vec_andc(vector bool int a, vector float b) { - return __builtin_altivec_vcmpgtfp(a, b); + vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b; + return (vector float)res; } -/* vec_cmple */ +static vector float __ATTRS_o_ai +vec_andc(vector float a, vector bool int b) +{ + vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b; + return (vector float)res; +} -static vector /*bool*/ int __attribute__((__always_inline__)) -vec_cmple(vector float a, vector float b) +/* vec_vandc */ + +static vector signed char __ATTRS_o_ai +vec_vandc(vector signed char a, vector signed char b) { - return __builtin_altivec_vcmpgefp(b, a); + return a & ~b; } -/* vec_cmplt */ +static vector signed char __ATTRS_o_ai +vec_vandc(vector bool char a, vector signed char b) +{ + return (vector signed char)a & ~b; +} -static vector /*bool*/ char __ATTRS_o_ai -vec_cmplt(vector signed char a, vector signed char b) +static vector signed char __ATTRS_o_ai +vec_vandc(vector signed char a, vector bool char b) { - return __builtin_altivec_vcmpgtsb(b, a); + return a & ~(vector signed char)b; } -static vector /*bool*/ char __ATTRS_o_ai -vec_cmplt(vector unsigned char a, vector unsigned char b) +static vector unsigned char __ATTRS_o_ai +vec_vandc(vector unsigned char a, vector unsigned char b) { - return __builtin_altivec_vcmpgtub(b, a); + return a & ~b; } -static vector /*bool*/ short __ATTRS_o_ai -vec_cmplt(vector short a, vector short b) +static vector unsigned char __ATTRS_o_ai +vec_vandc(vector bool char a, vector unsigned char b) { - return __builtin_altivec_vcmpgtsh(b, a); + return (vector unsigned char)a & ~b; } -static vector /*bool*/ short __ATTRS_o_ai -vec_cmplt(vector unsigned short a, vector unsigned short b) +static vector unsigned char __ATTRS_o_ai +vec_vandc(vector unsigned char a, vector bool char b) { - return __builtin_altivec_vcmpgtuh(b, a); + return a & ~(vector unsigned char)b; } -static vector /*bool*/ int __ATTRS_o_ai -vec_cmplt(vector int a, vector int b) +static vector bool char __ATTRS_o_ai +vec_vandc(vector bool char a, vector bool char b) { - return __builtin_altivec_vcmpgtsw(b, a); + return a & ~b; } -static vector /*bool*/ int __ATTRS_o_ai -vec_cmplt(vector unsigned int a, vector unsigned int b) +static vector short __ATTRS_o_ai +vec_vandc(vector short a, vector short b) { - return __builtin_altivec_vcmpgtuw(b, a); + return a & ~b; } -static vector /*bool*/ int __ATTRS_o_ai -vec_cmplt(vector float a, vector float b) +static vector short __ATTRS_o_ai +vec_vandc(vector bool short a, vector short b) { - return __builtin_altivec_vcmpgtfp(b, a); + return (vector short)a & ~b; } -/* vec_ctf */ +static vector short __ATTRS_o_ai +vec_vandc(vector short a, vector bool short b) +{ + return a & ~(vector short)b; +} -static vector float __ATTRS_o_ai -vec_ctf(vector int a, int b) +static vector unsigned short __ATTRS_o_ai +vec_vandc(vector unsigned short a, vector unsigned short b) { - return __builtin_altivec_vcfsx(a, b); + return a & ~b; } -static vector float __ATTRS_o_ai -vec_ctf(vector unsigned int a, int b) +static vector unsigned short __ATTRS_o_ai +vec_vandc(vector bool short a, vector unsigned short b) { - return __builtin_altivec_vcfux((vector int)a, b); + return (vector unsigned short)a & ~b; } -/* vec_vcfsx */ +static vector unsigned short __ATTRS_o_ai +vec_vandc(vector unsigned short a, vector bool short b) +{ + return a & ~(vector unsigned short)b; +} -static vector float __attribute__((__always_inline__)) -vec_vcfsx(vector int a, int b) +static vector bool short __ATTRS_o_ai +vec_vandc(vector bool short a, vector bool short b) { - return __builtin_altivec_vcfsx(a, b); + return a & ~b; } -/* vec_vcfux */ +static vector int __ATTRS_o_ai +vec_vandc(vector int a, vector int b) +{ + return a & ~b; +} -static vector float __attribute__((__always_inline__)) -vec_vcfux(vector unsigned int a, int b) +static vector int __ATTRS_o_ai +vec_vandc(vector bool int a, vector int b) { - return __builtin_altivec_vcfux((vector int)a, b); + return (vector int)a & ~b; } -/* vec_cts */ +static vector int __ATTRS_o_ai +vec_vandc(vector int a, vector bool int b) +{ + return a & ~(vector int)b; +} -static vector int __attribute__((__always_inline__)) -vec_cts(vector float a, int b) +static vector unsigned int __ATTRS_o_ai +vec_vandc(vector unsigned int a, vector unsigned int b) { - return __builtin_altivec_vctsxs(a, b); + return a & ~b; } -/* vec_vctsxs */ +static vector unsigned int __ATTRS_o_ai +vec_vandc(vector bool int a, vector unsigned int b) +{ + return (vector unsigned int)a & ~b; +} -static vector int __attribute__((__always_inline__)) -vec_vctsxs(vector float a, int b) +static vector unsigned int __ATTRS_o_ai +vec_vandc(vector unsigned int a, vector bool int b) { - return __builtin_altivec_vctsxs(a, b); + return a & ~(vector unsigned int)b; } -/* vec_ctu */ +static vector bool int __ATTRS_o_ai +vec_vandc(vector bool int a, vector bool int b) +{ + return a & ~b; +} -static vector unsigned int __attribute__((__always_inline__)) -vec_ctu(vector float a, int b) +static vector float __ATTRS_o_ai +vec_vandc(vector float a, vector float b) { - return __builtin_altivec_vctuxs(a, b); + vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b; + return (vector float)res; } -/* vec_vctuxs */ +static vector float __ATTRS_o_ai +vec_vandc(vector bool int a, vector float b) +{ + vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b; + return (vector float)res; +} -static vector unsigned int __attribute__((__always_inline__)) -vec_vctuxs(vector float a, int b) +static vector float __ATTRS_o_ai +vec_vandc(vector float a, vector bool int b) { - return __builtin_altivec_vctuxs(a, b); + vector unsigned int res = (vector unsigned int)a & ~(vector unsigned int)b; + return (vector float)res; } -/* vec_dss */ +/* vec_avg */ -static void __attribute__((__always_inline__)) -vec_dss(int a) +static vector signed char __ATTRS_o_ai +vec_avg(vector signed char a, vector signed char b) { - __builtin_altivec_dss(a); + return __builtin_altivec_vavgsb(a, b); } -/* vec_dssall */ +static vector unsigned char __ATTRS_o_ai +vec_avg(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vavgub(a, b); +} -static void __attribute__((__always_inline__)) -vec_dssall(void) +static vector short __ATTRS_o_ai +vec_avg(vector short a, vector short b) { - __builtin_altivec_dssall(); + return __builtin_altivec_vavgsh(a, b); } -/* vec_dst */ +static vector unsigned short __ATTRS_o_ai +vec_avg(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vavguh(a, b); +} -static void __attribute__((__always_inline__)) -vec_dst(void *a, int b, int c) +static vector int __ATTRS_o_ai +vec_avg(vector int a, vector int b) { - __builtin_altivec_dst(a, b, c); + return __builtin_altivec_vavgsw(a, b); } -/* vec_dstst */ +static vector unsigned int __ATTRS_o_ai +vec_avg(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vavguw(a, b); +} -static void __attribute__((__always_inline__)) -vec_dstst(void *a, int b, int c) +/* vec_vavgsb */ + +static vector signed char __attribute__((__always_inline__)) +vec_vavgsb(vector signed char a, vector signed char b) { - __builtin_altivec_dstst(a, b, c); + return __builtin_altivec_vavgsb(a, b); } -/* vec_dststt */ +/* vec_vavgub */ -static void __attribute__((__always_inline__)) -vec_dststt(void *a, int b, int c) +static vector unsigned char __attribute__((__always_inline__)) +vec_vavgub(vector unsigned char a, vector unsigned char b) { - __builtin_altivec_dststt(a, b, c); + return __builtin_altivec_vavgub(a, b); } -/* vec_dstt */ +/* vec_vavgsh */ -static void __attribute__((__always_inline__)) -vec_dstt(void *a, int b, int c) +static vector short __attribute__((__always_inline__)) +vec_vavgsh(vector short a, vector short b) { - __builtin_altivec_dstt(a, b, c); + return __builtin_altivec_vavgsh(a, b); } -/* vec_expte */ +/* vec_vavguh */ -static vector float __attribute__((__always_inline__)) -vec_expte(vector float a) +static vector unsigned short __attribute__((__always_inline__)) +vec_vavguh(vector unsigned short a, vector unsigned short b) { - return __builtin_altivec_vexptefp(a); + return __builtin_altivec_vavguh(a, b); } -/* vec_vexptefp */ +/* vec_vavgsw */ -static vector float __attribute__((__always_inline__)) -vec_vexptefp(vector float a) +static vector int __attribute__((__always_inline__)) +vec_vavgsw(vector int a, vector int b) { - return __builtin_altivec_vexptefp(a); + return __builtin_altivec_vavgsw(a, b); } -/* vec_floor */ +/* vec_vavguw */ -static vector float __attribute__((__always_inline__)) -vec_floor(vector float a) +static vector unsigned int __attribute__((__always_inline__)) +vec_vavguw(vector unsigned int a, vector unsigned int b) { - return __builtin_altivec_vrfim(a); + return __builtin_altivec_vavguw(a, b); } -/* vec_vrfim */ +/* vec_ceil */ static vector float __attribute__((__always_inline__)) -vec_vrfim(vector float a) +vec_ceil(vector float a) { - return __builtin_altivec_vrfim(a); + return __builtin_altivec_vrfip(a); } -/* vec_ld */ +/* vec_vrfip */ -static vector signed char __ATTRS_o_ai -vec_ld(int a, vector signed char *b) +static vector float __attribute__((__always_inline__)) +vec_vrfip(vector float a) { - return (vector signed char)__builtin_altivec_lvx(a, b); + return __builtin_altivec_vrfip(a); } -static vector signed char __ATTRS_o_ai -vec_ld(int a, signed char *b) +/* vec_cmpb */ + +static vector int __attribute__((__always_inline__)) +vec_cmpb(vector float a, vector float b) { - return (vector signed char)__builtin_altivec_lvx(a, b); + return __builtin_altivec_vcmpbfp(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_ld(int a, vector unsigned char *b) +/* vec_vcmpbfp */ + +static vector int __attribute__((__always_inline__)) +vec_vcmpbfp(vector float a, vector float b) { - return (vector unsigned char)__builtin_altivec_lvx(a, b); + return __builtin_altivec_vcmpbfp(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_ld(int a, unsigned char *b) +/* vec_cmpeq */ + +static vector bool char __ATTRS_o_ai +vec_cmpeq(vector signed char a, vector signed char b) { - return (vector unsigned char)__builtin_altivec_lvx(a, b); + return (vector bool char) + __builtin_altivec_vcmpequb((vector char)a, (vector char)b); } -static vector short __ATTRS_o_ai -vec_ld(int a, vector short *b) +static vector bool char __ATTRS_o_ai +vec_cmpeq(vector unsigned char a, vector unsigned char b) { - return (vector short)__builtin_altivec_lvx(a, b); + return (vector bool char) + __builtin_altivec_vcmpequb((vector char)a, (vector char)b); } -static vector short __ATTRS_o_ai -vec_ld(int a, short *b) +static vector bool short __ATTRS_o_ai +vec_cmpeq(vector short a, vector short b) { - return (vector short)__builtin_altivec_lvx(a, b); + return (vector bool short)__builtin_altivec_vcmpequh(a, b); } -static vector unsigned short __ATTRS_o_ai -vec_ld(int a, vector unsigned short *b) +static vector bool short __ATTRS_o_ai +vec_cmpeq(vector unsigned short a, vector unsigned short b) { - return (vector unsigned short)__builtin_altivec_lvx(a, b); + return (vector bool short) + __builtin_altivec_vcmpequh((vector short)a, (vector short)b); } -static vector unsigned short __ATTRS_o_ai -vec_ld(int a, unsigned short *b) +static vector bool int __ATTRS_o_ai +vec_cmpeq(vector int a, vector int b) { - return (vector unsigned short)__builtin_altivec_lvx(a, b); + return (vector bool int)__builtin_altivec_vcmpequw(a, b); } -static vector int __ATTRS_o_ai -vec_ld(int a, vector int *b) +static vector bool int __ATTRS_o_ai +vec_cmpeq(vector unsigned int a, vector unsigned int b) { - return (vector int)__builtin_altivec_lvx(a, b); + return (vector bool int) + __builtin_altivec_vcmpequw((vector int)a, (vector int)b); } -static vector int __ATTRS_o_ai -vec_ld(int a, int *b) +static vector bool int __ATTRS_o_ai +vec_cmpeq(vector float a, vector float b) { - return (vector int)__builtin_altivec_lvx(a, b); + return (vector bool int)__builtin_altivec_vcmpeqfp(a, b); } -static vector unsigned int __ATTRS_o_ai -vec_ld(int a, vector unsigned int *b) -{ - return (vector unsigned int)__builtin_altivec_lvx(a, b); -} +/* vec_cmpge */ -static vector unsigned int __ATTRS_o_ai -vec_ld(int a, unsigned int *b) +static vector bool int __attribute__((__always_inline__)) +vec_cmpge(vector float a, vector float b) { - return (vector unsigned int)__builtin_altivec_lvx(a, b); + return (vector bool int)__builtin_altivec_vcmpgefp(a, b); } -static vector float __ATTRS_o_ai -vec_ld(int a, vector float *b) +/* vec_vcmpgefp */ + +static vector bool int __attribute__((__always_inline__)) +vec_vcmpgefp(vector float a, vector float b) { - return (vector float)__builtin_altivec_lvx(a, b); + return (vector bool int)__builtin_altivec_vcmpgefp(a, b); } -static vector float __ATTRS_o_ai -vec_ld(int a, float *b) +/* vec_cmpgt */ + +static vector bool char __ATTRS_o_ai +vec_cmpgt(vector signed char a, vector signed char b) { - return (vector float)__builtin_altivec_lvx(a, b); + return (vector bool char)__builtin_altivec_vcmpgtsb(a, b); } -/* vec_lvx */ - -static vector signed char __ATTRS_o_ai -vec_lvx(int a, vector signed char *b) +static vector bool char __ATTRS_o_ai +vec_cmpgt(vector unsigned char a, vector unsigned char b) { - return (vector signed char)__builtin_altivec_lvx(a, b); + return (vector bool char)__builtin_altivec_vcmpgtub(a, b); } -static vector signed char __ATTRS_o_ai -vec_lvx(int a, signed char *b) +static vector bool short __ATTRS_o_ai +vec_cmpgt(vector short a, vector short b) { - return (vector signed char)__builtin_altivec_lvx(a, b); + return (vector bool short)__builtin_altivec_vcmpgtsh(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_lvx(int a, vector unsigned char *b) +static vector bool short __ATTRS_o_ai +vec_cmpgt(vector unsigned short a, vector unsigned short b) { - return (vector unsigned char)__builtin_altivec_lvx(a, b); + return (vector bool short)__builtin_altivec_vcmpgtuh(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_lvx(int a, unsigned char *b) +static vector bool int __ATTRS_o_ai +vec_cmpgt(vector int a, vector int b) { - return (vector unsigned char)__builtin_altivec_lvx(a, b); + return (vector bool int)__builtin_altivec_vcmpgtsw(a, b); } -static vector short __ATTRS_o_ai -vec_lvx(int a, vector short *b) +static vector bool int __ATTRS_o_ai +vec_cmpgt(vector unsigned int a, vector unsigned int b) { - return (vector short)__builtin_altivec_lvx(a, b); + return (vector bool int)__builtin_altivec_vcmpgtuw(a, b); } -static vector short __ATTRS_o_ai -vec_lvx(int a, short *b) +static vector bool int __ATTRS_o_ai +vec_cmpgt(vector float a, vector float b) { - return (vector short)__builtin_altivec_lvx(a, b); + return (vector bool int)__builtin_altivec_vcmpgtfp(a, b); } -static vector unsigned short __ATTRS_o_ai -vec_lvx(int a, vector unsigned short *b) +/* vec_vcmpgtsb */ + +static vector bool char __attribute__((__always_inline__)) +vec_vcmpgtsb(vector signed char a, vector signed char b) { - return (vector unsigned short)__builtin_altivec_lvx(a, b); + return (vector bool char)__builtin_altivec_vcmpgtsb(a, b); } -static vector unsigned short __ATTRS_o_ai -vec_lvx(int a, unsigned short *b) +/* vec_vcmpgtub */ + +static vector bool char __attribute__((__always_inline__)) +vec_vcmpgtub(vector unsigned char a, vector unsigned char b) { - return (vector unsigned short)__builtin_altivec_lvx(a, b); + return (vector bool char)__builtin_altivec_vcmpgtub(a, b); } -static vector int __ATTRS_o_ai -vec_lvx(int a, vector int *b) +/* vec_vcmpgtsh */ + +static vector bool short __attribute__((__always_inline__)) +vec_vcmpgtsh(vector short a, vector short b) { - return (vector int)__builtin_altivec_lvx(a, b); + return (vector bool short)__builtin_altivec_vcmpgtsh(a, b); } -static vector int __ATTRS_o_ai -vec_lvx(int a, int *b) +/* vec_vcmpgtuh */ + +static vector bool short __attribute__((__always_inline__)) +vec_vcmpgtuh(vector unsigned short a, vector unsigned short b) { - return (vector int)__builtin_altivec_lvx(a, b); + return (vector bool short)__builtin_altivec_vcmpgtuh(a, b); } -static vector unsigned int __ATTRS_o_ai -vec_lvx(int a, vector unsigned int *b) +/* vec_vcmpgtsw */ + +static vector bool int __attribute__((__always_inline__)) +vec_vcmpgtsw(vector int a, vector int b) { - return (vector unsigned int)__builtin_altivec_lvx(a, b); + return (vector bool int)__builtin_altivec_vcmpgtsw(a, b); } -static vector unsigned int __ATTRS_o_ai -vec_lvx(int a, unsigned int *b) +/* vec_vcmpgtuw */ + +static vector bool int __attribute__((__always_inline__)) +vec_vcmpgtuw(vector unsigned int a, vector unsigned int b) { - return (vector unsigned int)__builtin_altivec_lvx(a, b); + return (vector bool int)__builtin_altivec_vcmpgtuw(a, b); } -static vector float __ATTRS_o_ai -vec_lvx(int a, vector float *b) +/* vec_vcmpgtfp */ + +static vector bool int __attribute__((__always_inline__)) +vec_vcmpgtfp(vector float a, vector float b) { - return (vector float)__builtin_altivec_lvx(a, b); + return (vector bool int)__builtin_altivec_vcmpgtfp(a, b); } -static vector float __ATTRS_o_ai -vec_lvx(int a, float *b) +/* vec_cmple */ + +static vector bool int __attribute__((__always_inline__)) +vec_cmple(vector float a, vector float b) { - return (vector float)__builtin_altivec_lvx(a, b); + return (vector bool int)__builtin_altivec_vcmpgefp(b, a); } -/* vec_lde */ +/* vec_cmplt */ -static vector signed char __ATTRS_o_ai -vec_lde(int a, vector signed char *b) +static vector bool char __ATTRS_o_ai +vec_cmplt(vector signed char a, vector signed char b) { - return (vector signed char)__builtin_altivec_lvebx(a, b); + return (vector bool char)__builtin_altivec_vcmpgtsb(b, a); } -static vector unsigned char __ATTRS_o_ai -vec_lde(int a, vector unsigned char *b) +static vector bool char __ATTRS_o_ai +vec_cmplt(vector unsigned char a, vector unsigned char b) { - return (vector unsigned char)__builtin_altivec_lvebx(a, b); + return (vector bool char)__builtin_altivec_vcmpgtub(b, a); } -static vector short __ATTRS_o_ai -vec_lde(int a, vector short *b) +static vector bool short __ATTRS_o_ai +vec_cmplt(vector short a, vector short b) { - return (vector short)__builtin_altivec_lvehx(a, b); + return (vector bool short)__builtin_altivec_vcmpgtsh(b, a); } -static vector unsigned short __ATTRS_o_ai -vec_lde(int a, vector unsigned short *b) +static vector bool short __ATTRS_o_ai +vec_cmplt(vector unsigned short a, vector unsigned short b) { - return (vector unsigned short)__builtin_altivec_lvehx(a, b); + return (vector bool short)__builtin_altivec_vcmpgtuh(b, a); } -static vector int __ATTRS_o_ai -vec_lde(int a, vector int *b) +static vector bool int __ATTRS_o_ai +vec_cmplt(vector int a, vector int b) { - return (vector int)__builtin_altivec_lvewx(a, b); + return (vector bool int)__builtin_altivec_vcmpgtsw(b, a); } -static vector unsigned int __ATTRS_o_ai -vec_lde(int a, vector unsigned int *b) +static vector bool int __ATTRS_o_ai +vec_cmplt(vector unsigned int a, vector unsigned int b) { - return (vector unsigned int)__builtin_altivec_lvewx(a, b); + return (vector bool int)__builtin_altivec_vcmpgtuw(b, a); } -static vector float __ATTRS_o_ai -vec_lde(int a, vector float *b) +static vector bool int __ATTRS_o_ai +vec_cmplt(vector float a, vector float b) { - return (vector float)__builtin_altivec_lvewx(a, b); + return (vector bool int)__builtin_altivec_vcmpgtfp(b, a); } -/* vec_lvebx */ +/* vec_ctf */ -static vector signed char __ATTRS_o_ai -vec_lvebx(int a, vector signed char *b) +static vector float __ATTRS_o_ai +vec_ctf(vector int a, int b) { - return (vector signed char)__builtin_altivec_lvebx(a, b); + return __builtin_altivec_vcfsx(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_lvebx(int a, vector unsigned char *b) +static vector float __ATTRS_o_ai +vec_ctf(vector unsigned int a, int b) { - return (vector unsigned char)__builtin_altivec_lvebx(a, b); + return __builtin_altivec_vcfux((vector int)a, b); } -/* vec_lvehx */ +/* vec_vcfsx */ -static vector short __ATTRS_o_ai -vec_lvehx(int a, vector short *b) +static vector float __attribute__((__always_inline__)) +vec_vcfsx(vector int a, int b) { - return (vector short)__builtin_altivec_lvehx(a, b); + return __builtin_altivec_vcfsx(a, b); } -static vector unsigned short __ATTRS_o_ai -vec_lvehx(int a, vector unsigned short *b) +/* vec_vcfux */ + +static vector float __attribute__((__always_inline__)) +vec_vcfux(vector unsigned int a, int b) { - return (vector unsigned short)__builtin_altivec_lvehx(a, b); + return __builtin_altivec_vcfux((vector int)a, b); } -/* vec_lvewx */ +/* vec_cts */ -static vector int __ATTRS_o_ai -vec_lvewx(int a, vector int *b) +static vector int __attribute__((__always_inline__)) +vec_cts(vector float a, int b) { - return (vector int)__builtin_altivec_lvewx(a, b); + return __builtin_altivec_vctsxs(a, b); } -static vector unsigned int __ATTRS_o_ai -vec_lvewx(int a, vector unsigned int *b) -{ - return (vector unsigned int)__builtin_altivec_lvewx(a, b); -} +/* vec_vctsxs */ -static vector float __ATTRS_o_ai -vec_lvewx(int a, vector float *b) +static vector int __attribute__((__always_inline__)) +vec_vctsxs(vector float a, int b) { - return (vector float)__builtin_altivec_lvewx(a, b); + return __builtin_altivec_vctsxs(a, b); } -/* vec_ldl */ +/* vec_ctu */ -static vector signed char __ATTRS_o_ai -vec_ldl(int a, vector signed char *b) +static vector unsigned int __attribute__((__always_inline__)) +vec_ctu(vector float a, int b) { - return (vector signed char)__builtin_altivec_lvxl(a, b); + return __builtin_altivec_vctuxs(a, b); } -static vector signed char __ATTRS_o_ai -vec_ldl(int a, signed char *b) +/* vec_vctuxs */ + +static vector unsigned int __attribute__((__always_inline__)) +vec_vctuxs(vector float a, int b) { - return (vector signed char)__builtin_altivec_lvxl(a, b); + return __builtin_altivec_vctuxs(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_ldl(int a, vector unsigned char *b) +/* vec_dss */ + +static void __attribute__((__always_inline__)) +vec_dss(int a) { - return (vector unsigned char)__builtin_altivec_lvxl(a, b); + __builtin_altivec_dss(a); } -static vector unsigned char __ATTRS_o_ai -vec_ldl(int a, unsigned char *b) +/* vec_dssall */ + +static void __attribute__((__always_inline__)) +vec_dssall(void) { - return (vector unsigned char)__builtin_altivec_lvxl(a, b); + __builtin_altivec_dssall(); } -static vector short __ATTRS_o_ai -vec_ldl(int a, vector short *b) +/* vec_dst */ + +static void __attribute__((__always_inline__)) +vec_dst(void *a, int b, int c) { - return (vector short)__builtin_altivec_lvxl(a, b); + __builtin_altivec_dst(a, b, c); } -static vector short __ATTRS_o_ai -vec_ldl(int a, short *b) +/* vec_dstst */ + +static void __attribute__((__always_inline__)) +vec_dstst(void *a, int b, int c) { - return (vector short)__builtin_altivec_lvxl(a, b); + __builtin_altivec_dstst(a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_ldl(int a, vector unsigned short *b) +/* vec_dststt */ + +static void __attribute__((__always_inline__)) +vec_dststt(void *a, int b, int c) { - return (vector unsigned short)__builtin_altivec_lvxl(a, b); + __builtin_altivec_dststt(a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_ldl(int a, unsigned short *b) +/* vec_dstt */ + +static void __attribute__((__always_inline__)) +vec_dstt(void *a, int b, int c) { - return (vector unsigned short)__builtin_altivec_lvxl(a, b); + __builtin_altivec_dstt(a, b, c); } -static vector int __ATTRS_o_ai -vec_ldl(int a, vector int *b) +/* vec_expte */ + +static vector float __attribute__((__always_inline__)) +vec_expte(vector float a) { - return (vector int)__builtin_altivec_lvxl(a, b); + return __builtin_altivec_vexptefp(a); } -static vector int __ATTRS_o_ai -vec_ldl(int a, int *b) -{ - return (vector int)__builtin_altivec_lvxl(a, b); -} +/* vec_vexptefp */ -static vector unsigned int __ATTRS_o_ai -vec_ldl(int a, vector unsigned int *b) +static vector float __attribute__((__always_inline__)) +vec_vexptefp(vector float a) { - return (vector unsigned int)__builtin_altivec_lvxl(a, b); + return __builtin_altivec_vexptefp(a); } -static vector unsigned int __ATTRS_o_ai -vec_ldl(int a, unsigned int *b) -{ - return (vector unsigned int)__builtin_altivec_lvxl(a, b); -} +/* vec_floor */ -static vector float __ATTRS_o_ai -vec_ldl(int a, vector float *b) +static vector float __attribute__((__always_inline__)) +vec_floor(vector float a) { - return (vector float)__builtin_altivec_lvxl(a, b); + return __builtin_altivec_vrfim(a); } -static vector float __ATTRS_o_ai -vec_ldl(int a, float *b) +/* vec_vrfim */ + +static vector float __attribute__((__always_inline__)) +vec_vrfim(vector float a) { - return (vector float)__builtin_altivec_lvxl(a, b); + return __builtin_altivec_vrfim(a); } -/* vec_lvxl */ +/* vec_ld */ static vector signed char __ATTRS_o_ai -vec_lvxl(int a, vector signed char *b) +vec_ld(int a, vector signed char *b) { - return (vector signed char)__builtin_altivec_lvxl(a, b); + return (vector signed char)__builtin_altivec_lvx(a, b); } static vector signed char __ATTRS_o_ai -vec_lvxl(int a, signed char *b) +vec_ld(int a, signed char *b) { - return (vector signed char)__builtin_altivec_lvxl(a, b); + return (vector signed char)__builtin_altivec_lvx(a, b); } static vector unsigned char __ATTRS_o_ai -vec_lvxl(int a, vector unsigned char *b) +vec_ld(int a, vector unsigned char *b) { - return (vector unsigned char)__builtin_altivec_lvxl(a, b); + return (vector unsigned char)__builtin_altivec_lvx(a, b); } static vector unsigned char __ATTRS_o_ai -vec_lvxl(int a, unsigned char *b) +vec_ld(int a, unsigned char *b) { - return (vector unsigned char)__builtin_altivec_lvxl(a, b); + return (vector unsigned char)__builtin_altivec_lvx(a, b); +} + +static vector bool char __ATTRS_o_ai +vec_ld(int a, vector bool char *b) +{ + return (vector bool char)__builtin_altivec_lvx(a, b); } static vector short __ATTRS_o_ai -vec_lvxl(int a, vector short *b) +vec_ld(int a, vector short *b) { - return (vector short)__builtin_altivec_lvxl(a, b); + return (vector short)__builtin_altivec_lvx(a, b); } static vector short __ATTRS_o_ai -vec_lvxl(int a, short *b) +vec_ld(int a, short *b) { - return (vector short)__builtin_altivec_lvxl(a, b); + return (vector short)__builtin_altivec_lvx(a, b); } static vector unsigned short __ATTRS_o_ai -vec_lvxl(int a, vector unsigned short *b) +vec_ld(int a, vector unsigned short *b) { - return (vector unsigned short)__builtin_altivec_lvxl(a, b); + return (vector unsigned short)__builtin_altivec_lvx(a, b); } static vector unsigned short __ATTRS_o_ai -vec_lvxl(int a, unsigned short *b) +vec_ld(int a, unsigned short *b) { - return (vector unsigned short)__builtin_altivec_lvxl(a, b); + return (vector unsigned short)__builtin_altivec_lvx(a, b); } -static vector int __ATTRS_o_ai -vec_lvxl(int a, vector int *b) +static vector bool short __ATTRS_o_ai +vec_ld(int a, vector bool short *b) { - return (vector int)__builtin_altivec_lvxl(a, b); + return (vector bool short)__builtin_altivec_lvx(a, b); +} + +static vector pixel __ATTRS_o_ai +vec_ld(int a, vector pixel *b) +{ + return (vector pixel)__builtin_altivec_lvx(a, b); } static vector int __ATTRS_o_ai -vec_lvxl(int a, int *b) +vec_ld(int a, vector int *b) { - return (vector int)__builtin_altivec_lvxl(a, b); + return (vector int)__builtin_altivec_lvx(a, b); } -static vector unsigned int __ATTRS_o_ai -vec_lvxl(int a, vector unsigned int *b) +static vector int __ATTRS_o_ai +vec_ld(int a, int *b) { - return (vector unsigned int)__builtin_altivec_lvxl(a, b); + return (vector int)__builtin_altivec_lvx(a, b); } static vector unsigned int __ATTRS_o_ai -vec_lvxl(int a, unsigned int *b) +vec_ld(int a, vector unsigned int *b) { - return (vector unsigned int)__builtin_altivec_lvxl(a, b); + return (vector unsigned int)__builtin_altivec_lvx(a, b); } -static vector float __ATTRS_o_ai -vec_lvxl(int a, vector float *b) +static vector unsigned int __ATTRS_o_ai +vec_ld(int a, unsigned int *b) { - return (vector float)__builtin_altivec_lvxl(a, b); + return (vector unsigned int)__builtin_altivec_lvx(a, b); } -static vector float __ATTRS_o_ai -vec_lvxl(int a, float *b) +static vector bool int __ATTRS_o_ai +vec_ld(int a, vector bool int *b) { - return (vector float)__builtin_altivec_lvxl(a, b); + return (vector bool int)__builtin_altivec_lvx(a, b); } -/* vec_loge */ - -static vector float __attribute__((__always_inline__)) -vec_loge(vector float a) +static vector float __ATTRS_o_ai +vec_ld(int a, vector float *b) { - return __builtin_altivec_vlogefp(a); + return (vector float)__builtin_altivec_lvx(a, b); } -/* vec_vlogefp */ - -static vector float __attribute__((__always_inline__)) -vec_vlogefp(vector float a) +static vector float __ATTRS_o_ai +vec_ld(int a, float *b) { - return __builtin_altivec_vlogefp(a); + return (vector float)__builtin_altivec_lvx(a, b); } -/* vec_lvsl */ +/* vec_lvx */ -static vector unsigned char __ATTRS_o_ai -vec_lvsl(int a, signed char *b) +static vector signed char __ATTRS_o_ai +vec_lvx(int a, vector signed char *b) { - return (vector unsigned char)__builtin_altivec_lvsl(a, b); + return (vector signed char)__builtin_altivec_lvx(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_lvsl(int a, unsigned char *b) +static vector signed char __ATTRS_o_ai +vec_lvx(int a, signed char *b) { - return (vector unsigned char)__builtin_altivec_lvsl(a, b); + return (vector signed char)__builtin_altivec_lvx(a, b); } static vector unsigned char __ATTRS_o_ai -vec_lvsl(int a, short *b) +vec_lvx(int a, vector unsigned char *b) { - return (vector unsigned char)__builtin_altivec_lvsl(a, b); + return (vector unsigned char)__builtin_altivec_lvx(a, b); } static vector unsigned char __ATTRS_o_ai -vec_lvsl(int a, unsigned short *b) +vec_lvx(int a, unsigned char *b) { - return (vector unsigned char)__builtin_altivec_lvsl(a, b); + return (vector unsigned char)__builtin_altivec_lvx(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_lvsl(int a, int *b) +static vector bool char __ATTRS_o_ai +vec_lvx(int a, vector bool char *b) { - return (vector unsigned char)__builtin_altivec_lvsl(a, b); + return (vector bool char)__builtin_altivec_lvx(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_lvsl(int a, unsigned int *b) +static vector short __ATTRS_o_ai +vec_lvx(int a, vector short *b) { - return (vector unsigned char)__builtin_altivec_lvsl(a, b); + return (vector short)__builtin_altivec_lvx(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_lvsl(int a, float *b) +static vector short __ATTRS_o_ai +vec_lvx(int a, short *b) { - return (vector unsigned char)__builtin_altivec_lvsl(a, b); + return (vector short)__builtin_altivec_lvx(a, b); } -/* vec_lvsr */ - -static vector unsigned char __ATTRS_o_ai -vec_lvsr(int a, signed char *b) +static vector unsigned short __ATTRS_o_ai +vec_lvx(int a, vector unsigned short *b) { - return (vector unsigned char)__builtin_altivec_lvsr(a, b); + return (vector unsigned short)__builtin_altivec_lvx(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_lvsr(int a, unsigned char *b) +static vector unsigned short __ATTRS_o_ai +vec_lvx(int a, unsigned short *b) { - return (vector unsigned char)__builtin_altivec_lvsr(a, b); + return (vector unsigned short)__builtin_altivec_lvx(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_lvsr(int a, short *b) +static vector bool short __ATTRS_o_ai +vec_lvx(int a, vector bool short *b) { - return (vector unsigned char)__builtin_altivec_lvsr(a, b); + return (vector bool short)__builtin_altivec_lvx(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_lvsr(int a, unsigned short *b) +static vector pixel __ATTRS_o_ai +vec_lvx(int a, vector pixel *b) { - return (vector unsigned char)__builtin_altivec_lvsr(a, b); + return (vector pixel)__builtin_altivec_lvx(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_lvsr(int a, int *b) +static vector int __ATTRS_o_ai +vec_lvx(int a, vector int *b) { - return (vector unsigned char)__builtin_altivec_lvsr(a, b); + return (vector int)__builtin_altivec_lvx(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_lvsr(int a, unsigned int *b) +static vector int __ATTRS_o_ai +vec_lvx(int a, int *b) { - return (vector unsigned char)__builtin_altivec_lvsr(a, b); + return (vector int)__builtin_altivec_lvx(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_lvsr(int a, float *b) +static vector unsigned int __ATTRS_o_ai +vec_lvx(int a, vector unsigned int *b) { - return (vector unsigned char)__builtin_altivec_lvsr(a, b); + return (vector unsigned int)__builtin_altivec_lvx(a, b); } -/* vec_madd */ - -static vector float __attribute__((__always_inline__)) -vec_madd(vector float a, vector float b, vector float c) +static vector unsigned int __ATTRS_o_ai +vec_lvx(int a, unsigned int *b) { - return __builtin_altivec_vmaddfp(a, b, c); + return (vector unsigned int)__builtin_altivec_lvx(a, b); } -/* vec_vmaddfp */ - -static vector float __attribute__((__always_inline__)) -vec_vmaddfp(vector float a, vector float b, vector float c) +static vector bool int __ATTRS_o_ai +vec_lvx(int a, vector bool int *b) { - return __builtin_altivec_vmaddfp(a, b, c); + return (vector bool int)__builtin_altivec_lvx(a, b); } -/* vec_madds */ - -static vector signed short __attribute__((__always_inline__)) -vec_madds(vector signed short a, vector signed short b, vector signed short c) +static vector float __ATTRS_o_ai +vec_lvx(int a, vector float *b) { - return __builtin_altivec_vmhaddshs(a, b, c); + return (vector float)__builtin_altivec_lvx(a, b); } -/* vec_vmhaddshs */ -static vector signed short __attribute__((__always_inline__)) -vec_vmhaddshs(vector signed short a, vector signed short b, vector signed short c) +static vector float __ATTRS_o_ai +vec_lvx(int a, float *b) { - return __builtin_altivec_vmhaddshs(a, b, c); + return (vector float)__builtin_altivec_lvx(a, b); } -/* vec_max */ +/* vec_lde */ static vector signed char __ATTRS_o_ai -vec_max(vector signed char a, vector signed char b) +vec_lde(int a, vector signed char *b) { - return __builtin_altivec_vmaxsb(a, b); + return (vector signed char)__builtin_altivec_lvebx(a, b); } static vector unsigned char __ATTRS_o_ai -vec_max(vector unsigned char a, vector unsigned char b) +vec_lde(int a, vector unsigned char *b) { - return __builtin_altivec_vmaxub(a, b); + return (vector unsigned char)__builtin_altivec_lvebx(a, b); } static vector short __ATTRS_o_ai -vec_max(vector short a, vector short b) +vec_lde(int a, vector short *b) { - return __builtin_altivec_vmaxsh(a, b); + return (vector short)__builtin_altivec_lvehx(a, b); } static vector unsigned short __ATTRS_o_ai -vec_max(vector unsigned short a, vector unsigned short b) +vec_lde(int a, vector unsigned short *b) { - return __builtin_altivec_vmaxuh(a, b); + return (vector unsigned short)__builtin_altivec_lvehx(a, b); } static vector int __ATTRS_o_ai -vec_max(vector int a, vector int b) +vec_lde(int a, vector int *b) { - return __builtin_altivec_vmaxsw(a, b); + return (vector int)__builtin_altivec_lvewx(a, b); } static vector unsigned int __ATTRS_o_ai -vec_max(vector unsigned int a, vector unsigned int b) +vec_lde(int a, vector unsigned int *b) { - return __builtin_altivec_vmaxuw(a, b); + return (vector unsigned int)__builtin_altivec_lvewx(a, b); } static vector float __ATTRS_o_ai -vec_max(vector float a, vector float b) +vec_lde(int a, vector float *b) { - return __builtin_altivec_vmaxfp(a, b); + return (vector float)__builtin_altivec_lvewx(a, b); } -/* vec_vmaxsb */ +/* vec_lvebx */ -static vector signed char __attribute__((__always_inline__)) -vec_vmaxsb(vector signed char a, vector signed char b) +static vector signed char __ATTRS_o_ai +vec_lvebx(int a, vector signed char *b) { - return __builtin_altivec_vmaxsb(a, b); + return (vector signed char)__builtin_altivec_lvebx(a, b); } -/* vec_vmaxub */ - -static vector unsigned char __attribute__((__always_inline__)) -vec_vmaxub(vector unsigned char a, vector unsigned char b) -{ +static vector unsigned char __ATTRS_o_ai +vec_lvebx(int a, vector unsigned char *b) +{ + return (vector unsigned char)__builtin_altivec_lvebx(a, b); +} + +/* vec_lvehx */ + +static vector short __ATTRS_o_ai +vec_lvehx(int a, vector short *b) +{ + return (vector short)__builtin_altivec_lvehx(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_lvehx(int a, vector unsigned short *b) +{ + return (vector unsigned short)__builtin_altivec_lvehx(a, b); +} + +/* vec_lvewx */ + +static vector int __ATTRS_o_ai +vec_lvewx(int a, vector int *b) +{ + return (vector int)__builtin_altivec_lvewx(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_lvewx(int a, vector unsigned int *b) +{ + return (vector unsigned int)__builtin_altivec_lvewx(a, b); +} + +static vector float __ATTRS_o_ai +vec_lvewx(int a, vector float *b) +{ + return (vector float)__builtin_altivec_lvewx(a, b); +} + +/* vec_ldl */ + +static vector signed char __ATTRS_o_ai +vec_ldl(int a, vector signed char *b) +{ + return (vector signed char)__builtin_altivec_lvxl(a, b); +} + +static vector signed char __ATTRS_o_ai +vec_ldl(int a, signed char *b) +{ + return (vector signed char)__builtin_altivec_lvxl(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_ldl(int a, vector unsigned char *b) +{ + return (vector unsigned char)__builtin_altivec_lvxl(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_ldl(int a, unsigned char *b) +{ + return (vector unsigned char)__builtin_altivec_lvxl(a, b); +} + +static vector bool char __ATTRS_o_ai +vec_ldl(int a, vector bool char *b) +{ + return (vector bool char)__builtin_altivec_lvxl(a, b); +} + +static vector short __ATTRS_o_ai +vec_ldl(int a, vector short *b) +{ + return (vector short)__builtin_altivec_lvxl(a, b); +} + +static vector short __ATTRS_o_ai +vec_ldl(int a, short *b) +{ + return (vector short)__builtin_altivec_lvxl(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_ldl(int a, vector unsigned short *b) +{ + return (vector unsigned short)__builtin_altivec_lvxl(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_ldl(int a, unsigned short *b) +{ + return (vector unsigned short)__builtin_altivec_lvxl(a, b); +} + +static vector bool short __ATTRS_o_ai +vec_ldl(int a, vector bool short *b) +{ + return (vector bool short)__builtin_altivec_lvxl(a, b); +} + +static vector pixel __ATTRS_o_ai +vec_ldl(int a, vector pixel *b) +{ + return (vector pixel short)__builtin_altivec_lvxl(a, b); +} + +static vector int __ATTRS_o_ai +vec_ldl(int a, vector int *b) +{ + return (vector int)__builtin_altivec_lvxl(a, b); +} + +static vector int __ATTRS_o_ai +vec_ldl(int a, int *b) +{ + return (vector int)__builtin_altivec_lvxl(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_ldl(int a, vector unsigned int *b) +{ + return (vector unsigned int)__builtin_altivec_lvxl(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_ldl(int a, unsigned int *b) +{ + return (vector unsigned int)__builtin_altivec_lvxl(a, b); +} + +static vector bool int __ATTRS_o_ai +vec_ldl(int a, vector bool int *b) +{ + return (vector bool int)__builtin_altivec_lvxl(a, b); +} + +static vector float __ATTRS_o_ai +vec_ldl(int a, vector float *b) +{ + return (vector float)__builtin_altivec_lvxl(a, b); +} + +static vector float __ATTRS_o_ai +vec_ldl(int a, float *b) +{ + return (vector float)__builtin_altivec_lvxl(a, b); +} + +/* vec_lvxl */ + +static vector signed char __ATTRS_o_ai +vec_lvxl(int a, vector signed char *b) +{ + return (vector signed char)__builtin_altivec_lvxl(a, b); +} + +static vector signed char __ATTRS_o_ai +vec_lvxl(int a, signed char *b) +{ + return (vector signed char)__builtin_altivec_lvxl(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvxl(int a, vector unsigned char *b) +{ + return (vector unsigned char)__builtin_altivec_lvxl(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvxl(int a, unsigned char *b) +{ + return (vector unsigned char)__builtin_altivec_lvxl(a, b); +} + +static vector bool char __ATTRS_o_ai +vec_lvxl(int a, vector bool char *b) +{ + return (vector bool char)__builtin_altivec_lvxl(a, b); +} + +static vector short __ATTRS_o_ai +vec_lvxl(int a, vector short *b) +{ + return (vector short)__builtin_altivec_lvxl(a, b); +} + +static vector short __ATTRS_o_ai +vec_lvxl(int a, short *b) +{ + return (vector short)__builtin_altivec_lvxl(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_lvxl(int a, vector unsigned short *b) +{ + return (vector unsigned short)__builtin_altivec_lvxl(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_lvxl(int a, unsigned short *b) +{ + return (vector unsigned short)__builtin_altivec_lvxl(a, b); +} + +static vector bool short __ATTRS_o_ai +vec_lvxl(int a, vector bool short *b) +{ + return (vector bool short)__builtin_altivec_lvxl(a, b); +} + +static vector pixel __ATTRS_o_ai +vec_lvxl(int a, vector pixel *b) +{ + return (vector pixel)__builtin_altivec_lvxl(a, b); +} + +static vector int __ATTRS_o_ai +vec_lvxl(int a, vector int *b) +{ + return (vector int)__builtin_altivec_lvxl(a, b); +} + +static vector int __ATTRS_o_ai +vec_lvxl(int a, int *b) +{ + return (vector int)__builtin_altivec_lvxl(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_lvxl(int a, vector unsigned int *b) +{ + return (vector unsigned int)__builtin_altivec_lvxl(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_lvxl(int a, unsigned int *b) +{ + return (vector unsigned int)__builtin_altivec_lvxl(a, b); +} + +static vector bool int __ATTRS_o_ai +vec_lvxl(int a, vector bool int *b) +{ + return (vector bool int)__builtin_altivec_lvxl(a, b); +} + +static vector float __ATTRS_o_ai +vec_lvxl(int a, vector float *b) +{ + return (vector float)__builtin_altivec_lvxl(a, b); +} + +static vector float __ATTRS_o_ai +vec_lvxl(int a, float *b) +{ + return (vector float)__builtin_altivec_lvxl(a, b); +} + +/* vec_loge */ + +static vector float __attribute__((__always_inline__)) +vec_loge(vector float a) +{ + return __builtin_altivec_vlogefp(a); +} + +/* vec_vlogefp */ + +static vector float __attribute__((__always_inline__)) +vec_vlogefp(vector float a) +{ + return __builtin_altivec_vlogefp(a); +} + +/* vec_lvsl */ + +static vector unsigned char __ATTRS_o_ai +vec_lvsl(int a, signed char *b) +{ + return (vector unsigned char)__builtin_altivec_lvsl(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvsl(int a, unsigned char *b) +{ + return (vector unsigned char)__builtin_altivec_lvsl(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvsl(int a, short *b) +{ + return (vector unsigned char)__builtin_altivec_lvsl(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvsl(int a, unsigned short *b) +{ + return (vector unsigned char)__builtin_altivec_lvsl(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvsl(int a, int *b) +{ + return (vector unsigned char)__builtin_altivec_lvsl(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvsl(int a, unsigned int *b) +{ + return (vector unsigned char)__builtin_altivec_lvsl(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvsl(int a, float *b) +{ + return (vector unsigned char)__builtin_altivec_lvsl(a, b); +} + +/* vec_lvsr */ + +static vector unsigned char __ATTRS_o_ai +vec_lvsr(int a, signed char *b) +{ + return (vector unsigned char)__builtin_altivec_lvsr(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvsr(int a, unsigned char *b) +{ + return (vector unsigned char)__builtin_altivec_lvsr(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvsr(int a, short *b) +{ + return (vector unsigned char)__builtin_altivec_lvsr(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvsr(int a, unsigned short *b) +{ + return (vector unsigned char)__builtin_altivec_lvsr(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvsr(int a, int *b) +{ + return (vector unsigned char)__builtin_altivec_lvsr(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvsr(int a, unsigned int *b) +{ + return (vector unsigned char)__builtin_altivec_lvsr(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_lvsr(int a, float *b) +{ + return (vector unsigned char)__builtin_altivec_lvsr(a, b); +} + +/* vec_madd */ + +static vector float __attribute__((__always_inline__)) +vec_madd(vector float a, vector float b, vector float c) +{ + return __builtin_altivec_vmaddfp(a, b, c); +} + +/* vec_vmaddfp */ + +static vector float __attribute__((__always_inline__)) +vec_vmaddfp(vector float a, vector float b, vector float c) +{ + return __builtin_altivec_vmaddfp(a, b, c); +} + +/* vec_madds */ + +static vector signed short __attribute__((__always_inline__)) +vec_madds(vector signed short a, vector signed short b, vector signed short c) +{ + return __builtin_altivec_vmhaddshs(a, b, c); +} + +/* vec_vmhaddshs */ +static vector signed short __attribute__((__always_inline__)) +vec_vmhaddshs(vector signed short a, vector signed short b, vector signed short c) +{ + return __builtin_altivec_vmhaddshs(a, b, c); +} + +/* vec_max */ + +static vector signed char __ATTRS_o_ai +vec_max(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vmaxsb(a, b); +} + +static vector signed char __ATTRS_o_ai +vec_max(vector bool char a, vector signed char b) +{ + return __builtin_altivec_vmaxsb((vector signed char)a, b); +} + +static vector signed char __ATTRS_o_ai +vec_max(vector signed char a, vector bool char b) +{ + return __builtin_altivec_vmaxsb(a, (vector signed char)b); +} + +static vector unsigned char __ATTRS_o_ai +vec_max(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vmaxub(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_max(vector bool char a, vector unsigned char b) +{ + return __builtin_altivec_vmaxub((vector unsigned char)a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_max(vector unsigned char a, vector bool char b) +{ + return __builtin_altivec_vmaxub(a, (vector unsigned char)b); +} + +static vector short __ATTRS_o_ai +vec_max(vector short a, vector short b) +{ + return __builtin_altivec_vmaxsh(a, b); +} + +static vector short __ATTRS_o_ai +vec_max(vector bool short a, vector short b) +{ + return __builtin_altivec_vmaxsh((vector short)a, b); +} + +static vector short __ATTRS_o_ai +vec_max(vector short a, vector bool short b) +{ + return __builtin_altivec_vmaxsh(a, (vector short)b); +} + +static vector unsigned short __ATTRS_o_ai +vec_max(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vmaxuh(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_max(vector bool short a, vector unsigned short b) +{ + return __builtin_altivec_vmaxuh((vector unsigned short)a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_max(vector unsigned short a, vector bool short b) +{ + return __builtin_altivec_vmaxuh(a, (vector unsigned short)b); +} + +static vector int __ATTRS_o_ai +vec_max(vector int a, vector int b) +{ + return __builtin_altivec_vmaxsw(a, b); +} + +static vector int __ATTRS_o_ai +vec_max(vector bool int a, vector int b) +{ + return __builtin_altivec_vmaxsw((vector int)a, b); +} + +static vector int __ATTRS_o_ai +vec_max(vector int a, vector bool int b) +{ + return __builtin_altivec_vmaxsw(a, (vector int)b); +} + +static vector unsigned int __ATTRS_o_ai +vec_max(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vmaxuw(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_max(vector bool int a, vector unsigned int b) +{ + return __builtin_altivec_vmaxuw((vector unsigned int)a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_max(vector unsigned int a, vector bool int b) +{ + return __builtin_altivec_vmaxuw(a, (vector unsigned int)b); +} + +static vector float __ATTRS_o_ai +vec_max(vector float a, vector float b) +{ + return __builtin_altivec_vmaxfp(a, b); +} + +/* vec_vmaxsb */ + +static vector signed char __ATTRS_o_ai +vec_vmaxsb(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vmaxsb(a, b); +} + +static vector signed char __ATTRS_o_ai +vec_vmaxsb(vector bool char a, vector signed char b) +{ + return __builtin_altivec_vmaxsb((vector signed char)a, b); +} + +static vector signed char __ATTRS_o_ai +vec_vmaxsb(vector signed char a, vector bool char b) +{ + return __builtin_altivec_vmaxsb(a, (vector signed char)b); +} + +/* vec_vmaxub */ + +static vector unsigned char __ATTRS_o_ai +vec_vmaxub(vector unsigned char a, vector unsigned char b) +{ return __builtin_altivec_vmaxub(a, b); } -/* vec_vmaxsh */ +static vector unsigned char __ATTRS_o_ai +vec_vmaxub(vector bool char a, vector unsigned char b) +{ + return __builtin_altivec_vmaxub((vector unsigned char)a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vmaxub(vector unsigned char a, vector bool char b) +{ + return __builtin_altivec_vmaxub(a, (vector unsigned char)b); +} + +/* vec_vmaxsh */ + +static vector short __ATTRS_o_ai +vec_vmaxsh(vector short a, vector short b) +{ + return __builtin_altivec_vmaxsh(a, b); +} + +static vector short __ATTRS_o_ai +vec_vmaxsh(vector bool short a, vector short b) +{ + return __builtin_altivec_vmaxsh((vector short)a, b); +} + +static vector short __ATTRS_o_ai +vec_vmaxsh(vector short a, vector bool short b) +{ + return __builtin_altivec_vmaxsh(a, (vector short)b); +} + +/* vec_vmaxuh */ + +static vector unsigned short __ATTRS_o_ai +vec_vmaxuh(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vmaxuh(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vmaxuh(vector bool short a, vector unsigned short b) +{ + return __builtin_altivec_vmaxuh((vector unsigned short)a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vmaxuh(vector unsigned short a, vector bool short b) +{ + return __builtin_altivec_vmaxuh(a, (vector unsigned short)b); +} + +/* vec_vmaxsw */ + +static vector int __ATTRS_o_ai +vec_vmaxsw(vector int a, vector int b) +{ + return __builtin_altivec_vmaxsw(a, b); +} + +static vector int __ATTRS_o_ai +vec_vmaxsw(vector bool int a, vector int b) +{ + return __builtin_altivec_vmaxsw((vector int)a, b); +} + +static vector int __ATTRS_o_ai +vec_vmaxsw(vector int a, vector bool int b) +{ + return __builtin_altivec_vmaxsw(a, (vector int)b); +} + +/* vec_vmaxuw */ + +static vector unsigned int __ATTRS_o_ai +vec_vmaxuw(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vmaxuw(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_vmaxuw(vector bool int a, vector unsigned int b) +{ + return __builtin_altivec_vmaxuw((vector unsigned int)a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_vmaxuw(vector unsigned int a, vector bool int b) +{ + return __builtin_altivec_vmaxuw(a, (vector unsigned int)b); +} + +/* vec_vmaxfp */ + +static vector float __attribute__((__always_inline__)) +vec_vmaxfp(vector float a, vector float b) +{ + return __builtin_altivec_vmaxfp(a, b); +} + +/* vec_mergeh */ + +static vector signed char __ATTRS_o_ai +vec_mergeh(vector signed char a, vector signed char b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, + 0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17)); +} + +static vector unsigned char __ATTRS_o_ai +vec_mergeh(vector unsigned char a, vector unsigned char b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, + 0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17)); +} + +static vector bool char __ATTRS_o_ai +vec_mergeh(vector bool char a, vector bool char b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, + 0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17)); +} + +static vector short __ATTRS_o_ai +vec_mergeh(vector short a, vector short b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13, + 0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17)); +} + +static vector unsigned short __ATTRS_o_ai +vec_mergeh(vector unsigned short a, vector unsigned short b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13, + 0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17)); +} + +static vector bool short __ATTRS_o_ai +vec_mergeh(vector bool short a, vector bool short b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13, + 0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17)); +} + +static vector pixel __ATTRS_o_ai +vec_mergeh(vector pixel a, vector pixel b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13, + 0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17)); +} + +static vector int __ATTRS_o_ai +vec_mergeh(vector int a, vector int b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, + 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); +} + +static vector unsigned int __ATTRS_o_ai +vec_mergeh(vector unsigned int a, vector unsigned int b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, + 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); +} + +static vector bool int __ATTRS_o_ai +vec_mergeh(vector bool int a, vector bool int b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, + 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); +} + +static vector float __ATTRS_o_ai +vec_mergeh(vector float a, vector float b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, + 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); +} + +/* vec_vmrghb */ + +#define __builtin_altivec_vmrghb vec_vmrghb + +static vector signed char __ATTRS_o_ai +vec_vmrghb(vector signed char a, vector signed char b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, + 0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17)); +} + +static vector unsigned char __ATTRS_o_ai +vec_vmrghb(vector unsigned char a, vector unsigned char b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, + 0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17)); +} + +static vector bool char __ATTRS_o_ai +vec_vmrghb(vector bool char a, vector bool char b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, + 0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17)); +} + +/* vec_vmrghh */ + +#define __builtin_altivec_vmrghh vec_vmrghh + +static vector short __ATTRS_o_ai +vec_vmrghh(vector short a, vector short b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13, + 0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17)); +} + +static vector unsigned short __ATTRS_o_ai +vec_vmrghh(vector unsigned short a, vector unsigned short b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13, + 0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17)); +} + +static vector bool short __ATTRS_o_ai +vec_vmrghh(vector bool short a, vector bool short b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13, + 0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17)); +} + +static vector pixel __ATTRS_o_ai +vec_vmrghh(vector pixel a, vector pixel b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13, + 0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17)); +} + +/* vec_vmrghw */ + +#define __builtin_altivec_vmrghw vec_vmrghw + +static vector int __ATTRS_o_ai +vec_vmrghw(vector int a, vector int b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, + 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); +} + +static vector unsigned int __ATTRS_o_ai +vec_vmrghw(vector unsigned int a, vector unsigned int b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, + 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); +} + +static vector bool int __ATTRS_o_ai +vec_vmrghw(vector bool int a, vector bool int b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, + 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); +} + +static vector float __ATTRS_o_ai +vec_vmrghw(vector float a, vector float b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, + 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); +} + +/* vec_mergel */ + +static vector signed char __ATTRS_o_ai +vec_mergel(vector signed char a, vector signed char b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B, + 0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F)); +} + +static vector unsigned char __ATTRS_o_ai +vec_mergel(vector unsigned char a, vector unsigned char b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B, + 0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F)); +} + +static vector bool char __ATTRS_o_ai +vec_mergel(vector bool char a, vector bool char b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B, + 0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F)); +} + +static vector short __ATTRS_o_ai +vec_mergel(vector short a, vector short b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B, + 0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F)); +} + +static vector unsigned short __ATTRS_o_ai +vec_mergel(vector unsigned short a, vector unsigned short b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B, + 0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F)); +} + +static vector bool short __ATTRS_o_ai +vec_mergel(vector bool short a, vector bool short b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B, + 0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F)); +} + +static vector pixel __ATTRS_o_ai +vec_mergel(vector pixel a, vector pixel b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B, + 0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F)); +} + +static vector int __ATTRS_o_ai +vec_mergel(vector int a, vector int b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); +} + +static vector unsigned int __ATTRS_o_ai +vec_mergel(vector unsigned int a, vector unsigned int b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); +} + +static vector bool int __ATTRS_o_ai +vec_mergel(vector bool int a, vector bool int b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); +} + +static vector float __ATTRS_o_ai +vec_mergel(vector float a, vector float b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); +} + +/* vec_vmrglb */ + +#define __builtin_altivec_vmrglb vec_vmrglb + +static vector signed char __ATTRS_o_ai +vec_vmrglb(vector signed char a, vector signed char b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B, + 0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F)); +} + +static vector unsigned char __ATTRS_o_ai +vec_vmrglb(vector unsigned char a, vector unsigned char b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B, + 0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F)); +} + +static vector bool char __ATTRS_o_ai +vec_vmrglb(vector bool char a, vector bool char b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B, + 0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F)); +} + +/* vec_vmrglh */ + +#define __builtin_altivec_vmrglh vec_vmrglh + +static vector short __ATTRS_o_ai +vec_vmrglh(vector short a, vector short b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B, + 0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F)); +} + +static vector unsigned short __ATTRS_o_ai +vec_vmrglh(vector unsigned short a, vector unsigned short b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B, + 0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F)); +} + +static vector bool short __ATTRS_o_ai +vec_vmrglh(vector bool short a, vector bool short b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B, + 0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F)); +} + +static vector pixel __ATTRS_o_ai +vec_vmrglh(vector pixel a, vector pixel b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B, + 0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F)); +} + +/* vec_vmrglw */ + +#define __builtin_altivec_vmrglw vec_vmrglw + +static vector int __ATTRS_o_ai +vec_vmrglw(vector int a, vector int b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); +} + +static vector unsigned int __ATTRS_o_ai +vec_vmrglw(vector unsigned int a, vector unsigned int b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); +} + +static vector bool int __ATTRS_o_ai +vec_vmrglw(vector bool int a, vector bool int b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); +} + +static vector float __ATTRS_o_ai +vec_vmrglw(vector float a, vector float b) +{ + return vec_perm(a, b, (vector unsigned char) + (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); +} + +/* vec_mfvscr */ + +static vector unsigned short __attribute__((__always_inline__)) +vec_mfvscr(void) +{ + return __builtin_altivec_mfvscr(); +} + +/* vec_min */ + +static vector signed char __ATTRS_o_ai +vec_min(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vminsb(a, b); +} + +static vector signed char __ATTRS_o_ai +vec_min(vector bool char a, vector signed char b) +{ + return __builtin_altivec_vminsb((vector signed char)a, b); +} + +static vector signed char __ATTRS_o_ai +vec_min(vector signed char a, vector bool char b) +{ + return __builtin_altivec_vminsb(a, (vector signed char)b); +} + +static vector unsigned char __ATTRS_o_ai +vec_min(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vminub(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_min(vector bool char a, vector unsigned char b) +{ + return __builtin_altivec_vminub((vector unsigned char)a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_min(vector unsigned char a, vector bool char b) +{ + return __builtin_altivec_vminub(a, (vector unsigned char)b); +} + +static vector short __ATTRS_o_ai +vec_min(vector short a, vector short b) +{ + return __builtin_altivec_vminsh(a, b); +} + +static vector short __ATTRS_o_ai +vec_min(vector bool short a, vector short b) +{ + return __builtin_altivec_vminsh((vector short)a, b); +} + +static vector short __ATTRS_o_ai +vec_min(vector short a, vector bool short b) +{ + return __builtin_altivec_vminsh(a, (vector short)b); +} + +static vector unsigned short __ATTRS_o_ai +vec_min(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vminuh(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_min(vector bool short a, vector unsigned short b) +{ + return __builtin_altivec_vminuh((vector unsigned short)a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_min(vector unsigned short a, vector bool short b) +{ + return __builtin_altivec_vminuh(a, (vector unsigned short)b); +} + +static vector int __ATTRS_o_ai +vec_min(vector int a, vector int b) +{ + return __builtin_altivec_vminsw(a, b); +} + +static vector int __ATTRS_o_ai +vec_min(vector bool int a, vector int b) +{ + return __builtin_altivec_vminsw((vector int)a, b); +} + +static vector int __ATTRS_o_ai +vec_min(vector int a, vector bool int b) +{ + return __builtin_altivec_vminsw(a, (vector int)b); +} + +static vector unsigned int __ATTRS_o_ai +vec_min(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vminuw(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_min(vector bool int a, vector unsigned int b) +{ + return __builtin_altivec_vminuw((vector unsigned int)a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_min(vector unsigned int a, vector bool int b) +{ + return __builtin_altivec_vminuw(a, (vector unsigned int)b); +} + +static vector float __ATTRS_o_ai +vec_min(vector float a, vector float b) +{ + return __builtin_altivec_vminfp(a, b); +} + +/* vec_vminsb */ + +static vector signed char __ATTRS_o_ai +vec_vminsb(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vminsb(a, b); +} + +static vector signed char __ATTRS_o_ai +vec_vminsb(vector bool char a, vector signed char b) +{ + return __builtin_altivec_vminsb((vector signed char)a, b); +} + +static vector signed char __ATTRS_o_ai +vec_vminsb(vector signed char a, vector bool char b) +{ + return __builtin_altivec_vminsb(a, (vector signed char)b); +} + +/* vec_vminub */ + +static vector unsigned char __ATTRS_o_ai +vec_vminub(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vminub(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vminub(vector bool char a, vector unsigned char b) +{ + return __builtin_altivec_vminub((vector unsigned char)a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vminub(vector unsigned char a, vector bool char b) +{ + return __builtin_altivec_vminub(a, (vector unsigned char)b); +} + +/* vec_vminsh */ + +static vector short __ATTRS_o_ai +vec_vminsh(vector short a, vector short b) +{ + return __builtin_altivec_vminsh(a, b); +} + +static vector short __ATTRS_o_ai +vec_vminsh(vector bool short a, vector short b) +{ + return __builtin_altivec_vminsh((vector short)a, b); +} + +static vector short __ATTRS_o_ai +vec_vminsh(vector short a, vector bool short b) +{ + return __builtin_altivec_vminsh(a, (vector short)b); +} + +/* vec_vminuh */ + +static vector unsigned short __ATTRS_o_ai +vec_vminuh(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vminuh(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vminuh(vector bool short a, vector unsigned short b) +{ + return __builtin_altivec_vminuh((vector unsigned short)a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vminuh(vector unsigned short a, vector bool short b) +{ + return __builtin_altivec_vminuh(a, (vector unsigned short)b); +} + +/* vec_vminsw */ + +static vector int __ATTRS_o_ai +vec_vminsw(vector int a, vector int b) +{ + return __builtin_altivec_vminsw(a, b); +} + +static vector int __ATTRS_o_ai +vec_vminsw(vector bool int a, vector int b) +{ + return __builtin_altivec_vminsw((vector int)a, b); +} + +static vector int __ATTRS_o_ai +vec_vminsw(vector int a, vector bool int b) +{ + return __builtin_altivec_vminsw(a, (vector int)b); +} + +/* vec_vminuw */ + +static vector unsigned int __ATTRS_o_ai +vec_vminuw(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vminuw(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_vminuw(vector bool int a, vector unsigned int b) +{ + return __builtin_altivec_vminuw((vector unsigned int)a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_vminuw(vector unsigned int a, vector bool int b) +{ + return __builtin_altivec_vminuw(a, (vector unsigned int)b); +} + +/* vec_vminfp */ + +static vector float __attribute__((__always_inline__)) +vec_vminfp(vector float a, vector float b) +{ + return __builtin_altivec_vminfp(a, b); +} + +/* vec_mladd */ + +#define __builtin_altivec_vmladduhm vec_mladd + +static vector short __ATTRS_o_ai +vec_mladd(vector short a, vector short b, vector short c) +{ + return a * b + c; +} + +static vector short __ATTRS_o_ai +vec_mladd(vector short a, vector unsigned short b, vector unsigned short c) +{ + return a * (vector short)b + (vector short)c; +} + +static vector short __ATTRS_o_ai +vec_mladd(vector unsigned short a, vector short b, vector short c) +{ + return (vector short)a * b + c; +} + +static vector unsigned short __ATTRS_o_ai +vec_mladd(vector unsigned short a, vector unsigned short b, vector unsigned short c) +{ + return a * b + c; +} + +/* vec_vmladduhm */ + +static vector short __ATTRS_o_ai +vec_vmladduhm(vector short a, vector short b, vector short c) +{ + return a * b + c; +} + +static vector short __ATTRS_o_ai +vec_vmladduhm(vector short a, vector unsigned short b, vector unsigned short c) +{ + return a * (vector short)b + (vector short)c; +} + +static vector short __ATTRS_o_ai +vec_vmladduhm(vector unsigned short a, vector short b, vector short c) +{ + return (vector short)a * b + c; +} + +static vector unsigned short __ATTRS_o_ai +vec_vmladduhm(vector unsigned short a, vector unsigned short b, vector unsigned short c) +{ + return a * b + c; +} + +/* vec_mradds */ + +static vector short __attribute__((__always_inline__)) +vec_mradds(vector short a, vector short b, vector short c) +{ + return __builtin_altivec_vmhraddshs(a, b, c); +} + +/* vec_vmhraddshs */ + +static vector short __attribute__((__always_inline__)) +vec_vmhraddshs(vector short a, vector short b, vector short c) +{ + return __builtin_altivec_vmhraddshs(a, b, c); +} + +/* vec_msum */ + +static vector int __ATTRS_o_ai +vec_msum(vector signed char a, vector unsigned char b, vector int c) +{ + return __builtin_altivec_vmsummbm(a, b, c); +} + +static vector unsigned int __ATTRS_o_ai +vec_msum(vector unsigned char a, vector unsigned char b, vector unsigned int c) +{ + return __builtin_altivec_vmsumubm(a, b, c); +} + +static vector int __ATTRS_o_ai +vec_msum(vector short a, vector short b, vector int c) +{ + return __builtin_altivec_vmsumshm(a, b, c); +} + +static vector unsigned int __ATTRS_o_ai +vec_msum(vector unsigned short a, vector unsigned short b, vector unsigned int c) +{ + return __builtin_altivec_vmsumuhm(a, b, c); +} + +/* vec_vmsummbm */ + +static vector int __attribute__((__always_inline__)) +vec_vmsummbm(vector signed char a, vector unsigned char b, vector int c) +{ + return __builtin_altivec_vmsummbm(a, b, c); +} + +/* vec_vmsumubm */ + +static vector unsigned int __attribute__((__always_inline__)) +vec_vmsumubm(vector unsigned char a, vector unsigned char b, vector unsigned int c) +{ + return __builtin_altivec_vmsumubm(a, b, c); +} + +/* vec_vmsumshm */ + +static vector int __attribute__((__always_inline__)) +vec_vmsumshm(vector short a, vector short b, vector int c) +{ + return __builtin_altivec_vmsumshm(a, b, c); +} + +/* vec_vmsumuhm */ + +static vector unsigned int __attribute__((__always_inline__)) +vec_vmsumuhm(vector unsigned short a, vector unsigned short b, vector unsigned int c) +{ + return __builtin_altivec_vmsumuhm(a, b, c); +} + +/* vec_msums */ + +static vector int __ATTRS_o_ai +vec_msums(vector short a, vector short b, vector int c) +{ + return __builtin_altivec_vmsumshs(a, b, c); +} + +static vector unsigned int __ATTRS_o_ai +vec_msums(vector unsigned short a, vector unsigned short b, vector unsigned int c) +{ + return __builtin_altivec_vmsumuhs(a, b, c); +} + +/* vec_vmsumshs */ + +static vector int __attribute__((__always_inline__)) +vec_vmsumshs(vector short a, vector short b, vector int c) +{ + return __builtin_altivec_vmsumshs(a, b, c); +} + +/* vec_vmsumuhs */ + +static vector unsigned int __attribute__((__always_inline__)) +vec_vmsumuhs(vector unsigned short a, vector unsigned short b, vector unsigned int c) +{ + return __builtin_altivec_vmsumuhs(a, b, c); +} + +/* vec_mtvscr */ + +static void __ATTRS_o_ai +vec_mtvscr(vector signed char a) +{ + __builtin_altivec_mtvscr((vector int)a); +} + +static void __ATTRS_o_ai +vec_mtvscr(vector unsigned char a) +{ + __builtin_altivec_mtvscr((vector int)a); +} + +static void __ATTRS_o_ai +vec_mtvscr(vector bool char a) +{ + __builtin_altivec_mtvscr((vector int)a); +} + +static void __ATTRS_o_ai +vec_mtvscr(vector short a) +{ + __builtin_altivec_mtvscr((vector int)a); +} + +static void __ATTRS_o_ai +vec_mtvscr(vector unsigned short a) +{ + __builtin_altivec_mtvscr((vector int)a); +} + +static void __ATTRS_o_ai +vec_mtvscr(vector bool short a) +{ + __builtin_altivec_mtvscr((vector int)a); +} + +static void __ATTRS_o_ai +vec_mtvscr(vector pixel a) +{ + __builtin_altivec_mtvscr((vector int)a); +} + +static void __ATTRS_o_ai +vec_mtvscr(vector int a) +{ + __builtin_altivec_mtvscr((vector int)a); +} + +static void __ATTRS_o_ai +vec_mtvscr(vector unsigned int a) +{ + __builtin_altivec_mtvscr((vector int)a); +} + +static void __ATTRS_o_ai +vec_mtvscr(vector bool int a) +{ + __builtin_altivec_mtvscr((vector int)a); +} + +static void __ATTRS_o_ai +vec_mtvscr(vector float a) +{ + __builtin_altivec_mtvscr((vector int)a); +} + +/* vec_mule */ + +static vector short __ATTRS_o_ai +vec_mule(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vmulesb(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_mule(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vmuleub(a, b); +} + +static vector int __ATTRS_o_ai +vec_mule(vector short a, vector short b) +{ + return __builtin_altivec_vmulesh(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_mule(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vmuleuh(a, b); +} + +/* vec_vmulesb */ + +static vector short __attribute__((__always_inline__)) +vec_vmulesb(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vmulesb(a, b); +} + +/* vec_vmuleub */ + +static vector unsigned short __attribute__((__always_inline__)) +vec_vmuleub(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vmuleub(a, b); +} + +/* vec_vmulesh */ + +static vector int __attribute__((__always_inline__)) +vec_vmulesh(vector short a, vector short b) +{ + return __builtin_altivec_vmulesh(a, b); +} + +/* vec_vmuleuh */ + +static vector unsigned int __attribute__((__always_inline__)) +vec_vmuleuh(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vmuleuh(a, b); +} + +/* vec_mulo */ + +static vector short __ATTRS_o_ai +vec_mulo(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vmulosb(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_mulo(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vmuloub(a, b); +} + +static vector int __ATTRS_o_ai +vec_mulo(vector short a, vector short b) +{ + return __builtin_altivec_vmulosh(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_mulo(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vmulouh(a, b); +} + +/* vec_vmulosb */ + +static vector short __attribute__((__always_inline__)) +vec_vmulosb(vector signed char a, vector signed char b) +{ + return __builtin_altivec_vmulosb(a, b); +} + +/* vec_vmuloub */ + +static vector unsigned short __attribute__((__always_inline__)) +vec_vmuloub(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vmuloub(a, b); +} + +/* vec_vmulosh */ + +static vector int __attribute__((__always_inline__)) +vec_vmulosh(vector short a, vector short b) +{ + return __builtin_altivec_vmulosh(a, b); +} + +/* vec_vmulouh */ + +static vector unsigned int __attribute__((__always_inline__)) +vec_vmulouh(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vmulouh(a, b); +} + +/* vec_nmsub */ + +static vector float __attribute__((__always_inline__)) +vec_nmsub(vector float a, vector float b, vector float c) +{ + return __builtin_altivec_vnmsubfp(a, b, c); +} + +/* vec_vnmsubfp */ + +static vector float __attribute__((__always_inline__)) +vec_vnmsubfp(vector float a, vector float b, vector float c) +{ + return __builtin_altivec_vnmsubfp(a, b, c); +} + +/* vec_nor */ + +#define __builtin_altivec_vnor vec_nor + +static vector signed char __ATTRS_o_ai +vec_nor(vector signed char a, vector signed char b) +{ + return ~(a | b); +} + +static vector unsigned char __ATTRS_o_ai +vec_nor(vector unsigned char a, vector unsigned char b) +{ + return ~(a | b); +} + +static vector bool char __ATTRS_o_ai +vec_nor(vector bool char a, vector bool char b) +{ + return ~(a | b); +} + +static vector short __ATTRS_o_ai +vec_nor(vector short a, vector short b) +{ + return ~(a | b); +} + +static vector unsigned short __ATTRS_o_ai +vec_nor(vector unsigned short a, vector unsigned short b) +{ + return ~(a | b); +} + +static vector bool short __ATTRS_o_ai +vec_nor(vector bool short a, vector bool short b) +{ + return ~(a | b); +} + +static vector int __ATTRS_o_ai +vec_nor(vector int a, vector int b) +{ + return ~(a | b); +} + +static vector unsigned int __ATTRS_o_ai +vec_nor(vector unsigned int a, vector unsigned int b) +{ + return ~(a | b); +} + +static vector bool int __ATTRS_o_ai +vec_nor(vector bool int a, vector bool int b) +{ + return ~(a | b); +} + +static vector float __ATTRS_o_ai +vec_nor(vector float a, vector float b) +{ + vector unsigned int res = ~((vector unsigned int)a | (vector unsigned int)b); + return (vector float)res; +} + +/* vec_vnor */ + +static vector signed char __ATTRS_o_ai +vec_vnor(vector signed char a, vector signed char b) +{ + return ~(a | b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vnor(vector unsigned char a, vector unsigned char b) +{ + return ~(a | b); +} + +static vector bool char __ATTRS_o_ai +vec_vnor(vector bool char a, vector bool char b) +{ + return ~(a | b); +} + +static vector short __ATTRS_o_ai +vec_vnor(vector short a, vector short b) +{ + return ~(a | b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vnor(vector unsigned short a, vector unsigned short b) +{ + return ~(a | b); +} + +static vector bool short __ATTRS_o_ai +vec_vnor(vector bool short a, vector bool short b) +{ + return ~(a | b); +} + +static vector int __ATTRS_o_ai +vec_vnor(vector int a, vector int b) +{ + return ~(a | b); +} + +static vector unsigned int __ATTRS_o_ai +vec_vnor(vector unsigned int a, vector unsigned int b) +{ + return ~(a | b); +} + +static vector bool int __ATTRS_o_ai +vec_vnor(vector bool int a, vector bool int b) +{ + return ~(a | b); +} + +static vector float __ATTRS_o_ai +vec_vnor(vector float a, vector float b) +{ + vector unsigned int res = ~((vector unsigned int)a | (vector unsigned int)b); + return (vector float)res; +} + +/* vec_or */ + +#define __builtin_altivec_vor vec_or + +static vector signed char __ATTRS_o_ai +vec_or(vector signed char a, vector signed char b) +{ + return a | b; +} + +static vector signed char __ATTRS_o_ai +vec_or(vector bool char a, vector signed char b) +{ + return (vector signed char)a | b; +} + +static vector signed char __ATTRS_o_ai +vec_or(vector signed char a, vector bool char b) +{ + return a | (vector signed char)b; +} + +static vector unsigned char __ATTRS_o_ai +vec_or(vector unsigned char a, vector unsigned char b) +{ + return a | b; +} + +static vector unsigned char __ATTRS_o_ai +vec_or(vector bool char a, vector unsigned char b) +{ + return (vector unsigned char)a | b; +} + +static vector unsigned char __ATTRS_o_ai +vec_or(vector unsigned char a, vector bool char b) +{ + return a | (vector unsigned char)b; +} + +static vector bool char __ATTRS_o_ai +vec_or(vector bool char a, vector bool char b) +{ + return a | b; +} + +static vector short __ATTRS_o_ai +vec_or(vector short a, vector short b) +{ + return a | b; +} + +static vector short __ATTRS_o_ai +vec_or(vector bool short a, vector short b) +{ + return (vector short)a | b; +} + +static vector short __ATTRS_o_ai +vec_or(vector short a, vector bool short b) +{ + return a | (vector short)b; +} + +static vector unsigned short __ATTRS_o_ai +vec_or(vector unsigned short a, vector unsigned short b) +{ + return a | b; +} + +static vector unsigned short __ATTRS_o_ai +vec_or(vector bool short a, vector unsigned short b) +{ + return (vector unsigned short)a | b; +} + +static vector unsigned short __ATTRS_o_ai +vec_or(vector unsigned short a, vector bool short b) +{ + return a | (vector unsigned short)b; +} + +static vector bool short __ATTRS_o_ai +vec_or(vector bool short a, vector bool short b) +{ + return a | b; +} + +static vector int __ATTRS_o_ai +vec_or(vector int a, vector int b) +{ + return a | b; +} + +static vector int __ATTRS_o_ai +vec_or(vector bool int a, vector int b) +{ + return (vector int)a | b; +} + +static vector int __ATTRS_o_ai +vec_or(vector int a, vector bool int b) +{ + return a | (vector int)b; +} + +static vector unsigned int __ATTRS_o_ai +vec_or(vector unsigned int a, vector unsigned int b) +{ + return a | b; +} + +static vector unsigned int __ATTRS_o_ai +vec_or(vector bool int a, vector unsigned int b) +{ + return (vector unsigned int)a | b; +} + +static vector unsigned int __ATTRS_o_ai +vec_or(vector unsigned int a, vector bool int b) +{ + return a | (vector unsigned int)b; +} + +static vector bool int __ATTRS_o_ai +vec_or(vector bool int a, vector bool int b) +{ + return a | b; +} + +static vector float __ATTRS_o_ai +vec_or(vector float a, vector float b) +{ + vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b; + return (vector float)res; +} + +static vector float __ATTRS_o_ai +vec_or(vector bool int a, vector float b) +{ + vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b; + return (vector float)res; +} + +static vector float __ATTRS_o_ai +vec_or(vector float a, vector bool int b) +{ + vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b; + return (vector float)res; +} + +/* vec_vor */ + +static vector signed char __ATTRS_o_ai +vec_vor(vector signed char a, vector signed char b) +{ + return a | b; +} + +static vector signed char __ATTRS_o_ai +vec_vor(vector bool char a, vector signed char b) +{ + return (vector signed char)a | b; +} + +static vector signed char __ATTRS_o_ai +vec_vor(vector signed char a, vector bool char b) +{ + return a | (vector signed char)b; +} + +static vector unsigned char __ATTRS_o_ai +vec_vor(vector unsigned char a, vector unsigned char b) +{ + return a | b; +} + +static vector unsigned char __ATTRS_o_ai +vec_vor(vector bool char a, vector unsigned char b) +{ + return (vector unsigned char)a | b; +} + +static vector unsigned char __ATTRS_o_ai +vec_vor(vector unsigned char a, vector bool char b) +{ + return a | (vector unsigned char)b; +} + +static vector bool char __ATTRS_o_ai +vec_vor(vector bool char a, vector bool char b) +{ + return a | b; +} + +static vector short __ATTRS_o_ai +vec_vor(vector short a, vector short b) +{ + return a | b; +} + +static vector short __ATTRS_o_ai +vec_vor(vector bool short a, vector short b) +{ + return (vector short)a | b; +} + +static vector short __ATTRS_o_ai +vec_vor(vector short a, vector bool short b) +{ + return a | (vector short)b; +} + +static vector unsigned short __ATTRS_o_ai +vec_vor(vector unsigned short a, vector unsigned short b) +{ + return a | b; +} + +static vector unsigned short __ATTRS_o_ai +vec_vor(vector bool short a, vector unsigned short b) +{ + return (vector unsigned short)a | b; +} + +static vector unsigned short __ATTRS_o_ai +vec_vor(vector unsigned short a, vector bool short b) +{ + return a | (vector unsigned short)b; +} + +static vector bool short __ATTRS_o_ai +vec_vor(vector bool short a, vector bool short b) +{ + return a | b; +} + +static vector int __ATTRS_o_ai +vec_vor(vector int a, vector int b) +{ + return a | b; +} + +static vector int __ATTRS_o_ai +vec_vor(vector bool int a, vector int b) +{ + return (vector int)a | b; +} + +static vector int __ATTRS_o_ai +vec_vor(vector int a, vector bool int b) +{ + return a | (vector int)b; +} + +static vector unsigned int __ATTRS_o_ai +vec_vor(vector unsigned int a, vector unsigned int b) +{ + return a | b; +} + +static vector unsigned int __ATTRS_o_ai +vec_vor(vector bool int a, vector unsigned int b) +{ + return (vector unsigned int)a | b; +} + +static vector unsigned int __ATTRS_o_ai +vec_vor(vector unsigned int a, vector bool int b) +{ + return a | (vector unsigned int)b; +} + +static vector bool int __ATTRS_o_ai +vec_vor(vector bool int a, vector bool int b) +{ + return a | b; +} + +static vector float __ATTRS_o_ai +vec_vor(vector float a, vector float b) +{ + vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b; + return (vector float)res; +} + +static vector float __ATTRS_o_ai +vec_vor(vector bool int a, vector float b) +{ + vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b; + return (vector float)res; +} + +static vector float __ATTRS_o_ai +vec_vor(vector float a, vector bool int b) +{ + vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b; + return (vector float)res; +} + +/* vec_pack */ + +static vector signed char __ATTRS_o_ai +vec_pack(vector signed short a, vector signed short b) +{ + return (vector signed char)vec_perm(a, b, (vector unsigned char) + (0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, + 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F)); +} + +static vector unsigned char __ATTRS_o_ai +vec_pack(vector unsigned short a, vector unsigned short b) +{ + return (vector unsigned char)vec_perm(a, b, (vector unsigned char) + (0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, + 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F)); +} + +static vector bool char __ATTRS_o_ai +vec_pack(vector bool short a, vector bool short b) +{ + return (vector bool char)vec_perm(a, b, (vector unsigned char) + (0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, + 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F)); +} + +static vector short __ATTRS_o_ai +vec_pack(vector int a, vector int b) +{ + return (vector short)vec_perm(a, b, (vector unsigned char) + (0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F, + 0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F)); +} + +static vector unsigned short __ATTRS_o_ai +vec_pack(vector unsigned int a, vector unsigned int b) +{ + return (vector unsigned short)vec_perm(a, b, (vector unsigned char) + (0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F, + 0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F)); +} + +static vector bool short __ATTRS_o_ai +vec_pack(vector bool int a, vector bool int b) +{ + return (vector bool short)vec_perm(a, b, (vector unsigned char) + (0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F, + 0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F)); +} + +/* vec_vpkuhum */ + +#define __builtin_altivec_vpkuhum vec_vpkuhum + +static vector signed char __ATTRS_o_ai +vec_vpkuhum(vector signed short a, vector signed short b) +{ + return (vector signed char)vec_perm(a, b, (vector unsigned char) + (0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, + 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F)); +} + +static vector unsigned char __ATTRS_o_ai +vec_vpkuhum(vector unsigned short a, vector unsigned short b) +{ + return (vector unsigned char)vec_perm(a, b, (vector unsigned char) + (0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, + 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F)); +} + +static vector bool char __ATTRS_o_ai +vec_vpkuhum(vector bool short a, vector bool short b) +{ + return (vector bool char)vec_perm(a, b, (vector unsigned char) + (0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, + 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F)); +} + +/* vec_vpkuwum */ + +#define __builtin_altivec_vpkuwum vec_vpkuwum + +static vector short __ATTRS_o_ai +vec_vpkuwum(vector int a, vector int b) +{ + return (vector short)vec_perm(a, b, (vector unsigned char) + (0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F, + 0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F)); +} + +static vector unsigned short __ATTRS_o_ai +vec_vpkuwum(vector unsigned int a, vector unsigned int b) +{ + return (vector unsigned short)vec_perm(a, b, (vector unsigned char) + (0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F, + 0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F)); +} + +static vector bool short __ATTRS_o_ai +vec_vpkuwum(vector bool int a, vector bool int b) +{ + return (vector bool short)vec_perm(a, b, (vector unsigned char) + (0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F, + 0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F)); +} + +/* vec_packpx */ + +static vector pixel __attribute__((__always_inline__)) +vec_packpx(vector unsigned int a, vector unsigned int b) +{ + return (vector pixel)__builtin_altivec_vpkpx(a, b); +} + +/* vec_vpkpx */ + +static vector pixel __attribute__((__always_inline__)) +vec_vpkpx(vector unsigned int a, vector unsigned int b) +{ + return (vector pixel)__builtin_altivec_vpkpx(a, b); +} + +/* vec_packs */ + +static vector signed char __ATTRS_o_ai +vec_packs(vector short a, vector short b) +{ + return __builtin_altivec_vpkshss(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_packs(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vpkuhus(a, b); +} + +static vector signed short __ATTRS_o_ai +vec_packs(vector int a, vector int b) +{ + return __builtin_altivec_vpkswss(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_packs(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vpkuwus(a, b); +} + +/* vec_vpkshss */ + +static vector signed char __attribute__((__always_inline__)) +vec_vpkshss(vector short a, vector short b) +{ + return __builtin_altivec_vpkshss(a, b); +} + +/* vec_vpkuhus */ + +static vector unsigned char __attribute__((__always_inline__)) +vec_vpkuhus(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vpkuhus(a, b); +} + +/* vec_vpkswss */ + +static vector signed short __attribute__((__always_inline__)) +vec_vpkswss(vector int a, vector int b) +{ + return __builtin_altivec_vpkswss(a, b); +} + +/* vec_vpkuwus */ + +static vector unsigned short __attribute__((__always_inline__)) +vec_vpkuwus(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vpkuwus(a, b); +} + +/* vec_packsu */ + +static vector unsigned char __ATTRS_o_ai +vec_packsu(vector short a, vector short b) +{ + return __builtin_altivec_vpkshus(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_packsu(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vpkuhus(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_packsu(vector int a, vector int b) +{ + return __builtin_altivec_vpkswus(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_packsu(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vpkuwus(a, b); +} + +/* vec_vpkshus */ + +static vector unsigned char __ATTRS_o_ai +vec_vpkshus(vector short a, vector short b) +{ + return __builtin_altivec_vpkshus(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vpkshus(vector unsigned short a, vector unsigned short b) +{ + return __builtin_altivec_vpkuhus(a, b); +} + +/* vec_vpkswus */ + +static vector unsigned short __ATTRS_o_ai +vec_vpkswus(vector int a, vector int b) +{ + return __builtin_altivec_vpkswus(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vpkswus(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vpkuwus(a, b); +} + +/* vec_perm */ + +vector signed char __ATTRS_o_ai +vec_perm(vector signed char a, vector signed char b, vector unsigned char c) +{ + return (vector signed char)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector unsigned char __ATTRS_o_ai +vec_perm(vector unsigned char a, vector unsigned char b, vector unsigned char c) +{ + return (vector unsigned char)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector bool char __ATTRS_o_ai +vec_perm(vector bool char a, vector bool char b, vector unsigned char c) +{ + return (vector bool char)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector short __ATTRS_o_ai +vec_perm(vector short a, vector short b, vector unsigned char c) +{ + return (vector short)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector unsigned short __ATTRS_o_ai +vec_perm(vector unsigned short a, vector unsigned short b, vector unsigned char c) +{ + return (vector unsigned short)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector bool short __ATTRS_o_ai +vec_perm(vector bool short a, vector bool short b, vector unsigned char c) +{ + return (vector bool short)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector pixel __ATTRS_o_ai +vec_perm(vector pixel a, vector pixel b, vector unsigned char c) +{ + return (vector pixel)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector int __ATTRS_o_ai +vec_perm(vector int a, vector int b, vector unsigned char c) +{ + return (vector int)__builtin_altivec_vperm_4si(a, b, c); +} + +vector unsigned int __ATTRS_o_ai +vec_perm(vector unsigned int a, vector unsigned int b, vector unsigned char c) +{ + return (vector unsigned int)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector bool int __ATTRS_o_ai +vec_perm(vector bool int a, vector bool int b, vector unsigned char c) +{ + return (vector bool int)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector float __ATTRS_o_ai +vec_perm(vector float a, vector float b, vector unsigned char c) +{ + return (vector float)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +/* vec_vperm */ + +vector signed char __ATTRS_o_ai +vec_vperm(vector signed char a, vector signed char b, vector unsigned char c) +{ + return (vector signed char)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector unsigned char __ATTRS_o_ai +vec_vperm(vector unsigned char a, vector unsigned char b, vector unsigned char c) +{ + return (vector unsigned char)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector bool char __ATTRS_o_ai +vec_vperm(vector bool char a, vector bool char b, vector unsigned char c) +{ + return (vector bool char)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector short __ATTRS_o_ai +vec_vperm(vector short a, vector short b, vector unsigned char c) +{ + return (vector short)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector unsigned short __ATTRS_o_ai +vec_vperm(vector unsigned short a, vector unsigned short b, vector unsigned char c) +{ + return (vector unsigned short)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector bool short __ATTRS_o_ai +vec_vperm(vector bool short a, vector bool short b, vector unsigned char c) +{ + return (vector bool short)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector pixel __ATTRS_o_ai +vec_vperm(vector pixel a, vector pixel b, vector unsigned char c) +{ + return (vector pixel)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector int __ATTRS_o_ai +vec_vperm(vector int a, vector int b, vector unsigned char c) +{ + return (vector int)__builtin_altivec_vperm_4si(a, b, c); +} + +vector unsigned int __ATTRS_o_ai +vec_vperm(vector unsigned int a, vector unsigned int b, vector unsigned char c) +{ + return (vector unsigned int)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector bool int __ATTRS_o_ai +vec_vperm(vector bool int a, vector bool int b, vector unsigned char c) +{ + return (vector bool int)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +vector float __ATTRS_o_ai +vec_vperm(vector float a, vector float b, vector unsigned char c) +{ + return (vector float)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); +} + +/* vec_re */ + +vector float __attribute__((__always_inline__)) +vec_re(vector float a) +{ + return __builtin_altivec_vrefp(a); +} + +/* vec_vrefp */ + +vector float __attribute__((__always_inline__)) +vec_vrefp(vector float a) +{ + return __builtin_altivec_vrefp(a); +} + +/* vec_rl */ + +static vector signed char __ATTRS_o_ai +vec_rl(vector signed char a, vector unsigned char b) +{ + return (vector signed char)__builtin_altivec_vrlb((vector char)a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_rl(vector unsigned char a, vector unsigned char b) +{ + return (vector unsigned char)__builtin_altivec_vrlb((vector char)a, b); +} + +static vector short __ATTRS_o_ai +vec_rl(vector short a, vector unsigned short b) +{ + return __builtin_altivec_vrlh(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_rl(vector unsigned short a, vector unsigned short b) +{ + return (vector unsigned short)__builtin_altivec_vrlh((vector short)a, b); +} + +static vector int __ATTRS_o_ai +vec_rl(vector int a, vector unsigned int b) +{ + return __builtin_altivec_vrlw(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_rl(vector unsigned int a, vector unsigned int b) +{ + return (vector unsigned int)__builtin_altivec_vrlw((vector int)a, b); +} + +/* vec_vrlb */ + +static vector signed char __ATTRS_o_ai +vec_vrlb(vector signed char a, vector unsigned char b) +{ + return (vector signed char)__builtin_altivec_vrlb((vector char)a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vrlb(vector unsigned char a, vector unsigned char b) +{ + return (vector unsigned char)__builtin_altivec_vrlb((vector char)a, b); +} + +/* vec_vrlh */ + +static vector short __ATTRS_o_ai +vec_vrlh(vector short a, vector unsigned short b) +{ + return __builtin_altivec_vrlh(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vrlh(vector unsigned short a, vector unsigned short b) +{ + return (vector unsigned short)__builtin_altivec_vrlh((vector short)a, b); +} + +/* vec_vrlw */ + +static vector int __ATTRS_o_ai +vec_vrlw(vector int a, vector unsigned int b) +{ + return __builtin_altivec_vrlw(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_vrlw(vector unsigned int a, vector unsigned int b) +{ + return (vector unsigned int)__builtin_altivec_vrlw((vector int)a, b); +} + +/* vec_round */ + +static vector float __attribute__((__always_inline__)) +vec_round(vector float a) +{ + return __builtin_altivec_vrfin(a); +} + +/* vec_vrfin */ + +static vector float __attribute__((__always_inline__)) +vec_vrfin(vector float a) +{ + return __builtin_altivec_vrfin(a); +} + +/* vec_rsqrte */ + +static __vector float __attribute__((__always_inline__)) +vec_rsqrte(vector float a) +{ + return __builtin_altivec_vrsqrtefp(a); +} + +/* vec_vrsqrtefp */ + +static __vector float __attribute__((__always_inline__)) +vec_vrsqrtefp(vector float a) +{ + return __builtin_altivec_vrsqrtefp(a); +} + +/* vec_sel */ + +#define __builtin_altivec_vsel_4si vec_sel + +static vector signed char __ATTRS_o_ai +vec_sel(vector signed char a, vector signed char b, vector unsigned char c) +{ + return (a & ~(vector signed char)c) | (b & (vector signed char)c); +} + +static vector signed char __ATTRS_o_ai +vec_sel(vector signed char a, vector signed char b, vector bool char c) +{ + return (a & ~(vector signed char)c) | (b & (vector signed char)c); +} + +static vector unsigned char __ATTRS_o_ai +vec_sel(vector unsigned char a, vector unsigned char b, vector unsigned char c) +{ + return (a & ~c) | (b & c); +} + +static vector unsigned char __ATTRS_o_ai +vec_sel(vector unsigned char a, vector unsigned char b, vector bool char c) +{ + return (a & ~(vector unsigned char)c) | (b & (vector unsigned char)c); +} + +static vector bool char __ATTRS_o_ai +vec_sel(vector bool char a, vector bool char b, vector unsigned char c) +{ + return (a & ~(vector bool char)c) | (b & (vector bool char)c); +} + +static vector bool char __ATTRS_o_ai +vec_sel(vector bool char a, vector bool char b, vector bool char c) +{ + return (a & ~c) | (b & c); +} + +static vector short __ATTRS_o_ai +vec_sel(vector short a, vector short b, vector unsigned short c) +{ + return (a & ~(vector short)c) | (b & (vector short)c); +} + +static vector short __ATTRS_o_ai +vec_sel(vector short a, vector short b, vector bool short c) +{ + return (a & ~(vector short)c) | (b & (vector short)c); +} + +static vector unsigned short __ATTRS_o_ai +vec_sel(vector unsigned short a, vector unsigned short b, vector unsigned short c) +{ + return (a & ~c) | (b & c); +} + +static vector unsigned short __ATTRS_o_ai +vec_sel(vector unsigned short a, vector unsigned short b, vector bool short c) +{ + return (a & ~(vector unsigned short)c) | (b & (vector unsigned short)c); +} + +static vector bool short __ATTRS_o_ai +vec_sel(vector bool short a, vector bool short b, vector unsigned short c) +{ + return (a & ~(vector bool short)c) | (b & (vector bool short)c); +} + +static vector bool short __ATTRS_o_ai +vec_sel(vector bool short a, vector bool short b, vector bool short c) +{ + return (a & ~c) | (b & c); +} + +static vector int __ATTRS_o_ai +vec_sel(vector int a, vector int b, vector unsigned int c) +{ + return (a & ~(vector int)c) | (b & (vector int)c); +} + +static vector int __ATTRS_o_ai +vec_sel(vector int a, vector int b, vector bool int c) +{ + return (a & ~(vector int)c) | (b & (vector int)c); +} + +static vector unsigned int __ATTRS_o_ai +vec_sel(vector unsigned int a, vector unsigned int b, vector unsigned int c) +{ + return (a & ~c) | (b & c); +} + +static vector unsigned int __ATTRS_o_ai +vec_sel(vector unsigned int a, vector unsigned int b, vector bool int c) +{ + return (a & ~(vector unsigned int)c) | (b & (vector unsigned int)c); +} + +static vector bool int __ATTRS_o_ai +vec_sel(vector bool int a, vector bool int b, vector unsigned int c) +{ + return (a & ~(vector bool int)c) | (b & (vector bool int)c); +} + +static vector bool int __ATTRS_o_ai +vec_sel(vector bool int a, vector bool int b, vector bool int c) +{ + return (a & ~c) | (b & c); +} + +static vector float __ATTRS_o_ai +vec_sel(vector float a, vector float b, vector unsigned int c) +{ + vector int res = ((vector int)a & ~(vector int)c) | ((vector int)b & (vector int)c); + return (vector float)res; +} + +static vector float __ATTRS_o_ai +vec_sel(vector float a, vector float b, vector bool int c) +{ + vector int res = ((vector int)a & ~(vector int)c) | ((vector int)b & (vector int)c); + return (vector float)res; +} + +/* vec_vsel */ + +static vector signed char __ATTRS_o_ai +vec_vsel(vector signed char a, vector signed char b, vector unsigned char c) +{ + return (a & ~(vector signed char)c) | (b & (vector signed char)c); +} + +static vector signed char __ATTRS_o_ai +vec_vsel(vector signed char a, vector signed char b, vector bool char c) +{ + return (a & ~(vector signed char)c) | (b & (vector signed char)c); +} + +static vector unsigned char __ATTRS_o_ai +vec_vsel(vector unsigned char a, vector unsigned char b, vector unsigned char c) +{ + return (a & ~c) | (b & c); +} + +static vector unsigned char __ATTRS_o_ai +vec_vsel(vector unsigned char a, vector unsigned char b, vector bool char c) +{ + return (a & ~(vector unsigned char)c) | (b & (vector unsigned char)c); +} + +static vector bool char __ATTRS_o_ai +vec_vsel(vector bool char a, vector bool char b, vector unsigned char c) +{ + return (a & ~(vector bool char)c) | (b & (vector bool char)c); +} + +static vector bool char __ATTRS_o_ai +vec_vsel(vector bool char a, vector bool char b, vector bool char c) +{ + return (a & ~c) | (b & c); +} + +static vector short __ATTRS_o_ai +vec_vsel(vector short a, vector short b, vector unsigned short c) +{ + return (a & ~(vector short)c) | (b & (vector short)c); +} + +static vector short __ATTRS_o_ai +vec_vsel(vector short a, vector short b, vector bool short c) +{ + return (a & ~(vector short)c) | (b & (vector short)c); +} + +static vector unsigned short __ATTRS_o_ai +vec_vsel(vector unsigned short a, vector unsigned short b, vector unsigned short c) +{ + return (a & ~c) | (b & c); +} + +static vector unsigned short __ATTRS_o_ai +vec_vsel(vector unsigned short a, vector unsigned short b, vector bool short c) +{ + return (a & ~(vector unsigned short)c) | (b & (vector unsigned short)c); +} + +static vector bool short __ATTRS_o_ai +vec_vsel(vector bool short a, vector bool short b, vector unsigned short c) +{ + return (a & ~(vector bool short)c) | (b & (vector bool short)c); +} + +static vector bool short __ATTRS_o_ai +vec_vsel(vector bool short a, vector bool short b, vector bool short c) +{ + return (a & ~c) | (b & c); +} + +static vector int __ATTRS_o_ai +vec_vsel(vector int a, vector int b, vector unsigned int c) +{ + return (a & ~(vector int)c) | (b & (vector int)c); +} + +static vector int __ATTRS_o_ai +vec_vsel(vector int a, vector int b, vector bool int c) +{ + return (a & ~(vector int)c) | (b & (vector int)c); +} + +static vector unsigned int __ATTRS_o_ai +vec_vsel(vector unsigned int a, vector unsigned int b, vector unsigned int c) +{ + return (a & ~c) | (b & c); +} + +static vector unsigned int __ATTRS_o_ai +vec_vsel(vector unsigned int a, vector unsigned int b, vector bool int c) +{ + return (a & ~(vector unsigned int)c) | (b & (vector unsigned int)c); +} + +static vector bool int __ATTRS_o_ai +vec_vsel(vector bool int a, vector bool int b, vector unsigned int c) +{ + return (a & ~(vector bool int)c) | (b & (vector bool int)c); +} + +static vector bool int __ATTRS_o_ai +vec_vsel(vector bool int a, vector bool int b, vector bool int c) +{ + return (a & ~c) | (b & c); +} + +static vector float __ATTRS_o_ai +vec_vsel(vector float a, vector float b, vector unsigned int c) +{ + vector int res = ((vector int)a & ~(vector int)c) | ((vector int)b & (vector int)c); + return (vector float)res; +} + +static vector float __ATTRS_o_ai +vec_vsel(vector float a, vector float b, vector bool int c) +{ + vector int res = ((vector int)a & ~(vector int)c) | ((vector int)b & (vector int)c); + return (vector float)res; +} + +/* vec_sl */ + +static vector signed char __ATTRS_o_ai +vec_sl(vector signed char a, vector unsigned char b) +{ + return a << (vector signed char)b; +} + +static vector unsigned char __ATTRS_o_ai +vec_sl(vector unsigned char a, vector unsigned char b) +{ + return a << b; +} + +static vector short __ATTRS_o_ai +vec_sl(vector short a, vector unsigned short b) +{ + return a << (vector short)b; +} + +static vector unsigned short __ATTRS_o_ai +vec_sl(vector unsigned short a, vector unsigned short b) +{ + return a << b; +} + +static vector int __ATTRS_o_ai +vec_sl(vector int a, vector unsigned int b) +{ + return a << (vector int)b; +} + +static vector unsigned int __ATTRS_o_ai +vec_sl(vector unsigned int a, vector unsigned int b) +{ + return a << b; +} + +/* vec_vslb */ + +#define __builtin_altivec_vslb vec_vslb + +static vector signed char __ATTRS_o_ai +vec_vslb(vector signed char a, vector unsigned char b) +{ + return vec_sl(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vslb(vector unsigned char a, vector unsigned char b) +{ + return vec_sl(a, b); +} + +/* vec_vslh */ + +#define __builtin_altivec_vslh vec_vslh + +static vector short __ATTRS_o_ai +vec_vslh(vector short a, vector unsigned short b) +{ + return vec_sl(a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vslh(vector unsigned short a, vector unsigned short b) +{ + return vec_sl(a, b); +} + +/* vec_vslw */ + +#define __builtin_altivec_vslw vec_vslw + +static vector int __ATTRS_o_ai +vec_vslw(vector int a, vector unsigned int b) +{ + return vec_sl(a, b); +} + +static vector unsigned int __ATTRS_o_ai +vec_vslw(vector unsigned int a, vector unsigned int b) +{ + return vec_sl(a, b); +} + +/* vec_sld */ + +#define __builtin_altivec_vsldoi_4si vec_sld + +static vector signed char __ATTRS_o_ai +vec_sld(vector signed char a, vector signed char b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector unsigned char __ATTRS_o_ai +vec_sld(vector unsigned char a, vector unsigned char b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector short __ATTRS_o_ai +vec_sld(vector short a, vector short b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector unsigned short __ATTRS_o_ai +vec_sld(vector unsigned short a, vector unsigned short b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector pixel __ATTRS_o_ai +vec_sld(vector pixel a, vector pixel b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector int __ATTRS_o_ai +vec_sld(vector int a, vector int b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector unsigned int __ATTRS_o_ai +vec_sld(vector unsigned int a, vector unsigned int b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector float __ATTRS_o_ai +vec_sld(vector float a, vector float b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +/* vec_vsldoi */ + +static vector signed char __ATTRS_o_ai +vec_vsldoi(vector signed char a, vector signed char b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector unsigned char __ATTRS_o_ai +vec_vsldoi(vector unsigned char a, vector unsigned char b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector short __ATTRS_o_ai +vec_vsldoi(vector short a, vector short b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector unsigned short __ATTRS_o_ai +vec_vsldoi(vector unsigned short a, vector unsigned short b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector pixel __ATTRS_o_ai +vec_vsldoi(vector pixel a, vector pixel b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector int __ATTRS_o_ai +vec_vsldoi(vector int a, vector int b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector unsigned int __ATTRS_o_ai +vec_vsldoi(vector unsigned int a, vector unsigned int b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +static vector float __ATTRS_o_ai +vec_vsldoi(vector float a, vector float b, unsigned char c) +{ + return vec_perm(a, b, (vector unsigned char) + (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, + c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +} + +/* vec_sll */ + +static vector signed char __ATTRS_o_ai +vec_sll(vector signed char a, vector unsigned char b) +{ + return (vector signed char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector signed char __ATTRS_o_ai +vec_sll(vector signed char a, vector unsigned short b) +{ + return (vector signed char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector signed char __ATTRS_o_ai +vec_sll(vector signed char a, vector unsigned int b) +{ + return (vector signed char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned char __ATTRS_o_ai +vec_sll(vector unsigned char a, vector unsigned char b) +{ + return (vector unsigned char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned char __ATTRS_o_ai +vec_sll(vector unsigned char a, vector unsigned short b) +{ + return (vector unsigned char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned char __ATTRS_o_ai +vec_sll(vector unsigned char a, vector unsigned int b) +{ + return (vector unsigned char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool char __ATTRS_o_ai +vec_sll(vector bool char a, vector unsigned char b) +{ + return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool char __ATTRS_o_ai +vec_sll(vector bool char a, vector unsigned short b) +{ + return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool char __ATTRS_o_ai +vec_sll(vector bool char a, vector unsigned int b) +{ + return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector short __ATTRS_o_ai +vec_sll(vector short a, vector unsigned char b) +{ + return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector short __ATTRS_o_ai +vec_sll(vector short a, vector unsigned short b) +{ + return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector short __ATTRS_o_ai +vec_sll(vector short a, vector unsigned int b) +{ + return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned short __ATTRS_o_ai +vec_sll(vector unsigned short a, vector unsigned char b) +{ + return (vector unsigned short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned short __ATTRS_o_ai +vec_sll(vector unsigned short a, vector unsigned short b) +{ + return (vector unsigned short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned short __ATTRS_o_ai +vec_sll(vector unsigned short a, vector unsigned int b) +{ + return (vector unsigned short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool short __ATTRS_o_ai +vec_sll(vector bool short a, vector unsigned char b) +{ + return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool short __ATTRS_o_ai +vec_sll(vector bool short a, vector unsigned short b) +{ + return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool short __ATTRS_o_ai +vec_sll(vector bool short a, vector unsigned int b) +{ + return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector pixel __ATTRS_o_ai +vec_sll(vector pixel a, vector unsigned char b) +{ + return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector pixel __ATTRS_o_ai +vec_sll(vector pixel a, vector unsigned short b) +{ + return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector pixel __ATTRS_o_ai +vec_sll(vector pixel a, vector unsigned int b) +{ + return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector int __ATTRS_o_ai +vec_sll(vector int a, vector unsigned char b) +{ + return (vector int)__builtin_altivec_vsl(a, (vector int)b); +} + +static vector int __ATTRS_o_ai +vec_sll(vector int a, vector unsigned short b) +{ + return (vector int)__builtin_altivec_vsl(a, (vector int)b); +} + +static vector int __ATTRS_o_ai +vec_sll(vector int a, vector unsigned int b) +{ + return (vector int)__builtin_altivec_vsl(a, (vector int)b); +} + +static vector unsigned int __ATTRS_o_ai +vec_sll(vector unsigned int a, vector unsigned char b) +{ + return (vector unsigned int)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned int __ATTRS_o_ai +vec_sll(vector unsigned int a, vector unsigned short b) +{ + return (vector unsigned int)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned int __ATTRS_o_ai +vec_sll(vector unsigned int a, vector unsigned int b) +{ + return (vector unsigned int)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool int __ATTRS_o_ai +vec_sll(vector bool int a, vector unsigned char b) +{ + return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool int __ATTRS_o_ai +vec_sll(vector bool int a, vector unsigned short b) +{ + return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool int __ATTRS_o_ai +vec_sll(vector bool int a, vector unsigned int b) +{ + return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +/* vec_vsl */ + +static vector signed char __ATTRS_o_ai +vec_vsl(vector signed char a, vector unsigned char b) +{ + return (vector signed char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector signed char __ATTRS_o_ai +vec_vsl(vector signed char a, vector unsigned short b) +{ + return (vector signed char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector signed char __ATTRS_o_ai +vec_vsl(vector signed char a, vector unsigned int b) +{ + return (vector signed char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vsl(vector unsigned char a, vector unsigned char b) +{ + return (vector unsigned char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vsl(vector unsigned char a, vector unsigned short b) +{ + return (vector unsigned char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vsl(vector unsigned char a, vector unsigned int b) +{ + return (vector unsigned char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool char __ATTRS_o_ai +vec_vsl(vector bool char a, vector unsigned char b) +{ + return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool char __ATTRS_o_ai +vec_vsl(vector bool char a, vector unsigned short b) +{ + return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool char __ATTRS_o_ai +vec_vsl(vector bool char a, vector unsigned int b) +{ + return (vector bool char)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector short __ATTRS_o_ai +vec_vsl(vector short a, vector unsigned char b) +{ + return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector short __ATTRS_o_ai +vec_vsl(vector short a, vector unsigned short b) +{ + return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector short __ATTRS_o_ai +vec_vsl(vector short a, vector unsigned int b) +{ + return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vsl(vector unsigned short a, vector unsigned char b) +{ + return (vector unsigned short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vsl(vector unsigned short a, vector unsigned short b) +{ + return (vector unsigned short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vsl(vector unsigned short a, vector unsigned int b) +{ + return (vector unsigned short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool short __ATTRS_o_ai +vec_vsl(vector bool short a, vector unsigned char b) +{ + return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool short __ATTRS_o_ai +vec_vsl(vector bool short a, vector unsigned short b) +{ + return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool short __ATTRS_o_ai +vec_vsl(vector bool short a, vector unsigned int b) +{ + return (vector bool short)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector pixel __ATTRS_o_ai +vec_vsl(vector pixel a, vector unsigned char b) +{ + return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector pixel __ATTRS_o_ai +vec_vsl(vector pixel a, vector unsigned short b) +{ + return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector pixel __ATTRS_o_ai +vec_vsl(vector pixel a, vector unsigned int b) +{ + return (vector pixel)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector int __ATTRS_o_ai +vec_vsl(vector int a, vector unsigned char b) +{ + return (vector int)__builtin_altivec_vsl(a, (vector int)b); +} + +static vector int __ATTRS_o_ai +vec_vsl(vector int a, vector unsigned short b) +{ + return (vector int)__builtin_altivec_vsl(a, (vector int)b); +} + +static vector int __ATTRS_o_ai +vec_vsl(vector int a, vector unsigned int b) +{ + return (vector int)__builtin_altivec_vsl(a, (vector int)b); +} + +static vector unsigned int __ATTRS_o_ai +vec_vsl(vector unsigned int a, vector unsigned char b) +{ + return (vector unsigned int)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned int __ATTRS_o_ai +vec_vsl(vector unsigned int a, vector unsigned short b) +{ + return (vector unsigned int)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector unsigned int __ATTRS_o_ai +vec_vsl(vector unsigned int a, vector unsigned int b) +{ + return (vector unsigned int)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool int __ATTRS_o_ai +vec_vsl(vector bool int a, vector unsigned char b) +{ + return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool int __ATTRS_o_ai +vec_vsl(vector bool int a, vector unsigned short b) +{ + return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +static vector bool int __ATTRS_o_ai +vec_vsl(vector bool int a, vector unsigned int b) +{ + return (vector bool int)__builtin_altivec_vsl((vector int)a, (vector int)b); +} + +/* vec_slo */ + +static vector signed char __ATTRS_o_ai +vec_slo(vector signed char a, vector signed char b) +{ + return (vector signed char)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector signed char __ATTRS_o_ai +vec_slo(vector signed char a, vector unsigned char b) +{ + return (vector signed char)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector unsigned char __ATTRS_o_ai +vec_slo(vector unsigned char a, vector signed char b) +{ + return (vector unsigned char)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector unsigned char __ATTRS_o_ai +vec_slo(vector unsigned char a, vector unsigned char b) +{ + return (vector unsigned char)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector short __ATTRS_o_ai +vec_slo(vector short a, vector signed char b) +{ + return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector short __ATTRS_o_ai +vec_slo(vector short a, vector unsigned char b) +{ + return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector unsigned short __ATTRS_o_ai +vec_slo(vector unsigned short a, vector signed char b) +{ + return (vector unsigned short)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector unsigned short __ATTRS_o_ai +vec_slo(vector unsigned short a, vector unsigned char b) +{ + return (vector unsigned short)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector pixel __ATTRS_o_ai +vec_slo(vector pixel a, vector signed char b) +{ + return (vector pixel)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector pixel __ATTRS_o_ai +vec_slo(vector pixel a, vector unsigned char b) +{ + return (vector pixel)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector int __ATTRS_o_ai +vec_slo(vector int a, vector signed char b) +{ + return (vector int)__builtin_altivec_vslo(a, (vector int)b); +} + +static vector int __ATTRS_o_ai +vec_slo(vector int a, vector unsigned char b) +{ + return (vector int)__builtin_altivec_vslo(a, (vector int)b); +} + +static vector unsigned int __ATTRS_o_ai +vec_slo(vector unsigned int a, vector signed char b) +{ + return (vector unsigned int)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector unsigned int __ATTRS_o_ai +vec_slo(vector unsigned int a, vector unsigned char b) +{ + return (vector unsigned int)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector float __ATTRS_o_ai +vec_slo(vector float a, vector signed char b) +{ + return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector float __ATTRS_o_ai +vec_slo(vector float a, vector unsigned char b) +{ + return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +/* vec_vslo */ + +static vector signed char __ATTRS_o_ai +vec_vslo(vector signed char a, vector signed char b) +{ + return (vector signed char)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector signed char __ATTRS_o_ai +vec_vslo(vector signed char a, vector unsigned char b) +{ + return (vector signed char)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vslo(vector unsigned char a, vector signed char b) +{ + return (vector unsigned char)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vslo(vector unsigned char a, vector unsigned char b) +{ + return (vector unsigned char)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector short __ATTRS_o_ai +vec_vslo(vector short a, vector signed char b) +{ + return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector short __ATTRS_o_ai +vec_vslo(vector short a, vector unsigned char b) +{ + return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vslo(vector unsigned short a, vector signed char b) +{ + return (vector unsigned short)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector unsigned short __ATTRS_o_ai +vec_vslo(vector unsigned short a, vector unsigned char b) +{ + return (vector unsigned short)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector pixel __ATTRS_o_ai +vec_vslo(vector pixel a, vector signed char b) +{ + return (vector pixel)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector pixel __ATTRS_o_ai +vec_vslo(vector pixel a, vector unsigned char b) +{ + return (vector pixel)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector int __ATTRS_o_ai +vec_vslo(vector int a, vector signed char b) +{ + return (vector int)__builtin_altivec_vslo(a, (vector int)b); +} + +static vector int __ATTRS_o_ai +vec_vslo(vector int a, vector unsigned char b) +{ + return (vector int)__builtin_altivec_vslo(a, (vector int)b); +} + +static vector unsigned int __ATTRS_o_ai +vec_vslo(vector unsigned int a, vector signed char b) +{ + return (vector unsigned int)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector unsigned int __ATTRS_o_ai +vec_vslo(vector unsigned int a, vector unsigned char b) +{ + return (vector unsigned int)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector float __ATTRS_o_ai +vec_vslo(vector float a, vector signed char b) +{ + return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +static vector float __ATTRS_o_ai +vec_vslo(vector float a, vector unsigned char b) +{ + return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b); +} + +/* vec_splat */ + +static vector signed char __ATTRS_o_ai +vec_splat(vector signed char a, unsigned char b) +{ + return vec_perm(a, a, (vector unsigned char)(b)); +} + +static vector unsigned char __ATTRS_o_ai +vec_splat(vector unsigned char a, unsigned char b) +{ + return vec_perm(a, a, (vector unsigned char)(b)); +} + +static vector bool char __ATTRS_o_ai +vec_splat(vector bool char a, unsigned char b) +{ + return vec_perm(a, a, (vector unsigned char)(b)); +} + +static vector short __ATTRS_o_ai +vec_splat(vector short a, unsigned char b) +{ + b *= 2; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1)); +} + +static vector unsigned short __ATTRS_o_ai +vec_splat(vector unsigned short a, unsigned char b) +{ + b *= 2; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1)); +} + +static vector bool short __ATTRS_o_ai +vec_splat(vector bool short a, unsigned char b) +{ + b *= 2; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1)); +} + +static vector pixel __ATTRS_o_ai +vec_splat(vector pixel a, unsigned char b) +{ + b *= 2; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1)); +} + +static vector int __ATTRS_o_ai +vec_splat(vector int a, unsigned char b) +{ + b *= 4; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); +} + +static vector unsigned int __ATTRS_o_ai +vec_splat(vector unsigned int a, unsigned char b) +{ + b *= 4; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); +} + +static vector bool int __ATTRS_o_ai +vec_splat(vector bool int a, unsigned char b) +{ + b *= 4; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); +} + +static vector float __ATTRS_o_ai +vec_splat(vector float a, unsigned char b) +{ + b *= 4; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); +} + +/* vec_vspltb */ + +#define __builtin_altivec_vspltb vec_vspltb + +static vector signed char __ATTRS_o_ai +vec_vspltb(vector signed char a, unsigned char b) +{ + return vec_perm(a, a, (vector unsigned char)(b)); +} + +static vector unsigned char __ATTRS_o_ai +vec_vspltb(vector unsigned char a, unsigned char b) +{ + return vec_perm(a, a, (vector unsigned char)(b)); +} + +static vector bool char __ATTRS_o_ai +vec_vspltb(vector bool char a, unsigned char b) +{ + return vec_perm(a, a, (vector unsigned char)(b)); +} + +/* vec_vsplth */ + +#define __builtin_altivec_vsplth vec_vsplth + +static vector short __ATTRS_o_ai +vec_vsplth(vector short a, unsigned char b) +{ + b *= 2; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1)); +} + +static vector unsigned short __ATTRS_o_ai +vec_vsplth(vector unsigned short a, unsigned char b) +{ + b *= 2; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1)); +} + +static vector bool short __ATTRS_o_ai +vec_vsplth(vector bool short a, unsigned char b) +{ + b *= 2; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1)); +} + +static vector pixel __ATTRS_o_ai +vec_vsplth(vector pixel a, unsigned char b) +{ + b *= 2; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1)); +} + +/* vec_vspltw */ + +#define __builtin_altivec_vspltw vec_vspltw + +static vector int __ATTRS_o_ai +vec_vspltw(vector int a, unsigned char b) +{ + b *= 4; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); +} + +static vector unsigned int __ATTRS_o_ai +vec_vspltw(vector unsigned int a, unsigned char b) +{ + b *= 4; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); +} + +static vector bool int __ATTRS_o_ai +vec_vspltw(vector bool int a, unsigned char b) +{ + b *= 4; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); +} + +static vector float __ATTRS_o_ai +vec_vspltw(vector float a, unsigned char b) +{ + b *= 4; + return vec_perm(a, a, (vector unsigned char) + (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); +} + +/* vec_splat_s8 */ + +#define __builtin_altivec_vspltisb vec_splat_s8 + +// FIXME: parameter should be treated as 5-bit signed literal +static vector signed char __ATTRS_o_ai +vec_splat_s8(signed char a) +{ + return (vector signed char)(a); +} + +/* vec_vspltisb */ + +// FIXME: parameter should be treated as 5-bit signed literal +static vector signed char __ATTRS_o_ai +vec_vspltisb(signed char a) +{ + return (vector signed char)(a); +} + +/* vec_splat_s16 */ + +#define __builtin_altivec_vspltish vec_splat_s16 + +// FIXME: parameter should be treated as 5-bit signed literal +static vector short __ATTRS_o_ai +vec_splat_s16(signed char a) +{ + return (vector short)(a); +} + +/* vec_vspltish */ + +// FIXME: parameter should be treated as 5-bit signed literal +static vector short __ATTRS_o_ai +vec_vspltish(signed char a) +{ + return (vector short)(a); +} + +/* vec_splat_s32 */ + +#define __builtin_altivec_vspltisw vec_splat_s32 + +// FIXME: parameter should be treated as 5-bit signed literal +static vector int __ATTRS_o_ai +vec_splat_s32(signed char a) +{ + return (vector int)(a); +} + +/* vec_vspltisw */ + +// FIXME: parameter should be treated as 5-bit signed literal +static vector int __ATTRS_o_ai +vec_vspltisw(signed char a) +{ + return (vector int)(a); +} + +/* vec_splat_u8 */ + +// FIXME: parameter should be treated as 5-bit signed literal +static vector unsigned char __ATTRS_o_ai +vec_splat_u8(unsigned char a) +{ + return (vector unsigned char)(a); +} + +/* vec_splat_u16 */ + +// FIXME: parameter should be treated as 5-bit signed literal +static vector unsigned short __ATTRS_o_ai +vec_splat_u16(signed char a) +{ + return (vector unsigned short)(a); +} + +/* vec_splat_u32 */ + +// FIXME: parameter should be treated as 5-bit signed literal +static vector unsigned int __ATTRS_o_ai +vec_splat_u32(signed char a) +{ + return (vector unsigned int)(a); +} + +/* vec_sr */ + +static vector signed char __ATTRS_o_ai +vec_sr(vector signed char a, vector unsigned char b) +{ + return a >> (vector signed char)b; +} + +static vector unsigned char __ATTRS_o_ai +vec_sr(vector unsigned char a, vector unsigned char b) +{ + return a >> b; +} + +static vector short __ATTRS_o_ai +vec_sr(vector short a, vector unsigned short b) +{ + return a >> (vector short)b; +} + +static vector unsigned short __ATTRS_o_ai +vec_sr(vector unsigned short a, vector unsigned short b) +{ + return a >> b; +} + +static vector int __ATTRS_o_ai +vec_sr(vector int a, vector unsigned int b) +{ + return a >> (vector int)b; +} -static vector short __attribute__((__always_inline__)) -vec_vmaxsh(vector short a, vector short b) +static vector unsigned int __ATTRS_o_ai +vec_sr(vector unsigned int a, vector unsigned int b) { - return __builtin_altivec_vmaxsh(a, b); + return a >> b; } -/* vec_vmaxuh */ +/* vec_vsrb */ -static vector unsigned short __attribute__((__always_inline__)) -vec_vmaxuh(vector unsigned short a, vector unsigned short b) +#define __builtin_altivec_vsrb vec_vsrb + +static vector signed char __ATTRS_o_ai +vec_vsrb(vector signed char a, vector unsigned char b) { - return __builtin_altivec_vmaxuh(a, b); + return a >> (vector signed char)b; } -/* vec_vmaxsw */ - -static vector int __attribute__((__always_inline__)) -vec_vmaxsw(vector int a, vector int b) +static vector unsigned char __ATTRS_o_ai +vec_vsrb(vector unsigned char a, vector unsigned char b) { - return __builtin_altivec_vmaxsw(a, b); + return a >> b; } -/* vec_vmaxuw */ +/* vec_vsrh */ -static vector unsigned int __attribute__((__always_inline__)) -vec_vmaxuw(vector unsigned int a, vector unsigned int b) +#define __builtin_altivec_vsrh vec_vsrh + +static vector short __ATTRS_o_ai +vec_vsrh(vector short a, vector unsigned short b) { - return __builtin_altivec_vmaxuw(a, b); + return a >> (vector short)b; } -/* vec_vmaxfp */ +static vector unsigned short __ATTRS_o_ai +vec_vsrh(vector unsigned short a, vector unsigned short b) +{ + return a >> b; +} -static vector float __attribute__((__always_inline__)) -vec_vmaxfp(vector float a, vector float b) +/* vec_vsrw */ + +#define __builtin_altivec_vsrw vec_vsrw + +static vector int __ATTRS_o_ai +vec_vsrw(vector int a, vector unsigned int b) { - return __builtin_altivec_vmaxfp(a, b); + return a >> (vector int)b; } -/* vec_mergeh */ +static vector unsigned int __ATTRS_o_ai +vec_vsrw(vector unsigned int a, vector unsigned int b) +{ + return a >> b; +} + +/* vec_sra */ static vector signed char __ATTRS_o_ai -vec_mergeh(vector signed char a, vector signed char b) +vec_sra(vector signed char a, vector unsigned char b) { - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, - 0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17)); + return (vector signed char)__builtin_altivec_vsrab((vector char)a, b); } static vector unsigned char __ATTRS_o_ai -vec_mergeh(vector unsigned char a, vector unsigned char b) +vec_sra(vector unsigned char a, vector unsigned char b) { - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, - 0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17)); + return (vector unsigned char)__builtin_altivec_vsrab((vector char)a, b); } static vector short __ATTRS_o_ai -vec_mergeh(vector short a, vector short b) +vec_sra(vector short a, vector unsigned short b) { - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13, - 0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17)); + return __builtin_altivec_vsrah(a, (vector unsigned short)b); } static vector unsigned short __ATTRS_o_ai -vec_mergeh(vector unsigned short a, vector unsigned short b) +vec_sra(vector unsigned short a, vector unsigned short b) { - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13, - 0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17)); + return (vector unsigned short)__builtin_altivec_vsrah((vector short)a, b); } static vector int __ATTRS_o_ai -vec_mergeh(vector int a, vector int b) +vec_sra(vector int a, vector unsigned int b) { - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, - 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); + return __builtin_altivec_vsraw(a, b); } static vector unsigned int __ATTRS_o_ai -vec_mergeh(vector unsigned int a, vector unsigned int b) -{ - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, - 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); -} - -static vector float __ATTRS_o_ai -vec_mergeh(vector float a, vector float b) +vec_sra(vector unsigned int a, vector unsigned int b) { - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, - 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); + return (vector unsigned int)__builtin_altivec_vsraw((vector int)a, b); } -/* vec_vmrghb */ - -#define __builtin_altivec_vmrghb vec_vmrghb +/* vec_vsrab */ static vector signed char __ATTRS_o_ai -vec_vmrghb(vector signed char a, vector signed char b) +vec_vsrab(vector signed char a, vector unsigned char b) { - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, - 0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17)); + return (vector signed char)__builtin_altivec_vsrab((vector char)a, b); } static vector unsigned char __ATTRS_o_ai -vec_vmrghb(vector unsigned char a, vector unsigned char b) +vec_vsrab(vector unsigned char a, vector unsigned char b) { - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x10, 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, - 0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17)); + return (vector unsigned char)__builtin_altivec_vsrab((vector char)a, b); } -/* vec_vmrghh */ - -#define __builtin_altivec_vmrghh vec_vmrghh +/* vec_vsrah */ static vector short __ATTRS_o_ai -vec_vmrghh(vector short a, vector short b) +vec_vsrah(vector short a, vector unsigned short b) { - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13, - 0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17)); + return __builtin_altivec_vsrah(a, (vector unsigned short)b); } static vector unsigned short __ATTRS_o_ai -vec_vmrghh(vector unsigned short a, vector unsigned short b) +vec_vsrah(vector unsigned short a, vector unsigned short b) { - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x01, 0x10, 0x11, 0x02, 0x03, 0x12, 0x13, - 0x04, 0x05, 0x14, 0x15, 0x06, 0x07, 0x16, 0x17)); + return (vector unsigned short)__builtin_altivec_vsrah((vector short)a, b); } -/* vec_vmrghw */ - -#define __builtin_altivec_vmrghw vec_vmrghw +/* vec_vsraw */ static vector int __ATTRS_o_ai -vec_vmrghw(vector int a, vector int b) +vec_vsraw(vector int a, vector unsigned int b) { - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, - 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); + return __builtin_altivec_vsraw(a, b); } static vector unsigned int __ATTRS_o_ai -vec_vmrghw(vector unsigned int a, vector unsigned int b) +vec_vsraw(vector unsigned int a, vector unsigned int b) { - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, - 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); + return (vector unsigned int)__builtin_altivec_vsraw((vector int)a, b); } -static vector float __ATTRS_o_ai -vec_vmrghw(vector float a, vector float b) +/* vec_srl */ + +static vector signed char __ATTRS_o_ai +vec_srl(vector signed char a, vector unsigned char b) { - return vec_perm(a, b, (vector unsigned char) - (0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, - 0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17)); + return (vector signed char)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_mergel */ +static vector signed char __ATTRS_o_ai +vec_srl(vector signed char a, vector unsigned short b) +{ + return (vector signed char)__builtin_altivec_vsr((vector int)a, (vector int)b); +} static vector signed char __ATTRS_o_ai -vec_mergel(vector signed char a, vector signed char b) +vec_srl(vector signed char a, vector unsigned int b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B, - 0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F)); + return (vector signed char)__builtin_altivec_vsr((vector int)a, (vector int)b); } static vector unsigned char __ATTRS_o_ai -vec_mergel(vector unsigned char a, vector unsigned char b) +vec_srl(vector unsigned char a, vector unsigned char b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B, - 0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F)); + return (vector unsigned char)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector short __ATTRS_o_ai -vec_mergel(vector short a, vector short b) +static vector unsigned char __ATTRS_o_ai +vec_srl(vector unsigned char a, vector unsigned short b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B, - 0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F)); + return (vector unsigned char)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector unsigned short __ATTRS_o_ai -vec_mergel(vector unsigned short a, vector unsigned short b) +static vector unsigned char __ATTRS_o_ai +vec_srl(vector unsigned char a, vector unsigned int b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B, - 0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F)); + return (vector unsigned char)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector int __ATTRS_o_ai -vec_mergel(vector int a, vector int b) +static vector bool char __ATTRS_o_ai +vec_srl(vector bool char a, vector unsigned char b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); + return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector unsigned int __ATTRS_o_ai -vec_mergel(vector unsigned int a, vector unsigned int b) +static vector bool char __ATTRS_o_ai +vec_srl(vector bool char a, vector unsigned short b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); + return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector float __ATTRS_o_ai -vec_mergel(vector float a, vector float b) +static vector bool char __ATTRS_o_ai +vec_srl(vector bool char a, vector unsigned int b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); + return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vmrglb */ - -#define __builtin_altivec_vmrglb vec_vmrglb - -static vector signed char __ATTRS_o_ai -vec_vmrglb(vector signed char a, vector signed char b) +static vector short __ATTRS_o_ai +vec_srl(vector short a, vector unsigned char b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B, - 0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F)); + return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector unsigned char __ATTRS_o_ai -vec_vmrglb(vector unsigned char a, vector unsigned char b) +static vector short __ATTRS_o_ai +vec_srl(vector short a, vector unsigned short b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x18, 0x09, 0x19, 0x0A, 0x1A, 0x0B, 0x1B, - 0x0C, 0x1C, 0x0D, 0x1D, 0x0E, 0x1E, 0x0F, 0x1F)); + return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vmrglh */ - -#define __builtin_altivec_vmrglh vec_vmrglh - static vector short __ATTRS_o_ai -vec_vmrglh(vector short a, vector short b) +vec_srl(vector short a, vector unsigned int b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B, - 0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F)); + return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b); } static vector unsigned short __ATTRS_o_ai -vec_vmrglh(vector unsigned short a, vector unsigned short b) +vec_srl(vector unsigned short a, vector unsigned char b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x09, 0x18, 0x19, 0x0A, 0x0B, 0x1A, 0x1B, - 0x0C, 0x0D, 0x1C, 0x1D, 0x0E, 0x0F, 0x1E, 0x1F)); -} - -/* vec_vmrglw */ - -#define __builtin_altivec_vmrglw vec_vmrglw + return (vector unsigned short)__builtin_altivec_vsr((vector int)a, (vector int)b); +} -static vector int __ATTRS_o_ai -vec_vmrglw(vector int a, vector int b) +static vector unsigned short __ATTRS_o_ai +vec_srl(vector unsigned short a, vector unsigned short b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); + return (vector unsigned short)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector unsigned int __ATTRS_o_ai -vec_vmrglw(vector unsigned int a, vector unsigned int b) +static vector unsigned short __ATTRS_o_ai +vec_srl(vector unsigned short a, vector unsigned int b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); + return (vector unsigned short)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector float __ATTRS_o_ai -vec_vmrglw(vector float a, vector float b) +static vector bool short __ATTRS_o_ai +vec_srl(vector bool short a, vector unsigned char b) { - return vec_perm(a, b, (vector unsigned char) - (0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19, 0x1A, 0x1B, - 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D, 0x1E, 0x1F)); + return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_mfvscr */ +static vector bool short __ATTRS_o_ai +vec_srl(vector bool short a, vector unsigned short b) +{ + return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b); +} -static vector unsigned short __attribute__((__always_inline__)) -vec_mfvscr(void) +static vector bool short __ATTRS_o_ai +vec_srl(vector bool short a, vector unsigned int b) { - return __builtin_altivec_mfvscr(); + return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_min */ +static vector pixel __ATTRS_o_ai +vec_srl(vector pixel a, vector unsigned char b) +{ + return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b); +} -static vector signed char __ATTRS_o_ai -vec_min(vector signed char a, vector signed char b) +static vector pixel __ATTRS_o_ai +vec_srl(vector pixel a, vector unsigned short b) { - return __builtin_altivec_vminsb(a, b); + return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector unsigned char __ATTRS_o_ai -vec_min(vector unsigned char a, vector unsigned char b) +static vector pixel __ATTRS_o_ai +vec_srl(vector pixel a, vector unsigned int b) { - return __builtin_altivec_vminub(a, b); + return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector short __ATTRS_o_ai -vec_min(vector short a, vector short b) +static vector int __ATTRS_o_ai +vec_srl(vector int a, vector unsigned char b) { - return __builtin_altivec_vminsh(a, b); + return (vector int)__builtin_altivec_vsr(a, (vector int)b); } -static vector unsigned short __ATTRS_o_ai -vec_min(vector unsigned short a, vector unsigned short b) +static vector int __ATTRS_o_ai +vec_srl(vector int a, vector unsigned short b) { - return __builtin_altivec_vminuh(a, b); + return (vector int)__builtin_altivec_vsr(a, (vector int)b); } static vector int __ATTRS_o_ai -vec_min(vector int a, vector int b) +vec_srl(vector int a, vector unsigned int b) { - return __builtin_altivec_vminsw(a, b); + return (vector int)__builtin_altivec_vsr(a, (vector int)b); } static vector unsigned int __ATTRS_o_ai -vec_min(vector unsigned int a, vector unsigned int b) +vec_srl(vector unsigned int a, vector unsigned char b) { - return __builtin_altivec_vminuw(a, b); + return (vector unsigned int)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector float __ATTRS_o_ai -vec_min(vector float a, vector float b) +static vector unsigned int __ATTRS_o_ai +vec_srl(vector unsigned int a, vector unsigned short b) { - return __builtin_altivec_vminfp(a, b); + return (vector unsigned int)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vminsb */ - -static vector signed char __attribute__((__always_inline__)) -vec_vminsb(vector signed char a, vector signed char b) +static vector unsigned int __ATTRS_o_ai +vec_srl(vector unsigned int a, vector unsigned int b) { - return __builtin_altivec_vminsb(a, b); + return (vector unsigned int)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vminub */ - -static vector unsigned char __attribute__((__always_inline__)) -vec_vminub(vector unsigned char a, vector unsigned char b) +static vector bool int __ATTRS_o_ai +vec_srl(vector bool int a, vector unsigned char b) { - return __builtin_altivec_vminub(a, b); + return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vminsh */ +static vector bool int __ATTRS_o_ai +vec_srl(vector bool int a, vector unsigned short b) +{ + return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b); +} -static vector short __attribute__((__always_inline__)) -vec_vminsh(vector short a, vector short b) +static vector bool int __ATTRS_o_ai +vec_srl(vector bool int a, vector unsigned int b) { - return __builtin_altivec_vminsh(a, b); + return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vminuh */ +/* vec_vsr */ -static vector unsigned short __attribute__((__always_inline__)) -vec_vminuh(vector unsigned short a, vector unsigned short b) +static vector signed char __ATTRS_o_ai +vec_vsr(vector signed char a, vector unsigned char b) { - return __builtin_altivec_vminuh(a, b); + return (vector signed char)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vminsw */ +static vector signed char __ATTRS_o_ai +vec_vsr(vector signed char a, vector unsigned short b) +{ + return (vector signed char)__builtin_altivec_vsr((vector int)a, (vector int)b); +} -static vector int __attribute__((__always_inline__)) -vec_vminsw(vector int a, vector int b) +static vector signed char __ATTRS_o_ai +vec_vsr(vector signed char a, vector unsigned int b) { - return __builtin_altivec_vminsw(a, b); + return (vector signed char)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vminuw */ +static vector unsigned char __ATTRS_o_ai +vec_vsr(vector unsigned char a, vector unsigned char b) +{ + return (vector unsigned char)__builtin_altivec_vsr((vector int)a, (vector int)b); +} -static vector unsigned int __attribute__((__always_inline__)) -vec_vminuw(vector unsigned int a, vector unsigned int b) +static vector unsigned char __ATTRS_o_ai +vec_vsr(vector unsigned char a, vector unsigned short b) { - return __builtin_altivec_vminuw(a, b); + return (vector unsigned char)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vminfp */ +static vector unsigned char __ATTRS_o_ai +vec_vsr(vector unsigned char a, vector unsigned int b) +{ + return (vector unsigned char)__builtin_altivec_vsr((vector int)a, (vector int)b); +} -static vector float __attribute__((__always_inline__)) -vec_vminfp(vector float a, vector float b) +static vector bool char __ATTRS_o_ai +vec_vsr(vector bool char a, vector unsigned char b) { - return __builtin_altivec_vminfp(a, b); + return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_mladd */ +static vector bool char __ATTRS_o_ai +vec_vsr(vector bool char a, vector unsigned short b) +{ + return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b); +} -#define __builtin_altivec_vmladduhm vec_mladd +static vector bool char __ATTRS_o_ai +vec_vsr(vector bool char a, vector unsigned int b) +{ + return (vector bool char)__builtin_altivec_vsr((vector int)a, (vector int)b); +} static vector short __ATTRS_o_ai -vec_mladd(vector short a, vector short b, vector short c) +vec_vsr(vector short a, vector unsigned char b) { - return a * b + c; + return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b); } static vector short __ATTRS_o_ai -vec_mladd(vector short a, vector unsigned short b, vector unsigned short c) +vec_vsr(vector short a, vector unsigned short b) { - return a * (vector short)b + (vector short)c; + return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b); } static vector short __ATTRS_o_ai -vec_mladd(vector unsigned short a, vector short b, vector short c) +vec_vsr(vector short a, vector unsigned int b) { - return (vector short)a * b + c; + return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b); } static vector unsigned short __ATTRS_o_ai -vec_mladd(vector unsigned short a, vector unsigned short b, vector unsigned short c) +vec_vsr(vector unsigned short a, vector unsigned char b) { - return a * b + c; + return (vector unsigned short)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vmladduhm */ +static vector unsigned short __ATTRS_o_ai +vec_vsr(vector unsigned short a, vector unsigned short b) +{ + return (vector unsigned short)__builtin_altivec_vsr((vector int)a, (vector int)b); +} -static vector short __ATTRS_o_ai -vec_vmladduhm(vector short a, vector short b, vector short c) +static vector unsigned short __ATTRS_o_ai +vec_vsr(vector unsigned short a, vector unsigned int b) { - return a * b + c; + return (vector unsigned short)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector short __ATTRS_o_ai -vec_vmladduhm(vector short a, vector unsigned short b, vector unsigned short c) +static vector bool short __ATTRS_o_ai +vec_vsr(vector bool short a, vector unsigned char b) { - return a * (vector short)b + (vector short)c; + return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector short __ATTRS_o_ai -vec_vmladduhm(vector unsigned short a, vector short b, vector short c) +static vector bool short __ATTRS_o_ai +vec_vsr(vector bool short a, vector unsigned short b) { - return (vector short)a * b + c; + return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector unsigned short __ATTRS_o_ai -vec_vmladduhm(vector unsigned short a, vector unsigned short b, vector unsigned short c) +static vector bool short __ATTRS_o_ai +vec_vsr(vector bool short a, vector unsigned int b) { - return a * b + c; + return (vector bool short)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_mradds */ +static vector pixel __ATTRS_o_ai +vec_vsr(vector pixel a, vector unsigned char b) +{ + return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b); +} -static vector short __attribute__((__always_inline__)) -vec_mradds(vector short a, vector short b, vector short c) +static vector pixel __ATTRS_o_ai +vec_vsr(vector pixel a, vector unsigned short b) { - return __builtin_altivec_vmhraddshs(a, b, c); + return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vmhraddshs */ +static vector pixel __ATTRS_o_ai +vec_vsr(vector pixel a, vector unsigned int b) +{ + return (vector pixel)__builtin_altivec_vsr((vector int)a, (vector int)b); +} -static vector short __attribute__((__always_inline__)) -vec_vmhraddshs(vector short a, vector short b, vector short c) +static vector int __ATTRS_o_ai +vec_vsr(vector int a, vector unsigned char b) { - return __builtin_altivec_vmhraddshs(a, b, c); + return (vector int)__builtin_altivec_vsr(a, (vector int)b); } -/* vec_msum */ +static vector int __ATTRS_o_ai +vec_vsr(vector int a, vector unsigned short b) +{ + return (vector int)__builtin_altivec_vsr(a, (vector int)b); +} static vector int __ATTRS_o_ai -vec_msum(vector signed char a, vector unsigned char b, vector int c) +vec_vsr(vector int a, vector unsigned int b) { - return __builtin_altivec_vmsummbm(a, b, c); + return (vector int)__builtin_altivec_vsr(a, (vector int)b); } static vector unsigned int __ATTRS_o_ai -vec_msum(vector unsigned char a, vector unsigned char b, vector unsigned int c) +vec_vsr(vector unsigned int a, vector unsigned char b) { - return __builtin_altivec_vmsumubm(a, b, c); + return (vector unsigned int)__builtin_altivec_vsr((vector int)a, (vector int)b); } -static vector int __ATTRS_o_ai -vec_msum(vector short a, vector short b, vector int c) +static vector unsigned int __ATTRS_o_ai +vec_vsr(vector unsigned int a, vector unsigned short b) { - return __builtin_altivec_vmsumshm(a, b, c); + return (vector unsigned int)__builtin_altivec_vsr((vector int)a, (vector int)b); } static vector unsigned int __ATTRS_o_ai -vec_msum(vector unsigned short a, vector unsigned short b, vector unsigned int c) +vec_vsr(vector unsigned int a, vector unsigned int b) { - return __builtin_altivec_vmsumuhm(a, b, c); + return (vector unsigned int)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vmsummbm */ - -static vector int __attribute__((__always_inline__)) -vec_vmsummbm(vector signed char a, vector unsigned char b, vector int c) +static vector bool int __ATTRS_o_ai +vec_vsr(vector bool int a, vector unsigned char b) { - return __builtin_altivec_vmsummbm(a, b, c); + return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vmsumubm */ +static vector bool int __ATTRS_o_ai +vec_vsr(vector bool int a, vector unsigned short b) +{ + return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b); +} -static vector unsigned int __attribute__((__always_inline__)) -vec_vmsumubm(vector unsigned char a, vector unsigned char b, vector unsigned int c) +static vector bool int __ATTRS_o_ai +vec_vsr(vector bool int a, vector unsigned int b) { - return __builtin_altivec_vmsumubm(a, b, c); + return (vector bool int)__builtin_altivec_vsr((vector int)a, (vector int)b); } -/* vec_vmsumshm */ +/* vec_sro */ -static vector int __attribute__((__always_inline__)) -vec_vmsumshm(vector short a, vector short b, vector int c) +static vector signed char __ATTRS_o_ai +vec_sro(vector signed char a, vector signed char b) { - return __builtin_altivec_vmsumshm(a, b, c); + return (vector signed char)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_vmsumuhm */ +static vector signed char __ATTRS_o_ai +vec_sro(vector signed char a, vector unsigned char b) +{ + return (vector signed char)__builtin_altivec_vsro((vector int)a, (vector int)b); +} -static vector unsigned int __attribute__((__always_inline__)) -vec_vmsumuhm(vector unsigned short a, vector unsigned short b, vector unsigned int c) +static vector unsigned char __ATTRS_o_ai +vec_sro(vector unsigned char a, vector signed char b) { - return __builtin_altivec_vmsumuhm(a, b, c); + return (vector unsigned char)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_msums */ +static vector unsigned char __ATTRS_o_ai +vec_sro(vector unsigned char a, vector unsigned char b) +{ + return (vector unsigned char)__builtin_altivec_vsro((vector int)a, (vector int)b); +} -static vector int __ATTRS_o_ai -vec_msums(vector short a, vector short b, vector int c) +static vector short __ATTRS_o_ai +vec_sro(vector short a, vector signed char b) { - return __builtin_altivec_vmsumshs(a, b, c); + return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b); } -static vector unsigned int __ATTRS_o_ai -vec_msums(vector unsigned short a, vector unsigned short b, vector unsigned int c) +static vector short __ATTRS_o_ai +vec_sro(vector short a, vector unsigned char b) { - return __builtin_altivec_vmsumuhs(a, b, c); + return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b); +} + +static vector unsigned short __ATTRS_o_ai +vec_sro(vector unsigned short a, vector signed char b) +{ + return (vector unsigned short)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_vmsumshs */ - -static vector int __attribute__((__always_inline__)) -vec_vmsumshs(vector short a, vector short b, vector int c) +static vector unsigned short __ATTRS_o_ai +vec_sro(vector unsigned short a, vector unsigned char b) { - return __builtin_altivec_vmsumshs(a, b, c); + return (vector unsigned short)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_vmsumuhs */ - -static vector unsigned int __attribute__((__always_inline__)) -vec_vmsumuhs(vector unsigned short a, vector unsigned short b, vector unsigned int c) +static vector pixel __ATTRS_o_ai +vec_sro(vector pixel a, vector signed char b) { - return __builtin_altivec_vmsumuhs(a, b, c); + return (vector pixel)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_mtvscr */ - -static void __ATTRS_o_ai -vec_mtvscr(vector signed char a) +static vector pixel __ATTRS_o_ai +vec_sro(vector pixel a, vector unsigned char b) { - __builtin_altivec_mtvscr((vector int)a); + return (vector pixel)__builtin_altivec_vsro((vector int)a, (vector int)b); } -static void __ATTRS_o_ai -vec_mtvscr(vector unsigned char a) +static vector int __ATTRS_o_ai +vec_sro(vector int a, vector signed char b) { - __builtin_altivec_mtvscr((vector int)a); + return (vector int)__builtin_altivec_vsro(a, (vector int)b); } -static void __ATTRS_o_ai -vec_mtvscr(vector short a) +static vector int __ATTRS_o_ai +vec_sro(vector int a, vector unsigned char b) { - __builtin_altivec_mtvscr((vector int)a); + return (vector int)__builtin_altivec_vsro(a, (vector int)b); } -static void __ATTRS_o_ai -vec_mtvscr(vector unsigned short a) +static vector unsigned int __ATTRS_o_ai +vec_sro(vector unsigned int a, vector signed char b) { - __builtin_altivec_mtvscr((vector int)a); + return (vector unsigned int)__builtin_altivec_vsro((vector int)a, (vector int)b); } -static void __ATTRS_o_ai -vec_mtvscr(vector int a) +static vector unsigned int __ATTRS_o_ai +vec_sro(vector unsigned int a, vector unsigned char b) { - __builtin_altivec_mtvscr((vector int)a); + return (vector unsigned int)__builtin_altivec_vsro((vector int)a, (vector int)b); } -static void __ATTRS_o_ai -vec_mtvscr(vector unsigned int a) +static vector float __ATTRS_o_ai +vec_sro(vector float a, vector signed char b) { - __builtin_altivec_mtvscr((vector int)a); + return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b); } -static void __ATTRS_o_ai -vec_mtvscr(vector float a) +static vector float __ATTRS_o_ai +vec_sro(vector float a, vector unsigned char b) { - __builtin_altivec_mtvscr((vector int)a); + return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_mule */ +/* vec_vsro */ -static vector short __ATTRS_o_ai -vec_mule(vector signed char a, vector signed char b) +static vector signed char __ATTRS_o_ai +vec_vsro(vector signed char a, vector signed char b) { - return __builtin_altivec_vmulesb(a, b); + return (vector signed char)__builtin_altivec_vsro((vector int)a, (vector int)b); } -static vector unsigned short __ATTRS_o_ai -vec_mule(vector unsigned char a, vector unsigned char b) +static vector signed char __ATTRS_o_ai +vec_vsro(vector signed char a, vector unsigned char b) { - return __builtin_altivec_vmuleub(a, b); + return (vector signed char)__builtin_altivec_vsro((vector int)a, (vector int)b); } -static vector int __ATTRS_o_ai -vec_mule(vector short a, vector short b) +static vector unsigned char __ATTRS_o_ai +vec_vsro(vector unsigned char a, vector signed char b) { - return __builtin_altivec_vmulesh(a, b); + return (vector unsigned char)__builtin_altivec_vsro((vector int)a, (vector int)b); } -static vector unsigned int __ATTRS_o_ai -vec_mule(vector unsigned short a, vector unsigned short b) +static vector unsigned char __ATTRS_o_ai +vec_vsro(vector unsigned char a, vector unsigned char b) { - return __builtin_altivec_vmuleuh(a, b); + return (vector unsigned char)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_vmulesb */ - -static vector short __attribute__((__always_inline__)) -vec_vmulesb(vector signed char a, vector signed char b) +static vector short __ATTRS_o_ai +vec_vsro(vector short a, vector signed char b) { - return __builtin_altivec_vmulesb(a, b); + return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_vmuleub */ - -static vector unsigned short __attribute__((__always_inline__)) -vec_vmuleub(vector unsigned char a, vector unsigned char b) +static vector short __ATTRS_o_ai +vec_vsro(vector short a, vector unsigned char b) { - return __builtin_altivec_vmuleub(a, b); + return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_vmulesh */ - -static vector int __attribute__((__always_inline__)) -vec_vmulesh(vector short a, vector short b) +static vector unsigned short __ATTRS_o_ai +vec_vsro(vector unsigned short a, vector signed char b) { - return __builtin_altivec_vmulesh(a, b); + return (vector unsigned short)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_vmuleuh */ - -static vector unsigned int __attribute__((__always_inline__)) -vec_vmuleuh(vector unsigned short a, vector unsigned short b) +static vector unsigned short __ATTRS_o_ai +vec_vsro(vector unsigned short a, vector unsigned char b) { - return __builtin_altivec_vmuleuh(a, b); + return (vector unsigned short)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_mulo */ +static vector pixel __ATTRS_o_ai +vec_vsro(vector pixel a, vector signed char b) +{ + return (vector pixel)__builtin_altivec_vsro((vector int)a, (vector int)b); +} -static vector short __ATTRS_o_ai -vec_mulo(vector signed char a, vector signed char b) +static vector pixel __ATTRS_o_ai +vec_vsro(vector pixel a, vector unsigned char b) { - return __builtin_altivec_vmulosb(a, b); + return (vector pixel)__builtin_altivec_vsro((vector int)a, (vector int)b); } -static vector unsigned short __ATTRS_o_ai -vec_mulo(vector unsigned char a, vector unsigned char b) +static vector int __ATTRS_o_ai +vec_vsro(vector int a, vector signed char b) { - return __builtin_altivec_vmuloub(a, b); + return (vector int)__builtin_altivec_vsro(a, (vector int)b); } static vector int __ATTRS_o_ai -vec_mulo(vector short a, vector short b) +vec_vsro(vector int a, vector unsigned char b) { - return __builtin_altivec_vmulosh(a, b); + return (vector int)__builtin_altivec_vsro(a, (vector int)b); } static vector unsigned int __ATTRS_o_ai -vec_mulo(vector unsigned short a, vector unsigned short b) +vec_vsro(vector unsigned int a, vector signed char b) { - return __builtin_altivec_vmulouh(a, b); + return (vector unsigned int)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_vmulosb */ - -static vector short __attribute__((__always_inline__)) -vec_vmulosb(vector signed char a, vector signed char b) +static vector unsigned int __ATTRS_o_ai +vec_vsro(vector unsigned int a, vector unsigned char b) { - return __builtin_altivec_vmulosb(a, b); + return (vector unsigned int)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_vmuloub */ - -static vector unsigned short __attribute__((__always_inline__)) -vec_vmuloub(vector unsigned char a, vector unsigned char b) +static vector float __ATTRS_o_ai +vec_vsro(vector float a, vector signed char b) { - return __builtin_altivec_vmuloub(a, b); + return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_vmulosh */ - -static vector int __attribute__((__always_inline__)) -vec_vmulosh(vector short a, vector short b) +static vector float __ATTRS_o_ai +vec_vsro(vector float a, vector unsigned char b) { - return __builtin_altivec_vmulosh(a, b); + return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b); } -/* vec_vmulouh */ +/* vec_st */ -static vector unsigned int __attribute__((__always_inline__)) -vec_vmulouh(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_st(vector signed char a, int b, vector signed char *c) { - return __builtin_altivec_vmulouh(a, b); + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_nmsub */ - -static vector float __attribute__((__always_inline__)) -vec_nmsub(vector float a, vector float b, vector float c) +static void __ATTRS_o_ai +vec_st(vector signed char a, int b, signed char *c) { - return __builtin_altivec_vnmsubfp(a, b, c); + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_vnmsubfp */ - -static vector float __attribute__((__always_inline__)) -vec_vnmsubfp(vector float a, vector float b, vector float c) +static void __ATTRS_o_ai +vec_st(vector unsigned char a, int b, vector unsigned char *c) { - return __builtin_altivec_vnmsubfp(a, b, c); + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_nor */ - -#define __builtin_altivec_vnor vec_nor +static void __ATTRS_o_ai +vec_st(vector unsigned char a, int b, unsigned char *c) +{ + __builtin_altivec_stvx((vector int)a, b, c); +} -static vector signed char __ATTRS_o_ai -vec_nor(vector signed char a, vector signed char b) +static void __ATTRS_o_ai +vec_st(vector bool char a, int b, signed char *c) { - return ~(a | b); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_nor(vector unsigned char a, vector unsigned char b) +static void __ATTRS_o_ai +vec_st(vector bool char a, int b, unsigned char *c) { - return ~(a | b); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector short __ATTRS_o_ai -vec_nor(vector short a, vector short b) +static void __ATTRS_o_ai +vec_st(vector bool char a, int b, vector bool char *c) { - return ~(a | b); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_nor(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_st(vector short a, int b, vector short *c) { - return ~(a | b); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector int __ATTRS_o_ai -vec_nor(vector int a, vector int b) +static void __ATTRS_o_ai +vec_st(vector short a, int b, short *c) { - return ~(a | b); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned int __ATTRS_o_ai -vec_nor(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_st(vector unsigned short a, int b, vector unsigned short *c) { - return ~(a | b); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector float __ATTRS_o_ai -vec_nor(vector float a, vector float b) +static void __ATTRS_o_ai +vec_st(vector unsigned short a, int b, unsigned short *c) { - vector unsigned int res = ~((vector unsigned int)a | (vector unsigned int)b); - return (vector float)res; + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_vnor */ +static void __ATTRS_o_ai +vec_st(vector bool short a, int b, short *c) +{ + __builtin_altivec_stvx((vector int)a, b, c); +} -static vector signed char __ATTRS_o_ai -vec_vnor(vector signed char a, vector signed char b) +static void __ATTRS_o_ai +vec_st(vector bool short a, int b, unsigned short *c) { - return ~(a | b); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_vnor(vector unsigned char a, vector unsigned char b) +static void __ATTRS_o_ai +vec_st(vector bool short a, int b, vector bool short *c) { - return ~(a | b); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector short __ATTRS_o_ai -vec_vnor(vector short a, vector short b) +static void __ATTRS_o_ai +vec_st(vector pixel a, int b, short *c) { - return ~(a | b); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_vnor(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_st(vector pixel a, int b, unsigned short *c) { - return ~(a | b); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector int __ATTRS_o_ai -vec_vnor(vector int a, vector int b) +static void __ATTRS_o_ai +vec_st(vector pixel a, int b, vector pixel *c) { - return ~(a | b); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned int __ATTRS_o_ai -vec_vnor(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_st(vector int a, int b, vector int *c) { - return ~(a | b); + __builtin_altivec_stvx(a, b, c); } -static vector float __ATTRS_o_ai -vec_vnor(vector float a, vector float b) +static void __ATTRS_o_ai +vec_st(vector int a, int b, int *c) { - vector unsigned int res = ~((vector unsigned int)a | (vector unsigned int)b); - return (vector float)res; + __builtin_altivec_stvx(a, b, c); } -/* vec_or */ - -#define __builtin_altivec_vor vec_or - -static vector signed char __ATTRS_o_ai -vec_or(vector signed char a, vector signed char b) +static void __ATTRS_o_ai +vec_st(vector unsigned int a, int b, vector unsigned int *c) { - return a | b; + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_or(vector unsigned char a, vector unsigned char b) +static void __ATTRS_o_ai +vec_st(vector unsigned int a, int b, unsigned int *c) { - return a | b; + __builtin_altivec_stvx((vector int)a, b, c); } -static vector short __ATTRS_o_ai -vec_or(vector short a, vector short b) +static void __ATTRS_o_ai +vec_st(vector bool int a, int b, int *c) { - return a | b; + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_or(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_st(vector bool int a, int b, unsigned int *c) { - return a | b; + __builtin_altivec_stvx((vector int)a, b, c); } -static vector int __ATTRS_o_ai -vec_or(vector int a, vector int b) +static void __ATTRS_o_ai +vec_st(vector bool int a, int b, vector bool int *c) { - return a | b; + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned int __ATTRS_o_ai -vec_or(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_st(vector float a, int b, vector float *c) { - return a | b; + __builtin_altivec_stvx((vector int)a, b, c); } -static vector float __ATTRS_o_ai -vec_or(vector float a, vector float b) +static void __ATTRS_o_ai +vec_st(vector float a, int b, float *c) { - vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b; - return (vector float)res; + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_vor */ +/* vec_stvx */ -static vector signed char __ATTRS_o_ai -vec_vor(vector signed char a, vector signed char b) +static void __ATTRS_o_ai +vec_stvx(vector signed char a, int b, vector signed char *c) { - return a | b; + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_vor(vector unsigned char a, vector unsigned char b) +static void __ATTRS_o_ai +vec_stvx(vector signed char a, int b, signed char *c) { - return a | b; + __builtin_altivec_stvx((vector int)a, b, c); } -static vector short __ATTRS_o_ai -vec_vor(vector short a, vector short b) +static void __ATTRS_o_ai +vec_stvx(vector unsigned char a, int b, vector unsigned char *c) { - return a | b; + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_vor(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_stvx(vector unsigned char a, int b, unsigned char *c) { - return a | b; + __builtin_altivec_stvx((vector int)a, b, c); } -static vector int __ATTRS_o_ai -vec_vor(vector int a, vector int b) +static void __ATTRS_o_ai +vec_stvx(vector bool char a, int b, signed char *c) { - return a | b; + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned int __ATTRS_o_ai -vec_vor(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stvx(vector bool char a, int b, unsigned char *c) { - return a | b; + __builtin_altivec_stvx((vector int)a, b, c); } -static vector float __ATTRS_o_ai -vec_vor(vector float a, vector float b) +static void __ATTRS_o_ai +vec_stvx(vector bool char a, int b, vector bool char *c) { - vector unsigned int res = (vector unsigned int)a | (vector unsigned int)b; - return (vector float)res; + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_pack */ - -static vector signed char __ATTRS_o_ai -vec_pack(vector signed short a, vector signed short b) +static void __ATTRS_o_ai +vec_stvx(vector short a, int b, vector short *c) { - return (vector signed char)vec_perm(a, b, (vector unsigned char) - (0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, - 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F)); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_pack(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_stvx(vector short a, int b, short *c) { - return (vector unsigned char)vec_perm(a, b, (vector unsigned char) - (0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, - 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F)); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector short __ATTRS_o_ai -vec_pack(vector int a, vector int b) +static void __ATTRS_o_ai +vec_stvx(vector unsigned short a, int b, vector unsigned short *c) { - return (vector short)vec_perm(a, b, (vector unsigned char) - (0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F, - 0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F)); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_pack(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stvx(vector unsigned short a, int b, unsigned short *c) { - return (vector unsigned short)vec_perm(a, b, (vector unsigned char) - (0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F, - 0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F)); + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_vpkuhum */ - -#define __builtin_altivec_vpkuhum vec_vpkuhum - -static vector signed char __ATTRS_o_ai -vec_vpkuhum(vector signed short a, vector signed short b) +static void __ATTRS_o_ai +vec_stvx(vector bool short a, int b, short *c) { - return (vector signed char)vec_perm(a, b, (vector unsigned char) - (0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, - 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F)); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_vpkuhum(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_stvx(vector bool short a, int b, unsigned short *c) { - return (vector unsigned char)vec_perm(a, b, (vector unsigned char) - (0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, - 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F)); + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_vpkuwum */ - -#define __builtin_altivec_vpkuwum vec_vpkuwum - -static vector short __ATTRS_o_ai -vec_vpkuwum(vector int a, vector int b) +static void __ATTRS_o_ai +vec_stvx(vector bool short a, int b, vector bool short *c) { - return (vector short)vec_perm(a, b, (vector unsigned char) - (0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F, - 0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F)); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_vpkuwum(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stvx(vector pixel a, int b, short *c) { - return (vector unsigned short)vec_perm(a, b, (vector unsigned char) - (0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F, - 0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F)); + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_packpx */ - -static vector pixel __attribute__((__always_inline__)) -vec_packpx(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stvx(vector pixel a, int b, unsigned short *c) { - return (vector pixel)__builtin_altivec_vpkpx(a, b); + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_vpkpx */ - -static vector pixel __attribute__((__always_inline__)) -vec_vpkpx(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stvx(vector pixel a, int b, vector pixel *c) { - return (vector pixel)__builtin_altivec_vpkpx(a, b); + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_packs */ - -static vector signed char __ATTRS_o_ai -vec_packs(vector short a, vector short b) +static void __ATTRS_o_ai +vec_stvx(vector int a, int b, vector int *c) { - return __builtin_altivec_vpkshss(a, b); + __builtin_altivec_stvx(a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_packs(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_stvx(vector int a, int b, int *c) { - return __builtin_altivec_vpkuhus(a, b); + __builtin_altivec_stvx(a, b, c); } -static vector signed short __ATTRS_o_ai -vec_packs(vector int a, vector int b) +static void __ATTRS_o_ai +vec_stvx(vector unsigned int a, int b, vector unsigned int *c) { - return __builtin_altivec_vpkswss(a, b); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_packs(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stvx(vector unsigned int a, int b, unsigned int *c) { - return __builtin_altivec_vpkuwus(a, b); + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_vpkshss */ - -static vector signed char __attribute__((__always_inline__)) -vec_vpkshss(vector short a, vector short b) +static void __ATTRS_o_ai +vec_stvx(vector bool int a, int b, int *c) { - return __builtin_altivec_vpkshss(a, b); + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_vpkuhus */ - -static vector unsigned char __attribute__((__always_inline__)) -vec_vpkuhus(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_stvx(vector bool int a, int b, unsigned int *c) { - return __builtin_altivec_vpkuhus(a, b); + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_vpkswss */ - -static vector signed short __attribute__((__always_inline__)) -vec_vpkswss(vector int a, vector int b) +static void __ATTRS_o_ai +vec_stvx(vector bool int a, int b, vector bool int *c) { - return __builtin_altivec_vpkswss(a, b); + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_vpkuwus */ - -static vector unsigned short __attribute__((__always_inline__)) -vec_vpkuwus(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stvx(vector float a, int b, vector float *c) { - return __builtin_altivec_vpkuwus(a, b); + __builtin_altivec_stvx((vector int)a, b, c); } -/* vec_packsu */ - -static vector unsigned char __ATTRS_o_ai -vec_packsu(vector short a, vector short b) +static void __ATTRS_o_ai +vec_stvx(vector float a, int b, float *c) { - return __builtin_altivec_vpkshus(a, b); + __builtin_altivec_stvx((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_packsu(vector unsigned short a, vector unsigned short b) +/* vec_ste */ + +static void __ATTRS_o_ai +vec_ste(vector signed char a, int b, signed char *c) { - return __builtin_altivec_vpkuhus(a, b); + __builtin_altivec_stvebx((vector char)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_packsu(vector int a, vector int b) +static void __ATTRS_o_ai +vec_ste(vector unsigned char a, int b, unsigned char *c) { - return __builtin_altivec_vpkswus(a, b); + __builtin_altivec_stvebx((vector char)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_packsu(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_ste(vector bool char a, int b, signed char *c) { - return __builtin_altivec_vpkuwus(a, b); + __builtin_altivec_stvebx((vector char)a, b, c); } -/* vec_vpkshus */ - -static vector unsigned char __ATTRS_o_ai -vec_vpkshus(vector short a, vector short b) +static void __ATTRS_o_ai +vec_ste(vector bool char a, int b, unsigned char *c) { - return __builtin_altivec_vpkshus(a, b); + __builtin_altivec_stvebx((vector char)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_vpkshus(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_ste(vector short a, int b, short *c) { - return __builtin_altivec_vpkuhus(a, b); + __builtin_altivec_stvehx(a, b, c); } -/* vec_vpkswus */ - -static vector unsigned short __ATTRS_o_ai -vec_vpkswus(vector int a, vector int b) +static void __ATTRS_o_ai +vec_ste(vector unsigned short a, int b, unsigned short *c) { - return __builtin_altivec_vpkswus(a, b); + __builtin_altivec_stvehx((vector short)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_vpkswus(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_ste(vector bool short a, int b, short *c) { - return __builtin_altivec_vpkuwus(a, b); + __builtin_altivec_stvehx((vector short)a, b, c); } -/* vec_perm */ +static void __ATTRS_o_ai +vec_ste(vector bool short a, int b, unsigned short *c) +{ + __builtin_altivec_stvehx((vector short)a, b, c); +} -vector signed char __ATTRS_o_ai -vec_perm(vector signed char a, vector signed char b, vector unsigned char c) +static void __ATTRS_o_ai +vec_ste(vector pixel a, int b, short *c) { - return (vector signed char)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); + __builtin_altivec_stvehx((vector short)a, b, c); } -vector unsigned char __ATTRS_o_ai -vec_perm(vector unsigned char a, vector unsigned char b, vector unsigned char c) +static void __ATTRS_o_ai +vec_ste(vector pixel a, int b, unsigned short *c) { - return (vector unsigned char)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); + __builtin_altivec_stvehx((vector short)a, b, c); } -vector short __ATTRS_o_ai -vec_perm(vector short a, vector short b, vector unsigned char c) +static void __ATTRS_o_ai +vec_ste(vector int a, int b, int *c) { - return (vector short)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); + __builtin_altivec_stvewx(a, b, c); } -vector unsigned short __ATTRS_o_ai -vec_perm(vector unsigned short a, vector unsigned short b, vector unsigned char c) +static void __ATTRS_o_ai +vec_ste(vector unsigned int a, int b, unsigned int *c) { - return (vector unsigned short)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); + __builtin_altivec_stvewx((vector int)a, b, c); } -vector int __ATTRS_o_ai -vec_perm(vector int a, vector int b, vector unsigned char c) +static void __ATTRS_o_ai +vec_ste(vector bool int a, int b, int *c) { - return (vector int)__builtin_altivec_vperm_4si(a, b, c); + __builtin_altivec_stvewx((vector int)a, b, c); } -vector unsigned int __ATTRS_o_ai -vec_perm(vector unsigned int a, vector unsigned int b, vector unsigned char c) +static void __ATTRS_o_ai +vec_ste(vector bool int a, int b, unsigned int *c) { - return (vector unsigned int)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); + __builtin_altivec_stvewx((vector int)a, b, c); } -vector float __ATTRS_o_ai -vec_perm(vector float a, vector float b, vector unsigned char c) +static void __ATTRS_o_ai +vec_ste(vector float a, int b, float *c) { - return (vector float)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); + __builtin_altivec_stvewx((vector int)a, b, c); } -/* vec_vperm */ +/* vec_stvebx */ -vector signed char __ATTRS_o_ai -vec_vperm(vector signed char a, vector signed char b, vector unsigned char c) +static void __ATTRS_o_ai +vec_stvebx(vector signed char a, int b, signed char *c) { - return (vector signed char)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); + __builtin_altivec_stvebx((vector char)a, b, c); } -vector unsigned char __ATTRS_o_ai -vec_vperm(vector unsigned char a, vector unsigned char b, vector unsigned char c) +static void __ATTRS_o_ai +vec_stvebx(vector unsigned char a, int b, unsigned char *c) { - return (vector unsigned char)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); + __builtin_altivec_stvebx((vector char)a, b, c); } -vector short __ATTRS_o_ai -vec_vperm(vector short a, vector short b, vector unsigned char c) +static void __ATTRS_o_ai +vec_stvebx(vector bool char a, int b, signed char *c) { - return (vector short)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); + __builtin_altivec_stvebx((vector char)a, b, c); } -vector unsigned short __ATTRS_o_ai -vec_vperm(vector unsigned short a, vector unsigned short b, vector unsigned char c) +static void __ATTRS_o_ai +vec_stvebx(vector bool char a, int b, unsigned char *c) { - return (vector unsigned short)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); + __builtin_altivec_stvebx((vector char)a, b, c); } -vector int __ATTRS_o_ai -vec_vperm(vector int a, vector int b, vector unsigned char c) +/* vec_stvehx */ + +static void __ATTRS_o_ai +vec_stvehx(vector short a, int b, short *c) { - return (vector int)__builtin_altivec_vperm_4si(a, b, c); + __builtin_altivec_stvehx(a, b, c); } -vector unsigned int __ATTRS_o_ai -vec_vperm(vector unsigned int a, vector unsigned int b, vector unsigned char c) +static void __ATTRS_o_ai +vec_stvehx(vector unsigned short a, int b, unsigned short *c) { - return (vector unsigned int)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); + __builtin_altivec_stvehx((vector short)a, b, c); } -vector float __ATTRS_o_ai -vec_vperm(vector float a, vector float b, vector unsigned char c) +static void __ATTRS_o_ai +vec_stvehx(vector bool short a, int b, short *c) { - return (vector float)__builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); + __builtin_altivec_stvehx((vector short)a, b, c); } -/* vec_re */ - -vector float __attribute__((__always_inline__)) -vec_re(vector float a) +static void __ATTRS_o_ai +vec_stvehx(vector bool short a, int b, unsigned short *c) { - return __builtin_altivec_vrefp(a); + __builtin_altivec_stvehx((vector short)a, b, c); } -/* vec_vrefp */ - -vector float __attribute__((__always_inline__)) -vec_vrefp(vector float a) +static void __ATTRS_o_ai +vec_stvehx(vector pixel a, int b, short *c) { - return __builtin_altivec_vrefp(a); + __builtin_altivec_stvehx((vector short)a, b, c); } -/* vec_rl */ - -static vector signed char __ATTRS_o_ai -vec_rl(vector signed char a, vector unsigned char b) +static void __ATTRS_o_ai +vec_stvehx(vector pixel a, int b, unsigned short *c) { - return (vector signed char)__builtin_altivec_vrlb((vector char)a, b); + __builtin_altivec_stvehx((vector short)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_rl(vector unsigned char a, vector unsigned char b) +/* vec_stvewx */ + +static void __ATTRS_o_ai +vec_stvewx(vector int a, int b, int *c) { - return (vector unsigned char)__builtin_altivec_vrlb((vector char)a, b); + __builtin_altivec_stvewx(a, b, c); } -static vector short __ATTRS_o_ai -vec_rl(vector short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_stvewx(vector unsigned int a, int b, unsigned int *c) { - return __builtin_altivec_vrlh(a, b); + __builtin_altivec_stvewx((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_rl(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_stvewx(vector bool int a, int b, int *c) { - return (vector unsigned short)__builtin_altivec_vrlh((vector short)a, b); + __builtin_altivec_stvewx((vector int)a, b, c); } -static vector int __ATTRS_o_ai -vec_rl(vector int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stvewx(vector bool int a, int b, unsigned int *c) { - return __builtin_altivec_vrlw(a, b); + __builtin_altivec_stvewx((vector int)a, b, c); } -static vector unsigned int __ATTRS_o_ai -vec_rl(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stvewx(vector float a, int b, float *c) { - return (vector unsigned int)__builtin_altivec_vrlw((vector int)a, b); + __builtin_altivec_stvewx((vector int)a, b, c); } -/* vec_vrlb */ +/* vec_stl */ -static vector signed char __ATTRS_o_ai -vec_vrlb(vector signed char a, vector unsigned char b) +static void __ATTRS_o_ai +vec_stl(vector signed char a, int b, vector signed char *c) { - return (vector signed char)__builtin_altivec_vrlb((vector char)a, b); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_vrlb(vector unsigned char a, vector unsigned char b) +static void __ATTRS_o_ai +vec_stl(vector signed char a, int b, signed char *c) { - return (vector unsigned char)__builtin_altivec_vrlb((vector char)a, b); + __builtin_altivec_stvxl((vector int)a, b, c); } -/* vec_vrlh */ - -static vector short __ATTRS_o_ai -vec_vrlh(vector short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_stl(vector unsigned char a, int b, vector unsigned char *c) { - return __builtin_altivec_vrlh(a, b); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_vrlh(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_stl(vector unsigned char a, int b, unsigned char *c) { - return (vector unsigned short)__builtin_altivec_vrlh((vector short)a, b); + __builtin_altivec_stvxl((vector int)a, b, c); } -/* vec_vrlw */ - -static vector int __ATTRS_o_ai -vec_vrlw(vector int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stl(vector bool char a, int b, signed char *c) { - return __builtin_altivec_vrlw(a, b); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned int __ATTRS_o_ai -vec_vrlw(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stl(vector bool char a, int b, unsigned char *c) { - return (vector unsigned int)__builtin_altivec_vrlw((vector int)a, b); + __builtin_altivec_stvxl((vector int)a, b, c); } -/* vec_round */ - -static vector float __attribute__((__always_inline__)) -vec_round(vector float a) +static void __ATTRS_o_ai +vec_stl(vector bool char a, int b, vector bool char *c) { - return __builtin_altivec_vrfin(a); + __builtin_altivec_stvxl((vector int)a, b, c); } -/* vec_vrfin */ - -static vector float __attribute__((__always_inline__)) -vec_vrfin(vector float a) +static void __ATTRS_o_ai +vec_stl(vector short a, int b, vector short *c) { - return __builtin_altivec_vrfin(a); + __builtin_altivec_stvxl((vector int)a, b, c); } -/* vec_rsqrte */ - -static __vector float __attribute__((__always_inline__)) -vec_rsqrte(vector float a) +static void __ATTRS_o_ai +vec_stl(vector short a, int b, short *c) { - return __builtin_altivec_vrsqrtefp(a); + __builtin_altivec_stvxl((vector int)a, b, c); } -/* vec_vrsqrtefp */ - -static __vector float __attribute__((__always_inline__)) -vec_vrsqrtefp(vector float a) +static void __ATTRS_o_ai +vec_stl(vector unsigned short a, int b, vector unsigned short *c) { - return __builtin_altivec_vrsqrtefp(a); + __builtin_altivec_stvxl((vector int)a, b, c); } -/* vec_sel */ - -#define __builtin_altivec_vsel_4si vec_sel - -static vector signed char __ATTRS_o_ai -vec_sel(vector signed char a, vector signed char b, vector unsigned char c) +static void __ATTRS_o_ai +vec_stl(vector unsigned short a, int b, unsigned short *c) +{ + __builtin_altivec_stvxl((vector int)a, b, c); +} + +static void __ATTRS_o_ai +vec_stl(vector bool short a, int b, short *c) { - return (a & ~(vector signed char)c) | (b & (vector signed char)c); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_sel(vector unsigned char a, vector unsigned char b, vector unsigned char c) +static void __ATTRS_o_ai +vec_stl(vector bool short a, int b, unsigned short *c) { - return (a & ~c) | (b & c); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector short __ATTRS_o_ai -vec_sel(vector short a, vector short b, vector unsigned short c) +static void __ATTRS_o_ai +vec_stl(vector bool short a, int b, vector bool short *c) { - return (a & ~(vector short)c) | (b & (vector short)c); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_sel(vector unsigned short a, vector unsigned short b, vector unsigned short c) +static void __ATTRS_o_ai +vec_stl(vector pixel a, int b, short *c) { - return (a & ~c) | (b & c); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector int __ATTRS_o_ai -vec_sel(vector int a, vector int b, vector unsigned int c) +static void __ATTRS_o_ai +vec_stl(vector pixel a, int b, unsigned short *c) { - return (a & ~(vector int)c) | (b & (vector int)c); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned int __ATTRS_o_ai -vec_sel(vector unsigned int a, vector unsigned int b, vector unsigned int c) +static void __ATTRS_o_ai +vec_stl(vector pixel a, int b, vector pixel *c) { - return (a & ~c) | (b & c); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector float __ATTRS_o_ai -vec_sel(vector float a, vector float b, vector unsigned int c) +static void __ATTRS_o_ai +vec_stl(vector int a, int b, vector int *c) { - vector int res = ((vector int)a & ~(vector int)c) | ((vector int)b & (vector int)c); - return (vector float)res; + __builtin_altivec_stvxl(a, b, c); } -/* vec_vsel */ +static void __ATTRS_o_ai +vec_stl(vector int a, int b, int *c) +{ + __builtin_altivec_stvxl(a, b, c); +} -static vector signed char __ATTRS_o_ai -vec_vsel(vector signed char a, vector signed char b, vector unsigned char c) +static void __ATTRS_o_ai +vec_stl(vector unsigned int a, int b, vector unsigned int *c) { - return (a & ~(vector signed char)c) | (b & (vector signed char)c); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_vsel(vector unsigned char a, vector unsigned char b, vector unsigned char c) +static void __ATTRS_o_ai +vec_stl(vector unsigned int a, int b, unsigned int *c) { - return (a & ~c) | (b & c); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector short __ATTRS_o_ai -vec_vsel(vector short a, vector short b, vector unsigned short c) +static void __ATTRS_o_ai +vec_stl(vector bool int a, int b, int *c) { - return (a & ~(vector short)c) | (b & (vector short)c); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_vsel(vector unsigned short a, vector unsigned short b, vector unsigned short c) +static void __ATTRS_o_ai +vec_stl(vector bool int a, int b, unsigned int *c) { - return (a & ~c) | (b & c); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector int __ATTRS_o_ai -vec_vsel(vector int a, vector int b, vector unsigned int c) +static void __ATTRS_o_ai +vec_stl(vector bool int a, int b, vector bool int *c) { - return (a & ~(vector int)c) | (b & (vector int)c); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned int __ATTRS_o_ai -vec_vsel(vector unsigned int a, vector unsigned int b, vector unsigned int c) +static void __ATTRS_o_ai +vec_stl(vector float a, int b, vector float *c) { - return (a & ~c) | (b & c); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector float __ATTRS_o_ai -vec_vsel(vector float a, vector float b, vector unsigned int c) +static void __ATTRS_o_ai +vec_stl(vector float a, int b, float *c) { - vector int res = ((vector int)a & ~(vector int)c) | ((vector int)b & (vector int)c); - return (vector float)res; + __builtin_altivec_stvxl((vector int)a, b, c); } -/* vec_sl */ +/* vec_stvxl */ -static vector signed char __ATTRS_o_ai -vec_sl(vector signed char a, vector unsigned char b) +static void __ATTRS_o_ai +vec_stvxl(vector signed char a, int b, vector signed char *c) { - return a << (vector signed char)b; + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_sl(vector unsigned char a, vector unsigned char b) +static void __ATTRS_o_ai +vec_stvxl(vector signed char a, int b, signed char *c) { - return a << b; + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector short __ATTRS_o_ai -vec_sl(vector short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_stvxl(vector unsigned char a, int b, vector unsigned char *c) { - return a << (vector short)b; + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_sl(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_stvxl(vector unsigned char a, int b, unsigned char *c) { - return a << b; + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector int __ATTRS_o_ai -vec_sl(vector int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stvxl(vector bool char a, int b, signed char *c) { - return a << (vector int)b; + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned int __ATTRS_o_ai -vec_sl(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stvxl(vector bool char a, int b, unsigned char *c) { - return a << b; + __builtin_altivec_stvxl((vector int)a, b, c); } -/* vec_vslb */ - -#define __builtin_altivec_vslb vec_vslb - -static vector signed char __ATTRS_o_ai -vec_vslb(vector signed char a, vector unsigned char b) +static void __ATTRS_o_ai +vec_stvxl(vector bool char a, int b, vector bool char *c) { - return vec_sl(a, b); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_vslb(vector unsigned char a, vector unsigned char b) +static void __ATTRS_o_ai +vec_stvxl(vector short a, int b, vector short *c) { - return vec_sl(a, b); + __builtin_altivec_stvxl((vector int)a, b, c); } -/* vec_vslh */ - -#define __builtin_altivec_vslh vec_vslh - -static vector short __ATTRS_o_ai -vec_vslh(vector short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_stvxl(vector short a, int b, short *c) { - return vec_sl(a, b); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_vslh(vector unsigned short a, vector unsigned short b) +static void __ATTRS_o_ai +vec_stvxl(vector unsigned short a, int b, vector unsigned short *c) { - return vec_sl(a, b); + __builtin_altivec_stvxl((vector int)a, b, c); } -/* vec_vslw */ - -#define __builtin_altivec_vslw vec_vslw - -static vector int __ATTRS_o_ai -vec_vslw(vector int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stvxl(vector unsigned short a, int b, unsigned short *c) { - return vec_sl(a, b); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned int __ATTRS_o_ai -vec_vslw(vector unsigned int a, vector unsigned int b) +static void __ATTRS_o_ai +vec_stvxl(vector bool short a, int b, short *c) { - return vec_sl(a, b); + __builtin_altivec_stvxl((vector int)a, b, c); } -/* vec_sld */ - -#define __builtin_altivec_vsldoi_4si vec_sld - -static vector signed char __ATTRS_o_ai -vec_sld(vector signed char a, vector signed char b, unsigned char c) +static void __ATTRS_o_ai +vec_stvxl(vector bool short a, int b, unsigned short *c) { - return (vector signed char)vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_sld(vector unsigned char a, vector unsigned char b, unsigned char c) +static void __ATTRS_o_ai +vec_stvxl(vector bool short a, int b, vector bool short *c) { - return (vector unsigned char)vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector short __ATTRS_o_ai -vec_sld(vector short a, vector short b, unsigned char c) +static void __ATTRS_o_ai +vec_stvxl(vector pixel a, int b, short *c) { - return (vector short)vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_sld(vector unsigned short a, vector unsigned short b, unsigned char c) +static void __ATTRS_o_ai +vec_stvxl(vector pixel a, int b, unsigned short *c) { - return (vector unsigned short)vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector int __ATTRS_o_ai -vec_sld(vector int a, vector int b, unsigned char c) +static void __ATTRS_o_ai +vec_stvxl(vector pixel a, int b, vector pixel *c) { - return vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned int __ATTRS_o_ai -vec_sld(vector unsigned int a, vector unsigned int b, unsigned char c) +static void __ATTRS_o_ai +vec_stvxl(vector int a, int b, vector int *c) { - return (vector unsigned int)vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); + __builtin_altivec_stvxl(a, b, c); } -static vector float __ATTRS_o_ai -vec_sld(vector float a, vector float b, unsigned char c) +static void __ATTRS_o_ai +vec_stvxl(vector int a, int b, int *c) { - return (vector float)vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); + __builtin_altivec_stvxl(a, b, c); } -/* vec_vsldoi */ - -static vector signed char __ATTRS_o_ai -vec_vsldoi(vector signed char a, vector signed char b, unsigned char c) +static void __ATTRS_o_ai +vec_stvxl(vector unsigned int a, int b, vector unsigned int *c) { - return (vector signed char)vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned char __ATTRS_o_ai -vec_vsldoi(vector unsigned char a, vector unsigned char b, unsigned char c) +static void __ATTRS_o_ai +vec_stvxl(vector unsigned int a, int b, unsigned int *c) { - return (vector unsigned char)vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector short __ATTRS_o_ai -vec_vsldoi(vector short a, vector short b, unsigned char c) +static void __ATTRS_o_ai +vec_stvxl(vector bool int a, int b, int *c) { - return (vector short)vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned short __ATTRS_o_ai -vec_vsldoi(vector unsigned short a, vector unsigned short b, unsigned char c) +static void __ATTRS_o_ai +vec_stvxl(vector bool int a, int b, unsigned int *c) { - return (vector unsigned short)vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector int __ATTRS_o_ai -vec_vsldoi(vector int a, vector int b, unsigned char c) -{ - return vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); +static void __ATTRS_o_ai +vec_stvxl(vector bool int a, int b, vector bool int *c) +{ + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector unsigned int __ATTRS_o_ai -vec_vsldoi(vector unsigned int a, vector unsigned int b, unsigned char c) +static void __ATTRS_o_ai +vec_stvxl(vector float a, int b, vector float *c) { - return (vector unsigned int)vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); + __builtin_altivec_stvxl((vector int)a, b, c); } -static vector float __ATTRS_o_ai -vec_vsldoi(vector float a, vector float b, unsigned char c) +static void __ATTRS_o_ai +vec_stvxl(vector float a, int b, float *c) { - return (vector float)vec_perm(a, b, (vector unsigned char) - (c, c+1, c+2, c+3, c+4, c+5, c+6, c+7, - c+8, c+9, c+10, c+11, c+12, c+13, c+14, c+15)); + __builtin_altivec_stvxl((vector int)a, b, c); } -/* vec_sll */ +/* vec_sub */ static vector signed char __ATTRS_o_ai -vec_sll(vector signed char a, vector unsigned char b) +vec_sub(vector signed char a, vector signed char b) { - return (vector signed char)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - b; } static vector signed char __ATTRS_o_ai -vec_sll(vector signed char a, vector unsigned short b) +vec_sub(vector bool char a, vector signed char b) { - return (vector signed char)__builtin_altivec_vsl((vector int)a, (vector int)b); + return (vector signed char)a - b; } static vector signed char __ATTRS_o_ai -vec_sll(vector signed char a, vector unsigned int b) +vec_sub(vector signed char a, vector bool char b) { - return (vector signed char)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - (vector signed char)b; } static vector unsigned char __ATTRS_o_ai -vec_sll(vector unsigned char a, vector unsigned char b) +vec_sub(vector unsigned char a, vector unsigned char b) { - return (vector unsigned char)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - b; } static vector unsigned char __ATTRS_o_ai -vec_sll(vector unsigned char a, vector unsigned short b) +vec_sub(vector bool char a, vector unsigned char b) { - return (vector unsigned char)__builtin_altivec_vsl((vector int)a, (vector int)b); + return (vector unsigned char)a - b; } static vector unsigned char __ATTRS_o_ai -vec_sll(vector unsigned char a, vector unsigned int b) +vec_sub(vector unsigned char a, vector bool char b) { - return (vector unsigned char)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - (vector unsigned char)b; } static vector short __ATTRS_o_ai -vec_sll(vector short a, vector unsigned char b) +vec_sub(vector short a, vector short b) { - return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - b; } static vector short __ATTRS_o_ai -vec_sll(vector short a, vector unsigned short b) +vec_sub(vector bool short a, vector short b) { - return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b); + return (vector short)a - b; } static vector short __ATTRS_o_ai -vec_sll(vector short a, vector unsigned int b) +vec_sub(vector short a, vector bool short b) { - return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - (vector short)b; } static vector unsigned short __ATTRS_o_ai -vec_sll(vector unsigned short a, vector unsigned char b) +vec_sub(vector unsigned short a, vector unsigned short b) { - return (vector unsigned short)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - b; } static vector unsigned short __ATTRS_o_ai -vec_sll(vector unsigned short a, vector unsigned short b) +vec_sub(vector bool short a, vector unsigned short b) { - return (vector unsigned short)__builtin_altivec_vsl((vector int)a, (vector int)b); + return (vector unsigned short)a - b; } static vector unsigned short __ATTRS_o_ai -vec_sll(vector unsigned short a, vector unsigned int b) +vec_sub(vector unsigned short a, vector bool short b) { - return (vector unsigned short)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - (vector unsigned short)b; } static vector int __ATTRS_o_ai -vec_sll(vector int a, vector unsigned char b) +vec_sub(vector int a, vector int b) { - return (vector int)__builtin_altivec_vsl(a, (vector int)b); + return a - b; } static vector int __ATTRS_o_ai -vec_sll(vector int a, vector unsigned short b) +vec_sub(vector bool int a, vector int b) { - return (vector int)__builtin_altivec_vsl(a, (vector int)b); + return (vector int)a - b; } static vector int __ATTRS_o_ai -vec_sll(vector int a, vector unsigned int b) +vec_sub(vector int a, vector bool int b) { - return (vector int)__builtin_altivec_vsl(a, (vector int)b); + return a - (vector int)b; } static vector unsigned int __ATTRS_o_ai -vec_sll(vector unsigned int a, vector unsigned char b) +vec_sub(vector unsigned int a, vector unsigned int b) { - return (vector unsigned int)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - b; } static vector unsigned int __ATTRS_o_ai -vec_sll(vector unsigned int a, vector unsigned short b) +vec_sub(vector bool int a, vector unsigned int b) { - return (vector unsigned int)__builtin_altivec_vsl((vector int)a, (vector int)b); + return (vector unsigned int)a - b; } static vector unsigned int __ATTRS_o_ai -vec_sll(vector unsigned int a, vector unsigned int b) +vec_sub(vector unsigned int a, vector bool int b) { - return (vector unsigned int)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - (vector unsigned int)b; } -/* vec_vsl */ +static vector float __ATTRS_o_ai +vec_sub(vector float a, vector float b) +{ + return a - b; +} + +/* vec_vsububm */ + +#define __builtin_altivec_vsububm vec_vsububm static vector signed char __ATTRS_o_ai -vec_vsl(vector signed char a, vector unsigned char b) +vec_vsububm(vector signed char a, vector signed char b) { - return (vector signed char)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - b; } static vector signed char __ATTRS_o_ai -vec_vsl(vector signed char a, vector unsigned short b) +vec_vsububm(vector bool char a, vector signed char b) { - return (vector signed char)__builtin_altivec_vsl((vector int)a, (vector int)b); + return (vector signed char)a - b; } static vector signed char __ATTRS_o_ai -vec_vsl(vector signed char a, vector unsigned int b) +vec_vsububm(vector signed char a, vector bool char b) { - return (vector signed char)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - (vector signed char)b; } static vector unsigned char __ATTRS_o_ai -vec_vsl(vector unsigned char a, vector unsigned char b) +vec_vsububm(vector unsigned char a, vector unsigned char b) { - return (vector unsigned char)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - b; } static vector unsigned char __ATTRS_o_ai -vec_vsl(vector unsigned char a, vector unsigned short b) +vec_vsububm(vector bool char a, vector unsigned char b) { - return (vector unsigned char)__builtin_altivec_vsl((vector int)a, (vector int)b); + return (vector unsigned char)a - b; } static vector unsigned char __ATTRS_o_ai -vec_vsl(vector unsigned char a, vector unsigned int b) +vec_vsububm(vector unsigned char a, vector bool char b) { - return (vector unsigned char)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - (vector unsigned char)b; } +/* vec_vsubuhm */ + +#define __builtin_altivec_vsubuhm vec_vsubuhm + static vector short __ATTRS_o_ai -vec_vsl(vector short a, vector unsigned char b) +vec_vsubuhm(vector short a, vector short b) { - return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - b; } static vector short __ATTRS_o_ai -vec_vsl(vector short a, vector unsigned short b) +vec_vsubuhm(vector bool short a, vector short b) { - return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b); + return (vector short)a - b; } static vector short __ATTRS_o_ai -vec_vsl(vector short a, vector unsigned int b) +vec_vsubuhm(vector short a, vector bool short b) { - return (vector short)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - (vector short)b; } static vector unsigned short __ATTRS_o_ai -vec_vsl(vector unsigned short a, vector unsigned char b) +vec_vsubuhm(vector unsigned short a, vector unsigned short b) { - return (vector unsigned short)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - b; } static vector unsigned short __ATTRS_o_ai -vec_vsl(vector unsigned short a, vector unsigned short b) +vec_vsubuhm(vector bool short a, vector unsigned short b) { - return (vector unsigned short)__builtin_altivec_vsl((vector int)a, (vector int)b); + return (vector unsigned short)a - b; } static vector unsigned short __ATTRS_o_ai -vec_vsl(vector unsigned short a, vector unsigned int b) +vec_vsubuhm(vector unsigned short a, vector bool short b) { - return (vector unsigned short)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - (vector unsigned short)b; } +/* vec_vsubuwm */ + +#define __builtin_altivec_vsubuwm vec_vsubuwm + static vector int __ATTRS_o_ai -vec_vsl(vector int a, vector unsigned char b) +vec_vsubuwm(vector int a, vector int b) { - return (vector int)__builtin_altivec_vsl(a, (vector int)b); + return a - b; } static vector int __ATTRS_o_ai -vec_vsl(vector int a, vector unsigned short b) +vec_vsubuwm(vector bool int a, vector int b) { - return (vector int)__builtin_altivec_vsl(a, (vector int)b); + return (vector int)a - b; } static vector int __ATTRS_o_ai -vec_vsl(vector int a, vector unsigned int b) +vec_vsubuwm(vector int a, vector bool int b) { - return (vector int)__builtin_altivec_vsl(a, (vector int)b); + return a - (vector int)b; } static vector unsigned int __ATTRS_o_ai -vec_vsl(vector unsigned int a, vector unsigned char b) +vec_vsubuwm(vector unsigned int a, vector unsigned int b) { - return (vector unsigned int)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - b; } static vector unsigned int __ATTRS_o_ai -vec_vsl(vector unsigned int a, vector unsigned short b) +vec_vsubuwm(vector bool int a, vector unsigned int b) { - return (vector unsigned int)__builtin_altivec_vsl((vector int)a, (vector int)b); + return (vector unsigned int)a - b; } static vector unsigned int __ATTRS_o_ai -vec_vsl(vector unsigned int a, vector unsigned int b) +vec_vsubuwm(vector unsigned int a, vector bool int b) { - return (vector unsigned int)__builtin_altivec_vsl((vector int)a, (vector int)b); + return a - (vector unsigned int)b; } -/* vec_slo */ +/* vec_vsubfp */ + +#define __builtin_altivec_vsubfp vec_vsubfp + +static vector float __attribute__((__always_inline__)) +vec_vsubfp(vector float a, vector float b) +{ + return a - b; +} + +/* vec_subc */ + +static vector unsigned int __attribute__((__always_inline__)) +vec_subc(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vsubcuw(a, b); +} + +/* vec_vsubcuw */ + +static vector unsigned int __attribute__((__always_inline__)) +vec_vsubcuw(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vsubcuw(a, b); +} + +/* vec_subs */ static vector signed char __ATTRS_o_ai -vec_slo(vector signed char a, vector signed char b) +vec_subs(vector signed char a, vector signed char b) { - return (vector signed char)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubsbs(a, b); } static vector signed char __ATTRS_o_ai -vec_slo(vector signed char a, vector unsigned char b) +vec_subs(vector bool char a, vector signed char b) { - return (vector signed char)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubsbs((vector signed char)a, b); +} + +static vector signed char __ATTRS_o_ai +vec_subs(vector signed char a, vector bool char b) +{ + return __builtin_altivec_vsubsbs(a, (vector signed char)b); } static vector unsigned char __ATTRS_o_ai -vec_slo(vector unsigned char a, vector signed char b) +vec_subs(vector unsigned char a, vector unsigned char b) { - return (vector unsigned char)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsububs(a, b); } static vector unsigned char __ATTRS_o_ai -vec_slo(vector unsigned char a, vector unsigned char b) +vec_subs(vector bool char a, vector unsigned char b) { - return (vector unsigned char)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsububs((vector unsigned char)a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_subs(vector unsigned char a, vector bool char b) +{ + return __builtin_altivec_vsububs(a, (vector unsigned char)b); } static vector short __ATTRS_o_ai -vec_slo(vector short a, vector signed char b) +vec_subs(vector short a, vector short b) { - return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubshs(a, b); } static vector short __ATTRS_o_ai -vec_slo(vector short a, vector unsigned char b) +vec_subs(vector bool short a, vector short b) { - return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubshs((vector short)a, b); +} + +static vector short __ATTRS_o_ai +vec_subs(vector short a, vector bool short b) +{ + return __builtin_altivec_vsubshs(a, (vector short)b); } static vector unsigned short __ATTRS_o_ai -vec_slo(vector unsigned short a, vector signed char b) +vec_subs(vector unsigned short a, vector unsigned short b) { - return (vector unsigned short)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubuhs(a, b); } static vector unsigned short __ATTRS_o_ai -vec_slo(vector unsigned short a, vector unsigned char b) +vec_subs(vector bool short a, vector unsigned short b) { - return (vector unsigned short)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubuhs((vector unsigned short)a, b); +} + +static vector unsigned short __ATTRS_o_ai +vec_subs(vector unsigned short a, vector bool short b) +{ + return __builtin_altivec_vsubuhs(a, (vector unsigned short)b); } static vector int __ATTRS_o_ai -vec_slo(vector int a, vector signed char b) +vec_subs(vector int a, vector int b) { - return (vector int)__builtin_altivec_vslo(a, (vector int)b); + return __builtin_altivec_vsubsws(a, b); } static vector int __ATTRS_o_ai -vec_slo(vector int a, vector unsigned char b) +vec_subs(vector bool int a, vector int b) { - return (vector int)__builtin_altivec_vslo(a, (vector int)b); + return __builtin_altivec_vsubsws((vector int)a, b); } -static vector unsigned int __ATTRS_o_ai -vec_slo(vector unsigned int a, vector signed char b) +static vector int __ATTRS_o_ai +vec_subs(vector int a, vector bool int b) { - return (vector unsigned int)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubsws(a, (vector int)b); } static vector unsigned int __ATTRS_o_ai -vec_slo(vector unsigned int a, vector unsigned char b) +vec_subs(vector unsigned int a, vector unsigned int b) { - return (vector unsigned int)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubuws(a, b); } -static vector float __ATTRS_o_ai -vec_slo(vector float a, vector signed char b) +static vector unsigned int __ATTRS_o_ai +vec_subs(vector bool int a, vector unsigned int b) { - return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubuws((vector unsigned int)a, b); } -static vector float __ATTRS_o_ai -vec_slo(vector float a, vector unsigned char b) +static vector unsigned int __ATTRS_o_ai +vec_subs(vector unsigned int a, vector bool int b) { - return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubuws(a, (vector unsigned int)b); } -/* vec_vslo */ +/* vec_vsubsbs */ static vector signed char __ATTRS_o_ai -vec_vslo(vector signed char a, vector signed char b) +vec_vsubsbs(vector signed char a, vector signed char b) { - return (vector signed char)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubsbs(a, b); } static vector signed char __ATTRS_o_ai -vec_vslo(vector signed char a, vector unsigned char b) +vec_vsubsbs(vector bool char a, vector signed char b) { - return (vector signed char)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubsbs((vector signed char)a, b); +} + +static vector signed char __ATTRS_o_ai +vec_vsubsbs(vector signed char a, vector bool char b) +{ + return __builtin_altivec_vsubsbs(a, (vector signed char)b); } +/* vec_vsububs */ + static vector unsigned char __ATTRS_o_ai -vec_vslo(vector unsigned char a, vector signed char b) +vec_vsububs(vector unsigned char a, vector unsigned char b) { - return (vector unsigned char)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsububs(a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vsububs(vector bool char a, vector unsigned char b) +{ + return __builtin_altivec_vsububs((vector unsigned char)a, b); +} + +static vector unsigned char __ATTRS_o_ai +vec_vsububs(vector unsigned char a, vector bool char b) +{ + return __builtin_altivec_vsububs(a, (vector unsigned char)b); +} + +/* vec_vsubshs */ + +static vector short __ATTRS_o_ai +vec_vsubshs(vector short a, vector short b) +{ + return __builtin_altivec_vsubshs(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_vslo(vector unsigned char a, vector unsigned char b) +static vector short __ATTRS_o_ai +vec_vsubshs(vector bool short a, vector short b) { - return (vector unsigned char)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubshs((vector short)a, b); } static vector short __ATTRS_o_ai -vec_vslo(vector short a, vector signed char b) +vec_vsubshs(vector short a, vector bool short b) { - return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubshs(a, (vector short)b); } -static vector short __ATTRS_o_ai -vec_vslo(vector short a, vector unsigned char b) +/* vec_vsubuhs */ + +static vector unsigned short __ATTRS_o_ai +vec_vsubuhs(vector unsigned short a, vector unsigned short b) { - return (vector short)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubuhs(a, b); } static vector unsigned short __ATTRS_o_ai -vec_vslo(vector unsigned short a, vector signed char b) +vec_vsubuhs(vector bool short a, vector unsigned short b) { - return (vector unsigned short)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubuhs((vector unsigned short)a, b); } static vector unsigned short __ATTRS_o_ai -vec_vslo(vector unsigned short a, vector unsigned char b) +vec_vsubuhs(vector unsigned short a, vector bool short b) { - return (vector unsigned short)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubuhs(a, (vector unsigned short)b); } +/* vec_vsubsws */ + static vector int __ATTRS_o_ai -vec_vslo(vector int a, vector signed char b) +vec_vsubsws(vector int a, vector int b) { - return (vector int)__builtin_altivec_vslo(a, (vector int)b); + return __builtin_altivec_vsubsws(a, b); } static vector int __ATTRS_o_ai -vec_vslo(vector int a, vector unsigned char b) +vec_vsubsws(vector bool int a, vector int b) { - return (vector int)__builtin_altivec_vslo(a, (vector int)b); + return __builtin_altivec_vsubsws((vector int)a, b); } -static vector unsigned int __ATTRS_o_ai -vec_vslo(vector unsigned int a, vector signed char b) +static vector int __ATTRS_o_ai +vec_vsubsws(vector int a, vector bool int b) { - return (vector unsigned int)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubsws(a, (vector int)b); } +/* vec_vsubuws */ + static vector unsigned int __ATTRS_o_ai -vec_vslo(vector unsigned int a, vector unsigned char b) +vec_vsubuws(vector unsigned int a, vector unsigned int b) { - return (vector unsigned int)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubuws(a, b); } -static vector float __ATTRS_o_ai -vec_vslo(vector float a, vector signed char b) +static vector unsigned int __ATTRS_o_ai +vec_vsubuws(vector bool int a, vector unsigned int b) { - return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubuws((vector unsigned int)a, b); } -static vector float __ATTRS_o_ai -vec_vslo(vector float a, vector unsigned char b) +static vector unsigned int __ATTRS_o_ai +vec_vsubuws(vector unsigned int a, vector bool int b) { - return (vector float)__builtin_altivec_vslo((vector int)a, (vector int)b); + return __builtin_altivec_vsubuws(a, (vector unsigned int)b); } -/* vec_splat */ +/* vec_sum4s */ -static vector signed char __ATTRS_o_ai -vec_splat(vector signed char a, unsigned char b) +static vector int __ATTRS_o_ai +vec_sum4s(vector signed char a, vector int b) { - return (vector signed char)vec_perm(a, a, (vector unsigned char)(b)); + return __builtin_altivec_vsum4sbs(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_splat(vector unsigned char a, unsigned char b) +static vector unsigned int __ATTRS_o_ai +vec_sum4s(vector unsigned char a, vector unsigned int b) { - return (vector unsigned char)vec_perm(a, a, (vector unsigned char)(b)); + return __builtin_altivec_vsum4ubs(a, b); } -static vector short __ATTRS_o_ai -vec_splat(vector short a, unsigned char b) -{ - b *= 2; - return (vector short)vec_perm(a, a, (vector unsigned char) - (b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1)); +static vector int __ATTRS_o_ai +vec_sum4s(vector signed short a, vector int b) +{ + return __builtin_altivec_vsum4shs(a, b); } -static vector unsigned short __ATTRS_o_ai -vec_splat(vector unsigned short a, unsigned char b) -{ - b *= 2; - return (vector unsigned short)vec_perm(a, a, (vector unsigned char) - (b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1)); -} +/* vec_vsum4sbs */ -static vector int __ATTRS_o_ai -vec_splat(vector int a, unsigned char b) -{ - b *= 4; - return vec_perm(a, a, (vector unsigned char) - (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); +static vector int __attribute__((__always_inline__)) +vec_vsum4sbs(vector signed char a, vector int b) +{ + return __builtin_altivec_vsum4sbs(a, b); } -static vector unsigned int __ATTRS_o_ai -vec_splat(vector unsigned int a, unsigned char b) -{ - b *= 4; - return (vector unsigned int)vec_perm(a, a, (vector unsigned char) - (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); +/* vec_vsum4ubs */ + +static vector unsigned int __attribute__((__always_inline__)) +vec_vsum4ubs(vector unsigned char a, vector unsigned int b) +{ + return __builtin_altivec_vsum4ubs(a, b); } -static vector float __ATTRS_o_ai -vec_splat(vector float a, unsigned char b) -{ - b *= 4; - return (vector float)vec_perm(a, a, (vector unsigned char) - (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); +/* vec_vsum4shs */ + +static vector int __attribute__((__always_inline__)) +vec_vsum4shs(vector signed short a, vector int b) +{ + return __builtin_altivec_vsum4shs(a, b); } -/* vec_vspltb */ +/* vec_sum2s */ -#define __builtin_altivec_vspltb vec_vspltb +static vector signed int __attribute__((__always_inline__)) +vec_sum2s(vector int a, vector int b) +{ + return __builtin_altivec_vsum2sws(a, b); +} -static vector signed char __ATTRS_o_ai -vec_vspltb(vector signed char a, unsigned char b) +/* vec_vsum2sws */ + +static vector signed int __attribute__((__always_inline__)) +vec_vsum2sws(vector int a, vector int b) { - return (vector signed char)vec_perm(a, a, (vector unsigned char)(b)); + return __builtin_altivec_vsum2sws(a, b); } -static vector unsigned char __ATTRS_o_ai -vec_vspltb(vector unsigned char a, unsigned char b) +/* vec_sums */ + +static vector signed int __attribute__((__always_inline__)) +vec_sums(vector signed int a, vector signed int b) { - return (vector unsigned char)vec_perm(a, a, (vector unsigned char)(b)); + return __builtin_altivec_vsumsws(a, b); } -/* vec_vsplth */ +/* vec_vsumsws */ -#define __builtin_altivec_vsplth vec_vsplth +static vector signed int __attribute__((__always_inline__)) +vec_vsumsws(vector signed int a, vector signed int b) +{ + return __builtin_altivec_vsumsws(a, b); +} -static vector short __ATTRS_o_ai -vec_vsplth(vector short a, unsigned char b) +/* vec_trunc */ + +static vector float __attribute__((__always_inline__)) +vec_trunc(vector float a) { - b *= 2; - return (vector short)vec_perm(a, a, (vector unsigned char) - (b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1)); + return __builtin_altivec_vrfiz(a); } -static vector unsigned short __ATTRS_o_ai -vec_vsplth(vector unsigned short a, unsigned char b) +/* vec_vrfiz */ + +static vector float __attribute__((__always_inline__)) +vec_vrfiz(vector float a) { - b *= 2; - return (vector unsigned short)vec_perm(a, a, (vector unsigned char) - (b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1, b, b+1)); + return __builtin_altivec_vrfiz(a); } -/* vec_vspltw */ +/* vec_unpackh */ -#define __builtin_altivec_vspltw vec_vspltw +static vector short __ATTRS_o_ai +vec_unpackh(vector signed char a) +{ + return __builtin_altivec_vupkhsb((vector char)a); +} + +static vector bool short __ATTRS_o_ai +vec_unpackh(vector bool char a) +{ + return (vector bool short)__builtin_altivec_vupkhsb((vector char)a); +} static vector int __ATTRS_o_ai -vec_vspltw(vector int a, unsigned char b) +vec_unpackh(vector short a) { - b *= 4; - return (vector int)vec_perm(a, a, (vector unsigned char) - (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); + return __builtin_altivec_vupkhsh(a); } -static vector unsigned int __ATTRS_o_ai -vec_vspltw(vector unsigned int a, unsigned char b) +static vector bool int __ATTRS_o_ai +vec_unpackh(vector bool short a) { - b *= 4; - return (vector unsigned int)vec_perm(a, a, (vector unsigned char) - (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); + return (vector bool int)__builtin_altivec_vupkhsh((vector short)a); } -static vector float __ATTRS_o_ai -vec_vspltw(vector float a, unsigned char b) +static vector unsigned int __ATTRS_o_ai +vec_unpackh(vector pixel a) { - b *= 4; - return (vector float)vec_perm(a, a, (vector unsigned char) - (b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3, b, b+1, b+2, b+3)); + return (vector unsigned int)__builtin_altivec_vupkhsh((vector short)a); } -/* vec_splat_s8 */ +/* vec_vupkhsb */ -#define __builtin_altivec_vspltisb vec_splat_s8 +static vector short __ATTRS_o_ai +vec_vupkhsb(vector signed char a) +{ + return __builtin_altivec_vupkhsb((vector char)a); +} -// FIXME: parameter should be treated as 5-bit signed literal -static vector signed char __ATTRS_o_ai -vec_splat_s8(signed char a) +static vector bool short __ATTRS_o_ai +vec_vupkhsb(vector bool char a) { - return (vector signed char)(a); + return (vector bool short)__builtin_altivec_vupkhsb((vector char)a); } -/* vec_vspltisb */ +/* vec_vupkhsh */ -// FIXME: parameter should be treated as 5-bit signed literal -static vector signed char __ATTRS_o_ai -vec_vspltisb(signed char a) +static vector int __ATTRS_o_ai +vec_vupkhsh(vector short a) { - return (vector signed char)(a); + return __builtin_altivec_vupkhsh(a); } -/* vec_splat_s16 */ - -#define __builtin_altivec_vspltish vec_splat_s16 +static vector bool int __ATTRS_o_ai +vec_vupkhsh(vector bool short a) +{ + return (vector bool int)__builtin_altivec_vupkhsh((vector short)a); +} -// FIXME: parameter should be treated as 5-bit signed literal -static vector short __ATTRS_o_ai -vec_splat_s16(signed char a) +static vector unsigned int __ATTRS_o_ai +vec_vupkhsh(vector pixel a) { - return (vector short)(a); + return (vector unsigned int)__builtin_altivec_vupkhsh((vector short)a); } -/* vec_vspltish */ +/* vec_unpackl */ -// FIXME: parameter should be treated as 5-bit signed literal static vector short __ATTRS_o_ai -vec_vspltish(signed char a) +vec_unpackl(vector signed char a) { - return (vector short)(a); + return __builtin_altivec_vupklsb((vector char)a); } -/* vec_splat_s32 */ - -#define __builtin_altivec_vspltisw vec_splat_s32 +static vector bool short __ATTRS_o_ai +vec_unpackl(vector bool char a) +{ + return (vector bool short)__builtin_altivec_vupklsb((vector char)a); +} -// FIXME: parameter should be treated as 5-bit signed literal static vector int __ATTRS_o_ai -vec_splat_s32(signed char a) +vec_unpackl(vector short a) { - return (vector int)(a); + return __builtin_altivec_vupklsh(a); } -/* vec_vspltisw */ +static vector bool int __ATTRS_o_ai +vec_unpackl(vector bool short a) +{ + return (vector bool int)__builtin_altivec_vupklsh((vector short)a); +} -// FIXME: parameter should be treated as 5-bit signed literal -static vector int __ATTRS_o_ai -vec_vspltisw(signed char a) +static vector unsigned int __ATTRS_o_ai +vec_unpackl(vector pixel a) { - return (vector int)(a); + return (vector unsigned int)__builtin_altivec_vupklsh((vector short)a); } -/* vec_splat_u8 */ +/* vec_vupklsb */ -// FIXME: parameter should be treated as 5-bit signed literal -static vector unsigned char __ATTRS_o_ai -vec_splat_u8(unsigned char a) +static vector short __ATTRS_o_ai +vec_vupklsb(vector signed char a) { - return (vector unsigned char)(a); + return __builtin_altivec_vupklsb((vector char)a); } -/* vec_splat_u16 */ +static vector bool short __ATTRS_o_ai +vec_vupklsb(vector bool char a) +{ + return (vector bool short)__builtin_altivec_vupklsb((vector char)a); +} -// FIXME: parameter should be treated as 5-bit signed literal -static vector unsigned short __ATTRS_o_ai -vec_splat_u16(signed char a) +/* vec_vupklsh */ + +static vector int __ATTRS_o_ai +vec_vupklsh(vector short a) { - return (vector unsigned short)(a); + return __builtin_altivec_vupklsh(a); } -/* vec_splat_u32 */ +static vector bool int __ATTRS_o_ai +vec_vupklsh(vector bool short a) +{ + return (vector bool int)__builtin_altivec_vupklsh((vector short)a); +} -// FIXME: parameter should be treated as 5-bit signed literal static vector unsigned int __ATTRS_o_ai -vec_splat_u32(signed char a) +vec_vupklsh(vector pixel a) { - return (vector unsigned int)(a); + return (vector unsigned int)__builtin_altivec_vupklsh((vector short)a); } -/* vec_sr */ +/* vec_xor */ + +#define __builtin_altivec_vxor vec_xor static vector signed char __ATTRS_o_ai -vec_sr(vector signed char a, vector unsigned char b) +vec_xor(vector signed char a, vector signed char b) { - return a >> (vector signed char)b; + return a ^ b; } -static vector unsigned char __ATTRS_o_ai -vec_sr(vector unsigned char a, vector unsigned char b) +static vector signed char __ATTRS_o_ai +vec_xor(vector bool char a, vector signed char b) { - return a >> b; + return (vector signed char)a ^ b; } -static vector short __ATTRS_o_ai -vec_sr(vector short a, vector unsigned short b) +static vector signed char __ATTRS_o_ai +vec_xor(vector signed char a, vector bool char b) { - return a >> (vector short)b; + return a ^ (vector signed char)b; } -static vector unsigned short __ATTRS_o_ai -vec_sr(vector unsigned short a, vector unsigned short b) +static vector unsigned char __ATTRS_o_ai +vec_xor(vector unsigned char a, vector unsigned char b) { - return a >> b; + return a ^ b; } -static vector int __ATTRS_o_ai -vec_sr(vector int a, vector unsigned int b) +static vector unsigned char __ATTRS_o_ai +vec_xor(vector bool char a, vector unsigned char b) { - return a >> (vector int)b; + return (vector unsigned char)a ^ b; } -static vector unsigned int __ATTRS_o_ai -vec_sr(vector unsigned int a, vector unsigned int b) +static vector unsigned char __ATTRS_o_ai +vec_xor(vector unsigned char a, vector bool char b) { - return a >> b; + return a ^ (vector unsigned char)b; } -/* vec_vsrb */ - -#define __builtin_altivec_vsrb vec_vsrb - -static vector signed char __ATTRS_o_ai -vec_vsrb(vector signed char a, vector unsigned char b) +static vector bool char __ATTRS_o_ai +vec_xor(vector bool char a, vector bool char b) { - return a >> (vector signed char)b; + return a ^ b; } -static vector unsigned char __ATTRS_o_ai -vec_vsrb(vector unsigned char a, vector unsigned char b) +static vector short __ATTRS_o_ai +vec_xor(vector short a, vector short b) { - return a >> b; + return a ^ b; } -/* vec_vsrh */ - -#define __builtin_altivec_vsrh vec_vsrh - static vector short __ATTRS_o_ai -vec_vsrh(vector short a, vector unsigned short b) +vec_xor(vector bool short a, vector short b) { - return a >> (vector short)b; + return (vector short)a ^ b; } -static vector unsigned short __ATTRS_o_ai -vec_vsrh(vector unsigned short a, vector unsigned short b) +static vector short __ATTRS_o_ai +vec_xor(vector short a, vector bool short b) { - return a >> b; + return a ^ (vector short)b; } -/* vec_vsrw */ - -#define __builtin_altivec_vsrw vec_vsrw - -static vector int __ATTRS_o_ai -vec_vsrw(vector int a, vector unsigned int b) +static vector unsigned short __ATTRS_o_ai +vec_xor(vector unsigned short a, vector unsigned short b) { - return a >> (vector int)b; + return a ^ b; } -static vector unsigned int __ATTRS_o_ai -vec_vsrw(vector unsigned int a, vector unsigned int b) +static vector unsigned short __ATTRS_o_ai +vec_xor(vector bool short a, vector unsigned short b) { - return a >> b; + return (vector unsigned short)a ^ b; } -/* vec_sra */ - -static vector signed char __ATTRS_o_ai -vec_sra(vector signed char a, vector unsigned char b) +static vector unsigned short __ATTRS_o_ai +vec_xor(vector unsigned short a, vector bool short b) { - return (vector signed char)__builtin_altivec_vsrab((vector char)a, b); + return a ^ (vector unsigned short)b; } -static vector unsigned char __ATTRS_o_ai -vec_sra(vector unsigned char a, vector unsigned char b) +static vector bool short __ATTRS_o_ai +vec_xor(vector bool short a, vector bool short b) { - return (vector unsigned char)__builtin_altivec_vsrab((vector char)a, b); + return a ^ b; } -static vector short __ATTRS_o_ai -vec_sra(vector short a, vector unsigned short b) +static vector int __ATTRS_o_ai +vec_xor(vector int a, vector int b) { - return __builtin_altivec_vsrah(a, (vector unsigned short)b); + return a ^ b; } -static vector unsigned short __ATTRS_o_ai -vec_sra(vector unsigned short a, vector unsigned short b) +static vector int __ATTRS_o_ai +vec_xor(vector bool int a, vector int b) { - return (vector unsigned short)__builtin_altivec_vsrah((vector short)a, b); + return (vector int)a ^ b; } static vector int __ATTRS_o_ai -vec_sra(vector int a, vector unsigned int b) +vec_xor(vector int a, vector bool int b) { - return __builtin_altivec_vsraw(a, b); + return a ^ (vector int)b; } static vector unsigned int __ATTRS_o_ai -vec_sra(vector unsigned int a, vector unsigned int b) +vec_xor(vector unsigned int a, vector unsigned int b) { - return (vector unsigned int)__builtin_altivec_vsraw((vector int)a, b); + return a ^ b; } -/* vec_vsrab */ - -static vector signed char __ATTRS_o_ai -vec_vsrab(vector signed char a, vector unsigned char b) +static vector unsigned int __ATTRS_o_ai +vec_xor(vector bool int a, vector unsigned int b) { - return (vector signed char)__builtin_altivec_vsrab((vector char)a, b); + return (vector unsigned int)a ^ b; } -static vector unsigned char __ATTRS_o_ai -vec_vsrab(vector unsigned char a, vector unsigned char b) +static vector unsigned int __ATTRS_o_ai +vec_xor(vector unsigned int a, vector bool int b) { - return (vector unsigned char)__builtin_altivec_vsrab((vector char)a, b); + return a ^ (vector unsigned int)b; } -/* vec_vsrah */ - -static vector short __ATTRS_o_ai -vec_vsrah(vector short a, vector unsigned short b) +static vector bool int __ATTRS_o_ai +vec_xor(vector bool int a, vector bool int b) { - return __builtin_altivec_vsrah(a, (vector unsigned short)b); + return a ^ b; } -static vector unsigned short __ATTRS_o_ai -vec_vsrah(vector unsigned short a, vector unsigned short b) +static vector float __ATTRS_o_ai +vec_xor(vector float a, vector float b) { - return (vector unsigned short)__builtin_altivec_vsrah((vector short)a, b); + vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b; + return (vector float)res; } -/* vec_vsraw */ - -static vector int __ATTRS_o_ai -vec_vsraw(vector int a, vector unsigned int b) +static vector float __ATTRS_o_ai +vec_xor(vector bool int a, vector float b) { - return __builtin_altivec_vsraw(a, b); + vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b; + return (vector float)res; } -static vector unsigned int __ATTRS_o_ai -vec_vsraw(vector unsigned int a, vector unsigned int b) +static vector float __ATTRS_o_ai +vec_xor(vector float a, vector bool int b) { - return (vector unsigned int)__builtin_altivec_vsraw((vector int)a, b); + vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b; + return (vector float)res; } -/* vec_srl */ +/* vec_vxor */ static vector signed char __ATTRS_o_ai -vec_srl(vector signed char a, vector unsigned char b) +vec_vxor(vector signed char a, vector signed char b) { - return (vector signed char)__builtin_altivec_vsr((vector int)a, (vector int)b); + return a ^ b; } static vector signed char __ATTRS_o_ai -vec_srl(vector signed char a, vector unsigned short b) +vec_vxor(vector bool char a, vector signed char b) { - return (vector signed char)__builtin_altivec_vsr((vector int)a, (vector int)b); + return (vector signed char)a ^ b; } static vector signed char __ATTRS_o_ai -vec_srl(vector signed char a, vector unsigned int b) +vec_vxor(vector signed char a, vector bool char b) { - return (vector signed char)__builtin_altivec_vsr((vector int)a, (vector int)b); + return a ^ (vector signed char)b; } static vector unsigned char __ATTRS_o_ai -vec_srl(vector unsigned char a, vector unsigned char b) +vec_vxor(vector unsigned char a, vector unsigned char b) { - return (vector unsigned char)__builtin_altivec_vsr((vector int)a, (vector int)b); + return a ^ b; } static vector unsigned char __ATTRS_o_ai -vec_srl(vector unsigned char a, vector unsigned short b) +vec_vxor(vector bool char a, vector unsigned char b) { - return (vector unsigned char)__builtin_altivec_vsr((vector int)a, (vector int)b); + return (vector unsigned char)a ^ b; } static vector unsigned char __ATTRS_o_ai -vec_srl(vector unsigned char a, vector unsigned int b) +vec_vxor(vector unsigned char a, vector bool char b) { - return (vector unsigned char)__builtin_altivec_vsr((vector int)a, (vector int)b); + return a ^ (vector unsigned char)b; +} + +static vector bool char __ATTRS_o_ai +vec_vxor(vector bool char a, vector bool char b) +{ + return a ^ b; } static vector short __ATTRS_o_ai -vec_srl(vector short a, vector unsigned char b) +vec_vxor(vector short a, vector short b) { - return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b); + return a ^ b; } static vector short __ATTRS_o_ai -vec_srl(vector short a, vector unsigned short b) +vec_vxor(vector bool short a, vector short b) { - return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b); + return (vector short)a ^ b; } static vector short __ATTRS_o_ai -vec_srl(vector short a, vector unsigned int b) +vec_vxor(vector short a, vector bool short b) { - return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b); + return a ^ (vector short)b; } static vector unsigned short __ATTRS_o_ai -vec_srl(vector unsigned short a, vector unsigned char b) +vec_vxor(vector unsigned short a, vector unsigned short b) { - return (vector unsigned short)__builtin_altivec_vsr((vector int)a, (vector int)b); + return a ^ b; } static vector unsigned short __ATTRS_o_ai -vec_srl(vector unsigned short a, vector unsigned short b) +vec_vxor(vector bool short a, vector unsigned short b) { - return (vector unsigned short)__builtin_altivec_vsr((vector int)a, (vector int)b); + return (vector unsigned short)a ^ b; } static vector unsigned short __ATTRS_o_ai -vec_srl(vector unsigned short a, vector unsigned int b) +vec_vxor(vector unsigned short a, vector bool short b) { - return (vector unsigned short)__builtin_altivec_vsr((vector int)a, (vector int)b); + return a ^ (vector unsigned short)b; } -static vector int __ATTRS_o_ai -vec_srl(vector int a, vector unsigned char b) +static vector bool short __ATTRS_o_ai +vec_vxor(vector bool short a, vector bool short b) { - return (vector int)__builtin_altivec_vsr(a, (vector int)b); + return a ^ b; } static vector int __ATTRS_o_ai -vec_srl(vector int a, vector unsigned short b) +vec_vxor(vector int a, vector int b) { - return (vector int)__builtin_altivec_vsr(a, (vector int)b); + return a ^ b; } static vector int __ATTRS_o_ai -vec_srl(vector int a, vector unsigned int b) +vec_vxor(vector bool int a, vector int b) { - return (vector int)__builtin_altivec_vsr(a, (vector int)b); + return (vector int)a ^ b; } -static vector unsigned int __ATTRS_o_ai -vec_srl(vector unsigned int a, vector unsigned char b) +static vector int __ATTRS_o_ai +vec_vxor(vector int a, vector bool int b) { - return (vector unsigned int)__builtin_altivec_vsr((vector int)a, (vector int)b); + return a ^ (vector int)b; } static vector unsigned int __ATTRS_o_ai -vec_srl(vector unsigned int a, vector unsigned short b) +vec_vxor(vector unsigned int a, vector unsigned int b) { - return (vector unsigned int)__builtin_altivec_vsr((vector int)a, (vector int)b); + return a ^ b; } static vector unsigned int __ATTRS_o_ai -vec_srl(vector unsigned int a, vector unsigned int b) +vec_vxor(vector bool int a, vector unsigned int b) { - return (vector unsigned int)__builtin_altivec_vsr((vector int)a, (vector int)b); + return (vector unsigned int)a ^ b; } -/* vec_vsr */ - -static vector signed char __ATTRS_o_ai -vec_vsr(vector signed char a, vector unsigned char b) +static vector unsigned int __ATTRS_o_ai +vec_vxor(vector unsigned int a, vector bool int b) { - return (vector signed char)__builtin_altivec_vsr((vector int)a, (vector int)b); + return a ^ (vector unsigned int)b; } -static vector signed char __ATTRS_o_ai -vec_vsr(vector signed char a, vector unsigned short b) +static vector bool int __ATTRS_o_ai +vec_vxor(vector bool int a, vector bool int b) { - return (vector signed char)__builtin_altivec_vsr((vector int)a, (vector int)b); + return a ^ b; } -static vector signed char __ATTRS_o_ai -vec_vsr(vector signed char a, vector unsigned int b) +static vector float __ATTRS_o_ai +vec_vxor(vector float a, vector float b) { - return (vector signed char)__builtin_altivec_vsr((vector int)a, (vector int)b); + vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b; + return (vector float)res; } -static vector unsigned char __ATTRS_o_ai -vec_vsr(vector unsigned char a, vector unsigned char b) +static vector float __ATTRS_o_ai +vec_vxor(vector bool int a, vector float b) { - return (vector unsigned char)__builtin_altivec_vsr((vector int)a, (vector int)b); + vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b; + return (vector float)res; } -static vector unsigned char __ATTRS_o_ai -vec_vsr(vector unsigned char a, vector unsigned short b) +static vector float __ATTRS_o_ai +vec_vxor(vector float a, vector bool int b) { - return (vector unsigned char)__builtin_altivec_vsr((vector int)a, (vector int)b); + vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b; + return (vector float)res; } -static vector unsigned char __ATTRS_o_ai -vec_vsr(vector unsigned char a, vector unsigned int b) -{ - return (vector unsigned char)__builtin_altivec_vsr((vector int)a, (vector int)b); -} +/* ------------------------------ predicates ------------------------------------ */ -static vector short __ATTRS_o_ai -vec_vsr(vector short a, vector unsigned char b) -{ - return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b); -} +/* vec_all_eq */ -static vector short __ATTRS_o_ai -vec_vsr(vector short a, vector unsigned short b) +static int __ATTRS_o_ai +vec_all_eq(vector signed char a, vector signed char b) { - return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b); } -static vector short __ATTRS_o_ai -vec_vsr(vector short a, vector unsigned int b) +static int __ATTRS_o_ai +vec_all_eq(vector signed char a, vector bool char b) { - return (vector short)__builtin_altivec_vsr((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b); } -static vector unsigned short __ATTRS_o_ai -vec_vsr(vector unsigned short a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_eq(vector unsigned char a, vector unsigned char b) { - return (vector unsigned short)__builtin_altivec_vsr((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b); } -static vector unsigned short __ATTRS_o_ai -vec_vsr(vector unsigned short a, vector unsigned short b) +static int __ATTRS_o_ai +vec_all_eq(vector unsigned char a, vector bool char b) { - return (vector unsigned short)__builtin_altivec_vsr((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b); } -static vector unsigned short __ATTRS_o_ai -vec_vsr(vector unsigned short a, vector unsigned int b) +static int __ATTRS_o_ai +vec_all_eq(vector bool char a, vector signed char b) { - return (vector unsigned short)__builtin_altivec_vsr((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b); } -static vector int __ATTRS_o_ai -vec_vsr(vector int a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_eq(vector bool char a, vector unsigned char b) { - return (vector int)__builtin_altivec_vsr(a, (vector int)b); + return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b); } -static vector int __ATTRS_o_ai -vec_vsr(vector int a, vector unsigned short b) +static int __ATTRS_o_ai +vec_all_eq(vector bool char a, vector bool char b) { - return (vector int)__builtin_altivec_vsr(a, (vector int)b); + return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b); } -static vector int __ATTRS_o_ai -vec_vsr(vector int a, vector unsigned int b) +static int __ATTRS_o_ai +vec_all_eq(vector short a, vector short b) { - return (vector int)__builtin_altivec_vsr(a, (vector int)b); + return __builtin_altivec_vcmpequh_p(__CR6_LT, a, b); } -static vector unsigned int __ATTRS_o_ai -vec_vsr(vector unsigned int a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_eq(vector short a, vector bool short b) { - return (vector unsigned int)__builtin_altivec_vsr((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequh_p(__CR6_LT, a, (vector short)b); } -static vector unsigned int __ATTRS_o_ai -vec_vsr(vector unsigned int a, vector unsigned short b) +static int __ATTRS_o_ai +vec_all_eq(vector unsigned short a, vector unsigned short b) { - return (vector unsigned int)__builtin_altivec_vsr((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b); } -static vector unsigned int __ATTRS_o_ai -vec_vsr(vector unsigned int a, vector unsigned int b) +static int __ATTRS_o_ai +vec_all_eq(vector unsigned short a, vector bool short b) { - return (vector unsigned int)__builtin_altivec_vsr((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b); } -/* vec_sro */ - -static vector signed char __ATTRS_o_ai -vec_sro(vector signed char a, vector signed char b) +static int __ATTRS_o_ai +vec_all_eq(vector bool short a, vector short b) { - return (vector signed char)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b); } -static vector signed char __ATTRS_o_ai -vec_sro(vector signed char a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_eq(vector bool short a, vector unsigned short b) { - return (vector signed char)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b); } -static vector unsigned char __ATTRS_o_ai -vec_sro(vector unsigned char a, vector signed char b) +static int __ATTRS_o_ai +vec_all_eq(vector bool short a, vector bool short b) { - return (vector unsigned char)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b); } -static vector unsigned char __ATTRS_o_ai -vec_sro(vector unsigned char a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_eq(vector pixel a, vector pixel b) { - return (vector unsigned char)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b); } -static vector short __ATTRS_o_ai -vec_sro(vector short a, vector signed char b) +static int __ATTRS_o_ai +vec_all_eq(vector int a, vector int b) { - return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequw_p(__CR6_LT, a, b); } -static vector short __ATTRS_o_ai -vec_sro(vector short a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_eq(vector int a, vector bool int b) { - return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequw_p(__CR6_LT, a, (vector int)b); } -static vector unsigned short __ATTRS_o_ai -vec_sro(vector unsigned short a, vector signed char b) +static int __ATTRS_o_ai +vec_all_eq(vector unsigned int a, vector unsigned int b) { - return (vector unsigned short)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b); } -static vector unsigned short __ATTRS_o_ai -vec_sro(vector unsigned short a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_eq(vector unsigned int a, vector bool int b) { - return (vector unsigned short)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b); } -static vector int __ATTRS_o_ai -vec_sro(vector int a, vector signed char b) +static int __ATTRS_o_ai +vec_all_eq(vector bool int a, vector int b) { - return (vector int)__builtin_altivec_vsro(a, (vector int)b); + return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b); } -static vector int __ATTRS_o_ai -vec_sro(vector int a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_eq(vector bool int a, vector unsigned int b) { - return (vector int)__builtin_altivec_vsro(a, (vector int)b); + return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b); } -static vector unsigned int __ATTRS_o_ai -vec_sro(vector unsigned int a, vector signed char b) +static int __ATTRS_o_ai +vec_all_eq(vector bool int a, vector bool int b) { - return (vector unsigned int)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b); } -static vector unsigned int __ATTRS_o_ai -vec_sro(vector unsigned int a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_eq(vector float a, vector float b) { - return (vector unsigned int)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, b); } -static vector float __ATTRS_o_ai -vec_sro(vector float a, vector signed char b) +/* vec_all_ge */ + +static int __ATTRS_o_ai +vec_all_ge(vector signed char a, vector signed char b) { - return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, b, a); } -static vector float __ATTRS_o_ai -vec_sro(vector float a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_ge(vector signed char a, vector bool char b) { - return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, (vector signed char)b, a); } -/* vec_vsro */ - -static vector signed char __ATTRS_o_ai -vec_vsro(vector signed char a, vector signed char b) +static int __ATTRS_o_ai +vec_all_ge(vector unsigned char a, vector unsigned char b) { - return (vector signed char)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ, b, a); } -static vector signed char __ATTRS_o_ai -vec_vsro(vector signed char a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_ge(vector unsigned char a, vector bool char b) { - return (vector signed char)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)b, a); } -static vector unsigned char __ATTRS_o_ai -vec_vsro(vector unsigned char a, vector signed char b) +static int __ATTRS_o_ai +vec_all_ge(vector bool char a, vector signed char b) { - return (vector unsigned char)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)b, + (vector unsigned char)a); } -static vector unsigned char __ATTRS_o_ai -vec_vsro(vector unsigned char a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_ge(vector bool char a, vector unsigned char b) { - return (vector unsigned char)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ, b, (vector unsigned char)a); } -static vector short __ATTRS_o_ai -vec_vsro(vector short a, vector signed char b) +static int __ATTRS_o_ai +vec_all_ge(vector bool char a, vector bool char b) { - return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)b, + (vector unsigned char)a); } -static vector short __ATTRS_o_ai -vec_vsro(vector short a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_ge(vector short a, vector short b) { - return (vector short)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, b, a); } -static vector unsigned short __ATTRS_o_ai -vec_vsro(vector unsigned short a, vector signed char b) +static int __ATTRS_o_ai +vec_all_ge(vector short a, vector bool short b) { - return (vector unsigned short)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, (vector short)b, a); } -static vector unsigned short __ATTRS_o_ai -vec_vsro(vector unsigned short a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_ge(vector unsigned short a, vector unsigned short b) { - return (vector unsigned short)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, b, a); } -static vector int __ATTRS_o_ai -vec_vsro(vector int a, vector signed char b) +static int __ATTRS_o_ai +vec_all_ge(vector unsigned short a, vector bool short b) { - return (vector int)__builtin_altivec_vsro(a, (vector int)b); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)b, a); } -static vector int __ATTRS_o_ai -vec_vsro(vector int a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_ge(vector bool short a, vector short b) { - return (vector int)__builtin_altivec_vsro(a, (vector int)b); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)b, + (vector unsigned short)a); } -static vector unsigned int __ATTRS_o_ai -vec_vsro(vector unsigned int a, vector signed char b) +static int __ATTRS_o_ai +vec_all_ge(vector bool short a, vector unsigned short b) { - return (vector unsigned int)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, b, (vector unsigned short)a); } -static vector unsigned int __ATTRS_o_ai -vec_vsro(vector unsigned int a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_ge(vector bool short a, vector bool short b) { - return (vector unsigned int)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)b, + (vector unsigned short)a); } -static vector float __ATTRS_o_ai -vec_vsro(vector float a, vector signed char b) +static int __ATTRS_o_ai +vec_all_ge(vector int a, vector int b) { - return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, b, a); } -static vector float __ATTRS_o_ai -vec_vsro(vector float a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_ge(vector int a, vector bool int b) { - return (vector float)__builtin_altivec_vsro((vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, (vector int)b, a); } -/* vec_st */ - -static void __ATTRS_o_ai -vec_st(vector signed char a, int b, vector signed char *c) +static int __ATTRS_o_ai +vec_all_ge(vector unsigned int a, vector unsigned int b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, b, a); } -static void __ATTRS_o_ai -vec_st(vector signed char a, int b, signed char *c) +static int __ATTRS_o_ai +vec_all_ge(vector unsigned int a, vector bool int b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)b, a); } -static void __ATTRS_o_ai -vec_st(vector unsigned char a, int b, vector unsigned char *c) +static int __ATTRS_o_ai +vec_all_ge(vector bool int a, vector int b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)b, + (vector unsigned int)a); } -static void __ATTRS_o_ai -vec_st(vector unsigned char a, int b, unsigned char *c) +static int __ATTRS_o_ai +vec_all_ge(vector bool int a, vector unsigned int b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, b, (vector unsigned int)a); } -static void __ATTRS_o_ai -vec_st(vector short a, int b, vector short *c) +static int __ATTRS_o_ai +vec_all_ge(vector bool int a, vector bool int b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)b, + (vector unsigned int)a); } -static void __ATTRS_o_ai -vec_st(vector short a, int b, short *c) +static int __ATTRS_o_ai +vec_all_ge(vector float a, vector float b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgefp_p(__CR6_LT, a, b); } -static void __ATTRS_o_ai -vec_st(vector unsigned short a, int b, vector unsigned short *c) +/* vec_all_gt */ + +static int __ATTRS_o_ai +vec_all_gt(vector signed char a, vector signed char b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtsb_p(__CR6_LT, a, b); } -static void __ATTRS_o_ai -vec_st(vector unsigned short a, int b, unsigned short *c) +static int __ATTRS_o_ai +vec_all_gt(vector signed char a, vector bool char b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtsb_p(__CR6_LT, a, (vector signed char)b); } -static void __ATTRS_o_ai -vec_st(vector int a, int b, vector int *c) +static int __ATTRS_o_ai +vec_all_gt(vector unsigned char a, vector unsigned char b) { - __builtin_altivec_stvx(a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_LT, a, b); } -static void __ATTRS_o_ai -vec_st(vector int a, int b, int *c) +static int __ATTRS_o_ai +vec_all_gt(vector unsigned char a, vector bool char b) { - __builtin_altivec_stvx(a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_LT, a, (vector unsigned char)b); } -static void __ATTRS_o_ai -vec_st(vector unsigned int a, int b, vector unsigned int *c) +static int __ATTRS_o_ai +vec_all_gt(vector bool char a, vector signed char b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)a, + (vector unsigned char)b); } -static void __ATTRS_o_ai -vec_st(vector unsigned int a, int b, unsigned int *c) +static int __ATTRS_o_ai +vec_all_gt(vector bool char a, vector unsigned char b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)a, b); } -static void __ATTRS_o_ai -vec_st(vector float a, int b, vector float *c) +static int __ATTRS_o_ai +vec_all_gt(vector bool char a, vector bool char b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)a, + (vector unsigned char)b); } -static void __ATTRS_o_ai -vec_st(vector float a, int b, float *c) +static int __ATTRS_o_ai +vec_all_gt(vector short a, vector short b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtsh_p(__CR6_LT, a, b); } -/* vec_stvx */ +static int __ATTRS_o_ai +vec_all_gt(vector short a, vector bool short b) +{ + return __builtin_altivec_vcmpgtsh_p(__CR6_LT, a, (vector short)b); +} -static void __ATTRS_o_ai -vec_stvx(vector signed char a, int b, vector signed char *c) +static int __ATTRS_o_ai +vec_all_gt(vector unsigned short a, vector unsigned short b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_LT, a, b); } -static void __ATTRS_o_ai -vec_stvx(vector signed char a, int b, signed char *c) +static int __ATTRS_o_ai +vec_all_gt(vector unsigned short a, vector bool short b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_LT, a, (vector unsigned short)b); } -static void __ATTRS_o_ai -vec_stvx(vector unsigned char a, int b, vector unsigned char *c) +static int __ATTRS_o_ai +vec_all_gt(vector bool short a, vector short b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)a, + (vector unsigned short)b); } -static void __ATTRS_o_ai -vec_stvx(vector unsigned char a, int b, unsigned char *c) +static int __ATTRS_o_ai +vec_all_gt(vector bool short a, vector unsigned short b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)a, b); } -static void __ATTRS_o_ai -vec_stvx(vector short a, int b, vector short *c) +static int __ATTRS_o_ai +vec_all_gt(vector bool short a, vector bool short b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)a, + (vector unsigned short)b); } -static void __ATTRS_o_ai -vec_stvx(vector short a, int b, short *c) +static int __ATTRS_o_ai +vec_all_gt(vector int a, vector int b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtsw_p(__CR6_LT, a, b); } -static void __ATTRS_o_ai -vec_stvx(vector unsigned short a, int b, vector unsigned short *c) +static int __ATTRS_o_ai +vec_all_gt(vector int a, vector bool int b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtsw_p(__CR6_LT, a, (vector int)b); } -static void __ATTRS_o_ai -vec_stvx(vector unsigned short a, int b, unsigned short *c) +static int __ATTRS_o_ai +vec_all_gt(vector unsigned int a, vector unsigned int b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT, a, b); } -static void __ATTRS_o_ai -vec_stvx(vector int a, int b, vector int *c) +static int __ATTRS_o_ai +vec_all_gt(vector unsigned int a, vector bool int b) { - __builtin_altivec_stvx(a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT, a, (vector unsigned int)b); } -static void __ATTRS_o_ai -vec_stvx(vector int a, int b, int *c) +static int __ATTRS_o_ai +vec_all_gt(vector bool int a, vector int b) { - __builtin_altivec_stvx(a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)a, + (vector unsigned int)b); } -static void __ATTRS_o_ai -vec_stvx(vector unsigned int a, int b, vector unsigned int *c) +static int __ATTRS_o_ai +vec_all_gt(vector bool int a, vector unsigned int b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)a, b); } -static void __ATTRS_o_ai -vec_stvx(vector unsigned int a, int b, unsigned int *c) +static int __ATTRS_o_ai +vec_all_gt(vector bool int a, vector bool int b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)a, + (vector unsigned int)b); } -static void __ATTRS_o_ai -vec_stvx(vector float a, int b, vector float *c) +static int __ATTRS_o_ai +vec_all_gt(vector float a, vector float b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpgtfp_p(__CR6_LT, a, b); } -static void __ATTRS_o_ai -vec_stvx(vector float a, int b, float *c) +/* vec_all_in */ + +static int __attribute__((__always_inline__)) +vec_all_in(vector float a, vector float b) { - __builtin_altivec_stvx((vector int)a, b, c); + return __builtin_altivec_vcmpbfp_p(__CR6_EQ, a, b); } -/* vec_ste */ +/* vec_all_le */ -static void __ATTRS_o_ai -vec_ste(vector signed char a, int b, signed char *c) +static int __ATTRS_o_ai +vec_all_le(vector signed char a, vector signed char b) { - __builtin_altivec_stvebx((vector char)a, b, c); + return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, a, b); } -static void __ATTRS_o_ai -vec_ste(vector unsigned char a, int b, unsigned char *c) +static int __ATTRS_o_ai +vec_all_le(vector signed char a, vector bool char b) { - __builtin_altivec_stvebx((vector char)a, b, c); + return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, a, (vector signed char)b); } -static void __ATTRS_o_ai -vec_ste(vector short a, int b, short *c) +static int __ATTRS_o_ai +vec_all_le(vector unsigned char a, vector unsigned char b) { - __builtin_altivec_stvehx(a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ, a, b); } -static void __ATTRS_o_ai -vec_ste(vector unsigned short a, int b, unsigned short *c) +static int __ATTRS_o_ai +vec_all_le(vector unsigned char a, vector bool char b) { - __builtin_altivec_stvehx((vector short)a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ, a, (vector unsigned char)b); } -static void __ATTRS_o_ai -vec_ste(vector int a, int b, int *c) +static int __ATTRS_o_ai +vec_all_le(vector bool char a, vector signed char b) { - __builtin_altivec_stvewx(a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)a, + (vector unsigned char)b); } -static void __ATTRS_o_ai -vec_ste(vector unsigned int a, int b, unsigned int *c) +static int __ATTRS_o_ai +vec_all_le(vector bool char a, vector unsigned char b) { - __builtin_altivec_stvewx((vector int)a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)a, b); } -static void __ATTRS_o_ai -vec_ste(vector float a, int b, float *c) +static int __ATTRS_o_ai +vec_all_le(vector bool char a, vector bool char b) { - __builtin_altivec_stvewx((vector int)a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ, (vector unsigned char)a, + (vector unsigned char)b); } -/* vec_stvebx */ - -static void __ATTRS_o_ai -vec_stvebx(vector signed char a, int b, signed char *c) +static int __ATTRS_o_ai +vec_all_le(vector short a, vector short b) { - __builtin_altivec_stvebx((vector char)a, b, c); + return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, a, b); } -static void __ATTRS_o_ai -vec_stvebx(vector unsigned char a, int b, unsigned char *c) +static int __ATTRS_o_ai +vec_all_le(vector short a, vector bool short b) { - __builtin_altivec_stvebx((vector char)a, b, c); + return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, a, (vector short)b); } -/* vec_stvehx */ - -static void __ATTRS_o_ai -vec_stvehx(vector short a, int b, short *c) +static int __ATTRS_o_ai +vec_all_le(vector unsigned short a, vector unsigned short b) { - __builtin_altivec_stvehx(a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, a, b); } -static void __ATTRS_o_ai -vec_stvehx(vector unsigned short a, int b, unsigned short *c) +static int __ATTRS_o_ai +vec_all_le(vector unsigned short a, vector bool short b) { - __builtin_altivec_stvehx((vector short)a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, a, (vector unsigned short)b); } -/* vec_stvewx */ - -static void __ATTRS_o_ai -vec_stvewx(vector int a, int b, int *c) +static int __ATTRS_o_ai +vec_all_le(vector bool short a, vector short b) { - __builtin_altivec_stvewx(a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)a, + (vector unsigned short)b); } -static void __ATTRS_o_ai -vec_stvewx(vector unsigned int a, int b, unsigned int *c) +static int __ATTRS_o_ai +vec_all_le(vector bool short a, vector unsigned short b) { - __builtin_altivec_stvewx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)a, b); } -static void __ATTRS_o_ai -vec_stvewx(vector float a, int b, float *c) +static int __ATTRS_o_ai +vec_all_le(vector bool short a, vector bool short b) { - __builtin_altivec_stvewx((vector int)a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, (vector unsigned short)a, + (vector unsigned short)b); } -/* vec_stl */ +static int __ATTRS_o_ai +vec_all_le(vector int a, vector int b) +{ + return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, a, b); +} -static void __ATTRS_o_ai -vec_stl(vector signed char a, int b, vector signed char *c) +static int __ATTRS_o_ai +vec_all_le(vector int a, vector bool int b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, a, (vector int)b); } -static void __ATTRS_o_ai -vec_stl(vector signed char a, int b, signed char *c) +static int __ATTRS_o_ai +vec_all_le(vector unsigned int a, vector unsigned int b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, a, b); } -static void __ATTRS_o_ai -vec_stl(vector unsigned char a, int b, vector unsigned char *c) +static int __ATTRS_o_ai +vec_all_le(vector unsigned int a, vector bool int b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, a, (vector unsigned int)b); } -static void __ATTRS_o_ai -vec_stl(vector unsigned char a, int b, unsigned char *c) +static int __ATTRS_o_ai +vec_all_le(vector bool int a, vector int b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)a, + (vector unsigned int)b); } -static void __ATTRS_o_ai -vec_stl(vector short a, int b, vector short *c) +static int __ATTRS_o_ai +vec_all_le(vector bool int a, vector unsigned int b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)a, b); } -static void __ATTRS_o_ai -vec_stl(vector short a, int b, short *c) +static int __ATTRS_o_ai +vec_all_le(vector bool int a, vector bool int b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, (vector unsigned int)a, + (vector unsigned int)b); } -static void __ATTRS_o_ai -vec_stl(vector unsigned short a, int b, vector unsigned short *c) +static int __ATTRS_o_ai +vec_all_le(vector float a, vector float b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgefp_p(__CR6_LT, b, a); } -static void __ATTRS_o_ai -vec_stl(vector unsigned short a, int b, unsigned short *c) +/* vec_all_lt */ + +static int __ATTRS_o_ai +vec_all_lt(vector signed char a, vector signed char b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtsb_p(__CR6_LT, b, a); } -static void __ATTRS_o_ai -vec_stl(vector int a, int b, vector int *c) +static int __ATTRS_o_ai +vec_all_lt(vector signed char a, vector bool char b) { - __builtin_altivec_stvxl(a, b, c); + return __builtin_altivec_vcmpgtsb_p(__CR6_LT, (vector signed char)b, a); } -static void __ATTRS_o_ai -vec_stl(vector int a, int b, int *c) +static int __ATTRS_o_ai +vec_all_lt(vector unsigned char a, vector unsigned char b) { - __builtin_altivec_stvxl(a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_LT, b, a); } -static void __ATTRS_o_ai -vec_stl(vector unsigned int a, int b, vector unsigned int *c) +static int __ATTRS_o_ai +vec_all_lt(vector unsigned char a, vector bool char b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)b, a); } -static void __ATTRS_o_ai -vec_stl(vector unsigned int a, int b, unsigned int *c) +static int __ATTRS_o_ai +vec_all_lt(vector bool char a, vector signed char b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)b, + (vector unsigned char)a); } -static void __ATTRS_o_ai -vec_stl(vector float a, int b, vector float *c) +static int __ATTRS_o_ai +vec_all_lt(vector bool char a, vector unsigned char b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_LT, b, (vector unsigned char)a); } -static void __ATTRS_o_ai -vec_stl(vector float a, int b, float *c) +static int __ATTRS_o_ai +vec_all_lt(vector bool char a, vector bool char b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtub_p(__CR6_LT, (vector unsigned char)b, + (vector unsigned char)a); } -/* vec_stvxl */ +static int __ATTRS_o_ai +vec_all_lt(vector short a, vector short b) +{ + return __builtin_altivec_vcmpgtsh_p(__CR6_LT, b, a); +} -static void __ATTRS_o_ai -vec_stvxl(vector signed char a, int b, vector signed char *c) +static int __ATTRS_o_ai +vec_all_lt(vector short a, vector bool short b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtsh_p(__CR6_LT, (vector short)b, a); } -static void __ATTRS_o_ai -vec_stvxl(vector signed char a, int b, signed char *c) +static int __ATTRS_o_ai +vec_all_lt(vector unsigned short a, vector unsigned short b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_LT, b, a); } -static void __ATTRS_o_ai -vec_stvxl(vector unsigned char a, int b, vector unsigned char *c) +static int __ATTRS_o_ai +vec_all_lt(vector unsigned short a, vector bool short b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)b, a); } -static void __ATTRS_o_ai -vec_stvxl(vector unsigned char a, int b, unsigned char *c) +static int __ATTRS_o_ai +vec_all_lt(vector bool short a, vector short b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)b, + (vector unsigned short)a); } -static void __ATTRS_o_ai -vec_stvxl(vector short a, int b, vector short *c) +static int __ATTRS_o_ai +vec_all_lt(vector bool short a, vector unsigned short b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_LT, b, (vector unsigned short)a); } -static void __ATTRS_o_ai -vec_stvxl(vector short a, int b, short *c) +static int __ATTRS_o_ai +vec_all_lt(vector bool short a, vector bool short b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtuh_p(__CR6_LT, (vector unsigned short)b, + (vector unsigned short)a); } -static void __ATTRS_o_ai -vec_stvxl(vector unsigned short a, int b, vector unsigned short *c) +static int __ATTRS_o_ai +vec_all_lt(vector int a, vector int b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtsw_p(__CR6_LT, b, a); } -static void __ATTRS_o_ai -vec_stvxl(vector unsigned short a, int b, unsigned short *c) +static int __ATTRS_o_ai +vec_all_lt(vector int a, vector bool int b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtsw_p(__CR6_LT, (vector int)b, a); } -static void __ATTRS_o_ai -vec_stvxl(vector int a, int b, vector int *c) +static int __ATTRS_o_ai +vec_all_lt(vector unsigned int a, vector unsigned int b) { - __builtin_altivec_stvxl(a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT, b, a); } -static void __ATTRS_o_ai -vec_stvxl(vector int a, int b, int *c) +static int __ATTRS_o_ai +vec_all_lt(vector unsigned int a, vector bool int b) { - __builtin_altivec_stvxl(a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)b, a); } -static void __ATTRS_o_ai -vec_stvxl(vector unsigned int a, int b, vector unsigned int *c) +static int __ATTRS_o_ai +vec_all_lt(vector bool int a, vector int b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)b, + (vector unsigned int)a); } -static void __ATTRS_o_ai -vec_stvxl(vector unsigned int a, int b, unsigned int *c) +static int __ATTRS_o_ai +vec_all_lt(vector bool int a, vector unsigned int b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT, b, (vector unsigned int)a); } -static void __ATTRS_o_ai -vec_stvxl(vector float a, int b, vector float *c) +static int __ATTRS_o_ai +vec_all_lt(vector bool int a, vector bool int b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT, (vector unsigned int)b, + (vector unsigned int)a); } -static void __ATTRS_o_ai -vec_stvxl(vector float a, int b, float *c) +static int __ATTRS_o_ai +vec_all_lt(vector float a, vector float b) { - __builtin_altivec_stvxl((vector int)a, b, c); + return __builtin_altivec_vcmpgtfp_p(__CR6_LT, b, a); } -/* vec_sub */ +/* vec_all_nan */ -static vector signed char __ATTRS_o_ai -vec_sub(vector signed char a, vector signed char b) +static int __attribute__((__always_inline__)) +vec_all_nan(vector float a) { - return a - b; + return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, a); } -static vector unsigned char __ATTRS_o_ai -vec_sub(vector unsigned char a, vector unsigned char b) +/* vec_all_ne */ + +static int __ATTRS_o_ai +vec_all_ne(vector signed char a, vector signed char b) { - return a - b; + return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b); } -static vector short __ATTRS_o_ai -vec_sub(vector short a, vector short b) +static int __ATTRS_o_ai +vec_all_ne(vector signed char a, vector bool char b) { - return a - b; + return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b); } -static vector unsigned short __ATTRS_o_ai -vec_sub(vector unsigned short a, vector unsigned short b) +static int __ATTRS_o_ai +vec_all_ne(vector unsigned char a, vector unsigned char b) { - return a - b; + return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b); } -static vector int __ATTRS_o_ai -vec_sub(vector int a, vector int b) +static int __ATTRS_o_ai +vec_all_ne(vector unsigned char a, vector bool char b) { - return a - b; + return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b); } -static vector unsigned int __ATTRS_o_ai -vec_sub(vector unsigned int a, vector unsigned int b) +static int __ATTRS_o_ai +vec_all_ne(vector bool char a, vector signed char b) { - return a - b; + return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b); } -static vector float __ATTRS_o_ai -vec_sub(vector float a, vector float b) +static int __ATTRS_o_ai +vec_all_ne(vector bool char a, vector unsigned char b) { - return a - b; + return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b); } -/* vec_vsububm */ - -#define __builtin_altivec_vsububm vec_vsububm - -static vector signed char __ATTRS_o_ai -vec_vsububm(vector signed char a, vector signed char b) +static int __ATTRS_o_ai +vec_all_ne(vector bool char a, vector bool char b) { - return a - b; + return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b); } -static vector unsigned char __ATTRS_o_ai -vec_vsububm(vector unsigned char a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_ne(vector short a, vector short b) { - return a - b; + return __builtin_altivec_vcmpequh_p(__CR6_EQ, a, b); } -/* vec_vsubuhm */ - -#define __builtin_altivec_vsubuhm vec_vsubuhm - -static vector short __ATTRS_o_ai -vec_vsubuhm(vector short a, vector short b) +static int __ATTRS_o_ai +vec_all_ne(vector short a, vector bool short b) { - return a - b; + return __builtin_altivec_vcmpequh_p(__CR6_EQ, a, (vector short)b); } -static vector unsigned short __ATTRS_o_ai -vec_vsubuhm(vector unsigned short a, vector unsigned short b) +static int __ATTRS_o_ai +vec_all_ne(vector unsigned short a, vector unsigned short b) { - return a - b; + return __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b); } -/* vec_vsubuwm */ - -#define __builtin_altivec_vsubuwm vec_vsubuwm - -static vector int __ATTRS_o_ai -vec_vsubuwm(vector int a, vector int b) +static int __ATTRS_o_ai +vec_all_ne(vector unsigned short a, vector bool short b) { - return a - b; + return __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b); } -static vector unsigned int __ATTRS_o_ai -vec_vsubuwm(vector unsigned int a, vector unsigned int b) +static int __ATTRS_o_ai +vec_all_ne(vector bool short a, vector short b) { - return a - b; + return __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b); } -/* vec_vsubfp */ - -#define __builtin_altivec_vsubfp vec_vsubfp - -static vector float __attribute__((__always_inline__)) -vec_vsubfp(vector float a, vector float b) +static int __ATTRS_o_ai +vec_all_ne(vector bool short a, vector unsigned short b) { - return a - b; + return __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b); } -/* vec_subc */ +static int __ATTRS_o_ai +vec_all_ne(vector bool short a, vector bool short b) +{ + return __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b); +} -static vector unsigned int __attribute__((__always_inline__)) -vec_subc(vector unsigned int a, vector unsigned int b) +static int __ATTRS_o_ai +vec_all_ne(vector pixel a, vector pixel b) { - return __builtin_altivec_vsubcuw(a, b); + return __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b); } -/* vec_vsubcuw */ +static int __ATTRS_o_ai +vec_all_ne(vector int a, vector int b) +{ + return __builtin_altivec_vcmpequw_p(__CR6_EQ, a, b); +} -static vector unsigned int __attribute__((__always_inline__)) -vec_vsubcuw(vector unsigned int a, vector unsigned int b) +static int __ATTRS_o_ai +vec_all_ne(vector int a, vector bool int b) { - return __builtin_altivec_vsubcuw(a, b); + return __builtin_altivec_vcmpequw_p(__CR6_EQ, a, (vector int)b); } -/* vec_subs */ +static int __ATTRS_o_ai +vec_all_ne(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b); +} -static vector signed char __ATTRS_o_ai -vec_subs(vector signed char a, vector signed char b) +static int __ATTRS_o_ai +vec_all_ne(vector unsigned int a, vector bool int b) { - return __builtin_altivec_vsubsbs(a, b); + return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b); } -static vector unsigned char __ATTRS_o_ai -vec_subs(vector unsigned char a, vector unsigned char b) +static int __ATTRS_o_ai +vec_all_ne(vector bool int a, vector int b) { - return __builtin_altivec_vsububs(a, b); + return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b); } -static vector short __ATTRS_o_ai -vec_subs(vector short a, vector short b) +static int __ATTRS_o_ai +vec_all_ne(vector bool int a, vector unsigned int b) { - return __builtin_altivec_vsubshs(a, b); + return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b); } -static vector unsigned short __ATTRS_o_ai -vec_subs(vector unsigned short a, vector unsigned short b) +static int __ATTRS_o_ai +vec_all_ne(vector bool int a, vector bool int b) { - return __builtin_altivec_vsubuhs(a, b); + return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b); } -static vector int __ATTRS_o_ai -vec_subs(vector int a, vector int b) +static int __ATTRS_o_ai +vec_all_ne(vector float a, vector float b) { - return __builtin_altivec_vsubsws(a, b); + return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, b); } -static vector unsigned int __ATTRS_o_ai -vec_subs(vector unsigned int a, vector unsigned int b) +/* vec_all_nge */ + +static int __attribute__((__always_inline__)) +vec_all_nge(vector float a, vector float b) { - return __builtin_altivec_vsubuws(a, b); + return __builtin_altivec_vcmpgefp_p(__CR6_EQ, a, b); } -/* vec_vsubsbs */ +/* vec_all_ngt */ -static vector signed char __attribute__((__always_inline__)) -vec_vsubsbs(vector signed char a, vector signed char b) +static int __attribute__((__always_inline__)) +vec_all_ngt(vector float a, vector float b) { - return __builtin_altivec_vsubsbs(a, b); + return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, a, b); } -/* vec_vsububs */ +/* vec_all_nle */ -static vector unsigned char __attribute__((__always_inline__)) -vec_vsububs(vector unsigned char a, vector unsigned char b) +static int __attribute__((__always_inline__)) +vec_all_nle(vector float a, vector float b) { - return __builtin_altivec_vsububs(a, b); + return __builtin_altivec_vcmpgefp_p(__CR6_EQ, b, a); } -/* vec_vsubshs */ +/* vec_all_nlt */ -static vector short __attribute__((__always_inline__)) -vec_vsubshs(vector short a, vector short b) +static int __attribute__((__always_inline__)) +vec_all_nlt(vector float a, vector float b) { - return __builtin_altivec_vsubshs(a, b); + return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, b, a); } -/* vec_vsubuhs */ +/* vec_all_numeric */ -static vector unsigned short __attribute__((__always_inline__)) -vec_vsubuhs(vector unsigned short a, vector unsigned short b) +static int __attribute__((__always_inline__)) +vec_all_numeric(vector float a) { - return __builtin_altivec_vsubuhs(a, b); + return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, a); } -/* vec_vsubsws */ +/* vec_any_eq */ -static vector int __attribute__((__always_inline__)) -vec_vsubsws(vector int a, vector int b) +static int __ATTRS_o_ai +vec_any_eq(vector signed char a, vector signed char b) { - return __builtin_altivec_vsubsws(a, b); + return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b); } -/* vec_vsubuws */ +static int __ATTRS_o_ai +vec_any_eq(vector signed char a, vector bool char b) +{ + return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b); +} -static vector unsigned int __attribute__((__always_inline__)) -vec_vsubuws(vector unsigned int a, vector unsigned int b) +static int __ATTRS_o_ai +vec_any_eq(vector unsigned char a, vector unsigned char b) { - return __builtin_altivec_vsubuws(a, b); + return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b); } -/* vec_sum4s */ +static int __ATTRS_o_ai +vec_any_eq(vector unsigned char a, vector bool char b) +{ + return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b); +} -static vector int __ATTRS_o_ai -vec_sum4s(vector signed char a, vector int b) +static int __ATTRS_o_ai +vec_any_eq(vector bool char a, vector signed char b) { - return __builtin_altivec_vsum4sbs(a, b); + return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b); } -static vector unsigned int __ATTRS_o_ai -vec_sum4s(vector unsigned char a, vector unsigned int b) +static int __ATTRS_o_ai +vec_any_eq(vector bool char a, vector unsigned char b) { - return __builtin_altivec_vsum4ubs(a, b); + return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b); } -static vector int __ATTRS_o_ai -vec_sum4s(vector signed short a, vector int b) +static int __ATTRS_o_ai +vec_any_eq(vector bool char a, vector bool char b) { - return __builtin_altivec_vsum4shs(a, b); + return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b); } -/* vec_vsum4sbs */ +static int __ATTRS_o_ai +vec_any_eq(vector short a, vector short b) +{ + return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, a, b); +} -static vector int __attribute__((__always_inline__)) -vec_vsum4sbs(vector signed char a, vector int b) +static int __ATTRS_o_ai +vec_any_eq(vector short a, vector bool short b) { - return __builtin_altivec_vsum4sbs(a, b); + return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, a, (vector short)b); } -/* vec_vsum4ubs */ - -static vector unsigned int __attribute__((__always_inline__)) -vec_vsum4ubs(vector unsigned char a, vector unsigned int b) +static int __ATTRS_o_ai +vec_any_eq(vector unsigned short a, vector unsigned short b) { - return __builtin_altivec_vsum4ubs(a, b); + return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, (vector short)a, (vector short)b); } -/* vec_vsum4shs */ - -static vector int __attribute__((__always_inline__)) -vec_vsum4shs(vector signed short a, vector int b) +static int __ATTRS_o_ai +vec_any_eq(vector unsigned short a, vector bool short b) { - return __builtin_altivec_vsum4shs(a, b); + return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, (vector short)a, (vector short)b); } -/* vec_sum2s */ - -static vector signed int __attribute__((__always_inline__)) -vec_sum2s(vector int a, vector int b) +static int __ATTRS_o_ai +vec_any_eq(vector bool short a, vector short b) { - return __builtin_altivec_vsum2sws(a, b); + return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, (vector short)a, (vector short)b); } -/* vec_vsum2sws */ - -static vector signed int __attribute__((__always_inline__)) -vec_vsum2sws(vector int a, vector int b) +static int __ATTRS_o_ai +vec_any_eq(vector bool short a, vector unsigned short b) { - return __builtin_altivec_vsum2sws(a, b); + return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, (vector short)a, (vector short)b); } -/* vec_sums */ - -static vector signed int __attribute__((__always_inline__)) -vec_sums(vector signed int a, vector signed int b) +static int __ATTRS_o_ai +vec_any_eq(vector bool short a, vector bool short b) { - return __builtin_altivec_vsumsws(a, b); + return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, (vector short)a, (vector short)b); } -/* vec_vsumsws */ - -static vector signed int __attribute__((__always_inline__)) -vec_vsumsws(vector signed int a, vector signed int b) +static int __ATTRS_o_ai +vec_any_eq(vector pixel a, vector pixel b) { - return __builtin_altivec_vsumsws(a, b); + return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, (vector short)a, (vector short)b); } -/* vec_trunc */ - -static vector float __attribute__((__always_inline__)) -vec_trunc(vector float a) +static int __ATTRS_o_ai +vec_any_eq(vector int a, vector int b) { - return __builtin_altivec_vrfiz(a); + return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, a, b); } -/* vec_vrfiz */ - -static vector float __attribute__((__always_inline__)) -vec_vrfiz(vector float a) +static int __ATTRS_o_ai +vec_any_eq(vector int a, vector bool int b) { - return __builtin_altivec_vrfiz(a); + return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, a, (vector int)b); } -/* vec_unpackh */ - -static vector short __ATTRS_o_ai -vec_unpackh(vector signed char a) +static int __ATTRS_o_ai +vec_any_eq(vector unsigned int a, vector unsigned int b) { - return __builtin_altivec_vupkhsb((vector char)a); + return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b); } -static vector int __ATTRS_o_ai -vec_unpackh(vector short a) +static int __ATTRS_o_ai +vec_any_eq(vector unsigned int a, vector bool int b) { - return __builtin_altivec_vupkhsh(a); + return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b); } -/* vec_vupkhsb */ - -static vector short __attribute__((__always_inline__)) -vec_vupkhsb(vector signed char a) +static int __ATTRS_o_ai +vec_any_eq(vector bool int a, vector int b) { - return __builtin_altivec_vupkhsb((vector char)a); + return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b); } -/* vec_vupkhsh */ - -static vector int __attribute__((__always_inline__)) -vec_vupkhsh(vector short a) +static int __ATTRS_o_ai +vec_any_eq(vector bool int a, vector unsigned int b) { - return __builtin_altivec_vupkhsh(a); + return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b); } -/* vec_unpackl */ - -static vector short __ATTRS_o_ai -vec_unpackl(vector signed char a) +static int __ATTRS_o_ai +vec_any_eq(vector bool int a, vector bool int b) { - return __builtin_altivec_vupklsb((vector char)a); + return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b); } -static vector int __ATTRS_o_ai -vec_unpackl(vector short a) +static int __ATTRS_o_ai +vec_any_eq(vector float a, vector float b) { - return __builtin_altivec_vupklsh(a); + return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, a, b); } -/* vec_vupklsb */ +/* vec_any_ge */ -static vector short __attribute__((__always_inline__)) -vec_vupklsb(vector signed char a) +static int __ATTRS_o_ai +vec_any_ge(vector signed char a, vector signed char b) { - return __builtin_altivec_vupklsb((vector char)a); + return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, b, a); } -/* vec_vupklsh */ - -static vector int __attribute__((__always_inline__)) -vec_vupklsh(vector short a) +static int __ATTRS_o_ai +vec_any_ge(vector signed char a, vector bool char b) { - return __builtin_altivec_vupklsh(a); + return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, (vector signed char)b, a); } -/* vec_xor */ - -#define __builtin_altivec_vxor vec_xor - -static vector signed char __ATTRS_o_ai -vec_xor(vector signed char a, vector signed char b) +static int __ATTRS_o_ai +vec_any_ge(vector unsigned char a, vector unsigned char b) { - return a ^ b; + return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, b, a); } -static vector unsigned char __ATTRS_o_ai -vec_xor(vector unsigned char a, vector unsigned char b) +static int __ATTRS_o_ai +vec_any_ge(vector unsigned char a, vector bool char b) { - return a ^ b; + return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)b, a); } -static vector short __ATTRS_o_ai -vec_xor(vector short a, vector short b) +static int __ATTRS_o_ai +vec_any_ge(vector bool char a, vector signed char b) { - return a ^ b; + return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)b, + (vector unsigned char)a); } -static vector unsigned short __ATTRS_o_ai -vec_xor(vector unsigned short a, vector unsigned short b) +static int __ATTRS_o_ai +vec_any_ge(vector bool char a, vector unsigned char b) { - return a ^ b; + return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, b, (vector unsigned char)a); } -static vector int __ATTRS_o_ai -vec_xor(vector int a, vector int b) +static int __ATTRS_o_ai +vec_any_ge(vector bool char a, vector bool char b) { - return a ^ b; + return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)b, + (vector unsigned char)a); } -static vector unsigned int __ATTRS_o_ai -vec_xor(vector unsigned int a, vector unsigned int b) +static int __ATTRS_o_ai +vec_any_ge(vector short a, vector short b) { - return a ^ b; + return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, b, a); } -static vector float __ATTRS_o_ai -vec_xor(vector float a, vector float b) +static int __ATTRS_o_ai +vec_any_ge(vector short a, vector bool short b) { - vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b; - return (vector float)res; + return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, (vector short)b, a); } -/* vec_vxor */ - -static vector signed char __ATTRS_o_ai -vec_vxor(vector signed char a, vector signed char b) +static int __ATTRS_o_ai +vec_any_ge(vector unsigned short a, vector unsigned short b) { - return a ^ b; + return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, b, a); } -static vector unsigned char __ATTRS_o_ai -vec_vxor(vector unsigned char a, vector unsigned char b) +static int __ATTRS_o_ai +vec_any_ge(vector unsigned short a, vector bool short b) { - return a ^ b; + return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)b, a); } -static vector short __ATTRS_o_ai -vec_vxor(vector short a, vector short b) +static int __ATTRS_o_ai +vec_any_ge(vector bool short a, vector short b) { - return a ^ b; + return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)b, + (vector unsigned short)a); } -static vector unsigned short __ATTRS_o_ai -vec_vxor(vector unsigned short a, vector unsigned short b) +static int __ATTRS_o_ai +vec_any_ge(vector bool short a, vector unsigned short b) { - return a ^ b; + return + __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, b, (vector unsigned short)a); } -static vector int __ATTRS_o_ai -vec_vxor(vector int a, vector int b) +static int __ATTRS_o_ai +vec_any_ge(vector bool short a, vector bool short b) { - return a ^ b; + return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)b, + (vector unsigned short)a); } -static vector unsigned int __ATTRS_o_ai -vec_vxor(vector unsigned int a, vector unsigned int b) +static int __ATTRS_o_ai +vec_any_ge(vector int a, vector int b) { - return a ^ b; + return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, b, a); } -static vector float __ATTRS_o_ai -vec_vxor(vector float a, vector float b) +static int __ATTRS_o_ai +vec_any_ge(vector int a, vector bool int b) { - vector unsigned int res = (vector unsigned int)a ^ (vector unsigned int)b; - return (vector float)res; + return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, (vector int)b, a); } -/* ------------------------------ predicates ------------------------------------ */ - -/* vec_all_eq */ +static int __ATTRS_o_ai +vec_any_ge(vector unsigned int a, vector unsigned int b) +{ + return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, b, a); +} static int __ATTRS_o_ai -vec_all_eq(vector signed char a, vector signed char b) +vec_any_ge(vector unsigned int a, vector bool int b) { - return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)b, a); } static int __ATTRS_o_ai -vec_all_eq(vector unsigned char a, vector unsigned char b) +vec_any_ge(vector bool int a, vector int b) { - return __builtin_altivec_vcmpequb_p(__CR6_LT, (vector char)a, (vector char)b); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)b, + (vector unsigned int)a); } static int __ATTRS_o_ai -vec_all_eq(vector short a, vector short b) +vec_any_ge(vector bool int a, vector unsigned int b) { - return __builtin_altivec_vcmpequh_p(__CR6_LT, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, b, (vector unsigned int)a); } static int __ATTRS_o_ai -vec_all_eq(vector unsigned short a, vector unsigned short b) +vec_any_ge(vector bool int a, vector bool int b) { - return __builtin_altivec_vcmpequh_p(__CR6_LT, (vector short)a, (vector short)b); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)b, + (vector unsigned int)a); } static int __ATTRS_o_ai -vec_all_eq(vector int a, vector int b) +vec_any_ge(vector float a, vector float b) { - return __builtin_altivec_vcmpequw_p(__CR6_LT, a, b); + return __builtin_altivec_vcmpgefp_p(__CR6_EQ_REV, a, b); } +/* vec_any_gt */ + static int __ATTRS_o_ai -vec_all_eq(vector unsigned int a, vector unsigned int b) +vec_any_gt(vector signed char a, vector signed char b) { - return __builtin_altivec_vcmpequw_p(__CR6_LT, (vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, a, b); } static int __ATTRS_o_ai -vec_all_eq(vector float a, vector float b) +vec_any_gt(vector signed char a, vector bool char b) { - return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, b); + return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, a, (vector signed char)b); } -/* vec_all_ge */ +static int __ATTRS_o_ai +vec_any_gt(vector unsigned char a, vector unsigned char b) +{ + return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, a, b); +} static int __ATTRS_o_ai -vec_all_ge(vector signed char a, vector signed char b) +vec_any_gt(vector unsigned char a, vector bool char b) { - return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, b, a); + return + __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, a, (vector unsigned char)b); } static int __ATTRS_o_ai -vec_all_ge(vector unsigned char a, vector unsigned char b) +vec_any_gt(vector bool char a, vector signed char b) { - return __builtin_altivec_vcmpgtub_p(__CR6_EQ, b, a); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)a, + (vector unsigned char)b); } static int __ATTRS_o_ai -vec_all_ge(vector short a, vector short b) +vec_any_gt(vector bool char a, vector unsigned char b) { - return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, b, a); + return + __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)a, b); } static int __ATTRS_o_ai -vec_all_ge(vector unsigned short a, vector unsigned short b) +vec_any_gt(vector bool char a, vector bool char b) { - return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, b, a); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)a, + (vector unsigned char)b); } static int __ATTRS_o_ai -vec_all_ge(vector int a, vector int b) +vec_any_gt(vector short a, vector short b) { - return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, b, a); + return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, a, b); } static int __ATTRS_o_ai -vec_all_ge(vector unsigned int a, vector unsigned int b) +vec_any_gt(vector short a, vector bool short b) { - return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, b, a); + return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, a, (vector short)b); } static int __ATTRS_o_ai -vec_all_ge(vector float a, vector float b) +vec_any_gt(vector unsigned short a, vector unsigned short b) { - return __builtin_altivec_vcmpgefp_p(__CR6_LT, a, b); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, a, b); } -/* vec_all_gt */ +static int __ATTRS_o_ai +vec_any_gt(vector unsigned short a, vector bool short b) +{ + return + __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, a, (vector unsigned short)b); +} static int __ATTRS_o_ai -vec_all_gt(vector signed char a, vector signed char b) +vec_any_gt(vector bool short a, vector short b) { - return __builtin_altivec_vcmpgtsb_p(__CR6_LT, a, b); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)a, + (vector unsigned short)b); } static int __ATTRS_o_ai -vec_all_gt(vector unsigned char a, vector unsigned char b) +vec_any_gt(vector bool short a, vector unsigned short b) { - return __builtin_altivec_vcmpgtub_p(__CR6_LT, a, b); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)a, b); } static int __ATTRS_o_ai -vec_all_gt(vector short a, vector short b) +vec_any_gt(vector bool short a, vector bool short b) { - return __builtin_altivec_vcmpgtsh_p(__CR6_LT, a, b); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)a, + (vector unsigned short)b); } static int __ATTRS_o_ai -vec_all_gt(vector unsigned short a, vector unsigned short b) +vec_any_gt(vector int a, vector int b) { - return __builtin_altivec_vcmpgtuh_p(__CR6_LT, a, b); + return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, a, b); } static int __ATTRS_o_ai -vec_all_gt(vector int a, vector int b) +vec_any_gt(vector int a, vector bool int b) { - return __builtin_altivec_vcmpgtsw_p(__CR6_LT, a, b); + return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, a, (vector int)b); } static int __ATTRS_o_ai -vec_all_gt(vector unsigned int a, vector unsigned int b) +vec_any_gt(vector unsigned int a, vector unsigned int b) { - return __builtin_altivec_vcmpgtuw_p(__CR6_LT, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, a, b); } static int __ATTRS_o_ai -vec_all_gt(vector float a, vector float b) +vec_any_gt(vector unsigned int a, vector bool int b) { - return __builtin_altivec_vcmpgtfp_p(__CR6_LT, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, a, (vector unsigned int)b); } -/* vec_all_in */ - -static int __attribute__((__always_inline__)) -vec_all_in(vector float a, vector float b) +static int __ATTRS_o_ai +vec_any_gt(vector bool int a, vector int b) { - return __builtin_altivec_vcmpbfp_p(__CR6_EQ, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)a, + (vector unsigned int)b); } -/* vec_all_le */ - static int __ATTRS_o_ai -vec_all_le(vector signed char a, vector signed char b) +vec_any_gt(vector bool int a, vector unsigned int b) { - return __builtin_altivec_vcmpgtsb_p(__CR6_EQ, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)a, b); } static int __ATTRS_o_ai -vec_all_le(vector unsigned char a, vector unsigned char b) +vec_any_gt(vector bool int a, vector bool int b) { - return __builtin_altivec_vcmpgtub_p(__CR6_EQ, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)a, + (vector unsigned int)b); } static int __ATTRS_o_ai -vec_all_le(vector short a, vector short b) +vec_any_gt(vector float a, vector float b) { - return __builtin_altivec_vcmpgtsh_p(__CR6_EQ, a, b); + return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, a, b); } +/* vec_any_le */ + static int __ATTRS_o_ai -vec_all_le(vector unsigned short a, vector unsigned short b) +vec_any_le(vector signed char a, vector signed char b) { - return __builtin_altivec_vcmpgtuh_p(__CR6_EQ, a, b); + return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, a, b); } static int __ATTRS_o_ai -vec_all_le(vector int a, vector int b) +vec_any_le(vector signed char a, vector bool char b) { - return __builtin_altivec_vcmpgtsw_p(__CR6_EQ, a, b); + return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, a, (vector signed char)b); } static int __ATTRS_o_ai -vec_all_le(vector unsigned int a, vector unsigned int b) +vec_any_le(vector unsigned char a, vector unsigned char b) { - return __builtin_altivec_vcmpgtuw_p(__CR6_EQ, a, b); + return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, a, b); } static int __ATTRS_o_ai -vec_all_le(vector float a, vector float b) +vec_any_le(vector unsigned char a, vector bool char b) { - return __builtin_altivec_vcmpgefp_p(__CR6_LT, b, a); + return + __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, a, (vector unsigned char)b); } -/* vec_all_lt */ - static int __ATTRS_o_ai -vec_all_lt(vector signed char a, vector signed char b) +vec_any_le(vector bool char a, vector signed char b) { - return __builtin_altivec_vcmpgtsb_p(__CR6_LT, b, a); + return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)a, + (vector unsigned char)b); } static int __ATTRS_o_ai -vec_all_lt(vector unsigned char a, vector unsigned char b) +vec_any_le(vector bool char a, vector unsigned char b) { - return __builtin_altivec_vcmpgtub_p(__CR6_LT, b, a); + return + __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)a, b); } static int __ATTRS_o_ai -vec_all_lt(vector short a, vector short b) +vec_any_le(vector bool char a, vector bool char b) { - return __builtin_altivec_vcmpgtsh_p(__CR6_LT, b, a); + return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, (vector unsigned char)a, + (vector unsigned char)b); } static int __ATTRS_o_ai -vec_all_lt(vector unsigned short a, vector unsigned short b) +vec_any_le(vector short a, vector short b) { - return __builtin_altivec_vcmpgtuh_p(__CR6_LT, b, a); + return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, a, b); } static int __ATTRS_o_ai -vec_all_lt(vector int a, vector int b) +vec_any_le(vector short a, vector bool short b) { - return __builtin_altivec_vcmpgtsw_p(__CR6_LT, b, a); + return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, a, (vector short)b); } static int __ATTRS_o_ai -vec_all_lt(vector unsigned int a, vector unsigned int b) +vec_any_le(vector unsigned short a, vector unsigned short b) { - return __builtin_altivec_vcmpgtuw_p(__CR6_LT, b, a); + return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, a, b); } static int __ATTRS_o_ai -vec_all_lt(vector float a, vector float b) +vec_any_le(vector unsigned short a, vector bool short b) { - return __builtin_altivec_vcmpgtfp_p(__CR6_LT, b, a); + return + __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, a, (vector unsigned short)b); } -/* vec_all_nan */ - -static int __attribute__((__always_inline__)) -vec_all_nan(vector float a) +static int __ATTRS_o_ai +vec_any_le(vector bool short a, vector short b) { - return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, a); + return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)a, + (vector unsigned short)b); } -/* vec_all_ne */ - static int __ATTRS_o_ai -vec_all_ne(vector signed char a, vector signed char b) +vec_any_le(vector bool short a, vector unsigned short b) { - return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b); + return + __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)a, b); } static int __ATTRS_o_ai -vec_all_ne(vector unsigned char a, vector unsigned char b) +vec_any_le(vector bool short a, vector bool short b) { - return __builtin_altivec_vcmpequb_p(__CR6_EQ, (vector char)a, (vector char)b); + return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, (vector unsigned short)a, + (vector unsigned short)b); } static int __ATTRS_o_ai -vec_all_ne(vector short a, vector short b) +vec_any_le(vector int a, vector int b) { - return __builtin_altivec_vcmpequh_p(__CR6_EQ, a, b); + return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, a, b); } static int __ATTRS_o_ai -vec_all_ne(vector unsigned short a, vector unsigned short b) +vec_any_le(vector int a, vector bool int b) { - return __builtin_altivec_vcmpequh_p(__CR6_EQ, (vector short)a, (vector short)b); + return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, a, (vector int)b); } static int __ATTRS_o_ai -vec_all_ne(vector int a, vector int b) +vec_any_le(vector unsigned int a, vector unsigned int b) { - return __builtin_altivec_vcmpequw_p(__CR6_EQ, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, a, b); } static int __ATTRS_o_ai -vec_all_ne(vector unsigned int a, vector unsigned int b) +vec_any_le(vector unsigned int a, vector bool int b) { - return __builtin_altivec_vcmpequw_p(__CR6_EQ, (vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, a, (vector unsigned int)b); } static int __ATTRS_o_ai -vec_all_ne(vector float a, vector float b) +vec_any_le(vector bool int a, vector int b) { - return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)a, + (vector unsigned int)b); } -/* vec_all_nge */ - -static int __attribute__((__always_inline__)) -vec_all_nge(vector float a, vector float b) +static int __ATTRS_o_ai +vec_any_le(vector bool int a, vector unsigned int b) { - return __builtin_altivec_vcmpgefp_p(__CR6_EQ, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)a, b); } -/* vec_all_ngt */ - -static int __attribute__((__always_inline__)) -vec_all_ngt(vector float a, vector float b) +static int __ATTRS_o_ai +vec_any_le(vector bool int a, vector bool int b) { - return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, (vector unsigned int)a, + (vector unsigned int)b); } -/* vec_all_nle */ - -static int __attribute__((__always_inline__)) -vec_all_nle(vector float a, vector float b) +static int __ATTRS_o_ai +vec_any_le(vector float a, vector float b) { - return __builtin_altivec_vcmpgefp_p(__CR6_EQ, b, a); + return __builtin_altivec_vcmpgefp_p(__CR6_EQ_REV, b, a); } -/* vec_all_nlt */ +/* vec_any_lt */ -static int __attribute__((__always_inline__)) -vec_all_nlt(vector float a, vector float b) +static int __ATTRS_o_ai +vec_any_lt(vector signed char a, vector signed char b) { - return __builtin_altivec_vcmpgtfp_p(__CR6_EQ, b, a); + return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, b, a); } -/* vec_all_numeric */ - -static int __attribute__((__always_inline__)) -vec_all_numeric(vector float a) +static int __ATTRS_o_ai +vec_any_lt(vector signed char a, vector bool char b) { - return __builtin_altivec_vcmpeqfp_p(__CR6_LT, a, a); + return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, (vector signed char)b, a); } -/* vec_any_eq */ - static int __ATTRS_o_ai -vec_any_eq(vector signed char a, vector signed char b) +vec_any_lt(vector unsigned char a, vector unsigned char b) { - return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, b, a); } static int __ATTRS_o_ai -vec_any_eq(vector unsigned char a, vector unsigned char b) +vec_any_lt(vector unsigned char a, vector bool char b) { - return __builtin_altivec_vcmpequb_p(__CR6_EQ_REV, (vector char)a, (vector char)b); + return + __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)b, a); } static int __ATTRS_o_ai -vec_any_eq(vector short a, vector short b) +vec_any_lt(vector bool char a, vector signed char b) { - return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, a, b); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)b, + (vector unsigned char)a); } static int __ATTRS_o_ai -vec_any_eq(vector unsigned short a, vector unsigned short b) +vec_any_lt(vector bool char a, vector unsigned char b) { - return __builtin_altivec_vcmpequh_p(__CR6_EQ_REV, (vector short)a, (vector short)b); + return + __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, b, (vector unsigned char)a); } static int __ATTRS_o_ai -vec_any_eq(vector int a, vector int b) +vec_any_lt(vector bool char a, vector bool char b) { - return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, a, b); + return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, (vector unsigned char)b, + (vector unsigned char)a); } static int __ATTRS_o_ai -vec_any_eq(vector unsigned int a, vector unsigned int b) +vec_any_lt(vector short a, vector short b) { - return __builtin_altivec_vcmpequw_p(__CR6_EQ_REV, (vector int)a, (vector int)b); + return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, b, a); } static int __ATTRS_o_ai -vec_any_eq(vector float a, vector float b) +vec_any_lt(vector short a, vector bool short b) { - return __builtin_altivec_vcmpeqfp_p(__CR6_EQ_REV, a, b); + return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, (vector short)b, a); } -/* vec_any_ge */ - static int __ATTRS_o_ai -vec_any_ge(vector signed char a, vector signed char b) +vec_any_lt(vector unsigned short a, vector unsigned short b) { - return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, b, a); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, b, a); } static int __ATTRS_o_ai -vec_any_ge(vector unsigned char a, vector unsigned char b) +vec_any_lt(vector unsigned short a, vector bool short b) { - return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, b, a); + return + __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)b, a); } static int __ATTRS_o_ai -vec_any_ge(vector short a, vector short b) +vec_any_lt(vector bool short a, vector short b) { - return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, b, a); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)b, + (vector unsigned short)a); } static int __ATTRS_o_ai -vec_any_ge(vector unsigned short a, vector unsigned short b) +vec_any_lt(vector bool short a, vector unsigned short b) { - return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, b, a); + return + __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, b, (vector unsigned short)a); } static int __ATTRS_o_ai -vec_any_ge(vector int a, vector int b) +vec_any_lt(vector bool short a, vector bool short b) { - return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, b, a); + return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, (vector unsigned short)b, + (vector unsigned short)a); } static int __ATTRS_o_ai -vec_any_ge(vector unsigned int a, vector unsigned int b) +vec_any_lt(vector int a, vector int b) { - return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, b, a); + return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, b, a); } static int __ATTRS_o_ai -vec_any_ge(vector float a, vector float b) +vec_any_lt(vector int a, vector bool int b) { - return __builtin_altivec_vcmpgefp_p(__CR6_EQ_REV, a, b); + return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, (vector int)b, a); } -/* vec_any_gt */ - static int __ATTRS_o_ai -vec_any_gt(vector signed char a, vector signed char b) +vec_any_lt(vector unsigned int a, vector unsigned int b) { - return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, b, a); } static int __ATTRS_o_ai -vec_any_gt(vector unsigned char a, vector unsigned char b) +vec_any_lt(vector unsigned int a, vector bool int b) { - return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)b, a); } static int __ATTRS_o_ai -vec_any_gt(vector short a, vector short b) +vec_any_lt(vector bool int a, vector int b) { - return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)b, + (vector unsigned int)a); } static int __ATTRS_o_ai -vec_any_gt(vector unsigned short a, vector unsigned short b) +vec_any_lt(vector bool int a, vector unsigned int b) { - return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, b, (vector unsigned int)a); } static int __ATTRS_o_ai -vec_any_gt(vector int a, vector int b) +vec_any_lt(vector bool int a, vector bool int b) { - return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, a, b); + return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, (vector unsigned int)b, + (vector unsigned int)a); } static int __ATTRS_o_ai -vec_any_gt(vector unsigned int a, vector unsigned int b) +vec_any_lt(vector float a, vector float b) { - return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, a, b); + return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, b, a); } -static int __ATTRS_o_ai -vec_any_gt(vector float a, vector float b) +/* vec_any_nan */ + +static int __attribute__((__always_inline__)) +vec_any_nan(vector float a) { - return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, a, b); + return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, a, a); } -/* vec_any_le */ +/* vec_any_ne */ static int __ATTRS_o_ai -vec_any_le(vector signed char a, vector signed char b) +vec_any_ne(vector signed char a, vector signed char b) { - return __builtin_altivec_vcmpgtsb_p(__CR6_LT_REV, a, b); + return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b); } static int __ATTRS_o_ai -vec_any_le(vector unsigned char a, vector unsigned char b) +vec_any_ne(vector signed char a, vector bool char b) { - return __builtin_altivec_vcmpgtub_p(__CR6_LT_REV, a, b); + return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b); } static int __ATTRS_o_ai -vec_any_le(vector short a, vector short b) +vec_any_ne(vector unsigned char a, vector unsigned char b) { - return __builtin_altivec_vcmpgtsh_p(__CR6_LT_REV, a, b); + return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b); } static int __ATTRS_o_ai -vec_any_le(vector unsigned short a, vector unsigned short b) +vec_any_ne(vector unsigned char a, vector bool char b) { - return __builtin_altivec_vcmpgtuh_p(__CR6_LT_REV, a, b); + return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b); } static int __ATTRS_o_ai -vec_any_le(vector int a, vector int b) +vec_any_ne(vector bool char a, vector signed char b) { - return __builtin_altivec_vcmpgtsw_p(__CR6_LT_REV, a, b); + return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b); } static int __ATTRS_o_ai -vec_any_le(vector unsigned int a, vector unsigned int b) +vec_any_ne(vector bool char a, vector unsigned char b) { - return __builtin_altivec_vcmpgtuw_p(__CR6_LT_REV, a, b); + return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b); } static int __ATTRS_o_ai -vec_any_le(vector float a, vector float b) +vec_any_ne(vector bool char a, vector bool char b) { - return __builtin_altivec_vcmpgefp_p(__CR6_EQ_REV, b, a); + return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b); } -/* vec_any_lt */ - static int __ATTRS_o_ai -vec_any_lt(vector signed char a, vector signed char b) +vec_any_ne(vector short a, vector short b) { - return __builtin_altivec_vcmpgtsb_p(__CR6_EQ_REV, b, a); + return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, a, b); } static int __ATTRS_o_ai -vec_any_lt(vector unsigned char a, vector unsigned char b) +vec_any_ne(vector short a, vector bool short b) { - return __builtin_altivec_vcmpgtub_p(__CR6_EQ_REV, b, a); + return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, a, (vector short)b); } static int __ATTRS_o_ai -vec_any_lt(vector short a, vector short b) +vec_any_ne(vector unsigned short a, vector unsigned short b) { - return __builtin_altivec_vcmpgtsh_p(__CR6_EQ_REV, b, a); + return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, (vector short)a, (vector short)b); } static int __ATTRS_o_ai -vec_any_lt(vector unsigned short a, vector unsigned short b) +vec_any_ne(vector unsigned short a, vector bool short b) { - return __builtin_altivec_vcmpgtuh_p(__CR6_EQ_REV, b, a); + return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, (vector short)a, (vector short)b); } static int __ATTRS_o_ai -vec_any_lt(vector int a, vector int b) +vec_any_ne(vector bool short a, vector short b) { - return __builtin_altivec_vcmpgtsw_p(__CR6_EQ_REV, b, a); + return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, (vector short)a, (vector short)b); } static int __ATTRS_o_ai -vec_any_lt(vector unsigned int a, vector unsigned int b) +vec_any_ne(vector bool short a, vector unsigned short b) { - return __builtin_altivec_vcmpgtuw_p(__CR6_EQ_REV, b, a); + return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, (vector short)a, (vector short)b); } static int __ATTRS_o_ai -vec_any_lt(vector float a, vector float b) +vec_any_ne(vector bool short a, vector bool short b) { - return __builtin_altivec_vcmpgtfp_p(__CR6_EQ_REV, b, a); + return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, (vector short)a, (vector short)b); } -/* vec_any_nan */ - -static int __attribute__((__always_inline__)) -vec_any_nan(vector float a) +static int __ATTRS_o_ai +vec_any_ne(vector pixel a, vector pixel b) { - return __builtin_altivec_vcmpeqfp_p(__CR6_LT_REV, a, a); + return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, (vector short)a, (vector short)b); } -/* vec_any_ne */ +static int __ATTRS_o_ai +vec_any_ne(vector int a, vector int b) +{ + return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, a, b); +} static int __ATTRS_o_ai -vec_any_ne(vector signed char a, vector signed char b) +vec_any_ne(vector int a, vector bool int b) { - return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b); + return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, a, (vector int)b); } static int __ATTRS_o_ai -vec_any_ne(vector unsigned char a, vector unsigned char b) +vec_any_ne(vector unsigned int a, vector unsigned int b) { - return __builtin_altivec_vcmpequb_p(__CR6_LT_REV, (vector char)a, (vector char)b); + return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b); } static int __ATTRS_o_ai -vec_any_ne(vector short a, vector short b) +vec_any_ne(vector unsigned int a, vector bool int b) { - return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, a, b); + return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b); } static int __ATTRS_o_ai -vec_any_ne(vector unsigned short a, vector unsigned short b) +vec_any_ne(vector bool int a, vector int b) { - return __builtin_altivec_vcmpequh_p(__CR6_LT_REV, (vector short)a, (vector short)b); + return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b); } static int __ATTRS_o_ai -vec_any_ne(vector int a, vector int b) +vec_any_ne(vector bool int a, vector unsigned int b) { - return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, a, b); + return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b); } static int __ATTRS_o_ai -vec_any_ne(vector unsigned int a, vector unsigned int b) +vec_any_ne(vector bool int a, vector bool int b) { return __builtin_altivec_vcmpequw_p(__CR6_LT_REV, (vector int)a, (vector int)b); } diff --git a/lib/Headers/avxintrin.h b/lib/Headers/avxintrin.h new file mode 100644 index 0000000..884d31c --- /dev/null +++ b/lib/Headers/avxintrin.h @@ -0,0 +1,1156 @@ +/*===---- avxintrin.h - AVX intrinsics -------------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __IMMINTRIN_H +#error "Never use directly; include instead." +#endif + +typedef double __v4df __attribute__ ((__vector_size__ (32))); +typedef float __v8sf __attribute__ ((__vector_size__ (32))); +typedef long long __v4di __attribute__ ((__vector_size__ (32))); +typedef int __v8si __attribute__ ((__vector_size__ (32))); +typedef short __v16hi __attribute__ ((__vector_size__ (32))); +typedef char __v32qi __attribute__ ((__vector_size__ (32))); + +typedef float __m256 __attribute__ ((__vector_size__ (32))); +typedef double __m256d __attribute__((__vector_size__(32))); +typedef long long __m256i __attribute__((__vector_size__(32))); + +/* Arithmetic */ +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_add_pd(__m256d a, __m256d b) +{ + return a+b; +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_add_ps(__m256 a, __m256 b) +{ + return a+b; +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_sub_pd(__m256d a, __m256d b) +{ + return a-b; +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_sub_ps(__m256 a, __m256 b) +{ + return a-b; +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_addsub_pd(__m256d a, __m256d b) +{ + return (__m256d)__builtin_ia32_addsubpd256((__v4df)a, (__v4df)b); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_addsub_ps(__m256 a, __m256 b) +{ + return (__m256)__builtin_ia32_addsubps256((__v8sf)a, (__v8sf)b); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_div_pd(__m256d a, __m256d b) +{ + return a / b; +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_div_ps(__m256 a, __m256 b) +{ + return a / b; +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_max_pd(__m256d a, __m256d b) +{ + return (__m256d)__builtin_ia32_maxpd256((__v4df)a, (__v4df)b); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_max_ps(__m256 a, __m256 b) +{ + return (__m256)__builtin_ia32_maxps256((__v8sf)a, (__v8sf)b); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_min_pd(__m256d a, __m256d b) +{ + return (__m256d)__builtin_ia32_minpd256((__v4df)a, (__v4df)b); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_min_ps(__m256 a, __m256 b) +{ + return (__m256)__builtin_ia32_minps256((__v8sf)a, (__v8sf)b); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_mul_pd(__m256d a, __m256d b) +{ + return a * b; +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_mul_ps(__m256 a, __m256 b) +{ + return a * b; +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_sqrt_pd(__m256d a) +{ + return (__m256d)__builtin_ia32_sqrtpd256((__v4df)a); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_sqrt_ps(__m256 a) +{ + return (__m256)__builtin_ia32_sqrtps256((__v8sf)a); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_rsqrt_ps(__m256 a) +{ + return (__m256)__builtin_ia32_rsqrtps256((__v8sf)a); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_rcp_ps(__m256 a) +{ + return (__m256)__builtin_ia32_rcpps256((__v8sf)a); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_round_pd(__m256d v, const int m) +{ + return (__m256d)__builtin_ia32_roundpd256((__v4df)v, m); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_round_ps(__m256 v, const int m) +{ + return (__m256)__builtin_ia32_roundps256((__v8sf)v, m); +} + +#define _mm256_ceil_pd(V) _mm256_round_pd((V), _MM_FROUND_CEIL) +#define _mm256_floor_pd(V) _mm256_round_pd((V), _MM_FROUND_FLOOR) +#define _mm256_ceil_ps(V) _mm256_round_ps((V), _MM_FROUND_CEIL) +#define _mm256_floor_ps(V) _mm256_round_ps((V), _MM_FROUND_FLOOR) + +/* Logical */ +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_and_pd(__m256d a, __m256d b) +{ + return (__m256d)((__v4di)a & (__v4di)b); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_and_ps(__m256 a, __m256 b) +{ + return (__m256)((__v8si)a & (__v8si)b); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_andnot_pd(__m256d a, __m256d b) +{ + return (__m256d)(~(__v4di)a & (__v4di)b); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_andnot_ps(__m256 a, __m256 b) +{ + return (__m256)(~(__v8si)a & (__v8si)b); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_or_pd(__m256d a, __m256d b) +{ + return (__m256d)((__v4di)a | (__v4di)b); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_or_ps(__m256 a, __m256 b) +{ + return (__m256)((__v8si)a | (__v8si)b); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_xor_pd(__m256d a, __m256d b) +{ + return (__m256d)((__v4di)a ^ (__v4di)b); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_xor_ps(__m256 a, __m256 b) +{ + return (__m256)((__v8si)a ^ (__v8si)b); +} + +/* Horizontal arithmetic */ +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_hadd_pd(__m256d a, __m256d b) +{ + return (__m256d)__builtin_ia32_haddpd256((__v4df)a, (__v4df)b); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_hadd_ps(__m256 a, __m256 b) +{ + return (__m256)__builtin_ia32_haddps256((__v8sf)a, (__v8sf)b); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_hsub_pd(__m256d a, __m256d b) +{ + return (__m256d)__builtin_ia32_hsubpd256((__v4df)a, (__v4df)b); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_hsub_ps(__m256 a, __m256 b) +{ + return (__m256)__builtin_ia32_hsubps256((__v8sf)a, (__v8sf)b); +} + +/* Vector permutations */ +static __inline __m128d __attribute__((__always_inline__, __nodebug__)) +_mm_permutevar_pd(__m128d a, __m128i c) +{ + return (__m128d)__builtin_ia32_vpermilvarpd((__v2df)a, (__v2di)c); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_permutevar_pd(__m256d a, __m256i c) +{ + return (__m256d)__builtin_ia32_vpermilvarpd256((__v4df)a, (__v4di)c); +} + +static __inline __m128 __attribute__((__always_inline__, __nodebug__)) +_mm_permutevar_ps(__m128 a, __m128i c) +{ + return (__m128)__builtin_ia32_vpermilvarps((__v4sf)a, (__v4si)c); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_permutevar_ps(__m256 a, __m256i c) +{ + return (__m256)__builtin_ia32_vpermilvarps256((__v8sf)a, + (__v8si)c); +} + +static __inline __m128d __attribute__((__always_inline__, __nodebug__)) +_mm_permute_pd(__m128d a, const int c) +{ + return (__m128d)__builtin_ia32_vpermilpd((__v2df)a, c); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_permute_pd(__m256d a, const int c) +{ + return (__m256d)__builtin_ia32_vpermilpd256((__v4df)a, c); +} + +static __inline __m128 __attribute__((__always_inline__, __nodebug__)) +_mm_permute_ps(__m128 a, const int c) +{ + return (__m128)__builtin_ia32_vpermilps((__v4sf)a, c); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_permute_ps(__m256 a, const int c) +{ + return (__m256)__builtin_ia32_vpermilps256((__v8sf)a, c); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_permute2f128_pd(__m256d a, __m256d b, const int c) +{ + return (__m256d)__builtin_ia32_vperm2f128_pd256((__v4df)a, (__v4df)b, c); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_permute2f128_ps(__m256 a, __m256 b, const int c) +{ + return (__m256)__builtin_ia32_vperm2f128_ps256((__v8sf)a, (__v8sf)b, c); +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_permute2f128_si256(__m256i a, __m256i b, const int c) +{ + return (__m256i)__builtin_ia32_vperm2f128_si256((__v8si)a, (__v8si)b, c); +} + +/* Vector Blend */ +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_blend_pd(__m256d a, __m256d b, const int c) +{ + return (__m256d)__builtin_ia32_blendpd256((__v4df)a, (__v4df)b, c); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_blend_ps(__m256 a, __m256 b, const int c) +{ + return (__m256)__builtin_ia32_blendps256((__v8sf)a, (__v8sf)b, c); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_blendv_pd(__m256d a, __m256d b, __m256d c) +{ + return (__m256d)__builtin_ia32_blendvpd256((__v4df)a, (__v4df)b, (__v4df)c); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_blendv_ps(__m256 a, __m256 b, __m256 c) +{ + return (__m256)__builtin_ia32_blendvps256((__v8sf)a, (__v8sf)b, (__v8sf)c); +} + +/* Vector Dot Product */ +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_dp_ps(__m256 a, __m256 b, const int c) +{ + return (__m256)__builtin_ia32_dpps256((__v8sf)a, (__v8sf)b, c); +} + +/* Vector shuffle */ +#define _mm256_shuffle_ps(a, b, mask) \ + (__builtin_shufflevector((__v8sf)(a), (__v8sf)(b), \ + (mask) & 0x3, ((mask) & 0xc) >> 2, \ + (((mask) & 0x30) >> 4) + 8, (((mask) & 0xc0) >> 6) + 8, \ + (mask) & 0x3 + 4, (((mask) & 0xc) >> 2) + 4, \ + (((mask) & 0x30) >> 4) + 12, (((mask) & 0xc0) >> 6) + 12)) + +#define _mm256_shuffle_pd(a, b, mask) \ + (__builtin_shufflevector((__v4df)(a), (__v4df)(b), \ + (mask) & 0x1, \ + (((mask) & 0x2) >> 1) + 4, \ + (((mask) & 0x4) >> 2) + 2, \ + (((mask) & 0x8) >> 3) + 6)) + +/* Compare */ +#define _CMP_EQ_OQ 0x00 /* Equal (ordered, non-signaling) */ +#define _CMP_LT_OS 0x01 /* Less-than (ordered, signaling) */ +#define _CMP_LE_OS 0x02 /* Less-than-or-equal (ordered, signaling) */ +#define _CMP_UNORD_Q 0x03 /* Unordered (non-signaling) */ +#define _CMP_NEQ_UQ 0x04 /* Not-equal (unordered, non-signaling) */ +#define _CMP_NLT_US 0x05 /* Not-less-than (unordered, signaling) */ +#define _CMP_NLE_US 0x06 /* Not-less-than-or-equal (unordered, signaling) */ +#define _CMP_ORD_Q 0x07 /* Ordered (nonsignaling) */ +#define _CMP_EQ_UQ 0x08 /* Equal (unordered, non-signaling) */ +#define _CMP_NGE_US 0x09 /* Not-greater-than-or-equal (unord, signaling) */ +#define _CMP_NGT_US 0x0a /* Not-greater-than (unordered, signaling) */ +#define _CMP_FALSE_OQ 0x0b /* False (ordered, non-signaling) */ +#define _CMP_NEQ_OQ 0x0c /* Not-equal (ordered, non-signaling) */ +#define _CMP_GE_OS 0x0d /* Greater-than-or-equal (ordered, signaling) */ +#define _CMP_GT_OS 0x0e /* Greater-than (ordered, signaling) */ +#define _CMP_TRUE_UQ 0x0f /* True (unordered, non-signaling) */ +#define _CMP_EQ_OS 0x10 /* Equal (ordered, signaling) */ +#define _CMP_LT_OQ 0x11 /* Less-than (ordered, non-signaling) */ +#define _CMP_LE_OQ 0x12 /* Less-than-or-equal (ordered, non-signaling) */ +#define _CMP_UNORD_S 0x13 /* Unordered (signaling) */ +#define _CMP_NEQ_US 0x14 /* Not-equal (unordered, signaling) */ +#define _CMP_NLT_UQ 0x15 /* Not-less-than (unordered, non-signaling) */ +#define _CMP_NLE_UQ 0x16 /* Not-less-than-or-equal (unord, non-signaling) */ +#define _CMP_ORD_S 0x17 /* Ordered (signaling) */ +#define _CMP_EQ_US 0x18 /* Equal (unordered, signaling) */ +#define _CMP_NGE_UQ 0x19 /* Not-greater-than-or-equal (unord, non-sign) */ +#define _CMP_NGT_UQ 0x1a /* Not-greater-than (unordered, non-signaling) */ +#define _CMP_FALSE_OS 0x1b /* False (ordered, signaling) */ +#define _CMP_NEQ_OS 0x1c /* Not-equal (ordered, signaling) */ +#define _CMP_GE_OQ 0x1d /* Greater-than-or-equal (ordered, non-signaling) */ +#define _CMP_GT_OQ 0x1e /* Greater-than (ordered, non-signaling) */ +#define _CMP_TRUE_US 0x1f /* True (unordered, signaling) */ + +static __inline __m128d __attribute__((__always_inline__, __nodebug__)) +_mm_cmp_pd(__m128d a, __m128d b, const int c) +{ + return (__m128d)__builtin_ia32_cmppd((__v2df)a, (__v2df)b, c); +} + +static __inline __m128 __attribute__((__always_inline__, __nodebug__)) +_mm_cmp_ps(__m128 a, __m128 b, const int c) +{ + return (__m128)__builtin_ia32_cmpps((__v4sf)a, (__v4sf)b, c); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_cmp_pd(__m256d a, __m256d b, const int c) +{ + return (__m256d)__builtin_ia32_cmppd256((__v4df)a, (__v4df)b, c); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_cmp_ps(__m256 a, __m256 b, const int c) +{ + return (__m256)__builtin_ia32_cmpps256((__v8sf)a, (__v8sf)b, c); +} + +static __inline __m128d __attribute__((__always_inline__, __nodebug__)) +_mm_cmp_sd(__m128d a, __m128d b, const int c) +{ + return (__m128d)__builtin_ia32_cmpsd((__v2df)a, (__v2df)b, c); +} + +static __inline __m128 __attribute__((__always_inline__, __nodebug__)) +_mm_cmp_ss(__m128 a, __m128 b, const int c) +{ + return (__m128)__builtin_ia32_cmpss((__v4sf)a, (__v4sf)b, c); +} + +/* Vector extract */ +static __inline __m128d __attribute__((__always_inline__, __nodebug__)) +_mm256_extractf128_pd(__m256d a, const int o) +{ + return (__m128d)__builtin_ia32_vextractf128_pd256((__v4df)a, o); +} + +static __inline __m128 __attribute__((__always_inline__, __nodebug__)) +_mm256_extractf128_ps(__m256 a, const int o) +{ + return (__m128)__builtin_ia32_vextractf128_ps256((__v8sf)a, o); +} + +static __inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm256_extractf128_si256(__m256i a, const int o) +{ + return (__m128i)__builtin_ia32_vextractf128_si256((__v8si)a, o); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_extract_epi32(__m256i a, int const imm) +{ + __v8si b = (__v8si)a; + return b[imm]; +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_extract_epi16(__m256i a, int const imm) +{ + __v16hi b = (__v16hi)a; + return b[imm]; +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_extract_epi8(__m256i a, int const imm) +{ + __v32qi b = (__v32qi)a; + return b[imm]; +} + +#ifdef __x86_64__ +static __inline long long __attribute__((__always_inline__, __nodebug__)) +_mm256_extract_epi64(__m256i a, const int imm) +{ + __v4di b = (__v4di)a; + return b[imm]; +} +#endif + +/* Vector insert */ +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_insertf128_pd(__m256d a, __m128d b, const int o) +{ + return (__m256d)__builtin_ia32_vinsertf128_pd256((__v4df)a, (__v2df)b, o); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_insertf128_ps(__m256 a, __m128 b, const int o) +{ + return (__m256)__builtin_ia32_vinsertf128_ps256((__v8sf)a, (__v4sf)b, o); +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_insertf128_si256(__m256i a, __m128i b, const int o) +{ + return (__m256i)__builtin_ia32_vinsertf128_si256((__v8si)a, (__v4si)b, o); +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_insert_epi32(__m256i a, int b, int const imm) +{ + __v8si c = (__v8si)a; + c[imm & 7] = b; + return (__m256i)c; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_insert_epi16(__m256i a, int b, int const imm) +{ + __v16hi c = (__v16hi)a; + c[imm & 15] = b; + return (__m256i)c; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_insert_epi8(__m256i a, int b, int const imm) +{ + __v32qi c = (__v32qi)a; + c[imm & 31] = b; + return (__m256i)c; +} + +#ifdef __x86_64__ +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_insert_epi64(__m256i a, int b, int const imm) +{ + __v4di c = (__v4di)a; + c[imm & 3] = b; + return (__m256i)c; +} +#endif + +/* Conversion */ +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_cvtepi32_pd(__m128i a) +{ + return (__m256d)__builtin_ia32_cvtdq2pd256((__v4si) a); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_cvtepi32_ps(__m256i a) +{ + return (__m256)__builtin_ia32_cvtdq2ps256((__v8si) a); +} + +static __inline __m128 __attribute__((__always_inline__, __nodebug__)) +_mm256_cvtpd_ps(__m256d a) +{ + return (__m128)__builtin_ia32_cvtpd2ps256((__v4df) a); +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_cvtps_epi32(__m256 a) +{ + return (__m256i)__builtin_ia32_cvtps2dq256((__v8sf) a); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_cvtps_pd(__m128 a) +{ + return (__m256d)__builtin_ia32_cvtps2pd256((__v4sf) a); +} + +static __inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm256_cvttpd_epi32(__m256d a) +{ + return (__m128i)__builtin_ia32_cvttpd2dq256((__v4df) a); +} + +static __inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm256_cvtpd_epi32(__m256d a) +{ + return (__m128i)__builtin_ia32_cvtpd2dq256((__v4df) a); +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_cvttps_epi32(__m256 a) +{ + return (__m256i)__builtin_ia32_cvttps2dq256((__v8sf) a); +} + +/* Vector replicate */ +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_movehdup_ps(__m256 a) +{ + return __builtin_shufflevector(a, a, 1, 1, 3, 3, 5, 5, 7, 7); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_moveldup_ps(__m256 a) +{ + return __builtin_shufflevector(a, a, 0, 0, 2, 2, 4, 4, 6, 6); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_movedup_pd(__m256d a) +{ + return __builtin_shufflevector(a, a, 0, 0, 2, 2); +} + +/* Unpack and Interleave */ +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_unpackhi_pd(__m256d a, __m256d b) +{ + return __builtin_shufflevector(a, b, 1, 5, 1+2, 5+2); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_unpacklo_pd(__m256d a, __m256d b) +{ + return __builtin_shufflevector(a, b, 0, 4, 0+2, 4+2); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_unpackhi_ps(__m256 a, __m256 b) +{ + return __builtin_shufflevector(a, b, 2, 10, 2+1, 10+1, 6, 14, 6+1, 14+1); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_unpacklo_ps(__m256 a, __m256 b) +{ + return __builtin_shufflevector(a, b, 0, 8, 0+1, 8+1, 4, 12, 4+1, 12+1); +} + +/* Bit Test */ +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm_testz_pd(__m128d a, __m128d b) +{ + return __builtin_ia32_vtestzpd((__v2df)a, (__v2df)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm_testc_pd(__m128d a, __m128d b) +{ + return __builtin_ia32_vtestcpd((__v2df)a, (__v2df)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm_testnzc_pd(__m128d a, __m128d b) +{ + return __builtin_ia32_vtestnzcpd((__v2df)a, (__v2df)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm_testz_ps(__m128 a, __m128 b) +{ + return __builtin_ia32_vtestzps((__v4sf)a, (__v4sf)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm_testc_ps(__m128 a, __m128 b) +{ + return __builtin_ia32_vtestcps((__v4sf)a, (__v4sf)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm_testnzc_ps(__m128 a, __m128 b) +{ + return __builtin_ia32_vtestnzcps((__v4sf)a, (__v4sf)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_testz_pd(__m256d a, __m256d b) +{ + return __builtin_ia32_vtestzpd256((__v4df)a, (__v4df)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_testc_pd(__m256d a, __m256d b) +{ + return __builtin_ia32_vtestcpd256((__v4df)a, (__v4df)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_testnzc_pd(__m256d a, __m256d b) +{ + return __builtin_ia32_vtestnzcpd256((__v4df)a, (__v4df)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_testz_ps(__m256 a, __m256 b) +{ + return __builtin_ia32_vtestzps256((__v8sf)a, (__v8sf)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_testc_ps(__m256 a, __m256 b) +{ + return __builtin_ia32_vtestcps256((__v8sf)a, (__v8sf)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_testnzc_ps(__m256 a, __m256 b) +{ + return __builtin_ia32_vtestnzcps256((__v8sf)a, (__v8sf)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_testz_si256(__m256i a, __m256i b) +{ + return __builtin_ia32_ptestz256((__v4di)a, (__v4di)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_testc_si256(__m256i a, __m256i b) +{ + return __builtin_ia32_ptestc256((__v4di)a, (__v4di)b); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_testnzc_si256(__m256i a, __m256i b) +{ + return __builtin_ia32_ptestnzc256((__v4di)a, (__v4di)b); +} + +/* Vector extract sign mask */ +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_movemask_pd(__m256d a) +{ + return __builtin_ia32_movmskpd256((__v4df)a); +} + +static __inline int __attribute__((__always_inline__, __nodebug__)) +_mm256_movemask_ps(__m256 a) +{ + return __builtin_ia32_movmskps256((__v8sf)a); +} + +/* Vector zero */ +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm256_zeroall(void) +{ + __builtin_ia32_vzeroall(); +} + +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm256_zeroupper(void) +{ + __builtin_ia32_vzeroupper(); +} + +/* Vector load with broadcast */ +static __inline __m128 __attribute__((__always_inline__, __nodebug__)) +_mm_broadcast_ss(float const *a) +{ + return (__m128)__builtin_ia32_vbroadcastss(a); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_broadcast_sd(double const *a) +{ + return (__m256d)__builtin_ia32_vbroadcastsd256(a); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_broadcast_ss(float const *a) +{ + return (__m256)__builtin_ia32_vbroadcastss256(a); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_broadcast_pd(__m128d const *a) +{ + return (__m256d)__builtin_ia32_vbroadcastf128_pd256(a); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_broadcast_ps(__m128 const *a) +{ + return (__m256)__builtin_ia32_vbroadcastf128_ps256(a); +} + +/* SIMD load ops */ +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_load_pd(double const *p) +{ + return *(__m256d *)p; +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_load_ps(float const *p) +{ + return *(__m256 *)p; +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_loadu_pd(double const *p) +{ + return (__m256d)__builtin_ia32_loadupd256(p); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_loadu_ps(float const *p) +{ + return (__m256)__builtin_ia32_loadups256(p); +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_load_si256(__m256i const *p) +{ + return *p; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_loadu_si256(__m256i const *p) +{ + return (__m256i)__builtin_ia32_loaddqu256((char const *)p); +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_lddqu_si256(__m256i const *p) +{ + return (__m256i)__builtin_ia32_lddqu256((char const *)p); +} + +/* SIMD store ops */ +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm256_store_pd(double *p, __m256d a) +{ + *(__m256d *)p = a; +} + +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm256_store_ps(float *p, __m256 a) +{ + *(__m256 *)p = a; +} + +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm256_storeu_pd(double *p, __m256d a) +{ + __builtin_ia32_storeupd256(p, (__v4df)a); +} + +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm256_storeu_ps(float *p, __m256 a) +{ + __builtin_ia32_storeups256(p, (__v8sf)a); +} + +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm256_store_si256(__m256i *p, __m256i a) +{ + *p = a; +} + +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm256_storeu_si256(__m256i *p, __m256i a) +{ + __builtin_ia32_storedqu256((char *)p, (__v32qi)a); +} + +/* Conditional load ops */ +static __inline __m128d __attribute__((__always_inline__, __nodebug__)) +_mm_maskload_pd(double const *p, __m128d m) +{ + return (__m128d)__builtin_ia32_maskloadpd((const __v2df *)p, (__v2df)m); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_maskload_pd(double const *p, __m256d m) +{ + return (__m256d)__builtin_ia32_maskloadpd256((const __v4df *)p, (__v4df)m); +} + +static __inline __m128 __attribute__((__always_inline__, __nodebug__)) +_mm_maskload_ps(float const *p, __m128 m) +{ + return (__m128)__builtin_ia32_maskloadps((const __v4sf *)p, (__v4sf)m); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_maskload_ps(float const *p, __m256 m) +{ + return (__m256)__builtin_ia32_maskloadps256((const __v8sf *)p, (__v8sf)m); +} + +/* Conditional store ops */ +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm256_maskstore_ps(float *p, __m256 m, __m256 a) +{ + __builtin_ia32_maskstoreps256((__v8sf *)p, (__v8sf)m, (__v8sf)a); +} + +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm_maskstore_pd(double *p, __m128d m, __m128d a) +{ + __builtin_ia32_maskstorepd((__v2df *)p, (__v2df)m, (__v2df)a); +} + +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm256_maskstore_pd(double *p, __m256d m, __m256d a) +{ + __builtin_ia32_maskstorepd256((__v4df *)p, (__v4df)m, (__v4df)a); +} + +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm_maskstore_ps(float *p, __m128 m, __m128 a) +{ + __builtin_ia32_maskstoreps((__v4sf *)p, (__v4sf)m, (__v4sf)a); +} + +/* Cacheability support ops */ +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm256_stream_si256(__m256i *a, __m256i b) +{ + __builtin_ia32_movntdq256((__v4di *)a, (__v4di)b); +} + +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm256_stream_pd(double *a, __m256d b) +{ + __builtin_ia32_movntpd256(a, (__v4df)b); +} + +static __inline void __attribute__((__always_inline__, __nodebug__)) +_mm256_stream_ps(float *p, __m256 a) +{ + __builtin_ia32_movntps256(p, (__v8sf)a); +} + +/* Create vectors */ +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_set_pd(double a, double b, double c, double d) +{ + return (__m256d){ d, c, b, a }; +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_set_ps(float a, float b, float c, float d, + float e, float f, float g, float h) +{ + return (__m256){ h, g, f, e, d, c, b, a }; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_set_epi32(int i0, int i1, int i2, int i3, + int i4, int i5, int i6, int i7) +{ + return (__m256i)(__v8si){ i7, i6, i5, i4, i3, i2, i1, i0 }; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_set_epi16(short w15, short w14, short w13, short w12, + short w11, short w10, short w09, short w08, + short w07, short w06, short w05, short w04, + short w03, short w02, short w01, short w00) +{ + return (__m256i)(__v16hi){ w00, w01, w02, w03, w04, w05, w06, w07, + w08, w09, w10, w11, w12, w13, w14, w15 }; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_set_epi8(char b31, char b30, char b29, char b28, + char b27, char b26, char b25, char b24, + char b23, char b22, char b21, char b20, + char b19, char b18, char b17, char b16, + char b15, char b14, char b13, char b12, + char b11, char b10, char b09, char b08, + char b07, char b06, char b05, char b04, + char b03, char b02, char b01, char b00) +{ + return (__m256i)(__v32qi){ + b00, b01, b02, b03, b04, b05, b06, b07, + b08, b09, b10, b11, b12, b13, b14, b15, + b16, b17, b18, b19, b20, b21, b22, b23, + b24, b25, b26, b27, b28, b29, b30, b31 + }; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_set_epi64x(long long a, long long b, long long c, long long d) +{ + return (__m256i)(__v4di){ d, c, b, a }; +} + +/* Create vectors with elements in reverse order */ +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_setr_pd(double a, double b, double c, double d) +{ + return (__m256d){ a, b, c, d }; +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_setr_ps(float a, float b, float c, float d, + float e, float f, float g, float h) +{ + return (__m256){ a, b, c, d, e, f, g, h }; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_setr_epi32(int i0, int i1, int i2, int i3, + int i4, int i5, int i6, int i7) +{ + return (__m256i)(__v8si){ i0, i1, i2, i3, i4, i5, i6, i7 }; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_setr_epi16(short w15, short w14, short w13, short w12, + short w11, short w10, short w09, short w08, + short w07, short w06, short w05, short w04, + short w03, short w02, short w01, short w00) +{ + return (__m256i)(__v16hi){ w15, w14, w13, w12, w11, w10, w09, w08, + w07, w06, w05, w04, w03, w02, w01, w00 }; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_setr_epi8(char b31, char b30, char b29, char b28, + char b27, char b26, char b25, char b24, + char b23, char b22, char b21, char b20, + char b19, char b18, char b17, char b16, + char b15, char b14, char b13, char b12, + char b11, char b10, char b09, char b08, + char b07, char b06, char b05, char b04, + char b03, char b02, char b01, char b00) +{ + return (__m256i)(__v32qi){ + b31, b30, b29, b28, b27, b26, b25, b24, + b23, b22, b21, b20, b19, b18, b17, b16, + b15, b14, b13, b12, b11, b10, b09, b08, + b07, b06, b05, b04, b03, b02, b01, b00 }; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_setr_epi64x(long long a, long long b, long long c, long long d) +{ + return (__m256i)(__v4di){ a, b, c, d }; +} + +/* Create vectors with repeated elements */ +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_set1_pd(double w) +{ + return (__m256d){ w, w, w, w }; +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_set1_ps(float w) +{ + return (__m256){ w, w, w, w, w, w, w, w }; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_set1_epi32(int i) +{ + return (__m256i)(__v8si){ i, i, i, i, i, i, i, i }; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_set1_epi16(short w) +{ + return (__m256i)(__v16hi){ w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w }; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_set1_epi8(char b) +{ + return (__m256i)(__v32qi){ b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, + b, b, b, b, b, b, b, b, b, b, b, b, b, b, b, b }; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_set1_epi64x(long long q) +{ + return (__m256i)(__v4di){ q, q, q, q }; +} + +/* Create zeroed vectors */ +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_setzero_pd(void) +{ + return (__m256d){ 0, 0, 0, 0 }; +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_setzero_ps(void) +{ + return (__m256){ 0, 0, 0, 0, 0, 0, 0, 0 }; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_setzero_si256(void) +{ + return (__m256i){ 0LL, 0LL, 0LL, 0LL }; +} + +/* Cast between vector types */ +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_castpd_ps(__m256d in) +{ + return (__m256)in; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_castpd_si256(__m256d in) +{ + return (__m256i)in; +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_castps_pd(__m256 in) +{ + return (__m256d)in; +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_castps_si256(__m256 in) +{ + return (__m256i)in; +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_castsi256_ps(__m256i in) +{ + return (__m256)in; +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_castsi256_pd(__m256i in) +{ + return (__m256d)in; +} + +static __inline __m128d __attribute__((__always_inline__, __nodebug__)) +_mm256_castpd256_pd128(__m256d in) +{ + return __builtin_shufflevector(in, in, 0, 1); +} + +static __inline __m128 __attribute__((__always_inline__, __nodebug__)) +_mm256_castps256_ps128(__m256 in) +{ + return __builtin_shufflevector(in, in, 0, 1, 2, 3); +} + +static __inline __m128i __attribute__((__always_inline__, __nodebug__)) +_mm256_castsi256_si128(__m256i in) +{ + return __builtin_shufflevector(in, in, 0, 1); +} + +static __inline __m256d __attribute__((__always_inline__, __nodebug__)) +_mm256_castpd128_pd256(__m128d in) +{ + __m128d zero = _mm_setzero_pd(); + return __builtin_shufflevector(in, zero, 0, 1, 2, 2); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_castps128_ps256(__m128 in) +{ + __m128 zero = _mm_setzero_ps(); + return __builtin_shufflevector(in, zero, 0, 1, 2, 3, 4, 4, 4, 4); +} + +static __inline __m256i __attribute__((__always_inline__, __nodebug__)) +_mm256_castsi128_si256(__m128i in) +{ + __m128i zero = _mm_setzero_si128(); + return __builtin_shufflevector(in, zero, 0, 1, 2, 2); +} diff --git a/lib/Headers/emmintrin.h b/lib/Headers/emmintrin.h index f297f36..e5dfe26 100644 --- a/lib/Headers/emmintrin.h +++ b/lib/Headers/emmintrin.h @@ -1,4 +1,4 @@ -/*===---- xmmintrin.h - SSE intrinsics -------------------------------------=== +/*===---- emmintrin.h - SSE2 intrinsics ------------------------------------=== * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,7 +20,7 @@ * *===-----------------------------------------------------------------------=== */ - + #ifndef __EMMINTRIN_H #define __EMMINTRIN_H @@ -33,6 +33,9 @@ typedef double __m128d __attribute__((__vector_size__(16))); typedef long long __m128i __attribute__((__vector_size__(16))); +/* Type defines. */ +typedef double __v2df __attribute__ ((__vector_size__ (16))); +typedef long long __v2di __attribute__ ((__vector_size__ (16))); typedef short __v8hi __attribute__((__vector_size__(16))); typedef char __v16qi __attribute__((__vector_size__(16))); @@ -1194,7 +1197,7 @@ static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_extract_epi16(__m128i a, int imm) { __v8hi b = (__v8hi)a; - return b[imm]; + return (unsigned short)b[imm]; } static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h new file mode 100644 index 0000000..a19deaa --- /dev/null +++ b/lib/Headers/immintrin.h @@ -0,0 +1,59 @@ +/*===---- immintrin.h - Intel intrinsics -----------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __IMMINTRIN_H +#define __IMMINTRIN_H + +#ifdef __MMX__ +#include +#endif + +#ifdef __SSE__ +#include +#endif + +#ifdef __SSE2__ +#include +#endif + +#ifdef __SSE3__ +#include +#endif + +#ifdef __SSSE3__ +#include +#endif + +#if defined (__SSE4_2__) || defined (__SSE4_1__) +#include +#endif + +#if defined (__AES__) || defined (__PCLMUL__) +#include +#endif + +#ifdef __AVX__ +#include +#endif + +#endif /* __IMMINTRIN_H */ diff --git a/lib/Headers/mmintrin.h b/lib/Headers/mmintrin.h index 401d8a7..bad9e1c 100644 --- a/lib/Headers/mmintrin.h +++ b/lib/Headers/mmintrin.h @@ -443,6 +443,64 @@ _mm_setr_pi8(char __b7, char __b6, char __b5, char __b4, char __b3, char __b2, return (__m64)(__v8qi){ __b7, __b6, __b5, __b4, __b3, __b2, __b1, __b0 }; } + +/* Aliases for compatibility. */ +#define _m_empty _mm_empty +#define _m_from_int _mm_cvtsi32_si64 +#define _m_to_int _mm_cvtsi64_si32 +#define _m_packsswb _mm_packs_pi16 +#define _m_packssdw _mm_packs_pi32 +#define _m_packuswb _mm_packs_pu16 +#define _m_punpckhbw _mm_unpackhi_pi8 +#define _m_punpckhwd _mm_unpackhi_pi16 +#define _m_punpckhdq _mm_unpackhi_pi32 +#define _m_punpcklbw _mm_unpacklo_pi8 +#define _m_punpcklwd _mm_unpacklo_pi16 +#define _m_punpckldq _mm_unpacklo_pi32 +#define _m_paddb _mm_add_pi8 +#define _m_paddw _mm_add_pi16 +#define _m_paddd _mm_add_pi32 +#define _m_paddsb _mm_adds_pi8 +#define _m_paddsw _mm_adds_pi16 +#define _m_paddusb _mm_adds_pu8 +#define _m_paddusw _mm_adds_pu16 +#define _m_psubb _mm_sub_pi8 +#define _m_psubw _mm_sub_pi16 +#define _m_psubd _mm_sub_pi32 +#define _m_psubsb _mm_subs_pi8 +#define _m_psubsw _mm_subs_pi16 +#define _m_psubusb _mm_subs_pu8 +#define _m_psubusw _mm_subs_pu16 +#define _m_pmaddwd _mm_madd_pi16 +#define _m_pmulhw _mm_mulhi_pi16 +#define _m_pmullw _mm_mullo_pi16 +#define _m_psllw _mm_sll_pi16 +#define _m_psllwi _mm_slli_pi16 +#define _m_pslld _mm_sll_pi32 +#define _m_pslldi _mm_slli_pi32 +#define _m_psllq _mm_sll_si64 +#define _m_psllqi _mm_slli_si64 +#define _m_psraw _mm_sra_pi16 +#define _m_psrawi _mm_srai_pi16 +#define _m_psrad _mm_sra_pi32 +#define _m_psradi _mm_srai_pi32 +#define _m_psrlw _mm_srl_pi16 +#define _m_psrlwi _mm_srli_pi16 +#define _m_psrld _mm_srl_pi32 +#define _m_psrldi _mm_srli_pi32 +#define _m_psrlq _mm_srl_si64 +#define _m_psrlqi _mm_srli_si64 +#define _m_pand _mm_and_si64 +#define _m_pandn _mm_andnot_si64 +#define _m_por _mm_or_si64 +#define _m_pxor _mm_xor_si64 +#define _m_pcmpeqb _mm_cmpeq_pi8 +#define _m_pcmpeqw _mm_cmpeq_pi16 +#define _m_pcmpeqd _mm_cmpeq_pi32 +#define _m_pcmpgtb _mm_cmpgt_pi8 +#define _m_pcmpgtw _mm_cmpgt_pi16 +#define _m_pcmpgtd _mm_cmpgt_pi32 + #endif /* __MMX__ */ #endif /* __MMINTRIN_H */ diff --git a/lib/Headers/nmmintrin.h b/lib/Headers/nmmintrin.h index cc213ce..f12622d 100644 --- a/lib/Headers/nmmintrin.h +++ b/lib/Headers/nmmintrin.h @@ -1,25 +1,25 @@ -/*===---- nmmintrin.h - SSE intrinsics -------------------------------------=== -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -* -*===-----------------------------------------------------------------------=== -*/ +/*===---- nmmintrin.h - SSE4 intrinsics ------------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ #ifndef _NMMINTRIN_H #define _NMMINTRIN_H diff --git a/lib/Headers/smmintrin.h b/lib/Headers/smmintrin.h index 4b0d9e7..2b8b321 100644 --- a/lib/Headers/smmintrin.h +++ b/lib/Headers/smmintrin.h @@ -30,10 +30,6 @@ #include -/* Type defines. */ -typedef double __v2df __attribute__ ((__vector_size__ (16))); -typedef long long __v2di __attribute__ ((__vector_size__ (16))); - /* SSE4 Rounding macros. */ #define _MM_FROUND_TO_NEAREST_INT 0x00 #define _MM_FROUND_TO_NEG_INF 0x01 @@ -213,11 +209,13 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) __a;})) #endif /* __x86_64__ */ -/* Extract int from packed integer array at index. */ +/* Extract int from packed integer array at index. This returns the element + * as a zero extended value, so it is unsigned. + */ #define _mm_extract_epi8(X, N) (__extension__ ({ __v16qi __a = (__v16qi)(X); \ - __a[N];})) + (unsigned char)__a[N];})) #define _mm_extract_epi32(X, N) (__extension__ ({ __v4si __a = (__v4si)(X); \ - __a[N];})) + (unsigned)__a[N];})) #ifdef __x86_64__ #define _mm_extract_epi64(X, N) (__extension__ ({ __v2di __a = (__v2di)(X); \ __a[N];})) diff --git a/lib/Headers/stddef.h b/lib/Headers/stddef.h index b1d0d52..84ec1a7 100644 --- a/lib/Headers/stddef.h +++ b/lib/Headers/stddef.h @@ -34,12 +34,13 @@ typedef __typeof__(sizeof(int)) size_t; #ifndef __cplusplus #ifndef _WCHAR_T #define _WCHAR_T -typedef __typeof__(*L"") wchar_t; +typedef __WCHAR_TYPE__ wchar_t; #endif #endif #undef NULL #ifdef __cplusplus +#undef __null // VC++ hack. #define NULL __null #else #define NULL ((void*)0) diff --git a/lib/Headers/x86intrin.h b/lib/Headers/x86intrin.h new file mode 100644 index 0000000..e5e7a6a --- /dev/null +++ b/lib/Headers/x86intrin.h @@ -0,0 +1,31 @@ +/*===---- x86intrin.h - X86 intrinsics -------------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __X86INTRIN_H +#define __X86INTRIN_H + +#include + +// FIXME: SSE4A, 3dNOW, FMA4, XOP, LWP, ABM, POPCNT + +#endif /* __X86INTRIN_H */ diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h index 75e06b5..8363b45 100644 --- a/lib/Headers/xmmintrin.h +++ b/lib/Headers/xmmintrin.h @@ -416,6 +416,12 @@ _mm_cvtps_pi32(__m128 a) return (__m64)__builtin_ia32_cvtps2pi(a); } +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_mm_cvt_ps2pi(__m128 a) +{ + return _mm_cvtps_pi32(a); +} + static __inline__ int __attribute__((__always_inline__, __nodebug__)) _mm_cvttss_si32(__m128 a) { @@ -440,6 +446,12 @@ _mm_cvttps_pi32(__m128 a) return (__m64)__builtin_ia32_cvttps2pi(a); } +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_mm_cvtt_ps2pi(__m128 a) +{ + return _mm_cvttps_pi32(a); +} + static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_cvtsi32_ss(__m128 a, int b) { @@ -447,6 +459,12 @@ _mm_cvtsi32_ss(__m128 a, int b) return a; } +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) +_mm_cvt_si2ss(__m128 a, int b) +{ + return _mm_cvtsi32_ss(a, b); +} + #ifdef __x86_64__ static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) @@ -464,6 +482,12 @@ _mm_cvtpi32_ps(__m128 a, __m64 b) return __builtin_ia32_cvtpi2ps(a, (__v2si)b); } +static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) +_mm_cvt_pi2ps(__m128 a, __m64 b) +{ + return _mm_cvtpi32_ps(a, b); +} + static __inline__ float __attribute__((__always_inline__, __nodebug__)) _mm_cvtss_f32(__m128 a) { @@ -590,6 +614,12 @@ _mm_store1_ps(float *p, __m128 a) } static __inline__ void __attribute__((__always_inline__, __nodebug__)) +_mm_store_ps1(float *p, __m128 a) +{ + return _mm_store1_ps(p, a); +} + +static __inline__ void __attribute__((__always_inline__, __nodebug__)) _mm_store_ps(float *p, __m128 a) { *(__m128 *)p = a; @@ -602,9 +632,9 @@ _mm_storer_ps(float *p, __m128 a) _mm_store_ps(p, a); } -#define _MM_HINT_T0 1 +#define _MM_HINT_T0 3 #define _MM_HINT_T1 2 -#define _MM_HINT_T2 3 +#define _MM_HINT_T2 1 #define _MM_HINT_NTA 0 /* FIXME: We have to #define this because "sel" must be a constant integer, and @@ -908,6 +938,23 @@ do { \ (row3) = _mm_movehl_ps(tmp3, tmp1); \ } while (0) +/* Aliases for compatibility. */ +#define _m_pextrw _mm_extract_pi16 +#define _m_pinsrw _mm_insert_pi16 +#define _m_pmaxsw _mm_max_pi16 +#define _m_pmaxub _mm_max_pu8 +#define _m_pminsw _mm_min_pi16 +#define _m_pminub _mm_min_pu8 +#define _m_pmovmskb _mm_movemask_pi8 +#define _m_pmulhuw _mm_mulhi_pu16 +#define _m_pshufw _mm_shuffle_pi16 +#define _m_maskmovq _mm_maskmove_si64 +#define _m_pavgb _mm_avg_pu8 +#define _m_pavgw _mm_avg_pu16 +#define _m_psadbw _mm_sad_pu8 +#define _m_ _mm_ +#define _m_ _mm_ + /* Ugly hack for backwards-compatibility (compatible with gcc) */ #ifdef __SSE2__ #include diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt index 4d67035..61f69b2 100644 --- a/lib/Index/CMakeLists.txt +++ b/lib/Index/CMakeLists.txt @@ -11,6 +11,5 @@ add_clang_library(clangIndex IndexProvider.cpp Indexer.cpp Program.cpp - ResolveLocation.cpp SelectorMap.cpp ) diff --git a/lib/Index/Entity.cpp b/lib/Index/Entity.cpp index 7a24719..749dcc8 100644 --- a/lib/Index/Entity.cpp +++ b/lib/Index/Entity.cpp @@ -134,7 +134,7 @@ Entity EntityGetter::VisitVarDecl(VarDecl *D) { return Entity(); // If it's static it cannot be referred to by another translation unit. - if (D->getStorageClass() == VarDecl::Static) + if (D->getStorageClass() == SC_Static) return Entity(D); return VisitNamedDecl(D); @@ -142,7 +142,7 @@ Entity EntityGetter::VisitVarDecl(VarDecl *D) { Entity EntityGetter::VisitFunctionDecl(FunctionDecl *D) { // If it's static it cannot be refered to by another translation unit. - if (D->getStorageClass() == FunctionDecl::Static) + if (D->getStorageClass() == SC_Static) return Entity(D); return VisitNamedDecl(D); diff --git a/lib/Index/Makefile b/lib/Index/Makefile index e87e638..8607d78 100644 --- a/lib/Index/Makefile +++ b/lib/Index/Makefile @@ -13,7 +13,6 @@ CLANG_LEVEL := ../.. LIBRARYNAME := clangIndex -BUILD_ARCHIVE = 1 include $(CLANG_LEVEL)/Makefile diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp deleted file mode 100644 index ccd7a12..0000000 --- a/lib/Index/ResolveLocation.cpp +++ /dev/null @@ -1,602 +0,0 @@ -//===--- ResolveLocation.cpp - Source location resolver ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This defines the ResolveLocationInAST function, which resolves a -// source location into a ASTLocation. -// -//===----------------------------------------------------------------------===// - -#include "clang/Index/Utils.h" -#include "clang/Index/ASTLocation.h" -#include "clang/AST/TypeLocVisitor.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/Lex/Lexer.h" -#include "clang/Basic/SourceManager.h" -using namespace clang; -using namespace idx; - -namespace { - -/// \brief Base for the LocResolver classes. Mostly does source range checking. -class LocResolverBase { -protected: - ASTContext &Ctx; - SourceLocation Loc; - - ASTLocation ResolveInDeclarator(Decl *D, Stmt *Stm, TypeSourceInfo *TInfo); - - enum RangePos { - BeforeLoc, - ContainsLoc, - AfterLoc - }; - - RangePos CheckRange(SourceRange Range); - RangePos CheckRange(TypeSourceInfo *TInfo); - RangePos CheckRange(Decl *D) { - if (DeclaratorDecl *DD = dyn_cast(D)) - if (ContainsLocation(DD->getTypeSourceInfo())) - return ContainsLoc; - if (TypedefDecl *TD = dyn_cast(D)) - if (ContainsLocation(TD->getTypeSourceInfo())) - return ContainsLoc; - - return CheckRange(D->getSourceRange()); - } - RangePos CheckRange(Stmt *Node) { return CheckRange(Node->getSourceRange()); } - RangePos CheckRange(TypeLoc TL) { return CheckRange(TL.getLocalSourceRange()); } - - template - bool isBeforeLocation(T Node) { - return CheckRange(Node) == BeforeLoc; - } - - template - bool isAfterLocation(T Node) { - return CheckRange(Node) == AfterLoc; - } - -public: - LocResolverBase(ASTContext &ctx, SourceLocation loc) - : Ctx(ctx), Loc(loc) {} - - template - bool ContainsLocation(T Node) { - return CheckRange(Node) == ContainsLoc; - } - -#ifndef NDEBUG - /// \brief Debugging output. - void print(Decl *D); - /// \brief Debugging output. - void print(Stmt *Node); -#endif -}; - -/// \brief Searches a statement for the ASTLocation that corresponds to a source -/// location. -class StmtLocResolver : public LocResolverBase, - public StmtVisitor { - Decl * const Parent; - -public: - StmtLocResolver(ASTContext &ctx, SourceLocation loc, Decl *parent) - : LocResolverBase(ctx, loc), Parent(parent) {} - - ASTLocation VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node); - ASTLocation VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node); - ASTLocation VisitDeclStmt(DeclStmt *Node); - ASTLocation VisitStmt(Stmt *Node); -}; - -/// \brief Searches a declaration for the ASTLocation that corresponds to a -/// source location. -class DeclLocResolver : public LocResolverBase, - public DeclVisitor { -public: - DeclLocResolver(ASTContext &ctx, SourceLocation loc) - : LocResolverBase(ctx, loc) {} - - ASTLocation VisitDeclContext(DeclContext *DC); - ASTLocation VisitTranslationUnitDecl(TranslationUnitDecl *TU); - ASTLocation VisitDeclaratorDecl(DeclaratorDecl *D); - ASTLocation VisitVarDecl(VarDecl *D); - ASTLocation VisitFunctionDecl(FunctionDecl *D); - ASTLocation VisitObjCClassDecl(ObjCClassDecl *D); - ASTLocation VisitObjCMethodDecl(ObjCMethodDecl *D); - ASTLocation VisitTypedefDecl(TypedefDecl *D); - ASTLocation VisitDecl(Decl *D); -}; - -class TypeLocResolver : public LocResolverBase, - public TypeLocVisitor { - Decl * const ParentDecl; - -public: - TypeLocResolver(ASTContext &ctx, SourceLocation loc, Decl *pd) - : LocResolverBase(ctx, loc), ParentDecl(pd) { } - - ASTLocation VisitBuiltinTypeLoc(BuiltinTypeLoc TL); - ASTLocation VisitTypedefTypeLoc(TypedefTypeLoc TL); - ASTLocation VisitFunctionTypeLoc(FunctionTypeLoc TL); - ASTLocation VisitArrayTypeLoc(ArrayTypeLoc TL); - ASTLocation VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); - ASTLocation VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL); - ASTLocation VisitTypeLoc(TypeLoc TL); -}; - -} // anonymous namespace - -ASTLocation -StmtLocResolver::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { - assert(ContainsLocation(Node) && - "Should visit only after verifying that loc is in range"); - - if (Node->isArgumentType()) { - TypeSourceInfo *TInfo = Node->getArgumentTypeInfo(); - if (ContainsLocation(TInfo)) - return ResolveInDeclarator(Parent, Node, TInfo); - } else { - Expr *SubNode = Node->getArgumentExpr(); - if (ContainsLocation(SubNode)) - return Visit(SubNode); - } - - return ASTLocation(Parent, Node); -} - - -ASTLocation -StmtLocResolver::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) { - assert(ContainsLocation(Node) && - "Should visit only after verifying that loc is in range"); - - if (Node->getNumArgs() == 1) - // Unary operator. Let normal child traversal handle it. - return VisitCallExpr(Node); - - assert(Node->getNumArgs() == 2 && - "Wrong args for the C++ operator call expr ?"); - - llvm::SmallVector Nodes; - // Binary operator. Check in order of 1-left arg, 2-callee, 3-right arg. - Nodes.push_back(Node->getArg(0)); - Nodes.push_back(Node->getCallee()); - Nodes.push_back(Node->getArg(1)); - - for (unsigned i = 0, e = Nodes.size(); i != e; ++i) { - RangePos RP = CheckRange(Nodes[i]); - if (RP == AfterLoc) - break; - if (RP == ContainsLoc) - return Visit(Nodes[i]); - } - - return ASTLocation(Parent, Node); -} - -ASTLocation StmtLocResolver::VisitDeclStmt(DeclStmt *Node) { - assert(ContainsLocation(Node) && - "Should visit only after verifying that loc is in range"); - - // Search all declarations of this DeclStmt. - for (DeclStmt::decl_iterator - I = Node->decl_begin(), E = Node->decl_end(); I != E; ++I) { - RangePos RP = CheckRange(*I); - if (RP == AfterLoc) - break; - if (RP == ContainsLoc) - return DeclLocResolver(Ctx, Loc).Visit(*I); - } - - return ASTLocation(Parent, Node); -} - -ASTLocation StmtLocResolver::VisitStmt(Stmt *Node) { - assert(ContainsLocation(Node) && - "Should visit only after verifying that loc is in range"); - - // Search the child statements. - for (Stmt::child_iterator - I = Node->child_begin(), E = Node->child_end(); I != E; ++I) { - if (*I == NULL) - continue; - - RangePos RP = CheckRange(*I); - if (RP == AfterLoc) - break; - if (RP == ContainsLoc) - return Visit(*I); - } - - return ASTLocation(Parent, Node); -} - -ASTLocation DeclLocResolver::VisitDeclContext(DeclContext *DC) { - for (DeclContext::decl_iterator - I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { - RangePos RP = CheckRange(*I); - if (RP == AfterLoc) - break; - if (RP == ContainsLoc) - return Visit(*I); - } - - return ASTLocation(cast(DC)); -} - -ASTLocation DeclLocResolver::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { - ASTLocation ASTLoc = VisitDeclContext(TU); - if (ASTLoc.getParentDecl() == TU) - return ASTLocation(); - return ASTLoc; -} - -ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) { - assert(ContainsLocation(D) && - "Should visit only after verifying that loc is in range"); - - if (ContainsLocation(D->getTypeSourceInfo())) - return ResolveInDeclarator(D, 0, D->getTypeSourceInfo()); - - // First, search through the parameters of the function. - for (FunctionDecl::param_iterator - I = D->param_begin(), E = D->param_end(); I != E; ++I) { - RangePos RP = CheckRange(*I); - if (RP == AfterLoc) - return ASTLocation(D); - if (RP == ContainsLoc) - return Visit(*I); - } - - // We didn't find the location in the parameters and we didn't get passed it. - - if (!D->isThisDeclarationADefinition()) - return ASTLocation(D); - - // Second, search through the declarations that are part of the function. - // If we find the location there, we won't have to search through its body. - - for (DeclContext::decl_iterator - I = D->decls_begin(), E = D->decls_end(); I != E; ++I) { - if (isa(*I)) - continue; // We already searched through the parameters. - - RangePos RP = CheckRange(*I); - if (RP == AfterLoc) - break; - if (RP == ContainsLoc) - return Visit(*I); - } - - // We didn't find a declaration that corresponds to the source location. - - // Finally, search through the body of the function. - Stmt *Body = D->getBody(); - assert(Body && "Expected definition"); - assert(!isBeforeLocation(Body) && - "This function is supposed to contain the loc"); - if (isAfterLocation(Body)) - return ASTLocation(D); - - // The body contains the location. - assert(ContainsLocation(Body)); - return StmtLocResolver(Ctx, Loc, D).Visit(Body); -} - -ASTLocation DeclLocResolver::VisitDeclaratorDecl(DeclaratorDecl *D) { - assert(ContainsLocation(D) && - "Should visit only after verifying that loc is in range"); - if (ContainsLocation(D->getTypeSourceInfo())) - return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeSourceInfo()); - - return ASTLocation(D); -} - -ASTLocation DeclLocResolver::VisitTypedefDecl(TypedefDecl *D) { - assert(ContainsLocation(D) && - "Should visit only after verifying that loc is in range"); - - if (ContainsLocation(D->getTypeSourceInfo())) - return ResolveInDeclarator(D, /*Stmt=*/0, D->getTypeSourceInfo()); - - return ASTLocation(D); -} - -ASTLocation DeclLocResolver::VisitVarDecl(VarDecl *D) { - assert(ContainsLocation(D) && - "Should visit only after verifying that loc is in range"); - - // Check whether the location points to the init expression. - Expr *Init = D->getInit(); - if (Init && ContainsLocation(Init)) - return StmtLocResolver(Ctx, Loc, D).Visit(Init); - - if (ContainsLocation(D->getTypeSourceInfo())) - return ResolveInDeclarator(D, 0, D->getTypeSourceInfo()); - - return ASTLocation(D); -} - -ASTLocation DeclLocResolver::VisitObjCClassDecl(ObjCClassDecl *D) { - assert(ContainsLocation(D) && - "Should visit only after verifying that loc is in range"); - - for (ObjCClassDecl::iterator I = D->begin(), E = D->end() ; I != E; ++I) { - if (CheckRange(I->getLocation()) == ContainsLoc) - return ASTLocation(D, I->getInterface(), I->getLocation()); - } - return ASTLocation(D); -} - -ASTLocation DeclLocResolver::VisitObjCMethodDecl(ObjCMethodDecl *D) { - assert(ContainsLocation(D) && - "Should visit only after verifying that loc is in range"); - - // First, search through the parameters of the method. - for (ObjCMethodDecl::param_iterator - I = D->param_begin(), E = D->param_end(); I != E; ++I) { - RangePos RP = CheckRange(*I); - if (RP == AfterLoc) - return ASTLocation(D); - if (RP == ContainsLoc) - return Visit(*I); - } - - // We didn't find the location in the parameters and we didn't get passed it. - - if (!D->getBody()) - return ASTLocation(D); - - // Second, search through the declarations that are part of the method. - // If we find he location there, we won't have to search through its body. - - for (DeclContext::decl_iterator - I = D->decls_begin(), E = D->decls_end(); I != E; ++I) { - if (isa(*I)) - continue; // We already searched through the parameters. - - RangePos RP = CheckRange(*I); - if (RP == AfterLoc) - break; - if (RP == ContainsLoc) - return Visit(*I); - } - - // We didn't find a declaration that corresponds to the source location. - - // Finally, search through the body of the method. - Stmt *Body = D->getBody(); - assert(Body && "Expected definition"); - assert(!isBeforeLocation(Body) && - "This method is supposed to contain the loc"); - if (isAfterLocation(Body)) - return ASTLocation(D); - - // The body contains the location. - assert(ContainsLocation(Body)); - return StmtLocResolver(Ctx, Loc, D).Visit(Body); -} - -ASTLocation DeclLocResolver::VisitDecl(Decl *D) { - assert(ContainsLocation(D) && - "Should visit only after verifying that loc is in range"); - if (DeclContext *DC = dyn_cast(D)) - return VisitDeclContext(DC); - return ASTLocation(D); -} - -ASTLocation TypeLocResolver::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { - // Continue the 'id' magic by making the builtin type (which cannot - // actually be spelled) map to the typedef. - BuiltinType *T = TL.getTypePtr(); - if (T->getKind() == BuiltinType::ObjCId) { - TypedefDecl *D = Ctx.getObjCIdType()->getAs()->getDecl(); - return ASTLocation(ParentDecl, D, TL.getNameLoc()); - } - - // Same thing with 'Class'. - if (T->getKind() == BuiltinType::ObjCClass) { - TypedefDecl *D = Ctx.getObjCClassType()->getAs()->getDecl(); - return ASTLocation(ParentDecl, D, TL.getNameLoc()); - } - - return ASTLocation(ParentDecl, TL); -} - -ASTLocation TypeLocResolver::VisitTypedefTypeLoc(TypedefTypeLoc TL) { - assert(ContainsLocation(TL) && - "Should visit only after verifying that loc is in range"); - if (ContainsLocation(TL.getNameLoc())) - return ASTLocation(ParentDecl, TL.getTypedefDecl(), TL.getNameLoc()); - return ASTLocation(ParentDecl, TL); -} - -ASTLocation TypeLocResolver::VisitFunctionTypeLoc(FunctionTypeLoc TL) { - assert(ContainsLocation(TL) && - "Should visit only after verifying that loc is in range"); - - for (unsigned i = 0; i != TL.getNumArgs(); ++i) { - ParmVarDecl *Parm = TL.getArg(i); - RangePos RP = CheckRange(Parm); - if (RP == AfterLoc) - break; - if (RP == ContainsLoc) - return DeclLocResolver(Ctx, Loc).Visit(Parm); - } - - return ASTLocation(ParentDecl, TL); -} - -ASTLocation TypeLocResolver::VisitArrayTypeLoc(ArrayTypeLoc TL) { - assert(ContainsLocation(TL) && - "Should visit only after verifying that loc is in range"); - - Expr *E = TL.getSizeExpr(); - if (E && ContainsLocation(E)) - return StmtLocResolver(Ctx, Loc, ParentDecl).Visit(E); - - return ASTLocation(ParentDecl, TL); -} - -ASTLocation TypeLocResolver::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { - assert(ContainsLocation(TL) && - "Should visit only after verifying that loc is in range"); - if (ContainsLocation(TL.getNameLoc())) - return ASTLocation(ParentDecl, TL.getIFaceDecl(), TL.getNameLoc()); - - return ASTLocation(ParentDecl, TL); -} - -ASTLocation TypeLocResolver::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { - assert(ContainsLocation(TL) && - "Should visit only after verifying that loc is in range"); - - for (unsigned i = 0; i != TL.getNumProtocols(); ++i) { - SourceLocation L = TL.getProtocolLoc(i); - RangePos RP = CheckRange(L); - if (RP == AfterLoc) - break; - if (RP == ContainsLoc) - return ASTLocation(ParentDecl, TL.getProtocol(i), L); - } - - return ASTLocation(ParentDecl, TL); -} - -ASTLocation TypeLocResolver::VisitTypeLoc(TypeLoc TL) { - assert(ContainsLocation(TL) && - "Should visit only after verifying that loc is in range"); - return ASTLocation(ParentDecl, TL); -} - -ASTLocation LocResolverBase::ResolveInDeclarator(Decl *D, Stmt *Stm, - TypeSourceInfo *TInfo) { - assert(ContainsLocation(TInfo) && - "Should visit only after verifying that loc is in range"); - - (void)TypeLocResolver(Ctx, Loc, D); - for (TypeLoc TL = TInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc()) - if (ContainsLocation(TL)) - return TypeLocResolver(Ctx, Loc, D).Visit(TL); - - assert(0 && "Should have found the loc in a typeloc"); - return ASTLocation(D, Stm); -} - -LocResolverBase::RangePos LocResolverBase::CheckRange(TypeSourceInfo *TInfo) { - if (!TInfo) - return BeforeLoc; // Keep looking. - - for (TypeLoc TL = TInfo->getTypeLoc(); TL; TL = TL.getNextTypeLoc()) - if (ContainsLocation(TL)) - return ContainsLoc; - - return BeforeLoc; // Keep looking. -} - -LocResolverBase::RangePos LocResolverBase::CheckRange(SourceRange Range) { - if (!Range.isValid()) - return BeforeLoc; // Keep looking. - - // Update the end source range to cover the full length of the token - // positioned at the end of the source range. - // - // e.g., - // int foo - // ^ ^ - // - // will be updated to - // int foo - // ^ ^ - unsigned TokSize = Lexer::MeasureTokenLength(Range.getEnd(), - Ctx.getSourceManager(), - Ctx.getLangOptions()); - Range.setEnd(Range.getEnd().getFileLocWithOffset(TokSize-1)); - - SourceManager &SourceMgr = Ctx.getSourceManager(); - if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), Loc)) - return BeforeLoc; - - if (SourceMgr.isBeforeInTranslationUnit(Loc, Range.getBegin())) - return AfterLoc; - - return ContainsLoc; -} - -#ifndef NDEBUG -void LocResolverBase::print(Decl *D) { - llvm::raw_ostream &OS = llvm::outs(); - OS << "#### DECL " << D->getDeclKindName() << " ####\n"; - D->print(OS); - OS << " <"; - D->getLocStart().print(OS, Ctx.getSourceManager()); - OS << " > - <"; - D->getLocEnd().print(OS, Ctx.getSourceManager()); - OS << ">\n\n"; - OS.flush(); -} - -void LocResolverBase::print(Stmt *Node) { - llvm::raw_ostream &OS = llvm::outs(); - OS << "#### STMT " << Node->getStmtClassName() << " ####\n"; - Node->printPretty(OS, Ctx, 0, PrintingPolicy(Ctx.getLangOptions())); - OS << " <"; - Node->getLocStart().print(OS, Ctx.getSourceManager()); - OS << " > - <"; - Node->getLocEnd().print(OS, Ctx.getSourceManager()); - OS << ">\n\n"; - OS.flush(); -} -#endif - - -/// \brief Returns the AST node that a source location points to. -/// -ASTLocation idx::ResolveLocationInAST(ASTContext &Ctx, SourceLocation Loc, - ASTLocation *LastLoc) { - if (Loc.isInvalid()) - return ASTLocation(); - - if (LastLoc && LastLoc->isValid()) { - DeclContext *DC = 0; - - if (Decl *Dcl = LastLoc->dyn_AsDecl()) { - DC = Dcl->getDeclContext(); - } else if (LastLoc->isStmt()) { - Decl *Parent = LastLoc->getParentDecl(); - if (FunctionDecl *FD = dyn_cast(Parent)) - DC = FD; - else { - // This is needed to handle statements within an initializer. - // Example: - // void func() { long double fabsf = __builtin_fabsl(__x); } - // In this case, the 'parent' of __builtin_fabsl is fabsf. - DC = Parent->getDeclContext(); - } - } else { // We have 'N_NamedRef' or 'N_Type' - DC = LastLoc->getParentDecl()->getDeclContext(); - } - assert(DC && "Missing DeclContext"); - - FunctionDecl *FD = dyn_cast(DC); - DeclLocResolver DLocResolver(Ctx, Loc); - - if (FD && FD->isThisDeclarationADefinition() && - DLocResolver.ContainsLocation(FD)) { - return DLocResolver.VisitFunctionDecl(FD); - } - // Fall through and try the slow path... - // FIXME: Optimize more cases. - } - return DeclLocResolver(Ctx, Loc).Visit(Ctx.getTranslationUnitDecl()); -} diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 91b14f6..917829b 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -27,7 +27,9 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/LexDiagnostic.h" +#include "clang/Lex/CodeCompletionHandler.h" #include "clang/Basic/SourceManager.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include @@ -247,6 +249,200 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc, return TheTok.getLength(); } +SourceLocation Lexer::GetBeginningOfToken(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts) { + std::pair LocInfo = SM.getDecomposedLoc(Loc); + bool Invalid = false; + llvm::StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return Loc; + + // Back up from the current location until we hit the beginning of a line + // (or the buffer). We'll relex from that point. + const char *BufStart = Buffer.data(); + const char *StrData = BufStart+LocInfo.second; + if (StrData[0] == '\n' || StrData[0] == '\r') + return Loc; + + const char *LexStart = StrData; + while (LexStart != BufStart) { + if (LexStart[0] == '\n' || LexStart[0] == '\r') { + ++LexStart; + break; + } + + --LexStart; + } + + // Create a lexer starting at the beginning of this token. + SourceLocation LexerStartLoc = Loc.getFileLocWithOffset(-LocInfo.second); + Lexer TheLexer(LexerStartLoc, LangOpts, BufStart, LexStart, Buffer.end()); + TheLexer.SetCommentRetentionState(true); + + // Lex tokens until we find the token that contains the source location. + Token TheTok; + do { + TheLexer.LexFromRawLexer(TheTok); + + if (TheLexer.getBufferLocation() > StrData) { + // Lexing this token has taken the lexer past the source location we're + // looking for. If the current token encompasses our source location, + // return the beginning of that token. + if (TheLexer.getBufferLocation() - TheTok.getLength() <= StrData) + return TheTok.getLocation(); + + // We ended up skipping over the source location entirely, which means + // that it points into whitespace. We're done here. + break; + } + } while (TheTok.getKind() != tok::eof); + + // We've passed our source location; just return the original source location. + return Loc; +} + +namespace { + enum PreambleDirectiveKind { + PDK_Skipped, + PDK_StartIf, + PDK_EndIf, + PDK_Unknown + }; +} + +std::pair +Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, unsigned MaxLines) { + // Create a lexer starting at the beginning of the file. Note that we use a + // "fake" file source location at offset 1 so that the lexer will track our + // position within the file. + const unsigned StartOffset = 1; + SourceLocation StartLoc = SourceLocation::getFromRawEncoding(StartOffset); + LangOptions LangOpts; + Lexer TheLexer(StartLoc, LangOpts, Buffer->getBufferStart(), + Buffer->getBufferStart(), Buffer->getBufferEnd()); + + bool InPreprocessorDirective = false; + Token TheTok; + Token IfStartTok; + unsigned IfCount = 0; + unsigned Line = 0; + + do { + TheLexer.LexFromRawLexer(TheTok); + + if (InPreprocessorDirective) { + // If we've hit the end of the file, we're done. + if (TheTok.getKind() == tok::eof) { + InPreprocessorDirective = false; + break; + } + + // If we haven't hit the end of the preprocessor directive, skip this + // token. + if (!TheTok.isAtStartOfLine()) + continue; + + // We've passed the end of the preprocessor directive, and will look + // at this token again below. + InPreprocessorDirective = false; + } + + // Keep track of the # of lines in the preamble. + if (TheTok.isAtStartOfLine()) { + ++Line; + + // If we were asked to limit the number of lines in the preamble, + // and we're about to exceed that limit, we're done. + if (MaxLines && Line >= MaxLines) + break; + } + + // Comments are okay; skip over them. + if (TheTok.getKind() == tok::comment) + continue; + + if (TheTok.isAtStartOfLine() && TheTok.getKind() == tok::hash) { + // This is the start of a preprocessor directive. + Token HashTok = TheTok; + InPreprocessorDirective = true; + + // Figure out which direective this is. Since we're lexing raw tokens, + // we don't have an identifier table available. Instead, just look at + // the raw identifier to recognize and categorize preprocessor directives. + TheLexer.LexFromRawLexer(TheTok); + if (TheTok.getKind() == tok::identifier && !TheTok.needsCleaning()) { + const char *IdStart = Buffer->getBufferStart() + + TheTok.getLocation().getRawEncoding() - 1; + llvm::StringRef Keyword(IdStart, TheTok.getLength()); + PreambleDirectiveKind PDK + = llvm::StringSwitch(Keyword) + .Case("include", PDK_Skipped) + .Case("__include_macros", PDK_Skipped) + .Case("define", PDK_Skipped) + .Case("undef", PDK_Skipped) + .Case("line", PDK_Skipped) + .Case("error", PDK_Skipped) + .Case("pragma", PDK_Skipped) + .Case("import", PDK_Skipped) + .Case("include_next", PDK_Skipped) + .Case("warning", PDK_Skipped) + .Case("ident", PDK_Skipped) + .Case("sccs", PDK_Skipped) + .Case("assert", PDK_Skipped) + .Case("unassert", PDK_Skipped) + .Case("if", PDK_StartIf) + .Case("ifdef", PDK_StartIf) + .Case("ifndef", PDK_StartIf) + .Case("elif", PDK_Skipped) + .Case("else", PDK_Skipped) + .Case("endif", PDK_EndIf) + .Default(PDK_Unknown); + + switch (PDK) { + case PDK_Skipped: + continue; + + case PDK_StartIf: + if (IfCount == 0) + IfStartTok = HashTok; + + ++IfCount; + continue; + + case PDK_EndIf: + // Mismatched #endif. The preamble ends here. + if (IfCount == 0) + break; + + --IfCount; + continue; + + case PDK_Unknown: + // We don't know what this directive is; stop at the '#'. + break; + } + } + + // We only end up here if we didn't recognize the preprocessor + // directive or it was one that can't occur in the preamble at this + // point. Roll back the current token to the location of the '#'. + InPreprocessorDirective = false; + TheTok = HashTok; + } + + // We hit a token that we don't recognize as being in the + // "preprocessing only" part of the file, so we're no longer in + // the preamble. + break; + } while (true); + + SourceLocation End = IfCount? IfStartTok.getLocation() : TheTok.getLocation(); + return std::make_pair(End.getRawEncoding() - StartLoc.getRawEncoding(), + IfCount? IfStartTok.isAtStartOfLine() + : TheTok.isAtStartOfLine()); +} + //===----------------------------------------------------------------------===// // Character information. //===----------------------------------------------------------------------===// @@ -476,7 +672,7 @@ static char DecodeTrigraphChar(const char *CP, Lexer *L) { } if (!L->isLexingRawMode()) - L->Diag(CP-2, diag::trigraph_converted) << std::string()+Res; + L->Diag(CP-2, diag::trigraph_converted) << llvm::StringRef(&Res, 1); return Res; } @@ -647,6 +843,14 @@ Slash: // Helper methods for lexing. //===----------------------------------------------------------------------===// +/// \brief Routine that indiscriminately skips bytes in the source file. +void Lexer::SkipBytes(unsigned Bytes, bool StartOfLine) { + BufferPtr += Bytes; + if (BufferPtr > BufferEnd) + BufferPtr = BufferEnd; + IsAtStartOfLine = StartOfLine; +} + void Lexer::LexIdentifier(Token &Result, const char *CurPtr) { // Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$] unsigned Size; @@ -716,6 +920,16 @@ FinishIdentifier: } } +/// isHexaLiteral - Return true if Start points to a hex constant. +/// in microsoft mode (where this is supposed to be several different tokens). +static bool isHexaLiteral(const char *Start, const LangOptions &Features) { + unsigned Size; + char C1 = Lexer::getCharAndSizeNoWarn(Start, Size, Features); + if (C1 != '0') + return false; + char C2 = Lexer::getCharAndSizeNoWarn(Start + Size, Size, Features); + return (C2 == 'x' || C2 == 'X'); +} /// LexNumericConstant - Lex the remainder of a integer or floating point /// constant. From[-1] is the first character lexed. Return the end of the @@ -731,12 +945,16 @@ void Lexer::LexNumericConstant(Token &Result, const char *CurPtr) { } // If we fell out, check for a sign, due to 1e+12. If we have one, continue. - if ((C == '-' || C == '+') && (PrevCh == 'E' || PrevCh == 'e')) - return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result)); + if ((C == '-' || C == '+') && (PrevCh == 'E' || PrevCh == 'e')) { + // If we are in Microsoft mode, don't continue if the constant is hex. + // For example, MSVC will accept the following as 3 tokens: 0x1234567e+1 + if (!Features.Microsoft || !isHexaLiteral(BufferPtr, Features)) + return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result)); + } // If we have a hex FP constant, continue. if ((C == '-' || C == '+') && (PrevCh == 'P' || PrevCh == 'p') && - (!PP || !PP->getLangOptions().CPlusPlus0x)) + !Features.CPlusPlus0x) return LexNumericConstant(Result, ConsumeChar(CurPtr, Size, Result)); // Update the location of token as well as BufferPtr. @@ -759,7 +977,9 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, bool Wide) { if (C == '\n' || C == '\r' || // Newline. (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. - if (!isLexingRawMode() && !Features.AsmPreprocessor) + if (C == 0 && PP && PP->isCodeCompletionFile(FileLoc)) + PP->CodeCompleteNaturalLanguage(); + else if (!isLexingRawMode() && !Features.AsmPreprocessor) Diag(BufferPtr, diag::err_unterminated_string); FormTokenWithChars(Result, CurPtr-1, tok::unknown); return; @@ -836,7 +1056,9 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr) { C = getAndAdvanceChar(CurPtr, Result); } else if (C == '\n' || C == '\r' || // Newline. (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. - if (!isLexingRawMode() && !Features.AsmPreprocessor) + if (C == 0 && PP && PP->isCodeCompletionFile(FileLoc)) + PP->CodeCompleteNaturalLanguage(); + else if (!isLexingRawMode() && !Features.AsmPreprocessor) Diag(BufferPtr, diag::err_unterminated_char); FormTokenWithChars(Result, CurPtr-1, tok::unknown); return; @@ -980,7 +1202,13 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { } } - if (CurPtr == BufferEnd+1) { --CurPtr; break; } + if (CurPtr == BufferEnd+1) { + if (PP && PP->isCodeCompletionFile(FileLoc)) + PP->CodeCompleteNaturalLanguage(); + + --CurPtr; + break; + } } while (C != '\n' && C != '\r'); // Found but did not consume the newline. Notify comment handlers about the @@ -1219,7 +1447,9 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { Diag(CurPtr-1, diag::warn_nested_block_comment); } } else if (C == 0 && CurPtr == BufferEnd+1) { - if (!isLexingRawMode() && !PP->isCodeCompletionFile(FileLoc)) + if (PP && PP->isCodeCompletionFile(FileLoc)) + PP->CodeCompleteNaturalLanguage(); + else if (!isLexingRawMode()) Diag(BufferPtr, diag::err_unterminated_block_comment); // Note: the user probably forgot a */. We could continue immediately // after the /*, but this would involve lexing a lot of what really is the @@ -1305,6 +1535,11 @@ std::string Lexer::ReadToEndOfLine() { // Next, lex the character, which should handle the EOM transition. Lex(Tmp); + if (Tmp.is(tok::code_completion)) { + if (PP && PP->getCodeCompletionHandler()) + PP->getCodeCompletionHandler()->CodeCompleteNaturalLanguage(); + Lex(Tmp); + } assert(Tmp.is(tok::eom) && "Unexpected token!"); // Finally, we're done, return the string we found. @@ -1318,6 +1553,22 @@ std::string Lexer::ReadToEndOfLine() { /// This returns true if Result contains a token, false if PP.Lex should be /// called again. bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { + // Check if we are performing code completion. + if (PP && PP->isCodeCompletionFile(FileLoc)) { + // We're at the end of the file, but we've been asked to consider the + // end of the file to be a code-completion token. Return the + // code-completion token. + Result.startToken(); + FormTokenWithChars(Result, CurPtr, tok::code_completion); + + // Only do the eof -> code_completion translation once. + PP->SetCodeCompletionPoint(0, 0, 0); + + // Silence any diagnostics that occur once we hit the code-completion point. + PP->getDiagnostics().setSuppressAllDiagnostics(true); + return true; + } + // If we hit the end of the file while parsing a preprocessor directive, // end the preprocessor directive first. The next token returned will // then be the end of file. @@ -1340,29 +1591,14 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { FormTokenWithChars(Result, BufferEnd, tok::eof); return true; } - - // Otherwise, check if we are code-completing, then issue diagnostics for - // unterminated #if and missing newline. - - if (PP && PP->isCodeCompletionFile(FileLoc)) { - // We're at the end of the file, but we've been asked to consider the - // end of the file to be a code-completion token. Return the - // code-completion token. - Result.startToken(); - FormTokenWithChars(Result, CurPtr, tok::code_completion); - - // Only do the eof -> code_completion translation once. - PP->SetCodeCompletionPoint(0, 0, 0); - - // Silence any diagnostics that occur once we hit the code-completion point. - PP->getDiagnostics().setSuppressAllDiagnostics(true); - return true; - } + // Issue diagnostics for unterminated #if and missing newline. + // If we are in a #if directive, emit an error. while (!ConditionalStack.empty()) { - PP->Diag(ConditionalStack.back().IfLoc, - diag::err_pp_unterminated_conditional); + if (!PP->isCodeCompletionFile(FileLoc)) + PP->Diag(ConditionalStack.back().IfLoc, + diag::err_pp_unterminated_conditional); ConditionalStack.pop_back(); } diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index b8fd3ce..fb543d0 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -170,6 +170,7 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd, char *&ResultBuf, bool &HadError, SourceLocation Loc, Preprocessor &PP, + bool wide, bool Complain) { // FIXME: Add a warning - UCN's are only valid in C++ & C99. // FIXME: Handle wide strings. @@ -190,6 +191,7 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd, UTF32 UcnVal = 0; unsigned short UcnLen = (ThisTokBuf[-1] == 'u' ? 4 : 8); + unsigned short UcnLenSave = UcnLen; for (; ThisTokBuf != ThisTokEnd && UcnLen; ++ThisTokBuf, UcnLen--) { int CharVal = HexDigitValue(ThisTokBuf[0]); if (CharVal == -1) break; @@ -214,6 +216,17 @@ static void ProcessUCNEscape(const char *&ThisTokBuf, const char *ThisTokEnd, HadError = 1; return; } + if (wide) { + (void)UcnLenSave; + assert(UcnLenSave == 4 && + "ProcessUCNEscape - only ucn length of 4 supported"); + // little endian assumed. + *ResultBuf++ = (UcnVal & 0x000000FF); + *ResultBuf++ = (UcnVal & 0x0000FF00) >> 8; + *ResultBuf++ = (UcnVal & 0x00FF0000) >> 16; + *ResultBuf++ = (UcnVal & 0xFF000000) >> 24; + return; + } // Now that we've parsed/checked the UCN, we convert from UTF32->UTF8. // The conversion below was inspired by: // http://www.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c @@ -323,7 +336,7 @@ NumericLiteralParser(const char *begin, const char *end, // Done. } else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) { PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin), - diag::err_invalid_decimal_digit) << std::string(s, s+1); + diag::err_invalid_decimal_digit) << llvm::StringRef(s, 1); hadError = true; return; } else if (*s == '.') { @@ -439,7 +452,7 @@ NumericLiteralParser(const char *begin, const char *end, PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin), isFPConstant ? diag::err_invalid_suffix_float_constant : diag::err_invalid_suffix_integer_constant) - << std::string(SuffixBegin, ThisTokEnd); + << llvm::StringRef(SuffixBegin, ThisTokEnd-SuffixBegin); hadError = true; return; } @@ -510,7 +523,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) { // Done. } else if (isxdigit(*s)) { PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin), - diag::err_invalid_binary_digit) << std::string(s, s+1); + diag::err_invalid_binary_digit) << llvm::StringRef(s, 1); hadError = true; } // Other suffixes will be diagnosed by the caller. @@ -540,7 +553,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) { // the code is using an incorrect base. if (isxdigit(*s) && *s != 'e' && *s != 'E') { PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin), - diag::err_invalid_octal_digit) << std::string(s, s+1); + diag::err_invalid_octal_digit) << llvm::StringRef(s, 1); hadError = true; return; } @@ -830,12 +843,14 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks, } const char *ThisTokEnd = ThisTokBuf+ThisTokLen-1; // Skip end quote. - + bool wide = false; // TODO: Input character set mapping support. // Skip L marker for wide strings. - if (ThisTokBuf[0] == 'L') + if (ThisTokBuf[0] == 'L') { + wide = true; ++ThisTokBuf; + } assert(ThisTokBuf[0] == '"' && "Expected quote, lexer broken?"); ++ThisTokBuf; @@ -880,7 +895,8 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks, // Is this a Universal Character Name escape? if (ThisTokBuf[1] == 'u' || ThisTokBuf[1] == 'U') { ProcessUCNEscape(ThisTokBuf, ThisTokEnd, ResultPtr, - hadError, StringToks[i].getLocation(), PP, Complain); + hadError, StringToks[i].getLocation(), PP, wide, + Complain); continue; } // Otherwise, this is a non-UCN escape character. Process it. @@ -911,6 +927,20 @@ StringLiteralParser(const Token *StringToks, unsigned NumStringToks, hadError = 1; return; } + } else if (Complain) { + // Complain if this string literal has too many characters. + unsigned MaxChars = PP.getLangOptions().CPlusPlus? 65536 + : PP.getLangOptions().C99 ? 4095 + : 509; + + if (GetNumStringChars() > MaxChars) + PP.Diag(StringToks[0].getLocation(), diag::ext_string_too_long) + << GetNumStringChars() << MaxChars + << (PP.getLangOptions().CPlusPlus? 2 + : PP.getLangOptions().C99 ? 1 + : 0) + << SourceRange(StringToks[0].getLocation(), + StringToks[NumStringToks-1].getLocation()); } } diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp index fda884c..c6d0934 100644 --- a/lib/Lex/MacroInfo.cpp +++ b/lib/Lex/MacroInfo.cpp @@ -20,13 +20,32 @@ MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) { IsC99Varargs = false; IsGNUVarargs = false; IsBuiltinMacro = false; + IsFromAST = false; IsDisabled = false; IsUsed = true; + IsAllowRedefinitionsWithoutWarning = false; ArgumentList = 0; NumArguments = 0; } +MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) { + Location = MI.Location; + EndLocation = MI.EndLocation; + ReplacementTokens = MI.ReplacementTokens; + IsFunctionLike = MI.IsFunctionLike; + IsC99Varargs = MI.IsC99Varargs; + IsGNUVarargs = MI.IsGNUVarargs; + IsBuiltinMacro = MI.IsBuiltinMacro; + IsFromAST = MI.IsFromAST; + IsDisabled = MI.IsDisabled; + IsUsed = MI.IsUsed; + IsAllowRedefinitionsWithoutWarning = MI.IsAllowRedefinitionsWithoutWarning; + ArgumentList = 0; + NumArguments = 0; + setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator); +} + /// isIdenticalTo - Return true if the specified macro definition is equal to /// this macro in spelling, arguments, and whitespace. This is used to emit /// duplicate definition warnings. This implements the rules in C99 6.10.3. diff --git a/lib/Lex/Makefile b/lib/Lex/Makefile index 938b8d5..d80fb55 100644 --- a/lib/Lex/Makefile +++ b/lib/Lex/Makefile @@ -15,7 +15,6 @@ CLANG_LEVEL := ../.. include $(CLANG_LEVEL)/../../Makefile.config LIBRARYNAME := clangLex -BUILD_ARCHIVE = 1 ifeq ($(ARCH),PowerPC) CXX.Flags += -maltivec diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 417724b..8da7def 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -16,6 +16,7 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/LexDiagnostic.h" +#include "clang/Lex/CodeCompletionHandler.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/APInt.h" @@ -25,7 +26,7 @@ using namespace clang; // Utility Methods for Preprocessor Directive Handling. //===----------------------------------------------------------------------===// -MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) { +MacroInfo *Preprocessor::AllocateMacroInfo() { MacroInfo *MI; if (!MICache.empty()) { @@ -33,15 +34,26 @@ MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) { MICache.pop_back(); } else MI = (MacroInfo*) BP.Allocate(); + return MI; +} + +MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) { + MacroInfo *MI = AllocateMacroInfo(); new (MI) MacroInfo(L); return MI; } +MacroInfo *Preprocessor::CloneMacroInfo(const MacroInfo &MacroToClone) { + MacroInfo *MI = AllocateMacroInfo(); + new (MI) MacroInfo(MacroToClone, BP); + return MI; +} + /// ReleaseMacroInfo - Release the specified MacroInfo. This memory will /// be reused for allocating new MacroInfo objects. -void Preprocessor::ReleaseMacroInfo(MacroInfo* MI) { +void Preprocessor::ReleaseMacroInfo(MacroInfo *MI) { MICache.push_back(MI); - MI->FreeArgumentList(BP); + MI->FreeArgumentList(); } @@ -63,6 +75,13 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) { // Read the token, don't allow macro expansion on it. LexUnexpandedToken(MacroNameTok); + if (MacroNameTok.is(tok::code_completion)) { + if (CodeComplete) + CodeComplete->CodeCompleteMacroName(isDefineUndef == 1); + LexUnexpandedToken(MacroNameTok); + return; + } + // Missing macro name? if (MacroNameTok.is(tok::eom)) { Diag(MacroNameTok, diag::err_pp_missing_macro_name); @@ -166,13 +185,20 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, while (1) { CurLexer->Lex(Tok); + if (Tok.is(tok::code_completion)) { + if (CodeComplete) + CodeComplete->CodeCompleteInConditionalExclusion(); + continue; + } + // If this is the end of the buffer, we have an error. if (Tok.is(tok::eof)) { // Emit errors for each unterminated conditional on the stack, including // the current one. while (!CurPPLexer->ConditionalStack.empty()) { - Diag(CurPPLexer->ConditionalStack.back().IfLoc, - diag::err_pp_unterminated_conditional); + if (!isCodeCompletionFile(Tok.getLocation())) + Diag(CurPPLexer->ConditionalStack.back().IfLoc, + diag::err_pp_unterminated_conditional); CurPPLexer->ConditionalStack.pop_back(); } @@ -510,7 +536,11 @@ TryAgain: // Handle stuff like "# /*foo*/ define X" in -E -C mode. LexUnexpandedToken(Result); goto TryAgain; - + case tok::code_completion: + if (CodeComplete) + CodeComplete->CodeCompleteDirective( + CurPPLexer->getConditionalStackDepth() > 0); + return; case tok::numeric_constant: // # 7 GNU line marker directive. if (getLangOptions().AsmPreprocessor) break; // # 4 is not a preprocessor directive in .S files. @@ -1445,15 +1475,15 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { if (!OtherMI->isUsed()) Diag(OtherMI->getDefinitionLoc(), diag::pp_macro_not_used); - // Macros must be identical. This means all tokes and whitespace + // Macros must be identical. This means all tokens and whitespace // separation must be the same. C99 6.10.3.2. - if (!MI->isIdenticalTo(*OtherMI, *this)) { + if (!OtherMI->isAllowRedefinitionsWithoutWarning() && + !MI->isIdenticalTo(*OtherMI, *this)) { Diag(MI->getDefinitionLoc(), diag::ext_pp_macro_redef) << MacroNameTok.getIdentifierInfo(); Diag(OtherMI->getDefinitionLoc(), diag::note_previous_definition); } } - ReleaseMacroInfo(OtherMI); } @@ -1490,7 +1520,8 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) { // If the callbacks want to know, tell them about the macro #undef. if (Callbacks) - Callbacks->MacroUndefined(MacroNameTok.getIdentifierInfo(), MI); + Callbacks->MacroUndefined(MacroNameTok.getLocation(), + MacroNameTok.getIdentifierInfo(), MI); // Free macro definition. ReleaseMacroInfo(MI); diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp index 756ce27..163e869 100644 --- a/lib/Lex/PPExpressions.cpp +++ b/lib/Lex/PPExpressions.cpp @@ -19,11 +19,14 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/LiteralSupport.h" +#include "clang/Lex/CodeCompletionHandler.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/LexDiagnostic.h" #include "llvm/ADT/APSInt.h" using namespace clang; +namespace { + /// PPValue - Represents the value of a subexpression of a preprocessor /// conditional and the source range covered by it. class PPValue { @@ -47,6 +50,8 @@ public: void setEnd(SourceLocation L) { Range.setEnd(L); } }; +} + static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, Token &PeekTok, bool ValueLive, Preprocessor &PP); @@ -88,6 +93,12 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT, PP.LexUnexpandedToken(PeekTok); } + if (PeekTok.is(tok::code_completion)) { + if (PP.getCodeCompletionHandler()) + PP.getCodeCompletionHandler()->CodeCompleteMacroName(false); + PP.LexUnexpandedToken(PeekTok); + } + // If we don't have a pp-identifier now, this is an error. if ((II = PeekTok.getIdentifierInfo()) == 0) { PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier); @@ -138,6 +149,12 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, bool ValueLive, Preprocessor &PP) { DT.State = DefinedTracker::Unknown; + if (PeekTok.is(tok::code_completion)) { + if (PP.getCodeCompletionHandler()) + PP.getCodeCompletionHandler()->CodeCompletePreprocessorExpression(); + PP.LexUnexpandedToken(PeekTok); + } + // If this token's spelling is a pp-identifier, check to see if it is // 'defined' or if it is a macro. Note that we check here because many // keywords are pp-identifiers, so we can't check the kind. @@ -693,7 +710,7 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { // Peek ahead one token. Token Tok; Lex(Tok); - + // C99 6.10.1p3 - All expressions are evaluated as intmax_t or uintmax_t. unsigned BitWidth = getTargetInfo().getIntMaxTWidth(); diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index ebf606e..9015c27 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -19,6 +19,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/LexDiagnostic.h" +#include "clang/Lex/CodeCompletionHandler.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/raw_ostream.h" #include @@ -71,6 +72,12 @@ void Preprocessor::RegisterBuiltinMacros() { Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin"); Ident__has_include = RegisterBuiltinMacro(*this, "__has_include"); Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next"); + + // Microsoft Extensions. + if (Features.Microsoft) + Ident__pragma = RegisterBuiltinMacro(*this, "__pragma"); + else + Ident__pragma = 0; } /// isTrivialSingleTokenExpansion - Return true if MI, which has a single token @@ -323,6 +330,13 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, // an argument value in a macro could expand to ',' or '(' or ')'. LexUnexpandedToken(Tok); + if (Tok.is(tok::code_completion)) { + if (CodeComplete) + CodeComplete->CodeCompleteMacroArgument(MacroName.getIdentifierInfo(), + MI, NumActuals); + LexUnexpandedToken(Tok); + } + if (Tok.is(tok::eof) || Tok.is(tok::eom)) { // "#if f(" & "#if f(\n" Diag(MacroName, diag::err_unterm_macro_invoc); // Do not lose the EOF/EOM. Return it to the client. @@ -506,6 +520,10 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_static_assert", LangOpts.CPlusPlus0x) .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI) .Case("objc_weak_class", LangOpts.ObjCNonFragileABI) + .Case("ownership_holds", true) + .Case("ownership_returns", true) + .Case("ownership_takes", true) + .Case("cxx_inline_namespaces", true) //.Case("cxx_concepts", false) //.Case("cxx_lambdas", false) //.Case("cxx_nullptr", false) @@ -630,10 +648,12 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { IdentifierInfo *II = Tok.getIdentifierInfo(); assert(II && "Can't be a macro without id info!"); - // If this is an _Pragma directive, expand it, invoke the pragma handler, then - // lex the token after it. + // If this is an _Pragma or Microsoft __pragma directive, expand it, + // invoke the pragma handler, then lex the token after it. if (II == Ident_Pragma) return Handle_Pragma(Tok); + else if (II == Ident__pragma) // in non-MS mode this is null + return HandleMicrosoft__pragma(Tok); ++NumBuiltinMacroExpanded; diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp index 3b949d0..63b4823 100644 --- a/lib/Lex/PTHLexer.cpp +++ b/lib/Lex/PTHLexer.cpp @@ -101,16 +101,15 @@ LexNextToken: // Save the end-of-file token. EofToken = Tok; + // Save 'PP' to 'PPCache' as LexEndOfFile can delete 'this'. Preprocessor *PPCache = PP; assert(!ParsingPreprocessorDirective); assert(!LexingRawMode); - - // FIXME: Issue diagnostics similar to Lexer. - if (PP->HandleEndOfFile(Tok, false)) + + if (LexEndOfFile(Tok)) return; - assert(PPCache && "Raw buffer::LexEndOfFile should return a token"); return PPCache->Lex(Tok); } @@ -134,6 +133,29 @@ LexNextToken: MIOpt.ReadToken(); } +bool PTHLexer::LexEndOfFile(Token &Result) { + // If we hit the end of the file while parsing a preprocessor directive, + // end the preprocessor directive first. The next token returned will + // then be the end of file. + if (ParsingPreprocessorDirective) { + ParsingPreprocessorDirective = false; // Done parsing the "line". + return true; // Have a token. + } + + assert(!LexingRawMode); + + // If we are in a #if directive, emit an error. + while (!ConditionalStack.empty()) { + if (!PP->isCodeCompletionFile(FileStartLoc)) + PP->Diag(ConditionalStack.back().IfLoc, + diag::err_pp_unterminated_conditional); + ConditionalStack.pop_back(); + } + + // Finally, let the preprocessor handle this. + return PP->HandleEndOfFile(Result); +} + // FIXME: We can just grab the last token instead of storing a copy // into EofToken. void PTHLexer::getEOF(Token& Tok) { diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index 7bf4094..a7b289e 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -16,9 +16,12 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/MacroInfo.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" +#include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/ErrorHandling.h" #include using namespace clang; @@ -166,6 +169,62 @@ void Preprocessor::Handle_Pragma(Token &Tok) { --e; } } + + Handle_Pragma(StrVal, PragmaLoc, RParenLoc); + + // Finally, return whatever came after the pragma directive. + return Lex(Tok); +} + +/// HandleMicrosoft__pragma - Like Handle_Pragma except the pragma text +/// is not enclosed within a string literal. +void Preprocessor::HandleMicrosoft__pragma(Token &Tok) { + // Remember the pragma token location. + SourceLocation PragmaLoc = Tok.getLocation(); + + // Read the '('. + Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + Diag(PragmaLoc, diag::err__Pragma_malformed); + return; + } + + // Get the tokens enclosed within the __pragma(). + llvm::SmallVector PragmaToks; + int NumParens = 0; + Lex(Tok); + while (Tok.isNot(tok::eof)) { + if (Tok.is(tok::l_paren)) + NumParens++; + else if (Tok.is(tok::r_paren) && NumParens-- == 0) + break; + PragmaToks.push_back(Tok); + Lex(Tok); + } + + if (Tok.is(tok::eof)) { + Diag(PragmaLoc, diag::err_unterminated___pragma); + return; + } + + // Build the pragma string. + std::string StrVal = " "; + for (llvm::SmallVector::iterator I = + PragmaToks.begin(), E = PragmaToks.end(); I != E; ++I) { + StrVal += getSpelling(*I); + } + + SourceLocation RParenLoc = Tok.getLocation(); + + Handle_Pragma(StrVal, PragmaLoc, RParenLoc); + + // Finally, return whatever came after the pragma directive. + return Lex(Tok); +} + +void Preprocessor::Handle_Pragma(const std::string &StrVal, + SourceLocation PragmaLoc, + SourceLocation RParenLoc) { // Plop the string (including the newline and trailing null) into a buffer // where we can lex it. @@ -183,9 +242,6 @@ void Preprocessor::Handle_Pragma(Token &Tok) { // With everything set up, lex this as a #pragma directive. HandlePragmaDirective(); - - // Finally, return whatever came after the pragma directive. - return Lex(Tok); } @@ -328,7 +384,9 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { Lex(DependencyTok); } - Message.erase(Message.end()-1); + // Remove the trailing ' ' if present. + if (!Message.empty()) + Message.erase(Message.end()-1); Diag(FilenameTok, diag::pp_out_of_date_dependency) << Message; } } @@ -483,6 +541,109 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) { Callbacks->PragmaMessage(MessageLoc, MessageString); } +/// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro. +/// Return the IdentifierInfo* associated with the macro to push or pop. +IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) { + // Remember the pragma token location. + Token PragmaTok = Tok; + + // Read the '('. + Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + Diag(PragmaTok.getLocation(), diag::err_pragma_push_pop_macro_malformed) + << getSpelling(PragmaTok); + return 0; + } + + // Read the macro name string. + Lex(Tok); + if (Tok.isNot(tok::string_literal)) { + Diag(PragmaTok.getLocation(), diag::err_pragma_push_pop_macro_malformed) + << getSpelling(PragmaTok); + return 0; + } + + // Remember the macro string. + std::string StrVal = getSpelling(Tok); + + // Read the ')'. + Lex(Tok); + if (Tok.isNot(tok::r_paren)) { + Diag(PragmaTok.getLocation(), diag::err_pragma_push_pop_macro_malformed) + << getSpelling(PragmaTok); + return 0; + } + + assert(StrVal[0] == '"' && StrVal[StrVal.size()-1] == '"' && + "Invalid string token!"); + + // Create a Token from the string. + Token MacroTok; + MacroTok.startToken(); + MacroTok.setKind(tok::identifier); + CreateString(&StrVal[1], StrVal.size() - 2, MacroTok); + + // Get the IdentifierInfo of MacroToPushTok. + return LookUpIdentifierInfo(MacroTok); +} + +/// HandlePragmaPushMacro - Handle #pragma push_macro. +/// The syntax is: +/// #pragma push_macro("macro") +void Preprocessor::HandlePragmaPushMacro(Token &PushMacroTok) { + // Parse the pragma directive and get the macro IdentifierInfo*. + IdentifierInfo *IdentInfo = ParsePragmaPushOrPopMacro(PushMacroTok); + if (!IdentInfo) return; + + // Get the MacroInfo associated with IdentInfo. + MacroInfo *MI = getMacroInfo(IdentInfo); + + MacroInfo *MacroCopyToPush = 0; + if (MI) { + // Make a clone of MI. + MacroCopyToPush = CloneMacroInfo(*MI); + + // Allow the original MacroInfo to be redefined later. + MI->setIsAllowRedefinitionsWithoutWarning(true); + } + + // Push the cloned MacroInfo so we can retrieve it later. + PragmaPushMacroInfo[IdentInfo].push_back(MacroCopyToPush); +} + +/// HandlePragmaPopMacro - Handle #pragma push_macro. +/// The syntax is: +/// #pragma pop_macro("macro") +void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) { + SourceLocation MessageLoc = PopMacroTok.getLocation(); + + // Parse the pragma directive and get the macro IdentifierInfo*. + IdentifierInfo *IdentInfo = ParsePragmaPushOrPopMacro(PopMacroTok); + if (!IdentInfo) return; + + // Find the vector associated with the macro. + llvm::DenseMap >::iterator iter = + PragmaPushMacroInfo.find(IdentInfo); + if (iter != PragmaPushMacroInfo.end()) { + // Release the MacroInfo currently associated with IdentInfo. + MacroInfo *CurrentMI = getMacroInfo(IdentInfo); + if (CurrentMI) ReleaseMacroInfo(CurrentMI); + + // Get the MacroInfo we want to reinstall. + MacroInfo *MacroToReInstall = iter->second.back(); + + // Reinstall the previously pushed macro. + setMacroInfo(IdentInfo, MacroToReInstall); + + // Pop PragmaPushMacroInfo stack. + iter->second.pop_back(); + if (iter->second.size() == 0) + PragmaPushMacroInfo.erase(iter); + } else { + Diag(MessageLoc, diag::warn_pragma_pop_macro_no_push) + << IdentInfo->getName(); + } +} /// AddPragmaHandler - Add the specified pragma handler to the preprocessor. /// If 'Namespace' is non-null, then it is a token required to exist on the @@ -582,24 +743,51 @@ struct PragmaDependencyHandler : public PragmaHandler { } }; +struct PragmaDebugHandler : public PragmaHandler { + PragmaDebugHandler() : PragmaHandler("__debug") {} + virtual void HandlePragma(Preprocessor &PP, Token &DepToken) { + Token Tok; + PP.LexUnexpandedToken(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid); + return; + } + IdentifierInfo *II = Tok.getIdentifierInfo(); + + if (II->isStr("assert")) { + assert(0 && "This is an assertion!"); + } else if (II->isStr("crash")) { + *(volatile int*) 0x11 = 0; + } else if (II->isStr("llvm_fatal_error")) { + llvm::report_fatal_error("#pragma clang __debug llvm_fatal_error"); + } else if (II->isStr("llvm_unreachable")) { + llvm_unreachable("#pragma clang __debug llvm_unreachable"); + } else if (II->isStr("overflow_stack")) { + DebugOverflowStack(); + } else if (II->isStr("handle_crash")) { + llvm::CrashRecoveryContext *CRC =llvm::CrashRecoveryContext::GetCurrent(); + if (CRC) + CRC->HandleCrash(); + } else { + PP.Diag(Tok, diag::warn_pragma_debug_unexpected_command) + << II->getName(); + } + } + + void DebugOverflowStack() { + DebugOverflowStack(); + } +}; + /// PragmaDiagnosticHandler - e.g. '#pragma GCC diagnostic ignored "-Wformat"' -/// Since clang's diagnostic supports extended functionality beyond GCC's -/// the constructor takes a clangMode flag to tell it whether or not to allow -/// clang's extended functionality, or whether to reject it. struct PragmaDiagnosticHandler : public PragmaHandler { -private: - const bool ClangMode; public: - explicit PragmaDiagnosticHandler(const bool clangMode) - : PragmaHandler("diagnostic"), ClangMode(clangMode) {} - + explicit PragmaDiagnosticHandler() : PragmaHandler("diagnostic") {} virtual void HandlePragma(Preprocessor &PP, Token &DiagToken) { Token Tok; PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::identifier)) { - unsigned Diag = ClangMode ? diag::warn_pragma_diagnostic_clang_invalid - : diag::warn_pragma_diagnostic_gcc_invalid; - PP.Diag(Tok, Diag); + PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid); return; } IdentifierInfo *II = Tok.getIdentifierInfo(); @@ -613,22 +801,16 @@ public: Map = diag::MAP_IGNORE; else if (II->isStr("fatal")) Map = diag::MAP_FATAL; - else if (ClangMode) { - if (II->isStr("pop")) { - if (!PP.getDiagnostics().popMappings()) - PP.Diag(Tok, diag::warn_pragma_diagnostic_clang_cannot_ppp); - return; - } - - if (II->isStr("push")) { - PP.getDiagnostics().pushMappings(); - return; - } - - PP.Diag(Tok, diag::warn_pragma_diagnostic_clang_invalid); + else if (II->isStr("pop")) { + if (!PP.getDiagnostics().popMappings()) + PP.Diag(Tok, diag::warn_pragma_diagnostic_cannot_pop); + + return; + } else if (II->isStr("push")) { + PP.getDiagnostics().pushMappings(); return; } else { - PP.Diag(Tok, diag::warn_pragma_diagnostic_gcc_invalid); + PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid); return; } @@ -660,9 +842,7 @@ public: if (Literal.hadError) return; if (Literal.Pascal) { - unsigned Diag = ClangMode ? diag::warn_pragma_diagnostic_clang_invalid - : diag::warn_pragma_diagnostic_gcc_invalid; - PP.Diag(Tok, Diag); + PP.Diag(Tok, diag::warn_pragma_diagnostic_invalid); return; } @@ -699,6 +879,25 @@ struct PragmaMessageHandler : public PragmaHandler { } }; +/// PragmaPushMacroHandler - "#pragma push_macro" saves the value of the +/// macro on the top of the stack. +struct PragmaPushMacroHandler : public PragmaHandler { + PragmaPushMacroHandler() : PragmaHandler("push_macro") {} + virtual void HandlePragma(Preprocessor &PP, Token &PushMacroTok) { + PP.HandlePragmaPushMacro(PushMacroTok); + } +}; + + +/// PragmaPopMacroHandler - "#pragma pop_macro" sets the value of the +/// macro to the value on the top of the stack. +struct PragmaPopMacroHandler : public PragmaHandler { + PragmaPopMacroHandler() : PragmaHandler("pop_macro") {} + virtual void HandlePragma(Preprocessor &PP, Token &PopMacroTok) { + PP.HandlePragmaPopMacro(PopMacroTok); + } +}; + // Pragma STDC implementations. enum STDCSetting { @@ -780,17 +979,20 @@ struct PragmaSTDC_UnknownHandler : public PragmaHandler { void Preprocessor::RegisterBuiltinPragmas() { AddPragmaHandler(new PragmaOnceHandler()); AddPragmaHandler(new PragmaMarkHandler()); + AddPragmaHandler(new PragmaPushMacroHandler()); + AddPragmaHandler(new PragmaPopMacroHandler()); // #pragma GCC ... AddPragmaHandler("GCC", new PragmaPoisonHandler()); AddPragmaHandler("GCC", new PragmaSystemHeaderHandler()); AddPragmaHandler("GCC", new PragmaDependencyHandler()); - AddPragmaHandler("GCC", new PragmaDiagnosticHandler(false)); + AddPragmaHandler("GCC", new PragmaDiagnosticHandler()); // #pragma clang ... AddPragmaHandler("clang", new PragmaPoisonHandler()); AddPragmaHandler("clang", new PragmaSystemHeaderHandler()); + AddPragmaHandler("clang", new PragmaDebugHandler()); AddPragmaHandler("clang", new PragmaDependencyHandler()); - AddPragmaHandler("clang", new PragmaDiagnosticHandler(true)); + AddPragmaHandler("clang", new PragmaDiagnosticHandler()); AddPragmaHandler("STDC", new PragmaSTDC_FP_CONTRACTHandler()); AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler()); diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp index 6966c38..c446d96 100644 --- a/lib/Lex/PreprocessingRecord.cpp +++ b/lib/Lex/PreprocessingRecord.cpp @@ -118,7 +118,8 @@ void PreprocessingRecord::MacroDefined(const IdentifierInfo *II, PreprocessedEntities.push_back(Def); } -void PreprocessingRecord::MacroUndefined(const IdentifierInfo *II, +void PreprocessingRecord::MacroUndefined(SourceLocation Loc, + const IdentifierInfo *II, const MacroInfo *MI) { llvm::DenseMap::iterator Pos = MacroDefinitions.find(MI); diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 51f7293..5160acf 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -34,6 +34,7 @@ #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/ScratchBuffer.h" #include "clang/Lex/LexDiagnostic.h" +#include "clang/Lex/CodeCompletionHandler.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/TargetInfo.h" @@ -53,8 +54,9 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, bool OwnsHeaders) : Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()), SourceMgr(SM), HeaderInfo(Headers), ExternalSource(0), - Identifiers(opts, IILookup), BuiltinInfo(Target), CodeCompletionFile(0), - CurPPLexer(0), CurDirLookup(0), Callbacks(0), MacroArgCache(0), Record(0) { + Identifiers(opts, IILookup), BuiltinInfo(Target), CodeComplete(0), + CodeCompletionFile(0), SkipMainFilePreamble(0, true), CurPPLexer(0), + CurDirLookup(0), Callbacks(0), MacroArgCache(0), Record(0) { ScratchBuf = new ScratchBuffer(SourceMgr); CounterValue = 0; // __COUNTER__ starts at 0. OwnsHeaderSearch = OwnsHeaders; @@ -110,7 +112,7 @@ Preprocessor::~Preprocessor() { // will be released when the BumpPtrAllocator 'BP' object gets // destroyed. We still need to run the dtor, however, to free // memory alocated by MacroInfo. - I->second->Destroy(BP); + I->second->Destroy(); I->first->setHasMacroDefinition(false); } for (std::vector::iterator I = MICache.begin(), @@ -119,7 +121,7 @@ Preprocessor::~Preprocessor() { // will be released when the BumpPtrAllocator 'BP' object gets // destroyed. We still need to run the dtor, however, to free // memory alocated by MacroInfo. - (*I)->Destroy(BP); + (*I)->Destroy(); } // Free any cached macro expanders. @@ -163,7 +165,7 @@ void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const { llvm::errs() << " [ExpandDisabled]"; if (Tok.needsCleaning()) { const char *Start = SourceMgr.getCharacterData(Tok.getLocation()); - llvm::errs() << " [UnClean='" << std::string(Start, Start+Tok.getLength()) + llvm::errs() << " [UnClean='" << llvm::StringRef(Start, Tok.getLength()) << "']"; } @@ -282,6 +284,13 @@ bool Preprocessor::isCodeCompletionFile(SourceLocation FileLoc) const { == CodeCompletionFile; } +void Preprocessor::CodeCompleteNaturalLanguage() { + SetCodeCompletionPoint(0, 0, 0); + getDiagnostics().setSuppressAllDiagnostics(true); + if (CodeComplete) + CodeComplete->CodeCompleteNaturalLanguage(); +} + //===----------------------------------------------------------------------===// // Token Spelling //===----------------------------------------------------------------------===// @@ -508,6 +517,12 @@ void Preprocessor::EnterMainSourceFile() { // Enter the main file source buffer. EnterSourceFile(MainFileID, 0, SourceLocation()); + // If we've been asked to skip bytes in the main file (e.g., as part of a + // precompiled preamble), do so now. + if (SkipMainFilePreamble.first > 0) + CurLexer->SkipBytes(SkipMainFilePreamble.first, + SkipMainFilePreamble.second); + // Tell the header info that the main file was entered. If the file is later // #imported, it won't be re-entered. if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID)) @@ -516,7 +531,7 @@ void Preprocessor::EnterMainSourceFile() { // Preprocess Predefines to populate the initial preprocessor state. llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getMemBufferCopy(Predefines, ""); - assert(SB && "Cannot fail to create predefined source buffer"); + assert(SB && "Cannot create predefined source buffer"); FileID FID = SourceMgr.createFileIDForMemBuffer(SB); assert(!FID.isInvalid() && "Could not create FileID for predefines?"); @@ -639,6 +654,8 @@ bool Preprocessor::HandleComment(Token &result, SourceRange Comment) { CommentHandler::~CommentHandler() { } +CodeCompletionHandler::~CodeCompletionHandler() { } + void Preprocessor::createPreprocessingRecord() { if (Record) return; diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index 56bb073..94719b0 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -268,6 +268,13 @@ void TokenLexer::ExpandFunctionArguments() { // Remove the paste operator, report use of the extension. PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma); ResultToks.pop_back(); + + // If the comma was right after another paste (e.g. "X##,##__VA_ARGS__"), + // then removal of the comma should produce a placemarker token (in C99 + // terms) which we model by popping off the previous ##, giving us a plain + // "X" when __VA_ARGS__ is empty. + if (!ResultToks.empty() && ResultToks.back().is(tok::hashhash)) + ResultToks.pop_back(); } continue; } @@ -478,7 +485,7 @@ bool TokenLexer::PasteTokens(Token &Tok) { return true; } - // Do not emit the warning when preprocessing assembler code. + // Do not emit the error when preprocessing assembler code. if (!PP.getLangOptions().AsmPreprocessor) { // Explicitly convert the token location to have proper instantiation // information so that the user knows where it came from. @@ -486,8 +493,13 @@ bool TokenLexer::PasteTokens(Token &Tok) { SourceLocation Loc = SM.createInstantiationLoc(PasteOpLoc, InstantiateLocStart, InstantiateLocEnd, 2); - PP.Diag(Loc, diag::err_pp_bad_paste) - << std::string(Buffer.begin(), Buffer.end()); + // If we're in microsoft extensions mode, downgrade this from a hard + // error to a warning that defaults to an error. This allows + // disabling it. + PP.Diag(Loc, + PP.getLangOptions().Microsoft ? diag::err_pp_bad_paste_ms + : diag::err_pp_bad_paste) + << Buffer.str(); } // Do not consume the RHS. diff --git a/lib/Makefile b/lib/Makefile index 4fca624..dbd0eb6 100755 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,7 +9,7 @@ CLANG_LEVEL := .. PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \ - Checker Rewrite Frontend Index Driver + Checker Rewrite Serialization Frontend FrontendTool Index Driver include $(CLANG_LEVEL)/Makefile diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp deleted file mode 100644 index 98d5d07..0000000 --- a/lib/Parse/AttributeList.cpp +++ /dev/null @@ -1,130 +0,0 @@ -//===--- AttributeList.cpp --------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the AttributeList class implementation -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/AttributeList.h" -#include "clang/Basic/IdentifierTable.h" -#include "llvm/ADT/StringSwitch.h" -using namespace clang; - -AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, - IdentifierInfo *sName, SourceLocation sLoc, - IdentifierInfo *pName, SourceLocation pLoc, - ActionBase::ExprTy **ExprList, unsigned numArgs, - AttributeList *n, bool declspec, bool cxx0x) - : AttrName(aName), AttrLoc(aLoc), ScopeName(sName), ScopeLoc(sLoc), - ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n), - DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false) { - - if (numArgs == 0) - Args = 0; - else { - Args = new ActionBase::ExprTy*[numArgs]; - memcpy(Args, ExprList, numArgs*sizeof(Args[0])); - } -} - -AttributeList::~AttributeList() { - if (Args) { - // FIXME: before we delete the vector, we need to make sure the Expr's - // have been deleted. Since ActionBase::ExprTy is "void", we are dependent - // on the actions module for actually freeing the memory. The specific - // hooks are ActOnDeclarator, ActOnTypeName, ActOnParamDeclaratorType, - // ParseField, ParseTag. Once these routines have freed the expression, - // they should zero out the Args slot (to indicate the memory has been - // freed). If any element of the vector is non-null, we should assert. - delete [] Args; - } - delete Next; -} - -AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { - llvm::StringRef AttrName = Name->getName(); - - // Normalize the attribute name, __foo__ becomes foo. - if (AttrName.startswith("__") && AttrName.endswith("__")) - AttrName = AttrName.substr(2, AttrName.size() - 4); - - return llvm::StringSwitch(AttrName) - .Case("weak", AT_weak) - .Case("weakref", AT_weakref) - .Case("pure", AT_pure) - .Case("mode", AT_mode) - .Case("used", AT_used) - .Case("alias", AT_alias) - .Case("align", AT_aligned) - .Case("final", AT_final) - .Case("cdecl", AT_cdecl) - .Case("const", AT_const) - .Case("blocks", AT_blocks) - .Case("format", AT_format) - .Case("hiding", AT_hiding) - .Case("malloc", AT_malloc) - .Case("packed", AT_packed) - .Case("unused", AT_unused) - .Case("aligned", AT_aligned) - .Case("cleanup", AT_cleanup) - .Case("nodebug", AT_nodebug) - .Case("nonnull", AT_nonnull) - .Case("nothrow", AT_nothrow) - .Case("objc_gc", AT_objc_gc) - .Case("regparm", AT_regparm) - .Case("section", AT_section) - .Case("stdcall", AT_stdcall) - .Case("annotate", AT_annotate) - .Case("fastcall", AT_fastcall) - .Case("ibaction", AT_IBAction) - .Case("iboutlet", AT_IBOutlet) - .Case("iboutletcollection", AT_IBOutletCollection) - .Case("noreturn", AT_noreturn) - .Case("noinline", AT_noinline) - .Case("override", AT_override) - .Case("sentinel", AT_sentinel) - .Case("NSObject", AT_nsobject) - .Case("dllimport", AT_dllimport) - .Case("dllexport", AT_dllexport) - .Case("may_alias", IgnoredAttribute) // FIXME: TBAA - .Case("base_check", AT_base_check) - .Case("deprecated", AT_deprecated) - .Case("visibility", AT_visibility) - .Case("destructor", AT_destructor) - .Case("format_arg", AT_format_arg) - .Case("gnu_inline", AT_gnu_inline) - .Case("weak_import", AT_weak_import) - .Case("vector_size", AT_vector_size) - .Case("constructor", AT_constructor) - .Case("unavailable", AT_unavailable) - .Case("overloadable", AT_overloadable) - .Case("address_space", AT_address_space) - .Case("always_inline", AT_always_inline) - .Case("returns_twice", IgnoredAttribute) - .Case("vec_type_hint", IgnoredAttribute) - .Case("objc_exception", AT_objc_exception) - .Case("ext_vector_type", AT_ext_vector_type) - .Case("transparent_union", AT_transparent_union) - .Case("analyzer_noreturn", AT_analyzer_noreturn) - .Case("warn_unused_result", AT_warn_unused_result) - .Case("carries_dependency", AT_carries_dependency) - .Case("ns_returns_not_retained", AT_ns_returns_not_retained) - .Case("ns_returns_retained", AT_ns_returns_retained) - .Case("cf_returns_not_retained", AT_cf_returns_not_retained) - .Case("cf_returns_retained", AT_cf_returns_retained) - .Case("reqd_work_group_size", AT_reqd_wg_size) - .Case("init_priority", AT_init_priority) - .Case("no_instrument_function", AT_no_instrument_function) - .Case("thiscall", AT_thiscall) - .Case("__cdecl", AT_cdecl) - .Case("__stdcall", AT_stdcall) - .Case("__fastcall", AT_fastcall) - .Case("__thiscall", AT_thiscall) - .Default(UnknownAttribute); -} diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt index fafcf77..189af3d 100644 --- a/lib/Parse/CMakeLists.txt +++ b/lib/Parse/CMakeLists.txt @@ -1,9 +1,7 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangParse - AttributeList.cpp - DeclSpec.cpp - MinimalAction.cpp + ParseAST.cpp ParseCXXInlineMethods.cpp ParseDecl.cpp ParseDeclCXX.cpp @@ -18,4 +16,4 @@ add_clang_library(clangParse Parser.cpp ) -add_dependencies(clangParse ClangAttrList ClangDiagnosticParse) +add_dependencies(clangParse ClangAttrClasses ClangAttrList ClangDeclNodes ClangDiagnosticParse ClangStmtNodes) diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp deleted file mode 100644 index d2cd744..0000000 --- a/lib/Parse/DeclSpec.cpp +++ /dev/null @@ -1,595 +0,0 @@ -//===--- SemaDeclSpec.cpp - Declaration Specifier Semantic Analysis -------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements semantic analysis for declaration specifiers. -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/ParseDiagnostic.h" -#include "clang/Parse/Template.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Basic/LangOptions.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/ErrorHandling.h" -#include -using namespace clang; - - -static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc, - SourceManager &SrcMgr, unsigned DiagID) { - return D.Report(FullSourceLoc(Loc, SrcMgr), DiagID); -} - - -void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) { - assert(TemplateId && "NULL template-id annotation?"); - Kind = IK_TemplateId; - this->TemplateId = TemplateId; - StartLocation = TemplateId->TemplateNameLoc; - EndLocation = TemplateId->RAngleLoc; -} - -void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) { - assert(TemplateId && "NULL template-id annotation?"); - Kind = IK_ConstructorTemplateId; - this->TemplateId = TemplateId; - StartLocation = TemplateId->TemplateNameLoc; - EndLocation = TemplateId->RAngleLoc; -} - -/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. -/// "TheDeclarator" is the declarator that this will be added to. -DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, - SourceLocation EllipsisLoc, - ParamInfo *ArgInfo, - unsigned NumArgs, - unsigned TypeQuals, - bool hasExceptionSpec, - SourceLocation ThrowLoc, - bool hasAnyExceptionSpec, - ActionBase::TypeTy **Exceptions, - SourceRange *ExceptionRanges, - unsigned NumExceptions, - SourceLocation LPLoc, - SourceLocation RPLoc, - Declarator &TheDeclarator) { - DeclaratorChunk I; - I.Kind = Function; - I.Loc = LPLoc; - I.EndLoc = RPLoc; - I.Fun.hasPrototype = hasProto; - I.Fun.isVariadic = isVariadic; - I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding(); - I.Fun.DeleteArgInfo = false; - I.Fun.TypeQuals = TypeQuals; - I.Fun.NumArgs = NumArgs; - I.Fun.ArgInfo = 0; - I.Fun.hasExceptionSpec = hasExceptionSpec; - I.Fun.ThrowLoc = ThrowLoc.getRawEncoding(); - I.Fun.hasAnyExceptionSpec = hasAnyExceptionSpec; - I.Fun.NumExceptions = NumExceptions; - I.Fun.Exceptions = 0; - - // new[] an argument array if needed. - if (NumArgs) { - // If the 'InlineParams' in Declarator is unused and big enough, put our - // parameter list there (in an effort to avoid new/delete traffic). If it - // is already used (consider a function returning a function pointer) or too - // small (function taking too many arguments), go to the heap. - if (!TheDeclarator.InlineParamsUsed && - NumArgs <= llvm::array_lengthof(TheDeclarator.InlineParams)) { - I.Fun.ArgInfo = TheDeclarator.InlineParams; - I.Fun.DeleteArgInfo = false; - TheDeclarator.InlineParamsUsed = true; - } else { - I.Fun.ArgInfo = new DeclaratorChunk::ParamInfo[NumArgs]; - I.Fun.DeleteArgInfo = true; - } - memcpy(I.Fun.ArgInfo, ArgInfo, sizeof(ArgInfo[0])*NumArgs); - } - // new[] an exception array if needed - if (NumExceptions) { - I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions]; - for (unsigned i = 0; i != NumExceptions; ++i) { - I.Fun.Exceptions[i].Ty = Exceptions[i]; - I.Fun.Exceptions[i].Range = ExceptionRanges[i]; - } - } - return I; -} - -/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this -/// declaration specifier includes. -/// -unsigned DeclSpec::getParsedSpecifiers() const { - unsigned Res = 0; - if (StorageClassSpec != SCS_unspecified || - SCS_thread_specified) - Res |= PQ_StorageClassSpecifier; - - if (TypeQualifiers != TQ_unspecified) - Res |= PQ_TypeQualifier; - - if (hasTypeSpecifier()) - Res |= PQ_TypeSpecifier; - - if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified) - Res |= PQ_FunctionSpecifier; - return Res; -} - -template static bool BadSpecifier(T TNew, T TPrev, - const char *&PrevSpec, - unsigned &DiagID) { - PrevSpec = DeclSpec::getSpecifierName(TPrev); - DiagID = (TNew == TPrev ? diag::ext_duplicate_declspec - : diag::err_invalid_decl_spec_combination); - return true; -} - -const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) { - switch (S) { - case DeclSpec::SCS_unspecified: return "unspecified"; - case DeclSpec::SCS_typedef: return "typedef"; - case DeclSpec::SCS_extern: return "extern"; - case DeclSpec::SCS_static: return "static"; - case DeclSpec::SCS_auto: return "auto"; - case DeclSpec::SCS_register: return "register"; - case DeclSpec::SCS_private_extern: return "__private_extern__"; - case DeclSpec::SCS_mutable: return "mutable"; - } - llvm_unreachable("Unknown typespec!"); -} - -const char *DeclSpec::getSpecifierName(TSW W) { - switch (W) { - case TSW_unspecified: return "unspecified"; - case TSW_short: return "short"; - case TSW_long: return "long"; - case TSW_longlong: return "long long"; - } - llvm_unreachable("Unknown typespec!"); -} - -const char *DeclSpec::getSpecifierName(TSC C) { - switch (C) { - case TSC_unspecified: return "unspecified"; - case TSC_imaginary: return "imaginary"; - case TSC_complex: return "complex"; - } - llvm_unreachable("Unknown typespec!"); -} - - -const char *DeclSpec::getSpecifierName(TSS S) { - switch (S) { - case TSS_unspecified: return "unspecified"; - case TSS_signed: return "signed"; - case TSS_unsigned: return "unsigned"; - } - llvm_unreachable("Unknown typespec!"); -} - -const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { - switch (T) { - case DeclSpec::TST_unspecified: return "unspecified"; - case DeclSpec::TST_void: return "void"; - case DeclSpec::TST_char: return "char"; - case DeclSpec::TST_wchar: return "wchar_t"; - case DeclSpec::TST_char16: return "char16_t"; - case DeclSpec::TST_char32: return "char32_t"; - case DeclSpec::TST_int: return "int"; - case DeclSpec::TST_float: return "float"; - case DeclSpec::TST_double: return "double"; - case DeclSpec::TST_bool: return "_Bool"; - case DeclSpec::TST_decimal32: return "_Decimal32"; - case DeclSpec::TST_decimal64: return "_Decimal64"; - case DeclSpec::TST_decimal128: return "_Decimal128"; - case DeclSpec::TST_enum: return "enum"; - case DeclSpec::TST_class: return "class"; - case DeclSpec::TST_union: return "union"; - case DeclSpec::TST_struct: return "struct"; - case DeclSpec::TST_typename: return "type-name"; - case DeclSpec::TST_typeofType: - case DeclSpec::TST_typeofExpr: return "typeof"; - case DeclSpec::TST_auto: return "auto"; - case DeclSpec::TST_decltype: return "(decltype)"; - case DeclSpec::TST_error: return "(error)"; - } - llvm_unreachable("Unknown typespec!"); -} - -const char *DeclSpec::getSpecifierName(TQ T) { - switch (T) { - case DeclSpec::TQ_unspecified: return "unspecified"; - case DeclSpec::TQ_const: return "const"; - case DeclSpec::TQ_restrict: return "restrict"; - case DeclSpec::TQ_volatile: return "volatile"; - } - llvm_unreachable("Unknown typespec!"); -} - -bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, - const char *&PrevSpec, - unsigned &DiagID) { - if (StorageClassSpec != SCS_unspecified) - return BadSpecifier(S, (SCS)StorageClassSpec, PrevSpec, DiagID); - StorageClassSpec = S; - StorageClassSpecLoc = Loc; - assert((unsigned)S == StorageClassSpec && "SCS constants overflow bitfield"); - return false; -} - -bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc, - const char *&PrevSpec, - unsigned &DiagID) { - if (SCS_thread_specified) { - PrevSpec = "__thread"; - DiagID = diag::ext_duplicate_declspec; - return true; - } - SCS_thread_specified = true; - SCS_threadLoc = Loc; - return false; -} - - -/// These methods set the specified attribute of the DeclSpec, but return true -/// and ignore the request if invalid (e.g. "extern" then "auto" is -/// specified). -bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc, - const char *&PrevSpec, - unsigned &DiagID) { - if (TypeSpecWidth != TSW_unspecified && - // Allow turning long -> long long. - (W != TSW_longlong || TypeSpecWidth != TSW_long)) - return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID); - TypeSpecWidth = W; - TSWLoc = Loc; - if (TypeAltiVecVector && !TypeAltiVecBool && - ((TypeSpecWidth == TSW_long) || (TypeSpecWidth == TSW_longlong))) { - PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); - DiagID = diag::warn_vector_long_decl_spec_combination; - return true; - } - return false; -} - -bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc, - const char *&PrevSpec, - unsigned &DiagID) { - if (TypeSpecComplex != TSC_unspecified) - return BadSpecifier(C, (TSC)TypeSpecComplex, PrevSpec, DiagID); - TypeSpecComplex = C; - TSCLoc = Loc; - return false; -} - -bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc, - const char *&PrevSpec, - unsigned &DiagID) { - if (TypeSpecSign != TSS_unspecified) - return BadSpecifier(S, (TSS)TypeSpecSign, PrevSpec, DiagID); - TypeSpecSign = S; - TSSLoc = Loc; - return false; -} - -bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, - const char *&PrevSpec, - unsigned &DiagID, - void *Rep, bool Owned) { - if (TypeSpecType != TST_unspecified) { - PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); - DiagID = diag::err_invalid_decl_spec_combination; - return true; - } - if (TypeAltiVecVector && (T == TST_bool) && !TypeAltiVecBool) { - TypeAltiVecBool = true; - TSTLoc = Loc; - return false; - } - TypeSpecType = T; - TypeRep = Rep; - TSTLoc = Loc; - TypeSpecOwned = Owned; - if (TypeAltiVecVector && !TypeAltiVecBool && (TypeSpecType == TST_double)) { - PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); - DiagID = diag::err_invalid_vector_decl_spec; - return true; - } - return false; -} - -bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc, - const char *&PrevSpec, unsigned &DiagID) { - if (TypeSpecType != TST_unspecified) { - PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); - DiagID = diag::err_invalid_vector_decl_spec_combination; - return true; - } - TypeAltiVecVector = isAltiVecVector; - AltiVecLoc = Loc; - return false; -} - -bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc, - const char *&PrevSpec, unsigned &DiagID) { - if (!TypeAltiVecVector || TypeAltiVecPixel || - (TypeSpecType != TST_unspecified)) { - PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); - DiagID = diag::err_invalid_pixel_decl_spec_combination; - return true; - } - TypeAltiVecPixel = isAltiVecPixel; - TSTLoc = Loc; - return false; -} - -bool DeclSpec::SetTypeSpecError() { - TypeSpecType = TST_error; - TypeRep = 0; - TSTLoc = SourceLocation(); - return false; -} - -bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID, const LangOptions &Lang) { - // Duplicates turn into warnings pre-C99. - if ((TypeQualifiers & T) && !Lang.C99) - return BadSpecifier(T, T, PrevSpec, DiagID); - TypeQualifiers |= T; - - switch (T) { - default: assert(0 && "Unknown type qualifier!"); - case TQ_const: TQ_constLoc = Loc; break; - case TQ_restrict: TQ_restrictLoc = Loc; break; - case TQ_volatile: TQ_volatileLoc = Loc; break; - } - return false; -} - -bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID) { - // 'inline inline' is ok. - FS_inline_specified = true; - FS_inlineLoc = Loc; - return false; -} - -bool DeclSpec::SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID) { - // 'virtual virtual' is ok. - FS_virtual_specified = true; - FS_virtualLoc = Loc; - return false; -} - -bool DeclSpec::SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID) { - // 'explicit explicit' is ok. - FS_explicit_specified = true; - FS_explicitLoc = Loc; - return false; -} - -bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID) { - if (Friend_specified) { - PrevSpec = "friend"; - DiagID = diag::ext_duplicate_declspec; - return true; - } - - Friend_specified = true; - FriendLoc = Loc; - return false; -} - -bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID) { - // 'constexpr constexpr' is ok. - Constexpr_specified = true; - ConstexprLoc = Loc; - return false; -} - -void DeclSpec::setProtocolQualifiers(const ActionBase::DeclPtrTy *Protos, - unsigned NP, - SourceLocation *ProtoLocs, - SourceLocation LAngleLoc) { - if (NP == 0) return; - ProtocolQualifiers = new ActionBase::DeclPtrTy[NP]; - ProtocolLocs = new SourceLocation[NP]; - memcpy((void*)ProtocolQualifiers, Protos, sizeof(ActionBase::DeclPtrTy)*NP); - memcpy(ProtocolLocs, ProtoLocs, sizeof(SourceLocation)*NP); - NumProtocolQualifiers = NP; - ProtocolLAngleLoc = LAngleLoc; -} - -void DeclSpec::SaveWrittenBuiltinSpecs() { - writtenBS.Sign = getTypeSpecSign(); - writtenBS.Width = getTypeSpecWidth(); - writtenBS.Type = getTypeSpecType(); - // Search the list of attributes for the presence of a mode attribute. - writtenBS.ModeAttr = false; - AttributeList* attrs = getAttributes(); - while (attrs) { - if (attrs->getKind() == AttributeList::AT_mode) { - writtenBS.ModeAttr = true; - break; - } - attrs = attrs->getNext(); - } -} - -/// Finish - This does final analysis of the declspec, rejecting things like -/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or -/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, -/// DeclSpec is guaranteed self-consistent, even if an error occurred. -void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { - // Before possibly changing their values, save specs as written. - SaveWrittenBuiltinSpecs(); - SaveStorageSpecifierAsWritten(); - - // Check the type specifier components first. - SourceManager &SrcMgr = PP.getSourceManager(); - - // Validate and finalize AltiVec vector declspec. - if (TypeAltiVecVector) { - if (TypeAltiVecBool) { - // Sign specifiers are not allowed with vector bool. (PIM 2.1) - if (TypeSpecSign != TSS_unspecified) { - Diag(D, TSSLoc, SrcMgr, diag::err_invalid_vector_bool_decl_spec) - << getSpecifierName((TSS)TypeSpecSign); - } - - // Only char/int are valid with vector bool. (PIM 2.1) - if (((TypeSpecType != TST_unspecified) && (TypeSpecType != TST_char) && - (TypeSpecType != TST_int)) || TypeAltiVecPixel) { - Diag(D, TSTLoc, SrcMgr, diag::err_invalid_vector_bool_decl_spec) - << (TypeAltiVecPixel ? "__pixel" : - getSpecifierName((TST)TypeSpecType)); - } - - // Only 'short' is valid with vector bool. (PIM 2.1) - if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short)) - Diag(D, TSWLoc, SrcMgr, diag::err_invalid_vector_bool_decl_spec) - << getSpecifierName((TSW)TypeSpecWidth); - - // Elements of vector bool are interpreted as unsigned. (PIM 2.1) - if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) || - (TypeSpecWidth != TSW_unspecified)) - TypeSpecSign = TSS_unsigned; - } - - if (TypeAltiVecPixel) { - //TODO: perform validation - TypeSpecType = TST_int; - TypeSpecSign = TSS_unsigned; - TypeSpecWidth = TSW_short; - } - } - - // signed/unsigned are only valid with int/char/wchar_t. - if (TypeSpecSign != TSS_unspecified) { - if (TypeSpecType == TST_unspecified) - TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. - else if (TypeSpecType != TST_int && - TypeSpecType != TST_char && TypeSpecType != TST_wchar) { - Diag(D, TSSLoc, SrcMgr, diag::err_invalid_sign_spec) - << getSpecifierName((TST)TypeSpecType); - // signed double -> double. - TypeSpecSign = TSS_unspecified; - } - } - - // Validate the width of the type. - switch (TypeSpecWidth) { - case TSW_unspecified: break; - case TSW_short: // short int - case TSW_longlong: // long long int - if (TypeSpecType == TST_unspecified) - TypeSpecType = TST_int; // short -> short int, long long -> long long int. - else if (TypeSpecType != TST_int) { - Diag(D, TSWLoc, SrcMgr, - TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec - : diag::err_invalid_longlong_spec) - << getSpecifierName((TST)TypeSpecType); - TypeSpecType = TST_int; - } - break; - case TSW_long: // long double, long int - if (TypeSpecType == TST_unspecified) - TypeSpecType = TST_int; // long -> long int. - else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { - Diag(D, TSWLoc, SrcMgr, diag::err_invalid_long_spec) - << getSpecifierName((TST)TypeSpecType); - TypeSpecType = TST_int; - } - break; - } - - // TODO: if the implementation does not implement _Complex or _Imaginary, - // disallow their use. Need information about the backend. - if (TypeSpecComplex != TSC_unspecified) { - if (TypeSpecType == TST_unspecified) { - Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex) - << FixItHint::CreateInsertion( - PP.getLocForEndOfToken(getTypeSpecComplexLoc()), - " double"); - TypeSpecType = TST_double; // _Complex -> _Complex double. - } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { - // Note that this intentionally doesn't include _Complex _Bool. - Diag(D, TSTLoc, SrcMgr, diag::ext_integer_complex); - } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { - Diag(D, TSCLoc, SrcMgr, diag::err_invalid_complex_spec) - << getSpecifierName((TST)TypeSpecType); - TypeSpecComplex = TSC_unspecified; - } - } - - // C++ [class.friend]p6: - // No storage-class-specifier shall appear in the decl-specifier-seq - // of a friend declaration. - if (isFriendSpecified() && getStorageClassSpec()) { - DeclSpec::SCS SC = getStorageClassSpec(); - const char *SpecName = getSpecifierName(SC); - - SourceLocation SCLoc = getStorageClassSpecLoc(); - SourceLocation SCEndLoc = SCLoc.getFileLocWithOffset(strlen(SpecName)); - - Diag(D, SCLoc, SrcMgr, diag::err_friend_storage_spec) - << SpecName - << FixItHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc)); - - ClearStorageClassSpecs(); - } - - // Okay, now we can infer the real type. - - // TODO: return "auto function" and other bad things based on the real type. - - // 'data definition has no type or storage class'? -} - -bool DeclSpec::isMissingDeclaratorOk() { - TST tst = getTypeSpecType(); - return (tst == TST_union - || tst == TST_struct - || tst == TST_class - || tst == TST_enum - ) && getTypeRep() != 0 && StorageClassSpec != DeclSpec::SCS_typedef; -} - -void UnqualifiedId::clear() { - if (Kind == IK_TemplateId) - TemplateId->Destroy(); - - Kind = IK_Identifier; - Identifier = 0; - StartLocation = SourceLocation(); - EndLocation = SourceLocation(); -} - -void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc, - OverloadedOperatorKind Op, - SourceLocation SymbolLocations[3]) { - Kind = IK_OperatorFunctionId; - StartLocation = OperatorLoc; - EndLocation = OperatorLoc; - OperatorFunctionId.Operator = Op; - for (unsigned I = 0; I != 3; ++I) { - OperatorFunctionId.SymbolLocations[I] = SymbolLocations[I].getRawEncoding(); - - if (SymbolLocations[I].isValid()) - EndLocation = SymbolLocations[I]; - } -} diff --git a/lib/Parse/Makefile b/lib/Parse/Makefile index 238e02d..5ec7c333 100644 --- a/lib/Parse/Makefile +++ b/lib/Parse/Makefile @@ -13,7 +13,6 @@ CLANG_LEVEL := ../.. LIBRARYNAME := clangParse -BUILD_ARCHIVE = 1 include $(CLANG_LEVEL)/Makefile diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp deleted file mode 100644 index b720516..0000000 --- a/lib/Parse/MinimalAction.cpp +++ /dev/null @@ -1,281 +0,0 @@ -//===--- MinimalAction.cpp - Implement the MinimalAction class ------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the MinimalAction interface. -// -//===----------------------------------------------------------------------===// - -#include "clang/Parse/Parser.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" -#include "clang/Basic/TargetInfo.h" -#include "llvm/Support/Allocator.h" -#include "llvm/Support/RecyclingAllocator.h" -#include "llvm/Support/raw_ostream.h" -using namespace clang; - -/// Out-of-line virtual destructor to provide home for ActionBase class. -ActionBase::~ActionBase() {} - -/// Out-of-line virtual destructor to provide home for Action class. -Action::~Action() {} - -Action::ObjCMessageKind Action::getObjCMessageKind(Scope *S, - IdentifierInfo *Name, - SourceLocation NameLoc, - bool IsSuper, - bool HasTrailingDot, - TypeTy *&ReceiverType) { - ReceiverType = 0; - - if (IsSuper && !HasTrailingDot && S->isInObjcMethodScope()) - return ObjCSuperMessage; - - if (TypeTy *TyName = getTypeName(*Name, NameLoc, S)) { - DeclSpec DS; - const char *PrevSpec = 0; - unsigned DiagID = 0; - if (!DS.SetTypeSpecType(DeclSpec::TST_typename, NameLoc, PrevSpec, - DiagID, TyName)) { - DS.SetRangeEnd(NameLoc); - Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); - TypeResult Ty = ActOnTypeName(S, DeclaratorInfo); - if (!Ty.isInvalid()) - ReceiverType = Ty.get(); - } - return ObjCClassMessage; - } - - return ObjCInstanceMessage; -} - -// Defined out-of-line here because of dependecy on AttributeList -Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope, - SourceLocation UsingLoc, - SourceLocation NamespcLoc, - CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *NamespcName, - AttributeList *AttrList) { - - // FIXME: Parser seems to assume that Action::ActOn* takes ownership over - // passed AttributeList, however other actions don't free it, is it - // temporary state or bug? - delete AttrList; - return DeclPtrTy(); -} - -// Defined out-of-line here because of dependency on AttributeList -Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope, - AccessSpecifier AS, - bool HasUsingKeyword, - SourceLocation UsingLoc, - CXXScopeSpec &SS, - UnqualifiedId &Name, - AttributeList *AttrList, - bool IsTypeName, - SourceLocation TypenameLoc) { - - // FIXME: Parser seems to assume that Action::ActOn* takes ownership over - // passed AttributeList, however other actions don't free it, is it - // temporary state or bug? - delete AttrList; - return DeclPtrTy(); -} - - -void PrettyStackTraceActionsDecl::print(llvm::raw_ostream &OS) const { - if (Loc.isValid()) { - Loc.print(OS, SM); - OS << ": "; - } - OS << Message; - - std::string Name = Actions.getDeclName(TheDecl); - if (!Name.empty()) - OS << " '" << Name << '\''; - - OS << '\n'; -} - -/// TypeNameInfo - A link exists here for each scope that an identifier is -/// defined. -namespace { - struct TypeNameInfo { - TypeNameInfo *Prev; - bool isTypeName; - - TypeNameInfo(bool istypename, TypeNameInfo *prev) { - isTypeName = istypename; - Prev = prev; - } - }; - - struct TypeNameInfoTable { - llvm::RecyclingAllocator Allocator; - - void AddEntry(bool isTypename, IdentifierInfo *II) { - TypeNameInfo *TI = Allocator.Allocate(); - new (TI) TypeNameInfo(isTypename, II->getFETokenInfo()); - II->setFETokenInfo(TI); - } - - void DeleteEntry(TypeNameInfo *Entry) { - Entry->~TypeNameInfo(); - Allocator.Deallocate(Entry); - } - }; -} - -static TypeNameInfoTable *getTable(void *TP) { - return static_cast(TP); -} - -MinimalAction::MinimalAction(Preprocessor &pp) - : Idents(pp.getIdentifierTable()), PP(pp) { - TypeNameInfoTablePtr = new TypeNameInfoTable(); -} - -MinimalAction::~MinimalAction() { - delete getTable(TypeNameInfoTablePtr); -} - -void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { - TUScope = S; - - TypeNameInfoTable &TNIT = *getTable(TypeNameInfoTablePtr); - - if (PP.getTargetInfo().getPointerWidth(0) >= 64) { - // Install [u]int128_t for 64-bit targets. - TNIT.AddEntry(true, &Idents.get("__int128_t")); - TNIT.AddEntry(true, &Idents.get("__uint128_t")); - } - - if (PP.getLangOptions().ObjC1) { - // Recognize the ObjC built-in type identifiers as types. - TNIT.AddEntry(true, &Idents.get("id")); - TNIT.AddEntry(true, &Idents.get("SEL")); - TNIT.AddEntry(true, &Idents.get("Class")); - TNIT.AddEntry(true, &Idents.get("Protocol")); - } -} - -/// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to -/// determine whether the name is a type name (objc class name or typedef) or -/// not in this scope. -/// -/// FIXME: Use the passed CXXScopeSpec for accurate C++ type checking. -Action::TypeTy * -MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc, - Scope *S, CXXScopeSpec *SS, - bool isClassName, TypeTy *ObjectType) { - if (TypeNameInfo *TI = II.getFETokenInfo()) - if (TI->isTypeName) - return TI; - return 0; -} - -/// isCurrentClassName - Always returns false, because MinimalAction -/// does not support C++ classes with constructors. -bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *, - const CXXScopeSpec *) { - return false; -} - -TemplateNameKind -MinimalAction::isTemplateName(Scope *S, - CXXScopeSpec &SS, - UnqualifiedId &Name, - TypeTy *ObjectType, - bool EnteringScope, - TemplateTy &TemplateDecl, - bool &MemberOfUnknownSpecialization) { - MemberOfUnknownSpecialization = false; - return TNK_Non_template; -} - -/// ActOnDeclarator - If this is a typedef declarator, we modify the -/// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is -/// popped. -Action::DeclPtrTy -MinimalAction::ActOnDeclarator(Scope *S, Declarator &D) { - IdentifierInfo *II = D.getIdentifier(); - - // If there is no identifier associated with this declarator, bail out. - if (II == 0) return DeclPtrTy(); - - TypeNameInfo *weCurrentlyHaveTypeInfo = II->getFETokenInfo(); - bool isTypeName = - D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef; - - // this check avoids creating TypeNameInfo objects for the common case. - // It does need to handle the uncommon case of shadowing a typedef name with a - // non-typedef name. e.g. { typedef int a; a xx; { int a; } } - if (weCurrentlyHaveTypeInfo || isTypeName) { - // Allocate and add the 'TypeNameInfo' "decl". - getTable(TypeNameInfoTablePtr)->AddEntry(isTypeName, II); - - // Remember that this needs to be removed when the scope is popped. - S->AddDecl(DeclPtrTy::make(II)); - } - return DeclPtrTy(); -} - -Action::DeclPtrTy -MinimalAction::ActOnStartClassInterface(SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, - SourceLocation ClassLoc, - IdentifierInfo *SuperName, - SourceLocation SuperLoc, - const DeclPtrTy *ProtoRefs, - unsigned NumProtocols, - const SourceLocation *ProtoLocs, - SourceLocation EndProtoLoc, - AttributeList *AttrList) { - // Allocate and add the 'TypeNameInfo' "decl". - getTable(TypeNameInfoTablePtr)->AddEntry(true, ClassName); - return DeclPtrTy(); -} - -/// ActOnForwardClassDeclaration - -/// Scope will always be top level file scope. -Action::DeclPtrTy -MinimalAction::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, - IdentifierInfo **IdentList, - SourceLocation *IdentLocs, - unsigned NumElts) { - for (unsigned i = 0; i != NumElts; ++i) { - // Allocate and add the 'TypeNameInfo' "decl". - getTable(TypeNameInfoTablePtr)->AddEntry(true, IdentList[i]); - - // Remember that this needs to be removed when the scope is popped. - TUScope->AddDecl(DeclPtrTy::make(IdentList[i])); - } - return DeclPtrTy(); -} - -/// ActOnPopScope - When a scope is popped, if any typedefs are now -/// out-of-scope, they are removed from the IdentifierInfo::FETokenInfo field. -void MinimalAction::ActOnPopScope(SourceLocation Loc, Scope *S) { - TypeNameInfoTable &Table = *getTable(TypeNameInfoTablePtr); - - for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end(); - I != E; ++I) { - IdentifierInfo &II = *(*I).getAs(); - TypeNameInfo *TI = II.getFETokenInfo(); - assert(TI && "This decl didn't get pushed??"); - - if (TI) { - TypeNameInfo *Next = TI->Prev; - Table.DeleteEntry(TI); - - II.setFETokenInfo(Next); - } - } -} diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp new file mode 100644 index 0000000..d027879 --- /dev/null +++ b/lib/Parse/ParseAST.cpp @@ -0,0 +1,114 @@ +//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the clang::ParseAST method. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/ParseAST.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/Sema/SemaConsumer.h" +#include "clang/Sema/ExternalSemaSource.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/Stmt.h" +#include "clang/Parse/Parser.h" +#include + +using namespace clang; + +static void DumpRecordLayouts(ASTContext &C) { + for (ASTContext::type_iterator I = C.types_begin(), E = C.types_end(); + I != E; ++I) { + const RecordType *RT = dyn_cast(*I); + if (!RT) + continue; + + const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); + if (!RD || RD->isImplicit() || RD->isDependentType() || + RD->isInvalidDecl() || !RD->getDefinition()) + continue; + + // FIXME: Do we really need to hard code this? + if (RD->getQualifiedNameAsString() == "__va_list_tag") + continue; + + C.DumpRecordLayout(RD, llvm::errs()); + } +} + +//===----------------------------------------------------------------------===// +// Public interface to the file +//===----------------------------------------------------------------------===// + +/// ParseAST - Parse the entire file specified, notifying the ASTConsumer as +/// the file is parsed. This inserts the parsed decls into the translation unit +/// held by Ctx. +/// +void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, + ASTContext &Ctx, bool PrintStats, + bool CompleteTranslationUnit, + CodeCompleteConsumer *CompletionConsumer) { + Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer); + ParseAST(S, PrintStats); +} + +void clang::ParseAST(Sema &S, bool PrintStats) { + // Collect global stats on Decls/Stmts (until we have a module streamer). + if (PrintStats) { + Decl::CollectingStats(true); + Stmt::CollectingStats(true); + } + + ASTConsumer *Consumer = &S.getASTConsumer(); + + Parser P(S.getPreprocessor(), S); + S.getPreprocessor().EnterMainSourceFile(); + P.Initialize(); + S.Initialize(); + + if (ExternalASTSource *External = S.getASTContext().getExternalSource()) + External->StartTranslationUnit(Consumer); + + Parser::DeclGroupPtrTy ADecl; + + while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. + // If we got a null return and something *was* parsed, ignore it. This + // is due to a top-level semicolon, an action override, or a parse error + // skipping something. + if (ADecl) + Consumer->HandleTopLevelDecl(ADecl.get()); + }; + // Check for any pending objective-c implementation decl. + while ((ADecl = P.FinishPendingObjCActions())) + Consumer->HandleTopLevelDecl(ADecl.get()); + + // Process any TopLevelDecls generated by #pragma weak. + for (llvm::SmallVector::iterator + I = S.WeakTopLevelDecls().begin(), + E = S.WeakTopLevelDecls().end(); I != E; ++I) + Consumer->HandleTopLevelDecl(DeclGroupRef(*I)); + + // Dump record layouts, if requested. + if (S.getLangOptions().DumpRecordLayouts) + DumpRecordLayouts(S.getASTContext()); + + Consumer->HandleTranslationUnit(S.getASTContext()); + + if (PrintStats) { + fprintf(stderr, "\nSTATISTICS:\n"); + P.getActions().PrintStats(); + S.getASTContext().PrintStats(); + Decl::PrintStats(); + Stmt::PrintStats(); + Consumer->PrintStats(); + } +} diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 62a7ecd..d327db4 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -13,26 +13,25 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Scope.h" using namespace clang; /// ParseCXXInlineMethodDef - We parsed and verified that the specified /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. -Parser::DeclPtrTy -Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, +Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, const ParsedTemplateInfo &TemplateInfo) { assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && "This isn't a function declarator!"); assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && "Current token not a '{', ':' or 'try'!"); - Action::MultiTemplateParamsArg TemplateParams(Actions, + MultiTemplateParamsArg TemplateParams(Actions, TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0, TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0); - DeclPtrTy FnD; + Decl *FnD; if (D.getDeclSpec().isFriendSpecified()) // FIXME: Friend templates FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, true, @@ -139,12 +138,17 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { assert(Tok.is(tok::equal) && "Default argument not starting with '='"); SourceLocation EqualLoc = ConsumeToken(); - OwningExprResult DefArgResult(ParseAssignmentExpression()); + ExprResult DefArgResult(ParseAssignmentExpression()); if (DefArgResult.isInvalid()) Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param); - else + else { + if (Tok.is(tok::cxx_defaultarg_end)) + ConsumeToken(); + else + Diag(Tok.getLocation(), diag::err_default_arg_unparsed); Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc, - move(DefArgResult)); + DefArgResult.take()); + } assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, Tok.getLocation()) && @@ -227,7 +231,7 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { // Error recovery. if (!Tok.is(tok::l_brace)) { - Actions.ActOnFinishFunctionBody(LM.D, Action::StmtArg(Actions)); + Actions.ActOnFinishFunctionBody(LM.D, 0); continue; } } else diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 62ef3ec..555fcf0 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -13,8 +13,9 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" -#include "clang/Parse/Scope.h" -#include "clang/Parse/Template.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/PrettyDeclStackTrace.h" #include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallSet.h" using namespace clang; @@ -28,7 +29,7 @@ using namespace clang; /// specifier-qualifier-list abstract-declarator[opt] /// /// Called type-id in C++. -Action::TypeResult Parser::ParseTypeName(SourceRange *Range) { +TypeResult Parser::ParseTypeName(SourceRange *Range) { // Parse the common declaration-specifiers piece. DeclSpec DS; ParseSpecifierQualifierList(DS); @@ -131,7 +132,7 @@ AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { // now parse the non-empty comma separated list of expressions while (1) { - OwningExprResult ArgExpr(ParseAssignmentExpression()); + ExprResult ArgExpr(ParseAssignmentExpression()); if (ArgExpr.isInvalid()) { ArgExprsOk = false; SkipUntil(tok::r_paren); @@ -174,11 +175,13 @@ AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { case tok::kw_double: case tok::kw_void: case tok::kw_typeof: + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0, CurrAttr); + if (CurrAttr->getKind() == AttributeList::AT_IBOutletCollection) + Diag(Tok, diag::err_iboutletcollection_builtintype); // If it's a builtin type name, eat it and expect a rparen // __attribute__(( vec_type_hint(char) )) ConsumeToken(); - CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0, CurrAttr); if (Tok.is(tok::r_paren)) ConsumeParen(); break; @@ -189,7 +192,7 @@ AttributeList *Parser::ParseGNUAttributes(SourceLocation *EndLoc) { // now parse the list of expressions while (1) { - OwningExprResult ArgExpr(ParseAssignmentExpression()); + ExprResult ArgExpr(ParseAssignmentExpression()); if (ArgExpr.isInvalid()) { ArgExprsOk = false; SkipUntil(tok::r_paren); @@ -254,9 +257,9 @@ AttributeList* Parser::ParseMicrosoftDeclSpec(AttributeList *CurrAttr) { ConsumeParen(); // FIXME: This doesn't parse __declspec(property(get=get_func_name)) // correctly. - OwningExprResult ArgExpr(ParseAssignmentExpression()); + ExprResult ArgExpr(ParseAssignmentExpression()); if (!ArgExpr.isInvalid()) { - ExprTy* ExprList = ArgExpr.take(); + Expr *ExprList = ArgExpr.take(); CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), &ExprList, 1, CurrAttr, true); @@ -290,6 +293,17 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) { return CurrAttr; } +AttributeList* Parser::ParseBorlandTypeAttributes(AttributeList *CurrAttr) { + // Treat these like attributes + while (Tok.is(tok::kw___pascal)) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + SourceLocation AttrNameLoc = ConsumeToken(); + CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, CurrAttr, true); + } + return CurrAttr; +} + /// ParseDeclaration - Parse a full 'declaration', which consists of /// declaration-specifiers, some number of declarators, and a semicolon. /// 'Context' should be a Declarator::TheContext value. This returns the @@ -311,7 +325,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, CXX0XAttributeList Attr) { ParenBraceBracketBalancer BalancerRAIIObj(*this); - DeclPtrTy SingleDecl; + Decl *SingleDecl = 0; switch (Tok.getKind()) { case tok::kw_template: case tok::kw_export: @@ -320,6 +334,17 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(unsigned Context, << Attr.Range; SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd); break; + case tok::kw_inline: + // Could be the start of an inline namespace. Allowed as an ext in C++03. + if (getLang().CPlusPlus && NextToken().is(tok::kw_namespace)) { + if (Attr.HasAttr) + Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) + << Attr.Range; + SourceLocation InlineLoc = ConsumeToken(); + SingleDecl = ParseNamespace(Context, DeclEnd, InlineLoc); + break; + } + return ParseSimpleDeclaration(Context, DeclEnd, Attr.AttrList, true); case tok::kw_namespace: if (Attr.HasAttr) Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) @@ -366,7 +391,7 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(unsigned Context, // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { if (RequireSemi) ConsumeToken(); - DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, + Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, DS); DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); @@ -410,7 +435,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, DS.ClearStorageClassSpecs(); } - DeclPtrTy TheDecl = ParseFunctionDefinition(D); + Decl *TheDecl = ParseFunctionDefinition(D); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -427,10 +452,10 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } } - llvm::SmallVector DeclsInGroup; - DeclPtrTy FirstDecl = ParseDeclarationAfterDeclarator(D); + llvm::SmallVector DeclsInGroup; + Decl *FirstDecl = ParseDeclarationAfterDeclarator(D); D.complete(FirstDecl); - if (FirstDecl.get()) + if (FirstDecl) DeclsInGroup.push_back(FirstDecl); // If we don't have a comma, it is either the end of the list (a ';') or an @@ -457,9 +482,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, ParseDeclarator(D); - DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(D); + Decl *ThisDecl = ParseDeclarationAfterDeclarator(D); D.complete(ThisDecl); - if (ThisDecl.get()) + if (ThisDecl) DeclsInGroup.push_back(ThisDecl); } @@ -507,15 +532,15 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, /// According to the standard grammar, =default and =delete are function /// definitions, but that definitely doesn't fit with the parser here. /// -Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, +Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, const ParsedTemplateInfo &TemplateInfo) { // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { SourceLocation Loc; - OwningExprResult AsmLabel(ParseSimpleAsm(&Loc)); + ExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) { SkipUntil(tok::semi, true, true); - return DeclPtrTy(); + return 0; } D.setAsmLabel(AsmLabel.release()); @@ -530,7 +555,7 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, } // Inform the current actions module that we just parsed this declarator. - DeclPtrTy ThisDecl; + Decl *ThisDecl = 0; switch (TemplateInfo.Kind) { case ParsedTemplateInfo::NonTemplate: ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); @@ -539,21 +564,21 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, case ParsedTemplateInfo::Template: case ParsedTemplateInfo::ExplicitSpecialization: ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(), - Action::MultiTemplateParamsArg(Actions, + MultiTemplateParamsArg(Actions, TemplateInfo.TemplateParams->data(), TemplateInfo.TemplateParams->size()), D); break; case ParsedTemplateInfo::ExplicitInstantiation: { - Action::DeclResult ThisRes + DeclResult ThisRes = Actions.ActOnExplicitInstantiation(getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, D); if (ThisRes.isInvalid()) { SkipUntil(tok::semi, true, true); - return DeclPtrTy(); + return 0; } ThisDecl = ThisRes.get(); @@ -580,7 +605,7 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, return ThisDecl; } - OwningExprResult Init(ParseInitializer()); + ExprResult Init(ParseInitializer()); if (getLang().CPlusPlus && D.getCXXScopeSpec().isSet()) { Actions.ActOnCXXExitDeclInitializer(getCurScope(), ThisDecl); @@ -591,7 +616,7 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D, SkipUntil(tok::comma, true, true); Actions.ActOnInitializerError(ThisDecl); } else - Actions.AddInitializerToDecl(ThisDecl, move(Init)); + Actions.AddInitializerToDecl(ThisDecl, Init.take()); } } else if (Tok.is(tok::l_paren)) { // Parse C++ direct initializer: '(' expression-list ')' @@ -771,7 +796,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // This is almost certainly an invalid type name. Let the action emit a // diagnostic and attempt to recover. - Action::TypeTy *T = 0; + ParsedType T; if (Actions.DiagnoseUnknownTypeName(*Tok.getIdentifierInfo(), Loc, getCurScope(), SS, T)) { // The action emitted a diagnostic, so we don't have to. @@ -781,8 +806,7 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // name token, and we're done. const char *PrevSpec; unsigned DiagID; - DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T, - false); + DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T); DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); @@ -851,21 +875,7 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, - DeclSpecContext DSContext) { - if (Tok.is(tok::code_completion)) { - Action::CodeCompletionContext CCC = Action::CCC_Namespace; - if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) - CCC = DSContext == DSC_class? Action::CCC_MemberTemplate - : Action::CCC_Template; - else if (DSContext == DSC_class) - CCC = Action::CCC_Class; - else if (ObjCImpDecl) - CCC = Action::CCC_ObjCImplementation; - - Actions.CodeCompleteOrdinaryName(getCurScope(), CCC); - ConsumeCodeCompletionToken(); - } - + DeclSpecContext DSContext) { DS.SetRangeStart(Tok.getLocation()); while (1) { bool isInvalid = false; @@ -882,6 +892,38 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.Finish(Diags, PP); return; + case tok::code_completion: { + Sema::ParserCompletionContext CCC = Sema::PCC_Namespace; + if (DS.hasTypeSpecifier()) { + bool AllowNonIdentifiers + = (getCurScope()->getFlags() & (Scope::ControlScope | + Scope::BlockScope | + Scope::TemplateParamScope | + Scope::FunctionPrototypeScope | + Scope::AtCatchScope)) == 0; + bool AllowNestedNameSpecifiers + = DSContext == DSC_top_level || + (DSContext == DSC_class && DS.isFriendSpecified()); + + Actions.CodeCompleteDeclarator(getCurScope(), AllowNonIdentifiers, + AllowNestedNameSpecifiers); + ConsumeCodeCompletionToken(); + return; + } + + if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) + CCC = DSContext == DSC_class? Sema::PCC_MemberTemplate + : Sema::PCC_Template; + else if (DSContext == DSC_class) + CCC = Sema::PCC_Class; + else if (ObjCImpDecl) + CCC = Sema::PCC_ObjCImplementation; + + Actions.CodeCompleteOrdinaryName(getCurScope(), CCC); + ConsumeCodeCompletionToken(); + return; + } + case tok::coloncolon: // ::foo::bar // C++ scope specifier. Annotate and loop, or bail out on error. if (TryAnnotateCXXScopeToken(true)) { @@ -898,7 +940,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, goto DoneWithDeclSpec; CXXScopeSpec SS; - SS.setScopeRep(Tok.getAnnotationValue()); + SS.setScopeRep((NestedNameSpecifier*) Tok.getAnnotationValue()); SS.setRange(Tok.getAnnotationRange()); // We are looking for a qualified typename. @@ -961,10 +1003,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Next.is(tok::annot_typename)) { DS.getTypeSpecScope() = SS; ConsumeToken(); // The C++ scope. - if (Tok.getAnnotationValue()) + if (Tok.getAnnotationValue()) { + ParsedType T = getTypeAnnotation(Tok); isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, - PrevSpec, DiagID, - Tok.getAnnotationValue()); + PrevSpec, DiagID, T); + } else DS.SetTypeSpecError(); DS.SetRangeEnd(Tok.getAnnotationEndLoc()); @@ -993,8 +1036,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, << Next.getIdentifierInfo(); } - TypeTy *TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(), - Next.getLocation(), getCurScope(), &SS); + ParsedType TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(), + Next.getLocation(), + getCurScope(), &SS); // If the referenced identifier is not a type, then this declspec is // erroneous: We already checked about that it has no type specifier, and @@ -1021,10 +1065,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } case tok::annot_typename: { - if (Tok.getAnnotationValue()) + if (Tok.getAnnotationValue()) { + ParsedType T = getTypeAnnotation(Tok); isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, - DiagID, Tok.getAnnotationValue()); - else + DiagID, T); + } else DS.SetTypeSpecError(); if (isInvalid) @@ -1041,7 +1086,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector ProtocolDecl; + llvm::SmallVector ProtocolDecl; llvm::SmallVector ProtocolLocs; ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, LAngleLoc, EndProtoLoc); @@ -1077,12 +1122,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, break; // It has to be available as a typedef too! - TypeTy *TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), getCurScope()); + ParsedType TypeRep = + Actions.getTypeName(*Tok.getIdentifierInfo(), + Tok.getLocation(), getCurScope()); // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. - if (TypeRep == 0) { + if (!TypeRep) { if (ParseImplicitInt(DS, 0, TemplateInfo, AS)) continue; goto DoneWithDeclSpec; } @@ -1110,7 +1156,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector ProtocolDecl; + llvm::SmallVector ProtocolDecl; llvm::SmallVector ProtocolLocs; ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, LAngleLoc, EndProtoLoc); @@ -1172,6 +1218,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.AddAttributes(ParseMicrosoftTypeAttributes()); continue; + // Borland single token adornments. + case tok::kw___pascal: + DS.AddAttributes(ParseBorlandTypeAttributes()); + continue; + // storage-class-specifier case tok::kw_typedef: isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec, @@ -1383,7 +1434,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, { SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector ProtocolDecl; + llvm::SmallVector ProtocolDecl; llvm::SmallVector ProtocolLocs; ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, LAngleLoc, EndProtoLoc); @@ -1403,7 +1454,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (isInvalid) { assert(PrevSpec && "Method did not return previous specifier!"); assert(DiagID); - Diag(Tok, DiagID) << PrevSpec; + + if (DiagID == diag::ext_duplicate_declspec) + Diag(Tok, DiagID) + << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); + else + Diag(Tok, DiagID) << PrevSpec; } DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); @@ -1495,10 +1551,10 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, // simple-type-specifier: case tok::annot_typename: { - if (Tok.getAnnotationValue()) + if (ParsedType T = getTypeAnnotation(Tok)) { isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, - DiagID, Tok.getAnnotationValue()); - else + DiagID, T); + } else DS.SetTypeSpecError(); DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeToken(); // The typename @@ -1511,7 +1567,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, return true; SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector ProtocolDecl; + llvm::SmallVector ProtocolDecl; llvm::SmallVector ProtocolLocs; ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false, LAngleLoc, EndProtoLoc); @@ -1643,6 +1699,7 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID); break; + case tok::kw___ptr64: case tok::kw___w64: case tok::kw___cdecl: @@ -1652,6 +1709,10 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, DS.AddAttributes(ParseMicrosoftTypeAttributes()); return true; + case tok::kw___pascal: + DS.AddAttributes(ParseBorlandTypeAttributes()); + return true; + default: // Not a type-specifier; do nothing. return false; @@ -1728,7 +1789,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { if (Tok.is(tok::colon)) { ConsumeToken(); - OwningExprResult Res(ParseConstantExpression()); + ExprResult Res(ParseConstantExpression()); if (Res.isInvalid()) SkipUntil(tok::semi, true, true); else @@ -1743,7 +1804,7 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { } // We're done with this declarator; invoke the callback. - DeclPtrTy D = Fields.invoke(DeclaratorInfo); + Decl *D = Fields.invoke(DeclaratorInfo); PD.complete(D); // If we don't have a comma, it is either the end of the list (a ';') @@ -1769,10 +1830,9 @@ ParseStructDeclaration(DeclSpec &DS, FieldCallback &Fields) { /// [OBC] '@' 'defs' '(' class-name ')' /// void Parser::ParseStructUnionBody(SourceLocation RecordLoc, - unsigned TagType, DeclPtrTy TagDecl) { - PrettyStackTraceActionsDecl CrashInfo(TagDecl, RecordLoc, Actions, - PP.getSourceManager(), - "parsing struct/union body"); + unsigned TagType, Decl *TagDecl) { + PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc, + "parsing struct/union body"); SourceLocation LBraceLoc = ConsumeBrace(); @@ -1782,10 +1842,10 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, // Empty structs are an extension in C (C99 6.7.2.1p7), but are allowed in // C++. if (Tok.is(tok::r_brace) && !getLang().CPlusPlus) - Diag(Tok, diag::ext_empty_struct_union_enum) - << DeclSpec::getSpecifierName((DeclSpec::TST)TagType); + Diag(Tok, diag::ext_empty_struct_union) + << (TagType == TST_union); - llvm::SmallVector FieldDecls; + llvm::SmallVector FieldDecls; // While we still have something to read, read the declarations in the struct. while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { @@ -1806,16 +1866,16 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, if (!Tok.is(tok::at)) { struct CFieldCallback : FieldCallback { Parser &P; - DeclPtrTy TagDecl; - llvm::SmallVectorImpl &FieldDecls; + Decl *TagDecl; + llvm::SmallVectorImpl &FieldDecls; - CFieldCallback(Parser &P, DeclPtrTy TagDecl, - llvm::SmallVectorImpl &FieldDecls) : + CFieldCallback(Parser &P, Decl *TagDecl, + llvm::SmallVectorImpl &FieldDecls) : P(P), TagDecl(TagDecl), FieldDecls(FieldDecls) {} - virtual DeclPtrTy invoke(FieldDeclarator &FD) { + virtual Decl *invoke(FieldDeclarator &FD) { // Install the declarator into the current TagDecl. - DeclPtrTy Field = P.Actions.ActOnField(P.getCurScope(), TagDecl, + Decl *Field = P.Actions.ActOnField(P.getCurScope(), TagDecl, FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D, FD.BitfieldSize); FieldDecls.push_back(Field); @@ -1838,7 +1898,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, SkipUntil(tok::semi, true); continue; } - llvm::SmallVector Fields; + llvm::SmallVector Fields; Actions.ActOnDefs(getCurScope(), TagDecl, Tok.getLocation(), Tok.getIdentifierInfo(), Fields); FieldDecls.insert(FieldDecls.end(), Fields.begin(), Fields.end()); @@ -1905,7 +1965,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, CXXScopeSpec &SS = DS.getTypeSpecScope(); if (getLang().CPlusPlus) { - if (ParseOptionalCXXScopeSpecifier(SS, 0, false)) + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) return; if (SS.isSet() && Tok.isNot(tok::identifier)) { @@ -1944,18 +2004,18 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // enum foo {..}; void bar() { enum foo; } <- new foo in bar. // enum foo {..}; void bar() { enum foo x; } <- use of old foo. // - Action::TagUseKind TUK; + Sema::TagUseKind TUK; if (Tok.is(tok::l_brace)) - TUK = Action::TUK_Definition; + TUK = Sema::TUK_Definition; else if (Tok.is(tok::semi)) - TUK = Action::TUK_Declaration; + TUK = Sema::TUK_Declaration; else - TUK = Action::TUK_Reference; + TUK = Sema::TUK_Reference; // enums cannot be templates, although they can be referenced from a // template. if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && - TUK != Action::TUK_Reference) { + TUK != Sema::TUK_Reference) { Diag(Tok, diag::err_enum_template); // Skip the rest of this declarator, up until the comma or semicolon. @@ -1968,11 +2028,11 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; const char *PrevSpec = 0; unsigned DiagID; - DeclPtrTy TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, - StartLoc, SS, Name, NameLoc, Attr.get(), - AS, - Action::MultiTemplateParamsArg(Actions), - Owned, IsDependent); + Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, + StartLoc, SS, Name, NameLoc, Attr.get(), + AS, + MultiTemplateParamsArg(Actions), + Owned, IsDependent); if (IsDependent) { // This enum has a dependent nested-name-specifier. Handle it as a // dependent tag. @@ -1991,13 +2051,13 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, } if (DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, PrevSpec, DiagID, - Type.get(), false)) + Type.get())) Diag(StartLoc, DiagID) << PrevSpec; return; } - if (!TagDecl.get()) { + if (!TagDecl) { // The action failed to produce an enumeration tag. If this is a // definition, consume the entire definition. if (Tok.is(tok::l_brace)) { @@ -2012,10 +2072,10 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (Tok.is(tok::l_brace)) ParseEnumBody(StartLoc, TagDecl); - // FIXME: The DeclSpec should keep the locations of both the keyword and the - // name (if there is one). + // FIXME: The DeclSpec should keep the locations of both the keyword + // and the name (if there is one). if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID, - TagDecl.getAs(), Owned)) + TagDecl, Owned)) Diag(StartLoc, DiagID) << PrevSpec; } @@ -2029,7 +2089,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, /// enumeration-constant: /// identifier /// -void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { +void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { // Enter the scope of the enum body and start the definition. ParseScope EnumScope(this, Scope::DeclScope); Actions.ActOnTagStartDefinition(getCurScope(), EnumDecl); @@ -2040,9 +2100,9 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { if (Tok.is(tok::r_brace) && !getLang().CPlusPlus) Diag(Tok, diag::error_empty_enum); - llvm::SmallVector EnumConstantDecls; + llvm::SmallVector EnumConstantDecls; - DeclPtrTy LastEnumConstDecl; + Decl *LastEnumConstDecl = 0; // Parse the enumerator-list. while (Tok.is(tok::identifier)) { @@ -2050,7 +2110,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { SourceLocation IdentLoc = ConsumeToken(); SourceLocation EqualLoc; - OwningExprResult AssignedVal(Actions); + ExprResult AssignedVal; if (Tok.is(tok::equal)) { EqualLoc = ConsumeToken(); AssignedVal = ParseConstantExpression(); @@ -2059,11 +2119,11 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, DeclPtrTy EnumDecl) { } // Install the enumerator constant into EnumDecl. - DeclPtrTy EnumConstDecl = Actions.ActOnEnumConstant(getCurScope(), EnumDecl, - LastEnumConstDecl, - IdentLoc, Ident, - EqualLoc, - AssignedVal.release()); + Decl *EnumConstDecl = Actions.ActOnEnumConstant(getCurScope(), EnumDecl, + LastEnumConstDecl, + IdentLoc, Ident, + EqualLoc, + AssignedVal.release()); EnumConstantDecls.push_back(EnumConstDecl); LastEnumConstDecl = EnumConstDecl; @@ -2229,6 +2289,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw___thiscall: case tok::kw___w64: case tok::kw___ptr64: + case tok::kw___pascal: return true; } } @@ -2337,6 +2398,7 @@ bool Parser::isDeclarationSpecifier() { case tok::kw___w64: case tok::kw___ptr64: case tok::kw___forceinline: + case tok::kw___pascal: return true; } } @@ -2346,7 +2408,7 @@ bool Parser::isConstructorDeclarator() { // Parse the C++ scope specifier. CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, 0, true)) { + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), true)) { TPA.Revert(); return false; } @@ -2388,15 +2450,19 @@ bool Parser::isConstructorDeclarator() { } /// ParseTypeQualifierListOpt -/// type-qualifier-list: [C99 6.7.5] -/// type-qualifier -/// [GNU] attributes [ only if AttributesAllowed=true ] -/// type-qualifier-list type-qualifier -/// [GNU] type-qualifier-list attributes [ only if AttributesAllowed=true ] -/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq -/// if CXX0XAttributesAllowed = true +/// type-qualifier-list: [C99 6.7.5] +/// type-qualifier +/// [vendor] attributes +/// [ only if VendorAttributesAllowed=true ] +/// type-qualifier-list type-qualifier +/// [vendor] type-qualifier-list attributes +/// [ only if VendorAttributesAllowed=true ] +/// [C++0x] attribute-specifier[opt] is allowed before cv-qualifier-seq +/// [ only if CXX0XAttributesAllowed=true ] +/// Note: vendor can be GNU, MS, etc. /// -void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed, +void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, + bool VendorAttributesAllowed, bool CXX0XAttributesAllowed) { if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { SourceLocation Loc = Tok.getLocation(); @@ -2414,6 +2480,11 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed, SourceLocation Loc = Tok.getLocation(); switch (Tok.getKind()) { + case tok::code_completion: + Actions.CodeCompleteTypeQualifiers(DS); + ConsumeCodeCompletionToken(); + break; + case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID, getLang()); @@ -2432,13 +2503,19 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed, case tok::kw___stdcall: case tok::kw___fastcall: case tok::kw___thiscall: - if (GNUAttributesAllowed) { + if (VendorAttributesAllowed) { DS.AddAttributes(ParseMicrosoftTypeAttributes()); continue; } goto DoneWithTypeQuals; + case tok::kw___pascal: + if (VendorAttributesAllowed) { + DS.AddAttributes(ParseBorlandTypeAttributes()); + continue; + } + goto DoneWithTypeQuals; case tok::kw___attribute: - if (GNUAttributesAllowed) { + if (VendorAttributesAllowed) { DS.AddAttributes(ParseGNUAttributes()); continue; // do *not* consume the next token! } @@ -2494,6 +2571,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, DirectDeclParseFunction DirectDeclParser) { if (Diags.hasAllExtensionsSilenced()) D.setExtension(); + // C++ member pointers start with a '::' or a nested-name. // Member pointers get special handling, since there's no place for the // scope spec in the generic path below. @@ -2501,7 +2579,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope))) { CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); // ignore fail + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), true); // ignore fail if (SS.isNotEmpty()) { if (Tok.isNot(tok::star)) { @@ -2660,8 +2738,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (getLang().CPlusPlus && D.mayHaveIdentifier()) { // ParseDeclaratorInternal might already have parsed the scope. if (D.getCXXScopeSpec().isEmpty()) { - ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, - true); + ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), ParsedType(), true); } if (D.getCXXScopeSpec().isValid()) { @@ -2690,7 +2767,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { /*EnteringContext=*/true, /*AllowDestructorName=*/true, AllowConstructorName, - /*ObjectType=*/0, + ParsedType(), D.getName()) || // Once we're past the identifier, if the scope was bad, mark the // whole declarator bad. @@ -2724,7 +2801,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // scope when parsing the parenthesized declarator, then exited // the scope already. Re-enter the scope, if we need to. if (D.getCXXScopeSpec().isSet()) { - if (Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) + // If there was an error parsing parenthesized declarator, declarator + // scope may have been enterred before. Don't do it again. + if (!D.isInvalidType() && + Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) // Change the declaration context for name lookup, until this function // is exited (and the declarator has been parsed). DeclScopeObj.EnterDeclaratorScope(); @@ -2820,6 +2900,10 @@ void Parser::ParseParenDeclarator(Declarator &D) { Tok.is(tok::kw___w64) || Tok.is(tok::kw___ptr64)) { AttrList.reset(ParseMicrosoftTypeAttributes(AttrList.take())); } + // Eat any Borland extensions. + if (Tok.is(tok::kw___pascal)) { + AttrList.reset(ParseBorlandTypeAttributes(AttrList.take())); + } // If we haven't past the identifier yet (or where the identifier would be // stored, if this is an abstract declarator), then this is probably just @@ -2922,7 +3006,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, bool hasExceptionSpec = false; SourceLocation ThrowLoc; bool hasAnyExceptionSpec = false; - llvm::SmallVector Exceptions; + llvm::SmallVector Exceptions; llvm::SmallVector ExceptionRanges; if (getLang().CPlusPlus) { ParseTypeQualifierListOpt(DS, false /*no attributes*/); @@ -3061,7 +3145,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Inform the actions module about the parameter declarator, so it gets // added to the current scope. - DeclPtrTy Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl); + Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl); // Parse the default argument, if any. We parse the default // arguments in all dialects; the semantic analysis in @@ -3085,21 +3169,29 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, delete DefArgToks; DefArgToks = 0; Actions.ActOnParamDefaultArgumentError(Param); - } else + } else { + // Mark the end of the default argument so that we know when to + // stop when we parse it later on. + Token DefArgEnd; + DefArgEnd.startToken(); + DefArgEnd.setKind(tok::cxx_defaultarg_end); + DefArgEnd.setLocation(Tok.getLocation()); + DefArgToks->push_back(DefArgEnd); Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc, (*DefArgToks)[1].getLocation()); + } } else { // Consume the '='. ConsumeToken(); - OwningExprResult DefArgResult(ParseAssignmentExpression()); + ExprResult DefArgResult(ParseAssignmentExpression()); if (DefArgResult.isInvalid()) { Actions.ActOnParamDefaultArgumentError(Param); SkipUntil(tok::comma, tok::r_paren, true, true); } else { // Inform the actions module about the default argument Actions.ActOnParamDefaultArgument(Param, EqualLoc, - move(DefArgResult)); + DefArgResult.take()); } } } @@ -3141,7 +3233,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, bool hasExceptionSpec = false; SourceLocation ThrowLoc; bool hasAnyExceptionSpec = false; - llvm::SmallVector Exceptions; + llvm::SmallVector Exceptions; llvm::SmallVector ExceptionRanges; if (getLang().CPlusPlus) { @@ -3202,8 +3294,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, // The first identifier was already read, and is known to be the first // identifier in the list. Remember this identifier in ParamInfo. ParamsSoFar.insert(FirstIdent); - ParamInfo.push_back(DeclaratorChunk::ParamInfo(FirstIdent, FirstIdentLoc, - DeclPtrTy())); + ParamInfo.push_back(DeclaratorChunk::ParamInfo(FirstIdent, FirstIdentLoc, 0)); while (Tok.is(tok::comma)) { // Eat the comma. @@ -3229,7 +3320,7 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, // Remember this identifier in ParamInfo. ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, Tok.getLocation(), - DeclPtrTy())); + 0)); } // Eat the identifier. @@ -3271,7 +3362,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { } // Remember that we parsed the empty array type. - OwningExprResult NumElements(Actions); + ExprResult NumElements; D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, StartLoc, EndLoc), EndLoc); @@ -3279,7 +3370,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { } else if (Tok.getKind() == tok::numeric_constant && GetLookAheadToken(1).is(tok::r_square)) { // [4] is very common. Parse the numeric constant expression. - OwningExprResult ExprRes(Actions.ActOnNumericConstant(Tok)); + ExprResult ExprRes(Actions.ActOnNumericConstant(Tok)); ConsumeToken(); SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); @@ -3317,7 +3408,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // Handle "direct-declarator [ type-qual-list[opt] * ]". bool isStar = false; - OwningExprResult NumElements(Actions); + ExprResult NumElements; // Handle the case where we have '[*]' as the array size. However, a leading // star could be the start of an expression, for example 'X[*p + 4]'. Verify @@ -3382,12 +3473,12 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { const bool hasParens = Tok.is(tok::l_paren); bool isCastExpr; - TypeTy *CastTy; + ParsedType CastTy; SourceRange CastRange; - OwningExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok, - isCastExpr, - CastTy, - CastRange); + ExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok, + isCastExpr, + CastTy, + CastRange); if (hasParens) DS.setTypeofParensRange(CastRange); @@ -3422,7 +3513,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { unsigned DiagID; // Check for duplicate type specifiers (e.g. "int typeof(int)"). if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec, - DiagID, Operand.release())) + DiagID, Operand.get())) Diag(StartLoc, DiagID) << PrevSpec; } diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 590ba6c..b277156 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -14,37 +14,42 @@ #include "clang/Basic/OperatorKinds.h" #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" -#include "clang/Parse/Template.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/PrettyDeclStackTrace.h" #include "RAIIObjectsForParser.h" using namespace clang; /// ParseNamespace - We know that the current token is a namespace keyword. This -/// may either be a top level namespace or a block-level namespace alias. +/// may either be a top level namespace or a block-level namespace alias. If +/// there was an inline keyword, it has already been parsed. /// /// namespace-definition: [C++ 7.3: basic.namespace] /// named-namespace-definition /// unnamed-namespace-definition /// /// unnamed-namespace-definition: -/// 'namespace' attributes[opt] '{' namespace-body '}' +/// 'inline'[opt] 'namespace' attributes[opt] '{' namespace-body '}' /// /// named-namespace-definition: /// original-namespace-definition /// extension-namespace-definition /// /// original-namespace-definition: -/// 'namespace' identifier attributes[opt] '{' namespace-body '}' +/// 'inline'[opt] 'namespace' identifier attributes[opt] +/// '{' namespace-body '}' /// /// extension-namespace-definition: -/// 'namespace' original-namespace-name '{' namespace-body '}' +/// 'inline'[opt] 'namespace' original-namespace-name +/// '{' namespace-body '}' /// /// namespace-alias-definition: [C++ 7.3.2: namespace.alias] /// 'namespace' identifier '=' qualified-namespace-specifier ';' /// -Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, - SourceLocation &DeclEnd) { +Decl *Parser::ParseNamespace(unsigned Context, + SourceLocation &DeclEnd, + SourceLocation InlineLoc) { assert(Tok.is(tok::kw_namespace) && "Not a namespace!"); SourceLocation NamespaceLoc = ConsumeToken(); // eat the 'namespace'. @@ -75,6 +80,9 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, if (Tok.is(tok::equal)) { if (AttrList) Diag(attrTok, diag::err_unexpected_namespace_attributes_alias); + if (InlineLoc.isValid()) + Diag(InlineLoc, diag::err_inline_namespace_alias) + << FixItHint::CreateRemoval(InlineLoc); return ParseNamespaceAlias(NamespaceLoc, IdentLoc, Ident, DeclEnd); } @@ -82,7 +90,7 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, if (Tok.isNot(tok::l_brace)) { Diag(Tok, Ident ? diag::err_expected_lbrace : diag::err_expected_ident_lbrace); - return DeclPtrTy(); + return 0; } SourceLocation LBrace = ConsumeBrace(); @@ -92,19 +100,22 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, getCurScope()->getFnParent()) { Diag(LBrace, diag::err_namespace_nonnamespace_scope); SkipUntil(tok::r_brace, false); - return DeclPtrTy(); + return 0; } + // If we're still good, complain about inline namespaces in non-C++0x now. + if (!getLang().CPlusPlus0x && InlineLoc.isValid()) + Diag(InlineLoc, diag::ext_inline_namespace); + // Enter a scope for the namespace. ParseScope NamespaceScope(this, Scope::DeclScope); - DeclPtrTy NamespcDecl = - Actions.ActOnStartNamespaceDef(getCurScope(), IdentLoc, Ident, LBrace, - AttrList.get()); + Decl *NamespcDecl = + Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, IdentLoc, Ident, + LBrace, AttrList.get()); - PrettyStackTraceActionsDecl CrashInfo(NamespcDecl, NamespaceLoc, Actions, - PP.getSourceManager(), - "parsing namespace"); + PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc, + "parsing namespace"); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { CXX0XAttributeList Attr; @@ -126,7 +137,7 @@ Parser::DeclPtrTy Parser::ParseNamespace(unsigned Context, /// ParseNamespaceAlias - Parse the part after the '=' in a namespace /// alias definition. /// -Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, +Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, SourceLocation &DeclEnd) { @@ -141,13 +152,13 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, CXXScopeSpec SS; // Parse (optional) nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); if (SS.isInvalid() || Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_namespace_name); // Skip to end of the definition and eat the ';'. SkipUntil(tok::semi); - return DeclPtrTy(); + return 0; } // Parse identifier. @@ -170,7 +181,7 @@ Parser::DeclPtrTy Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, /// 'extern' string-literal '{' declaration-seq[opt] '}' /// 'extern' string-literal declaration /// -Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS, +Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { assert(Tok.is(tok::string_literal) && "Not a string literal!"); llvm::SmallString<8> LangBuffer; @@ -178,12 +189,12 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS, bool Invalid = false; llvm::StringRef Lang = PP.getSpelling(Tok, LangBuffer, &Invalid); if (Invalid) - return DeclPtrTy(); + return 0; SourceLocation Loc = ConsumeStringToken(); ParseScope LinkageScope(this, Scope::DeclScope); - DeclPtrTy LinkageSpec + Decl *LinkageSpec = Actions.ActOnStartLinkageSpecification(getCurScope(), /*FIXME: */SourceLocation(), Loc, Lang, @@ -196,7 +207,8 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS, } if (Tok.isNot(tok::l_brace)) { - ParseDeclarationOrFunctionDefinition(DS, Attr.AttrList); + DS.setExternInLinkageSpec(true); + ParseExternalDeclaration(Attr, &DS); return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec, SourceLocation()); } @@ -221,7 +233,7 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS, /// ParseUsingDirectiveOrDeclaration - Parse C++ using using-declaration or /// using-directive. Assumes that current token is 'using'. -Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, +Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, SourceLocation &DeclEnd, CXX0XAttributeList Attr) { assert(Tok.is(tok::kw_using) && "Not using token"); @@ -257,7 +269,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, /// 'using' 'namespace' ::[opt] nested-name-specifier[opt] /// namespace-name attributes[opt] ; /// -Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, +Decl *Parser::ParseUsingDirective(unsigned Context, SourceLocation UsingLoc, SourceLocation &DeclEnd, AttributeList *Attr) { @@ -273,7 +285,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, CXXScopeSpec SS; // Parse (optional) nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); IdentifierInfo *NamespcName = 0; SourceLocation IdentLoc = SourceLocation(); @@ -284,7 +296,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, // If there was invalid namespace name, skip to end of decl, and eat ';'. SkipUntil(tok::semi); // FIXME: Are there cases, when we would like to call ActOnUsingDirective? - return DeclPtrTy(); + return 0; } // Parse identifier. @@ -316,7 +328,7 @@ Parser::DeclPtrTy Parser::ParseUsingDirective(unsigned Context, /// unqualified-id /// 'using' :: unqualified-id /// -Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, +Decl *Parser::ParseUsingDeclaration(unsigned Context, SourceLocation UsingLoc, SourceLocation &DeclEnd, AccessSpecifier AS) { @@ -335,12 +347,12 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, IsTypeName = false; // Parse nested-name-specifier. - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); // Check nested-name specifier. if (SS.isInvalid()) { SkipUntil(tok::semi); - return DeclPtrTy(); + return 0; } // Parse the unqualified-id. We allow parsing of both constructor and @@ -351,10 +363,10 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, /*EnteringContext=*/false, /*AllowDestructorName=*/true, /*AllowConstructorName=*/true, - /*ObjectType=*/0, + ParsedType(), Name)) { SkipUntil(tok::semi); - return DeclPtrTy(); + return 0; } // Parse (optional) attributes (most likely GNU strong-using extension). @@ -377,43 +389,44 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, /// static_assert-declaration: /// static_assert ( constant-expression , string-literal ) ; /// -Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ +Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ assert(Tok.is(tok::kw_static_assert) && "Not a static_assert declaration"); SourceLocation StaticAssertLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen); - return DeclPtrTy(); + return 0; } SourceLocation LParenLoc = ConsumeParen(); - OwningExprResult AssertExpr(ParseConstantExpression()); + ExprResult AssertExpr(ParseConstantExpression()); if (AssertExpr.isInvalid()) { SkipUntil(tok::semi); - return DeclPtrTy(); + return 0; } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::semi)) - return DeclPtrTy(); + return 0; if (Tok.isNot(tok::string_literal)) { Diag(Tok, diag::err_expected_string_literal); SkipUntil(tok::semi); - return DeclPtrTy(); + return 0; } - OwningExprResult AssertMessage(ParseStringLiteralExpression()); + ExprResult AssertMessage(ParseStringLiteralExpression()); if (AssertMessage.isInvalid()) - return DeclPtrTy(); + return 0; MatchRHSPunctuation(tok::r_paren, LParenLoc); DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, diag::err_expected_semi_after_static_assert); - return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, move(AssertExpr), - move(AssertMessage)); + return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, + AssertExpr.take(), + AssertMessage.take()); } /// ParseDecltypeSpecifier - Parse a C++0x decltype specifier. @@ -437,8 +450,8 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { // C++0x [dcl.type.simple]p4: // The operand of the decltype specifier is an unevaluated operand. EnterExpressionEvaluationContext Unevaluated(Actions, - Action::Unevaluated); - OwningExprResult Result = ParseExpression(); + Sema::Unevaluated); + ExprResult Result = ParseExpression(); if (Result.isInvalid()) { SkipUntil(tok::r_paren); return; @@ -483,7 +496,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, AnnotateTemplateIdTokenAsType(SS); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); - TypeTy *Type = Tok.getAnnotationValue(); + ParsedType Type = getTypeAnnotation(Tok); EndLocation = Tok.getAnnotationEndLoc(); ConsumeToken(); @@ -536,13 +549,13 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, // Retrieve the type from the annotation token, consume that token, and // return. EndLocation = Tok.getAnnotationEndLoc(); - TypeTy *Type = Tok.getAnnotationValue(); + ParsedType Type = getTypeAnnotation(Tok); ConsumeToken(); return Type; } // We have an identifier; check whether it is actually a type. - TypeTy *Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), SS, true); + ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), SS, true); if (!Type) { Diag(IdLoc, diag::err_expected_class_name); return true; @@ -550,7 +563,19 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, // Consume the identifier. EndLocation = IdLoc; - return Type; + + // Fake up a Declarator to use with ActOnTypeName. + DeclSpec DS; + DS.SetRangeStart(IdLoc); + DS.SetRangeEnd(EndLocation); + DS.getTypeSpecScope() = *SS; + + const char *PrevSpec = 0; + unsigned DiagID; + DS.SetTypeSpecType(TST_typename, IdLoc, PrevSpec, DiagID, Type); + + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } /// ParseClassSpecifier - Parse a C++ class-specifier [C++ class] or @@ -633,7 +658,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, AttrList = ParseGNUAttributes(); // If declspecs exist after tag, parse them. - if (Tok.is(tok::kw___declspec)) + while (Tok.is(tok::kw___declspec)) AttrList = ParseMicrosoftDeclSpec(AttrList); // If C++0x attributes exist here, parse them. @@ -648,7 +673,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // token sequence "struct __is_pod", make __is_pod into a normal // identifier rather than a keyword, to allow libstdc++ 4.2 to work // properly. - Tok.getIdentifierInfo()->setTokenID(tok::identifier); + Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); Tok.setKind(tok::identifier); } @@ -658,7 +683,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // token sequence "struct __is_empty", make __is_empty into a normal // identifier rather than a keyword, to allow libstdc++ 4.2 to work // properly. - Tok.getIdentifierInfo()->setTokenID(tok::identifier); + Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); Tok.setKind(tok::identifier); } @@ -668,7 +693,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // "FOO : BAR" is not a potential typo for "FOO::BAR". ColonProtectionRAIIObject X(*this); - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), true)) + DS.SetTypeSpecError(); if (SS.isSet()) if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) Diag(Tok, diag::err_expected_ident); @@ -769,9 +795,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // or // &T::operator struct s; // For these, SuppressDeclarations is true. - Action::TagUseKind TUK; + Sema::TagUseKind TUK; if (SuppressDeclarations) - TUK = Action::TUK_Reference; + TUK = Sema::TUK_Reference; else if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))){ if (DS.isFriendSpecified()) { // C++ [class.friend]p2: @@ -782,20 +808,23 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Skip everything up to the semicolon, so that this looks like a proper // friend class (or template thereof) declaration. SkipUntil(tok::semi, true, true); - TUK = Action::TUK_Friend; + TUK = Sema::TUK_Friend; } else { // Okay, this is a class definition. - TUK = Action::TUK_Definition; + TUK = Sema::TUK_Definition; } } else if (Tok.is(tok::semi)) - TUK = DS.isFriendSpecified() ? Action::TUK_Friend : Action::TUK_Declaration; + TUK = DS.isFriendSpecified() ? Sema::TUK_Friend : Sema::TUK_Declaration; else - TUK = Action::TUK_Reference; - - if (!Name && !TemplateId && TUK != Action::TUK_Definition) { - // We have a declaration or reference to an anonymous class. - Diag(StartLoc, diag::err_anon_type_definition) - << DeclSpec::getSpecifierName(TagType); + TUK = Sema::TUK_Reference; + + if (!Name && !TemplateId && (DS.getTypeSpecType() == DeclSpec::TST_error || + TUK != Sema::TUK_Definition)) { + if (DS.getTypeSpecType() != DeclSpec::TST_error) { + // We have a declaration or reference to an anonymous class. + Diag(StartLoc, diag::err_anon_type_definition) + << DeclSpec::getSpecifierName(TagType); + } SkipUntil(tok::comma, true); @@ -805,8 +834,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } // Create the tag portion of the class or class template. - Action::DeclResult TagOrTempResult = true; // invalid - Action::TypeResult TypeResult = true; // invalid + DeclResult TagOrTempResult = true; // invalid + TypeResult TypeResult = true; // invalid bool Owned = false; if (TemplateId) { @@ -816,7 +845,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId->getTemplateArgs(), TemplateId->NumArgs); if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && - TUK == Action::TUK_Declaration) { + TUK == Sema::TUK_Declaration) { // This is an explicit instantiation of a class template. TagOrTempResult = Actions.ActOnExplicitInstantiation(getCurScope(), @@ -825,7 +854,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TagType, StartLoc, SS, - TemplateTy::make(TemplateId->Template), + TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, @@ -836,11 +865,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // they have template headers, in which case they're ill-formed // (FIXME: "template friend class A::B;"). // We diagnose this error in ActOnClassTemplateSpecialization. - } else if (TUK == Action::TUK_Reference || - (TUK == Action::TUK_Friend && + } else if (TUK == Sema::TUK_Reference || + (TUK == Sema::TUK_Friend && TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { TypeResult - = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + = Actions.ActOnTemplateIdType(TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, @@ -862,7 +891,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // but it actually has a definition. Most likely, this was // meant to be an explicit specialization, but the user forgot // the '<>' after 'template'. - assert(TUK == Action::TUK_Definition && "Expected a definition here"); + assert(TUK == Sema::TUK_Definition && "Expected a definition here"); SourceLocation LAngleLoc = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); @@ -887,19 +916,19 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TagOrTempResult = Actions.ActOnClassTemplateSpecialization(getCurScope(), TagType, TUK, StartLoc, SS, - TemplateTy::make(TemplateId->Template), + TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc, AttrList, - Action::MultiTemplateParamsArg(Actions, + MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); } TemplateId->Destroy(); } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && - TUK == Action::TUK_Declaration) { + TUK == Sema::TUK_Declaration) { // Explicit instantiation of a member of a class template // specialization, e.g., // @@ -913,7 +942,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, NameLoc, AttrList); } else { if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && - TUK == Action::TUK_Definition) { + TUK == Sema::TUK_Definition) { // FIXME: Diagnose this particular error. } @@ -922,7 +951,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Declaration or definition of a class type TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc, SS, Name, NameLoc, AttrList, AS, - Action::MultiTemplateParamsArg(Actions, + MultiTemplateParamsArg(Actions, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0), Owned, IsDependent); @@ -935,7 +964,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } // If there is a body, parse it and inform the actions module. - if (TUK == Action::TUK_Definition) { + if (TUK == Sema::TUK_Definition) { assert(Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon))); if (getLang().CPlusPlus) @@ -944,27 +973,25 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get()); } - void *Result; + // FIXME: The DeclSpec should keep the locations of both the keyword and the + // name (if there is one). + SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; + + const char *PrevSpec = 0; + unsigned DiagID; + bool Result; if (!TypeResult.isInvalid()) { - TagType = DeclSpec::TST_typename; - Result = TypeResult.get(); - Owned = false; + Result = DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, + PrevSpec, DiagID, TypeResult.get()); } else if (!TagOrTempResult.isInvalid()) { - Result = TagOrTempResult.get().getAs(); + Result = DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID, + TagOrTempResult.get(), Owned); } else { DS.SetTypeSpecError(); return; } - const char *PrevSpec = 0; - unsigned DiagID; - - // FIXME: The DeclSpec should keep the locations of both the keyword and the - // name (if there is one). - SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; - - if (DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID, - Result, Owned)) + if (Result) Diag(StartLoc, DiagID) << PrevSpec; // At this point, we've successfully parsed a class-specifier in 'definition' @@ -974,7 +1001,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // the end of the declaration and recover that way. // // This switch enumerates the valid "follow" set for definition. - if (TUK == Action::TUK_Definition) { + if (TUK == Sema::TUK_Definition) { bool ExpectedSemi = true; switch (Tok.getKind()) { default: break; @@ -1048,12 +1075,12 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, /// base-specifier-list: /// base-specifier '...'[opt] /// base-specifier-list ',' base-specifier '...'[opt] -void Parser::ParseBaseClause(DeclPtrTy ClassDecl) { +void Parser::ParseBaseClause(Decl *ClassDecl) { assert(Tok.is(tok::colon) && "Not a base clause"); ConsumeToken(); // Build up an array of parsed base specifiers. - llvm::SmallVector BaseInfo; + llvm::SmallVector BaseInfo; while (true) { // Parse a base-specifier. @@ -1090,7 +1117,7 @@ void Parser::ParseBaseClause(DeclPtrTy ClassDecl) { /// class-name /// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt] /// class-name -Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) { +Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { bool IsVirtual = false; SourceLocation StartLoc = Tok.getLocation(); @@ -1120,8 +1147,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) { // Parse optional '::' and optional nested-name-specifier. CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, - /*EnteringContext=*/false); + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); // The location of the base class itself. SourceLocation BaseLoc = Tok.getLocation(); @@ -1158,7 +1184,7 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const { } void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, - DeclPtrTy ThisDecl) { + Decl *ThisDecl) { // We just declared a member function. If this member function // has any default arguments, we'll need to parse them later. LateParsedMethodDeclaration *LateMethod = 0; @@ -1218,7 +1244,8 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, /// '=' constant-expression /// void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, - const ParsedTemplateInfo &TemplateInfo) { + const ParsedTemplateInfo &TemplateInfo, + ParsingDeclRAIIObject *TemplateDiags) { // Access declarations. if (!TemplateInfo.Kind && (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) && @@ -1233,11 +1260,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (isAccessDecl) { // Collect the scope specifier token we annotated earlier. CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType*/ 0, false); + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); // Try to parse an unqualified-id. UnqualifiedId Name; - if (ParseUnqualifiedId(SS, false, true, true, /*ObjectType*/ 0, Name)) { + if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), Name)) { SkipUntil(tok::semi); return; } @@ -1281,7 +1308,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); - return ParseCXXClassMemberDeclaration(AS, TemplateInfo); + return ParseCXXClassMemberDeclaration(AS, TemplateInfo, TemplateDiags); } // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it @@ -1317,17 +1344,19 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SourceLocation DSStart = Tok.getLocation(); // decl-specifier-seq: // Parse the common declaration-specifiers piece. - ParsingDeclSpec DS(*this); + ParsingDeclSpec DS(*this, TemplateDiags); DS.AddAttributes(AttrList.AttrList); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class); - Action::MultiTemplateParamsArg TemplateParams(Actions, + MultiTemplateParamsArg TemplateParams(Actions, TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); if (Tok.is(tok::semi)) { ConsumeToken(); - Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); + Decl *TheDecl = + Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); + DS.complete(TheDecl); return; } @@ -1385,9 +1414,9 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // member-declarator // member-declarator-list ',' member-declarator - llvm::SmallVector DeclsInGroup; - OwningExprResult BitfieldSize(Actions); - OwningExprResult Init(Actions); + llvm::SmallVector DeclsInGroup; + ExprResult BitfieldSize; + ExprResult Init; bool Deleted = false; while (1) { @@ -1426,7 +1455,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { SourceLocation Loc; - OwningExprResult AsmLabel(ParseSimpleAsm(&Loc)); + ExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) SkipUntil(tok::comma, true, true); @@ -1445,7 +1474,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // this call will *not* return the created decl; It will return null. // See Sema::ActOnCXXMemberDeclarator for details. - DeclPtrTy ThisDecl; + Decl *ThisDecl = 0; if (DS.isFriendSpecified()) { // TODO: handle initializers, bitfields, 'delete' ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, @@ -1515,14 +1544,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, /// access-specifier ':' member-specification[opt] /// void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, - unsigned TagType, DeclPtrTy TagDecl) { + unsigned TagType, Decl *TagDecl) { assert((TagType == DeclSpec::TST_struct || TagType == DeclSpec::TST_union || TagType == DeclSpec::TST_class) && "Invalid TagType!"); - PrettyStackTraceActionsDecl CrashInfo(TagDecl, RecordLoc, Actions, - PP.getSourceManager(), - "parsing struct/union/class body"); + PrettyDeclStackTraceEntry CrashInfo(Actions, TagDecl, RecordLoc, + "parsing struct/union/class body"); // Determine whether this is a non-nested class. Note that local // classes are *not* considered to be nested classes. @@ -1681,21 +1709,28 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, /// [C++] mem-initializer-list: /// mem-initializer /// mem-initializer , mem-initializer-list -void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) { +void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'"); SourceLocation ColonLoc = ConsumeToken(); - llvm::SmallVector MemInitializers; + llvm::SmallVector MemInitializers; bool AnyErrors = false; do { - MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); - if (!MemInit.isInvalid()) - MemInitializers.push_back(MemInit.get()); - else - AnyErrors = true; - + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteConstructorInitializer(ConstructorDecl, + MemInitializers.data(), + MemInitializers.size()); + ConsumeCodeCompletionToken(); + } else { + MemInitResult MemInit = ParseMemInitializer(ConstructorDecl); + if (!MemInit.isInvalid()) + MemInitializers.push_back(MemInit.get()); + else + AnyErrors = true; + } + if (Tok.is(tok::comma)) ConsumeToken(); else if (Tok.is(tok::l_brace)) @@ -1724,11 +1759,11 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) { /// [C++] mem-initializer-id: /// '::'[opt] nested-name-specifier[opt] class-name /// identifier -Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) { +Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { // parse '::'[opt] nested-name-specifier[opt] CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); - TypeTy *TemplateTypeTy = 0; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); + ParsedType TemplateTypeTy; if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = static_cast(Tok.getAnnotationValue()); @@ -1736,7 +1771,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) { TemplateId->Kind == TNK_Dependent_template_name) { AnnotateTemplateIdTokenAsType(&SS); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); - TemplateTypeTy = Tok.getAnnotationValue(); + TemplateTypeTy = getTypeAnnotation(Tok); } } if (!TemplateTypeTy && Tok.isNot(tok::identifier)) { @@ -1785,9 +1820,9 @@ Parser::MemInitResult Parser::ParseMemInitializer(DeclPtrTy ConstructorDecl) { /// type-id-list ',' type-id /// bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, - llvm::SmallVector + llvm::SmallVectorImpl &Exceptions, - llvm::SmallVector + llvm::SmallVectorImpl &Ranges, bool &hasAnyExceptionSpec) { assert(Tok.is(tok::kw_throw) && "expected throw"); @@ -1831,7 +1866,7 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, /// \brief We have just started parsing the definition of a new class, /// so push that class onto our stack of classes that is currently /// being parsed. -void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool NonNestedClass) { +void Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass) { assert((NonNestedClass || !ClassStack.empty()) && "Nested class without outer class"); ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass)); @@ -1997,7 +2032,7 @@ CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) { } SourceLocation ParamLoc = ConsumeParen(); - OwningExprResult ArgExpr = ParseCXX0XAlignArgument(ParamLoc); + ExprResult ArgExpr = ParseCXX0XAlignArgument(ParamLoc); MatchRHSPunctuation(tok::r_paren, ParamLoc); @@ -2042,15 +2077,14 @@ CXX0XAttributeList Parser::ParseCXX0XAttributes(SourceLocation *EndLoc) { /// /// [C++0x] 'align' '(' type-id ')' /// [C++0x] 'align' '(' assignment-expression ')' -Parser::OwningExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) { +ExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) { if (isTypeIdInParens()) { - EnterExpressionEvaluationContext Unevaluated(Actions, - Action::Unevaluated); + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); SourceLocation TypeLoc = Tok.getLocation(); - TypeTy *Ty = ParseTypeName().get(); + ParsedType Ty = ParseTypeName().get(); SourceRange TypeRange(Start, Tok.getLocation()); - return Actions.ActOnSizeOfAlignOfExpr(TypeLoc, false, true, Ty, - TypeRange); + return Actions.ActOnSizeOfAlignOfExpr(TypeLoc, false, true, + Ty.getAsOpaquePtr(), TypeRange); } else return ParseConstantExpression(); } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index e7973f7..c4beab1 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -20,9 +20,9 @@ //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" -#include "clang/Parse/Template.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ParsedTemplate.h" #include "clang/Basic/PrettyStackTrace.h" #include "RAIIObjectsForParser.h" #include "llvm/ADT/SmallVector.h" @@ -30,8 +30,7 @@ using namespace clang; /// getBinOpPrecedence - Return the precedence of the specified binary operator -/// token. This returns: -/// +/// token. static prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator, bool CPlusPlus0x) { @@ -176,8 +175,8 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, /// assignment-expression /// expression ',' assignment-expression /// -Parser::OwningExprResult Parser::ParseExpression() { - OwningExprResult LHS(ParseAssignmentExpression()); +ExprResult Parser::ParseExpression() { + ExprResult LHS(ParseAssignmentExpression()); if (LHS.isInvalid()) return move(LHS); return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); @@ -188,9 +187,9 @@ Parser::OwningExprResult Parser::ParseExpression() { /// routine is necessary to disambiguate @try-statement from, /// for example, @encode-expression. /// -Parser::OwningExprResult +ExprResult Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { - OwningExprResult LHS(ParseObjCAtExpression(AtLoc)); + ExprResult LHS(ParseObjCAtExpression(AtLoc)); if (LHS.isInvalid()) return move(LHS); return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); @@ -199,9 +198,9 @@ Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { /// This routine is called when a leading '__extension__' is seen and /// consumed. This is necessary because the token gets consumed in the /// process of disambiguating between an expression and a declaration. -Parser::OwningExprResult +ExprResult Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { - OwningExprResult LHS(Actions, true); + ExprResult LHS(true); { // Silence extension warnings in the sub-expression ExtensionRAIIObject O(Diags); @@ -211,27 +210,27 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { } LHS = Actions.ActOnUnaryOp(getCurScope(), ExtLoc, tok::kw___extension__, - move(LHS)); + LHS.take()); if (LHS.isInvalid()) return move(LHS); - return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); + return ParseRHSOfBinaryExpression(LHS.take(), prec::Comma); } /// ParseAssignmentExpression - Parse an expr that doesn't include commas. /// -Parser::OwningExprResult Parser::ParseAssignmentExpression() { +ExprResult Parser::ParseAssignmentExpression() { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(getCurScope(), Action::CCC_Expression); + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); ConsumeCodeCompletionToken(); } if (Tok.is(tok::kw_throw)) return ParseThrowExpression(); - OwningExprResult LHS(ParseCastExpression(false)); + ExprResult LHS(ParseCastExpression(false)); if (LHS.isInvalid()) return move(LHS); - return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment); + return ParseRHSOfBinaryExpression(LHS.take(), prec::Assignment); } /// ParseAssignmentExprWithObjCMessageExprStart - Parse an assignment expression @@ -242,38 +241,38 @@ Parser::OwningExprResult Parser::ParseAssignmentExpression() { /// /// Since this handles full assignment-expression's, it handles postfix /// expressions and other binary operators for these expressions as well. -Parser::OwningExprResult +ExprResult Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, SourceLocation SuperLoc, - TypeTy *ReceiverType, - ExprArg ReceiverExpr) { - OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, SuperLoc, - ReceiverType, - move(ReceiverExpr))); + ParsedType ReceiverType, + Expr *ReceiverExpr) { + ExprResult R + = ParseObjCMessageExpressionBody(LBracLoc, SuperLoc, + ReceiverType, ReceiverExpr); if (R.isInvalid()) return move(R); - R = ParsePostfixExpressionSuffix(move(R)); + R = ParsePostfixExpressionSuffix(R.take()); if (R.isInvalid()) return move(R); - return ParseRHSOfBinaryExpression(move(R), prec::Assignment); + return ParseRHSOfBinaryExpression(R.take(), prec::Assignment); } -Parser::OwningExprResult Parser::ParseConstantExpression() { +ExprResult Parser::ParseConstantExpression() { // C++ [basic.def.odr]p2: // An expression is potentially evaluated unless it appears where an // integral constant expression is required (see 5.19) [...]. EnterExpressionEvaluationContext Unevaluated(Actions, - Action::Unevaluated); + Sema::Unevaluated); - OwningExprResult LHS(ParseCastExpression(false)); + ExprResult LHS(ParseCastExpression(false)); if (LHS.isInvalid()) return move(LHS); - return ParseRHSOfBinaryExpression(move(LHS), prec::Conditional); + return ParseRHSOfBinaryExpression(LHS.take(), prec::Conditional); } /// ParseRHSOfBinaryExpression - Parse a binary expression that starts with /// LHS and has a precedence of at least MinPrec. -Parser::OwningExprResult -Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) { +ExprResult +Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLang().CPlusPlus0x); @@ -291,7 +290,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) { ConsumeToken(); // Special case handling for the ternary operator. - OwningExprResult TernaryMiddle(Actions, true); + ExprResult TernaryMiddle(true); if (NextTokPrec == prec::Conditional) { if (Tok.isNot(tok::colon)) { // Don't parse FOO:BAR as if it were a typo for FOO::BAR. @@ -358,7 +357,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) { // Therefore we need some special-casing here. // Also note that the third operand of the conditional operator is // an assignment-expression in C++. - OwningExprResult RHS(Actions); + ExprResult RHS; if (getLang().CPlusPlus && NextTokPrec <= prec::Conditional) RHS = ParseAssignmentExpression(); else @@ -385,7 +384,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) { // is okay, to bind exactly as tightly. For example, compile A=B=C=D as // A=(B=(C=D)), where each paren is a level of recursion here. // The function takes ownership of the RHS. - RHS = ParseRHSOfBinaryExpression(move(RHS), + RHS = ParseRHSOfBinaryExpression(RHS.get(), static_cast(ThisPrec + !isRightAssoc)); if (RHS.isInvalid()) return move(RHS); @@ -408,11 +407,11 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) { Actions.getExprRange(RHS.get()).getEnd())); LHS = Actions.ActOnBinOp(getCurScope(), OpToken.getLocation(), - OpToken.getKind(), move(LHS), move(RHS)); + OpToken.getKind(), LHS.take(), RHS.take()); } else LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc, - move(LHS), move(TernaryMiddle), - move(RHS)); + LHS.take(), TernaryMiddle.take(), + RHS.take()); } } } @@ -422,11 +421,11 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) { /// id-expression that is the operand of address-of gets special treatment /// due to member pointers. /// -Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, +ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, - TypeTy *TypeOfCast) { + ParsedType TypeOfCast) { bool NotCastExpr; - OwningExprResult Res = ParseCastExpression(isUnaryExpression, + ExprResult Res = ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, TypeOfCast); @@ -527,14 +526,14 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// '::'[opt] 'delete' '[' ']' cast-expression /// /// [GNU] unary-type-trait: -/// '__has_nothrow_assign' [TODO] -/// '__has_nothrow_copy' [TODO] -/// '__has_nothrow_constructor' [TODO] +/// '__has_nothrow_assign' +/// '__has_nothrow_copy' +/// '__has_nothrow_constructor' /// '__has_trivial_assign' [TODO] /// '__has_trivial_copy' [TODO] /// '__has_trivial_constructor' /// '__has_trivial_destructor' -/// '__has_virtual_destructor' [TODO] +/// '__has_virtual_destructor' /// '__is_abstract' [TODO] /// '__is_class' /// '__is_empty' [TODO] @@ -546,11 +545,11 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// [GNU] binary-type-trait: /// '__is_base_of' [TODO] /// -Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, +ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, bool &NotCastExpr, - TypeTy *TypeOfCast) { - OwningExprResult Res(Actions); + ParsedType TypeOfCast) { + ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); NotCastExpr = false; @@ -561,16 +560,17 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, // expression, or statement expression. // // If the parsed tokens consist of a primary-expression, the cases below - // call ParsePostfixExpressionSuffix to handle the postfix expression - // suffixes. Cases that cannot be followed by postfix exprs should - // return without invoking ParsePostfixExpressionSuffix. + // break out of the switch; at the end we call ParsePostfixExpressionSuffix + // to handle the postfix expression suffixes. Cases that cannot be followed + // by postfix exprs should return without invoking + // ParsePostfixExpressionSuffix. switch (SavedKind) { case tok::l_paren: { // If this expression is limited to being a unary-expression, the parent can // not start a cast expression. ParenParseOption ParenExprType = - isUnaryExpression ? CompoundLiteral : CastExpr; - TypeTy *CastTy; + (isUnaryExpression && !getLang().CPlusPlus)? CompoundLiteral : CastExpr; + ParsedType CastTy; SourceLocation LParenLoc = Tok.getLocation(); SourceLocation RParenLoc; @@ -597,8 +597,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, return move(Res); } - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(move(Res)); + break; } // primary-expression @@ -608,9 +607,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = Actions.ActOnNumericConstant(Tok); ConsumeToken(); - - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(move(Res)); + break; case tok::kw_true: case tok::kw_false: @@ -661,9 +658,12 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = Actions.ActOnClassPropertyRefExpr(II, PropertyName, ILoc, PropertyLoc); - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(move(Res)); + break; } + + // Make sure to pass down the right value for isAddressOfOperand. + if (isAddressOfOperand && isPostfixExpressionSuffixStart()) + isAddressOfOperand = false; // Function designators are allowed to be undeclared (C99 6.5.1p2), so we // need to know whether or not this identifier is a function designator or @@ -672,29 +672,23 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, CXXScopeSpec ScopeSpec; Name.setIdentifier(&II, ILoc); Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, Name, - Tok.is(tok::l_paren), false); - - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(move(Res)); + Tok.is(tok::l_paren), isAddressOfOperand); + break; } case tok::char_constant: // constant: character-constant Res = Actions.ActOnCharacterConstant(Tok); ConsumeToken(); - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(move(Res)); + break; case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2] case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU] case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind); ConsumeToken(); - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(move(Res)); + break; case tok::string_literal: // primary-expression: string-literal case tok::wide_string_literal: Res = ParseStringLiteralExpression(); - if (Res.isInvalid()) return move(Res); - // This can be followed by postfix-expr pieces (e.g. "foo"[1]). - return ParsePostfixExpressionSuffix(move(Res)); + break; case tok::kw___builtin_va_arg: case tok::kw___builtin_offsetof: case tok::kw___builtin_choose_expr: @@ -703,12 +697,16 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___null: return Actions.ActOnGNUNullExpr(ConsumeToken()); break; - case tok::plusplus: // unary-expression: '++' unary-expression - case tok::minusminus: { // unary-expression: '--' unary-expression + case tok::plusplus: // unary-expression: '++' unary-expression [C99] + case tok::minusminus: { // unary-expression: '--' unary-expression [C99] + // C++ [expr.unary] has: + // unary-expression: + // ++ cast-expression + // -- cast-expression SourceLocation SavedLoc = ConsumeToken(); - Res = ParseCastExpression(true); + Res = ParseCastExpression(!getLang().CPlusPlus); if (!Res.isInvalid()) - Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, move(Res)); + Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return move(Res); } case tok::amp: { // unary-expression: '&' cast-expression @@ -716,7 +714,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(false, true); if (!Res.isInvalid()) - Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, move(Res)); + Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return move(Res); } @@ -730,7 +728,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(false); if (!Res.isInvalid()) - Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, move(Res)); + Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return move(Res); } @@ -740,7 +738,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(false); if (!Res.isInvalid()) - Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, move(Res)); + Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return move(Res); } case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression @@ -766,16 +764,13 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_reinterpret_cast: case tok::kw_static_cast: Res = ParseCXXCasts(); - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(move(Res)); + break; case tok::kw_typeid: Res = ParseCXXTypeid(); - // This can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(move(Res)); + break; case tok::kw_this: Res = ParseCXXThis(); - // This can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(move(Res)); + break; case tok::kw_char: case tok::kw_wchar_t: @@ -814,8 +809,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, << DS.getSourceRange()); Res = ParseCXXTypeConstructExpression(DS); - // This can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(move(Res)); + break; } case tok::annot_cxxscope: { // [C++] id-expression: qualified-id @@ -836,7 +830,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, // type, translate it into a type and continue parsing as a // cast expression. CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); AnnotateTemplateIdTokenAsType(&SS); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, TypeOfCast); @@ -845,7 +839,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, // Parse as an id-expression. Res = ParseCXXIdExpression(isAddressOfOperand); - return ParsePostfixExpressionSuffix(move(Res)); + break; } case tok::annot_template_id: { // [C++] template-id @@ -865,7 +859,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id Res = ParseCXXIdExpression(isAddressOfOperand); - return ParsePostfixExpressionSuffix(move(Res)); + break; case tok::coloncolon: { // ::foo::bar -> global qualified name etc. If TryAnnotateTypeOrScopeToken @@ -906,6 +900,10 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___has_trivial_copy: case tok::kw___has_trivial_assign: case tok::kw___has_trivial_destructor: + case tok::kw___has_nothrow_assign: + case tok::kw___has_nothrow_copy: + case tok::kw___has_nothrow_constructor: + case tok::kw___has_virtual_destructor: return ParseUnaryTypeTrait(); case tok::at: { @@ -915,7 +913,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::caret: return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression()); case tok::code_completion: - Actions.CodeCompleteOrdinaryName(getCurScope(), Action::CCC_Expression); + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); ConsumeCodeCompletionToken(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, TypeOfCast); @@ -929,8 +927,9 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, return ExprError(); } - // unreachable. - abort(); + // These can be followed by postfix-expr pieces. + if (Res.isInvalid()) return move(Res); + return ParsePostfixExpressionSuffix(Res.get()); } /// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression @@ -951,8 +950,8 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// argument-expression /// argument-expression-list ',' assignment-expression /// -Parser::OwningExprResult -Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { +ExprResult +Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Now that the primary-expression piece of the postfix-expression has been // parsed, see if there are any postfix-expression pieces here. SourceLocation Loc; @@ -972,13 +971,13 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { return move(LHS); Loc = ConsumeBracket(); - OwningExprResult Idx(ParseExpression()); + ExprResult Idx(ParseExpression()); SourceLocation RLoc = Tok.getLocation(); if (!LHS.isInvalid() && !Idx.isInvalid() && Tok.is(tok::r_square)) { - LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), move(LHS), Loc, - move(Idx), RLoc); + LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.take(), Loc, + Idx.take(), RLoc); } else LHS = ExprError(); @@ -1004,7 +1003,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { } if (Tok.isNot(tok::r_paren)) { - if (ParseExpressionList(ArgExprs, CommaLocs, &Action::CodeCompleteCall, + if (ParseExpressionList(ArgExprs, CommaLocs, &Sema::CodeCompleteCall, LHS.get())) { SkipUntil(tok::r_paren); return ExprError(); @@ -1020,7 +1019,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { if (!LHS.isInvalid()) { assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); - LHS = Actions.ActOnCallExpr(getCurScope(), move(LHS), Loc, + LHS = Actions.ActOnCallExpr(getCurScope(), LHS.take(), Loc, move_arg(ArgExprs), CommaLocs.data(), Tok.getLocation()); } @@ -1036,10 +1035,10 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token. CXXScopeSpec SS; - Action::TypeTy *ObjectType = 0; + ParsedType ObjectType; bool MayBePseudoDestructor = false; if (getLang().CPlusPlus && !LHS.isInvalid()) { - LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), move(LHS), + LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), LHS.take(), OpLoc, OpKind, ObjectType, MayBePseudoDestructor); if (LHS.isInvalid()) @@ -1048,7 +1047,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { ParseOptionalCXXScopeSpecifier(SS, ObjectType, false, &MayBePseudoDestructor); if (SS.isNotEmpty()) - ObjectType = 0; + ObjectType = ParsedType(); } if (Tok.is(tok::code_completion)) { @@ -1059,8 +1058,8 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { ConsumeCodeCompletionToken(); } - if (MayBePseudoDestructor) { - LHS = ParseCXXPseudoDestructor(move(LHS), OpLoc, OpKind, SS, + if (MayBePseudoDestructor && !LHS.isInvalid()) { + LHS = ParseCXXPseudoDestructor(LHS.take(), OpLoc, OpKind, SS, ObjectType); break; } @@ -1080,7 +1079,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { return ExprError(); if (!LHS.isInvalid()) - LHS = Actions.ActOnMemberAccessExpr(getCurScope(), move(LHS), OpLoc, + LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.take(), OpLoc, OpKind, SS, Name, ObjCImpDecl, Tok.is(tok::l_paren)); break; @@ -1089,7 +1088,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { case tok::minusminus: // postfix-expression: postfix-expression '--' if (!LHS.isInvalid()) { LHS = Actions.ActOnPostfixUnaryOp(getCurScope(), Tok.getLocation(), - Tok.getKind(), move(LHS)); + Tok.getKind(), LHS.take()); } ConsumeToken(); break; @@ -1114,17 +1113,17 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { /// typeof ( type-name ) /// [GNU/C++] typeof unary-expression /// -Parser::OwningExprResult +ExprResult Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, bool &isCastExpr, - TypeTy *&CastTy, + ParsedType &CastTy, SourceRange &CastRange) { assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) || OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof)) && "Not a typeof/sizeof/alignof expression!"); - OwningExprResult Operand(Actions); + ExprResult Operand; // If the operand doesn't start with an '(', it must be an expression. if (Tok.isNot(tok::l_paren)) { @@ -1141,7 +1140,7 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, // The GNU typeof and alignof extensions also behave as unevaluated // operands. EnterExpressionEvaluationContext Unevaluated(Actions, - Action::Unevaluated); + Sema::Unevaluated); Operand = ParseCastExpression(true/*isUnaryExpression*/); } else { // If it starts with a '(', we know that it is either a parenthesized @@ -1158,10 +1157,9 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, // The GNU typeof and alignof extensions also behave as unevaluated // operands. EnterExpressionEvaluationContext Unevaluated(Actions, - Action::Unevaluated); + Sema::Unevaluated); Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/, - 0/*TypeOfCast*/, - CastTy, RParenLoc); + ParsedType(), CastTy, RParenLoc); CastRange = SourceRange(LParenLoc, RParenLoc); // If ParseParenExpression parsed a '(typename)' sequence only, then this is @@ -1171,10 +1169,14 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, return ExprEmpty(); } - // If this is a parenthesized expression, it is the start of a - // unary-expression, but doesn't include any postfix pieces. Parse these - // now if present. - Operand = ParsePostfixExpressionSuffix(move(Operand)); + if (getLang().CPlusPlus || OpTok.isNot(tok::kw_typeof)) { + // GNU typeof in C requires the expression to be parenthesized. Not so for + // sizeof/alignof or in C++. Therefore, the parenthesized expression is + // the start of a unary-expression, but doesn't include any postfix + // pieces. Parse these now if present. + if (!Operand.isInvalid()) + Operand = ParsePostfixExpressionSuffix(Operand.get()); + } } // If we get here, the operand to the typeof/sizeof/alignof was an expresion. @@ -1190,7 +1192,7 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' -Parser::OwningExprResult Parser::ParseSizeofAlignofExpression() { +ExprResult Parser::ParseSizeofAlignofExpression() { assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof) || Tok.is(tok::kw_alignof)) && "Not a sizeof/alignof expression!"); @@ -1198,9 +1200,9 @@ Parser::OwningExprResult Parser::ParseSizeofAlignofExpression() { ConsumeToken(); bool isCastExpr; - TypeTy *CastTy; + ParsedType CastTy; SourceRange CastRange; - OwningExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok, + ExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok, isCastExpr, CastTy, CastRange); @@ -1208,7 +1210,8 @@ Parser::OwningExprResult Parser::ParseSizeofAlignofExpression() { if (isCastExpr) return Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(), OpTok.is(tok::kw_sizeof), - /*isType=*/true, CastTy, + /*isType=*/true, + CastTy.getAsOpaquePtr(), CastRange); // If we get here, the operand to the sizeof/alignof was an expresion. @@ -1234,8 +1237,8 @@ Parser::OwningExprResult Parser::ParseSizeofAlignofExpression() { /// [GNU] offsetof-member-designator '.' identifier /// [GNU] offsetof-member-designator '[' expression ']' /// -Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { - OwningExprResult Res(Actions); +ExprResult Parser::ParseBuiltinPrimaryExpression() { + ExprResult Res; const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo(); tok::TokenKind T = Tok.getKind(); @@ -1252,7 +1255,7 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { switch (T) { default: assert(0 && "Not a builtin primary expression!"); case tok::kw___builtin_va_arg: { - OwningExprResult Expr(ParseAssignmentExpression()); + ExprResult Expr(ParseAssignmentExpression()); if (Expr.isInvalid()) { SkipUntil(tok::r_paren); return ExprError(); @@ -1270,7 +1273,7 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { if (Ty.isInvalid()) Res = ExprError(); else - Res = Actions.ActOnVAArg(StartLoc, move(Expr), Ty.get(), ConsumeParen()); + Res = Actions.ActOnVAArg(StartLoc, Expr.take(), Ty.get(), ConsumeParen()); break; } case tok::kw___builtin_offsetof: { @@ -1292,9 +1295,9 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { } // Keep track of the various subcomponents we see. - llvm::SmallVector Comps; + llvm::SmallVector Comps; - Comps.push_back(Action::OffsetOfComponent()); + Comps.push_back(Sema::OffsetOfComponent()); Comps.back().isBrackets = false; Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken(); @@ -1303,7 +1306,7 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { while (1) { if (Tok.is(tok::period)) { // offsetof-member-designator: offsetof-member-designator '.' identifier - Comps.push_back(Action::OffsetOfComponent()); + Comps.push_back(Sema::OffsetOfComponent()); Comps.back().isBrackets = false; Comps.back().LocStart = ConsumeToken(); @@ -1317,7 +1320,7 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { } else if (Tok.is(tok::l_square)) { // offsetof-member-designator: offsetof-member-design '[' expression ']' - Comps.push_back(Action::OffsetOfComponent()); + Comps.push_back(Sema::OffsetOfComponent()); Comps.back().isBrackets = true; Comps.back().LocStart = ConsumeBracket(); Res = ParseExpression(); @@ -1346,7 +1349,7 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { break; } case tok::kw___builtin_choose_expr: { - OwningExprResult Cond(ParseAssignmentExpression()); + ExprResult Cond(ParseAssignmentExpression()); if (Cond.isInvalid()) { SkipUntil(tok::r_paren); return move(Cond); @@ -1354,7 +1357,7 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprError(); - OwningExprResult Expr1(ParseAssignmentExpression()); + ExprResult Expr1(ParseAssignmentExpression()); if (Expr1.isInvalid()) { SkipUntil(tok::r_paren); return move(Expr1); @@ -1362,7 +1365,7 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprError(); - OwningExprResult Expr2(ParseAssignmentExpression()); + ExprResult Expr2(ParseAssignmentExpression()); if (Expr2.isInvalid()) { SkipUntil(tok::r_paren); return move(Expr2); @@ -1371,8 +1374,8 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { Diag(Tok, diag::err_expected_rparen); return ExprError(); } - Res = Actions.ActOnChooseExpr(StartLoc, move(Cond), move(Expr1), - move(Expr2), ConsumeParen()); + Res = Actions.ActOnChooseExpr(StartLoc, Cond.take(), Expr1.take(), + Expr2.take(), ConsumeParen()); break; } case tok::kw___builtin_types_compatible_p: @@ -1396,9 +1399,12 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { break; } + if (Res.isInvalid()) + return ExprError(); + // These can be followed by postfix-expr pieces because they are // primary-expressions. - return ParsePostfixExpressionSuffix(move(Res)); + return ParsePostfixExpressionSuffix(Res.take()); } /// ParseParenExpression - This parses the unit that starts with a '(' token, @@ -1415,25 +1421,25 @@ Parser::OwningExprResult Parser::ParseBuiltinPrimaryExpression() { /// cast-expression: [C99 6.5.4] /// '(' type-name ')' cast-expression /// -Parser::OwningExprResult +ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, - TypeTy *TypeOfCast, TypeTy *&CastTy, + ParsedType TypeOfCast, ParsedType &CastTy, SourceLocation &RParenLoc) { assert(Tok.is(tok::l_paren) && "Not a paren expr!"); GreaterThanIsOperatorScope G(GreaterThanIsOperator, true); SourceLocation OpenLoc = ConsumeParen(); - OwningExprResult Result(Actions, true); + ExprResult Result(true); bool isAmbiguousTypeId; - CastTy = 0; + CastTy = ParsedType(); if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { Diag(Tok, diag::ext_gnu_statement_expr); - OwningStmtResult Stmt(ParseCompoundStatement(0, true)); + StmtResult Stmt(ParseCompoundStatement(0, true)); ExprType = CompoundStmt; // If the substmt parsed correctly, build the AST node. if (!Stmt.isInvalid() && Tok.is(tok::r_paren)) - Result = Actions.ActOnStmtExpr(OpenLoc, move(Stmt), Tok.getLocation()); + Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.take(), Tok.getLocation()); } else if (ExprType >= CompoundLiteral && isTypeIdInParens(isAmbiguousTypeId)) { @@ -1473,7 +1479,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // Note that this doesn't parse the subsequent cast-expression, it just // returns the parsed type to the callee. if (stopIfCastExpr) - return OwningExprResult(Actions); + return ExprResult(); // Reject the cast of super idiom in ObjC. if (Tok.is(tok::identifier) && getLang().ObjC1 && @@ -1490,7 +1496,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Result = ParseCastExpression(false, false, CastTy); if (!Result.isInvalid()) Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc, CastTy, RParenLoc, - move(Result)); + Result.take()); return move(Result); } @@ -1510,7 +1516,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Result = ParseExpression(); ExprType = SimpleExpr; if (!Result.isInvalid() && Tok.is(tok::r_paren)) - Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), move(Result)); + Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.take()); } // Match the ')'. @@ -1534,16 +1540,16 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// -Parser::OwningExprResult -Parser::ParseCompoundLiteralExpression(TypeTy *Ty, +ExprResult +Parser::ParseCompoundLiteralExpression(ParsedType Ty, SourceLocation LParenLoc, SourceLocation RParenLoc) { assert(Tok.is(tok::l_brace) && "Not a compound literal!"); if (!getLang().C99) // Compound literals don't exist in C90. Diag(LParenLoc, diag::ext_c99_compound_literal); - OwningExprResult Result = ParseInitializer(); + ExprResult Result = ParseInitializer(); if (!Result.isInvalid() && Ty) - return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, move(Result)); + return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, Result.take()); return move(Result); } @@ -1553,7 +1559,7 @@ Parser::ParseCompoundLiteralExpression(TypeTy *Ty, /// /// primary-expression: [C99 6.5.1] /// string-literal -Parser::OwningExprResult Parser::ParseStringLiteralExpression() { +ExprResult Parser::ParseStringLiteralExpression() { assert(isTokenStringLiteral() && "Not a string literal!"); // String concat. Note that keywords like __func__ and __FUNCTION__ are not @@ -1579,12 +1585,13 @@ Parser::OwningExprResult Parser::ParseStringLiteralExpression() { /// [C++] assignment-expression /// [C++] expression-list , assignment-expression /// -bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs, - void (Action::*Completer)(Scope *S, - void *Data, - ExprTy **Args, +bool Parser::ParseExpressionList(llvm::SmallVectorImpl &Exprs, + llvm::SmallVectorImpl &CommaLocs, + void (Sema::*Completer)(Scope *S, + Expr *Data, + Expr **Args, unsigned NumArgs), - void *Data) { + Expr *Data) { while (1) { if (Tok.is(tok::code_completion)) { if (Completer) @@ -1592,7 +1599,7 @@ bool Parser::ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs, ConsumeCodeCompletionToken(); } - OwningExprResult Expr(ParseAssignmentExpression()); + ExprResult Expr(ParseAssignmentExpression()); if (Expr.isInvalid()) return true; @@ -1642,7 +1649,7 @@ void Parser::ParseBlockId() { /// [clang] block-args: /// [clang] '(' parameter-list ')' /// -Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { +ExprResult Parser::ParseBlockLiteralExpression() { assert(Tok.is(tok::caret) && "block literal starts with ^"); SourceLocation CaretLoc = ConsumeToken(); @@ -1717,7 +1724,7 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { } - OwningExprResult Result(Actions, true); + ExprResult Result(true); if (!Tok.is(tok::l_brace)) { // Saw something like: ^expr Diag(Tok, diag::err_expected_expression); @@ -1725,9 +1732,9 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() { return ExprError(); } - OwningStmtResult Stmt(ParseCompoundStatementBody()); + StmtResult Stmt(ParseCompoundStatementBody()); if (!Stmt.isInvalid()) - Result = Actions.ActOnBlockStmtExpr(CaretLoc, move(Stmt), getCurScope()); + Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.take(), getCurScope()); else Actions.ActOnBlockError(CaretLoc, getCurScope()); return move(Result); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 579d3bd..5041a21 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -13,8 +13,8 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Template.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/ParsedTemplate.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -57,14 +57,14 @@ using namespace clang; /// /// \returns true if there was an error parsing a scope specifier bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, - Action::TypeTy *ObjectType, + ParsedType ObjectType, bool EnteringContext, bool *MayBePseudoDestructor) { assert(getLang().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); if (Tok.is(tok::annot_cxxscope)) { - SS.setScopeRep(Tok.getAnnotationValue()); + SS.setScopeRep(static_cast(Tok.getAnnotationValue())); SS.setRange(Tok.getAnnotationRange()); ConsumeToken(); return false; @@ -104,7 +104,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // // To implement this, we clear out the object type as soon as we've // seen a leading '::' or part of a nested-name-specifier. - ObjectType = 0; + ObjectType = ParsedType(); if (Tok.is(tok::code_completion)) { // Code completion for a nested-name-specifier, where the code @@ -212,13 +212,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, HasScopeSpecifier = true; } - if (TypeToken.getAnnotationValue()) - SS.setScopeRep( - Actions.ActOnCXXNestedNameSpecifier(getCurScope(), SS, - TypeToken.getAnnotationValue(), + if (ParsedType T = getTypeAnnotation(TypeToken)) { + CXXScopeTy *Scope = + Actions.ActOnCXXNestedNameSpecifier(getCurScope(), SS, T, TypeToken.getAnnotationRange(), - CCLoc)); - else + CCLoc); + SS.setScopeRep(Scope); + } else SS.setScopeRep(0); SS.setEndLoc(CCLoc); continue; @@ -294,6 +294,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, TemplateName.setIdentifier(&II, Tok.getLocation()); bool MemberOfUnknownSpecialization; if (TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, TemplateName, ObjectType, EnteringContext, @@ -396,40 +397,27 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, /// the only place where a qualified-id naming a non-static class member may /// appear. /// -Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { +ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // qualified-id: // '::'[opt] nested-name-specifier 'template'[opt] unqualified-id // '::' unqualified-id // CXXScopeSpec SS; - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false); + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); UnqualifiedId Name; if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, /*AllowDestructorName=*/false, /*AllowConstructorName=*/false, - /*ObjectType=*/0, + /*ObjectType=*/ ParsedType(), Name)) return ExprError(); // This is only the direct operand of an & operator if it is not // followed by a postfix-expression suffix. - if (isAddressOfOperand) { - switch (Tok.getKind()) { - case tok::l_square: - case tok::l_paren: - case tok::arrow: - case tok::period: - case tok::plusplus: - case tok::minusminus: - isAddressOfOperand = false; - break; - - default: - break; - } - } + if (isAddressOfOperand && isPostfixExpressionSuffixStart()) + isAddressOfOperand = false; return Actions.ActOnIdExpression(getCurScope(), SS, Name, Tok.is(tok::l_paren), isAddressOfOperand); @@ -445,7 +433,7 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { /// 'reinterpret_cast' '<' type-name '>' '(' expression ')' /// 'const_cast' '<' type-name '>' '(' expression ')' /// -Parser::OwningExprResult Parser::ParseCXXCasts() { +ExprResult Parser::ParseCXXCasts() { tok::TokenKind Kind = Tok.getKind(); const char *CastName = 0; // For error messages @@ -474,7 +462,7 @@ Parser::OwningExprResult Parser::ParseCXXCasts() { if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, CastName)) return ExprError(); - OwningExprResult Result = ParseExpression(); + ExprResult Result = ParseExpression(); // Match the ')'. RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); @@ -483,7 +471,7 @@ Parser::OwningExprResult Parser::ParseCXXCasts() { Result = Actions.ActOnCXXNamedCast(OpLoc, Kind, LAngleBracketLoc, CastTy.get(), RAngleBracketLoc, - LParenLoc, move(Result), RParenLoc); + LParenLoc, Result.take(), RParenLoc); return move(Result); } @@ -494,7 +482,7 @@ Parser::OwningExprResult Parser::ParseCXXCasts() { /// 'typeid' '(' expression ')' /// 'typeid' '(' type-id ')' /// -Parser::OwningExprResult Parser::ParseCXXTypeid() { +ExprResult Parser::ParseCXXTypeid() { assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!"); SourceLocation OpLoc = ConsumeToken(); @@ -506,7 +494,7 @@ Parser::OwningExprResult Parser::ParseCXXTypeid() { "typeid")) return ExprError(); - OwningExprResult Result(Actions); + ExprResult Result; if (isTypeIdInParens()) { TypeResult Ty = ParseTypeName(); @@ -518,7 +506,7 @@ Parser::OwningExprResult Parser::ParseCXXTypeid() { return ExprError(); Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true, - Ty.get(), RParenLoc); + Ty.get().getAsOpaquePtr(), RParenLoc); } else { // C++0x [expr.typeid]p3: // When typeid is applied to an expression other than an lvalue of a @@ -529,7 +517,7 @@ Parser::OwningExprResult Parser::ParseCXXTypeid() { // polymorphic class type until after we've parsed the expression, so // we the expression is potentially potentially evaluated. EnterExpressionEvaluationContext Unevaluated(Actions, - Action::PotentiallyPotentiallyEvaluated); + Sema::PotentiallyPotentiallyEvaluated); Result = ParseExpression(); // Match the ')'. @@ -560,11 +548,11 @@ Parser::OwningExprResult Parser::ParseCXXTypeid() { /// ~type-name /// ::[opt] nested-name-specifier[opt] ~type-name /// -Parser::OwningExprResult +ExprResult Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, - Action::TypeTy *ObjectType) { + ParsedType ObjectType) { // We're parsing either a pseudo-destructor-name or a dependent // member access that has the same form as a // pseudo-destructor-name. We parse both in the same way and let @@ -612,7 +600,8 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, /*TemplateKWLoc*/SourceLocation())) return ExprError(); - return Actions.ActOnPseudoDestructorExpr(getCurScope(), move(Base), OpLoc, OpKind, + return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, + OpLoc, OpKind, SS, FirstTypeName, CCLoc, TildeLoc, SecondTypeName, Tok.is(tok::l_paren)); @@ -623,7 +612,7 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, /// boolean-literal: [C++ 2.13.5] /// 'true' /// 'false' -Parser::OwningExprResult Parser::ParseCXXBoolLiteral() { +ExprResult Parser::ParseCXXBoolLiteral() { tok::TokenKind Kind = Tok.getKind(); return Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind); } @@ -632,7 +621,7 @@ Parser::OwningExprResult Parser::ParseCXXBoolLiteral() { /// /// throw-expression: [C++ 15] /// 'throw' assignment-expression[opt] -Parser::OwningExprResult Parser::ParseThrowExpression() { +ExprResult Parser::ParseThrowExpression() { assert(Tok.is(tok::kw_throw) && "Not throw!"); SourceLocation ThrowLoc = ConsumeToken(); // Eat the throw token. @@ -646,12 +635,12 @@ Parser::OwningExprResult Parser::ParseThrowExpression() { case tok::r_brace: case tok::colon: case tok::comma: - return Actions.ActOnCXXThrow(ThrowLoc, ExprArg(Actions)); + return Actions.ActOnCXXThrow(ThrowLoc, 0); default: - OwningExprResult Expr(ParseAssignmentExpression()); + ExprResult Expr(ParseAssignmentExpression()); if (Expr.isInvalid()) return move(Expr); - return Actions.ActOnCXXThrow(ThrowLoc, move(Expr)); + return Actions.ActOnCXXThrow(ThrowLoc, Expr.take()); } } @@ -660,7 +649,7 @@ Parser::OwningExprResult Parser::ParseThrowExpression() { /// C++ 9.3.2: In the body of a non-static member function, the keyword this is /// a non-lvalue expression whose value is the address of the object for which /// the function is called. -Parser::OwningExprResult Parser::ParseCXXThis() { +ExprResult Parser::ParseCXXThis() { assert(Tok.is(tok::kw_this) && "Not 'this'!"); SourceLocation ThisLoc = ConsumeToken(); return Actions.ActOnCXXThis(ThisLoc); @@ -675,10 +664,10 @@ Parser::OwningExprResult Parser::ParseCXXThis() { /// simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] /// typename-specifier '(' expression-list[opt] ')' [TODO] /// -Parser::OwningExprResult +ExprResult Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); - TypeTy *TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); + ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); assert(Tok.is(tok::l_paren) && "Expected '('!"); SourceLocation LParenLoc = ConsumeParen(); @@ -728,27 +717,27 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { /// converted to a boolean value. /// /// \returns true if there was a parsing, false otherwise. -bool Parser::ParseCXXCondition(OwningExprResult &ExprResult, - DeclPtrTy &DeclResult, +bool Parser::ParseCXXCondition(ExprResult &ExprOut, + Decl *&DeclOut, SourceLocation Loc, bool ConvertToBoolean) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteOrdinaryName(getCurScope(), Action::CCC_Condition); + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Condition); ConsumeCodeCompletionToken(); } if (!isCXXConditionDeclaration()) { // Parse the expression. - ExprResult = ParseExpression(); // expression - DeclResult = DeclPtrTy(); - if (ExprResult.isInvalid()) + ExprOut = ParseExpression(); // expression + DeclOut = 0; + if (ExprOut.isInvalid()) return true; // If required, convert to a boolean value. if (ConvertToBoolean) - ExprResult - = Actions.ActOnBooleanCondition(getCurScope(), Loc, move(ExprResult)); - return ExprResult.isInvalid(); + ExprOut + = Actions.ActOnBooleanCondition(getCurScope(), Loc, ExprOut.get()); + return ExprOut.isInvalid(); } // type-specifier-seq @@ -762,7 +751,7 @@ bool Parser::ParseCXXCondition(OwningExprResult &ExprResult, // simple-asm-expr[opt] if (Tok.is(tok::kw_asm)) { SourceLocation Loc; - OwningExprResult AsmLabel(ParseSimpleAsm(&Loc)); + ExprResult AsmLabel(ParseSimpleAsm(&Loc)); if (AsmLabel.isInvalid()) { SkipUntil(tok::semi); return true; @@ -779,17 +768,17 @@ bool Parser::ParseCXXCondition(OwningExprResult &ExprResult, } // Type-check the declaration itself. - Action::DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(getCurScope(), + DeclResult Dcl = Actions.ActOnCXXConditionDeclaration(getCurScope(), DeclaratorInfo); - DeclResult = Dcl.get(); - ExprResult = ExprError(); + DeclOut = Dcl.get(); + ExprOut = ExprError(); // '=' assignment-expression if (Tok.is(tok::equal)) { SourceLocation EqualLoc = ConsumeToken(); - OwningExprResult AssignExpr(ParseAssignmentExpression()); + ExprResult AssignExpr(ParseAssignmentExpression()); if (!AssignExpr.isInvalid()) - Actions.AddInitializerToDecl(DeclResult, move(AssignExpr)); + Actions.AddInitializerToDecl(DeclOut, AssignExpr.take()); } else { // FIXME: C++0x allows a braced-init-list Diag(Tok, diag::err_expected_equal_after_declarator); @@ -874,7 +863,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { // type-name case tok::annot_typename: { DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, - Tok.getAnnotationValue()); + getTypeAnnotation(Tok)); break; } @@ -1002,7 +991,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, bool EnteringContext, - TypeTy *ObjectType, + ParsedType ObjectType, UnqualifiedId &Id, bool AssumeTemplateId, SourceLocation TemplateKWLoc) { @@ -1023,8 +1012,9 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, return true; } else { bool MemberOfUnknownSpecialization; - TNK = Actions.isTemplateName(getCurScope(), SS, Id, ObjectType, - EnteringContext, Template, + TNK = Actions.isTemplateName(getCurScope(), SS, + TemplateKWLoc.isValid(), Id, + ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization); if (TNK == TNK_Non_template && MemberOfUnknownSpecialization && @@ -1059,7 +1049,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, UnqualifiedId TemplateName; bool MemberOfUnknownSpecialization; TemplateName.setIdentifier(Name, NameLoc); - TNK = Actions.isTemplateName(getCurScope(), SS, TemplateName, ObjectType, + TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(), + TemplateName, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization); break; @@ -1076,11 +1067,12 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, if (TNK == TNK_Non_template) return true; } else { - TNK = Actions.isTemplateName(getCurScope(), SS, TemplateName, ObjectType, + TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(), + TemplateName, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization); - if (TNK == TNK_Non_template && Id.DestructorName == 0) { + if (TNK == TNK_Non_template && !Id.DestructorName.get()) { Diag(NameLoc, diag::err_destructor_template_id) << Name << SS.getRange(); return true; @@ -1124,7 +1116,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, TemplateId->TemplateNameLoc = Id.StartLocation; } - TemplateId->Template = Template.getAs(); + TemplateId->Template = Template; TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; TemplateId->RAngleLoc = RAngleLoc; @@ -1142,7 +1134,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, TemplateArgs.size()); // Constructor and destructor names. - Action::TypeResult Type + TypeResult Type = Actions.ActOnTemplateIdType(Template, NameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc); @@ -1198,7 +1190,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, /// /// \returns true if parsing fails, false otherwise. bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, - TypeTy *ObjectType, + ParsedType ObjectType, UnqualifiedId &Result) { assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword"); @@ -1334,7 +1326,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, ParseDeclaratorInternal(D, /*DirectDeclParser=*/0); // Finish up the type. - Action::TypeResult Ty = Actions.ActOnTypeName(getCurScope(), D); + TypeResult Ty = Actions.ActOnTypeName(getCurScope(), D); if (Ty.isInvalid()) return true; @@ -1377,7 +1369,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowDestructorName, bool AllowConstructorName, - TypeTy *ObjectType, + ParsedType ObjectType, UnqualifiedId &Result) { // Handle 'A::template B'. This is for template-ids which have not @@ -1511,17 +1503,17 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, SourceLocation ClassNameLoc = ConsumeToken(); if (TemplateSpecified || Tok.is(tok::less)) { - Result.setDestructorName(TildeLoc, 0, ClassNameLoc); + Result.setDestructorName(TildeLoc, ParsedType(), ClassNameLoc); return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc, EnteringContext, ObjectType, Result, TemplateSpecified, TemplateKWLoc); } // Note that this is a destructor name. - Action::TypeTy *Ty = Actions.getDestructorName(TildeLoc, *ClassName, - ClassNameLoc, getCurScope(), - SS, ObjectType, - EnteringContext); + ParsedType Ty = Actions.getDestructorName(TildeLoc, *ClassName, + ClassNameLoc, getCurScope(), + SS, ObjectType, + EnteringContext); if (!Ty) return true; @@ -1561,7 +1553,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, /// '(' expression-list[opt] ')' /// [C++0x] braced-init-list [TODO] /// -Parser::OwningExprResult +ExprResult Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { assert(Tok.is(tok::kw_new) && "expected 'new' token"); ConsumeToken(); // Consume 'new' @@ -1665,7 +1657,7 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { bool first = true; while (Tok.is(tok::l_square)) { SourceLocation LLoc = ConsumeBracket(); - OwningExprResult Size(first ? ParseExpression() + ExprResult Size(first ? ParseExpression() : ParseConstantExpression()); if (Size.isInvalid()) { // Recover @@ -1694,7 +1686,8 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { /// new-placement: /// '(' expression-list ')' /// -bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs, +bool Parser::ParseExpressionListOrTypeId( + llvm::SmallVectorImpl &PlacementArgs, Declarator &D) { // The '(' was already consumed. if (isTypeIdInParens()) { @@ -1721,7 +1714,7 @@ bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs, /// delete-expression: /// '::'[opt] 'delete' cast-expression /// '::'[opt] 'delete' '[' ']' cast-expression -Parser::OwningExprResult +ExprResult Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { assert(Tok.is(tok::kw_delete) && "Expected 'delete' keyword"); ConsumeToken(); // Consume 'delete' @@ -1736,11 +1729,11 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { return ExprError(); } - OwningExprResult Operand(ParseCastExpression(false)); + ExprResult Operand(ParseCastExpression(false)); if (Operand.isInvalid()) return move(Operand); - return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, move(Operand)); + return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.take()); } static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { @@ -1772,7 +1765,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { /// primary-expression: /// [GNU] unary-type-trait '(' type-id ')' /// -Parser::OwningExprResult Parser::ParseUnaryTypeTrait() { +ExprResult Parser::ParseUnaryTypeTrait() { UnaryTypeTrait UTT = UnaryTypeTraitFromTokKind(Tok.getKind()); SourceLocation Loc = ConsumeToken(); @@ -1796,17 +1789,17 @@ Parser::OwningExprResult Parser::ParseUnaryTypeTrait() { /// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a /// parenthesized ambiguous type-id. This uses tentative parsing to disambiguate /// based on the context past the parens. -Parser::OwningExprResult +ExprResult Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, - TypeTy *&CastTy, + ParsedType &CastTy, SourceLocation LParenLoc, SourceLocation &RParenLoc) { assert(getLang().CPlusPlus && "Should only be called for C++!"); assert(ExprType == CastExpr && "Compound literals are not ambiguous!"); assert(isTypeIdInParens() && "Not a type-id!"); - OwningExprResult Result(Actions, true); - CastTy = 0; + ExprResult Result(true); + CastTy = ParsedType(); // We need to disambiguate a very ugly part of the C++ syntax: // @@ -1851,7 +1844,8 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, // will be consumed. Result = ParseCastExpression(false/*isUnaryExpression*/, false/*isAddressofOperand*/, - NotCastExpr, 0/*TypeOfCast*/); + NotCastExpr, + ParsedType()/*TypeOfCast*/); } // If we parsed a cast-expression, it's really a type-id, otherwise it's @@ -1894,7 +1888,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, // Result is what ParseCastExpression returned earlier. if (!Result.isInvalid()) Result = Actions.ActOnCastExpr(getCurScope(), LParenLoc, CastTy, RParenLoc, - move(Result)); + Result.take()); return move(Result); } @@ -1904,7 +1898,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, ExprType = SimpleExpr; Result = ParseExpression(); if (!Result.isInvalid() && Tok.is(tok::r_paren)) - Result = Actions.ActOnParenExpr(LParenLoc, Tok.getLocation(), move(Result)); + Result = Actions.ActOnParenExpr(LParenLoc, Tok.getLocation(), Result.take()); // Match the ')'. if (Result.isInvalid()) { diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 8451aeb..4347294 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -11,10 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "clang/Parse/Designator.h" #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" -#include "clang/Parse/Scope.h" +#include "clang/Sema/Designator.h" +#include "clang/Sema/Scope.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -71,7 +71,7 @@ static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc, /// initializer (because it is an expression). We need to consider this case /// when parsing array designators. /// -Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { +ExprResult Parser::ParseInitializerWithPotentialDesignator() { // If this is the old-style GNU extension: // designation ::= identifier ':' @@ -137,7 +137,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { // [4][foo bar] -> obsolete GNU designation with objc message send. // SourceLocation StartLoc = ConsumeBracket(); - OwningExprResult Idx(Actions); + ExprResult Idx; // If Objective-C is enabled and this is a typename (class message // send) or send to 'super', parse this as a message send @@ -149,8 +149,9 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope()) { CheckArrayDesignatorSyntax(*this, StartLoc, Desig); return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, - ConsumeToken(), 0, - ExprArg(Actions)); + ConsumeToken(), + ParsedType(), + 0); } // Parse the receiver, which is either a type or an expression. @@ -167,35 +168,35 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { CheckArrayDesignatorSyntax(*this, StartLoc, Desig); return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, SourceLocation(), - TypeOrExpr, - ExprArg(Actions)); + ParsedType::getFromOpaquePtr(TypeOrExpr), + 0); } // If the receiver was an expression, we still don't know // whether we have a message send or an array designator; just // adopt the expression for further analysis below. // FIXME: potentially-potentially evaluated expression above? - Idx = OwningExprResult(Actions, TypeOrExpr); + Idx = ExprResult(static_cast(TypeOrExpr)); } else if (getLang().ObjC1 && Tok.is(tok::identifier)) { IdentifierInfo *II = Tok.getIdentifierInfo(); SourceLocation IILoc = Tok.getLocation(); - TypeTy *ReceiverType; + ParsedType ReceiverType; // Three cases. This is a message send to a type: [type foo] // This is a message send to super: [super foo] // This is a message sent to an expr: [super.bar foo] - switch (Action::ObjCMessageKind Kind + switch (Sema::ObjCMessageKind Kind = Actions.getObjCMessageKind(getCurScope(), II, IILoc, II == Ident_super, NextToken().is(tok::period), ReceiverType)) { - case Action::ObjCSuperMessage: - case Action::ObjCClassMessage: + case Sema::ObjCSuperMessage: + case Sema::ObjCClassMessage: CheckArrayDesignatorSyntax(*this, StartLoc, Desig); - if (Kind == Action::ObjCSuperMessage) + if (Kind == Sema::ObjCSuperMessage) return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, ConsumeToken(), - 0, - ExprArg(Actions)); + ParsedType(), + 0); ConsumeToken(); // the identifier if (!ReceiverType) { SkipUntil(tok::r_square); @@ -205,9 +206,9 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, SourceLocation(), ReceiverType, - ExprArg(Actions)); + 0); - case Action::ObjCInstanceMessage: + case Sema::ObjCInstanceMessage: // Fall through; we'll just parse the expression and // (possibly) treat this like an Objective-C message send // later. @@ -239,7 +240,8 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig); return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, SourceLocation(), - 0, move(Idx)); + ParsedType(), + Idx.take()); } // If this is a normal array designator, remember it. @@ -250,7 +252,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { Diag(Tok, diag::ext_gnu_array_range); SourceLocation EllipsisLoc = ConsumeToken(); - OwningExprResult RHS(ParseConstantExpression()); + ExprResult RHS(ParseConstantExpression()); if (RHS.isInvalid()) { SkipUntil(tok::r_square); return move(RHS); @@ -307,7 +309,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { /// designation[opt] initializer /// initializer-list ',' designation[opt] initializer /// -Parser::OwningExprResult Parser::ParseBraceInitializer() { +ExprResult Parser::ParseBraceInitializer() { SourceLocation LBraceLoc = ConsumeBrace(); /// InitExprs - This is the actual list of expressions contained in the @@ -319,7 +321,7 @@ Parser::OwningExprResult Parser::ParseBraceInitializer() { if (!getLang().CPlusPlus) Diag(LBraceLoc, diag::ext_gnu_empty_initializer); // Match the '}'. - return Actions.ActOnInitList(LBraceLoc, Action::MultiExprArg(Actions), + return Actions.ActOnInitList(LBraceLoc, MultiExprArg(Actions), ConsumeBrace()); } @@ -330,7 +332,7 @@ Parser::OwningExprResult Parser::ParseBraceInitializer() { // If we know that this cannot be a designation, just parse the nested // initializer directly. - OwningExprResult SubElt(Actions); + ExprResult SubElt; if (MayBeDesignationStart(Tok.getKind(), PP)) SubElt = ParseInitializerWithPotentialDesignator(); else diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 68473a5..6861ce9 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -11,10 +11,11 @@ // //===----------------------------------------------------------------------===// -#include "clang/Parse/Parser.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/PrettyDeclStackTrace.h" +#include "clang/Sema/Scope.h" #include "llvm/ADT/SmallVector.h" using namespace clang; @@ -27,7 +28,7 @@ using namespace clang; /// [OBJC] objc-protocol-definition /// [OBJC] objc-method-definition /// [OBJC] '@' 'end' -Parser::DeclPtrTy Parser::ParseObjCAtDirectives() { +Decl *Parser::ParseObjCAtDirectives() { SourceLocation AtLoc = ConsumeToken(); // the "@" if (Tok.is(tok::code_completion)) { @@ -55,7 +56,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtDirectives() { default: Diag(AtLoc, diag::err_unexpected_at); SkipUntil(tok::semi); - return DeclPtrTy(); + return 0; } } @@ -63,7 +64,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtDirectives() { /// objc-class-declaration: /// '@' 'class' identifier-list ';' /// -Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { +Decl *Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { ConsumeToken(); // the identifier "class" llvm::SmallVector ClassNames; llvm::SmallVector ClassLocs; @@ -73,7 +74,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::semi); - return DeclPtrTy(); + return 0; } ClassNames.push_back(Tok.getIdentifierInfo()); ClassLocs.push_back(Tok.getLocation()); @@ -87,7 +88,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { // Consume the ';'. if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@class")) - return DeclPtrTy(); + return 0; return Actions.ActOnForwardClassDeclaration(atLoc, ClassNames.data(), ClassLocs.data(), @@ -122,7 +123,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtClassDeclaration(SourceLocation atLoc) { /// __attribute__((unavailable)) /// __attribute__((objc_exception)) - used by NSException on 64-bit /// -Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( +Decl *Parser::ParseObjCAtInterfaceDeclaration( SourceLocation atLoc, AttributeList *attrList) { assert(Tok.isObjCAtKeyword(tok::objc_interface) && "ParseObjCAtInterfaceDeclaration(): Expected @interface"); @@ -136,7 +137,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing class or category name. - return DeclPtrTy(); + return 0; } // We have a class or category name - consume it. @@ -159,27 +160,27 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( } else if (!getLang().ObjC2) { Diag(Tok, diag::err_expected_ident); // missing category name. - return DeclPtrTy(); + return 0; } if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); SkipUntil(tok::r_paren, false); // don't stop at ';' - return DeclPtrTy(); + return 0; } rparenLoc = ConsumeParen(); // Next, we need to check for any protocol references. SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector ProtocolRefs; + llvm::SmallVector ProtocolRefs; llvm::SmallVector ProtocolLocs; if (Tok.is(tok::less) && ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, LAngleLoc, EndProtoLoc)) - return DeclPtrTy(); + return 0; if (attrList) // categories don't support attributes. Diag(Tok, diag::err_objc_no_attributes_on_category); - DeclPtrTy CategoryType = + Decl *CategoryType = Actions.ActOnStartCategoryInterface(atLoc, nameId, nameLoc, categoryId, categoryLoc, @@ -209,21 +210,21 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing super class name. - return DeclPtrTy(); + return 0; } superClassId = Tok.getIdentifierInfo(); superClassLoc = ConsumeToken(); } // Next, we need to check for any protocol references. - llvm::SmallVector ProtocolRefs; + llvm::SmallVector ProtocolRefs; llvm::SmallVector ProtocolLocs; SourceLocation LAngleLoc, EndProtoLoc; if (Tok.is(tok::less) && ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, LAngleLoc, EndProtoLoc)) - return DeclPtrTy(); + return 0; - DeclPtrTy ClsType = + Decl *ClsType = Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc, superClassId, superClassLoc, ProtocolRefs.data(), ProtocolRefs.size(), @@ -241,30 +242,30 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( /// it's used, but instead it's been lifted to here to support VS2005. struct Parser::ObjCPropertyCallback : FieldCallback { Parser &P; - DeclPtrTy IDecl; - llvm::SmallVectorImpl &Props; + Decl *IDecl; + llvm::SmallVectorImpl &Props; ObjCDeclSpec &OCDS; SourceLocation AtLoc; tok::ObjCKeywordKind MethodImplKind; - ObjCPropertyCallback(Parser &P, DeclPtrTy IDecl, - llvm::SmallVectorImpl &Props, + ObjCPropertyCallback(Parser &P, Decl *IDecl, + llvm::SmallVectorImpl &Props, ObjCDeclSpec &OCDS, SourceLocation AtLoc, tok::ObjCKeywordKind MethodImplKind) : P(P), IDecl(IDecl), Props(Props), OCDS(OCDS), AtLoc(AtLoc), MethodImplKind(MethodImplKind) { } - DeclPtrTy invoke(FieldDeclarator &FD) { + Decl *invoke(FieldDeclarator &FD) { if (FD.D.getIdentifier() == 0) { P.Diag(AtLoc, diag::err_objc_property_requires_field_name) << FD.D.getSourceRange(); - return DeclPtrTy(); + return 0; } if (FD.BitfieldSize) { P.Diag(AtLoc, diag::err_objc_property_bitfield) << FD.D.getSourceRange(); - return DeclPtrTy(); + return 0; } // Install the property declarator into interfaceDecl. @@ -282,7 +283,7 @@ struct Parser::ObjCPropertyCallback : FieldCallback { P.PP.getSelectorTable(), FD.D.getIdentifier()); bool isOverridingProperty = false; - DeclPtrTy Property = + Decl *Property = P.Actions.ActOnProperty(P.getCurScope(), AtLoc, FD, OCDS, GetterSel, SetterSel, IDecl, &isOverridingProperty, @@ -306,10 +307,10 @@ struct Parser::ObjCPropertyCallback : FieldCallback { /// @required /// @optional /// -void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, +void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, tok::ObjCKeywordKind contextKey) { - llvm::SmallVector allMethods; - llvm::SmallVector allProperties; + llvm::SmallVector allMethods; + llvm::SmallVector allProperties; llvm::SmallVector allTUVariables; tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword; @@ -318,7 +319,7 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, while (1) { // If this is a method prototype, parse it. if (Tok.is(tok::minus) || Tok.is(tok::plus)) { - DeclPtrTy methodPrototype = + Decl *methodPrototype = ParseObjCMethodPrototype(interfaceDecl, MethodImplKind); allMethods.push_back(methodPrototype); // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for @@ -329,10 +330,10 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, } if (Tok.is(tok::l_paren)) { Diag(Tok, diag::err_expected_minus_or_plus); - DeclPtrTy methodPrototype = ParseObjCMethodDecl(Tok.getLocation(), - tok::minus, - interfaceDecl, - MethodImplKind); + ParseObjCMethodDecl(Tok.getLocation(), + tok::minus, + interfaceDecl, + MethodImplKind); continue; } // Ignore excess semicolons. @@ -348,8 +349,8 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, // Code completion within an Objective-C interface. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), - ObjCImpDecl? Action::CCC_ObjCImplementation - : Action::CCC_ObjCInterface); + ObjCImpDecl? Sema::PCC_ObjCImplementation + : Sema::PCC_ObjCInterface); ConsumeCodeCompletionToken(); } @@ -468,8 +469,8 @@ void Parser::ParseObjCInterfaceDeclList(DeclPtrTy interfaceDecl, /// copy /// nonatomic /// -void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl, - DeclPtrTy *Methods, +void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl, + Decl **Methods, unsigned NumMethods) { assert(Tok.getKind() == tok::l_paren); SourceLocation LHSLoc = ConsumeParen(); // consume '(' @@ -562,14 +563,13 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, DeclPtrTy ClassDecl, /// objc-method-attributes: [OBJC2] /// __attribute__((deprecated)) /// -Parser::DeclPtrTy Parser::ParseObjCMethodPrototype(DeclPtrTy IDecl, - tok::ObjCKeywordKind MethodImplKind) { +Decl *Parser::ParseObjCMethodPrototype(Decl *IDecl, + tok::ObjCKeywordKind MethodImplKind) { assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-"); tok::TokenKind methodType = Tok.getKind(); SourceLocation mLoc = ConsumeToken(); - - DeclPtrTy MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl,MethodImplKind); + Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl,MethodImplKind); // Since this rule is used for both method declarations and definitions, // the caller is (optionally) responsible for consuming the ';'. return MDecl; @@ -584,9 +584,31 @@ Parser::DeclPtrTy Parser::ParseObjCMethodPrototype(DeclPtrTy IDecl, /// in out inout bycopy byref oneway int char float double void _Bool /// IdentifierInfo *Parser::ParseObjCSelectorPiece(SourceLocation &SelectorLoc) { + switch (Tok.getKind()) { default: return 0; + case tok::ampamp: + case tok::ampequal: + case tok::amp: + case tok::pipe: + case tok::tilde: + case tok::exclaim: + case tok::exclaimequal: + case tok::pipepipe: + case tok::pipeequal: + case tok::caret: + case tok::caretequal: { + std::string ThisTok(PP.getSpelling(Tok)); + if (isalpha(ThisTok[0])) { + IdentifierInfo *II = &PP.getIdentifierTable().get(ThisTok.data()); + Tok.setKind(tok::identifier); + SelectorLoc = ConsumeToken(); + return II; + } + return 0; + } + case tok::identifier: case tok::kw_asm: case tok::kw_auto: @@ -680,8 +702,13 @@ bool Parser::isTokIdentifier_in() const { /// objc-type-qualifier /// objc-type-qualifiers objc-type-qualifier /// -void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) { +void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, bool IsParameter) { while (1) { + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCPassingType(getCurScope(), DS); + ConsumeCodeCompletionToken(); + } + if (Tok.isNot(tok::identifier)) return; @@ -715,16 +742,16 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS) { /// '(' objc-type-qualifiers[opt] type-name ')' /// '(' objc-type-qualifiers[opt] ')' /// -Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) { +ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, bool IsParameter) { assert(Tok.is(tok::l_paren) && "expected ("); SourceLocation LParenLoc = ConsumeParen(); SourceLocation TypeStartLoc = Tok.getLocation(); // Parse type qualifiers, in, inout, etc. - ParseObjCTypeQualifierList(DS); + ParseObjCTypeQualifierList(DS, IsParameter); - TypeTy *Ty = 0; + ParsedType Ty; if (isTypeSpecifierQualifier()) { TypeResult TypeSpec = ParseTypeName(); if (!TypeSpec.isInvalid()) @@ -773,23 +800,23 @@ Parser::TypeTy *Parser::ParseObjCTypeName(ObjCDeclSpec &DS) { /// objc-keyword-attributes: [OBJC2] /// __attribute__((unused)) /// -Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, - tok::TokenKind mType, - DeclPtrTy IDecl, - tok::ObjCKeywordKind MethodImplKind) { +Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, + tok::TokenKind mType, + Decl *IDecl, + tok::ObjCKeywordKind MethodImplKind) { ParsingDeclRAIIObject PD(*this); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, - /*ReturnType=*/0, IDecl); + /*ReturnType=*/ ParsedType(), IDecl); ConsumeCodeCompletionToken(); } // Parse the return type if present. - TypeTy *ReturnType = 0; + ParsedType ReturnType; ObjCDeclSpec DSRet; if (Tok.is(tok::l_paren)) - ReturnType = ParseObjCTypeName(DSRet); + ReturnType = ParseObjCTypeName(DSRet, false); // If attributes exist before the method, parse them. llvm::OwningPtr MethodAttrs; @@ -812,7 +839,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, << SourceRange(mLoc, Tok.getLocation()); // Skip until we get a ; or {}. SkipUntil(tok::r_brace); - return DeclPtrTy(); + return 0; } llvm::SmallVector CParamInfo; @@ -823,7 +850,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, ParseGNUAttributes())); Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); - DeclPtrTy Result + Decl *Result = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, 0, @@ -835,10 +862,10 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, } llvm::SmallVector KeyIdents; - llvm::SmallVector ArgInfos; + llvm::SmallVector ArgInfos; while (1) { - Action::ObjCArgInfo ArgInfo; + Sema::ObjCArgInfo ArgInfo; // Each iteration parses a single keyword argument. if (Tok.isNot(tok::colon)) { @@ -847,9 +874,9 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, } ConsumeToken(); // Eat the ':'. - ArgInfo.Type = 0; + ArgInfo.Type = ParsedType(); if (Tok.is(tok::l_paren)) // Parse the argument type if present. - ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec); + ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, true); // If attributes exist before the argument name, parse them. ArgInfo.ArgAttrs = 0; @@ -918,7 +945,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, Declarator ParmDecl(DS, Declarator::PrototypeContext); ParseDeclarator(ParmDecl); IdentifierInfo *ParmII = ParmDecl.getIdentifier(); - DeclPtrTy Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl); + Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl); CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, ParmDecl.getIdentifierLoc(), Param, @@ -933,10 +960,10 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, ParseGNUAttributes())); if (KeyIdents.size() == 0) - return DeclPtrTy(); + return 0; Selector Sel = PP.getSelectorTable().getSelector(KeyIdents.size(), &KeyIdents[0]); - DeclPtrTy Result + Decl *Result = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, &ArgInfos[0], @@ -946,7 +973,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, PD.complete(Result); // Delete referenced AttributeList objects. - for (llvm::SmallVectorImpl::iterator + for (llvm::SmallVectorImpl::iterator I = ArgInfos.begin(), E = ArgInfos.end(); I != E; ++I) delete I->ArgAttrs; @@ -957,7 +984,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, /// '<' identifier-list '>' /// bool Parser:: -ParseObjCProtocolReferences(llvm::SmallVectorImpl &Protocols, +ParseObjCProtocolReferences(llvm::SmallVectorImpl &Protocols, llvm::SmallVectorImpl &ProtocolLocs, bool WarnOnDeclarations, SourceLocation &LAngleLoc, SourceLocation &EndLoc) { @@ -1024,11 +1051,11 @@ ParseObjCProtocolReferences(llvm::SmallVectorImpl &Protocols, /// objc-instance-variable-decl: /// struct-declaration /// -void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, +void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, tok::ObjCKeywordKind visibility, SourceLocation atLoc) { assert(Tok.is(tok::l_brace) && "expected {"); - llvm::SmallVector AllIvarDecls; + llvm::SmallVector AllIvarDecls; ParseScope ClassScope(this, Scope::DeclScope|Scope::ClassScope); @@ -1071,24 +1098,24 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), - Action::CCC_ObjCInstanceVariableList); + Sema::PCC_ObjCInstanceVariableList); ConsumeCodeCompletionToken(); } struct ObjCIvarCallback : FieldCallback { Parser &P; - DeclPtrTy IDecl; + Decl *IDecl; tok::ObjCKeywordKind visibility; - llvm::SmallVectorImpl &AllIvarDecls; + llvm::SmallVectorImpl &AllIvarDecls; - ObjCIvarCallback(Parser &P, DeclPtrTy IDecl, tok::ObjCKeywordKind V, - llvm::SmallVectorImpl &AllIvarDecls) : + ObjCIvarCallback(Parser &P, Decl *IDecl, tok::ObjCKeywordKind V, + llvm::SmallVectorImpl &AllIvarDecls) : P(P), IDecl(IDecl), visibility(V), AllIvarDecls(AllIvarDecls) { } - DeclPtrTy invoke(FieldDeclarator &FD) { + Decl *invoke(FieldDeclarator &FD) { // Install the declarator into the interface decl. - DeclPtrTy Field + Decl *Field = P.Actions.ActOnIvar(P.getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), IDecl, FD.D, FD.BitfieldSize, visibility); @@ -1097,7 +1124,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, return Field; } } Callback(*this, interfaceDecl, visibility, AllIvarDecls); - + // Parse all the comma separated declarators. DeclSpec DS; ParseStructDeclaration(DS, Callback); @@ -1111,6 +1138,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, } } SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); + Actions.ActOnLastBitfield(RBraceLoc, interfaceDecl, AllIvarDecls); // Call ActOnFields() even if we don't have any decls. This is useful // for code rewriting tools that need to be aware of the empty list. Actions.ActOnFields(getCurScope(), atLoc, interfaceDecl, @@ -1135,7 +1163,7 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, /// "@protocol identifier ;" should be resolved as "@protocol /// identifier-list ;": objc-interface-decl-list may not start with a /// semicolon in the first alternative if objc-protocol-refs are omitted. -Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, +Decl *Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, AttributeList *attrList) { assert(Tok.isObjCAtKeyword(tok::objc_protocol) && "ParseObjCAtProtocolDeclaration(): Expected @protocol"); @@ -1148,7 +1176,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing protocol name. - return DeclPtrTy(); + return 0; } // Save the protocol name, then consume it. IdentifierInfo *protocolName = Tok.getIdentifierInfo(); @@ -1171,7 +1199,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::semi); - return DeclPtrTy(); + return 0; } ProtocolRefs.push_back(IdentifierLocPair(Tok.getIdentifierInfo(), Tok.getLocation())); @@ -1182,7 +1210,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, } // Consume the ';'. if (ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@protocol")) - return DeclPtrTy(); + return 0; return Actions.ActOnForwardProtocolDeclaration(AtLoc, &ProtocolRefs[0], @@ -1193,14 +1221,14 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, // Last, and definitely not least, parse a protocol declaration. SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector ProtocolRefs; + llvm::SmallVector ProtocolRefs; llvm::SmallVector ProtocolLocs; if (Tok.is(tok::less) && ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, LAngleLoc, EndProtoLoc)) - return DeclPtrTy(); + return 0; - DeclPtrTy ProtoType = + Decl *ProtoType = Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc, ProtocolRefs.data(), ProtocolRefs.size(), @@ -1220,7 +1248,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, /// /// objc-category-implementation-prologue: /// @implementation identifier ( identifier ) -Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( +Decl *Parser::ParseObjCAtImplementationDeclaration( SourceLocation atLoc) { assert(Tok.isObjCAtKeyword(tok::objc_implementation) && "ParseObjCAtImplementationDeclaration(): Expected @implementation"); @@ -1234,7 +1262,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing class or category name. - return DeclPtrTy(); + return 0; } // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); @@ -1256,20 +1284,20 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( categoryLoc = ConsumeToken(); } else { Diag(Tok, diag::err_expected_ident); // missing category name. - return DeclPtrTy(); + return 0; } if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); SkipUntil(tok::r_paren, false); // don't stop at ';' - return DeclPtrTy(); + return 0; } rparenLoc = ConsumeParen(); - DeclPtrTy ImplCatType = Actions.ActOnStartCategoryImplementation( + Decl *ImplCatType = Actions.ActOnStartCategoryImplementation( atLoc, nameId, nameLoc, categoryId, categoryLoc); ObjCImpDecl = ImplCatType; PendingObjCImpDecl.push_back(ObjCImpDecl); - return DeclPtrTy(); + return 0; } // We have a class implementation SourceLocation superClassLoc; @@ -1279,12 +1307,12 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( ConsumeToken(); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); // missing super class name. - return DeclPtrTy(); + return 0; } superClassId = Tok.getIdentifierInfo(); superClassLoc = ConsumeToken(); // Consume super class name } - DeclPtrTy ImplClsType = Actions.ActOnStartClassImplementation( + Decl *ImplClsType = Actions.ActOnStartClassImplementation( atLoc, nameId, nameLoc, superClassId, superClassLoc); @@ -1294,17 +1322,17 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( ObjCImpDecl = ImplClsType; PendingObjCImpDecl.push_back(ObjCImpDecl); - return DeclPtrTy(); + return 0; } -Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { +Decl *Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { assert(Tok.isObjCAtKeyword(tok::objc_end) && "ParseObjCAtEndDeclaration(): Expected @end"); - DeclPtrTy Result = ObjCImpDecl; + Decl *Result = ObjCImpDecl; ConsumeToken(); // the "end" identifier if (ObjCImpDecl) { Actions.ActOnAtEnd(getCurScope(), atEnd, ObjCImpDecl); - ObjCImpDecl = DeclPtrTy(); + ObjCImpDecl = 0; PendingObjCImpDecl.pop_back(); } else { @@ -1314,10 +1342,11 @@ Parser::DeclPtrTy Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { return Result; } -Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() { +Parser::DeclGroupPtrTy Parser::FinishPendingObjCActions() { + Actions.DiagnoseUseOfUnimplementedSelectors(); if (PendingObjCImpDecl.empty()) - return Actions.ConvertDeclToDeclGroup(DeclPtrTy()); - DeclPtrTy ImpDecl = PendingObjCImpDecl.pop_back_val(); + return Actions.ConvertDeclToDeclGroup(0); + Decl *ImpDecl = PendingObjCImpDecl.pop_back_val(); Actions.ActOnAtEnd(getCurScope(), SourceRange(), ImpDecl); return Actions.ConvertDeclToDeclGroup(ImpDecl); } @@ -1325,25 +1354,25 @@ Parser::DeclGroupPtrTy Parser::RetrievePendingObjCImpDecl() { /// compatibility-alias-decl: /// @compatibility_alias alias-name class-name ';' /// -Parser::DeclPtrTy Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { +Decl *Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) && "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias"); ConsumeToken(); // consume compatibility_alias if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); - return DeclPtrTy(); + return 0; } IdentifierInfo *aliasId = Tok.getIdentifierInfo(); SourceLocation aliasLoc = ConsumeToken(); // consume alias-name if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); - return DeclPtrTy(); + return 0; } IdentifierInfo *classId = Tok.getIdentifierInfo(); SourceLocation classLoc = ConsumeToken(); // consume class-name; if (Tok.isNot(tok::semi)) { Diag(Tok, diag::err_expected_semi_after) << "@compatibility_alias"; - return DeclPtrTy(); + return 0; } return Actions.ActOnCompatiblityAlias(atLoc, aliasId, aliasLoc, classId, classLoc); @@ -1360,7 +1389,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtAliasDeclaration(SourceLocation atLoc) { /// identifier /// identifier '=' identifier /// -Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { +Decl *Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { assert(Tok.isObjCAtKeyword(tok::objc_synthesize) && "ParseObjCPropertyDynamic(): Expected '@synthesize'"); SourceLocation loc = ConsumeToken(); // consume synthesize @@ -1374,7 +1403,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_synthesized_property_name); SkipUntil(tok::semi); - return DeclPtrTy(); + return 0; } IdentifierInfo *propertyIvar = 0; @@ -1409,7 +1438,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { } else ConsumeToken(); // consume ';' - return DeclPtrTy(); + return 0; } /// property-dynamic: @@ -1419,7 +1448,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertySynthesize(SourceLocation atLoc) { /// identifier /// property-list ',' identifier /// -Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { +Decl *Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { assert(Tok.isObjCAtKeyword(tok::objc_dynamic) && "ParseObjCPropertyDynamic(): Expected '@dynamic'"); SourceLocation loc = ConsumeToken(); // consume dynamic @@ -1432,7 +1461,7 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::semi); - return DeclPtrTy(); + return 0; } IdentifierInfo *propertyId = Tok.getIdentifierInfo(); @@ -1450,14 +1479,14 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { } else ConsumeToken(); // consume ';' - return DeclPtrTy(); + return 0; } /// objc-throw-statement: /// throw expression[opt]; /// -Parser::OwningStmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) { - OwningExprResult Res(Actions); +StmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) { + ExprResult Res; ConsumeToken(); // consume throw if (Tok.isNot(tok::semi)) { Res = ParseExpression(); @@ -1468,13 +1497,13 @@ Parser::OwningStmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) { } // consume ';' ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@throw"); - return Actions.ActOnObjCAtThrowStmt(atLoc, move(Res), getCurScope()); + return Actions.ActOnObjCAtThrowStmt(atLoc, Res.take(), getCurScope()); } /// objc-synchronized-statement: /// @synchronized '(' expression ')' compound-statement /// -Parser::OwningStmtResult +StmtResult Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) { ConsumeToken(); // consume synchronized if (Tok.isNot(tok::l_paren)) { @@ -1482,7 +1511,7 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) { return StmtError(); } ConsumeParen(); // '(' - OwningExprResult Res(ParseExpression()); + ExprResult Res(ParseExpression()); if (Res.isInvalid()) { SkipUntil(tok::semi); return StmtError(); @@ -1500,12 +1529,12 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) { // statements can always hold declarations. ParseScope BodyScope(this, Scope::DeclScope); - OwningStmtResult SynchBody(ParseCompoundStatementBody()); + StmtResult SynchBody(ParseCompoundStatementBody()); BodyScope.Exit(); if (SynchBody.isInvalid()) SynchBody = Actions.ActOnNullStmt(Tok.getLocation()); - return Actions.ActOnObjCAtSynchronizedStmt(atLoc, move(Res), move(SynchBody)); + return Actions.ActOnObjCAtSynchronizedStmt(atLoc, Res.take(), SynchBody.take()); } /// objc-try-catch-statement: @@ -1519,7 +1548,7 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) { /// parameter-declaration /// '...' [OBJC2] /// -Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { +StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { bool catch_or_finally_seen = false; ConsumeToken(); // consume try @@ -1528,9 +1557,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { return StmtError(); } StmtVector CatchStmts(Actions); - OwningStmtResult FinallyStmt(Actions); + StmtResult FinallyStmt; ParseScope TryScope(this, Scope::DeclScope); - OwningStmtResult TryBody(ParseCompoundStatementBody()); + StmtResult TryBody(ParseCompoundStatementBody()); TryScope.Exit(); if (TryBody.isInvalid()) TryBody = Actions.ActOnNullStmt(Tok.getLocation()); @@ -1546,7 +1575,7 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { SourceLocation AtCatchFinallyLoc = ConsumeToken(); if (Tok.isObjCAtKeyword(tok::objc_catch)) { - DeclPtrTy FirstPart; + Decl *FirstPart = 0; ConsumeToken(); // consume catch if (Tok.is(tok::l_paren)) { ConsumeParen(); @@ -1573,7 +1602,7 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { else // Skip over garbage, until we get to ')'. Eat the ')'. SkipUntil(tok::r_paren, true, false); - OwningStmtResult CatchBody(Actions, true); + StmtResult CatchBody(true); if (Tok.is(tok::l_brace)) CatchBody = ParseCompoundStatementBody(); else @@ -1581,10 +1610,10 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { if (CatchBody.isInvalid()) CatchBody = Actions.ActOnNullStmt(Tok.getLocation()); - OwningStmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc, + StmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc, RParenLoc, FirstPart, - move(CatchBody)); + CatchBody.take()); if (!Catch.isInvalid()) CatchStmts.push_back(Catch.release()); @@ -1599,7 +1628,7 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { ConsumeToken(); // consume finally ParseScope FinallyScope(this, Scope::DeclScope); - OwningStmtResult FinallyBody(Actions, true); + StmtResult FinallyBody(true); if (Tok.is(tok::l_brace)) FinallyBody = ParseCompoundStatementBody(); else @@ -1607,7 +1636,7 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { if (FinallyBody.isInvalid()) FinallyBody = Actions.ActOnNullStmt(Tok.getLocation()); FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc, - move(FinallyBody)); + FinallyBody.take()); catch_or_finally_seen = true; break; } @@ -1617,19 +1646,18 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { return StmtError(); } - return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), + return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.take(), move_arg(CatchStmts), - move(FinallyStmt)); + FinallyStmt.take()); } /// objc-method-def: objc-method-proto ';'[opt] '{' body '}' /// -Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { - DeclPtrTy MDecl = ParseObjCMethodPrototype(ObjCImpDecl); +Decl *Parser::ParseObjCMethodDefinition() { + Decl *MDecl = ParseObjCMethodPrototype(ObjCImpDecl); - PrettyStackTraceActionsDecl CrashInfo(MDecl, Tok.getLocation(), Actions, - PP.getSourceManager(), - "parsing Objective-C method"); + PrettyDeclStackTraceEntry CrashInfo(Actions, MDecl, Tok.getLocation(), + "parsing Objective-C method"); // parse optional ';' if (Tok.is(tok::semi)) { @@ -1649,7 +1677,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { // If we didn't find the '{', bail out. if (Tok.isNot(tok::l_brace)) - return DeclPtrTy(); + return 0; } SourceLocation BraceLoc = Tok.getLocation(); @@ -1661,7 +1689,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { // specified Declarator for the method. Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl); - OwningStmtResult FnBody(ParseCompoundStatementBody()); + StmtResult FnBody(ParseCompoundStatementBody()); // If the function body could not be parsed, make a bogus compoundstmt. if (FnBody.isInvalid()) @@ -1669,7 +1697,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { MultiStmtArg(Actions), false); // TODO: Pass argument information. - Actions.ActOnFinishFunctionBody(MDecl, move(FnBody)); + Actions.ActOnFinishFunctionBody(MDecl, FnBody.take()); // Leave the function body scope. BodyScope.Exit(); @@ -1677,7 +1705,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { return MDecl; } -Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { +StmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCAtStatement(getCurScope()); ConsumeCodeCompletionToken(); @@ -1693,7 +1721,7 @@ Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { if (Tok.isObjCAtKeyword(tok::objc_synchronized)) return ParseObjCSynchronizedStmt(AtLoc); - OwningExprResult Res(ParseExpressionWithLeadingAt(AtLoc)); + ExprResult Res(ParseExpressionWithLeadingAt(AtLoc)); if (Res.isInvalid()) { // If the expression is invalid, skip ahead to the next semicolon. Not // doing this opens us up to the possibility of infinite loops if @@ -1704,10 +1732,10 @@ Parser::OwningStmtResult Parser::ParseObjCAtStatement(SourceLocation AtLoc) { // Otherwise, eat the semicolon. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); - return Actions.ActOnExprStmt(Actions.MakeFullExpr(Res)); + return Actions.ActOnExprStmt(Actions.MakeFullExpr(Res.take())); } -Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { +ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { switch (Tok.getKind()) { case tok::code_completion: Actions.CodeCompleteObjCAtExpression(getCurScope()); @@ -1764,7 +1792,7 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { if (!isCXXSimpleTypeSpecifier()) { // objc-receiver: // expression - OwningExprResult Receiver = ParseExpression(); + ExprResult Receiver = ParseExpression(); if (Receiver.isInvalid()) return true; @@ -1793,11 +1821,11 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { // postfix-expression suffix, followed by the (optional) // right-hand side of the binary expression. We have an // instance method. - OwningExprResult Receiver = ParseCXXTypeConstructExpression(DS); + ExprResult Receiver = ParseCXXTypeConstructExpression(DS); if (!Receiver.isInvalid()) - Receiver = ParsePostfixExpressionSuffix(move(Receiver)); + Receiver = ParsePostfixExpressionSuffix(Receiver.take()); if (!Receiver.isInvalid()) - Receiver = ParseRHSOfBinaryExpression(move(Receiver), prec::Comma); + Receiver = ParseRHSOfBinaryExpression(Receiver.take(), prec::Comma); if (Receiver.isInvalid()) return true; @@ -1815,7 +1843,7 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { return true; IsExpr = false; - TypeOrExpr = Type.get(); + TypeOrExpr = Type.get().getAsOpaquePtr(); return false; } @@ -1840,7 +1868,7 @@ bool Parser::isSimpleObjCMessageExpression() { /// class-name /// type-name /// -Parser::OwningExprResult Parser::ParseObjCMessageExpression() { +ExprResult Parser::ParseObjCMessageExpression() { assert(Tok.is(tok::l_square) && "'[' expected"); SourceLocation LBracLoc = ConsumeBracket(); // consume '[' @@ -1860,8 +1888,8 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() { // get in Objective-C. if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super && NextToken().isNot(tok::period) && getCurScope()->isInObjcMethodScope()) - return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0, - ExprArg(Actions)); + return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), + ParsedType(), 0); // Parse the receiver, which is either a type or an expression. bool IsExpr; @@ -1872,26 +1900,28 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() { } if (IsExpr) - return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0, - OwningExprResult(Actions, TypeOrExpr)); + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), + ParsedType(), + static_cast(TypeOrExpr)); return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), - TypeOrExpr, ExprArg(Actions)); + ParsedType::getFromOpaquePtr(TypeOrExpr), + 0); } if (Tok.is(tok::identifier)) { IdentifierInfo *Name = Tok.getIdentifierInfo(); SourceLocation NameLoc = Tok.getLocation(); - TypeTy *ReceiverType; + ParsedType ReceiverType; switch (Actions.getObjCMessageKind(getCurScope(), Name, NameLoc, Name == Ident_super, NextToken().is(tok::period), ReceiverType)) { - case Action::ObjCSuperMessage: - return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0, - ExprArg(Actions)); + case Sema::ObjCSuperMessage: + return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), + ParsedType(), 0); - case Action::ObjCClassMessage: + case Sema::ObjCClassMessage: if (!ReceiverType) { SkipUntil(tok::r_square); return ExprError(); @@ -1900,24 +1930,23 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() { ConsumeToken(); // the type name return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), - ReceiverType, - ExprArg(Actions)); + ReceiverType, 0); - case Action::ObjCInstanceMessage: + case Sema::ObjCInstanceMessage: // Fall through to parse an expression. break; } } // Otherwise, an arbitrary expression can be the receiver of a send. - OwningExprResult Res(ParseExpression()); + ExprResult Res(ParseExpression()); if (Res.isInvalid()) { SkipUntil(tok::r_square); return move(Res); } - return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0, - move(Res)); + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), + ParsedType(), Res.take()); } /// \brief Parse the remainder of an Objective-C message following the @@ -1958,10 +1987,10 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() { /// assignment-expression /// nonempty-expr-list , assignment-expression /// -Parser::OwningExprResult +ExprResult Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, SourceLocation SuperLoc, - TypeTy *ReceiverType, + ParsedType ReceiverType, ExprArg ReceiverExpr) { if (Tok.is(tok::code_completion)) { if (SuperLoc.isValid()) @@ -1969,7 +1998,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, else if (ReceiverType) Actions.CodeCompleteObjCClassMessage(getCurScope(), ReceiverType, 0, 0); else - Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr.get(), + Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, 0, 0); ConsumeCodeCompletionToken(); } @@ -1999,7 +2028,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, ConsumeToken(); // Eat the ':'. /// Parse the expression after ':' - OwningExprResult Res(ParseAssignmentExpression()); + ExprResult Res(ParseAssignmentExpression()); if (Res.isInvalid()) { // We must manually skip to a ']', otherwise the expression skipper will // stop at the ']' when it skips to the ';'. We want it to skip beyond @@ -2022,7 +2051,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, KeyIdents.data(), KeyIdents.size()); else - Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr.get(), + Actions.CodeCompleteObjCInstanceMessage(getCurScope(), ReceiverExpr, KeyIdents.data(), KeyIdents.size()); ConsumeCodeCompletionToken(); @@ -2038,7 +2067,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, while (Tok.is(tok::comma)) { ConsumeToken(); // Eat the ','. /// Parse the expression after ',' - OwningExprResult Res(ParseAssignmentExpression()); + ExprResult Res(ParseAssignmentExpression()); if (Res.isInvalid()) { // We must manually skip to a ']', otherwise the expression skipper will // stop at the ']' when it skips to the ';'. We want it to skip beyond @@ -2082,24 +2111,24 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, if (SuperLoc.isValid()) return Actions.ActOnSuperMessage(getCurScope(), SuperLoc, Sel, LBracLoc, SelectorLoc, RBracLoc, - Action::MultiExprArg(Actions, - KeyExprs.take(), - KeyExprs.size())); + MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); else if (ReceiverType) return Actions.ActOnClassMessage(getCurScope(), ReceiverType, Sel, LBracLoc, SelectorLoc, RBracLoc, - Action::MultiExprArg(Actions, - KeyExprs.take(), - KeyExprs.size())); - return Actions.ActOnInstanceMessage(getCurScope(), move(ReceiverExpr), Sel, + MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); + return Actions.ActOnInstanceMessage(getCurScope(), ReceiverExpr, Sel, LBracLoc, SelectorLoc, RBracLoc, - Action::MultiExprArg(Actions, - KeyExprs.take(), - KeyExprs.size())); + MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); } -Parser::OwningExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { - OwningExprResult Res(ParseStringLiteralExpression()); +ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { + ExprResult Res(ParseStringLiteralExpression()); if (Res.isInvalid()) return move(Res); // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string @@ -2117,7 +2146,7 @@ Parser::OwningExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { if (!isTokenStringLiteral()) return ExprError(Diag(Tok, diag::err_objc_concat_string)); - OwningExprResult Lit(ParseStringLiteralExpression()); + ExprResult Lit(ParseStringLiteralExpression()); if (Lit.isInvalid()) return move(Lit); @@ -2130,7 +2159,7 @@ Parser::OwningExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { /// objc-encode-expression: /// @encode ( type-name ) -Parser::OwningExprResult +ExprResult Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) { assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!"); @@ -2154,7 +2183,7 @@ Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) { /// objc-protocol-expression /// @protocol ( protocol-name ) -Parser::OwningExprResult +ExprResult Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) { SourceLocation ProtoLoc = ConsumeToken(); @@ -2177,8 +2206,7 @@ Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) { /// objc-selector-expression /// @selector '(' objc-keyword-selector ')' -Parser::OwningExprResult -Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { +ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { SourceLocation SelectorLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) @@ -2187,21 +2215,43 @@ Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { llvm::SmallVector KeyIdents; SourceLocation LParenLoc = ConsumeParen(); SourceLocation sLoc; + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(), + KeyIdents.size()); + ConsumeCodeCompletionToken(); + MatchRHSPunctuation(tok::r_paren, LParenLoc); + return ExprError(); + } + IdentifierInfo *SelIdent = ParseObjCSelectorPiece(sLoc); - if (!SelIdent && Tok.isNot(tok::colon)) // missing selector name. + if (!SelIdent && // missing selector name. + Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon)) return ExprError(Diag(Tok, diag::err_expected_ident)); KeyIdents.push_back(SelIdent); unsigned nColons = 0; if (Tok.isNot(tok::r_paren)) { while (1) { - if (Tok.isNot(tok::colon)) + if (Tok.is(tok::coloncolon)) { // Handle :: in C++. + ++nColons; + KeyIdents.push_back(0); + } else if (Tok.isNot(tok::colon)) return ExprError(Diag(Tok, diag::err_expected_colon)); - nColons++; + ++nColons; ConsumeToken(); // Eat the ':'. if (Tok.is(tok::r_paren)) break; + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCSelector(getCurScope(), KeyIdents.data(), + KeyIdents.size()); + ConsumeCodeCompletionToken(); + MatchRHSPunctuation(tok::r_paren, LParenLoc); + return ExprError(); + } + // Check for another keyword selector. SourceLocation Loc; SelIdent = ParseObjCSelectorPiece(Loc); diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index 64a4c16..ddba09a 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -13,11 +13,63 @@ #include "ParsePragma.h" #include "clang/Parse/ParseDiagnostic.h" -#include "clang/Lex/Preprocessor.h" -#include "clang/Parse/Action.h" #include "clang/Parse/Parser.h" +#include "clang/Lex/Preprocessor.h" using namespace clang; + +// #pragma GCC visibility comes in two variants: +// 'push' '(' [visibility] ')' +// 'pop' +void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, Token &VisTok) { + SourceLocation VisLoc = VisTok.getLocation(); + + Token Tok; + PP.Lex(Tok); + + const IdentifierInfo *PushPop = Tok.getIdentifierInfo(); + + bool IsPush; + const IdentifierInfo *VisType; + if (PushPop && PushPop->isStr("pop")) { + IsPush = false; + VisType = 0; + } else if (PushPop && PushPop->isStr("push")) { + IsPush = true; + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) + << "visibility"; + return; + } + PP.Lex(Tok); + VisType = Tok.getIdentifierInfo(); + if (!VisType) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << "visibility"; + return; + } + PP.Lex(Tok); + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) + << "visibility"; + return; + } + } else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << "visibility"; + return; + } + PP.Lex(Tok); + if (Tok.isNot(tok::eom)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << "visibility"; + return; + } + + Actions.ActOnPragmaVisibility(IsPush, VisType, VisLoc); +} + // #pragma pack(...) comes in the following delicious flavors: // pack '(' [integer] ')' // pack '(' 'show' ')' @@ -32,9 +84,9 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) { return; } - Action::PragmaPackKind Kind = Action::PPK_Default; + Sema::PragmaPackKind Kind = Sema::PPK_Default; IdentifierInfo *Name = 0; - Action::OwningExprResult Alignment(Actions); + ExprResult Alignment; SourceLocation LParenLoc = Tok.getLocation(); PP.Lex(Tok); if (Tok.is(tok::numeric_constant)) { @@ -46,13 +98,13 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) { } else if (Tok.is(tok::identifier)) { const IdentifierInfo *II = Tok.getIdentifierInfo(); if (II->isStr("show")) { - Kind = Action::PPK_Show; + Kind = Sema::PPK_Show; PP.Lex(Tok); } else { if (II->isStr("push")) { - Kind = Action::PPK_Push; + Kind = Sema::PPK_Push; } else if (II->isStr("pop")) { - Kind = Action::PPK_Pop; + Kind = Sema::PPK_Pop; } else { PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_invalid_action); return; @@ -110,46 +162,52 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) { LParenLoc, RParenLoc); } -// #pragma 'options' 'align' '=' {'native','natural','mac68k','power','reset'} -void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, Token &OptionsTok) { - SourceLocation OptionsLoc = OptionsTok.getLocation(); - +// #pragma 'align' '=' {'native','natural','mac68k','power','reset'} +// #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'} +static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok, + bool IsOptions) { Token Tok; - PP.Lex(Tok); - if (Tok.isNot(tok::identifier) || !Tok.getIdentifierInfo()->isStr("align")) { - PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align); - return; + + if (IsOptions) { + PP.Lex(Tok); + if (Tok.isNot(tok::identifier) || + !Tok.getIdentifierInfo()->isStr("align")) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align); + return; + } } PP.Lex(Tok); if (Tok.isNot(tok::equal)) { - PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_equal); + PP.Diag(Tok.getLocation(), diag::warn_pragma_align_expected_equal) + << IsOptions; return; } PP.Lex(Tok); if (Tok.isNot(tok::identifier)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) - << "options"; + << (IsOptions ? "options" : "align"); return; } - Action::PragmaOptionsAlignKind Kind = Action::POAK_Natural; + Sema::PragmaOptionsAlignKind Kind = Sema::POAK_Natural; const IdentifierInfo *II = Tok.getIdentifierInfo(); if (II->isStr("native")) - Kind = Action::POAK_Native; + Kind = Sema::POAK_Native; else if (II->isStr("natural")) - Kind = Action::POAK_Natural; + Kind = Sema::POAK_Natural; else if (II->isStr("packed")) - Kind = Action::POAK_Packed; + Kind = Sema::POAK_Packed; else if (II->isStr("power")) - Kind = Action::POAK_Power; + Kind = Sema::POAK_Power; else if (II->isStr("mac68k")) - Kind = Action::POAK_Mac68k; + Kind = Sema::POAK_Mac68k; else if (II->isStr("reset")) - Kind = Action::POAK_Reset; + Kind = Sema::POAK_Reset; else { - PP.Diag(Tok.getLocation(), diag::warn_pragma_options_invalid_option); + PP.Diag(Tok.getLocation(), diag::warn_pragma_align_invalid_option) + << IsOptions; return; } @@ -157,11 +215,19 @@ void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, Token &OptionsTok) { PP.Lex(Tok); if (Tok.isNot(tok::eom)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) - << "options"; + << (IsOptions ? "options" : "align"); return; } - Actions.ActOnPragmaOptionsAlign(Kind, OptionsLoc, KindLoc); + Actions.ActOnPragmaOptionsAlign(Kind, FirstTok.getLocation(), KindLoc); +} + +void PragmaAlignHandler::HandlePragma(Preprocessor &PP, Token &AlignTok) { + ParseAlignPragma(Actions, PP, AlignTok, /*IsOptions=*/false); +} + +void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, Token &OptionsTok) { + ParseAlignPragma(Actions, PP, OptionsTok, /*IsOptions=*/true); } // #pragma unused(identifier) diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h index 929ec46..0feaa99 100644 --- a/lib/Parse/ParsePragma.h +++ b/lib/Parse/ParsePragma.h @@ -17,41 +17,58 @@ #include "clang/Lex/Pragma.h" namespace clang { - class Action; + class Sema; class Parser; +class PragmaAlignHandler : public PragmaHandler { + Sema &Actions; +public: + explicit PragmaAlignHandler(Sema &A) : PragmaHandler("align"), Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); +}; + +class PragmaGCCVisibilityHandler : public PragmaHandler { + Sema &Actions; +public: + explicit PragmaGCCVisibilityHandler(Sema &A) : PragmaHandler("visibility"), + Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); +}; + class PragmaOptionsHandler : public PragmaHandler { - Action &Actions; + Sema &Actions; public: - explicit PragmaOptionsHandler(Action &A) : PragmaHandler("options"), - Actions(A) {} + explicit PragmaOptionsHandler(Sema &A) : PragmaHandler("options"), + Actions(A) {} virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); }; class PragmaPackHandler : public PragmaHandler { - Action &Actions; + Sema &Actions; public: - explicit PragmaPackHandler(Action &A) : PragmaHandler("pack"), - Actions(A) {} + explicit PragmaPackHandler(Sema &A) : PragmaHandler("pack"), + Actions(A) {} virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); }; class PragmaUnusedHandler : public PragmaHandler { - Action &Actions; + Sema &Actions; Parser &parser; public: - PragmaUnusedHandler(Action &A, Parser& p) + PragmaUnusedHandler(Sema &A, Parser& p) : PragmaHandler("unused"), Actions(A), parser(p) {} virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); }; class PragmaWeakHandler : public PragmaHandler { - Action &Actions; + Sema &Actions; public: - explicit PragmaWeakHandler(Action &A) + explicit PragmaWeakHandler(Sema &A) : PragmaHandler("weak"), Actions(A) {} virtual void HandlePragma(Preprocessor &PP, Token &FirstToken); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index c908ed9..6c240e6 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -14,8 +14,9 @@ #include "clang/Parse/Parser.h" #include "RAIIObjectsForParser.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/PrettyDeclStackTrace.h" +#include "clang/Sema/Scope.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Basic/SourceManager.h" @@ -73,10 +74,10 @@ using namespace clang; /// [OBC] '@' 'throw' expression ';' /// [OBC] '@' 'throw' ';' /// -Parser::OwningStmtResult +StmtResult Parser::ParseStatementOrDeclaration(bool OnlyStatement) { const char *SemiError = 0; - OwningStmtResult Res(Actions); + StmtResult Res; ParenBraceBracketBalancer BalancerRAIIObj(*this); @@ -98,7 +99,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { } case tok::code_completion: - Actions.CodeCompleteOrdinaryName(getCurScope(), Action::CCC_Statement); + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Statement); ConsumeCodeCompletionToken(); return ParseStatementOrDeclaration(OnlyStatement); @@ -125,7 +126,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { // FIXME: Use the attributes // expression[opt] ';' - OwningExprResult Expr(ParseExpression()); + ExprResult Expr(ParseExpression()); if (Expr.isInvalid()) { // If the expression is invalid, skip ahead to the next semicolon or '}'. // Not doing this opens us up to the possibility of infinite loops if @@ -137,7 +138,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { } // Otherwise, eat the semicolon. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); - return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr)); + return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get())); } case tok::kw_case: // C99 6.8.1: labeled-statement @@ -217,7 +218,7 @@ Parser::ParseStatementOrDeclaration(bool OnlyStatement) { /// identifier ':' statement /// [GNU] identifier ':' attributes[opt] statement /// -Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { +StmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { assert(Tok.is(tok::identifier) && Tok.getIdentifierInfo() && "Not an identifier!"); @@ -234,7 +235,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { if (Tok.is(tok::kw___attribute)) AttrList.reset(addAttributeLists(AttrList.take(), ParseGNUAttributes())); - OwningStmtResult SubStmt(ParseStatement()); + StmtResult SubStmt(ParseStatement()); // Broken substmt shouldn't prevent the label from being added to the AST. if (SubStmt.isInvalid()) @@ -243,7 +244,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { // FIXME: use attributes? return Actions.ActOnLabelStmt(IdentTok.getLocation(), IdentTok.getIdentifierInfo(), - ColonLoc, move(SubStmt)); + ColonLoc, SubStmt.get()); } /// ParseCaseStatement @@ -251,7 +252,7 @@ Parser::OwningStmtResult Parser::ParseLabeledStatement(AttributeList *Attr) { /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// -Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { +StmtResult Parser::ParseCaseStatement(AttributeList *Attr) { assert(Tok.is(tok::kw_case) && "Not a case stmt!"); // FIXME: Use attributes? delete Attr; @@ -272,7 +273,7 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { // TopLevelCase - This is the highest level we have parsed. 'case 1' in the // example above. - OwningStmtResult TopLevelCase(Actions, true); + StmtResult TopLevelCase(true); // DeepestParsedCaseStmt - This is the deepest statement we have parsed, which // gets updated each time a new case is parsed, and whose body is unset so @@ -293,7 +294,7 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { /// expression. ColonProtectionRAIIObject ColonProtection(*this); - OwningExprResult LHS(ParseConstantExpression()); + ExprResult LHS(ParseConstantExpression()); if (LHS.isInvalid()) { SkipUntil(tok::colon); return StmtError(); @@ -301,7 +302,7 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { // GNU case range extension. SourceLocation DotDotDotLoc; - OwningExprResult RHS(Actions); + ExprResult RHS; if (Tok.is(tok::ellipsis)) { Diag(Tok, diag::ext_gnu_case_range); DotDotDotLoc = ConsumeToken(); @@ -323,9 +324,9 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { SourceLocation ColonLoc = ConsumeToken(); - OwningStmtResult Case = - Actions.ActOnCaseStmt(CaseLoc, move(LHS), DotDotDotLoc, - move(RHS), ColonLoc); + StmtResult Case = + Actions.ActOnCaseStmt(CaseLoc, LHS.get(), DotDotDotLoc, + RHS.get(), ColonLoc); // If we had a sema error parsing this case, then just ignore it and // continue parsing the sub-stmt. @@ -336,11 +337,11 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { } else { // If this is the first case statement we parsed, it becomes TopLevelCase. // Otherwise we link it into the current chain. - StmtTy *NextDeepest = Case.get(); + Stmt *NextDeepest = Case.get(); if (TopLevelCase.isInvalid()) TopLevelCase = move(Case); else - Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, move(Case)); + Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, Case.get()); DeepestParsedCaseStmt = NextDeepest; } @@ -350,7 +351,7 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { assert(!TopLevelCase.isInvalid() && "Should have parsed at least one case!"); // If we found a non-case statement, start by parsing it. - OwningStmtResult SubStmt(Actions); + StmtResult SubStmt; if (Tok.isNot(tok::r_brace)) { SubStmt = ParseStatement(); @@ -367,7 +368,7 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { SubStmt = Actions.ActOnNullStmt(SourceLocation()); // Install the body into the most deeply-nested case. - Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, move(SubStmt)); + Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get()); // Return the top level parsed statement tree. return move(TopLevelCase); @@ -378,7 +379,7 @@ Parser::OwningStmtResult Parser::ParseCaseStatement(AttributeList *Attr) { /// 'default' ':' statement /// Note that this does not parse the 'statement' at the end. /// -Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) { +StmtResult Parser::ParseDefaultStatement(AttributeList *Attr) { //FIXME: Use attributes? delete Attr; @@ -399,12 +400,12 @@ Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) { return StmtError(); } - OwningStmtResult SubStmt(ParseStatement()); + StmtResult SubStmt(ParseStatement()); if (SubStmt.isInvalid()) return StmtError(); return Actions.ActOnDefaultStmt(DefaultLoc, ColonLoc, - move(SubStmt), getCurScope()); + SubStmt.get(), getCurScope()); } @@ -435,7 +436,7 @@ Parser::OwningStmtResult Parser::ParseDefaultStatement(AttributeList *Attr) { /// [OMP] barrier-directive /// [OMP] flush-directive /// -Parser::OwningStmtResult Parser::ParseCompoundStatement(AttributeList *Attr, +StmtResult Parser::ParseCompoundStatement(AttributeList *Attr, bool isStmtExpr) { //FIXME: Use attributes? delete Attr; @@ -455,7 +456,7 @@ Parser::OwningStmtResult Parser::ParseCompoundStatement(AttributeList *Attr, /// ActOnCompoundStmt action. This expects the '{' to be the current token, and /// consume the '}' at the end of the block. It does not manipulate the scope /// stack. -Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { +StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), Tok.getLocation(), "in compound statement ('{}')"); @@ -468,7 +469,7 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { typedef StmtVector StmtsTy; StmtsTy Stmts(Actions); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - OwningStmtResult R(Actions); + StmtResult R; if (Tok.isNot(tok::kw___extension__)) { R = ParseStatementOrDeclaration(false); } else { @@ -496,7 +497,7 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd); } else { // Otherwise this was a unary __extension__ marker. - OwningExprResult Res(ParseExpressionWithLeadingExtension(ExtLoc)); + ExprResult Res(ParseExpressionWithLeadingExtension(ExtLoc)); if (Res.isInvalid()) { SkipUntil(tok::semi); @@ -507,7 +508,7 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { // Eat the semicolon at the end of stmt and convert the expr into a // statement. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_expr); - R = Actions.ActOnExprStmt(Actions.MakeFullExpr(Res)); + R = Actions.ActOnExprStmt(Actions.MakeFullExpr(Res.get())); } } @@ -518,6 +519,7 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { // We broke out of the while loop because we found a '}' or EOF. if (Tok.isNot(tok::r_brace)) { Diag(Tok, diag::err_expected_rbrace); + Diag(LBraceLoc, diag::note_matching) << "{"; return StmtError(); } @@ -537,8 +539,8 @@ Parser::OwningStmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { /// should try to recover harder. It returns false if the condition is /// successfully parsed. Note that a successful parse can still have semantic /// errors in the condition. -bool Parser::ParseParenExprOrCondition(OwningExprResult &ExprResult, - DeclPtrTy &DeclResult, +bool Parser::ParseParenExprOrCondition(ExprResult &ExprResult, + Decl *&DeclResult, SourceLocation Loc, bool ConvertToBoolean) { bool ParseError = false; @@ -549,18 +551,18 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &ExprResult, ConvertToBoolean); else { ExprResult = ParseExpression(); - DeclResult = DeclPtrTy(); + DeclResult = 0; // If required, convert to a boolean value. if (!ExprResult.isInvalid() && ConvertToBoolean) ExprResult - = Actions.ActOnBooleanCondition(getCurScope(), Loc, move(ExprResult)); + = Actions.ActOnBooleanCondition(getCurScope(), Loc, ExprResult.get()); } // If the parser was confused by the condition and we don't have a ')', try to // recover by skipping ahead to a semi and bailing out. If condexp is // semantically invalid but we have well formed code, keep going. - if (ExprResult.isInvalid() && !DeclResult.get() && Tok.isNot(tok::r_paren)) { + if (ExprResult.isInvalid() && !DeclResult && Tok.isNot(tok::r_paren)) { SkipUntil(tok::semi); // Skipping may have stopped if it found the containing ')'. If so, we can // continue parsing the if statement. @@ -581,7 +583,7 @@ bool Parser::ParseParenExprOrCondition(OwningExprResult &ExprResult, /// [C++] 'if' '(' condition ')' statement /// [C++] 'if' '(' condition ')' statement 'else' statement /// -Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { +StmtResult Parser::ParseIfStatement(AttributeList *Attr) { // FIXME: Use attributes? delete Attr; @@ -611,12 +613,12 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX); // Parse the condition. - OwningExprResult CondExp(Actions); - DeclPtrTy CondVar; + ExprResult CondExp; + Decl *CondVar = 0; if (ParseParenExprOrCondition(CondExp, CondVar, IfLoc, true)) return StmtError(); - FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp)); + FullExprArg FullCondExp(Actions.MakeFullExpr(CondExp.get())); // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this @@ -641,7 +643,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { // Read the 'then' stmt. SourceLocation ThenStmtLoc = Tok.getLocation(); - OwningStmtResult ThenStmt(ParseStatement()); + StmtResult ThenStmt(ParseStatement()); // Pop the 'if' scope if needed. InnerScope.Exit(); @@ -649,7 +651,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { // If it has an else, parse it. SourceLocation ElseLoc; SourceLocation ElseStmtLoc; - OwningStmtResult ElseStmt(Actions); + StmtResult ElseStmt; if (Tok.is(tok::kw_else)) { ElseLoc = ConsumeToken(); @@ -667,13 +669,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { ParseScope InnerScope(this, Scope::DeclScope, C99orCXX && Tok.isNot(tok::l_brace)); - // Regardless of whether or not InnerScope actually pushed a scope, set the - // ElseScope flag for the innermost scope so we can diagnose use of the if - // condition variable in C++. - unsigned OldFlags = getCurScope()->getFlags(); - getCurScope()->setFlags(OldFlags | Scope::ElseScope); ElseStmt = ParseStatement(); - getCurScope()->setFlags(OldFlags); // Pop the 'else' scope if needed. InnerScope.Exit(); @@ -683,7 +679,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { // If the condition was invalid, discard the if statement. We could recover // better by replacing it with a valid expr, but don't do that yet. - if (CondExp.isInvalid() && !CondVar.get()) + if (CondExp.isInvalid() && !CondVar) return StmtError(); // If the then or else stmt is invalid and the other is valid (and present), @@ -702,15 +698,15 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { if (ElseStmt.isInvalid()) ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); - return Actions.ActOnIfStmt(IfLoc, FullCondExp, CondVar, move(ThenStmt), - ElseLoc, move(ElseStmt)); + return Actions.ActOnIfStmt(IfLoc, FullCondExp, CondVar, ThenStmt.get(), + ElseLoc, ElseStmt.get()); } /// ParseSwitchStatement /// switch-statement: /// 'switch' '(' expression ')' statement /// [C++] 'switch' '(' condition ')' statement -Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { +StmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { // FIXME: Use attributes? delete Attr; @@ -743,13 +739,13 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { ParseScope SwitchScope(this, ScopeFlags); // Parse the condition. - OwningExprResult Cond(Actions); - DeclPtrTy CondVar; + ExprResult Cond; + Decl *CondVar = 0; if (ParseParenExprOrCondition(Cond, CondVar, SwitchLoc, false)) return StmtError(); - OwningStmtResult Switch - = Actions.ActOnStartOfSwitchStmt(SwitchLoc, move(Cond), CondVar); + StmtResult Switch + = Actions.ActOnStartOfSwitchStmt(SwitchLoc, Cond.get(), CondVar); if (Switch.isInvalid()) { // Skip the switch body. @@ -779,7 +775,7 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { C99orCXX && Tok.isNot(tok::l_brace)); // Read the body statement. - OwningStmtResult Body(ParseStatement()); + StmtResult Body(ParseStatement()); // Pop the scopes. InnerScope.Exit(); @@ -789,14 +785,14 @@ Parser::OwningStmtResult Parser::ParseSwitchStatement(AttributeList *Attr) { // FIXME: Remove the case statement list from the Switch statement. Body = Actions.ActOnNullStmt(Tok.getLocation()); - return Actions.ActOnFinishSwitchStmt(SwitchLoc, move(Switch), move(Body)); + return Actions.ActOnFinishSwitchStmt(SwitchLoc, Switch.get(), Body.get()); } /// ParseWhileStatement /// while-statement: [C99 6.8.5.1] /// 'while' '(' expression ')' statement /// [C++] 'while' '(' condition ')' statement -Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) { +StmtResult Parser::ParseWhileStatement(AttributeList *Attr) { // FIXME: Use attributes? delete Attr; @@ -833,12 +829,12 @@ Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) { ParseScope WhileScope(this, ScopeFlags); // Parse the condition. - OwningExprResult Cond(Actions); - DeclPtrTy CondVar; + ExprResult Cond; + Decl *CondVar = 0; if (ParseParenExprOrCondition(Cond, CondVar, WhileLoc, true)) return StmtError(); - FullExprArg FullCond(Actions.MakeFullExpr(Cond)); + FullExprArg FullCond(Actions.MakeFullExpr(Cond.get())); // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this @@ -855,23 +851,23 @@ Parser::OwningStmtResult Parser::ParseWhileStatement(AttributeList *Attr) { C99orCXX && Tok.isNot(tok::l_brace)); // Read the body statement. - OwningStmtResult Body(ParseStatement()); + StmtResult Body(ParseStatement()); // Pop the body scope if needed. InnerScope.Exit(); WhileScope.Exit(); - if ((Cond.isInvalid() && !CondVar.get()) || Body.isInvalid()) + if ((Cond.isInvalid() && !CondVar) || Body.isInvalid()) return StmtError(); - return Actions.ActOnWhileStmt(WhileLoc, FullCond, CondVar, move(Body)); + return Actions.ActOnWhileStmt(WhileLoc, FullCond, CondVar, Body.get()); } /// ParseDoStatement /// do-statement: [C99 6.8.5.2] /// 'do' statement 'while' '(' expression ')' ';' /// Note: this lets the caller parse the end ';'. -Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) { +StmtResult Parser::ParseDoStatement(AttributeList *Attr) { // FIXME: Use attributes? delete Attr; @@ -901,7 +897,7 @@ Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) { Tok.isNot(tok::l_brace)); // Read the body statement. - OwningStmtResult Body(ParseStatement()); + StmtResult Body(ParseStatement()); // Pop the body scope if needed. InnerScope.Exit(); @@ -924,15 +920,15 @@ Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) { // Parse the parenthesized condition. SourceLocation LPLoc = ConsumeParen(); - OwningExprResult Cond = ParseExpression(); + ExprResult Cond = ParseExpression(); SourceLocation RPLoc = MatchRHSPunctuation(tok::r_paren, LPLoc); DoScope.Exit(); if (Cond.isInvalid() || Body.isInvalid()) return StmtError(); - return Actions.ActOnDoStmt(DoLoc, move(Body), WhileLoc, LPLoc, - move(Cond), RPLoc); + return Actions.ActOnDoStmt(DoLoc, Body.get(), WhileLoc, LPLoc, + Cond.get(), RPLoc); } /// ParseForStatement @@ -948,7 +944,7 @@ Parser::OwningStmtResult Parser::ParseDoStatement(AttributeList *Attr) { /// [C++] expression-statement /// [C++] simple-declaration /// -Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { +StmtResult Parser::ParseForStatement(AttributeList *Attr) { // FIXME: Use attributes? delete Attr; @@ -988,20 +984,20 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { ParseScope ForScope(this, ScopeFlags); SourceLocation LParenLoc = ConsumeParen(); - OwningExprResult Value(Actions); + ExprResult Value; bool ForEach = false; - OwningStmtResult FirstPart(Actions); + StmtResult FirstPart; bool SecondPartIsInvalid = false; FullExprArg SecondPart(Actions); - OwningExprResult Collection(Actions); + ExprResult Collection; FullExprArg ThirdPart(Actions); - DeclPtrTy SecondVar; + Decl *SecondVar = 0; if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), - C99orCXXorObjC? Action::CCC_ForInit - : Action::CCC_Expression); + C99orCXXorObjC? Sema::PCC_ForInit + : Sema::PCC_Expression); ConsumeCodeCompletionToken(); } @@ -1029,6 +1025,11 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { Actions.ActOnForEachDeclStmt(DG); // ObjC: for (id x in expr) ConsumeToken(); // consume 'in' + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCForCollection(getCurScope(), DG); + ConsumeCodeCompletionToken(); + } Collection = ParseExpression(); } else { Diag(Tok, diag::err_expected_semi_for); @@ -1039,12 +1040,17 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { // Turn the expression into a stmt. if (!Value.isInvalid()) - FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value)); + FirstPart = Actions.ActOnExprStmt(Actions.MakeFullExpr(Value.get())); if (Tok.is(tok::semi)) { ConsumeToken(); } else if ((ForEach = isTokIdentifier_in())) { ConsumeToken(); // consume 'in' + + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCForCollection(getCurScope(), DeclGroupPtrTy()); + ConsumeCodeCompletionToken(); + } Collection = ParseExpression(); } else { if (!Value.isInvalid()) Diag(Tok, diag::err_expected_semi_for); @@ -1052,36 +1058,36 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { } } if (!ForEach) { - assert(!SecondPart->get() && "Shouldn't have a second expression yet."); + assert(!SecondPart.get() && "Shouldn't have a second expression yet."); // Parse the second part of the for specifier. if (Tok.is(tok::semi)) { // for (...;; // no second part. } else { - OwningExprResult Second(Actions); + ExprResult Second; if (getLang().CPlusPlus) ParseCXXCondition(Second, SecondVar, ForLoc, true); else { Second = ParseExpression(); if (!Second.isInvalid()) Second = Actions.ActOnBooleanCondition(getCurScope(), ForLoc, - move(Second)); + Second.get()); } SecondPartIsInvalid = Second.isInvalid(); - SecondPart = Actions.MakeFullExpr(Second); + SecondPart = Actions.MakeFullExpr(Second.get()); } if (Tok.is(tok::semi)) { ConsumeToken(); } else { - if (!SecondPartIsInvalid || SecondVar.get()) + if (!SecondPartIsInvalid || SecondVar) Diag(Tok, diag::err_expected_semi_for); SkipUntil(tok::semi); } // Parse the third part of the for specifier. if (Tok.isNot(tok::r_paren)) { // for (...;...;) - OwningExprResult Third = ParseExpression(); - ThirdPart = Actions.MakeFullExpr(Third); + ExprResult Third = ParseExpression(); + ThirdPart = Actions.MakeFullExpr(Third.take()); } } // Match the ')'. @@ -1102,7 +1108,7 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { C99orCXXorObjC && Tok.isNot(tok::l_brace)); // Read the body statement. - OwningStmtResult Body(ParseStatement()); + StmtResult Body(ParseStatement()); // Pop the body scope if needed. InnerScope.Exit(); @@ -1114,14 +1120,14 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { return StmtError(); if (!ForEach) - return Actions.ActOnForStmt(ForLoc, LParenLoc, move(FirstPart), SecondPart, - SecondVar, ThirdPart, RParenLoc, move(Body)); + return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart, + SecondVar, ThirdPart, RParenLoc, Body.take()); // FIXME: It isn't clear how to communicate the late destruction of // C++ temporaries used to create the collection. - return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, move(FirstPart), - move(Collection), RParenLoc, - move(Body)); + return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, FirstPart.take(), + Collection.take(), RParenLoc, + Body.take()); } /// ParseGotoStatement @@ -1131,14 +1137,14 @@ Parser::OwningStmtResult Parser::ParseForStatement(AttributeList *Attr) { /// /// Note: this lets the caller parse the end ';'. /// -Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) { +StmtResult Parser::ParseGotoStatement(AttributeList *Attr) { // FIXME: Use attributes? delete Attr; assert(Tok.is(tok::kw_goto) && "Not a goto stmt!"); SourceLocation GotoLoc = ConsumeToken(); // eat the 'goto'. - OwningStmtResult Res(Actions); + StmtResult Res; if (Tok.is(tok::identifier)) { Res = Actions.ActOnGotoStmt(GotoLoc, Tok.getLocation(), Tok.getIdentifierInfo()); @@ -1147,12 +1153,12 @@ Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) { // GNU indirect goto extension. Diag(Tok, diag::ext_gnu_indirect_goto); SourceLocation StarLoc = ConsumeToken(); - OwningExprResult R(ParseExpression()); + ExprResult R(ParseExpression()); if (R.isInvalid()) { // Skip to the semicolon, but don't consume it. SkipUntil(tok::semi, false, true); return StmtError(); } - Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, move(R)); + Res = Actions.ActOnIndirectGotoStmt(GotoLoc, StarLoc, R.take()); } else { Diag(Tok, diag::err_expected_ident); return StmtError(); @@ -1167,7 +1173,7 @@ Parser::OwningStmtResult Parser::ParseGotoStatement(AttributeList *Attr) { /// /// Note: this lets the caller parse the end ';'. /// -Parser::OwningStmtResult Parser::ParseContinueStatement(AttributeList *Attr) { +StmtResult Parser::ParseContinueStatement(AttributeList *Attr) { // FIXME: Use attributes? delete Attr; @@ -1181,7 +1187,7 @@ Parser::OwningStmtResult Parser::ParseContinueStatement(AttributeList *Attr) { /// /// Note: this lets the caller parse the end ';'. /// -Parser::OwningStmtResult Parser::ParseBreakStatement(AttributeList *Attr) { +StmtResult Parser::ParseBreakStatement(AttributeList *Attr) { // FIXME: Use attributes? delete Attr; @@ -1192,14 +1198,14 @@ Parser::OwningStmtResult Parser::ParseBreakStatement(AttributeList *Attr) { /// ParseReturnStatement /// jump-statement: /// 'return' expression[opt] ';' -Parser::OwningStmtResult Parser::ParseReturnStatement(AttributeList *Attr) { +StmtResult Parser::ParseReturnStatement(AttributeList *Attr) { // FIXME: Use attributes? delete Attr; assert(Tok.is(tok::kw_return) && "Not a return stmt!"); SourceLocation ReturnLoc = ConsumeToken(); // eat the 'return'. - OwningExprResult R(Actions); + ExprResult R; if (Tok.isNot(tok::semi)) { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteReturn(getCurScope()); @@ -1214,12 +1220,12 @@ Parser::OwningStmtResult Parser::ParseReturnStatement(AttributeList *Attr) { return StmtError(); } } - return Actions.ActOnReturnStmt(ReturnLoc, move(R)); + return Actions.ActOnReturnStmt(ReturnLoc, R.take()); } /// FuzzyParseMicrosoftAsmStatement. When -fms-extensions is enabled, this /// routine is called to skip/ignore tokens that comprise the MS asm statement. -Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() { +StmtResult Parser::FuzzyParseMicrosoftAsmStatement() { if (Tok.is(tok::l_brace)) { unsigned short savedBraceCount = BraceCount; do { @@ -1240,16 +1246,16 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() { } Token t; t.setKind(tok::string_literal); - t.setLiteralData("\"FIXME: not done\""); + t.setLiteralData("\"/*FIXME: not done*/\""); t.clearFlag(Token::NeedsCleaning); - t.setLength(17); - OwningExprResult AsmString(Actions.ActOnStringLiteral(&t, 1)); + t.setLength(21); + ExprResult AsmString(Actions.ActOnStringLiteral(&t, 1)); ExprVector Constraints(Actions); ExprVector Exprs(Actions); ExprVector Clobbers(Actions); return Actions.ActOnAsmStmt(Tok.getLocation(), true, true, 0, 0, 0, move_arg(Constraints), move_arg(Exprs), - move(AsmString), move_arg(Clobbers), + AsmString.take(), move_arg(Clobbers), Tok.getLocation(), true); } @@ -1280,7 +1286,7 @@ Parser::OwningStmtResult Parser::FuzzyParseMicrosoftAsmStatement() { /// assembly-instruction ';'[opt] /// assembly-instruction-list ';' assembly-instruction ';'[opt] /// -Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { +StmtResult Parser::ParseAsmStatement(bool &msAsm) { assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); SourceLocation AsmLoc = ConsumeToken(); @@ -1307,7 +1313,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { } Loc = ConsumeParen(); - OwningExprResult AsmString(ParseAsmStringLiteral()); + ExprResult AsmString(ParseAsmStringLiteral()); if (AsmString.isInvalid()) return StmtError(); @@ -1322,7 +1328,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { return Actions.ActOnAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, /*NumOutputs*/ 0, /*NumInputs*/ 0, 0, move_arg(Constraints), move_arg(Exprs), - move(AsmString), move_arg(Clobbers), + AsmString.take(), move_arg(Clobbers), RParenLoc); } @@ -1367,17 +1373,19 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { if (!AteExtraColon) ConsumeToken(); - // Parse the asm-string list for clobbers. - while (1) { - OwningExprResult Clobber(ParseAsmStringLiteral()); + // Parse the asm-string list for clobbers if present. + if (Tok.isNot(tok::r_paren)) { + while (1) { + ExprResult Clobber(ParseAsmStringLiteral()); - if (Clobber.isInvalid()) - break; + if (Clobber.isInvalid()) + break; - Clobbers.push_back(Clobber.release()); + Clobbers.push_back(Clobber.release()); - if (Tok.isNot(tok::comma)) break; - ConsumeToken(); + if (Tok.isNot(tok::comma)) break; + ConsumeToken(); + } } } @@ -1385,7 +1393,7 @@ Parser::OwningStmtResult Parser::ParseAsmStatement(bool &msAsm) { return Actions.ActOnAsmStmt(AsmLoc, false, isVolatile, NumOutputs, NumInputs, Names.data(), move_arg(Constraints), move_arg(Exprs), - move(AsmString), move_arg(Clobbers), + AsmString.take(), move_arg(Clobbers), RParenLoc); } @@ -1428,7 +1436,7 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, } else Names.push_back(0); - OwningExprResult Constraint(ParseAsmStringLiteral()); + ExprResult Constraint(ParseAsmStringLiteral()); if (Constraint.isInvalid()) { SkipUntil(tok::r_paren); return true; @@ -1443,7 +1451,7 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, // Read the parenthesized expression. SourceLocation OpenLoc = ConsumeParen(); - OwningExprResult Res(ParseExpression()); + ExprResult Res(ParseExpression()); MatchRHSPunctuation(tok::r_paren, OpenLoc); if (Res.isInvalid()) { SkipUntil(tok::r_paren); @@ -1458,25 +1466,24 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, return true; } -Parser::DeclPtrTy Parser::ParseFunctionStatementBody(DeclPtrTy Decl) { +Decl *Parser::ParseFunctionStatementBody(Decl *Decl) { assert(Tok.is(tok::l_brace)); SourceLocation LBraceLoc = Tok.getLocation(); - PrettyStackTraceActionsDecl CrashInfo(Decl, LBraceLoc, Actions, - PP.getSourceManager(), - "parsing function body"); + PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc, + "parsing function body"); // Do not enter a scope for the brace, as the arguments are in the same scope // (the function body) as the body itself. Instead, just read the statement // list and put it into a CompoundStmt for safe keeping. - OwningStmtResult FnBody(ParseCompoundStatementBody()); + StmtResult FnBody(ParseCompoundStatementBody()); // If the function body could not be parsed, make a bogus compoundstmt. if (FnBody.isInvalid()) FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, MultiStmtArg(Actions), false); - return Actions.ActOnFinishFunctionBody(Decl, move(FnBody)); + return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); } /// ParseFunctionTryBlock - Parse a C++ function-try-block. @@ -1484,27 +1491,26 @@ Parser::DeclPtrTy Parser::ParseFunctionStatementBody(DeclPtrTy Decl) { /// function-try-block: /// 'try' ctor-initializer[opt] compound-statement handler-seq /// -Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) { +Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { assert(Tok.is(tok::kw_try) && "Expected 'try'"); SourceLocation TryLoc = ConsumeToken(); - PrettyStackTraceActionsDecl CrashInfo(Decl, TryLoc, Actions, - PP.getSourceManager(), - "parsing function try block"); + PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, TryLoc, + "parsing function try block"); // Constructor initializer list? if (Tok.is(tok::colon)) ParseConstructorInitializer(Decl); SourceLocation LBraceLoc = Tok.getLocation(); - OwningStmtResult FnBody(ParseCXXTryBlockCommon(TryLoc)); + StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc)); // If we failed to parse the try-catch, we just give the function an empty // compound statement as the body. if (FnBody.isInvalid()) FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, MultiStmtArg(Actions), false); - return Actions.ActOnFinishFunctionBody(Decl, move(FnBody)); + return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); } /// ParseCXXTryBlock - Parse a C++ try-block. @@ -1512,7 +1518,7 @@ Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) { /// try-block: /// 'try' compound-statement handler-seq /// -Parser::OwningStmtResult Parser::ParseCXXTryBlock(AttributeList* Attr) { +StmtResult Parser::ParseCXXTryBlock(AttributeList* Attr) { // FIXME: Add attributes? delete Attr; @@ -1534,11 +1540,11 @@ Parser::OwningStmtResult Parser::ParseCXXTryBlock(AttributeList* Attr) { /// handler-seq: /// handler handler-seq[opt] /// -Parser::OwningStmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { +StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? - OwningStmtResult TryBlock(ParseCompoundStatement(0)); + StmtResult TryBlock(ParseCompoundStatement(0)); if (TryBlock.isInvalid()) return move(TryBlock); @@ -1551,7 +1557,7 @@ Parser::OwningStmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Tok.isNot(tok::kw_catch)) return StmtError(Diag(Tok, diag::err_expected_catch)); while (Tok.is(tok::kw_catch)) { - OwningStmtResult Handler(ParseCXXCatchBlock()); + StmtResult Handler(ParseCXXCatchBlock()); if (!Handler.isInvalid()) Handlers.push_back(Handler.release()); } @@ -1560,7 +1566,7 @@ Parser::OwningStmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Handlers.empty()) return StmtError(); - return Actions.ActOnCXXTryBlock(TryLoc, move(TryBlock), move_arg(Handlers)); + return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), move_arg(Handlers)); } /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard @@ -1574,7 +1580,7 @@ Parser::OwningStmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { /// type-specifier-seq /// '...' /// -Parser::OwningStmtResult Parser::ParseCXXCatchBlock() { +StmtResult Parser::ParseCXXCatchBlock() { assert(Tok.is(tok::kw_catch) && "Expected 'catch'"); SourceLocation CatchLoc = ConsumeToken(); @@ -1590,7 +1596,7 @@ Parser::OwningStmtResult Parser::ParseCXXCatchBlock() { // exception-declaration is equivalent to '...' or a parameter-declaration // without default arguments. - DeclPtrTy ExceptionDecl; + Decl *ExceptionDecl = 0; if (Tok.isNot(tok::ellipsis)) { DeclSpec DS; if (ParseCXXTypeSpecifierSeq(DS)) @@ -1608,9 +1614,9 @@ Parser::OwningStmtResult Parser::ParseCXXCatchBlock() { return StmtError(Diag(Tok, diag::err_expected_lbrace)); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? - OwningStmtResult Block(ParseCompoundStatement(0)); + StmtResult Block(ParseCompoundStatement(0)); if (Block.isInvalid()) return move(Block); - return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, move(Block)); + return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.take()); } diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index e1aaf91..dfb4785 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -13,15 +13,15 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" -#include "clang/Parse/Template.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/Scope.h" #include "RAIIObjectsForParser.h" using namespace clang; /// \brief Parse a template declaration, explicit instantiation, or /// explicit specialization. -Parser::DeclPtrTy +Decl * Parser::ParseDeclarationStartingWithTemplate(unsigned Context, SourceLocation &DeclEnd, AccessSpecifier AS) { @@ -70,7 +70,7 @@ namespace { /// /// explicit-specialization: [ C++ temp.expl.spec] /// 'template' '<' '>' declaration -Parser::DeclPtrTy +Decl * Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, SourceLocation &DeclEnd, AccessSpecifier AS) { @@ -80,6 +80,10 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // Enter template-parameter scope. ParseScope TemplateParmScope(this, Scope::TemplateParamScope); + // Tell the action that names should be checked in the context of + // the declaration to come. + ParsingDeclRAIIObject ParsingTemplateParams(*this); + // Parse multiple levels of template headers within this template // parameter scope, e.g., // @@ -118,19 +122,19 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, TemplateLoc = ConsumeToken(); } else { Diag(Tok.getLocation(), diag::err_expected_template); - return DeclPtrTy(); + return 0; } // Parse the '<' template-parameter-list '>' SourceLocation LAngleLoc, RAngleLoc; - TemplateParameterList TemplateParams; + llvm::SmallVector TemplateParams; if (ParseTemplateParameters(Depth, TemplateParams, LAngleLoc, RAngleLoc)) { // Skip until the semi-colon or a }. SkipUntil(tok::r_brace, true, true); if (Tok.is(tok::semi)) ConsumeToken(); - return DeclPtrTy(); + return 0; } ParamLists.push_back( @@ -152,6 +156,7 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty), + ParsingTemplateParams, DeclEnd, AS); } @@ -175,10 +180,11 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, /// declaration. Will be AS_none for namespace-scope declarations. /// /// \returns the new declaration. -Parser::DeclPtrTy +Decl * Parser::ParseSingleDeclarationAfterTemplate( unsigned Context, const ParsedTemplateInfo &TemplateInfo, + ParsingDeclRAIIObject &DiagsFromTParams, SourceLocation &DeclEnd, AccessSpecifier AS) { assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && @@ -186,12 +192,13 @@ Parser::ParseSingleDeclarationAfterTemplate( if (Context == Declarator::MemberContext) { // We are parsing a member template. - ParseCXXClassMemberDeclaration(AS, TemplateInfo); - return DeclPtrTy::make((void*)0); + ParseCXXClassMemberDeclaration(AS, TemplateInfo, &DiagsFromTParams); + return 0; } - // Parse the declaration specifiers. - ParsingDeclSpec DS(*this); + // Parse the declaration specifiers, stealing the accumulated + // diagnostics from the template parameters. + ParsingDeclSpec DS(DiagsFromTParams); if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) DS.AddAttributes(ParseCXX0XAttributes().AttrList); @@ -201,7 +208,7 @@ Parser::ParseSingleDeclarationAfterTemplate( if (Tok.is(tok::semi)) { DeclEnd = ConsumeToken(); - DeclPtrTy Decl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); + Decl *Decl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); DS.complete(Decl); return Decl; } @@ -215,14 +222,14 @@ Parser::ParseSingleDeclarationAfterTemplate( SkipUntil(tok::r_brace, true, true); if (Tok.is(tok::semi)) ConsumeToken(); - return DeclPtrTy(); + return 0; } // If we have a declaration or declarator list, handle it. if (isDeclarationAfterDeclarator()) { // Parse this declaration. - DeclPtrTy ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo, - TemplateInfo); + Decl *ThisDecl = ParseDeclarationAfterDeclarator(DeclaratorInfo, + TemplateInfo); if (Tok.is(tok::comma)) { Diag(Tok, diag::err_multiple_template_declarators) @@ -251,7 +258,7 @@ Parser::ParseSingleDeclarationAfterTemplate( } else { SkipUntil(tok::semi); } - return DeclPtrTy(); + return 0; } return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo); } @@ -261,7 +268,7 @@ Parser::ParseSingleDeclarationAfterTemplate( else Diag(Tok, diag::err_invalid_token_after_toplevel_declarator); SkipUntil(tok::semi); - return DeclPtrTy(); + return 0; } /// ParseTemplateParameters - Parses a template-parameter-list enclosed in @@ -274,7 +281,7 @@ Parser::ParseSingleDeclarationAfterTemplate( /// /// \returns true if an error occurred, false otherwise. bool Parser::ParseTemplateParameters(unsigned Depth, - TemplateParameterList &TemplateParams, + llvm::SmallVectorImpl &TemplateParams, SourceLocation &LAngleLoc, SourceLocation &RAngleLoc) { // Get the template parameter list. @@ -307,9 +314,9 @@ bool Parser::ParseTemplateParameters(unsigned Depth, /// template-parameter-list ',' template-parameter bool Parser::ParseTemplateParameterList(unsigned Depth, - TemplateParameterList &TemplateParams) { + llvm::SmallVectorImpl &TemplateParams) { while (1) { - if (DeclPtrTy TmpParam + if (Decl *TmpParam = ParseTemplateParameter(Depth, TemplateParams.size())) { TemplateParams.push_back(TmpParam); } else { @@ -414,8 +421,7 @@ bool Parser::isStartOfTemplateTypeParameter() { /// 'typename' identifier[opt] '=' type-id /// 'template' ...[opt][C++0x] '<' template-parameter-list '>' 'class' identifier[opt] /// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression -Parser::DeclPtrTy -Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { +Decl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { if (isStartOfTemplateTypeParameter()) return ParseTypeParameter(Depth, Position); @@ -437,7 +443,7 @@ Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { /// 'class' identifier[opt] '=' type-id /// 'typename' ...[opt][C++0x] identifier[opt] /// 'typename' identifier[opt] '=' type-id -Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){ +Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { assert((Tok.is(tok::kw_class) || Tok.is(tok::kw_typename)) && "A type-parameter starts with 'class' or 'typename'"); @@ -468,14 +474,14 @@ Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){ // don't consume this token. } else { Diag(Tok.getLocation(), diag::err_expected_ident); - return DeclPtrTy(); + return 0; } // Grab a default argument (if available). // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before // we introduce the type parameter into the local scope. SourceLocation EqualLoc; - TypeTy *DefaultArg = 0; + ParsedType DefaultArg; if (Tok.is(tok::equal)) { EqualLoc = ConsumeToken(); DefaultArg = ParseTypeName().get(); @@ -492,19 +498,19 @@ Parser::DeclPtrTy Parser::ParseTypeParameter(unsigned Depth, unsigned Position){ /// type-parameter: [C++ temp.param] /// 'template' '<' template-parameter-list '>' 'class' identifier[opt] /// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression -Parser::DeclPtrTy +Decl * Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { assert(Tok.is(tok::kw_template) && "Expected 'template' keyword"); // Handle the template <...> part. SourceLocation TemplateLoc = ConsumeToken(); - TemplateParameterList TemplateParams; + llvm::SmallVector TemplateParams; SourceLocation LAngleLoc, RAngleLoc; { ParseScope TemplateParmScope(this, Scope::TemplateParamScope); if (ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc, RAngleLoc)) { - return DeclPtrTy(); + return 0; } } @@ -513,7 +519,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { if (!Tok.is(tok::kw_class)) { Diag(Tok.getLocation(), diag::err_expected_class_before) << PP.getSpelling(Tok); - return DeclPtrTy(); + return 0; } SourceLocation ClassLoc = ConsumeToken(); @@ -528,7 +534,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { // don't consume this token. } else { Diag(Tok.getLocation(), diag::err_expected_ident); - return DeclPtrTy(); + return 0; } TemplateParamsTy *ParamList = @@ -568,7 +574,7 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { /// template-parameter: /// ... /// parameter-declaration -Parser::DeclPtrTy +Decl * Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { SourceLocation StartLoc = Tok.getLocation(); @@ -581,21 +587,21 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { // Parse this as a typename. Declarator ParamDecl(DS, Declarator::TemplateParamContext); ParseDeclarator(ParamDecl); - if (DS.getTypeSpecType() == DeclSpec::TST_unspecified && !DS.getTypeRep()) { + if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { // This probably shouldn't happen - and it's more of a Sema thing, but // basically we didn't parse the type name because we couldn't associate // it with an AST node. we should just skip to the comma or greater. // TODO: This is currently a placeholder for some kind of Sema Error. Diag(Tok.getLocation(), diag::err_parse_error); SkipUntil(tok::comma, tok::greater, true, true); - return DeclPtrTy(); + return 0; } // If there is a default value, parse it. // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before // we introduce the template parameter into the local scope. SourceLocation EqualLoc; - OwningExprResult DefaultArg(Actions); + ExprResult DefaultArg; if (Tok.is(tok::equal)) { EqualLoc = ConsumeToken(); @@ -614,7 +620,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { // Create the parameter. return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl, Depth, Position, EqualLoc, - move(DefaultArg)); + DefaultArg.take()); } /// \brief Parses a template-id that after the template name has @@ -766,7 +772,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // Build the annotation token. if (TNK == TNK_Type_template && AllowTypeAnnotation) { - Action::TypeResult Type + TypeResult Type = Actions.ActOnTemplateIdType(Template, TemplateNameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc); @@ -779,7 +785,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, } Tok.setKind(tok::annot_typename); - Tok.setAnnotationValue(Type.get()); + setTypeAnnotation(Tok, Type.get()); if (SS && SS->isNotEmpty()) Tok.setLocation(SS->getBeginLoc()); else if (TemplateKWLoc.isValid()) @@ -800,7 +806,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateId->Name = 0; TemplateId->Operator = TemplateName.OperatorFunctionId.Operator; } - TemplateId->Template = Template.getAs(); + TemplateId->Template = Template; TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; TemplateId->RAngleLoc = RAngleLoc; @@ -844,15 +850,15 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { TemplateId->getTemplateArgs(), TemplateId->NumArgs); - Action::TypeResult Type - = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + TypeResult Type + = Actions.ActOnTemplateIdType(TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc); // Create the new "type" annotation token. Tok.setKind(tok::annot_typename); - Tok.setAnnotationValue(Type.isInvalid()? 0 : Type.get()); + setTypeAnnotation(Tok, Type.isInvalid() ? ParsedType() : Type.get()); if (SS && SS->isNotEmpty()) // it was a C++ qualified type name. Tok.setLocation(SS->getBeginLoc()); // End location stays the same @@ -887,7 +893,7 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { // followed by a token that terminates a template argument, such as ',', // '>', or (in some cases) '>>'. CXXScopeSpec SS; // nested-name-specifier, if present - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); if (SS.isSet() && Tok.is(tok::kw_template)) { @@ -906,8 +912,9 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { // template argument. TemplateTy Template; if (isEndOfTemplateArgument(Tok) && - Actions.ActOnDependentTemplateName(getCurScope(), TemplateLoc, SS, Name, - /*ObjectType=*/0, + Actions.ActOnDependentTemplateName(getCurScope(), TemplateLoc, + SS, Name, + /*ObjectType=*/ ParsedType(), /*EnteringContext=*/false, Template)) return ParsedTemplateArgument(SS, Template, Name.StartLocation); @@ -921,8 +928,10 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { if (isEndOfTemplateArgument(Tok)) { bool MemberOfUnknownSpecialization; - TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, Name, - /*ObjectType=*/0, + TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, + Name, + /*ObjectType=*/ ParsedType(), /*EnteringContext=*/false, Template, MemberOfUnknownSpecialization); @@ -957,7 +966,8 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { if (TypeArg.isInvalid()) return ParsedTemplateArgument(); - return ParsedTemplateArgument(ParsedTemplateArgument::Type, TypeArg.get(), + return ParsedTemplateArgument(ParsedTemplateArgument::Type, + TypeArg.get().getAsOpaquePtr(), Loc); } @@ -978,7 +988,7 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { // Parse a non-type template argument. SourceLocation Loc = Tok.getLocation(); - OwningExprResult ExprArg = ParseConstantExpression(); + ExprResult ExprArg = ParseConstantExpression(); if (ExprArg.isInvalid() || !ExprArg.get()) return ParsedTemplateArgument(); @@ -1053,12 +1063,15 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { /// 'extern' [opt] 'template' declaration /// /// Note that the 'extern' is a GNU extension and C++0x feature. -Parser::DeclPtrTy -Parser::ParseExplicitInstantiation(SourceLocation ExternLoc, - SourceLocation TemplateLoc, - SourceLocation &DeclEnd) { +Decl *Parser::ParseExplicitInstantiation(SourceLocation ExternLoc, + SourceLocation TemplateLoc, + SourceLocation &DeclEnd) { + // This isn't really required here. + ParsingDeclRAIIObject ParsingTemplateParams(*this); + return ParseSingleDeclarationAfterTemplate(Declarator::FileContext, ParsedTemplateInfo(ExternLoc, TemplateLoc), + ParsingTemplateParams, DeclEnd, AS_none); } diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 5e64e61..c22d99f 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -14,7 +14,7 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" -#include "clang/Parse/Template.h" +#include "clang/Sema/ParsedTemplate.h" using namespace clang; /// isCXXDeclarationStatement - C++-specialized function that disambiguates @@ -172,14 +172,6 @@ Parser::TPResult Parser::TryParseSimpleDeclaration() { /// '{' '}' /// Parser::TPResult Parser::TryParseInitDeclaratorList() { - // GCC only examines the first declarator for disambiguation: - // i.e: - // int(x), ++x; // GCC regards it as ill-formed declaration. - // - // Comeau and MSVC will regard the above statement as correct expression. - // Clang examines all of the declarators and also regards the above statement - // as correct expression. - while (1) { // declarator TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/); @@ -196,15 +188,22 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() { ConsumeParen(); if (!SkipUntil(tok::r_paren)) return TPResult::Error(); - } else if (Tok.is(tok::equal)) { - // MSVC won't examine the rest of declarators if '=' is encountered, it - // will conclude that it is a declaration. - // Comeau and Clang will examine the rest of declarators. - // Note that "int(x) = {0}, ++x;" will be interpreted as ill-formed - // expression. + } else if (Tok.is(tok::equal) || isTokIdentifier_in()) { + // MSVC and g++ won't examine the rest of declarators if '=' is + // encountered; they just conclude that we have a declaration. + // EDG parses the initializer completely, which is the proper behavior + // for this case. // - // Parse through the initializer-clause. - SkipUntil(tok::comma, true/*StopAtSemi*/, true/*DontConsume*/); + // At present, Clang follows MSVC and g++, since the parser does not have + // the ability to parse an expression fully without recording the + // results of that parse. + // Also allow 'in' after on objective-c declaration as in: + // for (int (^b)(void) in array). Ideally this should be done in the + // context of parsing for-init-statement of a foreach statement only. But, + // in any other context 'in' is invalid after a declaration and parser + // issues the error regardless of outcome of this decision. + // FIXME. Change if above assumption does not hold. + return TPResult::True(); } if (Tok.isNot(tok::comma)) @@ -758,6 +757,10 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw___ptr64: case tok::kw___forceinline: return TPResult::True(); + + // Borland + case tok::kw___pascal: + return TPResult::True(); // AltiVec case tok::kw___vector: diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index ac78f11..44bd0fb 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -13,15 +13,15 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Scope.h" -#include "clang/Parse/Template.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ParsedTemplate.h" #include "llvm/Support/raw_ostream.h" #include "RAIIObjectsForParser.h" #include "ParsePragma.h" using namespace clang; -Parser::Parser(Preprocessor &pp, Action &actions) +Parser::Parser(Preprocessor &pp, Sema &actions) : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()), GreaterThanIsOperator(true), ColonIsSacred(false), TemplateParameterDepth(0) { @@ -29,10 +29,16 @@ Parser::Parser(Preprocessor &pp, Action &actions) Actions.CurScope = 0; NumCachedScopes = 0; ParenCount = BracketCount = BraceCount = 0; - ObjCImpDecl = DeclPtrTy(); + ObjCImpDecl = 0; // Add #pragma handlers. These are removed and destroyed in the // destructor. + AlignHandler.reset(new PragmaAlignHandler(actions)); + PP.AddPragmaHandler(AlignHandler.get()); + + GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler(actions)); + PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get()); + OptionsHandler.reset(new PragmaOptionsHandler(actions)); PP.AddPragmaHandler(OptionsHandler.get()); @@ -44,6 +50,8 @@ Parser::Parser(Preprocessor &pp, Action &actions) WeakHandler.reset(new PragmaWeakHandler(actions)); PP.AddPragmaHandler(WeakHandler.get()); + + PP.setCodeCompletionHandler(*this); } /// If a crash happens while the parser is active, print out a line indicating @@ -298,6 +306,10 @@ Parser::~Parser() { delete ScopeCache[i]; // Remove the pragma handlers we installed. + PP.RemovePragmaHandler(AlignHandler.get()); + AlignHandler.reset(); + PP.RemovePragmaHandler("GCC", GCCVisibilityHandler.get()); + GCCVisibilityHandler.reset(); PP.RemovePragmaHandler(OptionsHandler.get()); OptionsHandler.reset(); PP.RemovePragmaHandler(PackHandler.get()); @@ -306,18 +318,19 @@ Parser::~Parser() { UnusedHandler.reset(); PP.RemovePragmaHandler(WeakHandler.get()); WeakHandler.reset(); + PP.clearCodeCompletionHandler(); } /// Initialize - Warm up the parser. /// void Parser::Initialize() { - // Prime the lexer look-ahead. - ConsumeToken(); - // Create the translation unit scope. Install it as the current scope. assert(getCurScope() == 0 && "A scope is already active?"); EnterScope(Scope::DeclScope); - Actions.ActOnTranslationUnitScope(Tok.getLocation(), getCurScope()); + Actions.ActOnTranslationUnitScope(getCurScope()); + + // Prime the lexer look-ahead. + ConsumeToken(); if (Tok.is(tok::eof) && !getLang().CPlusPlus) // Empty source file is an extension in C @@ -395,10 +408,11 @@ void Parser::ParseTranslationUnit() { /// ';' /// /// [C++0x/GNU] 'extern' 'template' declaration -Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) { +Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr, + ParsingDeclSpec *DS) { ParenBraceBracketBalancer BalancerRAIIObj(*this); - DeclPtrTy SingleDecl; + Decl *SingleDecl = 0; switch (Tok.getKind()) { case tok::semi: if (!getLang().CPlusPlus0x) @@ -426,14 +440,14 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) Diag(Attr.Range.getBegin(), diag::err_attributes_not_allowed) << Attr.Range; - OwningExprResult Result(ParseSimpleAsm()); + ExprResult Result(ParseSimpleAsm()); ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "top-level asm block"); if (Result.isInvalid()) return DeclGroupPtrTy(); - SingleDecl = Actions.ActOnFileScopeAsmDecl(Tok.getLocation(), move(Result)); + SingleDecl = Actions.ActOnFileScopeAsmDecl(Tok.getLocation(), Result.get()); break; } case tok::at: @@ -453,8 +467,8 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) break; case tok::code_completion: Actions.CodeCompleteOrdinaryName(getCurScope(), - ObjCImpDecl? Action::CCC_ObjCImplementation - : Action::CCC_Namespace); + ObjCImpDecl? Sema::PCC_ObjCImplementation + : Sema::PCC_Namespace); ConsumeCodeCompletionToken(); return ParseExternalDeclaration(Attr); case tok::kw_using: @@ -468,6 +482,15 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) SourceLocation DeclEnd; return ParseDeclaration(Declarator::FileContext, DeclEnd, Attr); } + + case tok::kw_inline: + if (getLang().CPlusPlus && NextToken().is(tok::kw_namespace)) { + // Inline namespaces. Allowed as an extension even in C++03. + SourceLocation DeclEnd; + return ParseDeclaration(Declarator::FileContext, DeclEnd, Attr); + } + goto dont_know; + case tok::kw_extern: if (getLang().CPlusPlus && NextToken().is(tok::kw_template)) { // Extern templates @@ -477,14 +500,16 @@ Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(CXX0XAttributeList Attr) return Actions.ConvertDeclToDeclGroup( ParseExplicitInstantiation(ExternLoc, TemplateLoc, DeclEnd)); } - // FIXME: Detect C++ linkage specifications here? - - // Fall through to handle other declarations or function definitions. + goto dont_know; default: + dont_know: // We can't tell whether this is a function-definition or declaration yet. - return ParseDeclarationOrFunctionDefinition(Attr.AttrList); + if (DS) + return ParseDeclarationOrFunctionDefinition(*DS, Attr.AttrList); + else + return ParseDeclarationOrFunctionDefinition(Attr.AttrList); } // This routine returns a DeclGroup, if the thing we parsed only contains a @@ -551,7 +576,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { ConsumeToken(); - DeclPtrTy TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); + Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS, DS); DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -575,7 +600,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, if (DS.SetTypeSpecType(DeclSpec::TST_unspecified, AtLoc, PrevSpec, DiagID)) Diag(AtLoc, DiagID) << PrevSpec; - DeclPtrTy TheDecl; + Decl *TheDecl = 0; if (Tok.isObjCAtKeyword(tok::objc_protocol)) TheDecl = ParseObjCAtProtocolDeclaration(AtLoc, DS.getAttributes()); else @@ -589,7 +614,7 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, if (Tok.is(tok::string_literal) && getLang().CPlusPlus && DS.getStorageClassSpec() == DeclSpec::SCS_extern && DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { - DeclPtrTy TheDecl = ParseLinkage(DS, Declarator::FileContext); + Decl *TheDecl = ParseLinkage(DS, Declarator::FileContext); return Actions.ConvertDeclToDeclGroup(TheDecl); } @@ -617,7 +642,7 @@ Parser::ParseDeclarationOrFunctionDefinition(AttributeList *Attr, /// [C++] function-definition: [C++ 8.4] /// decl-specifier-seq[opt] declarator function-try-block /// -Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D, +Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo) { const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0); assert(FnTypeInfo.Kind == DeclaratorChunk::Function && @@ -653,7 +678,7 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D, // If we didn't find the '{', bail out. if (Tok.isNot(tok::l_brace)) - return DeclPtrTy(); + return 0; } // Enter a scope for the function body. @@ -661,9 +686,9 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D, // Tell the actions module that we have entered a function definition with the // specified Declarator for the function. - DeclPtrTy Res = TemplateInfo.TemplateParams? + Decl *Res = TemplateInfo.TemplateParams? Actions.ActOnStartOfFunctionTemplateDef(getCurScope(), - Action::MultiTemplateParamsArg(Actions, + MultiTemplateParamsArg(Actions, TemplateInfo.TemplateParams->data(), TemplateInfo.TemplateParams->size()), D) @@ -686,7 +711,7 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D, // Recover from error. if (!Tok.is(tok::l_brace)) { - Actions.ActOnFinishFunctionBody(Res, Action::StmtArg(Actions)); + Actions.ActOnFinishFunctionBody(Res, 0); return Res; } } else @@ -752,7 +777,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { } // Ask the actions module to compute the type for this declarator. - Action::DeclPtrTy Param = + Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDeclarator); if (Param && @@ -819,13 +844,13 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { /// [GNU] asm-string-literal: /// string-literal /// -Parser::OwningExprResult Parser::ParseAsmStringLiteral() { +Parser::ExprResult Parser::ParseAsmStringLiteral() { if (!isTokenStringLiteral()) { Diag(Tok, diag::err_expected_string_literal); return ExprError(); } - OwningExprResult Res(ParseStringLiteralExpression()); + ExprResult Res(ParseStringLiteralExpression()); if (Res.isInvalid()) return move(Res); // TODO: Diagnose: wide string literal in 'asm' @@ -838,7 +863,7 @@ Parser::OwningExprResult Parser::ParseAsmStringLiteral() { /// [GNU] simple-asm-expr: /// 'asm' '(' asm-string-literal ')' /// -Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { +Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { assert(Tok.is(tok::kw_asm) && "Not an asm!"); SourceLocation Loc = ConsumeToken(); @@ -859,7 +884,7 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { Loc = ConsumeParen(); - OwningExprResult Result(ParseAsmStringLiteral()); + ExprResult Result(ParseAsmStringLiteral()); if (Result.isInvalid()) { SkipUntil(tok::r_paren, true, true); @@ -911,7 +936,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { // simple-template-id SourceLocation TypenameLoc = ConsumeToken(); CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, false)) + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(), false)) return true; if (!SS.isSet()) { Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); @@ -939,7 +964,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { if (Tok.getAnnotationValue()) Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS, SourceLocation(), - Tok.getAnnotationValue()); + getTypeAnnotation(Tok)); else Ty = true; } else { @@ -950,7 +975,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { SourceLocation EndLoc = Tok.getLastLoc(); Tok.setKind(tok::annot_typename); - Tok.setAnnotationValue(Ty.isInvalid()? 0 : Ty.get()); + setTypeAnnotation(Tok, Ty.isInvalid() ? ParsedType() : Ty.get()); Tok.setAnnotationEndLoc(EndLoc); Tok.setLocation(TypenameLoc); PP.AnnotateCachedTokens(Tok); @@ -962,17 +987,18 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { CXXScopeSpec SS; if (getLang().CPlusPlus) - if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext)) + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) return true; if (Tok.is(tok::identifier)) { // Determine whether the identifier is a type name. - if (TypeTy *Ty = Actions.getTypeName(*Tok.getIdentifierInfo(), - Tok.getLocation(), getCurScope(), &SS)) { + if (ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(), + Tok.getLocation(), getCurScope(), + &SS)) { // This is a typename. Replace the current token in-place with an // annotation type token. Tok.setKind(tok::annot_typename); - Tok.setAnnotationValue(Ty); + setTypeAnnotation(Tok, Ty); Tok.setAnnotationEndLoc(Tok.getLocation()); if (SS.isNotEmpty()) // it was a C++ qualified type name. Tok.setLocation(SS.getBeginLoc()); @@ -997,9 +1023,11 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); bool MemberOfUnknownSpecialization; if (TemplateNameKind TNK - = Actions.isTemplateName(getCurScope(), SS, TemplateName, - /*ObjectType=*/0, EnteringContext, - Template, MemberOfUnknownSpecialization)) { + = Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, TemplateName, + /*ObjectType=*/ ParsedType(), + EnteringContext, + Template, MemberOfUnknownSpecialization)) { // Consume the identifier. ConsumeToken(); if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) { @@ -1066,7 +1094,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { "Cannot be a type or scope token!"); CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext)) + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) return true; if (SS.isEmpty()) return false; @@ -1090,17 +1118,17 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { void Parser::CodeCompletionRecovery() { for (Scope *S = getCurScope(); S; S = S->getParent()) { if (S->getFlags() & Scope::FnScope) { - Actions.CodeCompleteOrdinaryName(getCurScope(), Action::CCC_RecoveryInFunction); + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_RecoveryInFunction); return; } if (S->getFlags() & Scope::ClassScope) { - Actions.CodeCompleteOrdinaryName(getCurScope(), Action::CCC_Class); + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Class); return; } } - Actions.CodeCompleteOrdinaryName(getCurScope(), Action::CCC_Namespace); + Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Namespace); } // Anchor the Parser::FieldCallback vtable to this translation unit. @@ -1109,3 +1137,32 @@ void Parser::CodeCompletionRecovery() { // performance-sensitive. void Parser::FieldCallback::_anchor() { } + +// Code-completion pass-through functions + +void Parser::CodeCompleteDirective(bool InConditional) { + Actions.CodeCompletePreprocessorDirective(InConditional); +} + +void Parser::CodeCompleteInConditionalExclusion() { + Actions.CodeCompleteInPreprocessorConditionalExclusion(getCurScope()); +} + +void Parser::CodeCompleteMacroName(bool IsDefinition) { + Actions.CodeCompletePreprocessorMacroName(IsDefinition); +} + +void Parser::CodeCompletePreprocessorExpression() { + Actions.CodeCompletePreprocessorExpression(); +} + +void Parser::CodeCompleteMacroArgument(IdentifierInfo *Macro, + MacroInfo *MacroInfo, + unsigned ArgumentIndex) { + Actions.CodeCompletePreprocessorMacroArgument(getCurScope(), Macro, MacroInfo, + ArgumentIndex); +} + +void Parser::CodeCompleteNaturalLanguage() { + Actions.CodeCompleteNaturalLanguage(); +} diff --git a/lib/Rewrite/CMakeLists.txt b/lib/Rewrite/CMakeLists.txt index ce728af..ffeb3e6 100644 --- a/lib/Rewrite/CMakeLists.txt +++ b/lib/Rewrite/CMakeLists.txt @@ -13,3 +13,9 @@ add_clang_library(clangRewrite Rewriter.cpp TokenRewriter.cpp ) + +add_dependencies(clangBasic + ClangAttrClasses + ClangAttrList + ClangDeclNodes + ClangStmtNodes) diff --git a/lib/Rewrite/DeltaTree.cpp b/lib/Rewrite/DeltaTree.cpp index 35e888b..085dfd8 100644 --- a/lib/Rewrite/DeltaTree.cpp +++ b/lib/Rewrite/DeltaTree.cpp @@ -116,7 +116,7 @@ namespace { void Destroy(); - static inline bool classof(const DeltaTreeNode *) { return true; } + //static inline bool classof(const DeltaTreeNode *) { return true; } }; } // end anonymous namespace @@ -133,12 +133,6 @@ namespace { public: DeltaTreeInteriorNode() : DeltaTreeNode(false /*nonleaf*/) {} - DeltaTreeInteriorNode(DeltaTreeNode *FirstChild) - : DeltaTreeNode(false /*nonleaf*/) { - FullDelta = FirstChild->FullDelta; - Children[0] = FirstChild; - } - DeltaTreeInteriorNode(const InsertResult &IR) : DeltaTreeNode(false /*nonleaf*/) { Children[0] = IR.LHS; @@ -157,7 +151,7 @@ namespace { return Children[i]; } - static inline bool classof(const DeltaTreeInteriorNode *) { return true; } + //static inline bool classof(const DeltaTreeInteriorNode *) { return true; } static inline bool classof(const DeltaTreeNode *N) { return !N->isLeaf(); } }; } diff --git a/lib/Rewrite/FixItRewriter.cpp b/lib/Rewrite/FixItRewriter.cpp index 29ac7e3..5820969 100644 --- a/lib/Rewrite/FixItRewriter.cpp +++ b/lib/Rewrite/FixItRewriter.cpp @@ -27,16 +27,17 @@ using namespace clang; FixItRewriter::FixItRewriter(Diagnostic &Diags, SourceManager &SourceMgr, const LangOptions &LangOpts, - FixItPathRewriter *PathRewriter) + FixItOptions *FixItOpts) : Diags(Diags), Rewrite(SourceMgr, LangOpts), - PathRewriter(PathRewriter), + FixItOpts(FixItOpts), NumFailures(0) { - Client = Diags.getClient(); + Client = Diags.takeClient(); Diags.setClient(this); } FixItRewriter::~FixItRewriter() { + Diags.takeClient(); Diags.setClient(Client); } @@ -49,16 +50,14 @@ bool FixItRewriter::WriteFixedFile(FileID ID, llvm::raw_ostream &OS) { } bool FixItRewriter::WriteFixedFiles() { - if (NumFailures > 0) { + if (NumFailures > 0 && !FixItOpts->FixWhatYouCan) { Diag(FullSourceLoc(), diag::warn_fixit_no_changes); return true; } for (iterator I = buffer_begin(), E = buffer_end(); I != E; ++I) { const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first); - std::string Filename = Entry->getName(); - if (PathRewriter) - Filename = PathRewriter->RewriteFilename(Filename); + std::string Filename = FixItOpts->RewriteFilename(Entry->getName()); std::string Err; llvm::raw_fd_ostream OS(Filename.c_str(), Err, llvm::raw_fd_ostream::F_Binary); @@ -98,12 +97,6 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel, CanRewrite = false; break; } - - if (Hint.InsertionLoc.isValid() && - !Rewrite.isRewritable(Hint.InsertionLoc)) { - CanRewrite = false; - break; - } } if (!CanRewrite) { @@ -122,12 +115,6 @@ void FixItRewriter::HandleDiagnostic(Diagnostic::Level DiagLevel, for (unsigned Idx = 0, Last = Info.getNumFixItHints(); Idx < Last; ++Idx) { const FixItHint &Hint = Info.getFixItHint(Idx); - if (!Hint.RemoveRange.isValid()) { - // We're adding code. - if (Rewrite.InsertTextBefore(Hint.InsertionLoc, Hint.CodeToInsert)) - Failed = true; - continue; - } if (Hint.CodeToInsert.empty()) { // We're removing code. @@ -158,10 +145,12 @@ void FixItRewriter::Diag(FullSourceLoc Loc, unsigned DiagID) { // When producing this diagnostic, we temporarily bypass ourselves, // clear out any current diagnostic, and let the downstream client // format the diagnostic. + Diags.takeClient(); Diags.setClient(Client); Diags.Clear(); Diags.Report(Loc, DiagID); + Diags.takeClient(); Diags.setClient(this); } -FixItPathRewriter::~FixItPathRewriter() {} +FixItOptions::~FixItOptions() {} diff --git a/lib/Rewrite/FrontendActions.cpp b/lib/Rewrite/FrontendActions.cpp index 6da3b4b..977e0cf 100644 --- a/lib/Rewrite/FrontendActions.cpp +++ b/lib/Rewrite/FrontendActions.cpp @@ -42,12 +42,19 @@ ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI, return new ASTConsumer(); } -class FixItActionSuffixInserter : public FixItPathRewriter { +class FixItRewriteInPlace : public FixItOptions { +public: + std::string RewriteFilename(const std::string &Filename) { return Filename; } +}; + +class FixItActionSuffixInserter : public FixItOptions { std::string NewSuffix; public: - explicit FixItActionSuffixInserter(std::string NewSuffix) - : NewSuffix(NewSuffix) {} + FixItActionSuffixInserter(std::string NewSuffix, bool FixWhatYouCan) + : NewSuffix(NewSuffix) { + this->FixWhatYouCan = FixWhatYouCan; + } std::string RewriteFilename(const std::string &Filename) { llvm::sys::Path Path(Filename); @@ -62,12 +69,14 @@ bool FixItAction::BeginSourceFileAction(CompilerInstance &CI, llvm::StringRef Filename) { const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts(); if (!FEOpts.FixItSuffix.empty()) { - PathRewriter.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix)); + FixItOpts.reset(new FixItActionSuffixInserter(FEOpts.FixItSuffix, + FEOpts.FixWhatYouCan)); } else { - PathRewriter.reset(); + FixItOpts.reset(new FixItRewriteInPlace); + FixItOpts->FixWhatYouCan = FEOpts.FixWhatYouCan; } Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(), - CI.getLangOpts(), PathRewriter.get())); + CI.getLangOpts(), FixItOpts.get())); return true; } diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp index 5fe0649..b461df4 100644 --- a/lib/Rewrite/HTMLRewrite.cpp +++ b/lib/Rewrite/HTMLRewrite.cpp @@ -486,8 +486,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { // Temporarily change the diagnostics object so that we ignore any generated // diagnostics from this pass. - IgnoringDiagClient TmpDC; - Diagnostic TmpDiags(&TmpDC); + Diagnostic TmpDiags(new IgnoringDiagClient); // FIXME: This is a huge hack; we reuse the input preprocessor because we want // its state, but we aren't actually changing it (we hope). This should really diff --git a/lib/Rewrite/Makefile b/lib/Rewrite/Makefile index 1c5b8a8..5fef9b2 100644 --- a/lib/Rewrite/Makefile +++ b/lib/Rewrite/Makefile @@ -13,7 +13,6 @@ CLANG_LEVEL := ../.. LIBRARYNAME := clangRewrite -BUILD_ARCHIVE = 1 include $(CLANG_LEVEL)/Makefile diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/RewriteObjC.cpp index 489fec9..578a063 100644 --- a/lib/Rewrite/RewriteObjC.cpp +++ b/lib/Rewrite/RewriteObjC.cpp @@ -229,14 +229,6 @@ namespace { Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); } - void RemoveText(SourceLocation Loc, unsigned StrLen) { - // If removal succeeded or warning disabled return with no warning. - if (!Rewrite.RemoveText(Loc, StrLen) || SilenceRewriteMacroWarning) - return; - - Diags.Report(Context->getFullLoc(Loc), RewriteFailedDiag); - } - void ReplaceText(SourceLocation Start, unsigned OrigLength, llvm::StringRef Str) { // If removal succeeded or warning disabled return with no warning. @@ -248,9 +240,7 @@ namespace { } // Syntactic Rewriting. - void RewritePrologue(SourceLocation Loc); void RewriteInclude(); - void RewriteTabs(); void RewriteForwardClassDecl(ObjCClassDecl *Dcl); void RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, ObjCImplementationDecl *IMD, @@ -275,7 +265,6 @@ namespace { void RewriteTypeOfDecl(VarDecl *VD); void RewriteObjCQualifiedInterfaceTypes(Expr *E); bool needToScanForQualifiers(QualType T); - bool isSuperReceiver(Expr *recExpr); QualType getSuperStructType(); QualType getConstantStringStructType(); QualType convertFunctionTypeOfBlocks(const FunctionType *FT); @@ -305,8 +294,6 @@ namespace { void RewriteSyncReturnStmts(Stmt *S, std::string buf); Stmt *RewriteObjCTryStmt(ObjCAtTryStmt *S); Stmt *RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S); - Stmt *RewriteObjCCatchStmt(ObjCAtCatchStmt *S); - Stmt *RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S); Stmt *RewriteObjCThrowStmt(ObjCAtThrowStmt *S); Stmt *RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, SourceLocation OrigEnd); @@ -343,17 +330,17 @@ namespace { void RewriteObjCMethodsMetaData(MethodIterator MethodBegin, MethodIterator MethodEnd, bool IsInstanceMethod, - const char *prefix, - const char *ClassName, + llvm::StringRef prefix, + llvm::StringRef ClassName, std::string &Result); void RewriteObjCProtocolMetaData(ObjCProtocolDecl *Protocol, - const char *prefix, - const char *ClassName, + llvm::StringRef prefix, + llvm::StringRef ClassName, std::string &Result); void RewriteObjCProtocolListMetaData(const ObjCList &Prots, - const char *prefix, - const char *ClassName, + llvm::StringRef prefix, + llvm::StringRef ClassName, std::string &Result); void SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, std::string &Result); @@ -371,7 +358,6 @@ namespace { void InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD); // Block specific rewrite rules. - void RewriteBlockCall(CallExpr *Exp); void RewriteBlockPointerDecl(NamedDecl *VD); void RewriteByRefVar(VarDecl *VD); std::string SynthesizeByrefCopyDestroyHelper(VarDecl *VD, int flag); @@ -380,18 +366,18 @@ namespace { void RewriteBlockPointerFunctionArgs(FunctionDecl *FD); std::string SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - const char *funcName, std::string Tag); + llvm::StringRef funcName, std::string Tag); std::string SynthesizeBlockFunc(BlockExpr *CE, int i, - const char *funcName, std::string Tag); + llvm::StringRef funcName, std::string Tag); std::string SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, std::string Desc); std::string SynthesizeBlockDescriptor(std::string DescTag, std::string ImplTag, - int i, const char *funcName, + int i, llvm::StringRef funcName, unsigned hasCopy); Stmt *SynthesizeBlockCall(CallExpr *Exp, const Expr* BlockExp); void SynthesizeBlockLiterals(SourceLocation FunLocStart, - const char *FunName); + llvm::StringRef FunName); void RewriteRecordBody(RecordDecl *RD); void CollectBlockDeclRefInfo(BlockExpr *Exp); @@ -441,7 +427,7 @@ namespace { const char *&RParen); void RewriteCastExpr(CStyleCastExpr *CE); - FunctionDecl *SynthBlockInitFunctionDecl(const char *name); + FunctionDecl *SynthBlockInitFunctionDecl(llvm::StringRef name); Stmt *SynthBlockInitExpr(BlockExpr *Exp, const llvm::SmallVector &InnerBlockDeclRefs); @@ -457,10 +443,10 @@ namespace { // Helper function: create a CStyleCastExpr with trivial type source info. CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty, - CastExpr::CastKind Kind, Expr *E) { + CastKind Kind, Expr *E) { TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation()); - return new (Ctx) CStyleCastExpr(Ty, Kind, E, CXXBaseSpecifierArray(), TInfo, - SourceLocation(), SourceLocation()); + return CStyleCastExpr::Create(*Ctx, Ty, Kind, E, 0, TInfo, + SourceLocation(), SourceLocation()); } } @@ -692,7 +678,7 @@ void RewriteObjC::HandleTopLevelSingleDecl(Decl *D) { RewriteFunctionDecl(FD); } else if (VarDecl *FVD = dyn_cast(D)) { // declared in - if (strcmp(FVD->getNameAsCString(), "_NSConstantStringClassReference") == 0) { + if (FVD->getName() == "_NSConstantStringClassReference") { ConstantStringClassReference = FVD; return; } @@ -747,36 +733,6 @@ void RewriteObjC::RewriteInclude() { } } -void RewriteObjC::RewriteTabs() { - llvm::StringRef MainBuf = SM->getBufferData(MainFileID); - const char *MainBufStart = MainBuf.begin(); - const char *MainBufEnd = MainBuf.end(); - - // Loop over the whole file, looking for tabs. - for (const char *BufPtr = MainBufStart; BufPtr != MainBufEnd; ++BufPtr) { - if (*BufPtr != '\t') - continue; - - // Okay, we found a tab. This tab will turn into at least one character, - // but it depends on which 'virtual column' it is in. Compute that now. - unsigned VCol = 0; - while (BufPtr-VCol != MainBufStart && BufPtr[-VCol-1] != '\t' && - BufPtr[-VCol-1] != '\n' && BufPtr[-VCol-1] != '\r') - ++VCol; - - // Okay, now that we know the virtual column, we know how many spaces to - // insert. We assume 8-character tab-stops. - unsigned Spaces = 8-(VCol & 7); - - // Get the location of the tab. - SourceLocation TabLoc = SM->getLocForStartOfFile(MainFileID); - TabLoc = TabLoc.getFileLocWithOffset(BufPtr-MainBufStart); - - // Rewrite the single tab character into a sequence of spaces. - ReplaceText(TabLoc, 1, llvm::StringRef(" ", Spaces)); - } -} - static std::string getIvarAccessString(ObjCInterfaceDecl *ClassDecl, ObjCIvarDecl *OID) { std::string S; @@ -885,7 +841,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, Setr += "objc_setProperty (self, _cmd, "; SynthesizeIvarOffsetComputation(ClassDecl, OID, Setr); Setr += ", (id)"; - Setr += PD->getNameAsCString(); + Setr += PD->getName(); Setr += ", "; if (Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) Setr += "0, "; @@ -898,7 +854,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, } else { Setr += getIvarAccessString(ClassDecl, OID) + " = "; - Setr += PD->getNameAsCString(); + Setr += PD->getName(); } Setr += "; }"; InsertText(onePastSemiLoc, Setr); @@ -1374,7 +1330,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, - CastExpr::CK_Unknown, + CK_Unknown, IV->getBase()); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(), @@ -1419,7 +1375,7 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, - CastExpr::CK_Unknown, + CK_Unknown, IV->getBase()); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(), @@ -1553,7 +1509,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, SourceLocation startLoc = S->getLocStart(); const char *startBuf = SM->getCharacterData(startLoc); - const char *elementName; + llvm::StringRef elementName; std::string elementTypeAsString; std::string buf; buf = "\n{\n\t"; @@ -1569,13 +1525,13 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, elementTypeAsString = ElementType.getAsString(Context->PrintingPolicy); buf += elementTypeAsString; buf += " "; - elementName = D->getNameAsCString(); + elementName = D->getName(); buf += elementName; buf += ";\n\t"; } else { DeclRefExpr *DR = cast(S->getElement()); - elementName = DR->getDecl()->getNameAsCString(); + elementName = DR->getDecl()->getName(); ValueDecl *VD = cast(DR->getDecl()); if (VD->getType()->isObjCQualifiedIdType() || VD->getType()->isObjCQualifiedInterfaceType()) @@ -1755,7 +1711,7 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) { std::string syncBuf; syncBuf += " objc_sync_exit("; Expr *syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CastExpr::CK_Unknown, + CK_Unknown, S->getSynchExpr()); std::string syncExprBufS; llvm::raw_string_ostream syncExprBuf(syncExprBufS); @@ -2024,14 +1980,6 @@ Stmt *RewriteObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { return 0; } -Stmt *RewriteObjC::RewriteObjCCatchStmt(ObjCAtCatchStmt *S) { - return 0; -} - -Stmt *RewriteObjC::RewriteObjCFinallyStmt(ObjCAtFinallyStmt *S) { - return 0; -} - // This can't be done with ReplaceStmt(S, ThrowExpr), since // the throw expression is typically a message expression that's already // been rewritten! (which implies the SourceLocation's are invalid). @@ -2106,9 +2054,8 @@ CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl( // Now, we cast the reference to a pointer to the objc_msgSend type. QualType pToFunc = Context->getPointerType(msgSendType); ImplicitCastExpr *ICE = - new (Context) ImplicitCastExpr(pToFunc, CastExpr::CK_Unknown, - DRE, CXXBaseSpecifierArray(), - /*isLvalue=*/false); + ImplicitCastExpr::Create(*Context, pToFunc, CK_Unknown, + DRE, 0, VK_RValue); const FunctionType *FT = msgSendType->getAs(); @@ -2318,14 +2265,14 @@ void RewriteObjC::SynthSelGetUidFunctionDecl() { SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), SelGetUidIdent, getFuncType, 0, - FunctionDecl::Extern, - FunctionDecl::None, false); + SC_Extern, + SC_None, false); } void RewriteObjC::RewriteFunctionDecl(FunctionDecl *FD) { // declared in if (FD->getIdentifier() && - strcmp(FD->getNameAsCString(), "sel_registerName") == 0) { + FD->getName() == "sel_registerName") { SelGetUidFunctionDecl = FD; return; } @@ -2385,7 +2332,7 @@ void RewriteObjC::RewriteBlockLiteralFunctionDecl(FunctionDecl *FD) { QualType Type = proto->getResultType(); std::string FdStr = Type.getAsString(Context->PrintingPolicy); FdStr += " "; - FdStr += FD->getNameAsCString(); + FdStr += FD->getName(); FdStr += "("; unsigned numArgs = proto->getNumArgs(); for (unsigned i = 0; i < numArgs; i++) { @@ -2417,8 +2364,8 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() { SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, - FunctionDecl::Extern, - FunctionDecl::None, false); + SC_Extern, + SC_None, false); } // SynthMsgSendFunctionDecl - id objc_msgSend(id self, SEL op, ...); @@ -2439,8 +2386,8 @@ void RewriteObjC::SynthMsgSendFunctionDecl() { MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, - FunctionDecl::Extern, - FunctionDecl::None, false); + SC_Extern, + SC_None, false); } // SynthMsgSendSuperFunctionDecl - id objc_msgSendSuper(struct objc_super *, SEL op, ...); @@ -2464,8 +2411,8 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() { MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, - FunctionDecl::Extern, - FunctionDecl::None, false); + SC_Extern, + SC_None, false); } // SynthMsgSendStretFunctionDecl - id objc_msgSend_stret(id self, SEL op, ...); @@ -2486,8 +2433,8 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() { MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, - FunctionDecl::Extern, - FunctionDecl::None, false); + SC_Extern, + SC_None, false); } // SynthMsgSendSuperStretFunctionDecl - @@ -2513,8 +2460,8 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, - FunctionDecl::Extern, - FunctionDecl::None, false); + SC_Extern, + SC_None, false); } // SynthMsgSendFpretFunctionDecl - double objc_msgSend_fpret(id self, SEL op, ...); @@ -2535,8 +2482,8 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() { MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), msgSendIdent, msgSendType, 0, - FunctionDecl::Extern, - FunctionDecl::None, false); + SC_Extern, + SC_None, false); } // SynthGetClassFunctionDecl - id objc_getClass(const char *name); @@ -2552,8 +2499,8 @@ void RewriteObjC::SynthGetClassFunctionDecl() { GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), getClassIdent, getClassType, 0, - FunctionDecl::Extern, - FunctionDecl::None, false); + SC_Extern, + SC_None, false); } // SynthGetSuperClassFunctionDecl - Class class_getSuperclass(Class cls); @@ -2571,8 +2518,8 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() { SourceLocation(), getSuperClassIdent, getClassType, 0, - FunctionDecl::Extern, - FunctionDecl::None, + SC_Extern, + SC_None, false); } @@ -2589,8 +2536,8 @@ void RewriteObjC::SynthGetMetaClassFunctionDecl() { GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), getClassIdent, getClassType, 0, - FunctionDecl::Extern, - FunctionDecl::None, false); + SC_Extern, + SC_None, false); } Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { @@ -2624,25 +2571,19 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), &Context->Idents.get(S), strType, 0, - VarDecl::Static, VarDecl::None); + SC_Static, SC_None); DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, strType, SourceLocation()); - Expr *Unop = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf, + Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, Context->getPointerType(DRE->getType()), SourceLocation()); // cast to NSConstantString * CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(), - CastExpr::CK_Unknown, Unop); + CK_Unknown, Unop); ReplaceStmt(Exp, cast); // delete Exp; leak for now, see RewritePropertySetter() usage for more info. return cast; } -bool RewriteObjC::isSuperReceiver(Expr *recExpr) { - // check if we are sending a message to 'super' - if (!CurMethodDef || !CurMethodDef->isInstanceMethod()) return false; - return isa(recExpr); -} - // struct objc_super { struct objc_object *receiver; struct objc_class *super; }; QualType RewriteObjC::getSuperStructType() { if (!SuperStructDecl) { @@ -2751,7 +2692,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // set the receiver to self, the first argument to all methods. InitExprs.push_back( NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CastExpr::CK_Unknown, + CK_Unknown, new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), Context->getObjCIdType(), SourceLocation())) @@ -2772,7 +2713,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // (Class)objc_getClass("CurrentClass") CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCClassType(), - CastExpr::CK_Unknown, Cls); + CK_Unknown, Cls); ClsExprs.clear(); ClsExprs.push_back(ArgExpr); Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, @@ -2784,7 +2725,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, InitExprs.push_back( // set 'super class', using class_getSuperclass(). NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CastExpr::CK_Unknown, Cls)); + CK_Unknown, Cls)); // struct objc_super QualType superType = getSuperStructType(); Expr *SuperRep; @@ -2803,12 +2744,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // we need the cast below. For example: // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) // - SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, + SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), SourceLocation()); SuperRep = NoTypeInfoCStyleCastExpr(Context, Context->getPointerType(superType), - CastExpr::CK_Unknown, SuperRep); + CK_Unknown, SuperRep); } else { // (struct objc_super) { } InitListExpr *ILE = @@ -2820,7 +2761,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo, superType, ILE, false); // struct objc_super * - SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, + SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), SourceLocation()); } @@ -2857,7 +2798,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, InitExprs.push_back( NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CastExpr::CK_Unknown, + CK_Unknown, new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(), Context->getObjCIdType(), SourceLocation())) @@ -2877,7 +2818,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // (Class)objc_getClass("CurrentClass") CastExpr *ArgExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCClassType(), - CastExpr::CK_Unknown, Cls); + CK_Unknown, Cls); ClsExprs.clear(); ClsExprs.push_back(ArgExpr); Cls = SynthesizeCallToFunctionDecl(GetSuperClassFunctionDecl, @@ -2889,7 +2830,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, InitExprs.push_back( // set 'super class', using class_getSuperclass(). NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CastExpr::CK_Unknown, Cls)); + CK_Unknown, Cls)); // struct objc_super QualType superType = getSuperStructType(); Expr *SuperRep; @@ -2908,12 +2849,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // we need the cast below. For example: // (struct objc_super *)&__rw_objc_super((id)self, (id)objc_getClass("SUPER")) // - SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf, + SuperRep = new (Context) UnaryOperator(SuperRep, UO_AddrOf, Context->getPointerType(SuperRep->getType()), SourceLocation()); SuperRep = NoTypeInfoCStyleCastExpr(Context, Context->getPointerType(superType), - CastExpr::CK_Unknown, SuperRep); + CK_Unknown, SuperRep); } else { // (struct objc_super) { } InitListExpr *ILE = @@ -2936,7 +2877,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, while (CStyleCastExpr *CE = dyn_cast(recExpr)) recExpr = CE->getSubExpr(); recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CastExpr::CK_Unknown, recExpr); + CK_Unknown, recExpr); MsgExprs.push_back(recExpr); break; } @@ -2966,7 +2907,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, : ICE->getType(); // Make sure we convert "type (^)(...)" to "type (*)(...)". (void)convertBlockPointerToFunctionPointer(type); - userExpr = NoTypeInfoCStyleCastExpr(Context, type, CastExpr::CK_Unknown, + userExpr = NoTypeInfoCStyleCastExpr(Context, type, CK_Unknown, userExpr); } // Make id cast into an 'id' cast. @@ -2975,7 +2916,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, while ((CE = dyn_cast(userExpr))) userExpr = CE->getSubExpr(); userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(), - CastExpr::CK_Unknown, userExpr); + CK_Unknown, userExpr); } } MsgExprs.push_back(userExpr); @@ -3025,7 +2966,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // xx.m:13: note: if this code is reached, the program will abort cast = NoTypeInfoCStyleCastExpr(Context, Context->getPointerType(Context->VoidTy), - CastExpr::CK_Unknown, DRE); + CK_Unknown, DRE); // Now do the "normal" pointer to function cast. QualType castType = Context->getFunctionType(returnType, @@ -3035,7 +2976,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, false, false, 0, 0, FunctionType::ExtInfo()); castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown, + cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_Unknown, cast); // Don't forget the parens to enforce the proper binding. @@ -3058,7 +2999,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // Need to cast objc_msgSend_stret to "void *" (see above comment). cast = NoTypeInfoCStyleCastExpr(Context, Context->getPointerType(Context->VoidTy), - CastExpr::CK_Unknown, STDRE); + CK_Unknown, STDRE); // Now do the "normal" pointer to function cast. castType = Context->getFunctionType(returnType, &ArgTypes[0], ArgTypes.size(), @@ -3066,7 +3007,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, false, false, 0, 0, FunctionType::ExtInfo()); castType = Context->getPointerType(castType); - cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown, + cast = NoTypeInfoCStyleCastExpr(Context, castType, CK_Unknown, cast); // Don't forget the parens to enforce the proper binding. @@ -3088,19 +3029,22 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, // is needed to decide what to do. unsigned IntSize = static_cast(Context->getTypeSize(Context->IntTy)); - IntegerLiteral *limit = new (Context) IntegerLiteral(llvm::APInt(IntSize, 8), - Context->IntTy, - SourceLocation()); + IntegerLiteral *limit = IntegerLiteral::Create(*Context, + llvm::APInt(IntSize, 8), + Context->IntTy, + SourceLocation()); BinaryOperator *lessThanExpr = new (Context) BinaryOperator(sizeofExpr, limit, - BinaryOperator::LE, + BO_LE, Context->IntTy, SourceLocation()); // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) ConditionalOperator *CondExpr = new (Context) ConditionalOperator(lessThanExpr, SourceLocation(), CE, - SourceLocation(), STCE, returnType); - ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(), CondExpr); + SourceLocation(), STCE, (Expr*)0, + returnType); + ReplacingStmt = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + CondExpr); } // delete Exp; leak for now, see RewritePropertySetter() usage for more info. return ReplacingStmt; @@ -3139,13 +3083,13 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { IdentifierInfo *ID = &Context->Idents.get(Name); VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(), ID, getProtocolType(), 0, - VarDecl::Extern, VarDecl::None); + SC_Extern, SC_None); DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, getProtocolType(), SourceLocation()); - Expr *DerefExpr = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf, + Expr *DerefExpr = new (Context) UnaryOperator(DRE, UO_AddrOf, Context->getPointerType(DRE->getType()), SourceLocation()); CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(), - CastExpr::CK_Unknown, + CK_Unknown, DerefExpr); ReplaceStmt(Exp, castExpr); ProtocolExprDecls.insert(Exp->getProtocol()); @@ -3185,7 +3129,7 @@ bool RewriteObjC::BufferContainsPPDirectives(const char *startBuf, void RewriteObjC::SynthesizeObjCInternalStruct(ObjCInterfaceDecl *CDecl, std::string &Result) { assert(CDecl && "Class missing in SynthesizeObjCInternalStruct"); - assert(CDecl->getNameAsCString() && + assert(CDecl->getName() != "" && "Name missing in SynthesizeObjCInternalStruct"); // Do not synthesize more than once. if (ObjCSynthesizedStructs.count(CDecl)) @@ -3318,8 +3262,8 @@ template void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin, MethodIterator MethodEnd, bool IsInstanceMethod, - const char *prefix, - const char *ClassName, + llvm::StringRef prefix, + llvm::StringRef ClassName, std::string &Result) { if (MethodBegin == MethodEnd) return; @@ -3388,8 +3332,8 @@ void RewriteObjC::RewriteObjCMethodsMetaData(MethodIterator MethodBegin, /// RewriteObjCProtocolMetaData - Rewrite protocols meta-data. void RewriteObjC:: -RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, const char *prefix, - const char *ClassName, std::string &Result) { +RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, llvm::StringRef prefix, + llvm::StringRef ClassName, std::string &Result) { static bool objc_protocol_methods = false; // Output struct protocol_methods holder of method selector and type. @@ -3435,7 +3379,7 @@ RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, const char *prefix, Result += "\t ,{{(struct objc_selector *)\""; else Result += "\t ,{(struct objc_selector *)\""; - Result += (*I)->getSelector().getAsString().c_str(); + Result += (*I)->getSelector().getAsString(); std::string MethodTypeString; Context->getObjCEncodingForMethodDecl((*I), MethodTypeString); Result += "\", \""; @@ -3473,7 +3417,7 @@ RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, const char *prefix, Result += "\t ,{{(struct objc_selector *)\""; else Result += "\t ,{(struct objc_selector *)\""; - Result += (*I)->getSelector().getAsString().c_str(); + Result += (*I)->getSelector().getAsString(); std::string MethodTypeString; Context->getObjCEncodingForMethodDecl((*I), MethodTypeString); Result += "\", \""; @@ -3536,7 +3480,7 @@ RewriteObjCProtocolMetaData(ObjCProtocolDecl *PDecl, const char *prefix, void RewriteObjC:: RewriteObjCProtocolListMetaData(const ObjCList &Protocols, - const char *prefix, const char *ClassName, + llvm::StringRef prefix, llvm::StringRef ClassName, std::string &Result) { if (Protocols.empty()) return; @@ -3629,7 +3573,7 @@ void RewriteObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl, // Null CDecl is case of a category implementation with no category interface if (CDecl) RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), "CATEGORY", - FullCategoryName.c_str(), Result); + FullCategoryName, Result); /* struct _objc_category { char *category_name; char *class_name; @@ -3827,15 +3771,15 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, InstanceMethods.push_back(Setter); } RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(), - true, "", IDecl->getNameAsCString(), Result); + true, "", IDecl->getName(), Result); // Build _objc_method_list for class's class methods if needed RewriteObjCMethodsMetaData(IDecl->classmeth_begin(), IDecl->classmeth_end(), - false, "", IDecl->getNameAsCString(), Result); + false, "", IDecl->getName(), Result); // Protocols referenced in class declaration? RewriteObjCProtocolListMetaData(CDecl->getReferencedProtocols(), - "CLASS", CDecl->getNameAsCString(), Result); + "CLASS", CDecl->getName(), Result); // Declaration of class/meta-class metadata /* struct _objc_class { @@ -4101,13 +4045,13 @@ static bool HasLocalVariableExternalStorage(ValueDecl *VD) { } std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, - const char *funcName, + llvm::StringRef funcName, std::string Tag) { const FunctionType *AFT = CE->getFunctionType(); QualType RT = AFT->getResultType(); std::string StructRef = "struct " + Tag; std::string S = "static " + RT.getAsString(Context->PrintingPolicy) + " __" + - funcName + "_" + "block_func_" + utostr(i); + funcName.str() + "_" + "block_func_" + utostr(i); BlockDecl *BD = CE->getBlockDecl(); @@ -4195,7 +4139,7 @@ std::string RewriteObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, } std::string RewriteObjC::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, - const char *funcName, + llvm::StringRef funcName, std::string Tag) { std::string StructRef = "struct " + Tag; std::string S = "static void __"; @@ -4309,37 +4253,48 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, S += FieldName + "; // by ref\n"; } // Finish writing the constructor. - Constructor += ", int flags=0) {\n"; - if (GlobalVarDecl) - Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; - else - Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; - Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; - - Constructor += " Desc = desc;\n"; - + Constructor += ", int flags=0)"; // Initialize all "by copy" arguments. + bool firsTime = true; for (llvm::SmallVector::iterator I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E; ++I) { std::string Name = (*I)->getNameAsString(); - Constructor += " "; - if (isTopLevelBlockPointerType((*I)->getType())) - Constructor += Name + " = (struct __block_impl *)_"; - else - Constructor += Name + " = _"; - Constructor += Name + ";\n"; + if (firsTime) { + Constructor += " : "; + firsTime = false; + } + else + Constructor += ", "; + if (isTopLevelBlockPointerType((*I)->getType())) + Constructor += Name + "((struct __block_impl *)_" + Name + ")"; + else + Constructor += Name + "(_" + Name + ")"; } // Initialize all "by ref" arguments. for (llvm::SmallVector::iterator I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E; ++I) { std::string Name = (*I)->getNameAsString(); - Constructor += " "; + if (firsTime) { + Constructor += " : "; + firsTime = false; + } + else + Constructor += ", "; if (isTopLevelBlockPointerType((*I)->getType())) - Constructor += Name + " = (struct __block_impl *)_"; + Constructor += Name + "((struct __block_impl *)_" + + Name + "->__forwarding)"; else - Constructor += Name + " = _"; - Constructor += Name + "->__forwarding;\n"; + Constructor += Name + "(_" + Name + "->__forwarding)"; } + + Constructor += " {\n"; + if (GlobalVarDecl) + Constructor += " impl.isa = &_NSConcreteGlobalBlock;\n"; + else + Constructor += " impl.isa = &_NSConcreteStackBlock;\n"; + Constructor += " impl.Flags = flags;\n impl.FuncPtr = fp;\n"; + + Constructor += " Desc = desc;\n"; } else { // Finish writing the constructor. Constructor += ", int flags=0) {\n"; @@ -4359,7 +4314,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, std::string ImplTag, int i, - const char *FunName, + llvm::StringRef FunName, unsigned hasCopy) { std::string S = "\nstatic struct " + DescTag; @@ -4378,21 +4333,21 @@ std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag, S += DescTag + "_DATA = { 0, sizeof(struct "; S += ImplTag + ")"; if (hasCopy) { - S += ", __" + std::string(FunName) + "_block_copy_" + utostr(i); - S += ", __" + std::string(FunName) + "_block_dispose_" + utostr(i); + S += ", __" + FunName.str() + "_block_copy_" + utostr(i); + S += ", __" + FunName.str() + "_block_dispose_" + utostr(i); } S += "};\n"; return S; } void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, - const char *FunName) { + llvm::StringRef FunName) { // Insert declaration for the function in which block literal is used. if (CurFunctionDeclToDeclareForBlock && !Blocks.empty()) RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock); bool RewriteSC = (GlobalVarDecl && !Blocks.empty() && - GlobalVarDecl->getStorageClass() == VarDecl::Static && + GlobalVarDecl->getStorageClass() == SC_Static && GlobalVarDecl->getType().getCVRQualifiers()); if (RewriteSC) { std::string SC(" void __"); @@ -4420,8 +4375,8 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, } } - std::string ImplTag = "__" + std::string(FunName) + "_block_impl_" + utostr(i); - std::string DescTag = "__" + std::string(FunName) + "_block_desc_" + utostr(i); + std::string ImplTag = "__" + FunName.str() + "_block_impl_" + utostr(i); + std::string DescTag = "__" + FunName.str() + "_block_desc_" + utostr(i); std::string CI = SynthesizeBlockImpl(Blocks[i], ImplTag, DescTag); @@ -4450,7 +4405,7 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, // Must insert any 'const/volatile/static here. Since it has been // removed as result of rewriting of block literals. std::string SC; - if (GlobalVarDecl->getStorageClass() == VarDecl::Static) + if (GlobalVarDecl->getStorageClass() == SC_Static) SC = "static "; if (GlobalVarDecl->getType().isConstQualified()) SC += "const "; @@ -4469,7 +4424,7 @@ void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart, void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { SourceLocation FunLocStart = FD->getTypeSpecStartLoc(); - const char *FuncName = FD->getNameAsCString(); + llvm::StringRef FuncName = FD->getName(); SynthesizeBlockLiterals(FunLocStart, FuncName); } @@ -4477,7 +4432,7 @@ void RewriteObjC::InsertBlockLiteralsWithinFunction(FunctionDecl *FD) { static void BuildUniqueMethodName(std::string &Name, ObjCMethodDecl *MD) { ObjCInterfaceDecl *IFace = MD->getClassInterface(); - Name = IFace->getNameAsCString(); + Name = IFace->getName(); Name += "__" + MD->getSelector().getAsString(); // Convert colons to underscores. std::string::size_type loc = 0; @@ -4491,7 +4446,7 @@ void RewriteObjC::InsertBlockLiteralsWithinMethod(ObjCMethodDecl *MD) { SourceLocation FunLocStart = MD->getLocStart(); std::string FuncName; BuildUniqueMethodName(FuncName, MD); - SynthesizeBlockLiterals(FunLocStart, FuncName.c_str()); + SynthesizeBlockLiterals(FunLocStart, FuncName); } void RewriteObjC::GetBlockDeclRefExprs(Stmt *S) { @@ -4613,7 +4568,8 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { ConditionalOperator *CondExpr = new (Context) ConditionalOperator(CONDExp, SourceLocation(), cast(LHSStmt), - SourceLocation(), cast(RHSStmt), + SourceLocation(), cast(RHSStmt), + (Expr*)0, Exp->getType()); return CondExpr; } else if (const ObjCIvarRefExpr *IRE = dyn_cast(BlockExp)) { @@ -4655,7 +4611,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType); CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock, - CastExpr::CK_Unknown, + CK_Unknown, const_cast(BlockExp)); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), @@ -4669,7 +4625,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { FD->getType()); CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType, - CastExpr::CK_Unknown, ME); + CK_Unknown, ME); PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast); llvm::SmallVector BlkExprs; @@ -4686,11 +4642,6 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { return CE; } -void RewriteObjC::RewriteBlockCall(CallExpr *Exp) { - Stmt *BlockCall = SynthesizeBlockCall(Exp, Exp->getCallee()); - ReplaceStmt(Exp, BlockCall); -} - // We need to return the rewritten expression to handle cases where the // BlockDeclRefExpr is embedded in another expression being rewritten. // For example: @@ -4724,7 +4675,7 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) { FD, SourceLocation(), FD->getType()); - const char *Name = VD->getNameAsCString(); + llvm::StringRef Name = VD->getName(); FD = FieldDecl::Create(*Context, 0, SourceLocation(), &Context->Idents.get(Name), Context->VoidPtrTy, 0, @@ -4749,7 +4700,7 @@ Stmt *RewriteObjC::RewriteLocalVariableExternalStorage(DeclRefExpr *DRE) { if (VarDecl *Var = dyn_cast(VD)) if (!ImportedLocalExternalDecls.count(Var)) return DRE; - Expr *Exp = new (Context) UnaryOperator(DRE, UnaryOperator::Deref, + Expr *Exp = new (Context) UnaryOperator(DRE, UO_Deref, DRE->getType(), DRE->getLocation()); // Need parens to enforce precedence. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), @@ -5098,7 +5049,6 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { startLoc = E->getLocStart(); startLoc = SM->getInstantiationLoc(startLoc); endBuf = SM->getCharacterData(startLoc); - ByrefType += " " + Name; ByrefType += " = {(void*)"; ByrefType += utostr(isa); @@ -5125,11 +5075,11 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { // // double __block BYREFVAR = 1.34, BYREFVAR2 = 1.37; // - const char *startBuf = SM->getCharacterData(startLoc); - const char *semiBuf = strchr(startBuf, ';'); + const char *startInitializerBuf = SM->getCharacterData(startLoc); + const char *semiBuf = strchr(startInitializerBuf, ';'); assert((*semiBuf == ';') && "RewriteByRefVar: can't find ';'"); SourceLocation semiLoc = - startLoc.getFileLocWithOffset(semiBuf-startBuf); + startLoc.getFileLocWithOffset(semiBuf-startInitializerBuf); InsertText(semiLoc, "}"); } @@ -5165,12 +5115,12 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { } } -FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(const char *name) { +FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(llvm::StringRef name) { IdentifierInfo *ID = &Context->Idents.get(name); QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy); return FunctionDecl::Create(*Context, TUDecl,SourceLocation(), - ID, FType, 0, FunctionDecl::Extern, - FunctionDecl::None, false, false); + ID, FType, 0, SC_Extern, + SC_None, false, false); } Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, @@ -5232,17 +5182,17 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, Expr *NewRep; // Simulate a contructor call... - FD = SynthBlockInitFunctionDecl(Tag.c_str()); + FD = SynthBlockInitFunctionDecl(Tag); DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, FType, SourceLocation()); llvm::SmallVector InitExprs; // Initialize the block function. - FD = SynthBlockInitFunctionDecl(Func.c_str()); + FD = SynthBlockInitFunctionDecl(Func); DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, - CastExpr::CK_Unknown, Arg); + CK_Unknown, Arg); InitExprs.push_back(castExpr); // Initialize the block descriptor. @@ -5251,11 +5201,11 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), &Context->Idents.get(DescData.c_str()), Context->VoidPtrTy, 0, - VarDecl::Static, VarDecl::None); + SC_Static, SC_None); UnaryOperator *DescRefExpr = new (Context) UnaryOperator( new (Context) DeclRefExpr(NewVD, Context->VoidPtrTy, SourceLocation()), - UnaryOperator::AddrOf, + UO_AddrOf, Context->getPointerType(Context->VoidPtrTy), SourceLocation()); InitExprs.push_back(DescRefExpr); @@ -5268,26 +5218,26 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, E = BlockByCopyDecls.end(); I != E; ++I) { if (isObjCType((*I)->getType())) { // FIXME: Conform to ABI ([[obj retain] autorelease]). - FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); + FD = SynthBlockInitFunctionDecl((*I)->getName()); Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); if (HasLocalVariableExternalStorage(*I)) { QualType QT = (*I)->getType(); QT = Context->getPointerType(QT); - Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf, QT, + Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, SourceLocation()); } } else if (isTopLevelBlockPointerType((*I)->getType())) { - FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); + FD = SynthBlockInitFunctionDecl((*I)->getName()); Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy, - CastExpr::CK_Unknown, Arg); + CK_Unknown, Arg); } else { - FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); + FD = SynthBlockInitFunctionDecl((*I)->getName()); Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); if (HasLocalVariableExternalStorage(*I)) { QualType QT = (*I)->getType(); QT = Context->getPointerType(QT); - Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf, QT, + Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, QT, SourceLocation()); } @@ -5308,12 +5258,12 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); - FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString()); + FD = SynthBlockInitFunctionDecl((*I)->getName()); Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation()); - Exp = new (Context) UnaryOperator(Exp, UnaryOperator::AddrOf, + Exp = new (Context) UnaryOperator(Exp, UO_AddrOf, Context->getPointerType(Exp->getType()), SourceLocation()); - Exp = NoTypeInfoCStyleCastExpr(Context, castT, CastExpr::CK_Unknown, Exp); + Exp = NoTypeInfoCStyleCastExpr(Context, castT, CK_Unknown, Exp); InitExprs.push_back(Exp); } } @@ -5322,16 +5272,16 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, int flag = (BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR); unsigned IntSize = static_cast(Context->getTypeSize(Context->IntTy)); - Expr *FlagExp = new (Context) IntegerLiteral(llvm::APInt(IntSize, flag), - Context->IntTy, SourceLocation()); + Expr *FlagExp = IntegerLiteral::Create(*Context, llvm::APInt(IntSize, flag), + Context->IntTy, SourceLocation()); InitExprs.push_back(FlagExp); } NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(), FType, SourceLocation()); - NewRep = new (Context) UnaryOperator(NewRep, UnaryOperator::AddrOf, + NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, Context->getPointerType(NewRep->getType()), SourceLocation()); - NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CastExpr::CK_Unknown, + NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CK_Unknown, NewRep); BlockDeclRefs.clear(); BlockByRefDecls.clear(); @@ -5609,7 +5559,9 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { } #if 0 if (ImplicitCastExpr *ICE = dyn_cast(S)) { - CastExpr *Replacement = new (Context) CastExpr(ICE->getType(), ICE->getSubExpr(), SourceLocation()); + CastExpr *Replacement = new (Context) CastExpr(ICE->getType(), + ICE->getSubExpr(), + SourceLocation()); // Get the new text. std::string SStr; llvm::raw_string_ostream Buf(SStr); @@ -5722,7 +5674,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { PropParentMap = 0; } SynthesizeBlockLiterals(VD->getTypeSpecStartLoc(), - VD->getNameAsCString()); + VD->getName()); GlobalVarDecl = 0; // This is needed for blocks. diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 448d161..cfebed6 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -13,9 +13,11 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "AnalysisBasedWarnings.h" +#include "clang/Sema/AnalysisBasedWarnings.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Basic/SourceManager.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtObjC.h" @@ -197,6 +199,8 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { return AlwaysFallThrough; } +namespace { + struct CheckFallThroughDiagnostics { unsigned diag_MaybeFallThrough_HasNoReturn; unsigned diag_MaybeFallThrough_ReturnsNonVoid; @@ -266,6 +270,8 @@ struct CheckFallThroughDiagnostics { } }; +} + /// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a /// function that should return a value. Check that we don't fall off the end /// of a noreturn function. We assume that functions and blocks not marked @@ -375,19 +381,16 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, S.SourceMgr.isInSystemHeader(D->getLocation())) return; - if (const FunctionDecl *FD = dyn_cast(D)) { - // For function templates, class templates and member function templates - // we'll do the analysis at instantiation time. - if (FD->isDependentContext()) - return; - } + // For code in dependent contexts, we'll do this at instantiation time. + if (cast(D)->isDependentContext()) + return; const Stmt *Body = D->getBody(); assert(Body); // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 // explosion for destrutors that can result and the compile time hit. - AnalysisContext AC(D, false); + AnalysisContext AC(D, 0, false); // Warning: check missing 'return' if (P.enableCheckFallThrough) { @@ -401,3 +404,21 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, if (P.enableCheckUnreachable) CheckUnreachable(S, AC); } + +void clang::sema:: +AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, + const BlockExpr *E) { + return IssueWarnings(P, E->getBlockDecl(), E->getType()); +} + +void clang::sema:: +AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, + const ObjCMethodDecl *D) { + return IssueWarnings(P, D, QualType()); +} + +void clang::sema:: +AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, + const FunctionDecl *D) { + return IssueWarnings(P, D, QualType()); +} diff --git a/lib/Sema/AnalysisBasedWarnings.h b/lib/Sema/AnalysisBasedWarnings.h deleted file mode 100644 index dea19ba..0000000 --- a/lib/Sema/AnalysisBasedWarnings.h +++ /dev/null @@ -1,55 +0,0 @@ -//=- AnalysisBasedWarnings.h - Sema warnings based on libAnalysis -*- C++ -*-=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines AnalysisBasedWarnings, a worker object used by Sema -// that issues warnings based on dataflow-analysis. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H -#define LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H - -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/DenseMap.h" - -namespace clang { - -class Sema; - -namespace sema { - -class AnalysisBasedWarnings { -public: - class Policy { - friend class AnalysisBasedWarnings; - // The warnings to run. - unsigned enableCheckFallThrough : 1; - unsigned enableCheckUnreachable : 1; - public: - Policy(); - void disableCheckFallThrough() { enableCheckFallThrough = 0; } - }; - -private: - Sema &S; - Policy DefaultPolicy; - - enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 }; - llvm::DenseMap VisitedFD; - -public: - AnalysisBasedWarnings(Sema &s); - - Policy getDefaultPolicy() { return DefaultPolicy; } - - void IssueWarnings(Policy P, const Decl *D, QualType BlockTy = QualType()); -}; - -}} // end namespace clang::sema - -#endif diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp new file mode 100644 index 0000000..8ccb2ca --- /dev/null +++ b/lib/Sema/AttributeList.cpp @@ -0,0 +1,136 @@ +//===--- AttributeList.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AttributeList class implementation +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/AttributeList.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/StringSwitch.h" +using namespace clang; + +AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, + IdentifierInfo *sName, SourceLocation sLoc, + IdentifierInfo *pName, SourceLocation pLoc, + Expr **ExprList, unsigned numArgs, + AttributeList *n, bool declspec, bool cxx0x) + : AttrName(aName), AttrLoc(aLoc), ScopeName(sName), ScopeLoc(sLoc), + ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n), + DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false) { + + if (numArgs == 0) + Args = 0; + else { + Args = new Expr*[numArgs]; + memcpy(Args, ExprList, numArgs*sizeof(Args[0])); + } +} + +AttributeList::~AttributeList() { + if (Args) { + // FIXME: before we delete the vector, we need to make sure the Expr's + // have been deleted. Since ActionBase::ExprTy is "void", we are dependent + // on the actions module for actually freeing the memory. The specific + // hooks are ActOnDeclarator, ActOnTypeName, ActOnParamDeclaratorType, + // ParseField, ParseTag. Once these routines have freed the expression, + // they should zero out the Args slot (to indicate the memory has been + // freed). If any element of the vector is non-null, we should assert. + delete [] Args; + } + delete Next; +} + +AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { + llvm::StringRef AttrName = Name->getName(); + + // Normalize the attribute name, __foo__ becomes foo. + if (AttrName.startswith("__") && AttrName.endswith("__")) + AttrName = AttrName.substr(2, AttrName.size() - 4); + + return llvm::StringSwitch(AttrName) + .Case("weak", AT_weak) + .Case("weakref", AT_weakref) + .Case("pure", AT_pure) + .Case("mode", AT_mode) + .Case("used", AT_used) + .Case("alias", AT_alias) + .Case("align", AT_aligned) + .Case("final", AT_final) + .Case("cdecl", AT_cdecl) + .Case("const", AT_const) + .Case("blocks", AT_blocks) + .Case("format", AT_format) + .Case("hiding", AT_hiding) + .Case("malloc", AT_malloc) + .Case("packed", AT_packed) + .Case("unused", AT_unused) + .Case("aligned", AT_aligned) + .Case("cleanup", AT_cleanup) + .Case("nodebug", AT_nodebug) + .Case("nonnull", AT_nonnull) + .Case("nothrow", AT_nothrow) + .Case("objc_gc", AT_objc_gc) + .Case("regparm", AT_regparm) + .Case("section", AT_section) + .Case("stdcall", AT_stdcall) + .Case("annotate", AT_annotate) + .Case("fastcall", AT_fastcall) + .Case("ibaction", AT_IBAction) + .Case("iboutlet", AT_IBOutlet) + .Case("iboutletcollection", AT_IBOutletCollection) + .Case("noreturn", AT_noreturn) + .Case("noinline", AT_noinline) + .Case("override", AT_override) + .Case("sentinel", AT_sentinel) + .Case("NSObject", AT_nsobject) + .Case("dllimport", AT_dllimport) + .Case("dllexport", AT_dllexport) + .Case("may_alias", IgnoredAttribute) // FIXME: TBAA + .Case("base_check", AT_base_check) + .Case("deprecated", AT_deprecated) + .Case("visibility", AT_visibility) + .Case("destructor", AT_destructor) + .Case("format_arg", AT_format_arg) + .Case("gnu_inline", AT_gnu_inline) + .Case("weak_import", AT_weak_import) + .Case("vecreturn", AT_vecreturn) + .Case("vector_size", AT_vector_size) + .Case("constructor", AT_constructor) + .Case("unavailable", AT_unavailable) + .Case("overloadable", AT_overloadable) + .Case("address_space", AT_address_space) + .Case("always_inline", AT_always_inline) + .Case("returns_twice", IgnoredAttribute) + .Case("vec_type_hint", IgnoredAttribute) + .Case("objc_exception", AT_objc_exception) + .Case("ext_vector_type", AT_ext_vector_type) + .Case("transparent_union", AT_transparent_union) + .Case("analyzer_noreturn", AT_analyzer_noreturn) + .Case("warn_unused_result", AT_warn_unused_result) + .Case("carries_dependency", AT_carries_dependency) + .Case("ns_returns_not_retained", AT_ns_returns_not_retained) + .Case("ns_returns_retained", AT_ns_returns_retained) + .Case("cf_returns_not_retained", AT_cf_returns_not_retained) + .Case("cf_returns_retained", AT_cf_returns_retained) + .Case("ownership_returns", AT_ownership_returns) + .Case("ownership_holds", AT_ownership_holds) + .Case("ownership_takes", AT_ownership_takes) + .Case("reqd_work_group_size", AT_reqd_wg_size) + .Case("init_priority", AT_init_priority) + .Case("no_instrument_function", AT_no_instrument_function) + .Case("thiscall", AT_thiscall) + .Case("pascal", AT_pascal) + .Case("__cdecl", AT_cdecl) + .Case("__stdcall", AT_stdcall) + .Case("__fastcall", AT_fastcall) + .Case("__thiscall", AT_thiscall) + .Case("__pascal", AT_pascal) + .Default(UnknownAttribute); +} diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 70b4792..e65bb22 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -2,10 +2,11 @@ set(LLVM_NO_RTTI 1) add_clang_library(clangSema AnalysisBasedWarnings.cpp + AttributeList.cpp CodeCompleteConsumer.cpp + DeclSpec.cpp IdentifierResolver.cpp JumpDiagnostics.cpp - ParseAST.cpp Sema.cpp SemaAccess.cpp SemaAttr.cpp diff --git a/lib/Sema/CXXFieldCollector.h b/lib/Sema/CXXFieldCollector.h deleted file mode 100644 index 63c6ee3..0000000 --- a/lib/Sema/CXXFieldCollector.h +++ /dev/null @@ -1,79 +0,0 @@ -//===- CXXFieldCollector.h - Utility class for C++ class semantic analysis ===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides CXXFieldCollector that is used during parsing & semantic -// analysis of C++ classes. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H -#define LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H - -#include "llvm/ADT/SmallVector.h" - -namespace clang { - class FieldDecl; - -/// CXXFieldCollector - Used to keep track of CXXFieldDecls during parsing of -/// C++ classes. -class CXXFieldCollector { - /// Fields - Contains all FieldDecls collected during parsing of a C++ - /// class. When a nested class is entered, its fields are appended to the - /// fields of its parent class, when it is exited its fields are removed. - llvm::SmallVector Fields; - - /// FieldCount - Each entry represents the number of fields collected during - /// the parsing of a C++ class. When a nested class is entered, a new field - /// count is pushed, when it is exited, the field count is popped. - llvm::SmallVector FieldCount; - - // Example: - // - // class C { - // int x,y; - // class NC { - // int q; - // // At this point, Fields contains [x,y,q] decls and FieldCount contains - // // [2,1]. - // }; - // int z; - // // At this point, Fields contains [x,y,z] decls and FieldCount contains - // // [3]. - // }; - -public: - /// StartClass - Called by Sema::ActOnStartCXXClassDef. - void StartClass() { FieldCount.push_back(0); } - - /// Add - Called by Sema::ActOnCXXMemberDeclarator. - void Add(FieldDecl *D) { - Fields.push_back(D); - ++FieldCount.back(); - } - - /// getCurNumField - The number of fields added to the currently parsed class. - size_t getCurNumFields() const { - assert(!FieldCount.empty() && "no currently-parsed class"); - return FieldCount.back(); - } - - /// getCurFields - Pointer to array of fields added to the currently parsed - /// class. - FieldDecl **getCurFields() { return &*(Fields.end() - getCurNumFields()); } - - /// FinishClass - Called by Sema::ActOnFinishCXXClassDef. - void FinishClass() { - Fields.resize(Fields.size() - getCurNumFields()); - FieldCount.pop_back(); - } -}; - -} // end namespace clang - -#endif diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 6cefc61..58a1627 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -11,11 +11,13 @@ // //===----------------------------------------------------------------------===// #include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/Sema.h" #include "clang/AST/DeclCXX.h" -#include "clang/Parse/Scope.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/Lex/Preprocessor.h" #include "clang-c/Index.h" -#include "Sema.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" #include @@ -234,8 +236,7 @@ std::string CodeCompletionString::getAsString() const { default: OS << C->Text; break; } } - OS.flush(); - return Result; + return OS.str(); } const char *CodeCompletionString::getTypedText() const { @@ -246,8 +247,10 @@ const char *CodeCompletionString::getTypedText() const { return 0; } -CodeCompletionString *CodeCompletionString::Clone() const { - CodeCompletionString *Result = new CodeCompletionString; +CodeCompletionString * +CodeCompletionString::Clone(CodeCompletionString *Result) const { + if (!Result) + Result = new CodeCompletionString; for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) Result->AddChunk(C->Clone()); return Result; @@ -373,19 +376,19 @@ bool CodeCompletionString::Deserialize(const char *&Str, const char *StrEnd) { return true; } -void CodeCompleteConsumer::Result::Destroy() { +void CodeCompletionResult::Destroy() { if (Kind == RK_Pattern) { delete Pattern; Pattern = 0; } } -unsigned CodeCompleteConsumer::Result::getPriorityFromDecl(NamedDecl *ND) { +unsigned CodeCompletionResult::getPriorityFromDecl(NamedDecl *ND) { if (!ND) return CCP_Unlikely; // Context-based decisions. - DeclContext *DC = ND->getDeclContext()->getLookupContext(); + DeclContext *DC = ND->getDeclContext()->getRedeclContext(); if (DC->isFunctionOrMethod() || isa(DC)) return CCP_LocalDeclaration; if (DC->isRecord() || isa(DC)) @@ -437,13 +440,16 @@ CodeCompleteConsumer::~CodeCompleteConsumer() { } void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, - Result *Results, + CodeCompletionContext Context, + CodeCompletionResult *Results, unsigned NumResults) { + std::stable_sort(Results, Results + NumResults); + // Print the results. for (unsigned I = 0; I != NumResults; ++I) { OS << "COMPLETION: "; switch (Results[I].Kind) { - case Result::RK_Declaration: + case CodeCompletionResult::RK_Declaration: OS << Results[I].Declaration; if (Results[I].Hidden) OS << " (Hidden)"; @@ -456,11 +462,11 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, OS << '\n'; break; - case Result::RK_Keyword: + case CodeCompletionResult::RK_Keyword: OS << Results[I].Keyword << '\n'; break; - case Result::RK_Macro: { + case CodeCompletionResult::RK_Macro: { OS << Results[I].Macro->getName(); if (CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef)) { @@ -471,7 +477,7 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, break; } - case Result::RK_Pattern: { + case CodeCompletionResult::RK_Pattern: { OS << "Pattern : " << Results[I].Pattern->getAsString() << '\n'; break; @@ -494,116 +500,104 @@ PrintingCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, } } +void CodeCompletionResult::computeCursorKindAndAvailability() { + switch (Kind) { + case RK_Declaration: + // Set the availability based on attributes. + Availability = CXAvailability_Available; + if (Declaration->getAttr()) + Availability = CXAvailability_NotAvailable; + else if (Declaration->getAttr()) + Availability = CXAvailability_Deprecated; + + if (FunctionDecl *Function = dyn_cast(Declaration)) + if (Function->isDeleted()) + Availability = CXAvailability_NotAvailable; + + CursorKind = getCursorKindForDecl(Declaration); + if (CursorKind == CXCursor_UnexposedDecl) + CursorKind = CXCursor_NotImplemented; + break; + + case RK_Macro: + Availability = CXAvailability_Available; + CursorKind = CXCursor_MacroDefinition; + break; + + case RK_Keyword: + Availability = CXAvailability_Available; + CursorKind = CXCursor_NotImplemented; + break; + + case RK_Pattern: + // Do nothing: Patterns can come with cursor kinds! + break; + } +} + +/// \brief Retrieve the name that should be used to order a result. +/// +/// If the name needs to be constructed as a string, that string will be +/// saved into Saved and the returned StringRef will refer to it. +static llvm::StringRef getOrderedName(const CodeCompletionResult &R, + std::string &Saved) { + switch (R.Kind) { + case CodeCompletionResult::RK_Keyword: + return R.Keyword; + + case CodeCompletionResult::RK_Pattern: + return R.Pattern->getTypedText(); + + case CodeCompletionResult::RK_Macro: + return R.Macro->getName(); + + case CodeCompletionResult::RK_Declaration: + // Handle declarations below. + break; + } + + DeclarationName Name = R.Declaration->getDeclName(); + + // If the name is a simple identifier (by far the common case), or a + // zero-argument selector, just return a reference to that identifier. + if (IdentifierInfo *Id = Name.getAsIdentifierInfo()) + return Id->getName(); + if (Name.isObjCZeroArgSelector()) + if (IdentifierInfo *Id + = Name.getObjCSelector().getIdentifierInfoForSlot(0)) + return Id->getName(); + + Saved = Name.getAsString(); + return Saved; +} + +bool clang::operator<(const CodeCompletionResult &X, + const CodeCompletionResult &Y) { + std::string XSaved, YSaved; + llvm::StringRef XStr = getOrderedName(X, XSaved); + llvm::StringRef YStr = getOrderedName(Y, YSaved); + int cmp = XStr.compare_lower(YStr); + if (cmp) + return cmp < 0; + + // If case-insensitive comparison fails, try case-sensitive comparison. + cmp = XStr.compare(YStr); + if (cmp) + return cmp < 0; + + return false; +} + void CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, - Result *Results, + CodeCompletionContext Context, + CodeCompletionResult *Results, unsigned NumResults) { // Print the results. for (unsigned I = 0; I != NumResults; ++I) { - CXCursorKind Kind = CXCursor_NotImplemented; - - switch (Results[I].Kind) { - case Result::RK_Declaration: - switch (Results[I].Declaration->getKind()) { - case Decl::Record: - case Decl::CXXRecord: - case Decl::ClassTemplateSpecialization: { - RecordDecl *Record = cast(Results[I].Declaration); - if (Record->isStruct()) - Kind = CXCursor_StructDecl; - else if (Record->isUnion()) - Kind = CXCursor_UnionDecl; - else - Kind = CXCursor_ClassDecl; - break; - } - - case Decl::ObjCMethod: { - ObjCMethodDecl *Method = cast(Results[I].Declaration); - if (Method->isInstanceMethod()) - Kind = CXCursor_ObjCInstanceMethodDecl; - else - Kind = CXCursor_ObjCClassMethodDecl; - break; - } - - case Decl::Typedef: - Kind = CXCursor_TypedefDecl; - break; - - case Decl::Enum: - Kind = CXCursor_EnumDecl; - break; - - case Decl::Field: - Kind = CXCursor_FieldDecl; - break; - - case Decl::EnumConstant: - Kind = CXCursor_EnumConstantDecl; - break; - - case Decl::Function: - case Decl::CXXMethod: - case Decl::CXXConstructor: - case Decl::CXXDestructor: - case Decl::CXXConversion: - Kind = CXCursor_FunctionDecl; - break; - - case Decl::Var: - Kind = CXCursor_VarDecl; - break; - - case Decl::ParmVar: - Kind = CXCursor_ParmDecl; - break; - - case Decl::ObjCInterface: - Kind = CXCursor_ObjCInterfaceDecl; - break; - - case Decl::ObjCCategory: - Kind = CXCursor_ObjCCategoryDecl; - break; - - case Decl::ObjCProtocol: - Kind = CXCursor_ObjCProtocolDecl; - break; - - case Decl::ObjCProperty: - Kind = CXCursor_ObjCPropertyDecl; - break; - - case Decl::ObjCIvar: - Kind = CXCursor_ObjCIvarDecl; - break; - - case Decl::ObjCImplementation: - Kind = CXCursor_ObjCImplementationDecl; - break; - - case Decl::ObjCCategoryImpl: - Kind = CXCursor_ObjCCategoryImplDecl; - break; - - default: - break; - } - break; - - case Result::RK_Macro: - Kind = CXCursor_MacroDefinition; - break; - - case Result::RK_Keyword: - case Result::RK_Pattern: - Kind = CXCursor_NotImplemented; - break; - } - - WriteUnsigned(OS, Kind); + WriteUnsigned(OS, Results[I].CursorKind); WriteUnsigned(OS, Results[I].Priority); + WriteUnsigned(OS, Results[I].Availability); CodeCompletionString *CCS = Results[I].CreateCodeCompletionString(SemaRef); assert(CCS && "No code-completion string?"); CCS->Serialize(OS); @@ -618,7 +612,8 @@ CIndexCodeCompleteConsumer::ProcessOverloadCandidates(Sema &SemaRef, unsigned NumCandidates) { for (unsigned I = 0; I != NumCandidates; ++I) { WriteUnsigned(OS, CXCursor_NotImplemented); - WriteUnsigned(OS, /*Priority=*/0); + WriteUnsigned(OS, /*Priority=*/I); + WriteUnsigned(OS, /*Availability=*/CXAvailability_Available); CodeCompletionString *CCS = Candidates[I].CreateSignatureString(CurrentArg, SemaRef); assert(CCS && "No code-completion string?"); diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp new file mode 100644 index 0000000..b46e8af --- /dev/null +++ b/lib/Sema/DeclSpec.cpp @@ -0,0 +1,667 @@ +//===--- SemaDeclSpec.cpp - Declaration Specifier Semantic Analysis -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for declaration specifiers. +// +//===----------------------------------------------------------------------===// + +#include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency! +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ErrorHandling.h" +#include +using namespace clang; + + +static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc, + SourceManager &SrcMgr, unsigned DiagID) { + return D.Report(FullSourceLoc(Loc, SrcMgr), DiagID); +} + + +void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) { + assert(TemplateId && "NULL template-id annotation?"); + Kind = IK_TemplateId; + this->TemplateId = TemplateId; + StartLocation = TemplateId->TemplateNameLoc; + EndLocation = TemplateId->RAngleLoc; +} + +void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) { + assert(TemplateId && "NULL template-id annotation?"); + Kind = IK_ConstructorTemplateId; + this->TemplateId = TemplateId; + StartLocation = TemplateId->TemplateNameLoc; + EndLocation = TemplateId->RAngleLoc; +} + +/// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. +/// "TheDeclarator" is the declarator that this will be added to. +DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, + SourceLocation EllipsisLoc, + ParamInfo *ArgInfo, + unsigned NumArgs, + unsigned TypeQuals, + bool hasExceptionSpec, + SourceLocation ThrowLoc, + bool hasAnyExceptionSpec, + ParsedType *Exceptions, + SourceRange *ExceptionRanges, + unsigned NumExceptions, + SourceLocation LPLoc, + SourceLocation RPLoc, + Declarator &TheDeclarator) { + DeclaratorChunk I; + I.Kind = Function; + I.Loc = LPLoc; + I.EndLoc = RPLoc; + I.Fun.hasPrototype = hasProto; + I.Fun.isVariadic = isVariadic; + I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding(); + I.Fun.DeleteArgInfo = false; + I.Fun.TypeQuals = TypeQuals; + I.Fun.NumArgs = NumArgs; + I.Fun.ArgInfo = 0; + I.Fun.hasExceptionSpec = hasExceptionSpec; + I.Fun.ThrowLoc = ThrowLoc.getRawEncoding(); + I.Fun.hasAnyExceptionSpec = hasAnyExceptionSpec; + I.Fun.NumExceptions = NumExceptions; + I.Fun.Exceptions = 0; + + // new[] an argument array if needed. + if (NumArgs) { + // If the 'InlineParams' in Declarator is unused and big enough, put our + // parameter list there (in an effort to avoid new/delete traffic). If it + // is already used (consider a function returning a function pointer) or too + // small (function taking too many arguments), go to the heap. + if (!TheDeclarator.InlineParamsUsed && + NumArgs <= llvm::array_lengthof(TheDeclarator.InlineParams)) { + I.Fun.ArgInfo = TheDeclarator.InlineParams; + I.Fun.DeleteArgInfo = false; + TheDeclarator.InlineParamsUsed = true; + } else { + I.Fun.ArgInfo = new DeclaratorChunk::ParamInfo[NumArgs]; + I.Fun.DeleteArgInfo = true; + } + memcpy(I.Fun.ArgInfo, ArgInfo, sizeof(ArgInfo[0])*NumArgs); + } + // new[] an exception array if needed + if (NumExceptions) { + I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions]; + for (unsigned i = 0; i != NumExceptions; ++i) { + I.Fun.Exceptions[i].Ty = Exceptions[i]; + I.Fun.Exceptions[i].Range = ExceptionRanges[i]; + } + } + return I; +} + +/// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this +/// declaration specifier includes. +/// +unsigned DeclSpec::getParsedSpecifiers() const { + unsigned Res = 0; + if (StorageClassSpec != SCS_unspecified || + SCS_thread_specified) + Res |= PQ_StorageClassSpecifier; + + if (TypeQualifiers != TQ_unspecified) + Res |= PQ_TypeQualifier; + + if (hasTypeSpecifier()) + Res |= PQ_TypeSpecifier; + + if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified) + Res |= PQ_FunctionSpecifier; + return Res; +} + +template static bool BadSpecifier(T TNew, T TPrev, + const char *&PrevSpec, + unsigned &DiagID) { + PrevSpec = DeclSpec::getSpecifierName(TPrev); + DiagID = (TNew == TPrev ? diag::ext_duplicate_declspec + : diag::err_invalid_decl_spec_combination); + return true; +} + +const char *DeclSpec::getSpecifierName(DeclSpec::SCS S) { + switch (S) { + case DeclSpec::SCS_unspecified: return "unspecified"; + case DeclSpec::SCS_typedef: return "typedef"; + case DeclSpec::SCS_extern: return "extern"; + case DeclSpec::SCS_static: return "static"; + case DeclSpec::SCS_auto: return "auto"; + case DeclSpec::SCS_register: return "register"; + case DeclSpec::SCS_private_extern: return "__private_extern__"; + case DeclSpec::SCS_mutable: return "mutable"; + } + llvm_unreachable("Unknown typespec!"); +} + +const char *DeclSpec::getSpecifierName(TSW W) { + switch (W) { + case TSW_unspecified: return "unspecified"; + case TSW_short: return "short"; + case TSW_long: return "long"; + case TSW_longlong: return "long long"; + } + llvm_unreachable("Unknown typespec!"); +} + +const char *DeclSpec::getSpecifierName(TSC C) { + switch (C) { + case TSC_unspecified: return "unspecified"; + case TSC_imaginary: return "imaginary"; + case TSC_complex: return "complex"; + } + llvm_unreachable("Unknown typespec!"); +} + + +const char *DeclSpec::getSpecifierName(TSS S) { + switch (S) { + case TSS_unspecified: return "unspecified"; + case TSS_signed: return "signed"; + case TSS_unsigned: return "unsigned"; + } + llvm_unreachable("Unknown typespec!"); +} + +const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { + switch (T) { + case DeclSpec::TST_unspecified: return "unspecified"; + case DeclSpec::TST_void: return "void"; + case DeclSpec::TST_char: return "char"; + case DeclSpec::TST_wchar: return "wchar_t"; + case DeclSpec::TST_char16: return "char16_t"; + case DeclSpec::TST_char32: return "char32_t"; + case DeclSpec::TST_int: return "int"; + case DeclSpec::TST_float: return "float"; + case DeclSpec::TST_double: return "double"; + case DeclSpec::TST_bool: return "_Bool"; + case DeclSpec::TST_decimal32: return "_Decimal32"; + case DeclSpec::TST_decimal64: return "_Decimal64"; + case DeclSpec::TST_decimal128: return "_Decimal128"; + case DeclSpec::TST_enum: return "enum"; + case DeclSpec::TST_class: return "class"; + case DeclSpec::TST_union: return "union"; + case DeclSpec::TST_struct: return "struct"; + case DeclSpec::TST_typename: return "type-name"; + case DeclSpec::TST_typeofType: + case DeclSpec::TST_typeofExpr: return "typeof"; + case DeclSpec::TST_auto: return "auto"; + case DeclSpec::TST_decltype: return "(decltype)"; + case DeclSpec::TST_error: return "(error)"; + } + llvm_unreachable("Unknown typespec!"); +} + +const char *DeclSpec::getSpecifierName(TQ T) { + switch (T) { + case DeclSpec::TQ_unspecified: return "unspecified"; + case DeclSpec::TQ_const: return "const"; + case DeclSpec::TQ_restrict: return "restrict"; + case DeclSpec::TQ_volatile: return "volatile"; + } + llvm_unreachable("Unknown typespec!"); +} + +bool DeclSpec::SetStorageClassSpec(SCS S, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID) { + if (StorageClassSpec != SCS_unspecified) { + // Changing storage class is allowed only if the previous one + // was the 'extern' that is part of a linkage specification and + // the new storage class is 'typedef'. + if (!(SCS_extern_in_linkage_spec && + StorageClassSpec == SCS_extern && + S == SCS_typedef)) + return BadSpecifier(S, (SCS)StorageClassSpec, PrevSpec, DiagID); + } + StorageClassSpec = S; + StorageClassSpecLoc = Loc; + assert((unsigned)S == StorageClassSpec && "SCS constants overflow bitfield"); + return false; +} + +bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID) { + if (SCS_thread_specified) { + PrevSpec = "__thread"; + DiagID = diag::ext_duplicate_declspec; + return true; + } + SCS_thread_specified = true; + SCS_threadLoc = Loc; + return false; +} + +/// These methods set the specified attribute of the DeclSpec, but return true +/// and ignore the request if invalid (e.g. "extern" then "auto" is +/// specified). +bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID) { + if (TypeSpecWidth != TSW_unspecified && + // Allow turning long -> long long. + (W != TSW_longlong || TypeSpecWidth != TSW_long)) + return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID); + TypeSpecWidth = W; + TSWLoc = Loc; + if (TypeAltiVecVector && !TypeAltiVecBool && + ((TypeSpecWidth == TSW_long) || (TypeSpecWidth == TSW_longlong))) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::warn_vector_long_decl_spec_combination; + return true; + } + return false; +} + +bool DeclSpec::SetTypeSpecComplex(TSC C, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID) { + if (TypeSpecComplex != TSC_unspecified) + return BadSpecifier(C, (TSC)TypeSpecComplex, PrevSpec, DiagID); + TypeSpecComplex = C; + TSCLoc = Loc; + return false; +} + +bool DeclSpec::SetTypeSpecSign(TSS S, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID) { + if (TypeSpecSign != TSS_unspecified) + return BadSpecifier(S, (TSS)TypeSpecSign, PrevSpec, DiagID); + TypeSpecSign = S; + TSSLoc = Loc; + return false; +} + +bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID, + ParsedType Rep) { + assert(isTypeRep(T) && "T does not store a type"); + assert(Rep && "no type provided!"); + if (TypeSpecType != TST_unspecified) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_decl_spec_combination; + return true; + } + TypeSpecType = T; + TypeRep = Rep; + TSTLoc = Loc; + TypeSpecOwned = false; + return false; +} + +bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID, + Expr *Rep) { + assert(isExprRep(T) && "T does not store an expr"); + assert(Rep && "no expression provided!"); + if (TypeSpecType != TST_unspecified) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_decl_spec_combination; + return true; + } + TypeSpecType = T; + ExprRep = Rep; + TSTLoc = Loc; + TypeSpecOwned = false; + return false; +} + +bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID, + Decl *Rep, bool Owned) { + assert(isDeclRep(T) && "T does not store a decl"); + // Unlike the other cases, we don't assert that we actually get a decl. + + if (TypeSpecType != TST_unspecified) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_decl_spec_combination; + return true; + } + TypeSpecType = T; + DeclRep = Rep; + TSTLoc = Loc; + TypeSpecOwned = Owned; + return false; +} + +bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, + const char *&PrevSpec, + unsigned &DiagID) { + assert(!isDeclRep(T) && !isTypeRep(T) && !isExprRep(T) && + "rep required for these type-spec kinds!"); + if (TypeSpecType != TST_unspecified) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_decl_spec_combination; + return true; + } + if (TypeAltiVecVector && (T == TST_bool) && !TypeAltiVecBool) { + TypeAltiVecBool = true; + TSTLoc = Loc; + return false; + } + TypeSpecType = T; + TSTLoc = Loc; + TypeSpecOwned = false; + if (TypeAltiVecVector && !TypeAltiVecBool && (TypeSpecType == TST_double)) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_vector_decl_spec; + return true; + } + return false; +} + +bool DeclSpec::SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID) { + if (TypeSpecType != TST_unspecified) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_vector_decl_spec_combination; + return true; + } + TypeAltiVecVector = isAltiVecVector; + AltiVecLoc = Loc; + return false; +} + +bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID) { + if (!TypeAltiVecVector || TypeAltiVecPixel || + (TypeSpecType != TST_unspecified)) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); + DiagID = diag::err_invalid_pixel_decl_spec_combination; + return true; + } + TypeAltiVecPixel = isAltiVecPixel; + TSTLoc = Loc; + return false; +} + +bool DeclSpec::SetTypeSpecError() { + TypeSpecType = TST_error; + TypeSpecOwned = false; + TSTLoc = SourceLocation(); + return false; +} + +bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, const LangOptions &Lang) { + // Duplicates turn into warnings pre-C99. + if ((TypeQualifiers & T) && !Lang.C99) + return BadSpecifier(T, T, PrevSpec, DiagID); + TypeQualifiers |= T; + + switch (T) { + default: assert(0 && "Unknown type qualifier!"); + case TQ_const: TQ_constLoc = Loc; break; + case TQ_restrict: TQ_restrictLoc = Loc; break; + case TQ_volatile: TQ_volatileLoc = Loc; break; + } + return false; +} + +bool DeclSpec::SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + // 'inline inline' is ok. + FS_inline_specified = true; + FS_inlineLoc = Loc; + return false; +} + +bool DeclSpec::SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + // 'virtual virtual' is ok. + FS_virtual_specified = true; + FS_virtualLoc = Loc; + return false; +} + +bool DeclSpec::SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + // 'explicit explicit' is ok. + FS_explicit_specified = true; + FS_explicitLoc = Loc; + return false; +} + +bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + if (Friend_specified) { + PrevSpec = "friend"; + DiagID = diag::ext_duplicate_declspec; + return true; + } + + Friend_specified = true; + FriendLoc = Loc; + return false; +} + +bool DeclSpec::SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID) { + // 'constexpr constexpr' is ok. + Constexpr_specified = true; + ConstexprLoc = Loc; + return false; +} + +void DeclSpec::setProtocolQualifiers(Decl * const *Protos, + unsigned NP, + SourceLocation *ProtoLocs, + SourceLocation LAngleLoc) { + if (NP == 0) return; + ProtocolQualifiers = new Decl*[NP]; + ProtocolLocs = new SourceLocation[NP]; + memcpy((void*)ProtocolQualifiers, Protos, sizeof(Decl*)*NP); + memcpy(ProtocolLocs, ProtoLocs, sizeof(SourceLocation)*NP); + NumProtocolQualifiers = NP; + ProtocolLAngleLoc = LAngleLoc; +} + +void DeclSpec::SaveWrittenBuiltinSpecs() { + writtenBS.Sign = getTypeSpecSign(); + writtenBS.Width = getTypeSpecWidth(); + writtenBS.Type = getTypeSpecType(); + // Search the list of attributes for the presence of a mode attribute. + writtenBS.ModeAttr = false; + AttributeList* attrs = getAttributes(); + while (attrs) { + if (attrs->getKind() == AttributeList::AT_mode) { + writtenBS.ModeAttr = true; + break; + } + attrs = attrs->getNext(); + } +} + +void DeclSpec::SaveStorageSpecifierAsWritten() { + if (SCS_extern_in_linkage_spec && StorageClassSpec == SCS_extern) + // If 'extern' is part of a linkage specification, + // then it is not a storage class "as written". + StorageClassSpecAsWritten = SCS_unspecified; + else + StorageClassSpecAsWritten = StorageClassSpec; +} + +/// Finish - This does final analysis of the declspec, rejecting things like +/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or +/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, +/// DeclSpec is guaranteed self-consistent, even if an error occurred. +void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { + // Before possibly changing their values, save specs as written. + SaveWrittenBuiltinSpecs(); + SaveStorageSpecifierAsWritten(); + + // Check the type specifier components first. + SourceManager &SrcMgr = PP.getSourceManager(); + + // Validate and finalize AltiVec vector declspec. + if (TypeAltiVecVector) { + if (TypeAltiVecBool) { + // Sign specifiers are not allowed with vector bool. (PIM 2.1) + if (TypeSpecSign != TSS_unspecified) { + Diag(D, TSSLoc, SrcMgr, diag::err_invalid_vector_bool_decl_spec) + << getSpecifierName((TSS)TypeSpecSign); + } + + // Only char/int are valid with vector bool. (PIM 2.1) + if (((TypeSpecType != TST_unspecified) && (TypeSpecType != TST_char) && + (TypeSpecType != TST_int)) || TypeAltiVecPixel) { + Diag(D, TSTLoc, SrcMgr, diag::err_invalid_vector_bool_decl_spec) + << (TypeAltiVecPixel ? "__pixel" : + getSpecifierName((TST)TypeSpecType)); + } + + // Only 'short' is valid with vector bool. (PIM 2.1) + if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short)) + Diag(D, TSWLoc, SrcMgr, diag::err_invalid_vector_bool_decl_spec) + << getSpecifierName((TSW)TypeSpecWidth); + + // Elements of vector bool are interpreted as unsigned. (PIM 2.1) + if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) || + (TypeSpecWidth != TSW_unspecified)) + TypeSpecSign = TSS_unsigned; + } + + if (TypeAltiVecPixel) { + //TODO: perform validation + TypeSpecType = TST_int; + TypeSpecSign = TSS_unsigned; + TypeSpecWidth = TSW_short; + TypeSpecOwned = false; + } + } + + // signed/unsigned are only valid with int/char/wchar_t. + if (TypeSpecSign != TSS_unspecified) { + if (TypeSpecType == TST_unspecified) + TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. + else if (TypeSpecType != TST_int && + TypeSpecType != TST_char && TypeSpecType != TST_wchar) { + Diag(D, TSSLoc, SrcMgr, diag::err_invalid_sign_spec) + << getSpecifierName((TST)TypeSpecType); + // signed double -> double. + TypeSpecSign = TSS_unspecified; + } + } + + // Validate the width of the type. + switch (TypeSpecWidth) { + case TSW_unspecified: break; + case TSW_short: // short int + case TSW_longlong: // long long int + if (TypeSpecType == TST_unspecified) + TypeSpecType = TST_int; // short -> short int, long long -> long long int. + else if (TypeSpecType != TST_int) { + Diag(D, TSWLoc, SrcMgr, + TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec + : diag::err_invalid_longlong_spec) + << getSpecifierName((TST)TypeSpecType); + TypeSpecType = TST_int; + TypeSpecOwned = false; + } + break; + case TSW_long: // long double, long int + if (TypeSpecType == TST_unspecified) + TypeSpecType = TST_int; // long -> long int. + else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { + Diag(D, TSWLoc, SrcMgr, diag::err_invalid_long_spec) + << getSpecifierName((TST)TypeSpecType); + TypeSpecType = TST_int; + TypeSpecOwned = false; + } + break; + } + + // TODO: if the implementation does not implement _Complex or _Imaginary, + // disallow their use. Need information about the backend. + if (TypeSpecComplex != TSC_unspecified) { + if (TypeSpecType == TST_unspecified) { + Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex) + << FixItHint::CreateInsertion( + PP.getLocForEndOfToken(getTypeSpecComplexLoc()), + " double"); + TypeSpecType = TST_double; // _Complex -> _Complex double. + } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { + // Note that this intentionally doesn't include _Complex _Bool. + Diag(D, TSTLoc, SrcMgr, diag::ext_integer_complex); + } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { + Diag(D, TSCLoc, SrcMgr, diag::err_invalid_complex_spec) + << getSpecifierName((TST)TypeSpecType); + TypeSpecComplex = TSC_unspecified; + } + } + + // C++ [class.friend]p6: + // No storage-class-specifier shall appear in the decl-specifier-seq + // of a friend declaration. + if (isFriendSpecified() && getStorageClassSpec()) { + DeclSpec::SCS SC = getStorageClassSpec(); + const char *SpecName = getSpecifierName(SC); + + SourceLocation SCLoc = getStorageClassSpecLoc(); + SourceLocation SCEndLoc = SCLoc.getFileLocWithOffset(strlen(SpecName)); + + Diag(D, SCLoc, SrcMgr, diag::err_friend_storage_spec) + << SpecName + << FixItHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc)); + + ClearStorageClassSpecs(); + } + + assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType)); + + // Okay, now we can infer the real type. + + // TODO: return "auto function" and other bad things based on the real type. + + // 'data definition has no type or storage class'? +} + +bool DeclSpec::isMissingDeclaratorOk() { + TST tst = getTypeSpecType(); + return isDeclRep(tst) && getRepAsDecl() != 0 && + StorageClassSpec != DeclSpec::SCS_typedef; +} + +void UnqualifiedId::clear() { + if (Kind == IK_TemplateId) + TemplateId->Destroy(); + + Kind = IK_Identifier; + Identifier = 0; + StartLocation = SourceLocation(); + EndLocation = SourceLocation(); +} + +void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc, + OverloadedOperatorKind Op, + SourceLocation SymbolLocations[3]) { + Kind = IK_OperatorFunctionId; + StartLocation = OperatorLoc; + EndLocation = OperatorLoc; + OperatorFunctionId.Operator = Op; + for (unsigned I = 0; I != 3; ++I) { + OperatorFunctionId.SymbolLocations[I] = SymbolLocations[I].getRawEncoding(); + + if (SymbolLocations[I].isValid()) + EndLocation = SymbolLocations[I]; + } +} diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp index b09526e..3f16ed7 100644 --- a/lib/Sema/IdentifierResolver.cpp +++ b/lib/Sema/IdentifierResolver.cpp @@ -12,7 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "IdentifierResolver.h" +#include "clang/Sema/IdentifierResolver.h" +#include "clang/Sema/Scope.h" +#include "clang/AST/Decl.h" #include "clang/Basic/LangOptions.h" using namespace clang; @@ -103,7 +105,7 @@ IdentifierResolver::~IdentifierResolver() { /// true if 'D' belongs to the given declaration context. bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, ASTContext &Context, Scope *S) const { - Ctx = Ctx->getLookupContext(); + Ctx = Ctx->getRedeclContext(); if (Ctx->isFunctionOrMethod()) { // Ignore the scopes associated within transparent declaration contexts. @@ -111,7 +113,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, ((DeclContext *)S->getEntity())->isTransparentContext()) S = S->getParent(); - if (S->isDeclScope(Action::DeclPtrTy::make(D))) + if (S->isDeclScope(D)) return true; if (LangOpt.CPlusPlus) { // C++ 3.3.2p3: @@ -128,17 +130,20 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, // assert(S->getParent() && "No TUScope?"); if (S->getParent()->getFlags() & Scope::ControlScope) - return S->getParent()->isDeclScope(Action::DeclPtrTy::make(D)); + return S->getParent()->isDeclScope(D); } return false; } - return D->getDeclContext()->getLookupContext()->Equals(Ctx); + return D->getDeclContext()->getRedeclContext()->Equals(Ctx); } /// AddDecl - Link the decl to its shadowed decl chain. void IdentifierResolver::AddDecl(NamedDecl *D) { DeclarationName Name = D->getDeclName(); + if (IdentifierInfo *II = Name.getAsIdentifierInfo()) + II->setIsFromAST(false); + void *Ptr = Name.getFETokenInfo(); if (!Ptr) { @@ -164,6 +169,9 @@ void IdentifierResolver::AddDecl(NamedDecl *D) { void IdentifierResolver::RemoveDecl(NamedDecl *D) { assert(D && "null param passed"); DeclarationName Name = D->getDeclName(); + if (IdentifierInfo *II = Name.getAsIdentifierInfo()) + II->setIsFromAST(false); + void *Ptr = Name.getFETokenInfo(); assert(Ptr && "Didn't find this decl on its identifier's chain!"); @@ -182,6 +190,9 @@ bool IdentifierResolver::ReplaceDecl(NamedDecl *Old, NamedDecl *New) { "Cannot replace a decl with another decl of a different name"); DeclarationName Name = Old->getDeclName(); + if (IdentifierInfo *II = Name.getAsIdentifierInfo()) + II->setIsFromAST(false); + void *Ptr = Name.getFETokenInfo(); if (!Ptr) @@ -218,6 +229,7 @@ IdentifierResolver::begin(DeclarationName Name) { void IdentifierResolver::AddDeclToIdentifierChain(IdentifierInfo *II, NamedDecl *D) { + II->setIsFromAST(false); void *Ptr = II->getFETokenInfo(); if (!Ptr) { @@ -261,3 +273,16 @@ IdentifierResolver::IdDeclInfoMap::operator[](DeclarationName Name) { ++CurIndex; return *IDI; } + +void IdentifierResolver::iterator::incrementSlowCase() { + NamedDecl *D = **this; + void *InfoPtr = D->getDeclName().getFETokenInfo(); + assert(!isDeclPtr(InfoPtr) && "Decl with wrong id ?"); + IdDeclInfo *Info = toIdDeclInfo(InfoPtr); + + BaseIter I = getIterator(); + if (I != Info->decls_begin()) + *this = iterator(I-1); + else // No more decls. + *this = iterator(); +} diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h deleted file mode 100644 index 59bd834..0000000 --- a/lib/Sema/IdentifierResolver.h +++ /dev/null @@ -1,203 +0,0 @@ -//===- IdentifierResolver.h - Lexical Scope Name lookup ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the IdentifierResolver class, which is used for lexical -// scoped lookup, based on declaration names. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_AST_SEMA_IDENTIFIERRESOLVER_H -#define LLVM_CLANG_AST_SEMA_IDENTIFIERRESOLVER_H - -#include "clang/Basic/IdentifierTable.h" -#include "clang/Parse/Scope.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclarationName.h" -#include "clang/AST/DeclCXX.h" - -namespace clang { - -/// IdentifierResolver - Keeps track of shadowed decls on enclosing -/// scopes. It manages the shadowing chains of declaration names and -/// implements efficent decl lookup based on a declaration name. -class IdentifierResolver { - - /// IdDeclInfo - Keeps track of information about decls associated - /// to a particular declaration name. IdDeclInfos are lazily - /// constructed and assigned to a declaration name the first time a - /// decl with that declaration name is shadowed in some scope. - class IdDeclInfo { - public: - typedef llvm::SmallVector DeclsTy; - - inline DeclsTy::iterator decls_begin() { return Decls.begin(); } - inline DeclsTy::iterator decls_end() { return Decls.end(); } - - void AddDecl(NamedDecl *D) { Decls.push_back(D); } - - /// RemoveDecl - Remove the decl from the scope chain. - /// The decl must already be part of the decl chain. - void RemoveDecl(NamedDecl *D); - - /// Replaces the Old declaration with the New declaration. If the - /// replacement is successful, returns true. If the old - /// declaration was not found, returns false. - bool ReplaceDecl(NamedDecl *Old, NamedDecl *New); - - private: - DeclsTy Decls; - }; - -public: - - /// iterator - Iterate over the decls of a specified declaration name. - /// It will walk or not the parent declaration contexts depending on how - /// it was instantiated. - class iterator { - public: - typedef NamedDecl * value_type; - typedef NamedDecl * reference; - typedef NamedDecl * pointer; - typedef std::input_iterator_tag iterator_category; - typedef std::ptrdiff_t difference_type; - - /// Ptr - There are 3 forms that 'Ptr' represents: - /// 1) A single NamedDecl. (Ptr & 0x1 == 0) - /// 2) A IdDeclInfo::DeclsTy::iterator that traverses only the decls of the - /// same declaration context. (Ptr & 0x3 == 0x1) - /// 3) A IdDeclInfo::DeclsTy::iterator that traverses the decls of parent - /// declaration contexts too. (Ptr & 0x3 == 0x3) - uintptr_t Ptr; - typedef IdDeclInfo::DeclsTy::iterator BaseIter; - - /// A single NamedDecl. (Ptr & 0x1 == 0) - iterator(NamedDecl *D) { - Ptr = reinterpret_cast(D); - assert((Ptr & 0x1) == 0 && "Invalid Ptr!"); - } - /// A IdDeclInfo::DeclsTy::iterator that walks or not the parent declaration - /// contexts depending on 'LookInParentCtx'. - iterator(BaseIter I) { - Ptr = reinterpret_cast(I) | 0x1; - } - - bool isIterator() const { return (Ptr & 0x1); } - - BaseIter getIterator() const { - assert(isIterator() && "Ptr not an iterator!"); - return reinterpret_cast(Ptr & ~0x3); - } - - friend class IdentifierResolver; - public: - iterator() : Ptr(0) {} - - NamedDecl *operator*() const { - if (isIterator()) - return *getIterator(); - else - return reinterpret_cast(Ptr); - } - - bool operator==(const iterator &RHS) const { - return Ptr == RHS.Ptr; - } - bool operator!=(const iterator &RHS) const { - return Ptr != RHS.Ptr; - } - - // Preincrement. - iterator& operator++() { - if (!isIterator()) // common case. - Ptr = 0; - else { - NamedDecl *D = **this; - void *InfoPtr = D->getDeclName().getFETokenInfo(); - assert(!isDeclPtr(InfoPtr) && "Decl with wrong id ?"); - IdDeclInfo *Info = toIdDeclInfo(InfoPtr); - - BaseIter I = getIterator(); - if (I != Info->decls_begin()) - *this = iterator(I-1); - else // No more decls. - *this = iterator(); - } - return *this; - } - - uintptr_t getAsOpaqueValue() const { return Ptr; } - - static iterator getFromOpaqueValue(uintptr_t P) { - iterator Result; - Result.Ptr = P; - return Result; - } - }; - - /// begin - Returns an iterator for decls with the name 'Name'. - static iterator begin(DeclarationName Name); - - /// end - Returns an iterator that has 'finished'. - static iterator end() { - return iterator(); - } - - /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true - /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns - /// true if 'D' belongs to the given declaration context. - bool isDeclInScope(Decl *D, DeclContext *Ctx, ASTContext &Context, - Scope *S = 0) const; - - /// AddDecl - Link the decl to its shadowed decl chain. - void AddDecl(NamedDecl *D); - - /// RemoveDecl - Unlink the decl from its shadowed decl chain. - /// The decl must already be part of the decl chain. - void RemoveDecl(NamedDecl *D); - - /// Replace the decl Old with the new declaration New on its - /// identifier chain. Returns true if the old declaration was found - /// (and, therefore, replaced). - bool ReplaceDecl(NamedDecl *Old, NamedDecl *New); - - /// \brief Link the declaration into the chain of declarations for - /// the given identifier. - /// - /// This is a lower-level routine used by the PCH reader to link a - /// declaration into a specific IdentifierInfo before the - /// declaration actually has a name. - void AddDeclToIdentifierChain(IdentifierInfo *II, NamedDecl *D); - - explicit IdentifierResolver(const LangOptions &LangOpt); - ~IdentifierResolver(); - -private: - const LangOptions &LangOpt; - - class IdDeclInfoMap; - IdDeclInfoMap *IdDeclInfos; - - /// FETokenInfo contains a Decl pointer if lower bit == 0. - static inline bool isDeclPtr(void *Ptr) { - return (reinterpret_cast(Ptr) & 0x1) == 0; - } - - /// FETokenInfo contains a IdDeclInfo pointer if lower bit == 1. - static inline IdDeclInfo *toIdDeclInfo(void *Ptr) { - assert((reinterpret_cast(Ptr) & 0x1) == 1 - && "Ptr not a IdDeclInfo* !"); - return reinterpret_cast( - reinterpret_cast(Ptr) & ~0x1 - ); - } -}; - -} // end namespace clang - -#endif diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index 3431ac6..b23f615 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -12,11 +12,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/BitVector.h" -#include "Sema.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" +#include "llvm/ADT/BitVector.h" using namespace clang; namespace { @@ -180,12 +181,6 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { // If we found a label, remember that it is in ParentScope scope. switch (S->getStmtClass()) { - case Stmt::LabelStmtClass: - case Stmt::DefaultStmtClass: - case Stmt::CaseStmtClass: - LabelAndGotoScopes[S] = ParentScope; - break; - case Stmt::AddrLabelExprClass: IndirectJumpTargets.push_back(cast(S)->getLabel()); break; @@ -225,6 +220,24 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { Stmt *SubStmt = *CI; if (SubStmt == 0) continue; + // Cases, labels, and defaults aren't "scope parents". It's also + // important to handle these iteratively instead of recursively in + // order to avoid blowing out the stack. + while (true) { + Stmt *Next; + if (isa(SubStmt)) + Next = cast(SubStmt)->getSubStmt(); + else if (isa(SubStmt)) + Next = cast(SubStmt)->getSubStmt(); + else if (isa(SubStmt)) + Next = cast(SubStmt)->getSubStmt(); + else + break; + + LabelAndGotoScopes[SubStmt] = ParentScope; + SubStmt = Next; + } + // If this is a declstmt with a VLA definition, it defines a scope from here // to the end of the containing context. if (DeclStmt *DS = dyn_cast(SubStmt)) { diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h deleted file mode 100644 index 271bb5b..0000000 --- a/lib/Sema/Lookup.h +++ /dev/null @@ -1,654 +0,0 @@ -//===--- Lookup.h - Classes for name lookup ---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the LookupResult class, which is integral to -// Sema's name-lookup subsystem. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_SEMA_LOOKUP_H -#define LLVM_CLANG_SEMA_LOOKUP_H - -#include "Sema.h" - -namespace clang { - -/// @brief Represents the results of name lookup. -/// -/// An instance of the LookupResult class captures the results of a -/// single name lookup, which can return no result (nothing found), -/// a single declaration, a set of overloaded functions, or an -/// ambiguity. Use the getKind() method to determine which of these -/// results occurred for a given lookup. -class LookupResult { -public: - enum LookupResultKind { - /// @brief No entity found met the criteria. - NotFound = 0, - - /// @brief No entity found met the criteria within the current - /// instantiation,, but there were dependent base classes of the - /// current instantiation that could not be searched. - NotFoundInCurrentInstantiation, - - /// @brief Name lookup found a single declaration that met the - /// criteria. getFoundDecl() will return this declaration. - Found, - - /// @brief Name lookup found a set of overloaded functions that - /// met the criteria. - FoundOverloaded, - - /// @brief Name lookup found an unresolvable value declaration - /// and cannot yet complete. This only happens in C++ dependent - /// contexts with dependent using declarations. - FoundUnresolvedValue, - - /// @brief Name lookup results in an ambiguity; use - /// getAmbiguityKind to figure out what kind of ambiguity - /// we have. - Ambiguous - }; - - enum AmbiguityKind { - /// Name lookup results in an ambiguity because multiple - /// entities that meet the lookup criteria were found in - /// subobjects of different types. For example: - /// @code - /// struct A { void f(int); } - /// struct B { void f(double); } - /// struct C : A, B { }; - /// void test(C c) { - /// c.f(0); // error: A::f and B::f come from subobjects of different - /// // types. overload resolution is not performed. - /// } - /// @endcode - AmbiguousBaseSubobjectTypes, - - /// Name lookup results in an ambiguity because multiple - /// nonstatic entities that meet the lookup criteria were found - /// in different subobjects of the same type. For example: - /// @code - /// struct A { int x; }; - /// struct B : A { }; - /// struct C : A { }; - /// struct D : B, C { }; - /// int test(D d) { - /// return d.x; // error: 'x' is found in two A subobjects (of B and C) - /// } - /// @endcode - AmbiguousBaseSubobjects, - - /// Name lookup results in an ambiguity because multiple definitions - /// of entity that meet the lookup criteria were found in different - /// declaration contexts. - /// @code - /// namespace A { - /// int i; - /// namespace B { int i; } - /// int test() { - /// using namespace B; - /// return i; // error 'i' is found in namespace A and A::B - /// } - /// } - /// @endcode - AmbiguousReference, - - /// Name lookup results in an ambiguity because an entity with a - /// tag name was hidden by an entity with an ordinary name from - /// a different context. - /// @code - /// namespace A { struct Foo {}; } - /// namespace B { void Foo(); } - /// namespace C { - /// using namespace A; - /// using namespace B; - /// } - /// void test() { - /// C::Foo(); // error: tag 'A::Foo' is hidden by an object in a - /// // different namespace - /// } - /// @endcode - AmbiguousTagHiding - }; - - /// A little identifier for flagging temporary lookup results. - enum TemporaryToken { - Temporary - }; - - typedef UnresolvedSetImpl::iterator iterator; - - LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc, - Sema::LookupNameKind LookupKind, - Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) - : ResultKind(NotFound), - Paths(0), - NamingClass(0), - SemaRef(SemaRef), - Name(Name), - NameLoc(NameLoc), - LookupKind(LookupKind), - IDNS(0), - Redecl(Redecl != Sema::NotForRedeclaration), - HideTags(true), - Diagnose(Redecl == Sema::NotForRedeclaration) - { - configure(); - } - - /// Creates a temporary lookup result, initializing its core data - /// using the information from another result. Diagnostics are always - /// disabled. - LookupResult(TemporaryToken _, const LookupResult &Other) - : ResultKind(NotFound), - Paths(0), - NamingClass(0), - SemaRef(Other.SemaRef), - Name(Other.Name), - NameLoc(Other.NameLoc), - LookupKind(Other.LookupKind), - IDNS(Other.IDNS), - Redecl(Other.Redecl), - HideTags(Other.HideTags), - Diagnose(false) - {} - - ~LookupResult() { - if (Diagnose) diagnose(); - if (Paths) deletePaths(Paths); - } - - /// Gets the name to look up. - DeclarationName getLookupName() const { - return Name; - } - - /// \brief Sets the name to look up. - void setLookupName(DeclarationName Name) { - this->Name = Name; - } - - /// Gets the kind of lookup to perform. - Sema::LookupNameKind getLookupKind() const { - return LookupKind; - } - - /// True if this lookup is just looking for an existing declaration. - bool isForRedeclaration() const { - return Redecl; - } - - /// Sets whether tag declarations should be hidden by non-tag - /// declarations during resolution. The default is true. - void setHideTags(bool Hide) { - HideTags = Hide; - } - - bool isAmbiguous() const { - return getResultKind() == Ambiguous; - } - - /// Determines if this names a single result which is not an - /// unresolved value using decl. If so, it is safe to call - /// getFoundDecl(). - bool isSingleResult() const { - return getResultKind() == Found; - } - - /// Determines if the results are overloaded. - bool isOverloadedResult() const { - return getResultKind() == FoundOverloaded; - } - - bool isUnresolvableResult() const { - return getResultKind() == FoundUnresolvedValue; - } - - LookupResultKind getResultKind() const { - sanity(); - return ResultKind; - } - - AmbiguityKind getAmbiguityKind() const { - assert(isAmbiguous()); - return Ambiguity; - } - - const UnresolvedSetImpl &asUnresolvedSet() const { - return Decls; - } - - iterator begin() const { return iterator(Decls.begin()); } - iterator end() const { return iterator(Decls.end()); } - - /// \brief Return true if no decls were found - bool empty() const { return Decls.empty(); } - - /// \brief Return the base paths structure that's associated with - /// these results, or null if none is. - CXXBasePaths *getBasePaths() const { - return Paths; - } - - /// \brief Tests whether the given declaration is acceptable. - bool isAcceptableDecl(NamedDecl *D) const { - return D->isInIdentifierNamespace(IDNS); - } - - /// \brief Returns the identifier namespace mask for this lookup. - unsigned getIdentifierNamespace() const { - return IDNS; - } - - /// \brief Returns whether these results arose from performing a - /// lookup into a class. - bool isClassLookup() const { - return NamingClass != 0; - } - - /// \brief Returns the 'naming class' for this lookup, i.e. the - /// class which was looked into to find these results. - /// - /// C++0x [class.access.base]p5: - /// The access to a member is affected by the class in which the - /// member is named. This naming class is the class in which the - /// member name was looked up and found. [Note: this class can be - /// explicit, e.g., when a qualified-id is used, or implicit, - /// e.g., when a class member access operator (5.2.5) is used - /// (including cases where an implicit "this->" is added). If both - /// a class member access operator and a qualified-id are used to - /// name the member (as in p->T::m), the class naming the member - /// is the class named by the nested-name-specifier of the - /// qualified-id (that is, T). -- end note ] - /// - /// This is set by the lookup routines when they find results in a class. - CXXRecordDecl *getNamingClass() const { - return NamingClass; - } - - /// \brief Sets the 'naming class' for this lookup. - void setNamingClass(CXXRecordDecl *Record) { - NamingClass = Record; - } - - /// \brief Returns the base object type associated with this lookup; - /// important for [class.protected]. Most lookups do not have an - /// associated base object. - QualType getBaseObjectType() const { - return BaseObjectType; - } - - /// \brief Sets the base object type for this lookup. - void setBaseObjectType(QualType T) { - BaseObjectType = T; - } - - /// \brief Add a declaration to these results with its natural access. - /// Does not test the acceptance criteria. - void addDecl(NamedDecl *D) { - addDecl(D, D->getAccess()); - } - - /// \brief Add a declaration to these results with the given access. - /// Does not test the acceptance criteria. - void addDecl(NamedDecl *D, AccessSpecifier AS) { - Decls.addDecl(D, AS); - ResultKind = Found; - } - - /// \brief Add all the declarations from another set of lookup - /// results. - void addAllDecls(const LookupResult &Other) { - Decls.append(Other.Decls.begin(), Other.Decls.end()); - ResultKind = Found; - } - - /// \brief Determine whether no result was found because we could not - /// search into dependent base classes of the current instantiation. - bool wasNotFoundInCurrentInstantiation() const { - return ResultKind == NotFoundInCurrentInstantiation; - } - - /// \brief Note that while no result was found in the current instantiation, - /// there were dependent base classes that could not be searched. - void setNotFoundInCurrentInstantiation() { - assert(ResultKind == NotFound && Decls.empty()); - ResultKind = NotFoundInCurrentInstantiation; - } - - /// \brief Resolves the result kind of the lookup, possibly hiding - /// decls. - /// - /// This should be called in any environment where lookup might - /// generate multiple lookup results. - void resolveKind(); - - /// \brief Re-resolves the result kind of the lookup after a set of - /// removals has been performed. - void resolveKindAfterFilter() { - if (Decls.empty()) { - if (ResultKind != NotFoundInCurrentInstantiation) - ResultKind = NotFound; - } else { - ResultKind = Found; - resolveKind(); - - if (Paths && (ResultKind != Ambiguous)) { - deletePaths(Paths); - Paths = 0; - } - } - } - - template - DeclClass *getAsSingle() const { - if (getResultKind() != Found) return 0; - return dyn_cast(getFoundDecl()); - } - - /// \brief Fetch the unique decl found by this lookup. Asserts - /// that one was found. - /// - /// This is intended for users who have examined the result kind - /// and are certain that there is only one result. - NamedDecl *getFoundDecl() const { - assert(getResultKind() == Found - && "getFoundDecl called on non-unique result"); - return (*begin())->getUnderlyingDecl(); - } - - /// Fetches a representative decl. Useful for lazy diagnostics. - NamedDecl *getRepresentativeDecl() const { - assert(!Decls.empty() && "cannot get representative of empty set"); - return *begin(); - } - - /// \brief Asks if the result is a single tag decl. - bool isSingleTagDecl() const { - return getResultKind() == Found && isa(getFoundDecl()); - } - - /// \brief Make these results show that the name was found in - /// base classes of different types. - /// - /// The given paths object is copied and invalidated. - void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P); - - /// \brief Make these results show that the name was found in - /// distinct base classes of the same type. - /// - /// The given paths object is copied and invalidated. - void setAmbiguousBaseSubobjects(CXXBasePaths &P); - - /// \brief Make these results show that the name was found in - /// different contexts and a tag decl was hidden by an ordinary - /// decl in a different context. - void setAmbiguousQualifiedTagHiding() { - setAmbiguous(AmbiguousTagHiding); - } - - /// \brief Clears out any current state. - void clear() { - ResultKind = NotFound; - Decls.clear(); - if (Paths) deletePaths(Paths); - Paths = NULL; - } - - /// \brief Clears out any current state and re-initializes for a - /// different kind of lookup. - void clear(Sema::LookupNameKind Kind) { - clear(); - LookupKind = Kind; - configure(); - } - - /// \brief Change this lookup's redeclaration kind. - void setRedeclarationKind(Sema::RedeclarationKind RK) { - Redecl = RK; - configure(); - } - - void print(llvm::raw_ostream &); - - /// Suppress the diagnostics that would normally fire because of this - /// lookup. This happens during (e.g.) redeclaration lookups. - void suppressDiagnostics() { - Diagnose = false; - } - - /// Determines whether this lookup is suppressing diagnostics. - bool isSuppressingDiagnostics() const { - return Diagnose; - } - - /// Sets a 'context' source range. - void setContextRange(SourceRange SR) { - NameContextRange = SR; - } - - /// Gets the source range of the context of this name; for C++ - /// qualified lookups, this is the source range of the scope - /// specifier. - SourceRange getContextRange() const { - return NameContextRange; - } - - /// Gets the location of the identifier. This isn't always defined: - /// sometimes we're doing lookups on synthesized names. - SourceLocation getNameLoc() const { - return NameLoc; - } - - /// \brief Get the Sema object that this lookup result is searching - /// with. - Sema &getSema() const { return SemaRef; } - - /// A class for iterating through a result set and possibly - /// filtering out results. The results returned are possibly - /// sugared. - class Filter { - LookupResult &Results; - LookupResult::iterator I; - bool Changed; -#ifndef NDEBUG - bool CalledDone; -#endif - - friend class LookupResult; - Filter(LookupResult &Results) - : Results(Results), I(Results.begin()), Changed(false) -#ifndef NDEBUG - , CalledDone(false) -#endif - {} - - public: -#ifndef NDEBUG - ~Filter() { - assert(CalledDone && - "LookupResult::Filter destroyed without done() call"); - } -#endif - - bool hasNext() const { - return I != Results.end(); - } - - NamedDecl *next() { - assert(I != Results.end() && "next() called on empty filter"); - return *I++; - } - - /// Erase the last element returned from this iterator. - void erase() { - Results.Decls.erase(--I); - Changed = true; - } - - /// Replaces the current entry with the given one, preserving the - /// access bits. - void replace(NamedDecl *D) { - Results.Decls.replace(I-1, D); - Changed = true; - } - - /// Replaces the current entry with the given one. - void replace(NamedDecl *D, AccessSpecifier AS) { - Results.Decls.replace(I-1, D, AS); - Changed = true; - } - - void done() { -#ifndef NDEBUG - assert(!CalledDone && "done() called twice"); - CalledDone = true; -#endif - - if (Changed) - Results.resolveKindAfterFilter(); - } - }; - - /// Create a filter for this result set. - Filter makeFilter() { - return Filter(*this); - } - -private: - void diagnose() { - if (isAmbiguous()) - SemaRef.DiagnoseAmbiguousLookup(*this); - else if (isClassLookup() && SemaRef.getLangOptions().AccessControl) - SemaRef.CheckLookupAccess(*this); - } - - void setAmbiguous(AmbiguityKind AK) { - ResultKind = Ambiguous; - Ambiguity = AK; - } - - void addDeclsFromBasePaths(const CXXBasePaths &P); - void configure(); - - // Sanity checks. - void sanity() const { - assert(ResultKind != NotFound || Decls.size() == 0); - assert(ResultKind != Found || Decls.size() == 1); - assert(ResultKind != FoundOverloaded || Decls.size() > 1 || - (Decls.size() == 1 && - isa((*begin())->getUnderlyingDecl()))); - assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved()); - assert(ResultKind != Ambiguous || Decls.size() > 1 || - (Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects)); - assert((Paths != NULL) == (ResultKind == Ambiguous && - (Ambiguity == AmbiguousBaseSubobjectTypes || - Ambiguity == AmbiguousBaseSubobjects))); - } - - bool sanityCheckUnresolved() const { - for (iterator I = begin(), E = end(); I != E; ++I) - if (isa(*I)) - return true; - return false; - } - - static void deletePaths(CXXBasePaths *); - - // Results. - LookupResultKind ResultKind; - AmbiguityKind Ambiguity; // ill-defined unless ambiguous - UnresolvedSet<8> Decls; - CXXBasePaths *Paths; - CXXRecordDecl *NamingClass; - QualType BaseObjectType; - - // Parameters. - Sema &SemaRef; - DeclarationName Name; - SourceLocation NameLoc; - SourceRange NameContextRange; - Sema::LookupNameKind LookupKind; - unsigned IDNS; // set by configure() - - bool Redecl; - - /// \brief True if tag declarations should be hidden if non-tags - /// are present - bool HideTags; - - bool Diagnose; -}; - - /// \brief Consumes visible declarations found when searching for - /// all visible names within a given scope or context. - /// - /// This abstract class is meant to be subclassed by clients of \c - /// Sema::LookupVisibleDecls(), each of which should override the \c - /// FoundDecl() function to process declarations as they are found. - class VisibleDeclConsumer { - public: - /// \brief Destroys the visible declaration consumer. - virtual ~VisibleDeclConsumer(); - - /// \brief Invoked each time \p Sema::LookupVisibleDecls() finds a - /// declaration visible from the current scope or context. - /// - /// \param ND the declaration found. - /// - /// \param Hiding a declaration that hides the declaration \p ND, - /// or NULL if no such declaration exists. - /// - /// \param InBaseClass whether this declaration was found in base - /// class of the context we searched. - virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, - bool InBaseClass) = 0; - }; - -/// \brief A class for storing results from argument-dependent lookup. -class ADLResult { -private: - /// A map from canonical decls to the 'most recent' decl. - llvm::DenseMap Decls; - -public: - /// Adds a new ADL candidate to this map. - void insert(NamedDecl *D); - - /// Removes any data associated with a given decl. - void erase(NamedDecl *D) { - Decls.erase(cast(D->getCanonicalDecl())); - } - - class iterator { - typedef llvm::DenseMap::iterator inner_iterator; - inner_iterator iter; - - friend class ADLResult; - iterator(const inner_iterator &iter) : iter(iter) {} - public: - iterator() {} - - iterator &operator++() { ++iter; return *this; } - iterator operator++(int) { return iterator(iter++); } - - NamedDecl *operator*() const { return iter->second; } - - bool operator==(const iterator &other) const { return iter == other.iter; } - bool operator!=(const iterator &other) const { return iter != other.iter; } - }; - - iterator begin() { return iterator(Decls.begin()); } - iterator end() { return iterator(Decls.end()); } -}; - -} - -#endif diff --git a/lib/Sema/Makefile b/lib/Sema/Makefile index 90f2dff..2c02739 100644 --- a/lib/Sema/Makefile +++ b/lib/Sema/Makefile @@ -14,7 +14,6 @@ CLANG_LEVEL := ../.. LIBRARYNAME := clangSema -BUILD_ARCHIVE = 1 include $(CLANG_LEVEL)/Makefile diff --git a/lib/Sema/ParseAST.cpp b/lib/Sema/ParseAST.cpp deleted file mode 100644 index bb0bd9e..0000000 --- a/lib/Sema/ParseAST.cpp +++ /dev/null @@ -1,125 +0,0 @@ -//===--- ParseAST.cpp - Provide the clang::ParseAST method ----------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the clang::ParseAST method. -// -//===----------------------------------------------------------------------===// - -#include "clang/Sema/ParseAST.h" -#include "Sema.h" -#include "clang/Sema/CodeCompleteConsumer.h" -#include "clang/Sema/SemaConsumer.h" -#include "clang/Sema/ExternalSemaSource.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ExternalASTSource.h" -#include "clang/AST/Stmt.h" -#include "clang/Parse/Parser.h" -#include - -using namespace clang; - -static void DumpRecordLayouts(ASTContext &C) { - for (ASTContext::type_iterator I = C.types_begin(), E = C.types_end(); - I != E; ++I) { - const RecordType *RT = dyn_cast(*I); - if (!RT) - continue; - - const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); - if (!RD || RD->isImplicit() || RD->isDependentType() || - RD->isInvalidDecl() || !RD->getDefinition()) - continue; - - // FIXME: Do we really need to hard code this? - if (RD->getQualifiedNameAsString() == "__va_list_tag") - continue; - - C.DumpRecordLayout(RD, llvm::errs()); - } -} - -//===----------------------------------------------------------------------===// -// Public interface to the file -//===----------------------------------------------------------------------===// - -/// ParseAST - Parse the entire file specified, notifying the ASTConsumer as -/// the file is parsed. This inserts the parsed decls into the translation unit -/// held by Ctx. -/// -void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, - ASTContext &Ctx, bool PrintStats, - bool CompleteTranslationUnit, - CodeCompleteConsumer *CompletionConsumer) { - // Collect global stats on Decls/Stmts (until we have a module streamer). - if (PrintStats) { - Decl::CollectingStats(true); - Stmt::CollectingStats(true); - } - - Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer); - Parser P(PP, S); - PP.EnterMainSourceFile(); - - // Initialize the parser. - P.Initialize(); - - Consumer->Initialize(Ctx); - - if (SemaConsumer *SC = dyn_cast(Consumer)) - SC->InitializeSema(S); - - if (ExternalASTSource *External = Ctx.getExternalSource()) { - if (ExternalSemaSource *ExternalSema = - dyn_cast(External)) - ExternalSema->InitializeSema(S); - - External->StartTranslationUnit(Consumer); - } - - Parser::DeclGroupPtrTy ADecl; - - while (!P.ParseTopLevelDecl(ADecl)) { // Not end of file. - // If we got a null return and something *was* parsed, ignore it. This - // is due to a top-level semicolon, an action override, or a parse error - // skipping something. - if (ADecl) - Consumer->HandleTopLevelDecl(ADecl.getAsVal()); - }; - // Check for any pending objective-c implementation decl. - while ((ADecl = P.RetrievePendingObjCImpDecl())) - Consumer->HandleTopLevelDecl(ADecl.getAsVal()); - - // Process any TopLevelDecls generated by #pragma weak. - for (llvm::SmallVector::iterator - I = S.WeakTopLevelDecls().begin(), - E = S.WeakTopLevelDecls().end(); I != E; ++I) - Consumer->HandleTopLevelDecl(DeclGroupRef(*I)); - - // Dump record layouts, if requested. - if (PP.getLangOptions().DumpRecordLayouts) - DumpRecordLayouts(Ctx); - - Consumer->HandleTranslationUnit(Ctx); - - if (ExternalSemaSource *ESS = - dyn_cast_or_null(Ctx.getExternalSource())) - ESS->ForgetSema(); - - if (SemaConsumer *SC = dyn_cast(Consumer)) - SC->ForgetSema(); - - if (PrintStats) { - fprintf(stderr, "\nSTATISTICS:\n"); - P.getActions().PrintStats(); - Ctx.PrintStats(); - Decl::PrintStats(); - Stmt::PrintStats(); - Consumer->PrintStats(); - } -} diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index cddc84e..17817d4 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -12,26 +12,36 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/DelayedDiagnostic.h" #include "TargetAttributesSema.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/APFloat.h" +#include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/ExternalSemaSource.h" -#include "clang/AST/ASTConsumer.h" +#include "clang/Sema/PrettyDeclStackTrace.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" using namespace clang; +using namespace sema; FunctionScopeInfo::~FunctionScopeInfo() { } void FunctionScopeInfo::Clear(unsigned NumErrors) { - NeedsScopeChecking = false; + HasBranchProtectedScope = false; + HasBranchIntoScope = false; + HasIndirectGoto = false; + LabelMap.clear(); SwitchStack.clear(); Returns.clear(); @@ -40,13 +50,13 @@ void FunctionScopeInfo::Clear(unsigned NumErrors) { BlockScopeInfo::~BlockScopeInfo() { } -void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { +void Sema::ActOnTranslationUnitScope(Scope *S) { TUScope = S; PushDeclContext(S, Context.getTranslationUnitDecl()); VAListTagName = PP.getIdentifierInfo("__va_list_tag"); - if (!Context.isInt128Installed() && // May be set by PCHReader. + if (!Context.isInt128Installed() && // May be set by ASTReader. PP.getTargetInfo().getPointerWidth(0) >= 64) { TypeSourceInfo *TInfo; @@ -68,7 +78,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { if (!PP.getLangOptions().ObjC1) return; - // Built-in ObjC types may already be set by PCHReader (hence isNull checks). + // Built-in ObjC types may already be set by ASTReader (hence isNull checks). if (Context.getObjCSelType().isNull()) { // Create the built-in typedef for 'SEL'. QualType SelT = Context.getPointerType(Context.ObjCBuiltinSelTy); @@ -113,7 +123,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { PushOnScopeChains(ClassTypedef, TUScope); Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef)); Context.ObjCClassRedefinitionType = Context.getObjCClassType(); - } + } } Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, @@ -123,9 +133,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), - PackContext(0), TopFunctionScope(0), ParsingDeclDepth(0), - IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0), - GlobalNewDeleteDeclared(false), + PackContext(0), VisContext(0), ParsingDeclDepth(0), + IdResolver(pp.getLangOptions()), GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), NumSFINAEErrors(0), SuppressAccessChecking(false), NonInstantiationEntries(0), CurrentInstantiationScope(0), TyposCorrected(0), @@ -140,22 +149,52 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, &Context); ExprEvalContexts.push_back( - ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0)); + ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0)); + + FunctionScopes.push_back(new FunctionScopeInfo(Diags.getNumErrors())); +} + +void Sema::Initialize() { + // Tell the AST consumer about this Sema object. + Consumer.Initialize(Context); + + // FIXME: Isn't this redundant with the initialization above? + if (SemaConsumer *SC = dyn_cast(&Consumer)) + SC->InitializeSema(*this); + + // Tell the external Sema source about this Sema object. + if (ExternalSemaSource *ExternalSema + = dyn_cast_or_null(Context.getExternalSource())) + ExternalSema->InitializeSema(*this); } Sema::~Sema() { if (PackContext) FreePackedContext(); + if (VisContext) FreeVisContext(); delete TheTargetAttributesSema; - while (!FunctionScopes.empty()) - PopFunctionOrBlockScope(); + + // Kill all the active scopes. + for (unsigned I = 1, E = FunctionScopes.size(); I != E; ++I) + delete FunctionScopes[I]; + if (FunctionScopes.size() == 1) + delete FunctionScopes[0]; + + // Tell the SemaConsumer to forget about us; we're going out of scope. + if (SemaConsumer *SC = dyn_cast(&Consumer)) + SC->ForgetSema(); + + // Detach from the external Sema source. + if (ExternalSemaSource *ExternalSema + = dyn_cast_or_null(Context.getExternalSource())) + ExternalSema->ForgetSema(); } /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. -/// If isLvalue, the result of the cast is an lvalue. +/// The result is of the given category. void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, - CastExpr::CastKind Kind, - bool isLvalue, CXXBaseSpecifierArray BasePath) { + CastKind Kind, ExprValueKind VK, + const CXXCastPath *BasePath) { QualType ExprTy = Context.getCanonicalType(Expr->getType()); QualType TypeTy = Context.getCanonicalType(Ty); @@ -173,8 +212,8 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, // If this is a derived-to-base cast to a through a virtual base, we // need a vtable. - if (Kind == CastExpr::CK_DerivedToBase && - BasePathInvolvesVirtualBase(BasePath)) { + if (Kind == CK_DerivedToBase && + BasePathInvolvesVirtualBase(*BasePath)) { QualType T = Expr->getType(); if (const PointerType *Pointer = T->getAs()) T = Pointer->getPointeeType(); @@ -184,53 +223,96 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, } if (ImplicitCastExpr *ImpCast = dyn_cast(Expr)) { - if (ImpCast->getCastKind() == Kind && BasePath.empty()) { + if (ImpCast->getCastKind() == Kind && (!BasePath || BasePath->empty())) { ImpCast->setType(Ty); - ImpCast->setLvalueCast(isLvalue); + ImpCast->setValueKind(VK); return; } } - Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, BasePath, isLvalue); + Expr = ImplicitCastExpr::Create(Context, Ty, Kind, Expr, BasePath, VK); } -void Sema::DeleteExpr(ExprTy *E) { - if (E) static_cast(E)->Destroy(Context); +ExprValueKind Sema::CastCategory(Expr *E) { + Expr::Classification Classification = E->Classify(Context); + return Classification.isRValue() ? VK_RValue : + (Classification.isLValue() ? VK_LValue : VK_XValue); } -void Sema::DeleteStmt(StmtTy *S) { - if (S) static_cast(S)->Destroy(Context); + +/// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector. +static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { + if (D->isUsed()) + return true; + + if (const FunctionDecl *FD = dyn_cast(D)) { + // UnusedFileScopedDecls stores the first declaration. + // The declaration may have become definition so check again. + const FunctionDecl *DeclToCheck; + if (FD->hasBody(DeclToCheck)) + return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); + + // Later redecls may add new information resulting in not having to warn, + // so check again. + DeclToCheck = FD->getMostRecentDeclaration(); + if (DeclToCheck != FD) + return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); + } + + if (const VarDecl *VD = dyn_cast(D)) { + // UnusedFileScopedDecls stores the first declaration. + // The declaration may have become definition so check again. + const VarDecl *DeclToCheck = VD->getDefinition(); + if (DeclToCheck) + return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); + + // Later redecls may add new information resulting in not having to warn, + // so check again. + DeclToCheck = VD->getMostRecentDeclaration(); + if (DeclToCheck != VD) + return !SemaRef->ShouldWarnIfUnusedFileScopedDecl(DeclToCheck); + } + + return false; } /// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. -void Sema::ActOnEndOfTranslationUnit() { - while (1) { - // C++: Perform implicit template instantiations. - // - // FIXME: When we perform these implicit instantiations, we do not carefully - // keep track of the point of instantiation (C++ [temp.point]). This means - // that name lookup that occurs within the template instantiation will - // always happen at the end of the translation unit, so it will find - // some names that should not be found. Although this is common behavior - // for C++ compilers, it is technically wrong. In the future, we either need - // to be able to filter the results of name lookup or we need to perform - // template instantiations earlier. - PerformPendingImplicitInstantiations(); - - /// If DefinedUsedVTables ends up marking any virtual member - /// functions it might lead to more pending template - /// instantiations, which is why we need to loop here. - if (!DefineUsedVTables()) - break; - } +void Sema::ActOnEndOfTranslationUnit() { + // At PCH writing, implicit instantiations and VTable handling info are + // stored and performed when the PCH is included. + if (CompleteTranslationUnit) + while (1) { + // C++: Perform implicit template instantiations. + // + // FIXME: When we perform these implicit instantiations, we do not + // carefully keep track of the point of instantiation (C++ [temp.point]). + // This means that name lookup that occurs within the template + // instantiation will always happen at the end of the translation unit, + // so it will find some names that should not be found. Although this is + // common behavior for C++ compilers, it is technically wrong. In the + // future, we either need to be able to filter the results of name lookup + // or we need to perform template instantiations earlier. + PerformPendingInstantiations(); + + /// If DefinedUsedVTables ends up marking any virtual member + /// functions it might lead to more pending template + /// instantiations, which is why we need to loop here. + if (!DefineUsedVTables()) + break; + } - // Remove functions that turned out to be used. - UnusedStaticFuncs.erase(std::remove_if(UnusedStaticFuncs.begin(), - UnusedStaticFuncs.end(), - std::bind2nd(std::mem_fun(&FunctionDecl::isUsed), - true)), - UnusedStaticFuncs.end()); + // Remove file scoped decls that turned out to be used. + UnusedFileScopedDecls.erase(std::remove_if(UnusedFileScopedDecls.begin(), + UnusedFileScopedDecls.end(), + std::bind1st(std::ptr_fun(ShouldRemoveFromUnused), + this)), + UnusedFileScopedDecls.end()); + + if (!CompleteTranslationUnit) { + TUScope = 0; + return; + } // Check for #pragma weak identifiers that were never declared // FIXME: This will cause diagnostics to be emitted in a non-determinstic @@ -244,9 +326,6 @@ void Sema::ActOnEndOfTranslationUnit() { << I->first; } - if (!CompleteTranslationUnit) - return; - // C99 6.9.2p2: // A declaration of an identifier for an object that has file // scope without an initializer, and without a storage-class @@ -293,14 +372,28 @@ void Sema::ActOnEndOfTranslationUnit() { } - // Output warning for unused functions. - for (std::vector::iterator - F = UnusedStaticFuncs.begin(), - FEnd = UnusedStaticFuncs.end(); - F != FEnd; - ++F) - Diag((*F)->getLocation(), diag::warn_unused_function) << (*F)->getDeclName(); - + // Output warning for unused file scoped decls. + for (llvm::SmallVectorImpl::iterator + I = UnusedFileScopedDecls.begin(), + E = UnusedFileScopedDecls.end(); I != E; ++I) { + if (const FunctionDecl *FD = dyn_cast(*I)) { + const FunctionDecl *DiagD; + if (!FD->hasBody(DiagD)) + DiagD = FD; + Diag(DiagD->getLocation(), + isa(DiagD) ? diag::warn_unused_member_function + : diag::warn_unused_function) + << DiagD->getDeclName(); + } else { + const VarDecl *DiagD = cast(*I)->getDefinition(); + if (!DiagD) + DiagD = cast(*I); + Diag(DiagD->getLocation(), diag::warn_unused_variable) + << DiagD->getDeclName(); + } + } + + TUScope = 0; } @@ -418,11 +511,11 @@ Scope *Sema::getScopeForContext(DeclContext *Ctx) { /// \brief Enter a new function scope void Sema::PushFunctionScope() { - if (FunctionScopes.empty()) { - // Use the "top" function scope rather than having to allocate memory for - // a new scope. - TopFunctionScope.Clear(getDiagnostics().getNumErrors()); - FunctionScopes.push_back(&TopFunctionScope); + if (FunctionScopes.size() == 1) { + // Use the "top" function scope rather than having to allocate + // memory for a new scope. + FunctionScopes.back()->Clear(getDiagnostics().getNumErrors()); + FunctionScopes.push_back(FunctionScopes.back()); return; } @@ -436,21 +529,17 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) { } void Sema::PopFunctionOrBlockScope() { - if (FunctionScopes.back() != &TopFunctionScope) - delete FunctionScopes.back(); - else - TopFunctionScope.Clear(getDiagnostics().getNumErrors()); - - FunctionScopes.pop_back(); + FunctionScopeInfo *Scope = FunctionScopes.pop_back_val(); + assert(!FunctionScopes.empty() && "mismatched push/pop!"); + if (FunctionScopes.back() != Scope) + delete Scope; } /// \brief Determine whether any errors occurred within this function/method/ /// block. bool Sema::hasAnyErrorsInThisFunction() const { - unsigned NumErrors = TopFunctionScope.NumErrorsAtStartOfFunction; - if (!FunctionScopes.empty()) - NumErrors = FunctionScopes.back()->NumErrorsAtStartOfFunction; - return NumErrors != getDiagnostics().getNumErrors(); + return getCurFunction()->NumErrorsAtStartOfFunction + != getDiagnostics().getNumErrors(); } BlockScopeInfo *Sema::getCurBlock() { @@ -462,3 +551,21 @@ BlockScopeInfo *Sema::getCurBlock() { // Pin this vtable to this file. ExternalSemaSource::~ExternalSemaSource() {} + +void PrettyDeclStackTraceEntry::print(llvm::raw_ostream &OS) const { + SourceLocation Loc = this->Loc; + if (!Loc.isValid() && TheDecl) Loc = TheDecl->getLocation(); + if (Loc.isValid()) { + Loc.print(OS, S.getSourceManager()); + OS << ": "; + } + OS << Message; + + if (TheDecl && isa(TheDecl)) { + std::string Name = cast(TheDecl)->getNameAsString(); + if (!Name.empty()) + OS << " '" << Name << '\''; + } + + OS << '\n'; +} diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h deleted file mode 100644 index 8336918..0000000 --- a/lib/Sema/Sema.h +++ /dev/null @@ -1,4655 +0,0 @@ -//===--- Sema.h - Semantic Analysis & AST Building --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the Sema class, which performs semantic analysis and -// builds ASTs. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_AST_SEMA_H -#define LLVM_CLANG_AST_SEMA_H - -#include "IdentifierResolver.h" -#include "CXXFieldCollector.h" -#include "SemaOverload.h" -#include "SemaTemplate.h" -#include "AnalysisBasedWarnings.h" -#include "clang/AST/Attr.h" -#include "clang/AST/DeclBase.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/ExprCXX.h" -#include "clang/AST/FullExpr.h" -#include "clang/Parse/Action.h" -#include "clang/Sema/SemaDiagnostic.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/OwningPtr.h" -#include -#include -#include -#include -#include - -namespace llvm { - class APSInt; -} - -namespace clang { - class ASTContext; - class ASTConsumer; - class CodeCompleteConsumer; - class Preprocessor; - class Decl; - class DeclContext; - class DeclSpec; - class ExternalSemaSource; - class NamedDecl; - class Stmt; - class Expr; - class InitListExpr; - class ParenListExpr; - class DesignatedInitExpr; - class CallExpr; - class DeclRefExpr; - class UnresolvedLookupExpr; - class UnresolvedMemberExpr; - class VarDecl; - class ParmVarDecl; - class TypedefDecl; - class FunctionDecl; - class QualType; - class LangOptions; - class Token; - class IntegerLiteral; - class StringLiteral; - class ArrayType; - class LabelStmt; - class SwitchStmt; - class CXXTryStmt; - class ExtVectorType; - class TypedefDecl; - class TemplateDecl; - class TemplateArgument; - class TemplateArgumentLoc; - class TemplateArgumentList; - class TemplateParameterList; - class TemplateTemplateParmDecl; - class ClassTemplatePartialSpecializationDecl; - class ClassTemplateDecl; - class ObjCInterfaceDecl; - class ObjCCompatibleAliasDecl; - class ObjCProtocolDecl; - class ObjCImplDecl; - class ObjCImplementationDecl; - class ObjCCategoryImplDecl; - class ObjCCategoryDecl; - class ObjCIvarDecl; - class ObjCMethodDecl; - class ObjCPropertyDecl; - class ObjCContainerDecl; - class PseudoDestructorTypeStorage; - class FunctionProtoType; - class CXXBasePath; - class CXXBasePaths; - class CXXTemporary; - class LookupResult; - class InitializedEntity; - class InitializationKind; - class InitializationSequence; - class VisibleDeclConsumer; - class TargetAttributesSema; - class ADLResult; - -/// \brief Retains information about a function, method, or block that is -/// currently being parsed. -struct FunctionScopeInfo { - /// \brief Whether this scope information structure defined information for - /// a block. - bool IsBlockInfo; - - /// \brief Set true when a function, method contains a VLA or ObjC try block, - /// which introduce scopes that need to be checked for goto conditions. If a - /// function does not contain this, then it need not have the jump checker run - /// on it. - bool NeedsScopeChecking; - - /// \brief The number of errors that had occurred before starting this - /// function or block. - unsigned NumErrorsAtStartOfFunction; - - /// LabelMap - This is a mapping from label identifiers to the LabelStmt for - /// it (which acts like the label decl in some ways). Forward referenced - /// labels have a LabelStmt created for them with a null location & SubStmt. - llvm::DenseMap LabelMap; - - /// SwitchStack - This is the current set of active switch statements in the - /// block. - llvm::SmallVector SwitchStack; - - /// \brief The list of return statements that occur within the function or - /// block, if there is any chance of applying the named return value - /// optimization. - llvm::SmallVector Returns; - - FunctionScopeInfo(unsigned NumErrors) - : IsBlockInfo(false), NeedsScopeChecking(false), - NumErrorsAtStartOfFunction(NumErrors) { } - - virtual ~FunctionScopeInfo(); - - /// \brief Clear out the information in this function scope, making it - /// suitable for reuse. - void Clear(unsigned NumErrors); - - static bool classof(const FunctionScopeInfo *FSI) { return true; } -}; - - -/// \brief Retains information about a block that is currently being parsed. -struct BlockScopeInfo : FunctionScopeInfo { - bool hasBlockDeclRefExprs; - - BlockDecl *TheDecl; - - /// TheScope - This is the scope for the block itself, which contains - /// arguments etc. - Scope *TheScope; - - /// ReturnType - The return type of the block, or null if the block - /// signature didn't provide an explicit return type. - QualType ReturnType; - - /// BlockType - The function type of the block, if one was given. - /// Its return type may be BuiltinType::Dependent. - QualType FunctionType; - - BlockScopeInfo(unsigned NumErrors, Scope *BlockScope, BlockDecl *Block) - : FunctionScopeInfo(NumErrors), hasBlockDeclRefExprs(false), - TheDecl(Block), TheScope(BlockScope) - { - IsBlockInfo = true; - } - - virtual ~BlockScopeInfo(); - - static bool classof(const FunctionScopeInfo *FSI) { return FSI->IsBlockInfo; } - static bool classof(const BlockScopeInfo *BSI) { return true; } -}; - -/// \brief Holds a QualType and a TypeSourceInfo* that came out of a declarator -/// parsing. -/// -/// LocInfoType is a "transient" type, only needed for passing to/from Parser -/// and Sema, when we want to preserve type source info for a parsed type. -/// It will not participate in the type system semantics in any way. -class LocInfoType : public Type { - enum { - // The last number that can fit in Type's TC. - // Avoids conflict with an existing Type class. - LocInfo = Type::TypeLast + 1 - }; - - TypeSourceInfo *DeclInfo; - - LocInfoType(QualType ty, TypeSourceInfo *TInfo) - : Type((TypeClass)LocInfo, ty, ty->isDependentType()), DeclInfo(TInfo) { - assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?"); - } - friend class Sema; - -public: - QualType getType() const { return getCanonicalTypeInternal(); } - TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; } - - virtual void getAsStringInternal(std::string &Str, - const PrintingPolicy &Policy) const; - - static bool classof(const Type *T) { - return T->getTypeClass() == (TypeClass)LocInfo; - } - static bool classof(const LocInfoType *) { return true; } -}; - -/// Sema - This implements semantic analysis and AST building for C. -class Sema : public Action { - Sema(const Sema&); // DO NOT IMPLEMENT - void operator=(const Sema&); // DO NOT IMPLEMENT - mutable const TargetAttributesSema* TheTargetAttributesSema; -public: - const LangOptions &LangOpts; - Preprocessor &PP; - ASTContext &Context; - ASTConsumer &Consumer; - Diagnostic &Diags; - SourceManager &SourceMgr; - - /// \brief Source of additional semantic information. - ExternalSemaSource *ExternalSource; - - /// \brief Code-completion consumer. - CodeCompleteConsumer *CodeCompleter; - - /// CurContext - This is the current declaration context of parsing. - DeclContext *CurContext; - - /// VAListTagName - The declaration name corresponding to __va_list_tag. - /// This is used as part of a hack to omit that class from ADL results. - DeclarationName VAListTagName; - - /// A RAII object to temporarily push a declaration context. - class ContextRAII { - private: - Sema &S; - DeclContext *SavedContext; - - public: - ContextRAII(Sema &S, DeclContext *ContextToPush) - : S(S), SavedContext(S.CurContext) { - assert(ContextToPush && "pushing null context"); - S.CurContext = ContextToPush; - } - - void pop() { - if (!SavedContext) return; - S.CurContext = SavedContext; - SavedContext = 0; - } - - ~ContextRAII() { - pop(); - } - }; - - /// PackContext - Manages the stack for #pragma pack. An alignment - /// of 0 indicates default alignment. - void *PackContext; // Really a "PragmaPackStack*" - - /// \brief Stack containing information about each of the nested function, - /// block, and method scopes that are currently active. - llvm::SmallVector FunctionScopes; - - /// \brief Cached function scope object used for the top function scope - /// and when there is no function scope (in error cases). - /// - /// This should never be accessed directly; rather, it's address will be - /// pushed into \c FunctionScopes when we want to re-use it. - FunctionScopeInfo TopFunctionScope; - - /// ExprTemporaries - This is the stack of temporaries that are created by - /// the current full expression. - llvm::SmallVector ExprTemporaries; - - /// ExtVectorDecls - This is a list all the extended vector types. This allows - /// us to associate a raw vector type with one of the ext_vector type names. - /// This is only necessary for issuing pretty diagnostics. - llvm::SmallVector ExtVectorDecls; - - /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes. - llvm::OwningPtr FieldCollector; - - typedef llvm::SmallPtrSet RecordDeclSetTy; - - /// PureVirtualClassDiagSet - a set of class declarations which we have - /// emitted a list of pure virtual functions. Used to prevent emitting the - /// same list more than once. - llvm::OwningPtr PureVirtualClassDiagSet; - - /// \brief A mapping from external names to the most recent - /// locally-scoped external declaration with that name. - /// - /// This map contains external declarations introduced in local - /// scoped, e.g., - /// - /// \code - /// void f() { - /// void foo(int, int); - /// } - /// \endcode - /// - /// Here, the name "foo" will be associated with the declaration on - /// "foo" within f. This name is not visible outside of - /// "f". However, we still find it in two cases: - /// - /// - If we are declaring another external with the name "foo", we - /// can find "foo" as a previous declaration, so that the types - /// of this external declaration can be checked for - /// compatibility. - /// - /// - If we would implicitly declare "foo" (e.g., due to a call to - /// "foo" in C when no prototype or definition is visible), then - /// we find this declaration of "foo" and complain that it is - /// not visible. - llvm::DenseMap LocallyScopedExternalDecls; - - /// \brief All the tentative definitions encountered in the TU. - std::vector TentativeDefinitions; - - /// \brief The set of static functions seen so far that have not been used. - std::vector UnusedStaticFuncs; - - class AccessedEntity { - public: - /// A member declaration found through lookup. The target is the - /// member. - enum MemberNonce { Member }; - - /// A hierarchy (base-to-derived or derived-to-base) conversion. - /// The target is the base class. - enum BaseNonce { Base }; - - bool isMemberAccess() const { return IsMember; } - - AccessedEntity(ASTContext &Context, - MemberNonce _, - CXXRecordDecl *NamingClass, - DeclAccessPair FoundDecl, - QualType BaseObjectType) - : Access(FoundDecl.getAccess()), IsMember(true), - Target(FoundDecl.getDecl()), NamingClass(NamingClass), - BaseObjectType(BaseObjectType), Diag(0, Context.getDiagAllocator()) { - } - - AccessedEntity(ASTContext &Context, - BaseNonce _, - CXXRecordDecl *BaseClass, - CXXRecordDecl *DerivedClass, - AccessSpecifier Access) - : Access(Access), IsMember(false), - Target(BaseClass), NamingClass(DerivedClass), - Diag(0, Context.getDiagAllocator()) { - } - - bool isQuiet() const { return Diag.getDiagID() == 0; } - - AccessSpecifier getAccess() const { return AccessSpecifier(Access); } - - // These apply to member decls... - NamedDecl *getTargetDecl() const { return Target; } - CXXRecordDecl *getNamingClass() const { return NamingClass; } - - // ...and these apply to hierarchy conversions. - CXXRecordDecl *getBaseClass() const { return cast(Target); } - CXXRecordDecl *getDerivedClass() const { return NamingClass; } - - /// Retrieves the base object type, important when accessing - /// an instance member. - QualType getBaseObjectType() const { return BaseObjectType; } - - /// Sets a diagnostic to be performed. The diagnostic is given - /// four (additional) arguments: - /// %0 - 0 if the entity was private, 1 if protected - /// %1 - the DeclarationName of the entity - /// %2 - the TypeDecl type of the naming class - /// %3 - the TypeDecl type of the declaring class - void setDiag(const PartialDiagnostic &PDiag) { - assert(isQuiet() && "partial diagnostic already defined"); - Diag = PDiag; - } - PartialDiagnostic &setDiag(unsigned DiagID) { - assert(isQuiet() && "partial diagnostic already defined"); - assert(DiagID && "creating null diagnostic"); - Diag.Reset(DiagID); - return Diag; - } - const PartialDiagnostic &getDiag() const { - return Diag; - } - - private: - unsigned Access : 2; - bool IsMember; - NamedDecl *Target; - CXXRecordDecl *NamingClass; - QualType BaseObjectType; - PartialDiagnostic Diag; - }; - - struct DelayedDiagnostic { - enum DDKind { Deprecation, Access }; - - unsigned char Kind; // actually a DDKind - bool Triggered; - - SourceLocation Loc; - - union { - /// Deprecation. - struct { NamedDecl *Decl; } DeprecationData; - - /// Access control. - char AccessData[sizeof(AccessedEntity)]; - }; - - void destroy() { - switch (Kind) { - case Access: getAccessData().~AccessedEntity(); break; - case Deprecation: break; - } - } - - static DelayedDiagnostic makeDeprecation(SourceLocation Loc, - NamedDecl *D) { - DelayedDiagnostic DD; - DD.Kind = Deprecation; - DD.Triggered = false; - DD.Loc = Loc; - DD.DeprecationData.Decl = D; - return DD; - } - - static DelayedDiagnostic makeAccess(SourceLocation Loc, - const AccessedEntity &Entity) { - DelayedDiagnostic DD; - DD.Kind = Access; - DD.Triggered = false; - DD.Loc = Loc; - new (&DD.getAccessData()) AccessedEntity(Entity); - return DD; - } - - AccessedEntity &getAccessData() { - return *reinterpret_cast(AccessData); - } - const AccessedEntity &getAccessData() const { - return *reinterpret_cast(AccessData); - } - }; - - /// \brief The stack of diagnostics that were delayed due to being - /// produced during the parsing of a declaration. - llvm::SmallVector DelayedDiagnostics; - - /// \brief The depth of the current ParsingDeclaration stack. - /// If nonzero, we are currently parsing a declaration (and - /// hence should delay deprecation warnings). - unsigned ParsingDeclDepth; - - /// WeakUndeclaredIdentifiers - Identifiers contained in - /// #pragma weak before declared. rare. may alias another - /// identifier, declared or undeclared - class WeakInfo { - IdentifierInfo *alias; // alias (optional) - SourceLocation loc; // for diagnostics - bool used; // identifier later declared? - public: - WeakInfo() - : alias(0), loc(SourceLocation()), used(false) {} - WeakInfo(IdentifierInfo *Alias, SourceLocation Loc) - : alias(Alias), loc(Loc), used(false) {} - inline IdentifierInfo * getAlias() const { return alias; } - inline SourceLocation getLocation() const { return loc; } - void setUsed(bool Used=true) { used = Used; } - inline bool getUsed() { return used; } - bool operator==(WeakInfo RHS) const { - return alias == RHS.getAlias() && loc == RHS.getLocation(); - } - bool operator!=(WeakInfo RHS) const { return !(*this == RHS); } - }; - llvm::DenseMap WeakUndeclaredIdentifiers; - - /// WeakTopLevelDecl - Translation-unit scoped declarations generated by - /// #pragma weak during processing of other Decls. - /// I couldn't figure out a clean way to generate these in-line, so - /// we store them here and handle separately -- which is a hack. - /// It would be best to refactor this. - llvm::SmallVector WeakTopLevelDecl; - - IdentifierResolver IdResolver; - - /// Translation Unit Scope - useful to Objective-C actions that need - /// to lookup file scope declarations in the "ordinary" C decl namespace. - /// For example, user-defined classes, built-in "id" type, etc. - Scope *TUScope; - - /// \brief The C++ "std" namespace, where the standard library resides. - NamespaceDecl *StdNamespace; - - /// \brief The C++ "std::bad_alloc" class, which is defined by the C++ - /// standard library. - CXXRecordDecl *StdBadAlloc; - - /// A flag to remember whether the implicit forms of operator new and delete - /// have been declared. - bool GlobalNewDeleteDeclared; - - /// \brief The set of declarations that have been referenced within - /// a potentially evaluated expression. - typedef std::vector > - PotentiallyReferencedDecls; - - /// \brief A set of diagnostics that may be emitted. - typedef std::vector > - PotentiallyEmittedDiagnostics; - - /// \brief Data structure used to record current or nested - /// expression evaluation contexts. - struct ExpressionEvaluationContextRecord { - /// \brief The expression evaluation context. - ExpressionEvaluationContext Context; - - /// \brief The number of temporaries that were active when we - /// entered this expression evaluation context. - unsigned NumTemporaries; - - /// \brief The set of declarations referenced within a - /// potentially potentially-evaluated context. - /// - /// When leaving a potentially potentially-evaluated context, each - /// of these elements will be as referenced if the corresponding - /// potentially potentially evaluated expression is potentially - /// evaluated. - PotentiallyReferencedDecls *PotentiallyReferenced; - - /// \brief The set of diagnostics to emit should this potentially - /// potentially-evaluated context become evaluated. - PotentiallyEmittedDiagnostics *PotentiallyDiagnosed; - - ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, - unsigned NumTemporaries) - : Context(Context), NumTemporaries(NumTemporaries), - PotentiallyReferenced(0), PotentiallyDiagnosed(0) { } - - void addReferencedDecl(SourceLocation Loc, Decl *Decl) { - if (!PotentiallyReferenced) - PotentiallyReferenced = new PotentiallyReferencedDecls; - PotentiallyReferenced->push_back(std::make_pair(Loc, Decl)); - } - - void addDiagnostic(SourceLocation Loc, const PartialDiagnostic &PD) { - if (!PotentiallyDiagnosed) - PotentiallyDiagnosed = new PotentiallyEmittedDiagnostics; - PotentiallyDiagnosed->push_back(std::make_pair(Loc, PD)); - } - - void Destroy() { - delete PotentiallyReferenced; - delete PotentiallyDiagnosed; - PotentiallyReferenced = 0; - PotentiallyDiagnosed = 0; - } - }; - - /// A stack of expression evaluation contexts. - llvm::SmallVector ExprEvalContexts; - - /// \brief Whether the code handled by Sema should be considered a - /// complete translation unit or not. - /// - /// When true (which is generally the case), Sema will perform - /// end-of-translation-unit semantic tasks (such as creating - /// initializers for tentative definitions in C) once parsing has - /// completed. This flag will be false when building PCH files, - /// since a PCH file is by definition not a complete translation - /// unit. - bool CompleteTranslationUnit; - - llvm::BumpPtrAllocator BumpAlloc; - - /// \brief The number of SFINAE diagnostics that have been trapped. - unsigned NumSFINAEErrors; - - typedef llvm::DenseMap MethodPool; - - /// Instance/Factory Method Pools - allows efficient lookup when typechecking - /// messages to "id". We need to maintain a list, since selectors can have - /// differing signatures across classes. In Cocoa, this happens to be - /// extremely uncommon (only 1% of selectors are "overloaded"). - MethodPool InstanceMethodPool; - MethodPool FactoryMethodPool; - - MethodPool::iterator ReadMethodPool(Selector Sel, bool isInstance); - - /// Private Helper predicate to check for 'self'. - bool isSelfExpr(Expr *RExpr); -public: - Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, - bool CompleteTranslationUnit = true, - CodeCompleteConsumer *CompletionConsumer = 0); - ~Sema(); - - const LangOptions &getLangOptions() const { return LangOpts; } - Diagnostic &getDiagnostics() const { return Diags; } - SourceManager &getSourceManager() const { return SourceMgr; } - const TargetAttributesSema &getTargetAttributesSema() const; - - /// \brief Helper class that creates diagnostics with optional - /// template instantiation stacks. - /// - /// This class provides a wrapper around the basic DiagnosticBuilder - /// class that emits diagnostics. SemaDiagnosticBuilder is - /// responsible for emitting the diagnostic (as DiagnosticBuilder - /// does) and, if the diagnostic comes from inside a template - /// instantiation, printing the template instantiation stack as - /// well. - class SemaDiagnosticBuilder : public DiagnosticBuilder { - Sema &SemaRef; - unsigned DiagID; - - public: - SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) - : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { } - - explicit SemaDiagnosticBuilder(Sema &SemaRef) - : DiagnosticBuilder(DiagnosticBuilder::Suppress), SemaRef(SemaRef) { } - - ~SemaDiagnosticBuilder(); - }; - - /// \brief Emit a diagnostic. - SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); - - /// \brief Emit a partial diagnostic. - SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD); - - /// \brief Build a partial diagnostic. - PartialDiagnostic PDiag(unsigned DiagID = 0) { - return PartialDiagnostic(DiagID, Context.getDiagAllocator()); - } - - virtual void DeleteExpr(ExprTy *E); - virtual void DeleteStmt(StmtTy *S); - - OwningExprResult Owned(Expr* E) { - assert(!E || E->isRetained()); - return OwningExprResult(*this, E); - } - OwningExprResult Owned(ExprResult R) { - if (R.isInvalid()) - return ExprError(); - assert(!R.get() || ((Expr*) R.get())->isRetained()); - return OwningExprResult(*this, R.get()); - } - OwningStmtResult Owned(Stmt* S) { - assert(!S || S->isRetained()); - return OwningStmtResult(*this, S); - } - - virtual void ActOnEndOfTranslationUnit(); - - Scope *getScopeForContext(DeclContext *Ctx); - - void PushFunctionScope(); - void PushBlockScope(Scope *BlockScope, BlockDecl *Block); - void PopFunctionOrBlockScope(); - - /// getLabelMap() - Return the current label map. If we're in a block, we - /// return it. - llvm::DenseMap &getLabelMap() { - if (FunctionScopes.empty()) - return TopFunctionScope.LabelMap; - - return FunctionScopes.back()->LabelMap; - } - - /// getSwitchStack - This is returns the switch stack for the current block or - /// function. - llvm::SmallVector &getSwitchStack() { - if (FunctionScopes.empty()) - return TopFunctionScope.SwitchStack; - - return FunctionScopes.back()->SwitchStack; - } - - /// \brief Determine whether the current function or block needs scope - /// checking. - bool &FunctionNeedsScopeChecking() { - if (FunctionScopes.empty()) - return TopFunctionScope.NeedsScopeChecking; - - return FunctionScopes.back()->NeedsScopeChecking; - } - - bool hasAnyErrorsInThisFunction() const; - - /// \brief Retrieve the current block, if any. - BlockScopeInfo *getCurBlock(); - - /// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls - llvm::SmallVector &WeakTopLevelDecls() { return WeakTopLevelDecl; } - - //===--------------------------------------------------------------------===// - // Type Analysis / Processing: SemaType.cpp. - // - - QualType adjustParameterType(QualType T); - QualType BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs); - QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVR) { - return BuildQualifiedType(T, Loc, Qualifiers::fromCVRMask(CVR)); - } - QualType BuildPointerType(QualType T, - SourceLocation Loc, DeclarationName Entity); - QualType BuildReferenceType(QualType T, bool LValueRef, - SourceLocation Loc, DeclarationName Entity); - QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, - Expr *ArraySize, unsigned Quals, - SourceRange Brackets, DeclarationName Entity); - QualType BuildExtVectorType(QualType T, ExprArg ArraySize, - SourceLocation AttrLoc); - QualType BuildFunctionType(QualType T, - QualType *ParamTypes, unsigned NumParamTypes, - bool Variadic, unsigned Quals, - SourceLocation Loc, DeclarationName Entity); - QualType BuildMemberPointerType(QualType T, QualType Class, - SourceLocation Loc, - DeclarationName Entity); - QualType BuildBlockPointerType(QualType T, - SourceLocation Loc, DeclarationName Entity); - TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S, - TagDecl **OwnedDecl = 0); - TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, - TypeSourceInfo *ReturnTypeInfo); - /// \brief Create a LocInfoType to hold the given QualType and TypeSourceInfo. - QualType CreateLocInfoType(QualType T, TypeSourceInfo *TInfo); - DeclarationName GetNameForDeclarator(Declarator &D); - DeclarationName GetNameFromUnqualifiedId(const UnqualifiedId &Name); - static QualType GetTypeFromParser(TypeTy *Ty, TypeSourceInfo **TInfo = 0); - bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range); - bool CheckDistantExceptionSpec(QualType T); - bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New); - bool CheckEquivalentExceptionSpec( - const FunctionProtoType *Old, SourceLocation OldLoc, - const FunctionProtoType *New, SourceLocation NewLoc); - bool CheckEquivalentExceptionSpec( - const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, - const FunctionProtoType *Old, SourceLocation OldLoc, - const FunctionProtoType *New, SourceLocation NewLoc, - bool *MissingExceptionSpecification = 0, - bool *MissingEmptyExceptionSpecification = 0); - bool CheckExceptionSpecSubset( - const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, - const FunctionProtoType *Superset, SourceLocation SuperLoc, - const FunctionProtoType *Subset, SourceLocation SubLoc); - bool CheckParamExceptionSpec(const PartialDiagnostic & NoteID, - const FunctionProtoType *Target, SourceLocation TargetLoc, - const FunctionProtoType *Source, SourceLocation SourceLoc); - - virtual TypeResult ActOnTypeName(Scope *S, Declarator &D); - - bool RequireCompleteType(SourceLocation Loc, QualType T, - const PartialDiagnostic &PD, - std::pair Note); - bool RequireCompleteType(SourceLocation Loc, QualType T, - const PartialDiagnostic &PD); - bool RequireCompleteType(SourceLocation Loc, QualType T, - unsigned DiagID); - - QualType getElaboratedType(ElaboratedTypeKeyword Keyword, - const CXXScopeSpec &SS, QualType T); - - QualType BuildTypeofExprType(Expr *E); - QualType BuildDecltypeType(Expr *E); - - //===--------------------------------------------------------------------===// - // Symbol table / Decl tracking callbacks: SemaDecl.cpp. - // - - /// getDeclName - Return a pretty name for the specified decl if possible, or - /// an empty string if not. This is used for pretty crash reporting. - virtual std::string getDeclName(DeclPtrTy D); - - DeclGroupPtrTy ConvertDeclToDeclGroup(DeclPtrTy Ptr); - - virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, CXXScopeSpec *SS, - bool isClassName = false, - TypeTy *ObjectType = 0); - virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S); - virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II, - SourceLocation IILoc, - Scope *S, - CXXScopeSpec *SS, - TypeTy *&SuggestedType); - - virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) { - return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false); - } - - DeclPtrTy HandleDeclarator(Scope *S, Declarator &D, - MultiTemplateParamsArg TemplateParameterLists, - bool IsFunctionDefinition); - void RegisterLocallyScopedExternCDecl(NamedDecl *ND, - const LookupResult &Previous, - Scope *S); - void DiagnoseFunctionSpecifiers(Declarator& D); - void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R); - void CheckShadow(Scope *S, VarDecl *D); - NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, TypeSourceInfo *TInfo, - LookupResult &Previous, bool &Redeclaration); - NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, TypeSourceInfo *TInfo, - LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists, - bool &Redeclaration); - void CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous, - bool &Redeclaration); - NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, - QualType R, TypeSourceInfo *TInfo, - LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists, - bool IsFunctionDefinition, - bool &Redeclaration); - void AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); - void CheckFunctionDeclaration(Scope *S, - FunctionDecl *NewFD, LookupResult &Previous, - bool IsExplicitSpecialization, - bool &Redeclaration, - bool &OverloadableAttrRequired); - void CheckMain(FunctionDecl *FD); - virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D); - ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, - SourceLocation Loc, - QualType T); - ParmVarDecl *CheckParameter(DeclContext *DC, - TypeSourceInfo *TSInfo, QualType T, - IdentifierInfo *Name, - SourceLocation NameLoc, - VarDecl::StorageClass StorageClass, - VarDecl::StorageClass StorageClassAsWritten); - virtual void ActOnParamDefaultArgument(DeclPtrTy param, - SourceLocation EqualLoc, - ExprArg defarg); - virtual void ActOnParamUnparsedDefaultArgument(DeclPtrTy param, - SourceLocation EqualLoc, - SourceLocation ArgLoc); - virtual void ActOnParamDefaultArgumentError(DeclPtrTy param); - bool SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg, - SourceLocation EqualLoc); - - - // Contains the locations of the beginning of unparsed default - // argument locations. - llvm::DenseMap UnparsedDefaultArgLocs; - - virtual void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init); - void AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit); - void ActOnUninitializedDecl(DeclPtrTy dcl, bool TypeContainsUndeducedAuto); - virtual void ActOnInitializerError(DeclPtrTy Dcl); - virtual void SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc); - virtual DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, - DeclPtrTy *Group, - unsigned NumDecls); - virtual void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, - SourceLocation LocAfterDecls); - virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *S, Declarator &D); - virtual DeclPtrTy ActOnStartOfFunctionDef(Scope *S, DeclPtrTy D); - virtual void ActOnStartOfObjCMethodDef(Scope *S, DeclPtrTy D); - - virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body); - DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body, - bool IsInstantiation); - - /// \brief Diagnose any unused parameters in the given sequence of - /// ParmVarDecl pointers. - template - void DiagnoseUnusedParameters(InputIterator Param, InputIterator ParamEnd) { - if (Diags.getDiagnosticLevel(diag::warn_unused_parameter) == - Diagnostic::Ignored) - return; - - // Don't diagnose unused-parameter errors in template instantiations; we - // will already have done so in the template itself. - if (!ActiveTemplateInstantiations.empty()) - return; - - for (; Param != ParamEnd; ++Param) { - if (!(*Param)->isUsed() && (*Param)->getDeclName() && - !(*Param)->template hasAttr()) { - Diag((*Param)->getLocation(), diag::warn_unused_parameter) - << (*Param)->getDeclName(); - } - } - } - - void DiagnoseInvalidJumps(Stmt *Body); - virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc, ExprArg expr); - - /// Scope actions. - virtual void ActOnPopScope(SourceLocation Loc, Scope *S); - virtual void ActOnTranslationUnitScope(SourceLocation Loc, Scope *S); - - /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with - /// no declarator (e.g. "struct foo;") is parsed. - virtual DeclPtrTy ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, - DeclSpec &DS); - - virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, - AccessSpecifier AS, - RecordDecl *Record); - - bool isAcceptableTagRedeclaration(const TagDecl *Previous, - TagDecl::TagKind NewTag, - SourceLocation NewTagLoc, - const IdentifierInfo &Name); - - virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, CXXScopeSpec &SS, - IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr, AccessSpecifier AS, - MultiTemplateParamsArg TemplateParameterLists, - bool &OwnedDecl, bool &IsDependent); - - virtual TypeResult ActOnDependentTag(Scope *S, - unsigned TagSpec, - TagUseKind TUK, - const CXXScopeSpec &SS, - IdentifierInfo *Name, - SourceLocation TagLoc, - SourceLocation NameLoc); - - virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, - IdentifierInfo *ClassName, - llvm::SmallVectorImpl &Decls); - virtual DeclPtrTy ActOnField(Scope *S, DeclPtrTy TagD, - SourceLocation DeclStart, - Declarator &D, ExprTy *BitfieldWidth); - - FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, - Declarator &D, Expr *BitfieldWidth, - AccessSpecifier AS); - - FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, - TypeSourceInfo *TInfo, - RecordDecl *Record, SourceLocation Loc, - bool Mutable, Expr *BitfieldWidth, - SourceLocation TSSL, - AccessSpecifier AS, NamedDecl *PrevDecl, - Declarator *D = 0); - - enum CXXSpecialMember { - CXXInvalid = -1, - CXXConstructor = 0, - CXXCopyConstructor = 1, - CXXCopyAssignment = 2, - CXXDestructor = 3 - }; - void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem); - CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD); - - virtual DeclPtrTy ActOnIvar(Scope *S, SourceLocation DeclStart, - DeclPtrTy IntfDecl, - Declarator &D, ExprTy *BitfieldWidth, - tok::ObjCKeywordKind visibility); - - // This is used for both record definitions and ObjC interface declarations. - virtual void ActOnFields(Scope* S, - SourceLocation RecLoc, DeclPtrTy TagDecl, - DeclPtrTy *Fields, unsigned NumFields, - SourceLocation LBrac, SourceLocation RBrac, - AttributeList *AttrList); - - /// ActOnTagStartDefinition - Invoked when we have entered the - /// scope of a tag's definition (e.g., for an enumeration, class, - /// struct, or union). - virtual void ActOnTagStartDefinition(Scope *S, DeclPtrTy TagDecl); - - /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a - /// C++ record definition's base-specifiers clause and are starting its - /// member declarations. - virtual void ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagDecl, - SourceLocation LBraceLoc); - - /// ActOnTagFinishDefinition - Invoked once we have finished parsing - /// the definition of a tag (enumeration, class, struct, or union). - virtual void ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagDecl, - SourceLocation RBraceLoc); - - /// ActOnTagDefinitionError - Invoked when there was an unrecoverable - /// error parsing the definition of a tag. - virtual void ActOnTagDefinitionError(Scope *S, DeclPtrTy TagDecl); - - EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum, - EnumConstantDecl *LastEnumConst, - SourceLocation IdLoc, - IdentifierInfo *Id, - ExprArg val); - - virtual DeclPtrTy ActOnEnumConstant(Scope *S, DeclPtrTy EnumDecl, - DeclPtrTy LastEnumConstant, - SourceLocation IdLoc, IdentifierInfo *Id, - SourceLocation EqualLoc, ExprTy *Val); - virtual void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, - SourceLocation RBraceLoc, DeclPtrTy EnumDecl, - DeclPtrTy *Elements, unsigned NumElements, - Scope *S, AttributeList *Attr); - - DeclContext *getContainingDC(DeclContext *DC); - - /// Set the current declaration context until it gets popped. - void PushDeclContext(Scope *S, DeclContext *DC); - void PopDeclContext(); - - /// EnterDeclaratorContext - Used when we must lookup names in the context - /// of a declarator's nested name specifier. - void EnterDeclaratorContext(Scope *S, DeclContext *DC); - void ExitDeclaratorContext(Scope *S); - - DeclContext *getFunctionLevelDeclContext(); - - /// getCurFunctionDecl - If inside of a function body, this returns a pointer - /// to the function decl for the function being parsed. If we're currently - /// in a 'block', this returns the containing context. - FunctionDecl *getCurFunctionDecl(); - - /// getCurMethodDecl - If inside of a method body, this returns a pointer to - /// the method decl for the method being parsed. If we're currently - /// in a 'block', this returns the containing context. - ObjCMethodDecl *getCurMethodDecl(); - - /// getCurFunctionOrMethodDecl - Return the Decl for the current ObjC method - /// or C function we're in, otherwise return null. If we're currently - /// in a 'block', this returns the containing context. - NamedDecl *getCurFunctionOrMethodDecl(); - - /// Add this decl to the scope shadowed decl chains. - void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true); - - /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true - /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns - /// true if 'D' belongs to the given declaration context. - bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0); - - /// Finds the scope corresponding to the given decl context, if it - /// happens to be an enclosing scope. Otherwise return NULL. - Scope *getScopeForDeclContext(Scope *S, DeclContext *DC) { - DeclContext *TargetDC = DC->getPrimaryContext(); - do { - if (DeclContext *ScopeDC = (DeclContext*) S->getEntity()) - if (ScopeDC->getPrimaryContext() == TargetDC) - return S; - } while ((S = S->getParent())); - - return NULL; - } - - /// Subroutines of ActOnDeclarator(). - TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, - TypeSourceInfo *TInfo); - void MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls); - bool MergeFunctionDecl(FunctionDecl *New, Decl *Old); - bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old); - void MergeVarDecl(VarDecl *New, LookupResult &OldDecls); - bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old); - - // AssignmentAction - This is used by all the assignment diagnostic functions - // to represent what is actually causing the operation - enum AssignmentAction { - AA_Assigning, - AA_Passing, - AA_Returning, - AA_Converting, - AA_Initializing, - AA_Sending, - AA_Casting - }; - - /// C++ Overloading. - enum OverloadKind { - /// This is a legitimate overload: the existing declarations are - /// functions or function templates with different signatures. - Ovl_Overload, - - /// This is not an overload because the signature exactly matches - /// an existing declaration. - Ovl_Match, - - /// This is not an overload because the lookup results contain a - /// non-function. - Ovl_NonFunction - }; - OverloadKind CheckOverload(Scope *S, - FunctionDecl *New, - const LookupResult &OldDecls, - NamedDecl *&OldDecl, - bool IsForUsingDecl); - bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl); - - bool TryImplicitConversion(InitializationSequence &Sequence, - const InitializedEntity &Entity, - Expr *From, - bool SuppressUserConversions, - bool AllowExplicit, - bool InOverloadResolution); - - ImplicitConversionSequence - TryImplicitConversion(Expr* From, QualType ToType, - bool SuppressUserConversions, - bool AllowExplicit, - bool InOverloadResolution); - bool IsStandardConversion(Expr *From, QualType ToType, - bool InOverloadResolution, - StandardConversionSequence& SCS); - bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); - bool IsFloatingPointPromotion(QualType FromType, QualType ToType); - bool IsComplexPromotion(QualType FromType, QualType ToType); - bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType, - bool InOverloadResolution, - QualType& ConvertedType, bool &IncompatibleObjC); - bool isObjCPointerConversion(QualType FromType, QualType ToType, - QualType& ConvertedType, bool &IncompatibleObjC); - bool FunctionArgTypesAreEqual (FunctionProtoType* OldType, - FunctionProtoType* NewType); - - bool CheckPointerConversion(Expr *From, QualType ToType, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray& BasePath, - bool IgnoreBaseAccess); - bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, - bool InOverloadResolution, - QualType &ConvertedType); - bool CheckMemberPointerConversion(Expr *From, QualType ToType, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath, - bool IgnoreBaseAccess); - bool IsQualificationConversion(QualType FromType, QualType ToType); - OverloadingResult IsUserDefinedConversion(Expr *From, QualType ToType, - UserDefinedConversionSequence& User, - OverloadCandidateSet& Conversions, - bool AllowExplicit); - bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); - - - ImplicitConversionSequence::CompareKind - CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, - const ImplicitConversionSequence& ICS2); - - ImplicitConversionSequence::CompareKind - CompareStandardConversionSequences(const StandardConversionSequence& SCS1, - const StandardConversionSequence& SCS2); - - ImplicitConversionSequence::CompareKind - CompareQualificationConversions(const StandardConversionSequence& SCS1, - const StandardConversionSequence& SCS2); - - ImplicitConversionSequence::CompareKind - CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, - const StandardConversionSequence& SCS2); - - OwningExprResult PerformCopyInitialization(const InitializedEntity &Entity, - SourceLocation EqualLoc, - OwningExprResult Init); - ImplicitConversionSequence - TryObjectArgumentInitialization(QualType FromType, CXXMethodDecl *Method, - CXXRecordDecl *ActingContext); - bool PerformObjectArgumentInitialization(Expr *&From, - NestedNameSpecifier *Qualifier, - NamedDecl *FoundDecl, - CXXMethodDecl *Method); - - ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From); - bool PerformContextuallyConvertToBool(Expr *&From); - - ImplicitConversionSequence TryContextuallyConvertToObjCId(Expr *From); - bool PerformContextuallyConvertToObjCId(Expr *&From); - - OwningExprResult - ConvertToIntegralOrEnumerationType(SourceLocation Loc, ExprArg FromE, - const PartialDiagnostic &NotIntDiag, - const PartialDiagnostic &IncompleteDiag, - const PartialDiagnostic &ExplicitConvDiag, - const PartialDiagnostic &ExplicitConvNote, - const PartialDiagnostic &AmbigDiag, - const PartialDiagnostic &AmbigNote, - const PartialDiagnostic &ConvDiag); - - bool PerformObjectMemberConversion(Expr *&From, - NestedNameSpecifier *Qualifier, - NamedDecl *FoundDecl, - NamedDecl *Member); - - // Members have to be NamespaceDecl* or TranslationUnitDecl*. - // TODO: make this is a typesafe union. - typedef llvm::SmallPtrSet AssociatedNamespaceSet; - typedef llvm::SmallPtrSet AssociatedClassSet; - - void AddOverloadCandidate(NamedDecl *Function, - DeclAccessPair FoundDecl, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet &CandidateSet); - - void AddOverloadCandidate(FunctionDecl *Function, - DeclAccessPair FoundDecl, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false, - bool PartialOverloading = false); - void AddFunctionCandidates(const UnresolvedSetImpl &Functions, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false); - void AddMethodCandidate(DeclAccessPair FoundDecl, - QualType ObjectType, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet, - bool SuppressUserConversion = false); - void AddMethodCandidate(CXXMethodDecl *Method, - DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, QualType ObjectType, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false); - void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, - DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, - const TemplateArgumentListInfo *ExplicitTemplateArgs, - QualType ObjectType, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false); - void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, - DeclAccessPair FoundDecl, - const TemplateArgumentListInfo *ExplicitTemplateArgs, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet, - bool SuppressUserConversions = false); - void AddConversionCandidate(CXXConversionDecl *Conversion, - DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, - Expr *From, QualType ToType, - OverloadCandidateSet& CandidateSet); - void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, - DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, - Expr *From, QualType ToType, - OverloadCandidateSet &CandidateSet); - void AddSurrogateCandidate(CXXConversionDecl *Conversion, - DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, - const FunctionProtoType *Proto, - QualType ObjectTy, Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet); - void AddMemberOperatorCandidates(OverloadedOperatorKind Op, - SourceLocation OpLoc, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet, - SourceRange OpRange = SourceRange()); - void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet, - bool IsAssignmentOperator = false, - unsigned NumContextualBoolArguments = 0); - void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, - SourceLocation OpLoc, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet& CandidateSet); - void AddArgumentDependentLookupCandidates(DeclarationName Name, - bool Operator, - Expr **Args, unsigned NumArgs, - const TemplateArgumentListInfo *ExplicitTemplateArgs, - OverloadCandidateSet& CandidateSet, - bool PartialOverloading = false); - bool isBetterOverloadCandidate(const OverloadCandidate& Cand1, - const OverloadCandidate& Cand2, - SourceLocation Loc); - OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet, - SourceLocation Loc, - OverloadCandidateSet::iterator& Best); - - enum OverloadCandidateDisplayKind { - /// Requests that all candidates be shown. Viable candidates will - /// be printed first. - OCD_AllCandidates, - - /// Requests that only viable candidates be shown. - OCD_ViableCandidates - }; - void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, - OverloadCandidateDisplayKind OCD, - Expr **Args, unsigned NumArgs, - const char *Opc = 0, - SourceLocation Loc = SourceLocation()); - - void NoteOverloadCandidate(FunctionDecl *Fn); - void DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS, - SourceLocation CaretLoc, - const PartialDiagnostic &PDiag); - - FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, - bool Complain, - DeclAccessPair &Found); - FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From); - - Expr *FixOverloadedFunctionReference(Expr *E, - DeclAccessPair FoundDecl, - FunctionDecl *Fn); - OwningExprResult FixOverloadedFunctionReference(OwningExprResult, - DeclAccessPair FoundDecl, - FunctionDecl *Fn); - - void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, - Expr **Args, unsigned NumArgs, - OverloadCandidateSet &CandidateSet, - bool PartialOverloading = false); - - OwningExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn, - UnresolvedLookupExpr *ULE, - SourceLocation LParenLoc, - Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc); - - OwningExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, - unsigned Opc, - const UnresolvedSetImpl &Fns, - ExprArg input); - - OwningExprResult CreateOverloadedBinOp(SourceLocation OpLoc, - unsigned Opc, - const UnresolvedSetImpl &Fns, - Expr *LHS, Expr *RHS); - - OwningExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, - SourceLocation RLoc, - ExprArg Base,ExprArg Idx); - - OwningExprResult - BuildCallToMemberFunction(Scope *S, Expr *MemExpr, - SourceLocation LParenLoc, Expr **Args, - unsigned NumArgs, SourceLocation *CommaLocs, - SourceLocation RParenLoc); - ExprResult - BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, - Expr **Args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc); - - OwningExprResult BuildOverloadedArrowExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc); - - /// CheckCallReturnType - Checks that a call expression's return type is - /// complete. Returns true on failure. The location passed in is the location - /// that best represents the call. - bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc, - CallExpr *CE, FunctionDecl *FD); - - /// Helpers for dealing with blocks and functions. - bool CheckParmsForFunctionDef(FunctionDecl *FD); - void CheckCXXDefaultArguments(FunctionDecl *FD); - void CheckExtraCXXDefaultArguments(Declarator &D); - Scope *getNonFieldDeclScope(Scope *S); - - /// \name Name lookup - /// - /// These routines provide name lookup that is used during semantic - /// analysis to resolve the various kinds of names (identifiers, - /// overloaded operator names, constructor names, etc.) into zero or - /// more declarations within a particular scope. The major entry - /// points are LookupName, which performs unqualified name lookup, - /// and LookupQualifiedName, which performs qualified name lookup. - /// - /// All name lookup is performed based on some specific criteria, - /// which specify what names will be visible to name lookup and how - /// far name lookup should work. These criteria are important both - /// for capturing language semantics (certain lookups will ignore - /// certain names, for example) and for performance, since name - /// lookup is often a bottleneck in the compilation of C++. Name - /// lookup criteria is specified via the LookupCriteria enumeration. - /// - /// The results of name lookup can vary based on the kind of name - /// lookup performed, the current language, and the translation - /// unit. In C, for example, name lookup will either return nothing - /// (no entity found) or a single declaration. In C++, name lookup - /// can additionally refer to a set of overloaded functions or - /// result in an ambiguity. All of the possible results of name - /// lookup are captured by the LookupResult class, which provides - /// the ability to distinguish among them. - //@{ - - /// @brief Describes the kind of name lookup to perform. - enum LookupNameKind { - /// Ordinary name lookup, which finds ordinary names (functions, - /// variables, typedefs, etc.) in C and most kinds of names - /// (functions, variables, members, types, etc.) in C++. - LookupOrdinaryName = 0, - /// Tag name lookup, which finds the names of enums, classes, - /// structs, and unions. - LookupTagName, - /// Member name lookup, which finds the names of - /// class/struct/union members. - LookupMemberName, - // Look up of an operator name (e.g., operator+) for use with - // operator overloading. This lookup is similar to ordinary name - // lookup, but will ignore any declarations that are class - // members. - LookupOperatorName, - /// Look up of a name that precedes the '::' scope resolution - /// operator in C++. This lookup completely ignores operator, object, - /// function, and enumerator names (C++ [basic.lookup.qual]p1). - LookupNestedNameSpecifierName, - /// Look up a namespace name within a C++ using directive or - /// namespace alias definition, ignoring non-namespace names (C++ - /// [basic.lookup.udir]p1). - LookupNamespaceName, - /// Look up all declarations in a scope with the given name, - /// including resolved using declarations. This is appropriate - /// for checking redeclarations for a using declaration. - LookupUsingDeclName, - /// Look up an ordinary name that is going to be redeclared as a - /// name with linkage. This lookup ignores any declarations that - /// are outside of the current scope unless they have linkage. See - /// C99 6.2.2p4-5 and C++ [basic.link]p6. - LookupRedeclarationWithLinkage, - /// Look up the name of an Objective-C protocol. - LookupObjCProtocolName - }; - - /// \brief Specifies whether (or how) name lookup is being performed for a - /// redeclaration (vs. a reference). - enum RedeclarationKind { - /// \brief The lookup is a reference to this name that is not for the - /// purpose of redeclaring the name. - NotForRedeclaration = 0, - /// \brief The lookup results will be used for redeclaration of a name, - /// if an entity by that name already exists. - ForRedeclaration - }; - -private: - bool CppLookupName(LookupResult &R, Scope *S); - -public: - /// \brief Look up a name, looking for a single declaration. Return - /// null if the results were absent, ambiguous, or overloaded. - /// - /// It is preferable to use the elaborated form and explicitly handle - /// ambiguity and overloaded. - NamedDecl *LookupSingleName(Scope *S, DeclarationName Name, - SourceLocation Loc, - LookupNameKind NameKind, - RedeclarationKind Redecl - = NotForRedeclaration); - bool LookupName(LookupResult &R, Scope *S, - bool AllowBuiltinCreation = false); - bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, - bool InUnqualifiedLookup = false); - bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, - bool AllowBuiltinCreation = false, - bool EnteringContext = false); - ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc); - - void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, - QualType T1, QualType T2, - UnresolvedSetImpl &Functions); - DeclContext::lookup_result LookupConstructors(CXXRecordDecl *Class); - CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); - - void ArgumentDependentLookup(DeclarationName Name, bool Operator, - Expr **Args, unsigned NumArgs, - ADLResult &Functions); - - void LookupVisibleDecls(Scope *S, LookupNameKind Kind, - VisibleDeclConsumer &Consumer); - void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, - VisibleDeclConsumer &Consumer); - - /// \brief The context in which typo-correction occurs. - /// - /// The typo-correction context affects which keywords (if any) are - /// considered when trying to correct for typos. - enum CorrectTypoContext { - /// \brief An unknown context, where any keyword might be valid. - CTC_Unknown, - /// \brief A context where no keywords are used (e.g. we expect an actual - /// name). - CTC_NoKeywords, - /// \brief A context where we're correcting a type name. - CTC_Type, - /// \brief An expression context. - CTC_Expression, - /// \brief A type cast, or anything else that can be followed by a '<'. - CTC_CXXCasts, - /// \brief A member lookup context. - CTC_MemberLookup, - /// \brief The receiver of an Objective-C message send within an - /// Objective-C method where 'super' is a valid keyword. - CTC_ObjCMessageReceiver - }; - - DeclarationName CorrectTypo(LookupResult &R, Scope *S, CXXScopeSpec *SS, - DeclContext *MemberContext = 0, - bool EnteringContext = false, - CorrectTypoContext CTC = CTC_Unknown, - const ObjCObjectPointerType *OPT = 0); - - void FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, - AssociatedNamespaceSet &AssociatedNamespaces, - AssociatedClassSet &AssociatedClasses); - - bool DiagnoseAmbiguousLookup(LookupResult &Result); - //@} - - ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, - SourceLocation IdLoc, - bool TypoCorrection = false); - NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, - Scope *S, bool ForRedeclaration, - SourceLocation Loc); - NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, - Scope *S); - void AddKnownFunctionAttributes(FunctionDecl *FD); - - // More parsing and symbol table subroutines. - - // Decl attributes - this routine is the top level dispatcher. - void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); - void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL); - - void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, - bool &IncompleteImpl, unsigned DiagID); - void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod, - ObjCMethodDecl *IntfMethod); - - bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl, - ObjCInterfaceDecl *IDecl); - - /// CheckProtocolMethodDefs - This routine checks unimplemented - /// methods declared in protocol, and those referenced by it. - /// \param IDecl - Used for checking for methods which may have been - /// inherited. - void CheckProtocolMethodDefs(SourceLocation ImpLoc, - ObjCProtocolDecl *PDecl, - bool& IncompleteImpl, - const llvm::DenseSet &InsMap, - const llvm::DenseSet &ClsMap, - ObjCContainerDecl *CDecl); - - /// CheckImplementationIvars - This routine checks if the instance variables - /// listed in the implelementation match those listed in the interface. - void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, - ObjCIvarDecl **Fields, unsigned nIvars, - SourceLocation Loc); - - /// ImplMethodsVsClassMethods - This is main routine to warn if any method - /// remains unimplemented in the class or category @implementation. - void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, - ObjCContainerDecl* IDecl, - bool IncompleteImpl = false); - - /// DiagnoseUnimplementedProperties - This routine warns on those properties - /// which must be implemented by this implementation. - void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, - ObjCContainerDecl *CDecl, - const llvm::DenseSet& InsMap); - - /// DefaultSynthesizeProperties - This routine default synthesizes all - /// properties which must be synthesized in class's @implementation. - void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, - ObjCInterfaceDecl *IDecl); - - /// CollectImmediateProperties - This routine collects all properties in - /// the class and its conforming protocols; but not those it its super class. - void CollectImmediateProperties(ObjCContainerDecl *CDecl, - llvm::DenseMap& PropMap, - llvm::DenseMap& SuperPropMap); - - - /// LookupPropertyDecl - Looks up a property in the current class and all - /// its protocols. - ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl, - IdentifierInfo *II); - - /// Called by ActOnProperty to handle @property declarations in - //// class extensions. - DeclPtrTy HandlePropertyInClassExtension(Scope *S, - ObjCCategoryDecl *CDecl, - SourceLocation AtLoc, - FieldDeclarator &FD, - Selector GetterSel, - Selector SetterSel, - const bool isAssign, - const bool isReadWrite, - const unsigned Attributes, - bool *isOverridingProperty, - TypeSourceInfo *T, - tok::ObjCKeywordKind MethodImplKind); - - /// Called by ActOnProperty and HandlePropertyInClassExtension to - /// handle creating the ObjcPropertyDecl for a category or @interface. - ObjCPropertyDecl *CreatePropertyDecl(Scope *S, - ObjCContainerDecl *CDecl, - SourceLocation AtLoc, - FieldDeclarator &FD, - Selector GetterSel, - Selector SetterSel, - const bool isAssign, - const bool isReadWrite, - const unsigned Attributes, - TypeSourceInfo *T, - tok::ObjCKeywordKind MethodImplKind, - DeclContext *lexicalDC = 0); - - /// AtomicPropertySetterGetterRules - This routine enforces the rule (via - /// warning) when atomic property has one but not the other user-declared - /// setter or getter. - void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl, - ObjCContainerDecl* IDecl); - - void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID); - - /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns - /// true, or false, accordingly. - bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, - const ObjCMethodDecl *PrevMethod, - bool matchBasedOnSizeAndAlignment = false); - - /// MatchAllMethodDeclarations - Check methods declaraed in interface or - /// or protocol against those declared in their implementations. - void MatchAllMethodDeclarations(const llvm::DenseSet &InsMap, - const llvm::DenseSet &ClsMap, - llvm::DenseSet &InsMapSeen, - llvm::DenseSet &ClsMapSeen, - ObjCImplDecl* IMPDecl, - ObjCContainerDecl* IDecl, - bool &IncompleteImpl, - bool ImmediateClass); - - /// AddInstanceMethodToGlobalPool - All instance methods in a translation - /// unit are added to a global pool. This allows us to efficiently associate - /// a selector with a method declaraation for purposes of typechecking - /// messages sent to "id" (where the class of the object is unknown). - void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method); - - /// LookupInstanceMethodInGlobalPool - Returns the method and warns if - /// there are multiple signatures. - ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R, - bool warn=true); - - /// LookupFactoryMethodInGlobalPool - Returns the method and warns if - /// there are multiple signatures. - ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R); - - /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. - void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method); - - /// CollectIvarsToConstructOrDestruct - Collect those ivars which require - /// initialization. - void CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI, - llvm::SmallVectorImpl &Ivars); - //===--------------------------------------------------------------------===// - // Statement Parsing Callbacks: SemaStmt.cpp. -public: - virtual OwningStmtResult ActOnExprStmt(FullExprArg Expr); - - virtual OwningStmtResult ActOnNullStmt(SourceLocation SemiLoc); - virtual OwningStmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, - MultiStmtArg Elts, - bool isStmtExpr); - virtual OwningStmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, - SourceLocation StartLoc, - SourceLocation EndLoc); - virtual void ActOnForEachDeclStmt(DeclGroupPtrTy Decl); - virtual OwningStmtResult ActOnCaseStmt(SourceLocation CaseLoc, ExprArg LHSVal, - SourceLocation DotDotDotLoc, ExprArg RHSVal, - SourceLocation ColonLoc); - virtual void ActOnCaseStmtBody(StmtTy *CaseStmt, StmtArg SubStmt); - - virtual OwningStmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, - SourceLocation ColonLoc, - StmtArg SubStmt, Scope *CurScope); - virtual OwningStmtResult ActOnLabelStmt(SourceLocation IdentLoc, - IdentifierInfo *II, - SourceLocation ColonLoc, - StmtArg SubStmt); - virtual OwningStmtResult ActOnIfStmt(SourceLocation IfLoc, - FullExprArg CondVal, DeclPtrTy CondVar, - StmtArg ThenVal, - SourceLocation ElseLoc, StmtArg ElseVal); - virtual OwningStmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, - ExprArg Cond, - DeclPtrTy CondVar); - virtual OwningStmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, - StmtArg Switch, StmtArg Body); - virtual OwningStmtResult ActOnWhileStmt(SourceLocation WhileLoc, - FullExprArg Cond, - DeclPtrTy CondVar, StmtArg Body); - virtual OwningStmtResult ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, - SourceLocation WhileLoc, - SourceLocation CondLParen, ExprArg Cond, - SourceLocation CondRParen); - - virtual OwningStmtResult ActOnForStmt(SourceLocation ForLoc, - SourceLocation LParenLoc, - StmtArg First, FullExprArg Second, - DeclPtrTy SecondVar, - FullExprArg Third, - SourceLocation RParenLoc, - StmtArg Body); - virtual OwningStmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, - SourceLocation LParenLoc, - StmtArg First, ExprArg Second, - SourceLocation RParenLoc, StmtArg Body); - - virtual OwningStmtResult ActOnGotoStmt(SourceLocation GotoLoc, - SourceLocation LabelLoc, - IdentifierInfo *LabelII); - virtual OwningStmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, - SourceLocation StarLoc, - ExprArg DestExp); - virtual OwningStmtResult ActOnContinueStmt(SourceLocation ContinueLoc, - Scope *CurScope); - virtual OwningStmtResult ActOnBreakStmt(SourceLocation GotoLoc, - Scope *CurScope); - - virtual OwningStmtResult ActOnReturnStmt(SourceLocation ReturnLoc, - ExprArg RetValExp); - OwningStmtResult ActOnBlockReturnStmt(SourceLocation ReturnLoc, - Expr *RetValExp); - - virtual OwningStmtResult ActOnAsmStmt(SourceLocation AsmLoc, - bool IsSimple, - bool IsVolatile, - unsigned NumOutputs, - unsigned NumInputs, - IdentifierInfo **Names, - MultiExprArg Constraints, - MultiExprArg Exprs, - ExprArg AsmString, - MultiExprArg Clobbers, - SourceLocation RParenLoc, - bool MSAsm = false); - - - VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, - IdentifierInfo *Name, SourceLocation NameLoc, - bool Invalid = false); - - virtual DeclPtrTy ActOnObjCExceptionDecl(Scope *S, Declarator &D); - - virtual OwningStmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, - SourceLocation RParen, - DeclPtrTy Parm, StmtArg Body); - - virtual OwningStmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, - StmtArg Body); - - virtual OwningStmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, - StmtArg Try, - MultiStmtArg Catch, - StmtArg Finally); - - virtual OwningStmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc, - ExprArg Throw); - virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, - ExprArg Throw, - Scope *CurScope); - virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, - ExprArg SynchExpr, - StmtArg SynchBody); - - VarDecl *BuildExceptionDeclaration(Scope *S, QualType ExDeclType, - TypeSourceInfo *TInfo, - IdentifierInfo *Name, - SourceLocation Loc, - SourceRange Range); - virtual DeclPtrTy ActOnExceptionDeclarator(Scope *S, Declarator &D); - - virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, - DeclPtrTy ExDecl, - StmtArg HandlerBlock); - virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc, - StmtArg TryBlock, - MultiStmtArg Handlers); - void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); - - /// DiagnoseUnusedExprResult - If the statement passed in is an expression - /// whose result is unused, warn. - void DiagnoseUnusedExprResult(const Stmt *S); - void DiagnoseUnusedDecl(const NamedDecl *ND); - - ParsingDeclStackState PushParsingDeclaration(); - void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D); - void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc); - - void HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, Decl *Ctx); - - //===--------------------------------------------------------------------===// - // Expression Parsing Callbacks: SemaExpr.cpp. - - bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc); - bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, - ObjCMethodDecl *Getter, - SourceLocation Loc); - void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, - Expr **Args, unsigned NumArgs); - - virtual void - PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext); - - virtual void PopExpressionEvaluationContext(); - - void MarkDeclarationReferenced(SourceLocation Loc, Decl *D); - void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); - bool DiagRuntimeBehavior(SourceLocation Loc, const PartialDiagnostic &PD); - - // Primary Expressions. - virtual SourceRange getExprRange(ExprTy *E) const; - - virtual OwningExprResult ActOnIdExpression(Scope *S, - CXXScopeSpec &SS, - UnqualifiedId &Name, - bool HasTrailingLParen, - bool IsAddressOfOperand); - - bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, - CorrectTypoContext CTC = CTC_Unknown); - - OwningExprResult LookupInObjCMethod(LookupResult &R, - Scope *S, - IdentifierInfo *II, - bool AllowBuiltinCreation=false); - - OwningExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, - DeclarationName Name, - SourceLocation NameLoc, - bool isAddressOfOperand, - const TemplateArgumentListInfo *TemplateArgs); - - OwningExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, - SourceLocation Loc, - const CXXScopeSpec *SS = 0); - VarDecl *BuildAnonymousStructUnionMemberPath(FieldDecl *Field, - llvm::SmallVectorImpl &Path); - OwningExprResult - BuildAnonymousStructUnionMemberReference(SourceLocation Loc, - FieldDecl *Field, - Expr *BaseObjectExpr = 0, - SourceLocation OpLoc = SourceLocation()); - OwningExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs); - OwningExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs, - bool IsDefiniteInstance); - bool UseArgumentDependentLookup(const CXXScopeSpec &SS, - const LookupResult &R, - bool HasTrailingLParen); - - OwningExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, - DeclarationName Name, - SourceLocation NameLoc); - OwningExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, - DeclarationName Name, - SourceLocation NameLoc, - const TemplateArgumentListInfo *TemplateArgs); - - OwningExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, - LookupResult &R, - bool ADL); - OwningExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, - SourceLocation Loc, - NamedDecl *D); - - virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc, - tok::TokenKind Kind); - virtual OwningExprResult ActOnNumericConstant(const Token &); - virtual OwningExprResult ActOnCharacterConstant(const Token &); - virtual OwningExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, - ExprArg Val); - virtual OwningExprResult ActOnParenOrParenListExpr(SourceLocation L, - SourceLocation R, - MultiExprArg Val, - TypeTy *TypeOfCast=0); - - /// ActOnStringLiteral - The specified tokens were lexed as pasted string - /// fragments (e.g. "foo" "bar" L"baz"). - virtual OwningExprResult ActOnStringLiteral(const Token *Toks, - unsigned NumToks); - - // Binary/Unary Operators. 'Tok' is the token for the operator. - OwningExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, - unsigned OpcIn, - ExprArg InputArg); - OwningExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc, - UnaryOperator::Opcode Opc, ExprArg input); - virtual OwningExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, - tok::TokenKind Op, ExprArg Input); - - OwningExprResult CreateSizeOfAlignOfExpr(TypeSourceInfo *T, - SourceLocation OpLoc, - bool isSizeOf, SourceRange R); - OwningExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, - bool isSizeOf, SourceRange R); - virtual OwningExprResult - ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, - void *TyOrEx, const SourceRange &ArgRange); - - bool CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, const SourceRange &R); - bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc, - const SourceRange &R, bool isSizeof); - - virtual OwningExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, - tok::TokenKind Kind, - ExprArg Input); - - virtual OwningExprResult ActOnArraySubscriptExpr(Scope *S, ExprArg Base, - SourceLocation LLoc, - ExprArg Idx, - SourceLocation RLoc); - OwningExprResult CreateBuiltinArraySubscriptExpr(ExprArg Base, - SourceLocation LLoc, - ExprArg Idx, - SourceLocation RLoc); - - OwningExprResult BuildMemberReferenceExpr(ExprArg Base, - QualType BaseType, - SourceLocation OpLoc, - bool IsArrow, - CXXScopeSpec &SS, - NamedDecl *FirstQualifierInScope, - DeclarationName Name, - SourceLocation NameLoc, - const TemplateArgumentListInfo *TemplateArgs); - - OwningExprResult BuildMemberReferenceExpr(ExprArg Base, - QualType BaseType, - SourceLocation OpLoc, bool IsArrow, - const CXXScopeSpec &SS, - NamedDecl *FirstQualifierInScope, - LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs, - bool SuppressQualifierCheck = false); - - OwningExprResult LookupMemberExpr(LookupResult &R, Expr *&Base, - bool &IsArrow, SourceLocation OpLoc, - CXXScopeSpec &SS, - DeclPtrTy ObjCImpDecl, - bool HasTemplateArgs); - - bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, - const CXXScopeSpec &SS, - const LookupResult &R); - - OwningExprResult ActOnDependentMemberExpr(ExprArg Base, - QualType BaseType, - bool IsArrow, - SourceLocation OpLoc, - const CXXScopeSpec &SS, - NamedDecl *FirstQualifierInScope, - DeclarationName Name, - SourceLocation NameLoc, - const TemplateArgumentListInfo *TemplateArgs); - - virtual OwningExprResult ActOnMemberAccessExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - CXXScopeSpec &SS, - UnqualifiedId &Member, - DeclPtrTy ObjCImpDecl, - bool HasTrailingLParen); - - virtual void ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl); - bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, - FunctionDecl *FDecl, - const FunctionProtoType *Proto, - Expr **Args, unsigned NumArgs, - SourceLocation RParenLoc); - - /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. - /// This provides the location of the left/right parens and a list of comma - /// locations. - virtual OwningExprResult ActOnCallExpr(Scope *S, ExprArg Fn, - SourceLocation LParenLoc, - MultiExprArg Args, - SourceLocation *CommaLocs, - SourceLocation RParenLoc); - OwningExprResult BuildResolvedCallExpr(Expr *Fn, - NamedDecl *NDecl, - SourceLocation LParenLoc, - Expr **Args, unsigned NumArgs, - SourceLocation RParenLoc); - - virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, - TypeTy *Ty, SourceLocation RParenLoc, - ExprArg Op); - OwningExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, - TypeSourceInfo *Ty, - SourceLocation RParenLoc, - ExprArg Op); - - virtual bool TypeIsVectorType(TypeTy *Ty) { - return GetTypeFromParser(Ty)->isVectorType(); - } - - OwningExprResult MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg ME); - OwningExprResult ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, - SourceLocation RParenLoc, ExprArg E, - TypeSourceInfo *TInfo); - - virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, - TypeTy *Ty, - SourceLocation RParenLoc, - ExprArg Op); - - OwningExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc, - TypeSourceInfo *TInfo, - SourceLocation RParenLoc, - ExprArg InitExpr); - - virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc, - MultiExprArg InitList, - SourceLocation RParenLoc); - - virtual OwningExprResult ActOnDesignatedInitializer(Designation &Desig, - SourceLocation Loc, - bool GNUSyntax, - OwningExprResult Init); - - virtual OwningExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, - tok::TokenKind Kind, - ExprArg LHS, ExprArg RHS); - OwningExprResult BuildBinOp(Scope *S, SourceLocation OpLoc, - BinaryOperator::Opcode Opc, - Expr *lhs, Expr *rhs); - OwningExprResult CreateBuiltinBinOp(SourceLocation TokLoc, - unsigned Opc, Expr *lhs, Expr *rhs); - - /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null - /// in the case of a the GNU conditional expr extension. - virtual OwningExprResult ActOnConditionalOp(SourceLocation QuestionLoc, - SourceLocation ColonLoc, - ExprArg Cond, ExprArg LHS, - ExprArg RHS); - - /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". - virtual OwningExprResult ActOnAddrLabel(SourceLocation OpLoc, - SourceLocation LabLoc, - IdentifierInfo *LabelII); - - virtual OwningExprResult ActOnStmtExpr(SourceLocation LPLoc, StmtArg SubStmt, - SourceLocation RPLoc); // "({..})" - - /// __builtin_offsetof(type, a.b[123][456].c) - OwningExprResult BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, - TypeSourceInfo *TInfo, - OffsetOfComponent *CompPtr, - unsigned NumComponents, - SourceLocation RParenLoc); - virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S, - SourceLocation BuiltinLoc, - SourceLocation TypeLoc, - TypeTy *Arg1, - OffsetOfComponent *CompPtr, - unsigned NumComponents, - SourceLocation RParenLoc); - - // __builtin_types_compatible_p(type1, type2) - virtual OwningExprResult ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, - TypeTy *arg1, TypeTy *arg2, - SourceLocation RPLoc); - - // __builtin_choose_expr(constExpr, expr1, expr2) - virtual OwningExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, - ExprArg cond, ExprArg expr1, - ExprArg expr2, SourceLocation RPLoc); - - // __builtin_va_arg(expr, type) - virtual OwningExprResult ActOnVAArg(SourceLocation BuiltinLoc, - ExprArg expr, TypeTy *type, - SourceLocation RPLoc); - - // __null - virtual OwningExprResult ActOnGNUNullExpr(SourceLocation TokenLoc); - - //===------------------------- "Block" Extension ------------------------===// - - /// ActOnBlockStart - This callback is invoked when a block literal is - /// started. - virtual void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope); - - /// ActOnBlockArguments - This callback allows processing of block arguments. - /// If there are no arguments, this is still invoked. - virtual void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope); - - /// ActOnBlockError - If there is an error parsing a block, this callback - /// is invoked to pop the information about the block from the action impl. - virtual void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope); - - /// ActOnBlockStmtExpr - This is called when the body of a block statement - /// literal was successfully completed. ^(int x){...} - virtual OwningExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, - StmtArg Body, Scope *CurScope); - - //===---------------------------- C++ Features --------------------------===// - - // Act on C++ namespaces - virtual DeclPtrTy ActOnStartNamespaceDef(Scope *S, SourceLocation IdentLoc, - IdentifierInfo *Ident, - SourceLocation LBrace, - AttributeList *AttrList); - virtual void ActOnFinishNamespaceDef(DeclPtrTy Dcl, SourceLocation RBrace); - - NamespaceDecl *getStdNamespace(); - virtual DeclPtrTy ActOnUsingDirective(Scope *CurScope, - SourceLocation UsingLoc, - SourceLocation NamespcLoc, - CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *NamespcName, - AttributeList *AttrList); - - void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir); - - virtual DeclPtrTy ActOnNamespaceAliasDef(Scope *CurScope, - SourceLocation NamespaceLoc, - SourceLocation AliasLoc, - IdentifierInfo *Alias, - CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *Ident); - - void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow); - bool CheckUsingShadowDecl(UsingDecl *UD, NamedDecl *Target, - const LookupResult &PreviousDecls); - UsingShadowDecl *BuildUsingShadowDecl(Scope *S, UsingDecl *UD, - NamedDecl *Target); - - bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc, - bool isTypeName, - const CXXScopeSpec &SS, - SourceLocation NameLoc, - const LookupResult &Previous); - bool CheckUsingDeclQualifier(SourceLocation UsingLoc, - const CXXScopeSpec &SS, - SourceLocation NameLoc); - - NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, - SourceLocation UsingLoc, - CXXScopeSpec &SS, - SourceLocation IdentLoc, - DeclarationName Name, - AttributeList *AttrList, - bool IsInstantiation, - bool IsTypeName, - SourceLocation TypenameLoc); - - virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope, - AccessSpecifier AS, - bool HasUsingKeyword, - SourceLocation UsingLoc, - CXXScopeSpec &SS, - UnqualifiedId &Name, - AttributeList *AttrList, - bool IsTypeName, - SourceLocation TypenameLoc); - - /// AddCXXDirectInitializerToDecl - This action is called immediately after - /// ActOnDeclarator, when a C++ direct initializer is present. - /// e.g: "int x(1);" - virtual void AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, - SourceLocation LParenLoc, - MultiExprArg Exprs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc); - - /// InitializeVarWithConstructor - Creates an CXXConstructExpr - /// and sets it as the initializer for the the passed in VarDecl. - bool InitializeVarWithConstructor(VarDecl *VD, - CXXConstructorDecl *Constructor, - MultiExprArg Exprs); - - /// BuildCXXConstructExpr - Creates a complete call to a constructor, - /// including handling of its default argument expressions. - OwningExprResult - BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, - CXXConstructorDecl *Constructor, MultiExprArg Exprs, - bool RequiresZeroInit = false, - CXXConstructExpr::ConstructionKind ConstructKind = - CXXConstructExpr::CK_Complete); - - // FIXME: Can re remove this and have the above BuildCXXConstructExpr check if - // the constructor can be elidable? - OwningExprResult - BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, - CXXConstructorDecl *Constructor, bool Elidable, - MultiExprArg Exprs, bool RequiresZeroInit = false, - CXXConstructExpr::ConstructionKind ConstructKind = - CXXConstructExpr::CK_Complete); - - /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating - /// the default expr if needed. - OwningExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc, - FunctionDecl *FD, - ParmVarDecl *Param); - - /// FinalizeVarWithDestructor - Prepare for calling destructor on the - /// constructed variable. - void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType); - - /// \brief Declare the implicit default constructor for the given class. - /// - /// \param ClassDecl The class declaration into which the implicit - /// default constructor will be added. - /// - /// \returns The implicitly-declared default constructor. - CXXConstructorDecl *DeclareImplicitDefaultConstructor( - CXXRecordDecl *ClassDecl); - - /// DefineImplicitDefaultConstructor - Checks for feasibility of - /// defining this constructor as the default constructor. - void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, - CXXConstructorDecl *Constructor); - - /// \brief Declare the implicit destructor for the given class. - /// - /// \param ClassDecl The class declaration into which the implicit - /// destructor will be added. - /// - /// \returns The implicitly-declared destructor. - CXXDestructorDecl *DeclareImplicitDestructor(CXXRecordDecl *ClassDecl); - - /// DefineImplicitDestructor - Checks for feasibility of - /// defining this destructor as the default destructor. - void DefineImplicitDestructor(SourceLocation CurrentLocation, - CXXDestructorDecl *Destructor); - - /// \brief Declare the implicit copy constructor for the given class. - /// - /// \param S The scope of the class, which may be NULL if this is a - /// template instantiation. - /// - /// \param ClassDecl The class declaration into which the implicit - /// copy constructor will be added. - /// - /// \returns The implicitly-declared copy constructor. - CXXConstructorDecl *DeclareImplicitCopyConstructor(CXXRecordDecl *ClassDecl); - - /// DefineImplicitCopyConstructor - Checks for feasibility of - /// defining this constructor as the copy constructor. - void DefineImplicitCopyConstructor(SourceLocation CurrentLocation, - CXXConstructorDecl *Constructor, - unsigned TypeQuals); - - /// \brief Declare the implicit copy assignment operator for the given class. - /// - /// \param S The scope of the class, which may be NULL if this is a - /// template instantiation. - /// - /// \param ClassDecl The class declaration into which the implicit - /// copy-assignment operator will be added. - /// - /// \returns The implicitly-declared copy assignment operator. - CXXMethodDecl *DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl); - - /// \brief Defined an implicitly-declared copy assignment operator. - void DefineImplicitCopyAssignment(SourceLocation CurrentLocation, - CXXMethodDecl *MethodDecl); - - /// \brief Force the declaration of any implicitly-declared members of this - /// class. - void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class); - - /// MaybeBindToTemporary - If the passed in expression has a record type with - /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise - /// it simply returns the passed in expression. - OwningExprResult MaybeBindToTemporary(Expr *E); - - bool CompleteConstructorCall(CXXConstructorDecl *Constructor, - MultiExprArg ArgsPtr, - SourceLocation Loc, - ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs); - - virtual TypeTy *getDestructorName(SourceLocation TildeLoc, - IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, CXXScopeSpec &SS, - TypeTy *ObjectType, - bool EnteringContext); - - /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. - virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc, - tok::TokenKind Kind, - SourceLocation LAngleBracketLoc, - TypeTy *Ty, - SourceLocation RAngleBracketLoc, - SourceLocation LParenLoc, - ExprArg E, - SourceLocation RParenLoc); - - OwningExprResult BuildCXXNamedCast(SourceLocation OpLoc, - tok::TokenKind Kind, - TypeSourceInfo *Ty, - ExprArg E, - SourceRange AngleBrackets, - SourceRange Parens); - - OwningExprResult BuildCXXTypeId(QualType TypeInfoType, - SourceLocation TypeidLoc, - TypeSourceInfo *Operand, - SourceLocation RParenLoc); - OwningExprResult BuildCXXTypeId(QualType TypeInfoType, - SourceLocation TypeidLoc, - ExprArg Operand, - SourceLocation RParenLoc); - - /// ActOnCXXTypeid - Parse typeid( something ). - virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc, - SourceLocation LParenLoc, bool isType, - void *TyOrExpr, - SourceLocation RParenLoc); - - //// ActOnCXXThis - Parse 'this' pointer. - virtual OwningExprResult ActOnCXXThis(SourceLocation ThisLoc); - - /// ActOnCXXBoolLiteral - Parse {true,false} literals. - virtual OwningExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, - tok::TokenKind Kind); - - /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. - virtual OwningExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc); - - //// ActOnCXXThrow - Parse throw expressions. - virtual OwningExprResult ActOnCXXThrow(SourceLocation OpLoc, - ExprArg expr); - bool CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E); - - /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. - /// Can be interpreted either as function-style casting ("int(x)") - /// or class type construction ("ClassType(x,y,z)") - /// or creation of a value-initialized type ("int()"). - virtual OwningExprResult ActOnCXXTypeConstructExpr(SourceRange TypeRange, - TypeTy *TypeRep, - SourceLocation LParenLoc, - MultiExprArg Exprs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc); - - /// ActOnCXXNew - Parsed a C++ 'new' expression. - virtual OwningExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, - SourceLocation PlacementLParen, - MultiExprArg PlacementArgs, - SourceLocation PlacementRParen, - SourceRange TypeIdParens, Declarator &D, - SourceLocation ConstructorLParen, - MultiExprArg ConstructorArgs, - SourceLocation ConstructorRParen); - OwningExprResult BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, - SourceLocation PlacementLParen, - MultiExprArg PlacementArgs, - SourceLocation PlacementRParen, - SourceRange TypeIdParens, - QualType AllocType, - SourceLocation TypeLoc, - SourceRange TypeRange, - ExprArg ArraySize, - SourceLocation ConstructorLParen, - MultiExprArg ConstructorArgs, - SourceLocation ConstructorRParen); - - bool CheckAllocatedType(QualType AllocType, SourceLocation Loc, - SourceRange R); - bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, - bool UseGlobal, QualType AllocType, bool IsArray, - Expr **PlaceArgs, unsigned NumPlaceArgs, - FunctionDecl *&OperatorNew, - FunctionDecl *&OperatorDelete); - bool FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, - DeclarationName Name, Expr** Args, - unsigned NumArgs, DeclContext *Ctx, - bool AllowMissing, FunctionDecl *&Operator); - void DeclareGlobalNewDelete(); - void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, - QualType Argument, - bool addMallocAttr = false); - - bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, - DeclarationName Name, FunctionDecl* &Operator); - - /// ActOnCXXDelete - Parsed a C++ 'delete' expression - virtual OwningExprResult ActOnCXXDelete(SourceLocation StartLoc, - bool UseGlobal, bool ArrayForm, - ExprArg Operand); - - virtual DeclResult ActOnCXXConditionDeclaration(Scope *S, - Declarator &D); - OwningExprResult CheckConditionVariable(VarDecl *ConditionVar, - SourceLocation StmtLoc, - bool ConvertToBoolean); - - /// ActOnUnaryTypeTrait - Parsed one of the unary type trait support - /// pseudo-functions. - virtual OwningExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT, - SourceLocation KWLoc, - SourceLocation LParen, - TypeTy *Ty, - SourceLocation RParen); - - virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S, - ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - TypeTy *&ObjectType, - bool &MayBePseudoDestructor); - - OwningExprResult DiagnoseDtorReference(SourceLocation NameLoc, - ExprArg MemExpr); - - OwningExprResult BuildPseudoDestructorExpr(ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - const CXXScopeSpec &SS, - TypeSourceInfo *ScopeType, - SourceLocation CCLoc, - SourceLocation TildeLoc, - PseudoDestructorTypeStorage DestroyedType, - bool HasTrailingLParen); - - virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, - SourceLocation OpLoc, - tok::TokenKind OpKind, - CXXScopeSpec &SS, - UnqualifiedId &FirstTypeName, - SourceLocation CCLoc, - SourceLocation TildeLoc, - UnqualifiedId &SecondTypeName, - bool HasTrailingLParen); - - /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is - /// non-empty, will create a new CXXExprWithTemporaries expression. - /// Otherwise, just returs the passed in expression. - Expr *MaybeCreateCXXExprWithTemporaries(Expr *SubExpr); - OwningExprResult MaybeCreateCXXExprWithTemporaries(OwningExprResult SubExpr); - FullExpr CreateFullExpr(Expr *SubExpr); - - virtual OwningExprResult ActOnFinishFullExpr(ExprArg Expr); - - // Marks SS invalid if it represents an incomplete type. - bool RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC); - - DeclContext *computeDeclContext(QualType T); - DeclContext *computeDeclContext(const CXXScopeSpec &SS, - bool EnteringContext = false); - bool isDependentScopeSpecifier(const CXXScopeSpec &SS); - CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); - bool isUnknownSpecialization(const CXXScopeSpec &SS); - - /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the - /// global scope ('::'). - virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S, - SourceLocation CCLoc); - - bool isAcceptableNestedNameSpecifier(NamedDecl *SD); - NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); - - virtual bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, - SourceLocation IdLoc, - IdentifierInfo &II, - TypeTy *ObjectType); - - CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S, - CXXScopeSpec &SS, - SourceLocation IdLoc, - SourceLocation CCLoc, - IdentifierInfo &II, - QualType ObjectType, - NamedDecl *ScopeLookupResult, - bool EnteringContext, - bool ErrorRecoveryLookup); - - virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, - CXXScopeSpec &SS, - SourceLocation IdLoc, - SourceLocation CCLoc, - IdentifierInfo &II, - TypeTy *ObjectType, - bool EnteringContext); - - virtual bool IsInvalidUnlessNestedName(Scope *S, - CXXScopeSpec &SS, - IdentifierInfo &II, - TypeTy *ObjectType, - bool EnteringContext); - - /// ActOnCXXNestedNameSpecifier - Called during parsing of a - /// nested-name-specifier that involves a template-id, e.g., - /// "foo::bar::", and now we need to build a scope - /// specifier. \p SS is empty or the previously parsed nested-name - /// part ("foo::"), \p Type is the already-parsed class template - /// specialization (or other template-id that names a type), \p - /// TypeRange is the source range where the type is located, and \p - /// CCLoc is the location of the trailing '::'. - virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, - const CXXScopeSpec &SS, - TypeTy *Type, - SourceRange TypeRange, - SourceLocation CCLoc); - - virtual bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); - - /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global - /// scope or nested-name-specifier) is parsed, part of a declarator-id. - /// After this method is called, according to [C++ 3.4.3p3], names should be - /// looked up in the declarator-id's scope, until the declarator is parsed and - /// ActOnCXXExitDeclaratorScope is called. - /// The 'SS' should be a non-empty valid CXXScopeSpec. - virtual bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS); - - /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously - /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same - /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well. - /// Used to indicate that names should revert to being looked up in the - /// defining scope. - virtual void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS); - - /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an - /// initializer for the declaration 'Dcl'. - /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a - /// static data member of class X, names should be looked up in the scope of - /// class X. - virtual void ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl); - - /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an - /// initializer for the declaration 'Dcl'. - virtual void ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl); - - // ParseObjCStringLiteral - Parse Objective-C string literals. - virtual ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, - ExprTy **Strings, - unsigned NumStrings); - - Expr *BuildObjCEncodeExpression(SourceLocation AtLoc, - TypeSourceInfo *EncodedTypeInfo, - SourceLocation RParenLoc); - CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, - NamedDecl *FoundDecl, - CXXMethodDecl *Method); - - virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, - SourceLocation EncodeLoc, - SourceLocation LParenLoc, - TypeTy *Ty, - SourceLocation RParenLoc); - - // ParseObjCSelectorExpression - Build selector expression for @selector - virtual ExprResult ParseObjCSelectorExpression(Selector Sel, - SourceLocation AtLoc, - SourceLocation SelLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc); - - // ParseObjCProtocolExpression - Build protocol expression for @protocol - virtual ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, - SourceLocation AtLoc, - SourceLocation ProtoLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc); - - //===--------------------------------------------------------------------===// - // C++ Declarations - // - virtual DeclPtrTy ActOnStartLinkageSpecification(Scope *S, - SourceLocation ExternLoc, - SourceLocation LangLoc, - llvm::StringRef Lang, - SourceLocation LBraceLoc); - virtual DeclPtrTy ActOnFinishLinkageSpecification(Scope *S, - DeclPtrTy LinkageSpec, - SourceLocation RBraceLoc); - - - //===--------------------------------------------------------------------===// - // C++ Classes - // - virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S, - const CXXScopeSpec *SS); - - virtual DeclPtrTy ActOnAccessSpecifier(AccessSpecifier Access, - SourceLocation ASLoc, - SourceLocation ColonLoc); - - virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, - Declarator &D, - MultiTemplateParamsArg TemplateParameterLists, - ExprTy *BitfieldWidth, - ExprTy *Init, bool IsDefinition, - bool Deleted = false); - - virtual MemInitResult ActOnMemInitializer(DeclPtrTy ConstructorD, - Scope *S, - CXXScopeSpec &SS, - IdentifierInfo *MemberOrBase, - TypeTy *TemplateTypeTy, - SourceLocation IdLoc, - SourceLocation LParenLoc, - ExprTy **Args, unsigned NumArgs, - SourceLocation *CommaLocs, - SourceLocation RParenLoc); - - MemInitResult BuildMemberInitializer(FieldDecl *Member, Expr **Args, - unsigned NumArgs, SourceLocation IdLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc); - - MemInitResult BuildBaseInitializer(QualType BaseType, - TypeSourceInfo *BaseTInfo, - Expr **Args, unsigned NumArgs, - SourceLocation LParenLoc, - SourceLocation RParenLoc, - CXXRecordDecl *ClassDecl); - - bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor, - CXXBaseOrMemberInitializer **Initializers, - unsigned NumInitializers, bool AnyErrors); - - void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation); - - - /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, - /// mark all the non-trivial destructors of its members and bases as - /// referenced. - void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, - CXXRecordDecl *Record); - - /// \brief The list of classes whose vtables have been used within - /// this translation unit, and the source locations at which the - /// first use occurred. - llvm::SmallVector, 16> - VTableUses; - - /// \brief The set of classes whose vtables have been used within - /// this translation unit, and a bit that will be true if the vtable is - /// required to be emitted (otherwise, it should be emitted only if needed - /// by code generation). - llvm::DenseMap VTablesUsed; - - /// \brief A list of all of the dynamic classes in this translation - /// unit. - llvm::SmallVector DynamicClasses; - - /// \brief Note that the vtable for the given class was used at the - /// given location. - void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, - bool DefinitionRequired = false); - - /// MarkVirtualMembersReferenced - Will mark all virtual members of the given - /// CXXRecordDecl referenced. - void MarkVirtualMembersReferenced(SourceLocation Loc, - const CXXRecordDecl *RD); - - /// \brief Define all of the vtables that have been used in this - /// translation unit and reference any virtual members used by those - /// vtables. - /// - /// \returns true if any work was done, false otherwise. - bool DefineUsedVTables(); - - void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); - - virtual void ActOnMemInitializers(DeclPtrTy ConstructorDecl, - SourceLocation ColonLoc, - MemInitTy **MemInits, unsigned NumMemInits, - bool AnyErrors); - - void CheckCompletedCXXClass(CXXRecordDecl *Record); - virtual void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, - DeclPtrTy TagDecl, - SourceLocation LBrac, - SourceLocation RBrac, - AttributeList *AttrList); - - virtual void ActOnReenterTemplateScope(Scope *S, DeclPtrTy Template); - virtual void ActOnStartDelayedMemberDeclarations(Scope *S, - DeclPtrTy Record); - virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S, - DeclPtrTy Method); - virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy Param); - virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, - DeclPtrTy Method); - virtual void ActOnFinishDelayedMemberDeclarations(Scope *S, - DeclPtrTy Record); - - virtual DeclPtrTy ActOnStaticAssertDeclaration(SourceLocation AssertLoc, - ExprArg AssertExpr, - ExprArg AssertMessageExpr); - - FriendDecl *CheckFriendTypeDecl(SourceLocation FriendLoc, - TypeSourceInfo *TSInfo); - DeclPtrTy ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, - MultiTemplateParamsArg TemplateParams); - DeclPtrTy ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool IsDefinition, - MultiTemplateParamsArg TemplateParams); - - QualType CheckConstructorDeclarator(Declarator &D, QualType R, - FunctionDecl::StorageClass& SC); - void CheckConstructor(CXXConstructorDecl *Constructor); - QualType CheckDestructorDeclarator(Declarator &D, QualType R, - FunctionDecl::StorageClass& SC); - bool CheckDestructor(CXXDestructorDecl *Destructor); - void CheckConversionDeclarator(Declarator &D, QualType &R, - FunctionDecl::StorageClass& SC); - DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion); - - //===--------------------------------------------------------------------===// - // C++ Derived Classes - // - - /// ActOnBaseSpecifier - Parsed a base specifier - CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class, - SourceRange SpecifierRange, - bool Virtual, AccessSpecifier Access, - QualType BaseType, - SourceLocation BaseLoc); - - /// SetClassDeclAttributesFromBase - Copies class decl traits - /// (such as whether the class has a trivial constructor, - /// trivial destructor etc) from the given base class. - void SetClassDeclAttributesFromBase(CXXRecordDecl *Class, - const CXXRecordDecl *BaseClass, - bool BaseIsVirtual); - - virtual BaseResult ActOnBaseSpecifier(DeclPtrTy classdecl, - SourceRange SpecifierRange, - bool Virtual, AccessSpecifier Access, - TypeTy *basetype, SourceLocation - BaseLoc); - - bool AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, - unsigned NumBases); - virtual void ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, - unsigned NumBases); - - bool IsDerivedFrom(QualType Derived, QualType Base); - bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths); - - // FIXME: I don't like this name. - void BuildBasePathArray(const CXXBasePaths &Paths, - CXXBaseSpecifierArray &BasePath); - - bool BasePathInvolvesVirtualBase(const CXXBaseSpecifierArray &BasePath); - - bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, - SourceLocation Loc, SourceRange Range, - CXXBaseSpecifierArray *BasePath = 0, - bool IgnoreAccess = false); - bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, - unsigned InaccessibleBaseID, - unsigned AmbigiousBaseConvID, - SourceLocation Loc, SourceRange Range, - DeclarationName Name, - CXXBaseSpecifierArray *BasePath); - - std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); - - /// CheckOverridingFunctionReturnType - Checks whether the return types are - /// covariant, according to C++ [class.virtual]p5. - bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New, - const CXXMethodDecl *Old); - - /// CheckOverridingFunctionExceptionSpec - Checks whether the exception - /// spec is a subset of base spec. - bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, - const CXXMethodDecl *Old); - - /// CheckOverridingFunctionAttributes - Checks whether attributes are - /// incompatible or prevent overriding. - bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New, - const CXXMethodDecl *Old); - - bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange); - - //===--------------------------------------------------------------------===// - // C++ Access Control - // - - enum AccessResult { - AR_accessible, - AR_inaccessible, - AR_dependent, - AR_delayed - }; - - bool SetMemberAccessSpecifier(NamedDecl *MemberDecl, - NamedDecl *PrevMemberDecl, - AccessSpecifier LexicalAS); - - AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, - DeclAccessPair FoundDecl); - AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, - DeclAccessPair FoundDecl); - AccessResult CheckAllocationAccess(SourceLocation OperatorLoc, - SourceRange PlacementRange, - CXXRecordDecl *NamingClass, - DeclAccessPair FoundDecl); - AccessResult CheckConstructorAccess(SourceLocation Loc, - CXXConstructorDecl *D, - const InitializedEntity &Entity, - AccessSpecifier Access, - bool IsCopyBindingRefToTemp = false); - AccessResult CheckDestructorAccess(SourceLocation Loc, - CXXDestructorDecl *Dtor, - const PartialDiagnostic &PDiag); - AccessResult CheckDirectMemberAccess(SourceLocation Loc, - NamedDecl *D, - const PartialDiagnostic &PDiag); - AccessResult CheckMemberOperatorAccess(SourceLocation Loc, - Expr *ObjectExpr, - Expr *ArgExpr, - DeclAccessPair FoundDecl); - AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr, - DeclAccessPair FoundDecl); - AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, - QualType Base, QualType Derived, - const CXXBasePath &Path, - unsigned DiagID, - bool ForceCheck = false, - bool ForceUnprivileged = false); - void CheckLookupAccess(const LookupResult &R); - - void HandleDependentAccessCheck(const DependentDiagnostic &DD, - const MultiLevelTemplateArgumentList &TemplateArgs); - void PerformDependentDiagnostics(const DeclContext *Pattern, - const MultiLevelTemplateArgumentList &TemplateArgs); - - void HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx); - - /// A flag to suppress access checking. - bool SuppressAccessChecking; - - void ActOnStartSuppressingAccessChecks(); - void ActOnStopSuppressingAccessChecks(); - - enum AbstractDiagSelID { - AbstractNone = -1, - AbstractReturnType, - AbstractParamType, - AbstractVariableType, - AbstractFieldType - }; - - bool RequireNonAbstractType(SourceLocation Loc, QualType T, - const PartialDiagnostic &PD, - const CXXRecordDecl *CurrentRD = 0); - - bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, - AbstractDiagSelID SelID = AbstractNone, - const CXXRecordDecl *CurrentRD = 0); - - //===--------------------------------------------------------------------===// - // C++ Overloaded Operators [C++ 13.5] - // - - bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl); - - bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl); - - //===--------------------------------------------------------------------===// - // C++ Templates [C++ 14] - // - void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, - QualType ObjectType, bool EnteringContext, - bool &MemberOfUnknownSpecialization); - - virtual TemplateNameKind isTemplateName(Scope *S, - CXXScopeSpec &SS, - UnqualifiedId &Name, - TypeTy *ObjectType, - bool EnteringContext, - TemplateTy &Template, - bool &MemberOfUnknownSpecialization); - - virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, - SourceLocation IILoc, - Scope *S, - const CXXScopeSpec *SS, - TemplateTy &SuggestedTemplate, - TemplateNameKind &SuggestedKind); - - bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); - TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl); - - virtual DeclPtrTy ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, - SourceLocation EllipsisLoc, - SourceLocation KeyLoc, - IdentifierInfo *ParamName, - SourceLocation ParamNameLoc, - unsigned Depth, unsigned Position, - SourceLocation EqualLoc, - TypeTy *DefaultArg); - - QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc); - virtual DeclPtrTy ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, - unsigned Depth, - unsigned Position, - SourceLocation EqualLoc, - ExprArg DefaultArg); - virtual DeclPtrTy ActOnTemplateTemplateParameter(Scope *S, - SourceLocation TmpLoc, - TemplateParamsTy *Params, - IdentifierInfo *ParamName, - SourceLocation ParamNameLoc, - unsigned Depth, - unsigned Position, - SourceLocation EqualLoc, - const ParsedTemplateArgument &DefaultArg); - - virtual TemplateParamsTy * - ActOnTemplateParameterList(unsigned Depth, - SourceLocation ExportLoc, - SourceLocation TemplateLoc, - SourceLocation LAngleLoc, - DeclPtrTy *Params, unsigned NumParams, - SourceLocation RAngleLoc); - - /// \brief The context in which we are checking a template parameter - /// list. - enum TemplateParamListContext { - TPC_ClassTemplate, - TPC_FunctionTemplate, - TPC_ClassTemplateMember, - TPC_FriendFunctionTemplate - }; - - bool CheckTemplateParameterList(TemplateParameterList *NewParams, - TemplateParameterList *OldParams, - TemplateParamListContext TPC); - TemplateParameterList * - MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, - const CXXScopeSpec &SS, - TemplateParameterList **ParamLists, - unsigned NumParamLists, - bool IsFriend, - bool &IsExplicitSpecialization, - bool &Invalid); - - DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, CXXScopeSpec &SS, - IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr, - TemplateParameterList *TemplateParams, - AccessSpecifier AS); - - void translateTemplateArguments(const ASTTemplateArgsPtr &In, - TemplateArgumentListInfo &Out); - - QualType CheckTemplateIdType(TemplateName Template, - SourceLocation TemplateLoc, - const TemplateArgumentListInfo &TemplateArgs); - - virtual TypeResult - ActOnTemplateIdType(TemplateTy Template, SourceLocation TemplateLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, - SourceLocation RAngleLoc); - - virtual TypeResult ActOnTagTemplateIdType(TypeResult Type, - TagUseKind TUK, - DeclSpec::TST TagSpec, - SourceLocation TagLoc); - - OwningExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, - LookupResult &R, - bool RequiresADL, - const TemplateArgumentListInfo &TemplateArgs); - OwningExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, - DeclarationName Name, - SourceLocation NameLoc, - const TemplateArgumentListInfo &TemplateArgs); - - virtual TemplateNameKind ActOnDependentTemplateName(Scope *S, - SourceLocation TemplateKWLoc, - CXXScopeSpec &SS, - UnqualifiedId &Name, - TypeTy *ObjectType, - bool EnteringContext, - TemplateTy &Template); - - bool CheckClassTemplatePartialSpecializationArgs( - TemplateParameterList *TemplateParams, - const TemplateArgumentListBuilder &TemplateArgs, - bool &MirrorsPrimaryTemplate); - - virtual DeclResult - ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, - CXXScopeSpec &SS, - TemplateTy Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, - SourceLocation RAngleLoc, - AttributeList *Attr, - MultiTemplateParamsArg TemplateParameterLists); - - virtual DeclPtrTy ActOnTemplateDeclarator(Scope *S, - MultiTemplateParamsArg TemplateParameterLists, - Declarator &D); - - virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, - MultiTemplateParamsArg TemplateParameterLists, - Declarator &D); - - bool - CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, - TemplateSpecializationKind NewTSK, - NamedDecl *PrevDecl, - TemplateSpecializationKind PrevTSK, - SourceLocation PrevPtOfInstantiation, - bool &SuppressNew); - - bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, - const TemplateArgumentListInfo &ExplicitTemplateArgs, - LookupResult &Previous); - - bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, - const TemplateArgumentListInfo *ExplicitTemplateArgs, - LookupResult &Previous); - bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); - - virtual DeclResult - ActOnExplicitInstantiation(Scope *S, - SourceLocation ExternLoc, - SourceLocation TemplateLoc, - unsigned TagSpec, - SourceLocation KWLoc, - const CXXScopeSpec &SS, - TemplateTy Template, - SourceLocation TemplateNameLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, - SourceLocation RAngleLoc, - AttributeList *Attr); - - virtual DeclResult - ActOnExplicitInstantiation(Scope *S, - SourceLocation ExternLoc, - SourceLocation TemplateLoc, - unsigned TagSpec, - SourceLocation KWLoc, - CXXScopeSpec &SS, - IdentifierInfo *Name, - SourceLocation NameLoc, - AttributeList *Attr); - - virtual DeclResult ActOnExplicitInstantiation(Scope *S, - SourceLocation ExternLoc, - SourceLocation TemplateLoc, - Declarator &D); - - TemplateArgumentLoc - SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, - SourceLocation TemplateLoc, - SourceLocation RAngleLoc, - Decl *Param, - TemplateArgumentListBuilder &Converted); - - /// \brief Specifies the context in which a particular template - /// argument is being checked. - enum CheckTemplateArgumentKind { - /// \brief The template argument was specified in the code or was - /// instantiated with some deduced template arguments. - CTAK_Specified, - - /// \brief The template argument was deduced via template argument - /// deduction. - CTAK_Deduced, - - /// \brief The template argument was deduced from an array bound - /// via template argument deduction. - CTAK_DeducedFromArrayBound - }; - - bool CheckTemplateArgument(NamedDecl *Param, - const TemplateArgumentLoc &Arg, - TemplateDecl *Template, - SourceLocation TemplateLoc, - SourceLocation RAngleLoc, - TemplateArgumentListBuilder &Converted, - CheckTemplateArgumentKind CTAK = CTAK_Specified); - - bool CheckTemplateArgumentList(TemplateDecl *Template, - SourceLocation TemplateLoc, - const TemplateArgumentListInfo &TemplateArgs, - bool PartialTemplateArgs, - TemplateArgumentListBuilder &Converted); - - bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, - const TemplateArgumentLoc &Arg, - TemplateArgumentListBuilder &Converted); - - bool CheckTemplateArgument(TemplateTypeParmDecl *Param, - TypeSourceInfo *Arg); - bool CheckTemplateArgumentPointerToMember(Expr *Arg, - TemplateArgument &Converted); - bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, - QualType InstantiatedParamType, Expr *&Arg, - TemplateArgument &Converted, - CheckTemplateArgumentKind CTAK = CTAK_Specified); - bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, - const TemplateArgumentLoc &Arg); - - OwningExprResult - BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, - QualType ParamType, - SourceLocation Loc); - OwningExprResult - BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, - SourceLocation Loc); - - /// \brief Enumeration describing how template parameter lists are compared - /// for equality. - enum TemplateParameterListEqualKind { - /// \brief We are matching the template parameter lists of two templates - /// that might be redeclarations. - /// - /// \code - /// template struct X; - /// template struct X; - /// \endcode - TPL_TemplateMatch, - - /// \brief We are matching the template parameter lists of two template - /// template parameters as part of matching the template parameter lists - /// of two templates that might be redeclarations. - /// - /// \code - /// template class TT> struct X; - /// template class Other> struct X; - /// \endcode - TPL_TemplateTemplateParmMatch, - - /// \brief We are matching the template parameter lists of a template - /// template argument against the template parameter lists of a template - /// template parameter. - /// - /// \code - /// template class Metafun> struct X; - /// template struct integer_c; - /// X xic; - /// \endcode - TPL_TemplateTemplateArgumentMatch - }; - - bool TemplateParameterListsAreEqual(TemplateParameterList *New, - TemplateParameterList *Old, - bool Complain, - TemplateParameterListEqualKind Kind, - SourceLocation TemplateArgLoc - = SourceLocation()); - - bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams); - - /// \brief Called when the parser has parsed a C++ typename - /// specifier, e.g., "typename T::type". - /// - /// \param S The scope in which this typename type occurs. - /// \param TypenameLoc the location of the 'typename' keyword - /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). - /// \param II the identifier we're retrieving (e.g., 'type' in the example). - /// \param IdLoc the location of the identifier. - virtual TypeResult - ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, - const CXXScopeSpec &SS, const IdentifierInfo &II, - SourceLocation IdLoc); - - /// \brief Called when the parser has parsed a C++ typename - /// specifier that ends in a template-id, e.g., - /// "typename MetaFun::template apply". - /// - /// \param S The scope in which this typename type occurs. - /// \param TypenameLoc the location of the 'typename' keyword - /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). - /// \param TemplateLoc the location of the 'template' keyword, if any. - /// \param Ty the type that the typename specifier refers to. - virtual TypeResult - ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, - const CXXScopeSpec &SS, SourceLocation TemplateLoc, - TypeTy *Ty); - - QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, - const IdentifierInfo &II, - SourceLocation KeywordLoc, - SourceRange NNSRange, - SourceLocation IILoc); - - TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, - SourceLocation Loc, - DeclarationName Name); - bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS); - - std::string - getTemplateArgumentBindingsText(const TemplateParameterList *Params, - const TemplateArgumentList &Args); - - std::string - getTemplateArgumentBindingsText(const TemplateParameterList *Params, - const TemplateArgument *Args, - unsigned NumArgs); - - /// \brief Describes the result of template argument deduction. - /// - /// The TemplateDeductionResult enumeration describes the result of - /// template argument deduction, as returned from - /// DeduceTemplateArguments(). The separate TemplateDeductionInfo - /// structure provides additional information about the results of - /// template argument deduction, e.g., the deduced template argument - /// list (if successful) or the specific template parameters or - /// deduced arguments that were involved in the failure. - enum TemplateDeductionResult { - /// \brief Template argument deduction was successful. - TDK_Success = 0, - /// \brief Template argument deduction exceeded the maximum template - /// instantiation depth (which has already been diagnosed). - TDK_InstantiationDepth, - /// \brief Template argument deduction did not deduce a value - /// for every template parameter. - TDK_Incomplete, - /// \brief Template argument deduction produced inconsistent - /// deduced values for the given template parameter. - TDK_Inconsistent, - /// \brief Template argument deduction failed due to inconsistent - /// cv-qualifiers on a template parameter type that would - /// otherwise be deduced, e.g., we tried to deduce T in "const T" - /// but were given a non-const "X". - TDK_InconsistentQuals, - /// \brief Substitution of the deduced template argument values - /// resulted in an error. - TDK_SubstitutionFailure, - /// \brief Substitution of the deduced template argument values - /// into a non-deduced context produced a type or value that - /// produces a type that does not match the original template - /// arguments provided. - TDK_NonDeducedMismatch, - /// \brief When performing template argument deduction for a function - /// template, there were too many call arguments. - TDK_TooManyArguments, - /// \brief When performing template argument deduction for a function - /// template, there were too few call arguments. - TDK_TooFewArguments, - /// \brief The explicitly-specified template arguments were not valid - /// template arguments for the given template. - TDK_InvalidExplicitArguments, - /// \brief The arguments included an overloaded function name that could - /// not be resolved to a suitable function. - TDK_FailedOverloadResolution - }; - - /// \brief Provides information about an attempted template argument - /// deduction, whose success or failure was described by a - /// TemplateDeductionResult value. - class TemplateDeductionInfo { - /// \brief The context in which the template arguments are stored. - ASTContext &Context; - - /// \brief The deduced template argument list. - /// - TemplateArgumentList *Deduced; - - /// \brief The source location at which template argument - /// deduction is occurring. - SourceLocation Loc; - - // do not implement these - TemplateDeductionInfo(const TemplateDeductionInfo&); - TemplateDeductionInfo &operator=(const TemplateDeductionInfo&); - - public: - TemplateDeductionInfo(ASTContext &Context, SourceLocation Loc) - : Context(Context), Deduced(0), Loc(Loc) { } - - ~TemplateDeductionInfo() { - // FIXME: if (Deduced) Deduced->Destroy(Context); - } - - /// \brief Returns the location at which template argument is - /// occuring. - SourceLocation getLocation() const { - return Loc; - } - - /// \brief Take ownership of the deduced template argument list. - TemplateArgumentList *take() { - TemplateArgumentList *Result = Deduced; - Deduced = 0; - return Result; - } - - /// \brief Provide a new template argument list that contains the - /// results of template argument deduction. - void reset(TemplateArgumentList *NewDeduced) { - // FIXME: if (Deduced) Deduced->Destroy(Context); - Deduced = NewDeduced; - } - - /// \brief The template parameter to which a template argument - /// deduction failure refers. - /// - /// Depending on the result of template argument deduction, this - /// template parameter may have different meanings: - /// - /// TDK_Incomplete: this is the first template parameter whose - /// corresponding template argument was not deduced. - /// - /// TDK_Inconsistent: this is the template parameter for which - /// two different template argument values were deduced. - TemplateParameter Param; - - /// \brief The first template argument to which the template - /// argument deduction failure refers. - /// - /// Depending on the result of the template argument deduction, - /// this template argument may have different meanings: - /// - /// TDK_Inconsistent: this argument is the first value deduced - /// for the corresponding template parameter. - /// - /// TDK_SubstitutionFailure: this argument is the template - /// argument we were instantiating when we encountered an error. - /// - /// TDK_NonDeducedMismatch: this is the template argument - /// provided in the source code. - TemplateArgument FirstArg; - - /// \brief The second template argument to which the template - /// argument deduction failure refers. - /// - /// FIXME: Finish documenting this. - TemplateArgument SecondArg; - }; - - TemplateDeductionResult - DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, - const TemplateArgumentList &TemplateArgs, - TemplateDeductionInfo &Info); - - TemplateDeductionResult - SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - const TemplateArgumentListInfo &ExplicitTemplateArgs, - llvm::SmallVectorImpl &Deduced, - llvm::SmallVectorImpl &ParamTypes, - QualType *FunctionType, - TemplateDeductionInfo &Info); - - TemplateDeductionResult - FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, - llvm::SmallVectorImpl &Deduced, - unsigned NumExplicitlySpecified, - FunctionDecl *&Specialization, - TemplateDeductionInfo &Info); - - TemplateDeductionResult - DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - const TemplateArgumentListInfo *ExplicitTemplateArgs, - Expr **Args, unsigned NumArgs, - FunctionDecl *&Specialization, - TemplateDeductionInfo &Info); - - TemplateDeductionResult - DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - const TemplateArgumentListInfo *ExplicitTemplateArgs, - QualType ArgFunctionType, - FunctionDecl *&Specialization, - TemplateDeductionInfo &Info); - - TemplateDeductionResult - DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - QualType ToType, - CXXConversionDecl *&Specialization, - TemplateDeductionInfo &Info); - - TemplateDeductionResult - DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - const TemplateArgumentListInfo *ExplicitTemplateArgs, - FunctionDecl *&Specialization, - TemplateDeductionInfo &Info); - - FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, - FunctionTemplateDecl *FT2, - SourceLocation Loc, - TemplatePartialOrderingContext TPOC); - UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, - UnresolvedSetIterator SEnd, - TemplatePartialOrderingContext TPOC, - SourceLocation Loc, - const PartialDiagnostic &NoneDiag, - const PartialDiagnostic &AmbigDiag, - const PartialDiagnostic &CandidateDiag); - - ClassTemplatePartialSpecializationDecl * - getMoreSpecializedPartialSpecialization( - ClassTemplatePartialSpecializationDecl *PS1, - ClassTemplatePartialSpecializationDecl *PS2, - SourceLocation Loc); - - void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, - bool OnlyDeduced, - unsigned Depth, - llvm::SmallVectorImpl &Used); - void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, - llvm::SmallVectorImpl &Deduced); - - //===--------------------------------------------------------------------===// - // C++ Template Instantiation - // - - MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D, - const TemplateArgumentList *Innermost = 0, - bool RelativeToPrimary = false, - const FunctionDecl *Pattern = 0); - - /// \brief A template instantiation that is currently in progress. - struct ActiveTemplateInstantiation { - /// \brief The kind of template instantiation we are performing - enum InstantiationKind { - /// We are instantiating a template declaration. The entity is - /// the declaration we're instantiating (e.g., a CXXRecordDecl). - TemplateInstantiation, - - /// We are instantiating a default argument for a template - /// parameter. The Entity is the template, and - /// TemplateArgs/NumTemplateArguments provides the template - /// arguments as specified. - /// FIXME: Use a TemplateArgumentList - DefaultTemplateArgumentInstantiation, - - /// We are instantiating a default argument for a function. - /// The Entity is the ParmVarDecl, and TemplateArgs/NumTemplateArgs - /// provides the template arguments as specified. - DefaultFunctionArgumentInstantiation, - - /// We are substituting explicit template arguments provided for - /// a function template. The entity is a FunctionTemplateDecl. - ExplicitTemplateArgumentSubstitution, - - /// We are substituting template argument determined as part of - /// template argument deduction for either a class template - /// partial specialization or a function template. The - /// Entity is either a ClassTemplatePartialSpecializationDecl or - /// a FunctionTemplateDecl. - DeducedTemplateArgumentSubstitution, - - /// We are substituting prior template arguments into a new - /// template parameter. The template parameter itself is either a - /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. - PriorTemplateArgumentSubstitution, - - /// We are checking the validity of a default template argument that - /// has been used when naming a template-id. - DefaultTemplateArgumentChecking - } Kind; - - /// \brief The point of instantiation within the source code. - SourceLocation PointOfInstantiation; - - /// \brief The template in which we are performing the instantiation, - /// for substitutions of prior template arguments. - TemplateDecl *Template; - - /// \brief The entity that is being instantiated. - uintptr_t Entity; - - /// \brief The list of template arguments we are substituting, if they - /// are not part of the entity. - const TemplateArgument *TemplateArgs; - - /// \brief The number of template arguments in TemplateArgs. - unsigned NumTemplateArgs; - - /// \brief The source range that covers the construct that cause - /// the instantiation, e.g., the template-id that causes a class - /// template instantiation. - SourceRange InstantiationRange; - - ActiveTemplateInstantiation() - : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0), - NumTemplateArgs(0) {} - - /// \brief Determines whether this template is an actual instantiation - /// that should be counted toward the maximum instantiation depth. - bool isInstantiationRecord() const; - - friend bool operator==(const ActiveTemplateInstantiation &X, - const ActiveTemplateInstantiation &Y) { - if (X.Kind != Y.Kind) - return false; - - if (X.Entity != Y.Entity) - return false; - - switch (X.Kind) { - case TemplateInstantiation: - return true; - - case PriorTemplateArgumentSubstitution: - case DefaultTemplateArgumentChecking: - if (X.Template != Y.Template) - return false; - - // Fall through - - case DefaultTemplateArgumentInstantiation: - case ExplicitTemplateArgumentSubstitution: - case DeducedTemplateArgumentSubstitution: - case DefaultFunctionArgumentInstantiation: - return X.TemplateArgs == Y.TemplateArgs; - - } - - return true; - } - - friend bool operator!=(const ActiveTemplateInstantiation &X, - const ActiveTemplateInstantiation &Y) { - return !(X == Y); - } - }; - - /// \brief List of active template instantiations. - /// - /// This vector is treated as a stack. As one template instantiation - /// requires another template instantiation, additional - /// instantiations are pushed onto the stack up to a - /// user-configurable limit LangOptions::InstantiationDepth. - llvm::SmallVector - ActiveTemplateInstantiations; - - /// \brief The number of ActiveTemplateInstantiation entries in - /// \c ActiveTemplateInstantiations that are not actual instantiations and, - /// therefore, should not be counted as part of the instantiation depth. - unsigned NonInstantiationEntries; - - /// \brief The last template from which a template instantiation - /// error or warning was produced. - /// - /// This value is used to suppress printing of redundant template - /// instantiation backtraces when there are multiple errors in the - /// same instantiation. FIXME: Does this belong in Sema? It's tough - /// to implement it anywhere else. - ActiveTemplateInstantiation LastTemplateInstantiationErrorContext; - - /// \brief The stack of calls expression undergoing template instantiation. - /// - /// The top of this stack is used by a fixit instantiating unresolved - /// function calls to fix the AST to match the textual change it prints. - llvm::SmallVector CallsUndergoingInstantiation; - - /// \brief A stack object to be created when performing template - /// instantiation. - /// - /// Construction of an object of type \c InstantiatingTemplate - /// pushes the current instantiation onto the stack of active - /// instantiations. If the size of this stack exceeds the maximum - /// number of recursive template instantiations, construction - /// produces an error and evaluates true. - /// - /// Destruction of this object will pop the named instantiation off - /// the stack. - struct InstantiatingTemplate { - /// \brief Note that we are instantiating a class template, - /// function template, or a member thereof. - InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - Decl *Entity, - SourceRange InstantiationRange = SourceRange()); - - /// \brief Note that we are instantiating a default argument in a - /// template-id. - InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - TemplateDecl *Template, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs, - SourceRange InstantiationRange = SourceRange()); - - /// \brief Note that we are instantiating a default argument in a - /// template-id. - InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - FunctionTemplateDecl *FunctionTemplate, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs, - ActiveTemplateInstantiation::InstantiationKind Kind, - SourceRange InstantiationRange = SourceRange()); - - /// \brief Note that we are instantiating as part of template - /// argument deduction for a class template partial - /// specialization. - InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - ClassTemplatePartialSpecializationDecl *PartialSpec, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs, - SourceRange InstantiationRange = SourceRange()); - - InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - ParmVarDecl *Param, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs, - SourceRange InstantiationRange = SourceRange()); - - /// \brief Note that we are substituting prior template arguments into a - /// non-type or template template parameter. - InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - TemplateDecl *Template, - NonTypeTemplateParmDecl *Param, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs, - SourceRange InstantiationRange); - - InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - TemplateDecl *Template, - TemplateTemplateParmDecl *Param, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs, - SourceRange InstantiationRange); - - /// \brief Note that we are checking the default template argument - /// against the template parameter for a given template-id. - InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - TemplateDecl *Template, - NamedDecl *Param, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs, - SourceRange InstantiationRange); - - - /// \brief Note that we have finished instantiating this template. - void Clear(); - - ~InstantiatingTemplate() { Clear(); } - - /// \brief Determines whether we have exceeded the maximum - /// recursive template instantiations. - operator bool() const { return Invalid; } - - private: - Sema &SemaRef; - bool Invalid; - - bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, - SourceRange InstantiationRange); - - InstantiatingTemplate(const InstantiatingTemplate&); // not implemented - - InstantiatingTemplate& - operator=(const InstantiatingTemplate&); // not implemented - }; - - void PrintInstantiationStack(); - - /// \brief Determines whether we are currently in a context where - /// template argument substitution failures are not considered - /// errors. - /// - /// When this routine returns true, the emission of most diagnostics - /// will be suppressed and there will be no local error recovery. - bool isSFINAEContext() const; - - /// \brief RAII class used to determine whether SFINAE has - /// trapped any errors that occur during template argument - /// deduction. - class SFINAETrap { - Sema &SemaRef; - unsigned PrevSFINAEErrors; - public: - explicit SFINAETrap(Sema &SemaRef) - : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors) { } - - ~SFINAETrap() { SemaRef.NumSFINAEErrors = PrevSFINAEErrors; } - - /// \brief Determine whether any SFINAE errors have been trapped. - bool hasErrorOccurred() const { - return SemaRef.NumSFINAEErrors > PrevSFINAEErrors; - } - }; - - /// \brief RAII class that determines when any errors have occurred - /// between the time the instance was created and the time it was - /// queried. - class ErrorTrap { - Sema &SemaRef; - unsigned PrevErrors; - - public: - explicit ErrorTrap(Sema &SemaRef) - : SemaRef(SemaRef), PrevErrors(SemaRef.getDiagnostics().getNumErrors()) {} - - /// \brief Determine whether any errors have occurred since this - /// object instance was created. - bool hasErrorOccurred() const { - return SemaRef.getDiagnostics().getNumErrors() > PrevErrors; - } - }; - - /// \brief A stack-allocated class that identifies which local - /// variable declaration instantiations are present in this scope. - /// - /// A new instance of this class type will be created whenever we - /// instantiate a new function declaration, which will have its own - /// set of parameter declarations. - class LocalInstantiationScope { - /// \brief Reference to the semantic analysis that is performing - /// this template instantiation. - Sema &SemaRef; - - /// \brief A mapping from local declarations that occur - /// within a template to their instantiations. - /// - /// This mapping is used during instantiation to keep track of, - /// e.g., function parameter and variable declarations. For example, - /// given: - /// - /// \code - /// template T add(T x, T y) { return x + y; } - /// \endcode - /// - /// when we instantiate add, we will introduce a mapping from - /// the ParmVarDecl for 'x' that occurs in the template to the - /// instantiated ParmVarDecl for 'x'. - llvm::DenseMap LocalDecls; - - /// \brief The outer scope, which contains local variable - /// definitions from some other instantiation (that may not be - /// relevant to this particular scope). - LocalInstantiationScope *Outer; - - /// \brief Whether we have already exited this scope. - bool Exited; - - /// \brief Whether to combine this scope with the outer scope, such that - /// lookup will search our outer scope. - bool CombineWithOuterScope; - - // This class is non-copyable - LocalInstantiationScope(const LocalInstantiationScope &); - LocalInstantiationScope &operator=(const LocalInstantiationScope &); - - public: - LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) - : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), - Exited(false), CombineWithOuterScope(CombineWithOuterScope) - { - SemaRef.CurrentInstantiationScope = this; - } - - ~LocalInstantiationScope() { - Exit(); - } - - /// \brief Exit this local instantiation scope early. - void Exit() { - if (Exited) - return; - - SemaRef.CurrentInstantiationScope = Outer; - Exited = true; - } - - Decl *getInstantiationOf(const Decl *D); - - VarDecl *getInstantiationOf(const VarDecl *Var) { - return cast(getInstantiationOf(cast(Var))); - } - - ParmVarDecl *getInstantiationOf(const ParmVarDecl *Var) { - return cast(getInstantiationOf(cast(Var))); - } - - NonTypeTemplateParmDecl *getInstantiationOf( - const NonTypeTemplateParmDecl *Var) { - return cast(getInstantiationOf(cast(Var))); - } - - void InstantiatedLocal(const Decl *D, Decl *Inst); - }; - - /// \brief The current instantiation scope used to store local - /// variables. - LocalInstantiationScope *CurrentInstantiationScope; - - /// \brief The number of typos corrected by CorrectTypo. - unsigned TyposCorrected; - - /// \brief Worker object for performing CFG-based warnings. - sema::AnalysisBasedWarnings AnalysisWarnings; - - /// \brief An entity for which implicit template instantiation is required. - /// - /// The source location associated with the declaration is the first place in - /// the source code where the declaration was "used". It is not necessarily - /// the point of instantiation (which will be either before or after the - /// namespace-scope declaration that triggered this implicit instantiation), - /// However, it is the location that diagnostics should generally refer to, - /// because users will need to know what code triggered the instantiation. - typedef std::pair PendingImplicitInstantiation; - - /// \brief The queue of implicit template instantiations that are required - /// but have not yet been performed. - std::deque PendingImplicitInstantiations; - - /// \brief The queue of implicit template instantiations that are required - /// and must be performed within the current local scope. - /// - /// This queue is only used for member functions of local classes in - /// templates, which must be instantiated in the same scope as their - /// enclosing function, so that they can reference function-local - /// types, static variables, enumerators, etc. - std::deque PendingLocalImplicitInstantiations; - - void PerformPendingImplicitInstantiations(bool LocalOnly = false); - - TypeSourceInfo *SubstType(TypeSourceInfo *T, - const MultiLevelTemplateArgumentList &TemplateArgs, - SourceLocation Loc, DeclarationName Entity); - - QualType SubstType(QualType T, - const MultiLevelTemplateArgumentList &TemplateArgs, - SourceLocation Loc, DeclarationName Entity); - - TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T, - const MultiLevelTemplateArgumentList &TemplateArgs, - SourceLocation Loc, - DeclarationName Entity); - ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, - const MultiLevelTemplateArgumentList &TemplateArgs); - OwningExprResult SubstExpr(Expr *E, - const MultiLevelTemplateArgumentList &TemplateArgs); - - OwningStmtResult SubstStmt(Stmt *S, - const MultiLevelTemplateArgumentList &TemplateArgs); - - Decl *SubstDecl(Decl *D, DeclContext *Owner, - const MultiLevelTemplateArgumentList &TemplateArgs); - - bool - SubstBaseSpecifiers(CXXRecordDecl *Instantiation, - CXXRecordDecl *Pattern, - const MultiLevelTemplateArgumentList &TemplateArgs); - - bool - InstantiateClass(SourceLocation PointOfInstantiation, - CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, - const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateSpecializationKind TSK, - bool Complain = true); - - bool - InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation, - ClassTemplateSpecializationDecl *ClassTemplateSpec, - TemplateSpecializationKind TSK, - bool Complain = true); - - void InstantiateClassMembers(SourceLocation PointOfInstantiation, - CXXRecordDecl *Instantiation, - const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateSpecializationKind TSK); - - void InstantiateClassTemplateSpecializationMembers( - SourceLocation PointOfInstantiation, - ClassTemplateSpecializationDecl *ClassTemplateSpec, - TemplateSpecializationKind TSK); - - NestedNameSpecifier * - SubstNestedNameSpecifier(NestedNameSpecifier *NNS, - SourceRange Range, - const MultiLevelTemplateArgumentList &TemplateArgs); - - TemplateName - SubstTemplateName(TemplateName Name, SourceLocation Loc, - const MultiLevelTemplateArgumentList &TemplateArgs); - bool Subst(const TemplateArgumentLoc &Arg, TemplateArgumentLoc &Result, - const MultiLevelTemplateArgumentList &TemplateArgs); - - void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, - FunctionDecl *Function, - bool Recursive = false, - bool DefinitionRequired = false); - void InstantiateStaticDataMemberDefinition( - SourceLocation PointOfInstantiation, - VarDecl *Var, - bool Recursive = false, - bool DefinitionRequired = false); - - void InstantiateMemInitializers(CXXConstructorDecl *New, - const CXXConstructorDecl *Tmpl, - const MultiLevelTemplateArgumentList &TemplateArgs); - - NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, - const MultiLevelTemplateArgumentList &TemplateArgs); - DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, - const MultiLevelTemplateArgumentList &TemplateArgs); - - // Objective-C declarations. - virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, - SourceLocation ClassLoc, - IdentifierInfo *SuperName, - SourceLocation SuperLoc, - const DeclPtrTy *ProtoRefs, - unsigned NumProtoRefs, - const SourceLocation *ProtoLocs, - SourceLocation EndProtoLoc, - AttributeList *AttrList); - - virtual DeclPtrTy ActOnCompatiblityAlias( - SourceLocation AtCompatibilityAliasLoc, - IdentifierInfo *AliasName, SourceLocation AliasLocation, - IdentifierInfo *ClassName, SourceLocation ClassLocation); - - void CheckForwardProtocolDeclarationForCircularDependency( - IdentifierInfo *PName, - SourceLocation &PLoc, SourceLocation PrevLoc, - const ObjCList &PList); - - virtual DeclPtrTy ActOnStartProtocolInterface( - SourceLocation AtProtoInterfaceLoc, - IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, - const DeclPtrTy *ProtoRefNames, unsigned NumProtoRefs, - const SourceLocation *ProtoLocs, - SourceLocation EndProtoLoc, - AttributeList *AttrList); - - virtual DeclPtrTy ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, - IdentifierInfo *ClassName, - SourceLocation ClassLoc, - IdentifierInfo *CategoryName, - SourceLocation CategoryLoc, - const DeclPtrTy *ProtoRefs, - unsigned NumProtoRefs, - const SourceLocation *ProtoLocs, - SourceLocation EndProtoLoc); - - virtual DeclPtrTy ActOnStartClassImplementation( - SourceLocation AtClassImplLoc, - IdentifierInfo *ClassName, SourceLocation ClassLoc, - IdentifierInfo *SuperClassname, - SourceLocation SuperClassLoc); - - virtual DeclPtrTy ActOnStartCategoryImplementation( - SourceLocation AtCatImplLoc, - IdentifierInfo *ClassName, - SourceLocation ClassLoc, - IdentifierInfo *CatName, - SourceLocation CatLoc); - - virtual DeclPtrTy ActOnForwardClassDeclaration(SourceLocation Loc, - IdentifierInfo **IdentList, - SourceLocation *IdentLocs, - unsigned NumElts); - - virtual DeclPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc, - const IdentifierLocPair *IdentList, - unsigned NumElts, - AttributeList *attrList); - - virtual void FindProtocolDeclaration(bool WarnOnDeclarations, - const IdentifierLocPair *ProtocolId, - unsigned NumProtocols, - llvm::SmallVectorImpl &Protocols); - - /// Ensure attributes are consistent with type. - /// \param [in, out] Attributes The attributes to check; they will - /// be modified to be consistent with \arg PropertyTy. - void CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy, - SourceLocation Loc, - unsigned &Attributes); - void ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCContainerDecl *DC); - void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, - ObjCPropertyDecl *SuperProperty, - const IdentifierInfo *Name); - void ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl); - - void CompareMethodParamsInBaseAndSuper(Decl *IDecl, - ObjCMethodDecl *MethodDecl, - bool IsInstance); - - void CompareProperties(Decl *CDecl, DeclPtrTy MergeProtocols); - - void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, - ObjCInterfaceDecl *ID); - - void MatchOneProtocolPropertiesInClass(Decl *CDecl, - ObjCProtocolDecl *PDecl); - - virtual void ActOnAtEnd(Scope *S, SourceRange AtEnd, - DeclPtrTy classDecl, - DeclPtrTy *allMethods = 0, unsigned allNum = 0, - DeclPtrTy *allProperties = 0, unsigned pNum = 0, - DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0); - - virtual DeclPtrTy ActOnProperty(Scope *S, SourceLocation AtLoc, - FieldDeclarator &FD, ObjCDeclSpec &ODS, - Selector GetterSel, Selector SetterSel, - DeclPtrTy ClassCategory, - bool *OverridingProperty, - tok::ObjCKeywordKind MethodImplKind); - - virtual DeclPtrTy ActOnPropertyImplDecl(Scope *S, - SourceLocation AtLoc, - SourceLocation PropertyLoc, - bool ImplKind,DeclPtrTy ClassImplDecl, - IdentifierInfo *PropertyId, - IdentifierInfo *PropertyIvar); - - virtual DeclPtrTy ActOnMethodDeclaration( - SourceLocation BeginLoc, // location of the + or -. - SourceLocation EndLoc, // location of the ; or {. - tok::TokenKind MethodType, - DeclPtrTy ClassDecl, ObjCDeclSpec &ReturnQT, TypeTy *ReturnType, - Selector Sel, - // optional arguments. The number of types/arguments is obtained - // from the Sel.getNumArgs(). - ObjCArgInfo *ArgInfo, - DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args - AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind, - bool isVariadic = false); - - // Helper method for ActOnClassMethod/ActOnInstanceMethod. - // Will search "local" class/category implementations for a method decl. - // Will also search in class's root looking for instance method. - // Returns 0 if no method is found. - ObjCMethodDecl *LookupPrivateClassMethod(Selector Sel, - ObjCInterfaceDecl *CDecl); - ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel, - ObjCInterfaceDecl *ClassDecl); - - OwningExprResult - HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, - Expr *BaseExpr, - DeclarationName MemberName, - SourceLocation MemberLoc); - - virtual OwningExprResult - ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, - IdentifierInfo &propertyName, - SourceLocation receiverNameLoc, - SourceLocation propertyNameLoc); - - virtual ObjCMessageKind getObjCMessageKind(Scope *S, - IdentifierInfo *Name, - SourceLocation NameLoc, - bool IsSuper, - bool HasTrailingDot, - TypeTy *&ReceiverType); - - virtual OwningExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, - Selector Sel, - SourceLocation LBracLoc, - SourceLocation SelectorLoc, - SourceLocation RBracLoc, - MultiExprArg Args); - - OwningExprResult BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, - QualType ReceiverType, - SourceLocation SuperLoc, - Selector Sel, - ObjCMethodDecl *Method, - SourceLocation LBracLoc, - SourceLocation RBracLoc, - MultiExprArg Args); - - virtual OwningExprResult ActOnClassMessage(Scope *S, - TypeTy *Receiver, - Selector Sel, - SourceLocation LBracLoc, - SourceLocation SelectorLoc, - SourceLocation RBracLoc, - MultiExprArg Args); - - OwningExprResult BuildInstanceMessage(ExprArg Receiver, - QualType ReceiverType, - SourceLocation SuperLoc, - Selector Sel, - ObjCMethodDecl *Method, - SourceLocation LBracLoc, - SourceLocation RBracLoc, - MultiExprArg Args); - - virtual OwningExprResult ActOnInstanceMessage(Scope *S, - ExprArg Receiver, - Selector Sel, - SourceLocation LBracLoc, - SourceLocation SelectorLoc, - SourceLocation RBracLoc, - MultiExprArg Args); - - - /// ActOnPragmaOptionsAlign - Called on well formed #pragma options align. - virtual void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, - SourceLocation PragmaLoc, - SourceLocation KindLoc); - - /// ActOnPragmaPack - Called on well formed #pragma pack(...). - virtual void ActOnPragmaPack(PragmaPackKind Kind, - IdentifierInfo *Name, - ExprTy *Alignment, - SourceLocation PragmaLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc); - - /// ActOnPragmaUnused - Called on well-formed '#pragma unused'. - virtual void ActOnPragmaUnused(const Token *Identifiers, - unsigned NumIdentifiers, Scope *curScope, - SourceLocation PragmaLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc); - - NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II); - void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W); - - /// ActOnPragmaWeakID - Called on well formed #pragma weak ident. - virtual void ActOnPragmaWeakID(IdentifierInfo* WeakName, - SourceLocation PragmaLoc, - SourceLocation WeakNameLoc); - - /// ActOnPragmaWeakAlias - Called on well formed #pragma weak ident = ident. - virtual void ActOnPragmaWeakAlias(IdentifierInfo* WeakName, - IdentifierInfo* AliasName, - SourceLocation PragmaLoc, - SourceLocation WeakNameLoc, - SourceLocation AliasNameLoc); - - /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to - /// a the record decl, to handle '#pragma pack' and '#pragma options align'. - void AddAlignmentAttributesForRecord(RecordDecl *RD); - - /// FreePackedContext - Deallocate and null out PackContext. - void FreePackedContext(); - - /// AddAlignedAttr - Adds an aligned attribute to a particular declaration. - void AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E); - - /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit - /// cast. If there is already an implicit cast, merge into the existing one. - /// If isLvalue, the result of the cast is an lvalue. - void ImpCastExprToType(Expr *&Expr, QualType Type, CastExpr::CastKind Kind, - bool isLvalue = false, - CXXBaseSpecifierArray BasePath = - CXXBaseSpecifierArray()); - - // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts - // functions and arrays to their respective pointers (C99 6.3.2.1). - Expr *UsualUnaryConversions(Expr *&expr); - - // DefaultFunctionArrayConversion - converts functions and arrays - // to their respective pointers (C99 6.3.2.1). - void DefaultFunctionArrayConversion(Expr *&expr); - - // DefaultFunctionArrayLvalueConversion - converts functions and - // arrays to their respective pointers and performs the - // lvalue-to-rvalue conversion. - void DefaultFunctionArrayLvalueConversion(Expr *&expr); - - // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that - // do not have a prototype. Integer promotions are performed on each - // argument, and arguments that have type float are promoted to double. - void DefaultArgumentPromotion(Expr *&Expr); - - // Used for emitting the right warning by DefaultVariadicArgumentPromotion - enum VariadicCallType { - VariadicFunction, - VariadicBlock, - VariadicMethod, - VariadicConstructor, - VariadicDoesNotApply - }; - - /// GatherArgumentsForCall - Collector argument expressions for various - /// form of call prototypes. - bool GatherArgumentsForCall(SourceLocation CallLoc, - FunctionDecl *FDecl, - const FunctionProtoType *Proto, - unsigned FirstProtoArg, - Expr **Args, unsigned NumArgs, - llvm::SmallVector &AllArgs, - VariadicCallType CallType = VariadicDoesNotApply); - - // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but - // will warn if the resulting type is not a POD type. - bool DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT, - FunctionDecl *FDecl); - - // UsualArithmeticConversions - performs the UsualUnaryConversions on it's - // operands and then handles various conversions that are common to binary - // operators (C99 6.3.1.8). If both operands aren't arithmetic, this - // routine returns the first non-arithmetic type found. The client is - // responsible for emitting appropriate error diagnostics. - QualType UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr, - bool isCompAssign = false); - - /// AssignConvertType - All of the 'assignment' semantic checks return this - /// enum to indicate whether the assignment was allowed. These checks are - /// done for simple assignments, as well as initialization, return from - /// function, argument passing, etc. The query is phrased in terms of a - /// source and destination type. - enum AssignConvertType { - /// Compatible - the types are compatible according to the standard. - Compatible, - - /// PointerToInt - The assignment converts a pointer to an int, which we - /// accept as an extension. - PointerToInt, - - /// IntToPointer - The assignment converts an int to a pointer, which we - /// accept as an extension. - IntToPointer, - - /// FunctionVoidPointer - The assignment is between a function pointer and - /// void*, which the standard doesn't allow, but we accept as an extension. - FunctionVoidPointer, - - /// IncompatiblePointer - The assignment is between two pointers types that - /// are not compatible, but we accept them as an extension. - IncompatiblePointer, - - /// IncompatiblePointer - The assignment is between two pointers types which - /// point to integers which have a different sign, but are otherwise identical. - /// This is a subset of the above, but broken out because it's by far the most - /// common case of incompatible pointers. - IncompatiblePointerSign, - - /// CompatiblePointerDiscardsQualifiers - The assignment discards - /// c/v/r qualifiers, which we accept as an extension. - CompatiblePointerDiscardsQualifiers, - - /// IncompatibleNestedPointerQualifiers - The assignment is between two - /// nested pointer types, and the qualifiers other than the first two - /// levels differ e.g. char ** -> const char **, but we accept them as an - /// extension. - IncompatibleNestedPointerQualifiers, - - /// IncompatibleVectors - The assignment is between two vector types that - /// have the same size, which we accept as an extension. - IncompatibleVectors, - - /// IntToBlockPointer - The assignment converts an int to a block - /// pointer. We disallow this. - IntToBlockPointer, - - /// IncompatibleBlockPointer - The assignment is between two block - /// pointers types that are not compatible. - IncompatibleBlockPointer, - - /// IncompatibleObjCQualifiedId - The assignment is between a qualified - /// id type and something else (that is incompatible with it). For example, - /// "id " = "Foo *", where "Foo *" doesn't implement the XXX protocol. - IncompatibleObjCQualifiedId, - - /// Incompatible - We reject this conversion outright, it is invalid to - /// represent it in the AST. - Incompatible - }; - - /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the - /// assignment conversion type specified by ConvTy. This returns true if the - /// conversion was invalid or false if the conversion was accepted. - bool DiagnoseAssignmentResult(AssignConvertType ConvTy, - SourceLocation Loc, - QualType DstType, QualType SrcType, - Expr *SrcExpr, AssignmentAction Action, - bool *Complained = 0); - - /// CheckAssignmentConstraints - Perform type checking for assignment, - /// argument passing, variable initialization, and function return values. - /// This routine is only used by the following two methods. C99 6.5.16. - AssignConvertType CheckAssignmentConstraints(QualType lhs, QualType rhs); - - // CheckSingleAssignmentConstraints - Currently used by - // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking, - // this routine performs the default function/array converions. - AssignConvertType CheckSingleAssignmentConstraints(QualType lhs, - Expr *&rExpr); - - // \brief If the lhs type is a transparent union, check whether we - // can initialize the transparent union with the given expression. - AssignConvertType CheckTransparentUnionArgumentConstraints(QualType lhs, - Expr *&rExpr); - - // Helper function for CheckAssignmentConstraints (C99 6.5.16.1p1) - AssignConvertType CheckPointerTypesForAssignment(QualType lhsType, - QualType rhsType); - - AssignConvertType CheckObjCPointerTypesForAssignment(QualType lhsType, - QualType rhsType); - - // Helper function for CheckAssignmentConstraints involving two - // block pointer types. - AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType, - QualType rhsType); - - bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); - - bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType); - - bool PerformImplicitConversion(Expr *&From, QualType ToType, - AssignmentAction Action, - bool AllowExplicit = false); - bool PerformImplicitConversion(Expr *&From, QualType ToType, - AssignmentAction Action, - bool AllowExplicit, - ImplicitConversionSequence& ICS); - bool PerformImplicitConversion(Expr *&From, QualType ToType, - const ImplicitConversionSequence& ICS, - AssignmentAction Action, - bool IgnoreBaseAccess = false); - bool PerformImplicitConversion(Expr *&From, QualType ToType, - const StandardConversionSequence& SCS, - AssignmentAction Action,bool IgnoreBaseAccess); - - /// the following "Check" methods will return a valid/converted QualType - /// or a null QualType (indicating an error diagnostic was issued). - - /// type checking binary operators (subroutines of CreateBuiltinBinOp). - QualType InvalidOperands(SourceLocation l, Expr *&lex, Expr *&rex); - QualType CheckPointerToMemberOperands( // C++ 5.5 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isIndirect); - QualType CheckMultiplyDivideOperands( // C99 6.5.5 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign, - bool isDivide); - QualType CheckRemainderOperands( // C99 6.5.5 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); - QualType CheckAdditionOperands( // C99 6.5.6 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, QualType* CompLHSTy = 0); - QualType CheckSubtractionOperands( // C99 6.5.6 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, QualType* CompLHSTy = 0); - QualType CheckShiftOperands( // C99 6.5.7 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); - QualType CheckCompareOperands( // C99 6.5.8/9 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, unsigned Opc, - bool isRelational); - QualType CheckBitwiseOperands( // C99 6.5.[10...12] - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); - QualType CheckLogicalOperands( // C99 6.5.[13,14] - Expr *&lex, Expr *&rex, SourceLocation OpLoc, unsigned Opc); - // CheckAssignmentOperands is used for both simple and compound assignment. - // For simple assignment, pass both expressions and a null converted type. - // For compound assignment, pass both expressions and the converted type. - QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] - Expr *lex, Expr *&rex, SourceLocation OpLoc, QualType convertedType); - QualType CheckCommaOperands( // C99 6.5.17 - Expr *lex, Expr *&rex, SourceLocation OpLoc); - QualType CheckConditionalOperands( // C99 6.5.15 - Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); - QualType CXXCheckConditionalOperands( // C++ 5.16 - Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc); - QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, - bool *NonStandardCompositeType = 0); - - QualType FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, - SourceLocation questionLoc); - - /// type checking for vector binary operators. - QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex); - QualType CheckVectorCompareOperands(Expr *&lex, Expr *&rx, - SourceLocation l, bool isRel); - - /// type checking unary operators (subroutines of ActOnUnaryOp). - /// C99 6.5.3.1, 6.5.3.2, 6.5.3.4 - QualType CheckIncrementDecrementOperand(Expr *op, SourceLocation OpLoc, - bool isInc, bool isPrefix); - QualType CheckAddressOfOperand(Expr *op, SourceLocation OpLoc); - QualType CheckIndirectionOperand(Expr *op, SourceLocation OpLoc); - QualType CheckRealImagOperand(Expr *&Op, SourceLocation OpLoc, bool isReal); - - /// type checking primary expressions. - QualType CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, - const IdentifierInfo *Comp, - SourceLocation CmpLoc); - - /// type checking declaration initializers (C99 6.7.8) - bool CheckInitList(const InitializedEntity &Entity, - InitListExpr *&InitList, QualType &DeclType); - bool CheckForConstantInitializer(Expr *e, QualType t); - - // type checking C++ declaration initializers (C++ [dcl.init]). - - /// ReferenceCompareResult - Expresses the result of comparing two - /// types (cv1 T1 and cv2 T2) to determine their compatibility for the - /// purposes of initialization by reference (C++ [dcl.init.ref]p4). - enum ReferenceCompareResult { - /// Ref_Incompatible - The two types are incompatible, so direct - /// reference binding is not possible. - Ref_Incompatible = 0, - /// Ref_Related - The two types are reference-related, which means - /// that their unqualified forms (T1 and T2) are either the same - /// or T1 is a base class of T2. - Ref_Related, - /// Ref_Compatible_With_Added_Qualification - The two types are - /// reference-compatible with added qualification, meaning that - /// they are reference-compatible and the qualifiers on T1 (cv1) - /// are greater than the qualifiers on T2 (cv2). - Ref_Compatible_With_Added_Qualification, - /// Ref_Compatible - The two types are reference-compatible and - /// have equivalent qualifiers (cv1 == cv2). - Ref_Compatible - }; - - ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc, - QualType T1, QualType T2, - bool& DerivedToBase); - - /// CheckCastTypes - Check type constraints for casting between types under - /// C semantics, or forward to CXXCheckCStyleCast in C++. - bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr, - CastExpr::CastKind &Kind, CXXBaseSpecifierArray &BasePath, - bool FunctionalStyle = false); - - // CheckVectorCast - check type constraints for vectors. - // Since vectors are an extension, there are no C standard reference for this. - // We allow casting between vectors and integer datatypes of the same size. - // returns true if the cast is invalid - bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, - CastExpr::CastKind &Kind); - - // CheckExtVectorCast - check type constraints for extended vectors. - // Since vectors are an extension, there are no C standard reference for this. - // We allow casting between vectors and integer datatypes of the same size, - // or vectors and the element type of that vector. - // returns true if the cast is invalid - bool CheckExtVectorCast(SourceRange R, QualType VectorTy, Expr *&CastExpr, - CastExpr::CastKind &Kind); - - /// CXXCheckCStyleCast - Check constraints of a C-style or function-style - /// cast under C++ semantics. - bool CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath, - bool FunctionalStyle); - - /// CheckMessageArgumentTypes - Check types in an Obj-C message send. - /// \param Method - May be null. - /// \param [out] ReturnType - The return type of the send. - /// \return true iff there were any incompatible types. - bool CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, Selector Sel, - ObjCMethodDecl *Method, bool isClassMessage, - SourceLocation lbrac, SourceLocation rbrac, - QualType &ReturnType); - - /// CheckBooleanCondition - Diagnose problems involving the use of - /// the given expression as a boolean condition (e.g. in an if - /// statement). Also performs the standard function and array - /// decays, possibly changing the input variable. - /// - /// \param Loc - A location associated with the condition, e.g. the - /// 'if' keyword. - /// \return true iff there were any errors - bool CheckBooleanCondition(Expr *&CondExpr, SourceLocation Loc); - - virtual OwningExprResult ActOnBooleanCondition(Scope *S, SourceLocation Loc, - ExprArg SubExpr); - - /// DiagnoseAssignmentAsCondition - Given that an expression is - /// being used as a boolean condition, warn if it's an assignment. - void DiagnoseAssignmentAsCondition(Expr *E); - - /// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid. - bool CheckCXXBooleanCondition(Expr *&CondExpr); - - /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have - /// the specified width and sign. If an overflow occurs, detect it and emit - /// the specified diagnostic. - void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal, - unsigned NewWidth, bool NewSign, - SourceLocation Loc, unsigned DiagID); - - /// Checks that the Objective-C declaration is declared in the global scope. - /// Emits an error and marks the declaration as invalid if it's not declared - /// in the global scope. - bool CheckObjCDeclScope(Decl *D); - - void InitBuiltinVaListType(); - - /// VerifyIntegerConstantExpression - verifies that an expression is an ICE, - /// and reports the appropriate diagnostics. Returns false on success. - /// Can optionally return the value of the expression. - bool VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result = 0); - - /// VerifyBitField - verifies that a bit field expression is an ICE and has - /// the correct width, and that the field type is valid. - /// Returns false on success. - /// Can optionally return whether the bit-field is of width 0 - bool VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, - QualType FieldTy, const Expr *BitWidth, - bool *ZeroWidth = 0); - - /// \name Code completion - //@{ - virtual void CodeCompleteOrdinaryName(Scope *S, - CodeCompletionContext CompletionContext); - virtual void CodeCompleteExpression(Scope *S, QualType T); - virtual void CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *Base, - SourceLocation OpLoc, - bool IsArrow); - virtual void CodeCompleteTag(Scope *S, unsigned TagSpec); - virtual void CodeCompleteCase(Scope *S); - virtual void CodeCompleteCall(Scope *S, ExprTy *Fn, - ExprTy **Args, unsigned NumArgs); - virtual void CodeCompleteInitializer(Scope *S, DeclPtrTy D); - virtual void CodeCompleteReturn(Scope *S); - virtual void CodeCompleteAssignmentRHS(Scope *S, ExprTy *LHS); - - virtual void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, - bool EnteringContext); - virtual void CodeCompleteUsing(Scope *S); - virtual void CodeCompleteUsingDirective(Scope *S); - virtual void CodeCompleteNamespaceDecl(Scope *S); - virtual void CodeCompleteNamespaceAliasDecl(Scope *S); - virtual void CodeCompleteOperatorName(Scope *S); - - virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, - bool InInterface); - virtual void CodeCompleteObjCAtVisibility(Scope *S); - virtual void CodeCompleteObjCAtStatement(Scope *S); - virtual void CodeCompleteObjCAtExpression(Scope *S); - virtual void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); - virtual void CodeCompleteObjCPropertyGetter(Scope *S, DeclPtrTy ClassDecl, - DeclPtrTy *Methods, - unsigned NumMethods); - virtual void CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ClassDecl, - DeclPtrTy *Methods, - unsigned NumMethods); - virtual void CodeCompleteObjCMessageReceiver(Scope *S); - virtual void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, - IdentifierInfo **SelIdents, - unsigned NumSelIdents); - virtual void CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, - IdentifierInfo **SelIdents, - unsigned NumSelIdents); - virtual void CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, - IdentifierInfo **SelIdents, - unsigned NumSelIdents); - virtual void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, - unsigned NumProtocols); - virtual void CodeCompleteObjCProtocolDecl(Scope *S); - virtual void CodeCompleteObjCInterfaceDecl(Scope *S); - virtual void CodeCompleteObjCSuperclass(Scope *S, - IdentifierInfo *ClassName, - SourceLocation ClassNameLoc); - virtual void CodeCompleteObjCImplementationDecl(Scope *S); - virtual void CodeCompleteObjCInterfaceCategory(Scope *S, - IdentifierInfo *ClassName, - SourceLocation ClassNameLoc); - virtual void CodeCompleteObjCImplementationCategory(Scope *S, - IdentifierInfo *ClassName, - SourceLocation ClassNameLoc); - virtual void CodeCompleteObjCPropertyDefinition(Scope *S, - DeclPtrTy ObjCImpDecl); - virtual void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, - IdentifierInfo *PropertyName, - DeclPtrTy ObjCImpDecl); - virtual void CodeCompleteObjCMethodDecl(Scope *S, - bool IsInstanceMethod, - TypeTy *ReturnType, - DeclPtrTy IDecl); - virtual void CodeCompleteObjCMethodDeclSelector(Scope *S, - bool IsInstanceMethod, - bool AtParameterName, - TypeTy *ReturnType, - IdentifierInfo **SelIdents, - unsigned NumSelIdents); - - //@} - - //===--------------------------------------------------------------------===// - // Extra semantic analysis beyond the C type system - -public: - SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, - unsigned ByteNo) const; - -private: - bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall); - bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall); - - bool CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall); - bool CheckObjCString(Expr *Arg); - - Action::OwningExprResult CheckBuiltinFunctionCall(unsigned BuiltinID, - CallExpr *TheCall); - bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - - bool SemaBuiltinVAStart(CallExpr *TheCall); - bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); - bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); - -public: - // Used by C++ template instantiation. - Action::OwningExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); - -private: - bool SemaBuiltinPrefetch(CallExpr *TheCall); - bool SemaBuiltinObjectSize(CallExpr *TheCall); - bool SemaBuiltinLongjmp(CallExpr *TheCall); - OwningExprResult SemaBuiltinAtomicOverloaded(OwningExprResult TheCallResult); - bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, - llvm::APSInt &Result); - bool SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, - bool HasVAListArg, unsigned format_idx, - unsigned firstDataArg); - void CheckPrintfString(const StringLiteral *FExpr, const Expr *OrigFormatExpr, - const CallExpr *TheCall, bool HasVAListArg, - unsigned format_idx, unsigned firstDataArg); - void CheckNonNullArguments(const NonNullAttr *NonNull, - const CallExpr *TheCall); - void CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, - unsigned format_idx, unsigned firstDataArg); - void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, - SourceLocation ReturnLoc); - void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex); - void CheckImplicitConversions(Expr *E); -}; - -//===--------------------------------------------------------------------===// -// Typed version of Parser::ExprArg (smart pointer for wrapping Expr pointers). -template -class ExprOwningPtr : public Action::ExprArg { -public: - ExprOwningPtr(Sema *S, T *expr) : Action::ExprArg(*S, expr) {} - - void reset(T* p) { Action::ExprArg::operator=(p); } - T* get() const { return static_cast(Action::ExprArg::get()); } - T* take() { return static_cast(Action::ExprArg::take()); } - T* release() { return take(); } - - T& operator*() const { return *get(); } - T* operator->() const { return get(); } -}; - -} // end namespace clang - -#endif diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index e110e3d..e629f0f 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -11,9 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "SemaInit.h" -#include "Lookup.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" @@ -22,6 +23,7 @@ #include "clang/AST/ExprCXX.h" using namespace clang; +using namespace sema; /// A copy of Sema's enum without AR_delayed. enum AccessResult { @@ -132,10 +134,10 @@ struct EffectiveContext { bool Dependent; }; -/// Like Sema's AccessedEntity, but kindly lets us scribble all over +/// Like sema:;AccessedEntity, but kindly lets us scribble all over /// it. -struct AccessTarget : public Sema::AccessedEntity { - AccessTarget(const Sema::AccessedEntity &Entity) +struct AccessTarget : public AccessedEntity { + AccessTarget(const AccessedEntity &Entity) : AccessedEntity(Entity) { initialize(); } @@ -562,6 +564,130 @@ static AccessResult GetFriendKind(Sema &S, return OnFailure; } +namespace { + +/// A helper class for checking for a friend which will grant access +/// to a protected instance member. +struct ProtectedFriendContext { + Sema &S; + const EffectiveContext &EC; + const CXXRecordDecl *NamingClass; + bool CheckDependent; + bool EverDependent; + + /// The path down to the current base class. + llvm::SmallVector CurPath; + + ProtectedFriendContext(Sema &S, const EffectiveContext &EC, + const CXXRecordDecl *InstanceContext, + const CXXRecordDecl *NamingClass) + : S(S), EC(EC), NamingClass(NamingClass), + CheckDependent(InstanceContext->isDependentContext() || + NamingClass->isDependentContext()), + EverDependent(false) {} + + /// Check classes in the current path for friendship, starting at + /// the given index. + bool checkFriendshipAlongPath(unsigned I) { + assert(I < CurPath.size()); + for (unsigned E = CurPath.size(); I != E; ++I) { + switch (GetFriendKind(S, EC, CurPath[I])) { + case AR_accessible: return true; + case AR_inaccessible: continue; + case AR_dependent: EverDependent = true; continue; + } + } + return false; + } + + /// Perform a search starting at the given class. + /// + /// PrivateDepth is the index of the last (least derived) class + /// along the current path such that a notional public member of + /// the final class in the path would have access in that class. + bool findFriendship(const CXXRecordDecl *Cur, unsigned PrivateDepth) { + // If we ever reach the naming class, check the current path for + // friendship. We can also stop recursing because we obviously + // won't find the naming class there again. + if (Cur == NamingClass) + return checkFriendshipAlongPath(PrivateDepth); + + if (CheckDependent && MightInstantiateTo(Cur, NamingClass)) + EverDependent = true; + + // Recurse into the base classes. + for (CXXRecordDecl::base_class_const_iterator + I = Cur->bases_begin(), E = Cur->bases_end(); I != E; ++I) { + + // If this is private inheritance, then a public member of the + // base will not have any access in classes derived from Cur. + unsigned BasePrivateDepth = PrivateDepth; + if (I->getAccessSpecifier() == AS_private) + BasePrivateDepth = CurPath.size() - 1; + + const CXXRecordDecl *RD; + + QualType T = I->getType(); + if (const RecordType *RT = T->getAs()) { + RD = cast(RT->getDecl()); + } else if (const InjectedClassNameType *IT + = T->getAs()) { + RD = IT->getDecl(); + } else { + assert(T->isDependentType() && "non-dependent base wasn't a record?"); + EverDependent = true; + continue; + } + + // Recurse. We don't need to clean up if this returns true. + CurPath.push_back(RD); + if (findFriendship(RD->getCanonicalDecl(), BasePrivateDepth)) + return true; + CurPath.pop_back(); + } + + return false; + } + + bool findFriendship(const CXXRecordDecl *Cur) { + assert(CurPath.empty()); + CurPath.push_back(Cur); + return findFriendship(Cur, 0); + } +}; +} + +/// Search for a class P that EC is a friend of, under the constraint +/// InstanceContext <= P <= NamingClass +/// and with the additional restriction that a protected member of +/// NamingClass would have some natural access in P. +/// +/// That second condition isn't actually quite right: the condition in +/// the standard is whether the target would have some natural access +/// in P. The difference is that the target might be more accessible +/// along some path not passing through NamingClass. Allowing that +/// introduces two problems: +/// - It breaks encapsulation because you can suddenly access a +/// forbidden base class's members by subclassing it elsewhere. +/// - It makes access substantially harder to compute because it +/// breaks the hill-climbing algorithm: knowing that the target is +/// accessible in some base class would no longer let you change +/// the question solely to whether the base class is accessible, +/// because the original target might have been more accessible +/// because of crazy subclassing. +/// So we don't implement that. +static AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC, + const CXXRecordDecl *InstanceContext, + const CXXRecordDecl *NamingClass) { + assert(InstanceContext->getCanonicalDecl() == InstanceContext); + assert(NamingClass->getCanonicalDecl() == NamingClass); + + ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass); + if (PRC.findFriendship(InstanceContext)) return AR_accessible; + if (PRC.EverDependent) return AR_dependent; + return AR_inaccessible; +} + static AccessResult HasAccess(Sema &S, const EffectiveContext &EC, const CXXRecordDecl *NamingClass, @@ -629,20 +755,25 @@ static AccessResult HasAccess(Sema &S, } } - if (!NamingClass->hasFriends()) - return OnFailure; - - // Don't consider friends if we're under the [class.protected] - // restriction, above. + // [M3] and [B3] say that, if the target is protected in N, we grant + // access if the access occurs in a friend or member of some class P + // that's a subclass of N and where the target has some natural + // access in P. The 'member' aspect is easy to handle because P + // would necessarily be one of the effective-context records, and we + // address that above. The 'friend' aspect is completely ridiculous + // to implement because there are no restrictions at all on P + // *unless* the [class.protected] restriction applies. If it does, + // however, we should ignore whether the naming class is a friend, + // and instead rely on whether any potential P is a friend. if (Access == AS_protected && Target.hasInstanceContext()) { const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); if (!InstanceContext) return AR_dependent; - - switch (IsDerivedFromInclusive(InstanceContext, NamingClass)) { - case AR_accessible: break; + switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass)) { + case AR_accessible: return AR_accessible; case AR_inaccessible: return OnFailure; case AR_dependent: return AR_dependent; } + llvm_unreachable("impossible friendship kind"); } switch (GetFriendKind(S, EC, NamingClass)) { @@ -799,6 +930,57 @@ static CXXBasePath *FindBestPath(Sema &S, return BestPath; } +/// Given that an entity has protected natural access, check whether +/// access might be denied because of the protected member access +/// restriction. +/// +/// \return true if a note was emitted +static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC, + AccessTarget &Target) { + // Only applies to instance accesses. + if (!Target.hasInstanceContext()) + return false; + assert(Target.isMemberAccess()); + NamedDecl *D = Target.getTargetDecl(); + + const CXXRecordDecl *DeclaringClass = Target.getDeclaringClass(); + DeclaringClass = DeclaringClass->getCanonicalDecl(); + + for (EffectiveContext::record_iterator + I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { + const CXXRecordDecl *ECRecord = *I; + switch (IsDerivedFromInclusive(ECRecord, DeclaringClass)) { + case AR_accessible: break; + case AR_inaccessible: continue; + case AR_dependent: continue; + } + + // The effective context is a subclass of the declaring class. + // If that class isn't a superclass of the instance context, + // then the [class.protected] restriction applies. + + // To get this exactly right, this might need to be checked more + // holistically; it's not necessarily the case that gaining + // access here would grant us access overall. + + const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); + assert(InstanceContext && "diagnosing dependent access"); + + switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { + case AR_accessible: continue; + case AR_dependent: continue; + case AR_inaccessible: + S.Diag(D->getLocation(), diag::note_access_protected_restricted) + << (InstanceContext != Target.getNamingClass()->getCanonicalDecl()) + << S.Context.getTypeDeclType(InstanceContext) + << S.Context.getTypeDeclType(ECRecord); + return true; + } + } + + return false; +} + /// Diagnose the path which caused the given declaration or base class /// to become inaccessible. static void DiagnoseAccessPath(Sema &S, @@ -817,6 +999,10 @@ static void DiagnoseAccessPath(Sema &S, if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) { switch (HasAccess(S, EC, DeclaringClass, D->getAccess(), Entity)) { case AR_inaccessible: { + if (Access == AS_protected && + TryDiagnoseProtectedAccess(S, EC, Entity)) + return; + S.Diag(D->getLocation(), diag::note_access_natural) << (unsigned) (Access == AS_protected) << /*FIXME: not implicitly*/ 0; @@ -1033,7 +1219,7 @@ static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, // access control. if (S.CurContext->isFileContext() && S.ParsingDeclDepth) { S.DelayedDiagnostics.push_back( - Sema::DelayedDiagnostic::makeAccess(Loc, Entity)); + DelayedDiagnostic::makeAccess(Loc, Entity)); return Sema::AR_delayed; } @@ -1266,7 +1452,7 @@ Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr, Found.getAccess() == AS_public) return AR_accessible; - OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).getPointer(); + OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).Expression; CXXRecordDecl *NamingClass = Ovl->getNamingClass(); AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 69f27b0..0921156 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -12,8 +12,9 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "Lookup.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Lookup.h" +#include "clang/AST/Attr.h" #include "clang/AST/Expr.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" @@ -62,18 +63,30 @@ namespace { /// alignment to the previous value. If \arg Name is non-zero then /// the first such named record is popped, otherwise the top record /// is popped. Returns true if the pop succeeded. - bool pop(IdentifierInfo *Name); + bool pop(IdentifierInfo *Name, bool IsReset); }; } // end anonymous namespace. -bool PragmaPackStack::pop(IdentifierInfo *Name) { - if (Stack.empty()) - return false; - +bool PragmaPackStack::pop(IdentifierInfo *Name, bool IsReset) { // If name is empty just pop top. if (!Name) { - Alignment = Stack.back().Alignment; - Stack.pop_back(); + // An empty stack is a special case... + if (Stack.empty()) { + // If this isn't a reset, it is always an error. + if (!IsReset) + return false; + + // Otherwise, it is an error only if some alignment has been set. + if (!Alignment) + return false; + + // Otherwise, reset to the default alignment. + Alignment = 0; + } else { + Alignment = Stack.back().Alignment; + Stack.pop_back(); + } + return true; } @@ -108,9 +121,11 @@ void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) { // Otherwise, check to see if we need a max field alignment attribute. if (unsigned Alignment = Stack->getAlignment()) { if (Alignment == PackStackEntry::kMac68kAlignmentSentinel) - RD->addAttr(::new (Context) AlignMac68kAttr()); + RD->addAttr(::new (Context) AlignMac68kAttr(SourceLocation(), Context)); else - RD->addAttr(::new (Context) MaxFieldAlignmentAttr(Alignment * 8)); + RD->addAttr(::new (Context) MaxFieldAlignmentAttr(SourceLocation(), + Context, + Alignment * 8)); } } @@ -122,13 +137,10 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, PragmaPackStack *Context = static_cast(PackContext); - // Reset just pops the top of the stack. - if (Kind == Action::POAK_Reset) { - // Do the pop. - if (!Context->pop(0)) { - // If a name was specified then failure indicates the name - // wasn't found. Otherwise failure indicates the stack was - // empty. + // Reset just pops the top of the stack, or resets the current alignment to + // default. + if (Kind == Sema::POAK_Reset) { + if (!Context->pop(0, /*IsReset=*/true)) { Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed) << "stack empty"; } @@ -188,7 +200,6 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, !(Val == 0 || Val.isPowerOf2()) || Val.getZExtValue() > 16) { Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment); - Alignment->Destroy(Context); return; // Ignore } @@ -201,11 +212,11 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, PragmaPackStack *Context = static_cast(PackContext); switch (Kind) { - case Action::PPK_Default: // pack([n]) + case Sema::PPK_Default: // pack([n]) Context->setAlignment(AlignmentVal); break; - case Action::PPK_Show: // pack(show) + case Sema::PPK_Show: // pack(show) // Show the current alignment, making sure to show the right value // for the default. AlignmentVal = Context->getAlignment(); @@ -218,21 +229,21 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal; break; - case Action::PPK_Push: // pack(push [, id] [, [n]) + case Sema::PPK_Push: // pack(push [, id] [, [n]) Context->push(Name); // Set the new alignment if specified. if (Alignment) Context->setAlignment(AlignmentVal); break; - case Action::PPK_Pop: // pack(pop [, id] [, n]) + case Sema::PPK_Pop: // pack(pop [, id] [, n]) // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack: // "#pragma pack(pop, identifier, n) is undefined" if (Alignment && Name) Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment); // Do the pop. - if (!Context->pop(Name)) { + if (!Context->pop(Name, /*IsReset=*/false)) { // If a name was specified then failure indicates the name // wasn't found. Otherwise failure indicates the stack was // empty. @@ -277,6 +288,80 @@ void Sema::ActOnPragmaUnused(const Token *Identifiers, unsigned NumIdentifiers, continue; } - VD->addAttr(::new (Context) UnusedAttr()); + VD->addAttr(::new (Context) UnusedAttr(Tok.getLocation(), Context)); + } +} + +typedef std::vector > VisStack; + +void Sema::AddPushedVisibilityAttribute(Decl *D) { + if (!VisContext) + return; + + if (D->hasAttr()) + return; + + VisStack *Stack = static_cast(VisContext); + VisibilityAttr::VisibilityType type = Stack->back().first; + SourceLocation loc = Stack->back().second; + + D->addAttr(::new (Context) VisibilityAttr(loc, Context, type)); +} + +/// FreeVisContext - Deallocate and null out VisContext. +void Sema::FreeVisContext() { + delete static_cast(VisContext); + VisContext = 0; +} + +static void PushPragmaVisibility(Sema &S, VisibilityAttr::VisibilityType type, + SourceLocation loc) { + // Put visibility on stack. + if (!S.VisContext) + S.VisContext = new VisStack; + + VisStack *Stack = static_cast(S.VisContext); + Stack->push_back(std::make_pair(type, loc)); +} + +void Sema::ActOnPragmaVisibility(bool IsPush, const IdentifierInfo* VisType, + SourceLocation PragmaLoc) { + if (IsPush) { + // Compute visibility to use. + VisibilityAttr::VisibilityType type; + if (VisType->isStr("default")) + type = VisibilityAttr::Default; + else if (VisType->isStr("hidden")) + type = VisibilityAttr::Hidden; + else if (VisType->isStr("internal")) + type = VisibilityAttr::Hidden; // FIXME + else if (VisType->isStr("protected")) + type = VisibilityAttr::Protected; + else { + Diag(PragmaLoc, diag::warn_attribute_unknown_visibility) << + VisType->getName(); + return; + } + PushPragmaVisibility(*this, type, PragmaLoc); + } else { + PopPragmaVisibility(); + } +} + +void Sema::PushVisibilityAttr(const VisibilityAttr *Attr) { + PushPragmaVisibility(*this, Attr->getVisibility(), Attr->getLocation()); +} + +void Sema::PopPragmaVisibility() { + // Pop visibility from stack, if there is one on the stack. + if (VisContext) { + VisStack *Stack = static_cast(VisContext); + + Stack->pop_back(); + // To simplify the implementation, never keep around an empty stack. + if (Stack->empty()) + FreeVisContext(); } + // FIXME: Add diag for pop without push. } diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index b8e27e7..21b1a73 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "SemaInit.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Initialization.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" @@ -43,16 +43,16 @@ static void CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, const SourceRange &DestRange, - CastExpr::CastKind &Kind); + CastKind &Kind); static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath); + CastKind &Kind, + CXXCastPath &BasePath); static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, const SourceRange &DestRange, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath); + CastKind &Kind, + CXXCastPath &BasePath); static bool CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType); @@ -73,54 +73,54 @@ static TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath); + CastKind &Kind, + CXXCastPath &BasePath); static TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath); + CastKind &Kind, + CXXCastPath &BasePath); static TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, bool CStyle, const SourceRange &OpRange, QualType OrigSrcType, QualType OrigDestType, unsigned &msg, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath); + CastKind &Kind, + CXXCastPath &BasePath); static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, QualType DestType,bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath); + CastKind &Kind, + CXXCastPath &BasePath); static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind); + CastKind &Kind); static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath); + CastKind &Kind, + CXXCastPath &BasePath); static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, unsigned &msg); static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind); + CastKind &Kind); /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. -Action::OwningExprResult +ExprResult Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, - SourceLocation LAngleBracketLoc, TypeTy *Ty, + SourceLocation LAngleBracketLoc, ParsedType Ty, SourceLocation RAngleBracketLoc, - SourceLocation LParenLoc, ExprArg E, + SourceLocation LParenLoc, Expr *E, SourceLocation RParenLoc) { TypeSourceInfo *DestTInfo; @@ -133,11 +133,10 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceRange(LParenLoc, RParenLoc)); } -Action::OwningExprResult +ExprResult Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, - TypeSourceInfo *DestTInfo, ExprArg E, + TypeSourceInfo *DestTInfo, Expr *Ex, SourceRange AngleBrackets, SourceRange Parens) { - Expr *Ex = E.takeAs(); QualType DestType = DestTInfo->getType(); SourceRange OpRange(OpLoc, Parens.getEnd()); @@ -153,39 +152,39 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, case tok::kw_const_cast: if (!TypeDependent) CheckConstCast(*this, Ex, DestType, OpRange, DestRange); - return Owned(new (Context) CXXConstCastExpr( + return Owned(CXXConstCastExpr::Create(Context, DestType.getNonLValueExprType(Context), - Ex, DestTInfo, OpLoc)); + Ex, DestTInfo, OpLoc)); case tok::kw_dynamic_cast: { - CastExpr::CastKind Kind = CastExpr::CK_Unknown; - CXXBaseSpecifierArray BasePath; + CastKind Kind = CK_Unknown; + CXXCastPath BasePath; if (!TypeDependent) CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind, BasePath); - return Owned(new (Context)CXXDynamicCastExpr( + return Owned(CXXDynamicCastExpr::Create(Context, DestType.getNonLValueExprType(Context), - Kind, Ex, BasePath, DestTInfo, - OpLoc)); + Kind, Ex, &BasePath, DestTInfo, + OpLoc)); } case tok::kw_reinterpret_cast: { - CastExpr::CastKind Kind = CastExpr::CK_Unknown; + CastKind Kind = CK_Unknown; if (!TypeDependent) CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind); - return Owned(new (Context) CXXReinterpretCastExpr( + return Owned(CXXReinterpretCastExpr::Create(Context, DestType.getNonLValueExprType(Context), - Kind, Ex, CXXBaseSpecifierArray(), + Kind, Ex, 0, DestTInfo, OpLoc)); } case tok::kw_static_cast: { - CastExpr::CastKind Kind = CastExpr::CK_Unknown; - CXXBaseSpecifierArray BasePath; + CastKind Kind = CK_Unknown; + CXXCastPath BasePath; if (!TypeDependent) CheckStaticCast(*this, Ex, DestType, OpRange, Kind, BasePath); - return Owned(new (Context) CXXStaticCastExpr( + return Owned(CXXStaticCastExpr::Create(Context, DestType.getNonLValueExprType(Context), - Kind, Ex, BasePath, - DestTInfo, OpLoc)); + Kind, Ex, &BasePath, + DestTInfo, OpLoc)); } } @@ -197,7 +196,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, /// the same kind of pointer (plain or to-member). Unlike the Sema function, /// this one doesn't care if the two pointers-to-member don't point into the /// same class. This is because CastsAwayConstness doesn't care. -bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) { +static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) { const PointerType *T1PtrType = T1->getAs(), *T2PtrType = T2->getAs(); if (T1PtrType && T2PtrType) { @@ -307,8 +306,8 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, - const SourceRange &DestRange, CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath) { + const SourceRange &DestRange, CastKind &Kind, + CXXCastPath &BasePath) { QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); DestType = Self.Context.getCanonicalType(DestType); @@ -396,6 +395,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, // C++ 5.2.7p3: If the type of v is the same as the required result type, // [except for cv]. if (DestRecord == SrcRecord) { + Kind = CK_NoOp; return; } @@ -407,7 +407,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, &BasePath)) return; - Kind = CastExpr::CK_DerivedToBase; + Kind = CK_DerivedToBase; // If we are casting to or through a virtual base class, we need a // vtable. @@ -428,7 +428,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, cast(SrcRecord->getDecl())); // Done. Everything else is run-time checks. - Kind = CastExpr::CK_Dynamic; + Kind = CK_Dynamic; } /// CheckConstCast - Check that a const_cast\(SrcExpr) is valid. @@ -457,7 +457,7 @@ CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, const SourceRange &OpRange, const SourceRange &DestRange, - CastExpr::CastKind &Kind) { + CastKind &Kind) { if (!DestType->isLValueReferenceType()) Self.DefaultFunctionArrayLvalueConversion(SrcExpr); @@ -475,13 +475,13 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, /// implicit conversions explicit and getting rid of data loss warnings. void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, - const SourceRange &OpRange, CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath) { + const SourceRange &OpRange, CastKind &Kind, + CXXCastPath &BasePath) { // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (DestType->isVoidType()) { - Kind = CastExpr::CK_ToVoid; + Kind = CK_ToVoid; return; } @@ -493,6 +493,8 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, Kind, BasePath) != TC_Success && msg != 0) Self.Diag(OpRange.getBegin(), msg) << CT_Static << SrcExpr->getType() << DestType << OpRange; + else if (Kind == CK_Unknown || Kind == CK_BitCast) + Self.CheckCastAlign(SrcExpr, DestType, OpRange); } /// TryStaticCast - Check if a static cast can be performed, and do so if @@ -501,8 +503,8 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath) { + CastKind &Kind, + CXXCastPath &BasePath) { // The order the tests is not entirely arbitrary. There is one conversion // that can be handled in two different ways. Given: // struct A {}; @@ -532,7 +534,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, msg); if (tcr != TC_NotApplicable) { - Kind = CastExpr::CK_NoOp; + Kind = CK_NoOp; return tcr; } @@ -567,7 +569,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, if (SrcType->isComplexType() || SrcType->isVectorType()) { // Fall through - these cannot be converted. } else if (SrcType->isArithmeticType() || SrcType->isEnumeralType()) { - Kind = CastExpr::CK_IntegralCast; + Kind = CK_IntegralCast; return TC_Success; } } @@ -602,19 +604,19 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, msg = diag::err_bad_cxx_cast_const_away; return TC_Failed; } - Kind = CastExpr::CK_BitCast; + Kind = CK_BitCast; return TC_Success; } } else if (DestType->isObjCObjectPointerType()) { // allow both c-style cast and static_cast of objective-c pointers as // they are pervasive. - Kind = CastExpr::CK_AnyPointerToObjCPointerCast; + Kind = CK_AnyPointerToObjCPointerCast; return TC_Success; } else if (CStyle && DestType->isBlockPointerType()) { // allow c-style cast of void * to block pointers. - Kind = CastExpr::CK_AnyPointerToBlockPointerCast; + Kind = CK_AnyPointerToBlockPointerCast; return TC_Success; } } @@ -645,9 +647,10 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, // this is the only cast possibility, so we issue an error if we fail now. // FIXME: Should allow casting away constness if CStyle. bool DerivedToBase; + bool ObjCConversion; if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(), SrcExpr->getType(), R->getPointeeType(), - DerivedToBase) < + DerivedToBase, ObjCConversion) < Sema::Ref_Compatible_With_Added_Qualification) { msg = diag::err_bad_lvalue_to_rvalue_cast; return TC_Failed; @@ -662,8 +665,8 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, TryCastResult TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg, CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath) { + unsigned &msg, CastKind &Kind, + CXXCastPath &BasePath) { // C++ 5.2.9p5: An lvalue of type "cv1 B", where B is a class type, can be // cast to type "reference to cv2 D", where D is a class derived from B, // if a valid standard conversion from "pointer to D" to "pointer to B" @@ -697,8 +700,8 @@ TryStaticReferenceDowncast(Sema &Self, Expr *SrcExpr, QualType DestType, TryCastResult TryStaticPointerDowncast(Sema &Self, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg, CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath) { + unsigned &msg, CastKind &Kind, + CXXCastPath &BasePath) { // C++ 5.2.9p8: An rvalue of type "pointer to cv1 B", where B is a class // type, can be converted to an rvalue of type "pointer to cv2 D", where D // is a class derived from B, if a valid standard conversion from "pointer @@ -732,7 +735,7 @@ TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, bool CStyle, const SourceRange &OpRange, QualType OrigSrcType, QualType OrigDestType, unsigned &msg, - CastExpr::CastKind &Kind, CXXBaseSpecifierArray &BasePath) { + CastKind &Kind, CXXCastPath &BasePath) { // We can only work with complete types. But don't complain if it doesn't work if (Self.RequireCompleteType(OpRange.getBegin(), SrcType, Self.PDiag(0)) || Self.RequireCompleteType(OpRange.getBegin(), DestType, Self.PDiag(0))) @@ -824,7 +827,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, } Self.BuildBasePathArray(Paths, BasePath); - Kind = CastExpr::CK_BaseToDerived; + Kind = CK_BaseToDerived; return TC_Success; } @@ -839,8 +842,8 @@ TryCastResult TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, - unsigned &msg, CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath) { + unsigned &msg, CastKind &Kind, + CXXCastPath &BasePath) { const MemberPointerType *DestMemPtr = DestType->getAs(); if (!DestMemPtr) return TC_NotApplicable; @@ -900,7 +903,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, } if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(), - DestType, SrcType, + DestClass, SrcClass, Paths.front(), diag::err_upcast_to_inaccessible_base)) { msg = 0; @@ -927,7 +930,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, } Self.BuildBasePathArray(Paths, BasePath); - Kind = CastExpr::CK_DerivedToBaseMemberPointer; + Kind = CK_DerivedToBaseMemberPointer; return TC_Success; } @@ -939,7 +942,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind) { + CastKind &Kind) { if (DestType->isRecordType()) { if (Self.RequireCompleteType(OpRange.getBegin(), DestType, diag::err_bad_dynamic_cast_incomplete)) { @@ -961,18 +964,17 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, (CStyle || !DestType->isReferenceType())) return TC_NotApplicable; - Sema::OwningExprResult Result - = InitSeq.Perform(Self, Entity, InitKind, - Action::MultiExprArg(Self, (void**)&SrcExpr, 1)); + ExprResult Result + = InitSeq.Perform(Self, Entity, InitKind, MultiExprArg(Self, &SrcExpr, 1)); if (Result.isInvalid()) { msg = 0; return TC_Failed; } if (InitSeq.isConstructorInitialization()) - Kind = CastExpr::CK_ConstructorConversion; + Kind = CK_ConstructorConversion; else - Kind = CastExpr::CK_NoOp; + Kind = CK_NoOp; SrcExpr = Result.takeAs(); return TC_Success; @@ -1051,7 +1053,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, - CastExpr::CastKind &Kind) { + CastKind &Kind) { bool IsLValueCast = false; DestType = Self.Context.getCanonicalType(DestType); @@ -1097,8 +1099,15 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, return TC_Failed; } + // Don't allow casting between member pointers of different sizes. + if (Self.Context.getTypeSize(DestMemPtr) != + Self.Context.getTypeSize(SrcMemPtr)) { + msg = diag::err_bad_cxx_cast_member_pointer_size; + return TC_Failed; + } + // A valid member pointer cast. - Kind = IsLValueCast? CastExpr::CK_LValueBitCast : CastExpr::CK_BitCast; + Kind = IsLValueCast? CK_LValueBitCast : CK_BitCast; return TC_Success; } @@ -1113,7 +1122,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, msg = diag::err_bad_reinterpret_cast_small_int; return TC_Failed; } - Kind = CastExpr::CK_PointerToIntegral; + Kind = CK_PointerToIntegral; return TC_Success; } @@ -1132,7 +1141,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, // If both types have the same size, we can successfully cast. if (Self.Context.getTypeSize(SrcType) == Self.Context.getTypeSize(DestType)) { - Kind = CastExpr::CK_BitCast; + Kind = CK_BitCast; return TC_Success; } @@ -1163,7 +1172,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, // to the same type. However, the behavior of compilers is pretty consistent // on this point: allow same-type conversion if the involved types are // pointers, disallow otherwise. - Kind = CastExpr::CK_NoOp; + Kind = CK_NoOp; return TC_Success; } @@ -1176,7 +1185,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, msg = diag::err_bad_reinterpret_cast_small_int; return TC_Failed; } - Kind = CastExpr::CK_PointerToIntegral; + Kind = CK_PointerToIntegral; return TC_Success; } @@ -1184,7 +1193,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, assert(destIsPtr && "One type must be a pointer"); // C++ 5.2.10p5: A value of integral or enumeration type can be explicitly // converted to a pointer. - Kind = CastExpr::CK_IntegralToPointer; + Kind = CK_IntegralToPointer; return TC_Success; } @@ -1209,13 +1218,13 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, // Any pointer can be cast to an Objective-C pointer type with a C-style // cast. if (CStyle && DestType->isObjCObjectPointerType()) { - Kind = CastExpr::CK_AnyPointerToObjCPointerCast; + Kind = CK_AnyPointerToObjCPointerCast; return TC_Success; } // Not casting away constness, so the only remaining check is for compatible // pointer categories. - Kind = IsLValueCast? CastExpr::CK_LValueBitCast : CastExpr::CK_BitCast; + Kind = IsLValueCast? CK_LValueBitCast : CK_BitCast; if (SrcType->isFunctionPointerType()) { if (DestType->isFunctionPointerType()) { @@ -1252,14 +1261,14 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr, bool Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath, + CastKind &Kind, + CXXCastPath &BasePath, bool FunctionalStyle) { // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (CastTy->isVoidType()) { - Kind = CastExpr::CK_ToVoid; + Kind = CK_ToVoid; return false; } @@ -1285,7 +1294,7 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, TryCastResult tcr = TryConstCast(*this, CastExpr, CastTy, /*CStyle*/true, msg); if (tcr == TC_Success) - Kind = CastExpr::CK_NoOp; + Kind = CK_NoOp; if (tcr == TC_NotApplicable) { // ... or if that is not possible, a static_cast, ignoring const, ... @@ -1301,6 +1310,8 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, Expr *&CastExpr, if (tcr != TC_Success && msg != 0) Diag(R.getBegin(), msg) << (FunctionalStyle ? CT_Functional : CT_CStyle) << CastExpr->getType() << CastTy << R; + else if (Kind == CK_Unknown || Kind == CK_BitCast) + CheckCastAlign(CastExpr, CastTy, R); return tcr != TC_Success; } diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index f56573a..631308e 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -11,14 +11,14 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "Lookup.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Lookup.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/Basic/PartialDiagnostic.h" -#include "clang/Parse/DeclSpec.h" +#include "clang/Sema/DeclSpec.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -283,7 +283,7 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, SourceLocation IdLoc, IdentifierInfo &II, - TypeTy *ObjectTypePtr) { + ParsedType ObjectTypePtr) { QualType ObjectType = GetTypeFromParser(ObjectTypePtr); LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName); @@ -416,7 +416,17 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, ObjectTypeSearchedInScope = true; } - } else if (isDependent) { + } else if (!isDependent) { + // Perform unqualified name lookup in the current scope. + LookupName(Found, S); + } + + // If we performed lookup into a dependent context and did not find anything, + // that's fine: just build a dependent nested-name-specifier. + if (Found.empty() && isDependent && + !(LookupCtx && LookupCtx->isRecord() && + (!cast(LookupCtx)->hasDefinition() || + !cast(LookupCtx)->hasAnyDependentBases()))) { // Don't speculate if we're just trying to improve error recovery. if (ErrorRecoveryLookup) return 0; @@ -429,11 +439,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, return NestedNameSpecifier::Create(Context, &II); return NestedNameSpecifier::Create(Context, Prefix, &II); - } else { - // Perform unqualified name lookup in the current scope. - LookupName(Found, S); - } - + } + // FIXME: Deal with ambiguities cleanly. if (Found.empty() && !ErrorRecoveryLookup) { @@ -560,10 +567,10 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, - TypeTy *ObjectTypePtr, + ParsedType ObjectTypePtr, bool EnteringContext) { return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II, - QualType::getFromOpaquePtr(ObjectTypePtr), + GetTypeFromParser(ObjectTypePtr), /*ScopeLookupResult=*/0, EnteringContext, false); } @@ -575,21 +582,20 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, /// /// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier. bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, - IdentifierInfo &II, TypeTy *ObjectType, + IdentifierInfo &II, ParsedType ObjectType, bool EnteringContext) { return BuildCXXNestedNameSpecifier(S, SS, SourceLocation(), SourceLocation(), - II, QualType::getFromOpaquePtr(ObjectType), + II, GetTypeFromParser(ObjectType), /*ScopeLookupResult=*/0, EnteringContext, true); } Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, - TypeTy *Ty, + ParsedType Ty, SourceRange TypeRange, SourceLocation CCLoc) { - NestedNameSpecifier *Prefix - = static_cast(SS.getScopeRep()); + NestedNameSpecifier *Prefix = SS.getScopeRep(); QualType T = GetTypeFromParser(Ty); return NestedNameSpecifier::Create(Context, Prefix, /*FIXME:*/false, T.getTypePtr()); @@ -620,7 +626,7 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { case NestedNameSpecifier::Namespace: // These are always namespace scopes. We never want to enter a // namespace scope from anything but a file context. - return CurContext->getLookupContext()->isFileContext(); + return CurContext->getRedeclContext()->isFileContext(); case NestedNameSpecifier::Identifier: case NestedNameSpecifier::TypeSpec: diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 7a39f05..a0b4b98 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -12,10 +12,13 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "clang/Analysis/Analyses/PrintfFormatString.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/ScopeInfo.h" +#include "clang/Analysis/Analyses/FormatString.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -26,12 +29,12 @@ #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include using namespace clang; +using namespace sema; /// getLocationOfStringLiteralByte - Return a source location that points to the /// specified byte of the specified string literal. @@ -122,9 +125,9 @@ bool Sema::CheckablePrintfAttr(const FormatAttr *Format, CallExpr *TheCall) { return false; } -Action::OwningExprResult +ExprResult Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - OwningExprResult TheCallResult(Owned(TheCall)); + ExprResult TheCallResult(Owned(TheCall)); switch (BuiltinID) { case Builtin::BI__builtin___CFStringMakeConstantString: @@ -298,6 +301,10 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { unsigned i = 0, l = 0, u = 0; switch (BuiltinID) { default: return false; + case ARM::BI__builtin_arm_ssat: i = 1; l = 1; u = 31; break; + case ARM::BI__builtin_arm_usat: i = 1; u = 31; break; + case ARM::BI__builtin_arm_vcvtr_f: + case ARM::BI__builtin_arm_vcvtr_d: i = 1; u = 1; break; #define GET_NEON_IMMEDIATE_CHECK #include "clang/Basic/arm_neon.inc" #undef GET_NEON_IMMEDIATE_CHECK @@ -311,9 +318,9 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { unsigned Val = Result.getZExtValue(); if (Val < l || Val > (u + l)) return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) - << llvm::utostr(l) << llvm::utostr(u+l) - << TheCall->getArg(i)->getSourceRange(); + << l << u+l << TheCall->getArg(i)->getSourceRange(); + // FIXME: VFP Intrinsics should error if VFP not present. return false; } @@ -334,16 +341,22 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { // Printf checking. if (const FormatAttr *Format = FDecl->getAttr()) { - if (CheckablePrintfAttr(Format, TheCall)) { + const bool b = Format->getType() == "scanf"; + if (b || CheckablePrintfAttr(Format, TheCall)) { bool HasVAListArg = Format->getFirstArg() == 0; - CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, - HasVAListArg ? 0 : Format->getFirstArg() - 1); + CheckPrintfScanfArguments(TheCall, HasVAListArg, + Format->getFormatIdx() - 1, + HasVAListArg ? 0 : Format->getFirstArg() - 1, + !b); } } - for (const NonNullAttr *NonNull = FDecl->getAttr(); NonNull; - NonNull = NonNull->getNext()) - CheckNonNullArguments(NonNull, TheCall); + specific_attr_iterator + i = FDecl->specific_attr_begin(), + e = FDecl->specific_attr_end(); + + for (; i != e; ++i) + CheckNonNullArguments(*i, TheCall); return false; } @@ -362,12 +375,13 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) { if (!Ty->isBlockPointerType()) return false; - if (!CheckablePrintfAttr(Format, TheCall)) + const bool b = Format->getType() == "scanf"; + if (!b && !CheckablePrintfAttr(Format, TheCall)) return false; bool HasVAListArg = Format->getFirstArg() == 0; - CheckPrintfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, - HasVAListArg ? 0 : Format->getFirstArg() - 1); + CheckPrintfScanfArguments(TheCall, HasVAListArg, Format->getFormatIdx() - 1, + HasVAListArg ? 0 : Format->getFirstArg() - 1, !b); return false; } @@ -380,8 +394,8 @@ bool Sema::CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall) { /// /// This function goes through and does final semantic checking for these /// builtins, -Sema::OwningExprResult -Sema::SemaBuiltinAtomicOverloaded(OwningExprResult TheCallResult) { +ExprResult +Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { CallExpr *TheCall = (CallExpr *)TheCallResult.get(); DeclRefExpr *DRE =cast(TheCall->getCallee()->IgnoreParenCasts()); FunctionDecl *FDecl = cast(DRE->getDecl()); @@ -415,6 +429,10 @@ Sema::SemaBuiltinAtomicOverloaded(OwningExprResult TheCallResult) { return ExprError(); } + // The majority of builtins return a value, but a few have special return + // types, so allow them to override appropriately below. + QualType ResultType = ValType; + // We need to figure out which concrete builtin this maps onto. For example, // __sync_fetch_and_add with a 2 byte object turns into // __sync_fetch_and_add_2. @@ -483,11 +501,13 @@ Sema::SemaBuiltinAtomicOverloaded(OwningExprResult TheCallResult) { case Builtin::BI__sync_bool_compare_and_swap: BuiltinIndex = 11; NumFixed = 2; + ResultType = Context.BoolTy; break; case Builtin::BI__sync_lock_test_and_set: BuiltinIndex = 12; break; case Builtin::BI__sync_lock_release: BuiltinIndex = 13; NumFixed = 0; + ResultType = Context.VoidTy; break; } @@ -508,19 +528,10 @@ Sema::SemaBuiltinAtomicOverloaded(OwningExprResult TheCallResult) { FunctionDecl *NewBuiltinDecl = cast(LazilyCreateBuiltin(NewBuiltinII, NewBuiltinID, TUScope, false, DRE->getLocStart())); - const FunctionProtoType *BuiltinFT = - NewBuiltinDecl->getType()->getAs(); - - QualType OrigValType = ValType; - ValType = BuiltinFT->getArgType(0)->getAs()->getPointeeType(); - - // If the first type needs to be converted (e.g. void** -> int*), do it now. - if (BuiltinFT->getArgType(0) != FirstArg->getType()) { - ImpCastExprToType(FirstArg, BuiltinFT->getArgType(0), CastExpr::CK_BitCast); - TheCall->setArg(0, FirstArg); - } - // Next, walk the valid ones promoting to the right type. + // The first argument --- the pointer --- has a fixed type; we + // deduce the types of the rest of the arguments accordingly. Walk + // the remaining arguments, converting them to the deduced value type. for (unsigned i = 0; i != NumFixed; ++i) { Expr *Arg = TheCall->getArg(i+1); @@ -529,14 +540,13 @@ Sema::SemaBuiltinAtomicOverloaded(OwningExprResult TheCallResult) { if (ImplicitCastExpr *ICE = dyn_cast(Arg)) { Arg = ICE->getSubExpr(); ICE->setSubExpr(0); - ICE->Destroy(Context); TheCall->setArg(i+1, Arg); } // GCC does an implicit conversion to the pointer or integer ValType. This // can fail in some cases (1i -> int**), check for this error case now. - CastExpr::CastKind Kind = CastExpr::CK_Unknown; - CXXBaseSpecifierArray BasePath; + CastKind Kind = CK_Unknown; + CXXCastPath BasePath; if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind, BasePath)) return ExprError(); @@ -546,7 +556,7 @@ Sema::SemaBuiltinAtomicOverloaded(OwningExprResult TheCallResult) { // pass in 42. The 42 gets converted to char. This is even more strange // for things like 45.123 -> char, etc. // FIXME: Do this check. - ImpCastExprToType(Arg, ValType, Kind); + ImpCastExprToType(Arg, ValType, Kind, VK_RValue, &BasePath); TheCall->setArg(i+1, Arg); } @@ -560,28 +570,10 @@ Sema::SemaBuiltinAtomicOverloaded(OwningExprResult TheCallResult) { UsualUnaryConversions(PromotedCall); TheCall->setCallee(PromotedCall); - // Change the result type of the call to match the result type of the decl. - TheCall->setType(NewBuiltinDecl->getCallResultType()); - - // If the value type was converted to an integer when processing the - // arguments (e.g. void* -> int), we need to convert the result back. - if (!Context.hasSameUnqualifiedType(ValType, OrigValType)) { - Expr *E = TheCallResult.takeAs(); - - assert(ValType->isIntegerType() && - "We always convert atomic operation values to integers."); - // FIXME: Handle floating point value type here too. - CastExpr::CastKind Kind; - if (OrigValType->isIntegerType()) - Kind = CastExpr::CK_IntegralCast; - else if (OrigValType->hasPointerRepresentation()) - Kind = CastExpr::CK_IntegralToPointer; - else - llvm_unreachable("Unhandled original value type!"); - - ImpCastExprToType(E, OrigValType, Kind); - return Owned(E); - } + // Change the result type of the call to match the original value type. This + // is arbitrary, but the codegen for these builtins ins design to handle it + // gracefully. + TheCall->setType(ResultType); return move(TheCallResult); } @@ -604,16 +596,11 @@ bool Sema::CheckObjCString(Expr *Arg) { return true; } - const char *Data = Literal->getStrData(); - unsigned Length = Literal->getByteLength(); - - for (unsigned i = 0; i < Length; ++i) { - if (!Data[i]) { - Diag(getLocationOfStringLiteralByte(Literal, i), - diag::warn_cfstring_literal_contains_nul_character) - << Arg->getSourceRange(); - break; - } + size_t NulPos = Literal->getString().find('\0'); + if (NulPos != llvm::StringRef::npos) { + Diag(getLocationOfStringLiteralByte(Literal, NulPos), + diag::warn_cfstring_literal_contains_nul_character) + << Arg->getSourceRange(); } return false; @@ -753,7 +740,6 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { assert(Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) && "promotion from float to double is the only expected cast here"); Cast->setSubExpr(0); - Cast->Destroy(Context); TheCall->setArg(NumArgs-1, CastArg); OrigArg = CastArg; } @@ -764,7 +750,7 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { /// SemaBuiltinShuffleVector - Handle __builtin_shufflevector. // This is declared to take (...), so we have to check everything. -Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { +ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { if (TheCall->getNumArgs() < 2) return ExprError(Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args_at_least) @@ -797,7 +783,7 @@ Action::OwningExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { // with mask. If so, verify that RHS is an integer vector type with the // same number of elts as lhs. if (TheCall->getNumArgs() == 2) { - if (!RHSType->isIntegerType() || + if (!RHSType->hasIntegerRepresentation() || RHSType->getAs()->getNumElements() != numElements) Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector) << SourceRange(TheCall->getArg(1)->getLocStart(), @@ -941,29 +927,31 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { // Handle i > 1 ? "x" : "y", recursivelly bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, bool HasVAListArg, - unsigned format_idx, unsigned firstDataArg) { + unsigned format_idx, unsigned firstDataArg, + bool isPrintf) { + if (E->isTypeDependent() || E->isValueDependent()) return false; switch (E->getStmtClass()) { case Stmt::ConditionalOperatorClass: { const ConditionalOperator *C = cast(E); - return SemaCheckStringLiteral(C->getTrueExpr(), TheCall, - HasVAListArg, format_idx, firstDataArg) - && SemaCheckStringLiteral(C->getRHS(), TheCall, - HasVAListArg, format_idx, firstDataArg); + return SemaCheckStringLiteral(C->getTrueExpr(), TheCall, HasVAListArg, + format_idx, firstDataArg, isPrintf) + && SemaCheckStringLiteral(C->getRHS(), TheCall, HasVAListArg, + format_idx, firstDataArg, isPrintf); } case Stmt::ImplicitCastExprClass: { const ImplicitCastExpr *Expr = cast(E); return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg, - format_idx, firstDataArg); + format_idx, firstDataArg, isPrintf); } case Stmt::ParenExprClass: { const ParenExpr *Expr = cast(E); return SemaCheckStringLiteral(Expr->getSubExpr(), TheCall, HasVAListArg, - format_idx, firstDataArg); + format_idx, firstDataArg, isPrintf); } case Stmt::DeclRefExprClass: { @@ -985,7 +973,8 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, if (isConstant) { if (const Expr *Init = VD->getAnyInitializer()) return SemaCheckStringLiteral(Init, TheCall, - HasVAListArg, format_idx, firstDataArg); + HasVAListArg, format_idx, firstDataArg, + isPrintf); } // For vprintf* functions (i.e., HasVAListArg==true), we add a @@ -1025,7 +1014,7 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, const Expr *Arg = CE->getArg(ArgIndex - 1); return SemaCheckStringLiteral(Arg, TheCall, HasVAListArg, - format_idx, firstDataArg); + format_idx, firstDataArg, isPrintf); } } } @@ -1043,8 +1032,8 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, StrE = cast(E); if (StrE) { - CheckPrintfString(StrE, E, TheCall, HasVAListArg, format_idx, - firstDataArg); + CheckFormatString(StrE, E, TheCall, HasVAListArg, format_idx, + firstDataArg, isPrintf); return true; } @@ -1059,7 +1048,8 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, void Sema::CheckNonNullArguments(const NonNullAttr *NonNull, const CallExpr *TheCall) { - for (NonNullAttr::iterator i = NonNull->begin(), e = NonNull->end(); + for (NonNullAttr::args_iterator i = NonNull->args_begin(), + e = NonNull->args_end(); i != e; ++i) { const Expr *ArgExpr = TheCall->getArg(*i); if (ArgExpr->isNullPointerConstant(Context, @@ -1069,55 +1059,13 @@ Sema::CheckNonNullArguments(const NonNullAttr *NonNull, } } -/// CheckPrintfArguments - Check calls to printf (and similar functions) for -/// correct use of format strings. -/// -/// HasVAListArg - A predicate indicating whether the printf-like -/// function is passed an explicit va_arg argument (e.g., vprintf) -/// -/// format_idx - The index into Args for the format string. -/// -/// Improper format strings to functions in the printf family can be -/// the source of bizarre bugs and very serious security holes. A -/// good source of information is available in the following paper -/// (which includes additional references): -/// -/// FormatGuard: Automatic Protection From printf Format String -/// Vulnerabilities, Proceedings of the 10th USENIX Security Symposium, 2001. -/// -/// TODO: -/// Functionality implemented: -/// -/// We can statically check the following properties for string -/// literal format strings for non v.*printf functions (where the -/// arguments are passed directly): -// -/// (1) Are the number of format conversions equal to the number of -/// data arguments? -/// -/// (2) Does each format conversion correctly match the type of the -/// corresponding data argument? -/// -/// Moreover, for all printf functions we can: -/// -/// (3) Check for a missing format string (when not caught by type checking). -/// -/// (4) Check for no-operation flags; e.g. using "#" with format -/// conversion 'c' (TODO) -/// -/// (5) Check the use of '%n', a major source of security holes. -/// -/// (6) Check for malformed format conversions that don't specify anything. -/// -/// (7) Check for empty format strings. e.g: printf(""); -/// -/// (8) Check that the format string is a wide literal. -/// -/// All of these checks can be done by parsing the format string. -/// +/// CheckPrintfScanfArguments - Check calls to printf and scanf (and similar +/// functions) for correct use of format strings. void -Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, - unsigned format_idx, unsigned firstDataArg) { +Sema::CheckPrintfScanfArguments(const CallExpr *TheCall, bool HasVAListArg, + unsigned format_idx, unsigned firstDataArg, + bool isPrintf) { + const Expr *Fn = TheCall->getCallee(); // The way the format attribute works in GCC, the implicit this argument @@ -1132,9 +1080,9 @@ Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, --firstDataArg; } - // CHECK: printf-like function is called with no format string. + // CHECK: printf/scanf-like function is called with no format string. if (format_idx >= TheCall->getNumArgs()) { - Diag(TheCall->getRParenLoc(), diag::warn_printf_missing_format_string) + Diag(TheCall->getRParenLoc(), diag::warn_missing_format_string) << Fn->getSourceRange(); return; } @@ -1154,23 +1102,24 @@ Sema::CheckPrintfArguments(const CallExpr *TheCall, bool HasVAListArg, // ObjC string uses the same format specifiers as C string, so we can use // the same format string checking logic for both ObjC and C strings. if (SemaCheckStringLiteral(OrigFormatExpr, TheCall, HasVAListArg, format_idx, - firstDataArg)) + firstDataArg, isPrintf)) return; // Literal format string found, check done! // If there are no arguments specified, warn with -Wformat-security, otherwise // warn only with -Wformat-nonliteral. if (TheCall->getNumArgs() == format_idx+1) Diag(TheCall->getArg(format_idx)->getLocStart(), - diag::warn_printf_nonliteral_noargs) + diag::warn_format_nonliteral_noargs) << OrigFormatExpr->getSourceRange(); else Diag(TheCall->getArg(format_idx)->getLocStart(), - diag::warn_printf_nonliteral) + diag::warn_format_nonliteral) << OrigFormatExpr->getSourceRange(); } namespace { -class CheckPrintfHandler : public analyze_printf::FormatStringHandler { +class CheckFormatHandler : public analyze_format_string::FormatStringHandler { +protected: Sema &S; const StringLiteral *FExpr; const Expr *OrigFormatExpr; @@ -1185,7 +1134,7 @@ class CheckPrintfHandler : public analyze_printf::FormatStringHandler { bool usesPositionalArgs; bool atFirstArg; public: - CheckPrintfHandler(Sema &s, const StringLiteral *fexpr, + CheckFormatHandler(Sema &s, const StringLiteral *fexpr, const Expr *origFormatExpr, unsigned firstDataArg, unsigned numDataArgs, bool isObjCLiteral, const char *beg, bool hasVAListArg, @@ -1203,55 +1152,43 @@ public: void DoneProcessing(); - void HandleIncompleteFormatSpecifier(const char *startSpecifier, - unsigned specifierLen); - - bool - HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS, - const char *startSpecifier, - unsigned specifierLen); - + void HandleIncompleteSpecifier(const char *startSpecifier, + unsigned specifierLen); + virtual void HandleInvalidPosition(const char *startSpecifier, unsigned specifierLen, - analyze_printf::PositionContext p); + analyze_format_string::PositionContext p); virtual void HandleZeroPosition(const char *startPos, unsigned posLen); void HandleNullChar(const char *nullCharacter); - bool HandleFormatSpecifier(const analyze_printf::FormatSpecifier &FS, - const char *startSpecifier, - unsigned specifierLen); -private: +protected: + bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, + const char *startSpec, + unsigned specifierLen, + const char *csStart, unsigned csLen); + SourceRange getFormatStringRange(); - CharSourceRange getFormatSpecifierRange(const char *startSpecifier, - unsigned specifierLen); + CharSourceRange getSpecifierRange(const char *startSpecifier, + unsigned specifierLen); SourceLocation getLocationOfByte(const char *x); - bool HandleAmount(const analyze_printf::OptionalAmount &Amt, unsigned k, - const char *startSpecifier, unsigned specifierLen); - void HandleInvalidAmount(const analyze_printf::FormatSpecifier &FS, - const analyze_printf::OptionalAmount &Amt, - unsigned type, - const char *startSpecifier, unsigned specifierLen); - void HandleFlag(const analyze_printf::FormatSpecifier &FS, - const analyze_printf::OptionalFlag &flag, - const char *startSpecifier, unsigned specifierLen); - void HandleIgnoredFlag(const analyze_printf::FormatSpecifier &FS, - const analyze_printf::OptionalFlag &ignoredFlag, - const analyze_printf::OptionalFlag &flag, - const char *startSpecifier, unsigned specifierLen); - const Expr *getDataArg(unsigned i) const; + + bool CheckNumArgs(const analyze_format_string::FormatSpecifier &FS, + const analyze_format_string::ConversionSpecifier &CS, + const char *startSpecifier, unsigned specifierLen, + unsigned argIndex); }; } -SourceRange CheckPrintfHandler::getFormatStringRange() { +SourceRange CheckFormatHandler::getFormatStringRange() { return OrigFormatExpr->getSourceRange(); } -CharSourceRange CheckPrintfHandler:: -getFormatSpecifierRange(const char *startSpecifier, unsigned specifierLen) { +CharSourceRange CheckFormatHandler:: +getSpecifierRange(const char *startSpecifier, unsigned specifierLen) { SourceLocation Start = getLocationOfByte(startSpecifier); SourceLocation End = getLocationOfByte(startSpecifier + specifierLen - 1); @@ -1261,39 +1198,67 @@ getFormatSpecifierRange(const char *startSpecifier, unsigned specifierLen) { return CharSourceRange::getCharRange(Start, End); } -SourceLocation CheckPrintfHandler::getLocationOfByte(const char *x) { +SourceLocation CheckFormatHandler::getLocationOfByte(const char *x) { return S.getLocationOfStringLiteralByte(FExpr, x - Beg); } -void CheckPrintfHandler:: -HandleIncompleteFormatSpecifier(const char *startSpecifier, - unsigned specifierLen) { +void CheckFormatHandler::HandleIncompleteSpecifier(const char *startSpecifier, + unsigned specifierLen){ SourceLocation Loc = getLocationOfByte(startSpecifier); S.Diag(Loc, diag::warn_printf_incomplete_specifier) - << getFormatSpecifierRange(startSpecifier, specifierLen); + << getSpecifierRange(startSpecifier, specifierLen); } void -CheckPrintfHandler::HandleInvalidPosition(const char *startPos, unsigned posLen, - analyze_printf::PositionContext p) { +CheckFormatHandler::HandleInvalidPosition(const char *startPos, unsigned posLen, + analyze_format_string::PositionContext p) { SourceLocation Loc = getLocationOfByte(startPos); - S.Diag(Loc, diag::warn_printf_invalid_positional_specifier) - << (unsigned) p << getFormatSpecifierRange(startPos, posLen); + S.Diag(Loc, diag::warn_format_invalid_positional_specifier) + << (unsigned) p << getSpecifierRange(startPos, posLen); } -void CheckPrintfHandler::HandleZeroPosition(const char *startPos, +void CheckFormatHandler::HandleZeroPosition(const char *startPos, unsigned posLen) { SourceLocation Loc = getLocationOfByte(startPos); - S.Diag(Loc, diag::warn_printf_zero_positional_specifier) - << getFormatSpecifierRange(startPos, posLen); + S.Diag(Loc, diag::warn_format_zero_positional_specifier) + << getSpecifierRange(startPos, posLen); +} + +void CheckFormatHandler::HandleNullChar(const char *nullCharacter) { + // The presence of a null character is likely an error. + S.Diag(getLocationOfByte(nullCharacter), + diag::warn_printf_format_string_contains_null_char) + << getFormatStringRange(); } -bool CheckPrintfHandler:: -HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS, - const char *startSpecifier, - unsigned specifierLen) { +const Expr *CheckFormatHandler::getDataArg(unsigned i) const { + return TheCall->getArg(FirstDataArg + i); +} - unsigned argIndex = FS.getArgIndex(); +void CheckFormatHandler::DoneProcessing() { + // Does the number of data arguments exceed the number of + // format conversions in the format string? + if (!HasVAListArg) { + // Find any arguments that weren't covered. + CoveredArgs.flip(); + signed notCoveredArg = CoveredArgs.find_first(); + if (notCoveredArg >= 0) { + assert((unsigned)notCoveredArg < NumDataArgs); + S.Diag(getDataArg((unsigned) notCoveredArg)->getLocStart(), + diag::warn_printf_data_arg_not_used) + << getFormatStringRange(); + } + } +} + +bool +CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, + SourceLocation Loc, + const char *startSpec, + unsigned specifierLen, + const char *csStart, + unsigned csLen) { + bool keepGoing = true; if (argIndex < NumDataArgs) { // Consider the argument coverered, even though the specifier doesn't @@ -1308,32 +1273,95 @@ HandleInvalidConversionSpecifier(const analyze_printf::FormatSpecifier &FS, // gibberish when trying to match arguments. keepGoing = false; } + + S.Diag(Loc, diag::warn_format_invalid_conversion) + << llvm::StringRef(csStart, csLen) + << getSpecifierRange(startSpec, specifierLen); + + return keepGoing; +} - const analyze_printf::ConversionSpecifier &CS = - FS.getConversionSpecifier(); - SourceLocation Loc = getLocationOfByte(CS.getStart()); - S.Diag(Loc, diag::warn_printf_invalid_conversion) - << llvm::StringRef(CS.getStart(), CS.getLength()) - << getFormatSpecifierRange(startSpecifier, specifierLen); +bool +CheckFormatHandler::CheckNumArgs( + const analyze_format_string::FormatSpecifier &FS, + const analyze_format_string::ConversionSpecifier &CS, + const char *startSpecifier, unsigned specifierLen, unsigned argIndex) { - return keepGoing; + if (argIndex >= NumDataArgs) { + if (FS.usesPositionalArg()) { + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_printf_positional_arg_exceeds_data_args) + << (argIndex+1) << NumDataArgs + << getSpecifierRange(startSpecifier, specifierLen); + } + else { + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_printf_insufficient_data_args) + << getSpecifierRange(startSpecifier, specifierLen); + } + + return false; + } + return true; } -void CheckPrintfHandler::HandleNullChar(const char *nullCharacter) { - // The presence of a null character is likely an error. - S.Diag(getLocationOfByte(nullCharacter), - diag::warn_printf_format_string_contains_null_char) - << getFormatStringRange(); +//===--- CHECK: Printf format string checking ------------------------------===// + +namespace { +class CheckPrintfHandler : public CheckFormatHandler { +public: + CheckPrintfHandler(Sema &s, const StringLiteral *fexpr, + const Expr *origFormatExpr, unsigned firstDataArg, + unsigned numDataArgs, bool isObjCLiteral, + const char *beg, bool hasVAListArg, + const CallExpr *theCall, unsigned formatIdx) + : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, + numDataArgs, isObjCLiteral, beg, hasVAListArg, + theCall, formatIdx) {} + + + bool HandleInvalidPrintfConversionSpecifier( + const analyze_printf::PrintfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen); + + bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen); + + bool HandleAmount(const analyze_format_string::OptionalAmount &Amt, unsigned k, + const char *startSpecifier, unsigned specifierLen); + void HandleInvalidAmount(const analyze_printf::PrintfSpecifier &FS, + const analyze_printf::OptionalAmount &Amt, + unsigned type, + const char *startSpecifier, unsigned specifierLen); + void HandleFlag(const analyze_printf::PrintfSpecifier &FS, + const analyze_printf::OptionalFlag &flag, + const char *startSpecifier, unsigned specifierLen); + void HandleIgnoredFlag(const analyze_printf::PrintfSpecifier &FS, + const analyze_printf::OptionalFlag &ignoredFlag, + const analyze_printf::OptionalFlag &flag, + const char *startSpecifier, unsigned specifierLen); +}; } -const Expr *CheckPrintfHandler::getDataArg(unsigned i) const { - return TheCall->getArg(FirstDataArg + i); +bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier( + const analyze_printf::PrintfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + const analyze_printf::PrintfConversionSpecifier &CS = + FS.getConversionSpecifier(); + + return HandleInvalidConversionSpecifier(FS.getArgIndex(), + getLocationOfByte(CS.getStart()), + startSpecifier, specifierLen, + CS.getStart(), CS.getLength()); } -bool -CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt, - unsigned k, const char *startSpecifier, - unsigned specifierLen) { +bool CheckPrintfHandler::HandleAmount( + const analyze_format_string::OptionalAmount &Amt, + unsigned k, const char *startSpecifier, + unsigned specifierLen) { if (Amt.hasDataArgument()) { if (!HasVAListArg) { @@ -1341,7 +1369,7 @@ CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt, if (argIndex >= NumDataArgs) { S.Diag(getLocationOfByte(Amt.getStart()), diag::warn_printf_asterisk_missing_arg) - << k << getFormatSpecifierRange(startSpecifier, specifierLen); + << k << getSpecifierRange(startSpecifier, specifierLen); // Don't do any more checking. We will just emit // spurious errors. return false; @@ -1363,7 +1391,7 @@ CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt, diag::warn_printf_asterisk_wrong_type) << k << ATR.getRepresentativeType(S.Context) << T - << getFormatSpecifierRange(startSpecifier, specifierLen) + << getSpecifierRange(startSpecifier, specifierLen) << Arg->getSourceRange(); // Don't do any more checking. We will just emit // spurious errors. @@ -1375,20 +1403,21 @@ CheckPrintfHandler::HandleAmount(const analyze_printf::OptionalAmount &Amt, } void CheckPrintfHandler::HandleInvalidAmount( - const analyze_printf::FormatSpecifier &FS, + const analyze_printf::PrintfSpecifier &FS, const analyze_printf::OptionalAmount &Amt, unsigned type, const char *startSpecifier, unsigned specifierLen) { - const analyze_printf::ConversionSpecifier &CS = FS.getConversionSpecifier(); + const analyze_printf::PrintfConversionSpecifier &CS = + FS.getConversionSpecifier(); switch (Amt.getHowSpecified()) { case analyze_printf::OptionalAmount::Constant: S.Diag(getLocationOfByte(Amt.getStart()), diag::warn_printf_nonsensical_optional_amount) << type << CS.toString() - << getFormatSpecifierRange(startSpecifier, specifierLen) - << FixItHint::CreateRemoval(getFormatSpecifierRange(Amt.getStart(), + << getSpecifierRange(startSpecifier, specifierLen) + << FixItHint::CreateRemoval(getSpecifierRange(Amt.getStart(), Amt.getConstantLength())); break; @@ -1397,26 +1426,27 @@ void CheckPrintfHandler::HandleInvalidAmount( diag::warn_printf_nonsensical_optional_amount) << type << CS.toString() - << getFormatSpecifierRange(startSpecifier, specifierLen); + << getSpecifierRange(startSpecifier, specifierLen); break; } } -void CheckPrintfHandler::HandleFlag(const analyze_printf::FormatSpecifier &FS, +void CheckPrintfHandler::HandleFlag(const analyze_printf::PrintfSpecifier &FS, const analyze_printf::OptionalFlag &flag, const char *startSpecifier, unsigned specifierLen) { // Warn about pointless flag with a fixit removal. - const analyze_printf::ConversionSpecifier &CS = FS.getConversionSpecifier(); + const analyze_printf::PrintfConversionSpecifier &CS = + FS.getConversionSpecifier(); S.Diag(getLocationOfByte(flag.getPosition()), diag::warn_printf_nonsensical_flag) << flag.toString() << CS.toString() - << getFormatSpecifierRange(startSpecifier, specifierLen) - << FixItHint::CreateRemoval(getFormatSpecifierRange(flag.getPosition(), 1)); + << getSpecifierRange(startSpecifier, specifierLen) + << FixItHint::CreateRemoval(getSpecifierRange(flag.getPosition(), 1)); } void CheckPrintfHandler::HandleIgnoredFlag( - const analyze_printf::FormatSpecifier &FS, + const analyze_printf::PrintfSpecifier &FS, const analyze_printf::OptionalFlag &ignoredFlag, const analyze_printf::OptionalFlag &flag, const char *startSpecifier, @@ -1425,30 +1455,33 @@ void CheckPrintfHandler::HandleIgnoredFlag( S.Diag(getLocationOfByte(ignoredFlag.getPosition()), diag::warn_printf_ignored_flag) << ignoredFlag.toString() << flag.toString() - << getFormatSpecifierRange(startSpecifier, specifierLen) - << FixItHint::CreateRemoval(getFormatSpecifierRange( + << getSpecifierRange(startSpecifier, specifierLen) + << FixItHint::CreateRemoval(getSpecifierRange( ignoredFlag.getPosition(), 1)); } bool -CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier +CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { + using namespace analyze_format_string; using namespace analyze_printf; - const ConversionSpecifier &CS = FS.getConversionSpecifier(); + const PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); - if (atFirstArg) { - atFirstArg = false; - usesPositionalArgs = FS.usesPositionalArg(); - } - else if (usesPositionalArgs != FS.usesPositionalArg()) { - // Cannot mix-and-match positional and non-positional arguments. - S.Diag(getLocationOfByte(CS.getStart()), - diag::warn_printf_mix_positional_nonpositional_args) - << getFormatSpecifierRange(startSpecifier, specifierLen); - return false; + if (FS.consumesDataArgument()) { + if (atFirstArg) { + atFirstArg = false; + usesPositionalArgs = FS.usesPositionalArg(); + } + else if (usesPositionalArgs != FS.usesPositionalArg()) { + // Cannot mix-and-match positional and non-positional arguments. + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_format_mix_positional_nonpositional_args) + << getSpecifierRange(startSpecifier, specifierLen); + return false; + } } // First check if the field width, precision, and conversion specifier @@ -1481,7 +1514,8 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier // Check for using an Objective-C specific conversion specifier // in a non-ObjC literal. if (!IsObjCLiteral && CS.isObjCArg()) { - return HandleInvalidConversionSpecifier(FS, startSpecifier, specifierLen); + return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, + specifierLen); } // Check for invalid use of field width @@ -1520,17 +1554,17 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier const LengthModifier &LM = FS.getLengthModifier(); if (!FS.hasValidLengthModifier()) S.Diag(getLocationOfByte(LM.getStart()), - diag::warn_printf_nonsensical_length) + diag::warn_format_nonsensical_length) << LM.toString() << CS.toString() - << getFormatSpecifierRange(startSpecifier, specifierLen) - << FixItHint::CreateRemoval(getFormatSpecifierRange(LM.getStart(), + << getSpecifierRange(startSpecifier, specifierLen) + << FixItHint::CreateRemoval(getSpecifierRange(LM.getStart(), LM.getLength())); // Are we using '%n'? - if (CS.getKind() == ConversionSpecifier::OutIntPtrArg) { + if (CS.getKind() == ConversionSpecifier::nArg) { // Issue a warning about this being a possible security issue. S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_write_back) - << getFormatSpecifierRange(startSpecifier, specifierLen); + << getSpecifierRange(startSpecifier, specifierLen); // Continue checking the other format specifiers. return true; } @@ -1539,22 +1573,8 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier if (HasVAListArg) return true; - if (argIndex >= NumDataArgs) { - if (FS.usesPositionalArg()) { - S.Diag(getLocationOfByte(CS.getStart()), - diag::warn_printf_positional_arg_exceeds_data_args) - << (argIndex+1) << NumDataArgs - << getFormatSpecifierRange(startSpecifier, specifierLen); - } - else { - S.Diag(getLocationOfByte(CS.getStart()), - diag::warn_printf_insufficient_data_args) - << getFormatSpecifierRange(startSpecifier, specifierLen); - } - - // Don't do any more checking. + if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex)) return false; - } // Now type check the data expression that matches the // format specifier. @@ -1570,7 +1590,7 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier return true; // We may be able to offer a FixItHint if it is a supported type. - FormatSpecifier fixedFS = FS; + PrintfSpecifier fixedFS = FS; bool success = fixedFS.fixType(Ex->getType()); if (success) { @@ -1579,20 +1599,23 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier llvm::raw_svector_ostream os(buf); fixedFS.toString(os); + // FIXME: getRepresentativeType() perhaps should return a string + // instead of a QualType to better handle when the representative + // type is 'wint_t' (which is defined in the system headers). S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_conversion_argument_type_mismatch) << ATR.getRepresentativeType(S.Context) << Ex->getType() - << getFormatSpecifierRange(startSpecifier, specifierLen) + << getSpecifierRange(startSpecifier, specifierLen) << Ex->getSourceRange() << FixItHint::CreateReplacement( - getFormatSpecifierRange(startSpecifier, specifierLen), + getSpecifierRange(startSpecifier, specifierLen), os.str()); } else { S.Diag(getLocationOfByte(CS.getStart()), diag::warn_printf_conversion_argument_type_mismatch) << ATR.getRepresentativeType(S.Context) << Ex->getType() - << getFormatSpecifierRange(startSpecifier, specifierLen) + << getSpecifierRange(startSpecifier, specifierLen) << Ex->getSourceRange(); } } @@ -1600,54 +1623,173 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier return true; } -void CheckPrintfHandler::DoneProcessing() { - // Does the number of data arguments exceed the number of - // format conversions in the format string? - if (!HasVAListArg) { - // Find any arguments that weren't covered. - CoveredArgs.flip(); - signed notCoveredArg = CoveredArgs.find_first(); - if (notCoveredArg >= 0) { - assert((unsigned)notCoveredArg < NumDataArgs); - S.Diag(getDataArg((unsigned) notCoveredArg)->getLocStart(), - diag::warn_printf_data_arg_not_used) - << getFormatStringRange(); +//===--- CHECK: Scanf format string checking ------------------------------===// + +namespace { +class CheckScanfHandler : public CheckFormatHandler { +public: + CheckScanfHandler(Sema &s, const StringLiteral *fexpr, + const Expr *origFormatExpr, unsigned firstDataArg, + unsigned numDataArgs, bool isObjCLiteral, + const char *beg, bool hasVAListArg, + const CallExpr *theCall, unsigned formatIdx) + : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, + numDataArgs, isObjCLiteral, beg, hasVAListArg, + theCall, formatIdx) {} + + bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen); + + bool HandleInvalidScanfConversionSpecifier( + const analyze_scanf::ScanfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen); + + void HandleIncompleteScanList(const char *start, const char *end); +}; +} + +void CheckScanfHandler::HandleIncompleteScanList(const char *start, + const char *end) { + S.Diag(getLocationOfByte(end), diag::warn_scanf_scanlist_incomplete) + << getSpecifierRange(start, end - start); +} + +bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier( + const analyze_scanf::ScanfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + + const analyze_scanf::ScanfConversionSpecifier &CS = + FS.getConversionSpecifier(); + + return HandleInvalidConversionSpecifier(FS.getArgIndex(), + getLocationOfByte(CS.getStart()), + startSpecifier, specifierLen, + CS.getStart(), CS.getLength()); +} + +bool CheckScanfHandler::HandleScanfSpecifier( + const analyze_scanf::ScanfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + + using namespace analyze_scanf; + using namespace analyze_format_string; + + const ScanfConversionSpecifier &CS = FS.getConversionSpecifier(); + + // Handle case where '%' and '*' don't consume an argument. These shouldn't + // be used to decide if we are using positional arguments consistently. + if (FS.consumesDataArgument()) { + if (atFirstArg) { + atFirstArg = false; + usesPositionalArgs = FS.usesPositionalArg(); + } + else if (usesPositionalArgs != FS.usesPositionalArg()) { + // Cannot mix-and-match positional and non-positional arguments. + S.Diag(getLocationOfByte(CS.getStart()), + diag::warn_format_mix_positional_nonpositional_args) + << getSpecifierRange(startSpecifier, specifierLen); + return false; + } + } + + // Check if the field with is non-zero. + const OptionalAmount &Amt = FS.getFieldWidth(); + if (Amt.getHowSpecified() == OptionalAmount::Constant) { + if (Amt.getConstantAmount() == 0) { + const CharSourceRange &R = getSpecifierRange(Amt.getStart(), + Amt.getConstantLength()); + S.Diag(getLocationOfByte(Amt.getStart()), + diag::warn_scanf_nonzero_width) + << R << FixItHint::CreateRemoval(R); } } + + if (!FS.consumesDataArgument()) { + // FIXME: Technically specifying a precision or field width here + // makes no sense. Worth issuing a warning at some point. + return true; + } + + // Consume the argument. + unsigned argIndex = FS.getArgIndex(); + if (argIndex < NumDataArgs) { + // The check to see if the argIndex is valid will come later. + // We set the bit here because we may exit early from this + // function if we encounter some other error. + CoveredArgs.set(argIndex); + } + + // Check the length modifier is valid with the given conversion specifier. + const LengthModifier &LM = FS.getLengthModifier(); + if (!FS.hasValidLengthModifier()) { + S.Diag(getLocationOfByte(LM.getStart()), + diag::warn_format_nonsensical_length) + << LM.toString() << CS.toString() + << getSpecifierRange(startSpecifier, specifierLen) + << FixItHint::CreateRemoval(getSpecifierRange(LM.getStart(), + LM.getLength())); + } + + // The remaining checks depend on the data arguments. + if (HasVAListArg) + return true; + + if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex)) + return false; + + // FIXME: Check that the argument type matches the format specifier. + + return true; } -void Sema::CheckPrintfString(const StringLiteral *FExpr, +void Sema::CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr, const CallExpr *TheCall, bool HasVAListArg, - unsigned format_idx, unsigned firstDataArg) { - + unsigned format_idx, unsigned firstDataArg, + bool isPrintf) { + // CHECK: is the format string a wide literal? if (FExpr->isWide()) { Diag(FExpr->getLocStart(), - diag::warn_printf_format_string_is_wide_literal) + diag::warn_format_string_is_wide_literal) << OrigFormatExpr->getSourceRange(); return; } - + // Str - The format string. NOTE: this is NOT null-terminated! - const char *Str = FExpr->getStrData(); - + llvm::StringRef StrRef = FExpr->getString(); + const char *Str = StrRef.data(); + unsigned StrLen = StrRef.size(); + // CHECK: empty format string? - unsigned StrLen = FExpr->getByteLength(); - if (StrLen == 0) { - Diag(FExpr->getLocStart(), diag::warn_printf_empty_format_string) + Diag(FExpr->getLocStart(), diag::warn_empty_format_string) << OrigFormatExpr->getSourceRange(); return; } - - CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, - TheCall->getNumArgs() - firstDataArg, - isa(OrigFormatExpr), Str, - HasVAListArg, TheCall, format_idx); - - if (!analyze_printf::ParseFormatString(H, Str, Str + StrLen)) - H.DoneProcessing(); + + if (isPrintf) { + CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, + TheCall->getNumArgs() - firstDataArg, + isa(OrigFormatExpr), Str, + HasVAListArg, TheCall, format_idx); + + if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen)) + H.DoneProcessing(); + } + else { + CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, + TheCall->getNumArgs() - firstDataArg, + isa(OrigFormatExpr), Str, + HasVAListArg, TheCall, format_idx); + + if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen)) + H.DoneProcessing(); + } } //===--- CHECK: Return Address of Stack Variable --------------------------===// @@ -1729,7 +1871,7 @@ static DeclRefExpr* EvalAddr(Expr *E) { // is AddrOf. All others don't make sense as pointers. UnaryOperator *U = cast(E); - if (U->getOpcode() == UnaryOperator::AddrOf) + if (U->getOpcode() == UO_AddrOf) return EvalVal(U->getSubExpr()); else return NULL; @@ -1739,9 +1881,9 @@ static DeclRefExpr* EvalAddr(Expr *E) { // Handle pointer arithmetic. All other binary operators are not valid // in this context. BinaryOperator *B = cast(E); - BinaryOperator::Opcode op = B->getOpcode(); + BinaryOperatorKind op = B->getOpcode(); - if (op != BinaryOperator::Add && op != BinaryOperator::Sub) + if (op != BO_Add && op != BO_Sub) return NULL; Expr *Base = B->getLHS(); @@ -1814,7 +1956,7 @@ static DeclRefExpr* EvalAddr(Expr *E) { /// EvalVal - This function is complements EvalAddr in the mutual recursion. /// See the comments for EvalAddr for more details. static DeclRefExpr* EvalVal(Expr *E) { - +do { // We should only be called for evaluating non-pointer expressions, or // expressions with a pointer type that are not used as references but instead // are l-values (e.g., DeclRefExpr with a pointer type). @@ -1823,6 +1965,15 @@ static DeclRefExpr* EvalVal(Expr *E) { // viewed AST node. We then recursively traverse the AST by calling // EvalAddr and EvalVal appropriately. switch (E->getStmtClass()) { + case Stmt::ImplicitCastExprClass: { + ImplicitCastExpr *IE = cast(E); + if (IE->getValueKind() == VK_LValue) { + E = IE->getSubExpr(); + continue; + } + return NULL; + } + case Stmt::DeclRefExprClass: { // DeclRefExpr: the base case. When we hit a DeclRefExpr we are looking // at code that refers to a variable's name. We check if it has local @@ -1835,9 +1986,11 @@ static DeclRefExpr* EvalVal(Expr *E) { return NULL; } - case Stmt::ParenExprClass: + case Stmt::ParenExprClass: { // Ignore parentheses. - return EvalVal(cast(E)->getSubExpr()); + E = cast(E)->getSubExpr(); + continue; + } case Stmt::UnaryOperatorClass: { // The only unary operator that make sense to handle here @@ -1845,7 +1998,7 @@ static DeclRefExpr* EvalVal(Expr *E) { // handling all sorts of rvalues passed to a unary operator. UnaryOperator *U = cast(E); - if (U->getOpcode() == UnaryOperator::Deref) + if (U->getOpcode() == UO_Deref) return EvalAddr(U->getSubExpr()); return NULL; @@ -1876,16 +2029,22 @@ static DeclRefExpr* EvalVal(Expr *E) { MemberExpr *M = cast(E); // Check for indirect access. We only want direct field accesses. - if (!M->isArrow()) - return EvalVal(M->getBase()); - else + if (M->isArrow()) return NULL; + + // Check whether the member type is itself a reference, in which case + // we're not going to refer to the member, but to what the member refers to. + if (M->getMemberDecl()->getType()->isReferenceType()) + return NULL; + + return EvalVal(M->getBase()); } // Everything else: we simply don't reason about them. default: return NULL; } +} while (true); } //===--- CHECK: Floating-Point comparisons (-Wfloat-equal) ---------------===// @@ -1954,7 +2113,6 @@ struct IntRange { /// True if the int is known not to have negative values. bool NonNegative; - IntRange() {} IntRange(unsigned Width, bool NonNegative) : Width(Width), NonNegative(NonNegative) {} @@ -2063,13 +2221,13 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { // user has an explicit widening cast, we should treat the value as // being of the new, wider type. if (ImplicitCastExpr *CE = dyn_cast(E)) { - if (CE->getCastKind() == CastExpr::CK_NoOp) + if (CE->getCastKind() == CK_NoOp) return GetExprRange(C, CE->getSubExpr(), MaxWidth); IntRange OutputTypeRange = IntRange::forType(C, CE->getType()); - bool isIntegerCast = (CE->getCastKind() == CastExpr::CK_IntegralCast); - if (!isIntegerCast && CE->getCastKind() == CastExpr::CK_Unknown) + bool isIntegerCast = (CE->getCastKind() == CK_IntegralCast); + if (!isIntegerCast && CE->getCastKind() == CK_Unknown) isIntegerCast = CE->getSubExpr()->getType()->isIntegerType(); // Assume that non-integer casts can span the full range of the type. @@ -2108,38 +2266,38 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { switch (BO->getOpcode()) { // Boolean-valued operations are single-bit and positive. - case BinaryOperator::LAnd: - case BinaryOperator::LOr: - case BinaryOperator::LT: - case BinaryOperator::GT: - case BinaryOperator::LE: - case BinaryOperator::GE: - case BinaryOperator::EQ: - case BinaryOperator::NE: + case BO_LAnd: + case BO_LOr: + case BO_LT: + case BO_GT: + case BO_LE: + case BO_GE: + case BO_EQ: + case BO_NE: return IntRange::forBoolType(); // The type of these compound assignments is the type of the LHS, // so the RHS is not necessarily an integer. - case BinaryOperator::MulAssign: - case BinaryOperator::DivAssign: - case BinaryOperator::RemAssign: - case BinaryOperator::AddAssign: - case BinaryOperator::SubAssign: + case BO_MulAssign: + case BO_DivAssign: + case BO_RemAssign: + case BO_AddAssign: + case BO_SubAssign: return IntRange::forType(C, E->getType()); // Operations with opaque sources are black-listed. - case BinaryOperator::PtrMemD: - case BinaryOperator::PtrMemI: + case BO_PtrMemD: + case BO_PtrMemI: return IntRange::forType(C, E->getType()); // Bitwise-and uses the *infinum* of the two source ranges. - case BinaryOperator::And: - case BinaryOperator::AndAssign: + case BO_And: + case BO_AndAssign: return IntRange::meet(GetExprRange(C, BO->getLHS(), MaxWidth), GetExprRange(C, BO->getRHS(), MaxWidth)); // Left shift gets black-listed based on a judgement call. - case BinaryOperator::Shl: + case BO_Shl: // ...except that we want to treat '1 << (blah)' as logically // positive. It's an important idiom. if (IntegerLiteral *I @@ -2151,12 +2309,12 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { } // fallthrough - case BinaryOperator::ShlAssign: + case BO_ShlAssign: return IntRange::forType(C, E->getType()); // Right shift by a constant can narrow its left argument. - case BinaryOperator::Shr: - case BinaryOperator::ShrAssign: { + case BO_Shr: + case BO_ShrAssign: { IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth); // If the shift amount is a positive constant, drop the width by @@ -2175,11 +2333,11 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { } // Comma acts as its right operand. - case BinaryOperator::Comma: + case BO_Comma: return GetExprRange(C, BO->getRHS(), MaxWidth); // Black-list pointer subtractions. - case BinaryOperator::Sub: + case BO_Sub: if (BO->getLHS()->getType()->isPointerType()) return IntRange::forType(C, E->getType()); // fallthrough @@ -2198,13 +2356,12 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { if (UnaryOperator *UO = dyn_cast(E)) { switch (UO->getOpcode()) { // Boolean-valued operations are white-listed. - case UnaryOperator::LNot: + case UO_LNot: return IntRange::forBoolType(); // Operations with opaque sources are black-listed. - case UnaryOperator::Deref: - case UnaryOperator::AddrOf: // should be impossible - case UnaryOperator::OffsetOf: + case UO_Deref: + case UO_AddrOf: // should be impossible return IntRange::forType(C, E->getType()); default: @@ -2277,20 +2434,20 @@ bool IsZero(Sema &S, Expr *E) { } void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { - BinaryOperator::Opcode op = E->getOpcode(); - if (op == BinaryOperator::LT && IsZero(S, E->getRHS())) { + BinaryOperatorKind op = E->getOpcode(); + if (op == BO_LT && IsZero(S, E->getRHS())) { S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) << "< 0" << "false" << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); - } else if (op == BinaryOperator::GE && IsZero(S, E->getRHS())) { + } else if (op == BO_GE && IsZero(S, E->getRHS())) { S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) << ">= 0" << "true" << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); - } else if (op == BinaryOperator::GT && IsZero(S, E->getLHS())) { + } else if (op == BO_GT && IsZero(S, E->getLHS())) { S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) << "0 >" << "false" << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); - } else if (op == BinaryOperator::LE && IsZero(S, E->getLHS())) { + } else if (op == BO_LE && IsZero(S, E->getLHS())) { S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) << "0 <=" << "true" << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); @@ -2319,7 +2476,7 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { // We don't do anything special if this isn't an unsigned integral // comparison: we're only interested in integral comparisons, and // signed comparisons only happen in cases we don't care to warn about. - if (!T->isUnsignedIntegerType()) + if (!T->hasUnsignedIntegerRepresentation()) return AnalyzeImpConvsInComparison(S, E); Expr *lex = E->getLHS()->IgnoreParenImpCasts(); @@ -2328,12 +2485,12 @@ void AnalyzeComparison(Sema &S, BinaryOperator *E) { // Check to see if one of the (unmodified) operands is of different // signedness. Expr *signedOperand, *unsignedOperand; - if (lex->getType()->isSignedIntegerType()) { - assert(!rex->getType()->isSignedIntegerType() && + if (lex->getType()->hasSignedIntegerRepresentation()) { + assert(!rex->getType()->hasSignedIntegerRepresentation() && "unsigned comparison between two signed integer expressions?"); signedOperand = lex; unsignedOperand = rex; - } else if (rex->getType()->isSignedIntegerType()) { + } else if (rex->getType()->hasSignedIntegerRepresentation()) { signedOperand = rex; unsignedOperand = lex; } else { @@ -2648,3 +2805,48 @@ bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) { return HasInvalidParm; } + +/// CheckCastAlign - Implements -Wcast-align, which warns when a +/// pointer cast increases the alignment requirements. +void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { + // This is actually a lot of work to potentially be doing on every + // cast; don't do it if we're ignoring -Wcast_align (as is the default). + if (getDiagnostics().getDiagnosticLevel(diag::warn_cast_align) + == Diagnostic::Ignored) + return; + + // Ignore dependent types. + if (T->isDependentType() || Op->getType()->isDependentType()) + return; + + // Require that the destination be a pointer type. + const PointerType *DestPtr = T->getAs(); + if (!DestPtr) return; + + // If the destination has alignment 1, we're done. + QualType DestPointee = DestPtr->getPointeeType(); + if (DestPointee->isIncompleteType()) return; + CharUnits DestAlign = Context.getTypeAlignInChars(DestPointee); + if (DestAlign.isOne()) return; + + // Require that the source be a pointer type. + const PointerType *SrcPtr = Op->getType()->getAs(); + if (!SrcPtr) return; + QualType SrcPointee = SrcPtr->getPointeeType(); + + // Whitelist casts from cv void*. We already implicitly + // whitelisted casts to cv void*, since they have alignment 1. + // Also whitelist casts involving incomplete types, which implicitly + // includes 'void'. + if (SrcPointee->isIncompleteType()) return; + + CharUnits SrcAlign = Context.getTypeAlignInChars(SrcPointee); + if (SrcAlign >= DestAlign) return; + + Diag(TRange.getBegin(), diag::warn_cast_align) + << Op->getType() << T + << static_cast(SrcAlign.getQuantity()) + << static_cast(DestAlign.getQuantity()) + << TRange << Op->getSourceRange(); +} + diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 5528875..f00d1cd 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -10,10 +10,14 @@ // This file defines the code-completion semantic actions. // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "Lookup.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Overload.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/Lex/MacroInfo.h" @@ -21,11 +25,13 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" #include #include #include using namespace clang; +using namespace sema; namespace { /// \brief A container of code-completion results. @@ -37,7 +43,7 @@ namespace { /// filtered out (returns false). typedef bool (ResultBuilder::*LookupFilter)(NamedDecl *) const; - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; private: /// \brief The actual results we have found. @@ -130,17 +136,28 @@ namespace { /// different levels of, e.g., the inheritance hierarchy. std::list ShadowMaps; + /// \brief If we're potentially referring to a C++ member function, the set + /// of qualifiers applied to the object type. + Qualifiers ObjectTypeQualifiers; + + /// \brief Whether the \p ObjectTypeQualifiers field is active. + bool HasObjectTypeQualifiers; + + /// \brief The selector that we prefer. + Selector PreferredSelector; + void AdjustResultPriorityForPreferredType(Result &R); public: explicit ResultBuilder(Sema &SemaRef, LookupFilter Filter = 0) - : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false) { } + : SemaRef(SemaRef), Filter(Filter), AllowNestedNameSpecifiers(false), + HasObjectTypeQualifiers(false) { } /// \brief Whether we should include code patterns in the completion /// results. bool includeCodePatterns() const { return SemaRef.CodeCompleter && - SemaRef.CodeCompleter->includeCodePatterns(); + SemaRef.CodeCompleter->includeCodePatterns(); } /// \brief Set the filter used for code-completion results. @@ -161,6 +178,27 @@ namespace { PreferredType = SemaRef.Context.getCanonicalType(T); } + /// \brief Set the cv-qualifiers on the object type, for us in filtering + /// calls to member functions. + /// + /// When there are qualifiers in this set, they will be used to filter + /// out member functions that aren't available (because there will be a + /// cv-qualifier mismatch) or prefer functions with an exact qualifier + /// match. + void setObjectTypeQualifiers(Qualifiers Quals) { + ObjectTypeQualifiers = Quals; + HasObjectTypeQualifiers = true; + } + + /// \brief Set the preferred selector. + /// + /// When an Objective-C method declaration result is added, and that + /// method's selector matches this preferred selector, we give that method + /// a slight priority boost. + void setPreferredSelector(Selector Sel) { + PreferredSelector = Sel; + } + /// \brief Specify whether nested-name-specifiers are allowed. void allowNestedNameSpecifiers(bool Allow = true) { AllowNestedNameSpecifiers = Allow; @@ -227,6 +265,7 @@ namespace { //@{ bool IsOrdinaryName(NamedDecl *ND) const; bool IsOrdinaryNonTypeName(NamedDecl *ND) const; + bool IsIntegralConstantValue(NamedDecl *ND) const; bool IsOrdinaryNonValueName(NamedDecl *ND) const; bool IsNestedNameSpecifier(NamedDecl *ND) const; bool IsEnum(NamedDecl *ND) const; @@ -238,6 +277,7 @@ namespace { bool IsMember(NamedDecl *ND) const; bool IsObjCIvar(NamedDecl *ND) const; bool IsObjCMessageReceiver(NamedDecl *ND) const; + bool IsObjCCollection(NamedDecl *ND) const; //@} }; } @@ -365,8 +405,12 @@ getRequiredQualification(ASTContext &Context, DeclContext *Parent = TargetParents.back(); TargetParents.pop_back(); - if (NamespaceDecl *Namespace = dyn_cast(Parent)) + if (NamespaceDecl *Namespace = dyn_cast(Parent)) { + if (!Namespace->getIdentifier()) + continue; + Result = NestedNameSpecifier::Create(Context, Result, Namespace); + } else if (TagDecl *TD = dyn_cast(Parent)) Result = NestedNameSpecifier::Create(Context, Result, false, @@ -425,6 +469,12 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND, if (isa(ND)) return false; + if (Filter == &ResultBuilder::IsNestedNameSpecifier || + ((isa(ND) || isa(ND)) && + Filter != &ResultBuilder::IsNamespace && + Filter != &ResultBuilder::IsNamespaceOrAlias)) + AsNestedNameSpecifier = true; + // Filter out any unwanted results. if (Filter && !(this->*Filter)(ND)) { // Check whether it is interesting as a nested-name-specifier. @@ -438,11 +488,7 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND, } return false; - } - - if (Filter == &ResultBuilder::IsNestedNameSpecifier) - AsNestedNameSpecifier = true; - + } // ... then it must be interesting! return true; } @@ -455,13 +501,13 @@ bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext, if (!SemaRef.getLangOptions().CPlusPlus) return true; - DeclContext *HiddenCtx = R.Declaration->getDeclContext()->getLookupContext(); + DeclContext *HiddenCtx = R.Declaration->getDeclContext()->getRedeclContext(); // There is no way to qualify a name declared in a function or method. if (HiddenCtx->isFunctionOrMethod()) return true; - if (HiddenCtx == Hiding->getDeclContext()->getLookupContext()) + if (HiddenCtx == Hiding->getDeclContext()->getRedeclContext()) return true; // We can refer to the result with the appropriate qualification. Do it. @@ -475,21 +521,9 @@ bool ResultBuilder::CheckHiddenResult(Result &R, DeclContext *CurContext, return false; } -enum SimplifiedTypeClass { - STC_Arithmetic, - STC_Array, - STC_Block, - STC_Function, - STC_ObjectiveC, - STC_Other, - STC_Pointer, - STC_Record, - STC_Void -}; - /// \brief A simplified classification of types used to determine whether two /// types are "similar enough" when adjusting priorities. -static SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T) { +SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) { switch (T->getTypeClass()) { case Type::Builtin: switch (cast(T)->getKind()) { @@ -560,7 +594,7 @@ static SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T) { /// \brief Get the type that a given expression will have if this declaration /// is used as an expression in its "typical" code-completion form. -static QualType getDeclUsageType(ASTContext &C, NamedDecl *ND) { +QualType clang::getDeclUsageType(ASTContext &C, NamedDecl *ND) { ND = cast(ND->getUnderlyingDecl()); if (TypeDecl *Type = dyn_cast(ND)) @@ -594,9 +628,12 @@ void ResultBuilder::AdjustResultPriorityForPreferredType(Result &R) { CanQualType TC = SemaRef.Context.getCanonicalType(T); // Check for exactly-matching types (modulo qualifiers). - if (SemaRef.Context.hasSameUnqualifiedType(PreferredType, TC)) - R.Priority /= CCF_ExactTypeMatch; - // Check for nearly-matching types, based on classification of each. + if (SemaRef.Context.hasSameUnqualifiedType(PreferredType, TC)) { + if (PreferredType->isVoidType()) + R.Priority += CCD_VoidMatch; + else + R.Priority /= CCF_ExactTypeMatch; + } // Check for nearly-matching types, based on classification of each. else if ((getSimplifiedTypeClass(PreferredType) == getSimplifiedTypeClass(TC)) && !(PreferredType->isEnumeralType() && TC->isEnumeralType())) @@ -681,7 +718,14 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { // Make sure that any given declaration only shows up in the result set once. if (!AllDeclsFound.insert(CanonDecl)) return; - + + // If this is an Objective-C method declaration whose selector matches our + // preferred selector, give it a priority boost. + if (!PreferredSelector.isNull()) + if (ObjCMethodDecl *Method = dyn_cast(R.Declaration)) + if (PreferredSelector == Method->getSelector()) + R.Priority += CCD_SelectorMatch; + // If the filter is for nested-name-specifiers, then this result starts a // nested-name-specifier. if (AsNestedNameSpecifier) { @@ -689,7 +733,7 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { R.Priority = CCP_NestedNameSpecifier; } else if (!PreferredType.isNull()) AdjustResultPriorityForPreferredType(R); - + // If this result is supposed to have an informative qualifier, add one. if (R.QualifierIsInformative && !R.Qualifier && !R.StartsNestedNameSpecifier) { @@ -742,7 +786,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, } else if (Filter == &ResultBuilder::IsMember && !R.Qualifier && InBaseClass && isa(R.Declaration->getDeclContext() - ->getLookupContext())) + ->getRedeclContext())) R.QualifierIsInformative = true; // If this result is supposed to have an informative qualifier, add one. @@ -762,9 +806,30 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, if (InBaseClass) R.Priority += CCD_InBaseClass; + // If this is an Objective-C method declaration whose selector matches our + // preferred selector, give it a priority boost. + if (!PreferredSelector.isNull()) + if (ObjCMethodDecl *Method = dyn_cast(R.Declaration)) + if (PreferredSelector == Method->getSelector()) + R.Priority += CCD_SelectorMatch; + if (!PreferredType.isNull()) AdjustResultPriorityForPreferredType(R); + if (HasObjectTypeQualifiers) + if (CXXMethodDecl *Method = dyn_cast(R.Declaration)) + if (Method->isInstance()) { + Qualifiers MethodQuals + = Qualifiers::fromCVRMask(Method->getTypeQualifiers()); + if (ObjectTypeQualifiers == MethodQuals) + R.Priority += CCD_ObjectQualifierMatch; + else if (ObjectTypeQualifiers - MethodQuals) { + // The method cannot be invoked, because doing so would drop + // qualifiers. + return; + } + } + // Insert this result into the set of results. Results.push_back(R); } @@ -821,6 +886,17 @@ bool ResultBuilder::IsOrdinaryNonTypeName(NamedDecl *ND) const { return ND->getIdentifierNamespace() & IDNS; } +bool ResultBuilder::IsIntegralConstantValue(NamedDecl *ND) const { + if (!IsOrdinaryNonTypeName(ND)) + return 0; + + if (ValueDecl *VD = dyn_cast(ND->getUnderlyingDecl())) + if (VD->getType()->isIntegralOrEnumerationType()) + return true; + + return false; +} + /// \brief Determines whether this given declaration will be found by /// ordinary name lookup. bool ResultBuilder::IsOrdinaryNonValueName(NamedDecl *ND) const { @@ -888,7 +964,10 @@ bool ResultBuilder::IsNamespaceOrAlias(NamedDecl *ND) const { /// \brief Determines whether the given declaration is a type. bool ResultBuilder::IsType(NamedDecl *ND) const { - return isa(ND); + if (UsingShadowDecl *Using = dyn_cast(ND)) + ND = Using->getTargetDecl(); + + return isa(ND) || isa(ND); } /// \brief Determines which members of a class should be visible via @@ -944,6 +1023,20 @@ bool ResultBuilder::IsObjCMessageReceiver(NamedDecl *ND) const { return isObjCReceiverType(SemaRef.Context, T); } +bool ResultBuilder::IsObjCCollection(NamedDecl *ND) const { + if ((SemaRef.getLangOptions().CPlusPlus && !IsOrdinaryName(ND)) || + (!SemaRef.getLangOptions().CPlusPlus && !IsOrdinaryNonTypeName(ND))) + return false; + + QualType T = getDeclUsageType(SemaRef.Context, ND); + if (T.isNull()) + return false; + + T = SemaRef.Context.getBaseElementType(T); + return T->isObjCObjectType() || T->isObjCObjectPointerType() || + T->isObjCIdType() || + (SemaRef.getLangOptions().CPlusPlus && T->isRecordType()); +} /// \rief Determines whether the given declaration is an Objective-C /// instance variable. @@ -971,7 +1064,7 @@ namespace { /// \brief Add type specifiers for the current language as keyword results. static void AddTypeSpecifierResults(const LangOptions &LangOpts, ResultBuilder &Results) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; Results.AddResult(Result("short", CCP_Type)); Results.AddResult(Result("long", CCP_Type)); Results.AddResult(Result("signed", CCP_Type)); @@ -1046,10 +1139,10 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, } } -static void AddStorageSpecifiers(Action::CodeCompletionContext CCC, +static void AddStorageSpecifiers(Sema::ParserCompletionContext CCC, const LangOptions &LangOpts, ResultBuilder &Results) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; // Note: we don't suggest either "auto" or "register", because both // are pointless as storage specifiers. Elsewhere, we suggest "auto" // in C++0x as a type specifier. @@ -1057,13 +1150,13 @@ static void AddStorageSpecifiers(Action::CodeCompletionContext CCC, Results.AddResult(Result("static")); } -static void AddFunctionSpecifiers(Action::CodeCompletionContext CCC, +static void AddFunctionSpecifiers(Sema::ParserCompletionContext CCC, const LangOptions &LangOpts, ResultBuilder &Results) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; switch (CCC) { - case Action::CCC_Class: - case Action::CCC_MemberTemplate: + case Sema::PCC_Class: + case Sema::PCC_MemberTemplate: if (LangOpts.CPlusPlus) { Results.AddResult(Result("explicit")); Results.AddResult(Result("friend")); @@ -1072,20 +1165,21 @@ static void AddFunctionSpecifiers(Action::CodeCompletionContext CCC, } // Fall through - case Action::CCC_ObjCInterface: - case Action::CCC_ObjCImplementation: - case Action::CCC_Namespace: - case Action::CCC_Template: + case Sema::PCC_ObjCInterface: + case Sema::PCC_ObjCImplementation: + case Sema::PCC_Namespace: + case Sema::PCC_Template: if (LangOpts.CPlusPlus || LangOpts.C99) Results.AddResult(Result("inline")); break; - case Action::CCC_ObjCInstanceVariableList: - case Action::CCC_Expression: - case Action::CCC_Statement: - case Action::CCC_ForInit: - case Action::CCC_Condition: - case Action::CCC_RecoveryInFunction: + case Sema::PCC_ObjCInstanceVariableList: + case Sema::PCC_Expression: + case Sema::PCC_Statement: + case Sema::PCC_ForInit: + case Sema::PCC_Condition: + case Sema::PCC_RecoveryInFunction: + case Sema::PCC_Type: break; } } @@ -1110,31 +1204,32 @@ static void AddTypedefResult(ResultBuilder &Results) { Pattern->AddPlaceholderChunk("type"); Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); Pattern->AddPlaceholderChunk("name"); - Results.AddResult(CodeCompleteConsumer::Result(Pattern)); + Results.AddResult(CodeCompletionResult(Pattern)); } -static bool WantTypesInContext(Action::CodeCompletionContext CCC, +static bool WantTypesInContext(Sema::ParserCompletionContext CCC, const LangOptions &LangOpts) { if (LangOpts.CPlusPlus) return true; switch (CCC) { - case Action::CCC_Namespace: - case Action::CCC_Class: - case Action::CCC_ObjCInstanceVariableList: - case Action::CCC_Template: - case Action::CCC_MemberTemplate: - case Action::CCC_Statement: - case Action::CCC_RecoveryInFunction: + case Sema::PCC_Namespace: + case Sema::PCC_Class: + case Sema::PCC_ObjCInstanceVariableList: + case Sema::PCC_Template: + case Sema::PCC_MemberTemplate: + case Sema::PCC_Statement: + case Sema::PCC_RecoveryInFunction: + case Sema::PCC_Type: return true; - case Action::CCC_ObjCInterface: - case Action::CCC_ObjCImplementation: - case Action::CCC_Expression: - case Action::CCC_Condition: + case Sema::PCC_ObjCInterface: + case Sema::PCC_ObjCImplementation: + case Sema::PCC_Expression: + case Sema::PCC_Condition: return false; - case Action::CCC_ForInit: + case Sema::PCC_ForInit: return LangOpts.ObjC1 || LangOpts.C99; } @@ -1142,13 +1237,13 @@ static bool WantTypesInContext(Action::CodeCompletionContext CCC, } /// \brief Add language constructs that show up for "ordinary" names. -static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, +static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Sema &SemaRef, ResultBuilder &Results) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; switch (CCC) { - case Action::CCC_Namespace: + case Sema::PCC_Namespace: if (SemaRef.getLangOptions().CPlusPlus) { CodeCompletionString *Pattern = 0; @@ -1207,7 +1302,7 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, AddTypedefResult(Results); // Fall through - case Action::CCC_Class: + case Sema::PCC_Class: if (SemaRef.getLangOptions().CPlusPlus) { // Using declaration CodeCompletionString *Pattern = new CodeCompletionString; @@ -1231,7 +1326,7 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Results.AddResult(Result(Pattern)); } - if (CCC == Action::CCC_Class) { + if (CCC == Sema::PCC_Class) { AddTypedefResult(Results); // public: @@ -1255,8 +1350,8 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, } // Fall through - case Action::CCC_Template: - case Action::CCC_MemberTemplate: + case Sema::PCC_Template: + case Sema::PCC_MemberTemplate: if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) { // template < parameters > CodeCompletionString *Pattern = new CodeCompletionString; @@ -1271,24 +1366,24 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results); break; - case Action::CCC_ObjCInterface: + case Sema::PCC_ObjCInterface: AddObjCInterfaceResults(SemaRef.getLangOptions(), Results, true); AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results); AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results); break; - case Action::CCC_ObjCImplementation: + case Sema::PCC_ObjCImplementation: AddObjCImplementationResults(SemaRef.getLangOptions(), Results, true); AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results); AddFunctionSpecifiers(CCC, SemaRef.getLangOptions(), Results); break; - case Action::CCC_ObjCInstanceVariableList: + case Sema::PCC_ObjCInstanceVariableList: AddObjCVisibilityResults(SemaRef.getLangOptions(), Results, true); break; - case Action::CCC_RecoveryInFunction: - case Action::CCC_Statement: { + case Sema::PCC_RecoveryInFunction: + case Sema::PCC_Statement: { AddTypedefResult(Results); CodeCompletionString *Pattern = 0; @@ -1344,7 +1439,7 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, } // Switch-specific statements. - if (!SemaRef.getSwitchStack().empty()) { + if (!SemaRef.getCurFunction()->SwitchStack.empty()) { // case expression: Pattern = new CodeCompletionString; Pattern->AddTypedTextChunk("case"); @@ -1460,12 +1555,12 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, } // Fall through (for statement expressions). - case Action::CCC_ForInit: - case Action::CCC_Condition: + case Sema::PCC_ForInit: + case Sema::PCC_Condition: AddStorageSpecifiers(CCC, SemaRef.getLangOptions(), Results); // Fall through: conditions and statements can have expressions. - case Action::CCC_Expression: { + case Sema::PCC_Expression: { CodeCompletionString *Pattern = 0; if (SemaRef.getLangOptions().CPlusPlus) { // 'this', if we're in a non-static member function. @@ -1600,12 +1695,15 @@ static void AddOrdinaryNameResults(Action::CodeCompletionContext CCC, Results.AddResult(Result(Pattern)); break; } + + case Sema::PCC_Type: + break; } if (WantTypesInContext(CCC, SemaRef.getLangOptions())) AddTypeSpecifierResults(SemaRef.getLangOptions(), Results); - if (SemaRef.getLangOptions().CPlusPlus) + if (SemaRef.getLangOptions().CPlusPlus && CCC != Sema::PCC_Type) Results.AddResult(Result("operator")); } @@ -1645,6 +1743,117 @@ static void AddResultTypeChunk(ASTContext &Context, Result->AddResultTypeChunk(TypeStr); } +static void MaybeAddSentinel(ASTContext &Context, NamedDecl *FunctionOrMethod, + CodeCompletionString *Result) { + if (SentinelAttr *Sentinel = FunctionOrMethod->getAttr()) + if (Sentinel->getSentinel() == 0) { + if (Context.getLangOptions().ObjC1 && + Context.Idents.get("nil").hasMacroDefinition()) + Result->AddTextChunk(", nil"); + else if (Context.Idents.get("NULL").hasMacroDefinition()) + Result->AddTextChunk(", NULL"); + else + Result->AddTextChunk(", (void*)0"); + } +} + +static std::string FormatFunctionParameter(ASTContext &Context, + ParmVarDecl *Param, + bool SuppressName = false) { + bool ObjCMethodParam = isa(Param->getDeclContext()); + if (Param->getType()->isDependentType() || + !Param->getType()->isBlockPointerType()) { + // The argument for a dependent or non-block parameter is a placeholder + // containing that parameter's type. + std::string Result; + + if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName) + Result = Param->getIdentifier()->getName(); + + Param->getType().getAsStringInternal(Result, + Context.PrintingPolicy); + + if (ObjCMethodParam) { + Result = "(" + Result; + Result += ")"; + if (Param->getIdentifier() && !SuppressName) + Result += Param->getIdentifier()->getName(); + } + return Result; + } + + // The argument for a block pointer parameter is a block literal with + // the appropriate type. + FunctionProtoTypeLoc *Block = 0; + TypeLoc TL; + if (TypeSourceInfo *TSInfo = Param->getTypeSourceInfo()) { + TL = TSInfo->getTypeLoc().getUnqualifiedLoc(); + while (true) { + // Look through typedefs. + if (TypedefTypeLoc *TypedefTL = dyn_cast(&TL)) { + if (TypeSourceInfo *InnerTSInfo + = TypedefTL->getTypedefDecl()->getTypeSourceInfo()) { + TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc(); + continue; + } + } + + // Look through qualified types + if (QualifiedTypeLoc *QualifiedTL = dyn_cast(&TL)) { + TL = QualifiedTL->getUnqualifiedLoc(); + continue; + } + + // Try to get the function prototype behind the block pointer type, + // then we're done. + if (BlockPointerTypeLoc *BlockPtr + = dyn_cast(&TL)) { + TL = BlockPtr->getPointeeLoc(); + Block = dyn_cast(&TL); + } + break; + } + } + + if (!Block) { + // We were unable to find a FunctionProtoTypeLoc with parameter names + // for the block; just use the parameter type as a placeholder. + std::string Result; + Param->getType().getUnqualifiedType(). + getAsStringInternal(Result, Context.PrintingPolicy); + + if (ObjCMethodParam) { + Result = "(" + Result; + Result += ")"; + if (Param->getIdentifier()) + Result += Param->getIdentifier()->getName(); + } + + return Result; + } + + // We have the function prototype behind the block pointer type, as it was + // written in the source. + std::string Result = "(^)("; + for (unsigned I = 0, N = Block->getNumArgs(); I != N; ++I) { + if (I) + Result += ", "; + Result += FormatFunctionParameter(Context, Block->getArg(I)); + + if (I == N - 1 && Block->getTypePtr()->isVariadic()) + Result += ", ..."; + } + if (Block->getTypePtr()->isVariadic() && Block->getNumArgs() == 0) + Result += "..."; + else if (Block->getNumArgs() == 0 && !Context.getLangOptions().CPlusPlus) + Result += "void"; + + Result += ")"; + Block->getTypePtr()->getResultType().getAsStringInternal(Result, + Context.PrintingPolicy); + return Result; +} + /// \brief Add function parameter chunks to the given code completion string. static void AddFunctionParameterChunks(ASTContext &Context, FunctionDecl *Function, @@ -1668,21 +1877,23 @@ static void AddFunctionParameterChunks(ASTContext &Context, CCStr->AddChunk(Chunk(CodeCompletionString::CK_Comma)); // Format the placeholder string. - std::string PlaceholderStr; - if (Param->getIdentifier()) - PlaceholderStr = Param->getIdentifier()->getName(); - - Param->getType().getAsStringInternal(PlaceholderStr, - Context.PrintingPolicy); - + std::string PlaceholderStr = FormatFunctionParameter(Context, Param); + + if (Function->isVariadic() && P == N - 1) + PlaceholderStr += ", ..."; + // Add the placeholder string. CCStr->AddPlaceholderChunk(PlaceholderStr); } if (const FunctionProtoType *Proto = Function->getType()->getAs()) - if (Proto->isVariadic()) - CCStr->AddPlaceholderChunk(", ..."); + if (Proto->isVariadic()) { + if (Proto->getNumArgs() == 0) + CCStr->AddPlaceholderChunk("..."); + + MaybeAddSentinel(Context, Function, CCStr); + } } /// \brief Add template parameter chunks to the given code completion string. @@ -1799,13 +2010,15 @@ static void AddFunctionTypeQualsToCompletionString(CodeCompletionString *Result, /// how to use this result, or NULL to indicate that the string or name of the /// result is all that is needed. CodeCompletionString * -CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { +CodeCompletionResult::CreateCodeCompletionString(Sema &S, + CodeCompletionString *Result) { typedef CodeCompletionString::Chunk Chunk; if (Kind == RK_Pattern) - return Pattern->Clone(); + return Pattern->Clone(Result); - CodeCompletionString *Result = new CodeCompletionString; + if (!Result) + Result = new CodeCompletionString; if (Kind == RK_Keyword) { Result->AddTypedTextChunk(Keyword); @@ -1978,10 +2191,20 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { continue; std::string Arg; - (*P)->getType().getAsStringInternal(Arg, S.Context.PrintingPolicy); - Arg = "(" + Arg + ")"; - if (IdentifierInfo *II = (*P)->getIdentifier()) - Arg += II->getName().str(); + + if ((*P)->getType()->isBlockPointerType() && !DeclaringEntity) + Arg = FormatFunctionParameter(S.Context, *P, true); + else { + (*P)->getType().getAsStringInternal(Arg, S.Context.PrintingPolicy); + Arg = "(" + Arg + ")"; + if (IdentifierInfo *II = (*P)->getIdentifier()) + if (DeclaringEntity || AllParametersAreInformative) + Arg += II->getName().str(); + } + + if (Method->isVariadic() && (P + 1) == PEnd) + Arg += ", ..."; + if (DeclaringEntity) Result->AddTextChunk(Arg); else if (AllParametersAreInformative) @@ -1991,12 +2214,16 @@ CodeCompleteConsumer::Result::CreateCodeCompletionString(Sema &S) { } if (Method->isVariadic()) { - if (DeclaringEntity) - Result->AddTextChunk(", ..."); - else if (AllParametersAreInformative) - Result->AddInformativeChunk(", ..."); - else - Result->AddPlaceholderChunk(", ..."); + if (Method->param_size() == 0) { + if (DeclaringEntity) + Result->AddTextChunk(", ..."); + else if (AllParametersAreInformative) + Result->AddInformativeChunk(", ..."); + else + Result->AddPlaceholderChunk(", ..."); + } + + MaybeAddSentinel(S.Context, Method, Result); } return Result; @@ -2076,226 +2303,421 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( return Result; } -namespace { - struct SortCodeCompleteResult { - typedef CodeCompleteConsumer::Result Result; - - bool isEarlierDeclarationName(DeclarationName X, DeclarationName Y) const { - Selector XSel = X.getObjCSelector(); - Selector YSel = Y.getObjCSelector(); - if (!XSel.isNull() && !YSel.isNull()) { - // We are comparing two selectors. - unsigned N = std::min(XSel.getNumArgs(), YSel.getNumArgs()); - if (N == 0) - ++N; - for (unsigned I = 0; I != N; ++I) { - IdentifierInfo *XId = XSel.getIdentifierInfoForSlot(I); - IdentifierInfo *YId = YSel.getIdentifierInfoForSlot(I); - if (!XId || !YId) - return XId && !YId; - - switch (XId->getName().compare_lower(YId->getName())) { - case -1: return true; - case 1: return false; - default: break; - } - } - - return XSel.getNumArgs() < YSel.getNumArgs(); - } +unsigned clang::getMacroUsagePriority(llvm::StringRef MacroName, + bool PreferredTypeIsPointer) { + unsigned Priority = CCP_Macro; + + // Treat the "nil" and "NULL" macros as null pointer constants. + if (MacroName.equals("nil") || MacroName.equals("NULL")) { + Priority = CCP_Constant; + if (PreferredTypeIsPointer) + Priority = Priority / CCF_SimilarTypeMatch; + } + + return Priority; +} - // For non-selectors, order by kind. - if (X.getNameKind() != Y.getNameKind()) - return X.getNameKind() < Y.getNameKind(); - - // Order identifiers by comparison of their lowercased names. - if (IdentifierInfo *XId = X.getAsIdentifierInfo()) - return XId->getName().compare_lower( - Y.getAsIdentifierInfo()->getName()) < 0; - - // Order overloaded operators by the order in which they appear - // in our list of operators. - if (OverloadedOperatorKind XOp = X.getCXXOverloadedOperator()) - return XOp < Y.getCXXOverloadedOperator(); - - // Order C++0x user-defined literal operators lexically by their - // lowercased suffixes. - if (IdentifierInfo *XLit = X.getCXXLiteralIdentifier()) - return XLit->getName().compare_lower( - Y.getCXXLiteralIdentifier()->getName()) < 0; - - // The only stable ordering we have is to turn the name into a - // string and then compare the lower-case strings. This is - // inefficient, but thankfully does not happen too often. - return llvm::StringRef(X.getAsString()).compare_lower( - Y.getAsString()) < 0; - } - - /// \brief Retrieve the name that should be used to order a result. - /// - /// If the name needs to be constructed as a string, that string will be - /// saved into Saved and the returned StringRef will refer to it. - static llvm::StringRef getOrderedName(const Result &R, - std::string &Saved) { - switch (R.Kind) { - case Result::RK_Keyword: - return R.Keyword; - - case Result::RK_Pattern: - return R.Pattern->getTypedText(); - - case Result::RK_Macro: - return R.Macro->getName(); - - case Result::RK_Declaration: - // Handle declarations below. - break; - } - - DeclarationName Name = R.Declaration->getDeclName(); - - // If the name is a simple identifier (by far the common case), or a - // zero-argument selector, just return a reference to that identifier. - if (IdentifierInfo *Id = Name.getAsIdentifierInfo()) - return Id->getName(); - if (Name.isObjCZeroArgSelector()) - if (IdentifierInfo *Id - = Name.getObjCSelector().getIdentifierInfoForSlot(0)) - return Id->getName(); - - Saved = Name.getAsString(); - return Saved; - } - - bool operator()(const Result &X, const Result &Y) const { - std::string XSaved, YSaved; - llvm::StringRef XStr = getOrderedName(X, XSaved); - llvm::StringRef YStr = getOrderedName(Y, YSaved); - int cmp = XStr.compare_lower(YStr); - if (cmp) - return cmp < 0; - - // Non-hidden names precede hidden names. - if (X.Hidden != Y.Hidden) - return !X.Hidden; +CXCursorKind clang::getCursorKindForDecl(Decl *D) { + if (!D) + return CXCursor_UnexposedDecl; + + switch (D->getKind()) { + case Decl::Enum: return CXCursor_EnumDecl; + case Decl::EnumConstant: return CXCursor_EnumConstantDecl; + case Decl::Field: return CXCursor_FieldDecl; + case Decl::Function: + return CXCursor_FunctionDecl; + case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl; + case Decl::ObjCCategoryImpl: return CXCursor_ObjCCategoryImplDecl; + case Decl::ObjCClass: + // FIXME + return CXCursor_UnexposedDecl; + case Decl::ObjCForwardProtocol: + // FIXME + return CXCursor_UnexposedDecl; + case Decl::ObjCImplementation: return CXCursor_ObjCImplementationDecl; + case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl; + case Decl::ObjCIvar: return CXCursor_ObjCIvarDecl; + case Decl::ObjCMethod: + return cast(D)->isInstanceMethod() + ? CXCursor_ObjCInstanceMethodDecl : CXCursor_ObjCClassMethodDecl; + case Decl::CXXMethod: return CXCursor_CXXMethod; + case Decl::CXXConstructor: return CXCursor_Constructor; + case Decl::CXXDestructor: return CXCursor_Destructor; + case Decl::CXXConversion: return CXCursor_ConversionFunction; + case Decl::ObjCProperty: return CXCursor_ObjCPropertyDecl; + case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl; + case Decl::ParmVar: return CXCursor_ParmDecl; + case Decl::Typedef: return CXCursor_TypedefDecl; + case Decl::Var: return CXCursor_VarDecl; + case Decl::Namespace: return CXCursor_Namespace; + case Decl::NamespaceAlias: return CXCursor_NamespaceAlias; + case Decl::TemplateTypeParm: return CXCursor_TemplateTypeParameter; + case Decl::NonTypeTemplateParm:return CXCursor_NonTypeTemplateParameter; + case Decl::TemplateTemplateParm:return CXCursor_TemplateTemplateParameter; + case Decl::FunctionTemplate: return CXCursor_FunctionTemplate; + case Decl::ClassTemplate: return CXCursor_ClassTemplate; + case Decl::ClassTemplatePartialSpecialization: + return CXCursor_ClassTemplatePartialSpecialization; + case Decl::UsingDirective: return CXCursor_UsingDirective; - // Non-nested-name-specifiers precede nested-name-specifiers. - if (X.StartsNestedNameSpecifier != Y.StartsNestedNameSpecifier) - return !X.StartsNestedNameSpecifier; + case Decl::Using: + case Decl::UnresolvedUsingValue: + case Decl::UnresolvedUsingTypename: + return CXCursor_UsingDeclaration; - return false; - } - }; + default: + if (TagDecl *TD = dyn_cast(D)) { + switch (TD->getTagKind()) { + case TTK_Struct: return CXCursor_StructDecl; + case TTK_Class: return CXCursor_ClassDecl; + case TTK_Union: return CXCursor_UnionDecl; + case TTK_Enum: return CXCursor_EnumDecl; + } + } + } + + return CXCursor_UnexposedDecl; } static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results, bool TargetTypeIsPointer = false) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; Results.EnterNewScope(); for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end(); M != MEnd; ++M) { - unsigned Priority = CCP_Macro; - - // Treat the "nil" and "NULL" macros as null pointer constants. - if (M->first->isStr("nil") || M->first->isStr("NULL")) { - Priority = CCP_Constant; - if (TargetTypeIsPointer) - Priority = Priority / CCF_SimilarTypeMatch; - } - - Results.AddResult(Result(M->first, Priority)); + Results.AddResult(Result(M->first, + getMacroUsagePriority(M->first->getName(), + TargetTypeIsPointer))); } Results.ExitScope(); } +static void AddPrettyFunctionResults(const LangOptions &LangOpts, + ResultBuilder &Results) { + typedef CodeCompletionResult Result; + + Results.EnterNewScope(); + Results.AddResult(Result("__PRETTY_FUNCTION__", CCP_Constant)); + Results.AddResult(Result("__FUNCTION__", CCP_Constant)); + if (LangOpts.C99 || LangOpts.CPlusPlus0x) + Results.AddResult(Result("__func__", CCP_Constant)); + Results.ExitScope(); +} + static void HandleCodeCompleteResults(Sema *S, CodeCompleteConsumer *CodeCompleter, - CodeCompleteConsumer::Result *Results, - unsigned NumResults) { - std::stable_sort(Results, Results + NumResults, SortCodeCompleteResult()); - + CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults) { if (CodeCompleter) - CodeCompleter->ProcessCodeCompleteResults(*S, Results, NumResults); + CodeCompleter->ProcessCodeCompleteResults(*S, Context, Results, NumResults); for (unsigned I = 0; I != NumResults; ++I) Results[I].Destroy(); } +static enum CodeCompletionContext::Kind mapCodeCompletionContext(Sema &S, + Sema::ParserCompletionContext PCC) { + switch (PCC) { + case Sema::PCC_Namespace: + return CodeCompletionContext::CCC_TopLevel; + + case Sema::PCC_Class: + return CodeCompletionContext::CCC_ClassStructUnion; + + case Sema::PCC_ObjCInterface: + return CodeCompletionContext::CCC_ObjCInterface; + + case Sema::PCC_ObjCImplementation: + return CodeCompletionContext::CCC_ObjCImplementation; + + case Sema::PCC_ObjCInstanceVariableList: + return CodeCompletionContext::CCC_ObjCIvarList; + + case Sema::PCC_Template: + case Sema::PCC_MemberTemplate: + case Sema::PCC_RecoveryInFunction: + return CodeCompletionContext::CCC_Other; + + case Sema::PCC_Expression: + case Sema::PCC_ForInit: + case Sema::PCC_Condition: + return CodeCompletionContext::CCC_Expression; + + case Sema::PCC_Statement: + return CodeCompletionContext::CCC_Statement; + + case Sema::PCC_Type: + return CodeCompletionContext::CCC_Type; + } + + return CodeCompletionContext::CCC_Other; +} + +/// \brief If we're in a C++ virtual member function, add completion results +/// that invoke the functions we override, since it's common to invoke the +/// overridden function as well as adding new functionality. +/// +/// \param S The semantic analysis object for which we are generating results. +/// +/// \param InContext This context in which the nested-name-specifier preceding +/// the code-completion point +static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, + ResultBuilder &Results) { + // Look through blocks. + DeclContext *CurContext = S.CurContext; + while (isa(CurContext)) + CurContext = CurContext->getParent(); + + + CXXMethodDecl *Method = dyn_cast(CurContext); + if (!Method || !Method->isVirtual()) + return; + + // We need to have names for all of the parameters, if we're going to + // generate a forwarding call. + for (CXXMethodDecl::param_iterator P = Method->param_begin(), + PEnd = Method->param_end(); + P != PEnd; + ++P) { + if (!(*P)->getDeclName()) + return; + } + + for (CXXMethodDecl::method_iterator M = Method->begin_overridden_methods(), + MEnd = Method->end_overridden_methods(); + M != MEnd; ++M) { + CodeCompletionString *Pattern = new CodeCompletionString; + CXXMethodDecl *Overridden = const_cast(*M); + if (Overridden->getCanonicalDecl() == Method->getCanonicalDecl()) + continue; + + // If we need a nested-name-specifier, add one now. + if (!InContext) { + NestedNameSpecifier *NNS + = getRequiredQualification(S.Context, CurContext, + Overridden->getDeclContext()); + if (NNS) { + std::string Str; + llvm::raw_string_ostream OS(Str); + NNS->print(OS, S.Context.PrintingPolicy); + Pattern->AddTextChunk(OS.str()); + } + } else if (!InContext->Equals(Overridden->getDeclContext())) + continue; + + Pattern->AddTypedTextChunk(Overridden->getNameAsString()); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + bool FirstParam = true; + for (CXXMethodDecl::param_iterator P = Method->param_begin(), + PEnd = Method->param_end(); + P != PEnd; ++P) { + if (FirstParam) + FirstParam = false; + else + Pattern->AddChunk(CodeCompletionString::CK_Comma); + + Pattern->AddPlaceholderChunk((*P)->getIdentifier()->getName()); + } + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(CodeCompletionResult(Pattern, + CCP_SuperCompletion, + CXCursor_CXXMethod)); + Results.Ignore(Overridden); + } +} + void Sema::CodeCompleteOrdinaryName(Scope *S, - CodeCompletionContext CompletionContext) { - typedef CodeCompleteConsumer::Result Result; - ResultBuilder Results(*this); + ParserCompletionContext CompletionContext) { + typedef CodeCompletionResult Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); // Determine how to filter results, e.g., so that the names of // values (functions, enumerators, function templates, etc.) are // only allowed where we can have an expression. switch (CompletionContext) { - case CCC_Namespace: - case CCC_Class: - case CCC_ObjCInterface: - case CCC_ObjCImplementation: - case CCC_ObjCInstanceVariableList: - case CCC_Template: - case CCC_MemberTemplate: + case PCC_Namespace: + case PCC_Class: + case PCC_ObjCInterface: + case PCC_ObjCImplementation: + case PCC_ObjCInstanceVariableList: + case PCC_Template: + case PCC_MemberTemplate: + case PCC_Type: Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName); break; - case CCC_Expression: - case CCC_Statement: - case CCC_ForInit: - case CCC_Condition: + case PCC_Statement: + // For statements that are expressions, we prefer to call 'void' functions + // rather than functions that return a result, since then the result would + // be ignored. + Results.setPreferredType(Context.VoidTy); + // Fall through + + case PCC_Expression: + case PCC_ForInit: + case PCC_Condition: if (WantTypesInContext(CompletionContext, getLangOptions())) Results.setFilter(&ResultBuilder::IsOrdinaryName); else Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName); + + if (getLangOptions().CPlusPlus) + MaybeAddOverrideCalls(*this, /*InContext=*/0, Results); break; - case CCC_RecoveryInFunction: + case PCC_RecoveryInFunction: // Unfiltered break; } + // If we are in a C++ non-static member function, check the qualifiers on + // the member function to filter/prioritize the results list. + if (CXXMethodDecl *CurMethod = dyn_cast(CurContext)) + if (CurMethod->isInstance()) + Results.setObjectTypeQualifiers( + Qualifiers::fromCVRMask(CurMethod->getTypeQualifiers())); + CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); - Results.EnterNewScope(); AddOrdinaryNameResults(CompletionContext, S, *this, Results); Results.ExitScope(); + switch (CompletionContext) { + case PCC_Expression: + case PCC_Statement: + case PCC_RecoveryInFunction: + if (S->getFnParent()) + AddPrettyFunctionResults(PP.getLangOptions(), Results); + break; + + case PCC_Namespace: + case PCC_Class: + case PCC_ObjCInterface: + case PCC_ObjCImplementation: + case PCC_ObjCInstanceVariableList: + case PCC_Template: + case PCC_MemberTemplate: + case PCC_ForInit: + case PCC_Condition: + case PCC_Type: + break; + } + if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + + HandleCodeCompleteResults(this, CodeCompleter, + mapCodeCompletionContext(*this, CompletionContext), + Results.data(),Results.size()); +} + +void Sema::CodeCompleteDeclarator(Scope *S, + bool AllowNonIdentifiers, + bool AllowNestedNameSpecifiers) { + typedef CodeCompletionResult Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Type qualifiers can come after names. + Results.AddResult(Result("const")); + Results.AddResult(Result("volatile")); + if (getLangOptions().C99) + Results.AddResult(Result("restrict")); + + if (getLangOptions().CPlusPlus) { + if (AllowNonIdentifiers) { + Results.AddResult(Result("operator")); + } + + // Add nested-name-specifiers. + if (AllowNestedNameSpecifiers) { + Results.allowNestedNameSpecifiers(); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer, + CodeCompleter->includeGlobals()); + } + } + Results.ExitScope(); + + // Note that we intentionally suppress macro results here, since we do not + // encourage using macros to produce the names of entities. + + HandleCodeCompleteResults(this, CodeCompleter, + AllowNestedNameSpecifiers + ? CodeCompletionContext::CCC_PotentiallyQualifiedName + : CodeCompletionContext::CCC_Name, + Results.data(), Results.size()); } +struct Sema::CodeCompleteExpressionData { + CodeCompleteExpressionData(QualType PreferredType = QualType()) + : PreferredType(PreferredType), IntegralConstantExpression(false), + ObjCCollection(false) { } + + QualType PreferredType; + bool IntegralConstantExpression; + bool ObjCCollection; + llvm::SmallVector IgnoreDecls; +}; + /// \brief Perform code-completion in an expression context when we know what /// type we're looking for. -void Sema::CodeCompleteExpression(Scope *S, QualType T) { - typedef CodeCompleteConsumer::Result Result; +/// +/// \param IntegralConstantExpression Only permit integral constant +/// expressions. +void Sema::CodeCompleteExpression(Scope *S, + const CodeCompleteExpressionData &Data) { + typedef CodeCompletionResult Result; ResultBuilder Results(*this); - if (WantTypesInContext(CCC_Expression, getLangOptions())) + if (Data.ObjCCollection) + Results.setFilter(&ResultBuilder::IsObjCCollection); + else if (Data.IntegralConstantExpression) + Results.setFilter(&ResultBuilder::IsIntegralConstantValue); + else if (WantTypesInContext(PCC_Expression, getLangOptions())) Results.setFilter(&ResultBuilder::IsOrdinaryName); else Results.setFilter(&ResultBuilder::IsOrdinaryNonTypeName); - Results.setPreferredType(T.getNonReferenceType()); + + if (!Data.PreferredType.isNull()) + Results.setPreferredType(Data.PreferredType.getNonReferenceType()); + + // Ignore any declarations that we were told that we don't care about. + for (unsigned I = 0, N = Data.IgnoreDecls.size(); I != N; ++I) + Results.Ignore(Data.IgnoreDecls[I]); CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); Results.EnterNewScope(); - AddOrdinaryNameResults(CCC_Expression, S, *this, Results); + AddOrdinaryNameResults(PCC_Expression, S, *this, Results); Results.ExitScope(); bool PreferredTypeIsPointer = false; - if (!T.isNull()) - PreferredTypeIsPointer = T->isAnyPointerType() || - T->isMemberPointerType() || T->isBlockPointerType(); + if (!Data.PreferredType.isNull()) + PreferredTypeIsPointer = Data.PreferredType->isAnyPointerType() + || Data.PreferredType->isMemberPointerType() + || Data.PreferredType->isBlockPointerType(); + if (S->getFnParent() && + !Data.ObjCCollection && + !Data.IntegralConstantExpression) + AddPrettyFunctionResults(PP.getLangOptions(), Results); + if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results, PreferredTypeIsPointer); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext(CodeCompletionContext::CCC_Expression, + Data.PreferredType), + Results.data(),Results.size()); } @@ -2303,7 +2725,7 @@ static void AddObjCProperties(ObjCContainerDecl *Container, bool AllowCategories, DeclContext *CurContext, ResultBuilder &Results) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; // Add properties in this container. for (ObjCContainerDecl::prop_iterator P = Container->prop_begin(), @@ -2327,9 +2749,9 @@ static void AddObjCProperties(ObjCContainerDecl *Container, } // Look through protocols. - for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(), - E = IFace->protocol_end(); - I != E; ++I) + for (ObjCInterfaceDecl::all_protocol_iterator + I = IFace->all_referenced_protocol_begin(), + E = IFace->all_referenced_protocol_end(); I != E; ++I) AddObjCProperties(*I, AllowCategories, CurContext, Results); // Look in the superclass. @@ -2339,8 +2761,8 @@ static void AddObjCProperties(ObjCContainerDecl *Container, } else if (const ObjCCategoryDecl *Category = dyn_cast(Container)) { // Look through protocols. - for (ObjCInterfaceDecl::protocol_iterator P = Category->protocol_begin(), - PEnd = Category->protocol_end(); + for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(), + PEnd = Category->protocol_end(); P != PEnd; ++P) AddObjCProperties(*P, AllowCategories, CurContext, Results); } @@ -2352,7 +2774,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, if (!BaseE || !CodeCompleter) return; - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; Expr *Base = static_cast(BaseE); QualType BaseType = Base->getType(); @@ -2361,7 +2783,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, if (const PointerType *Ptr = BaseType->getAs()) BaseType = Ptr->getPointeeType(); else if (BaseType->isObjCObjectPointerType()) - /*Do nothing*/ ; + /*Do nothing*/ ; else return; } @@ -2369,10 +2791,15 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, ResultBuilder Results(*this, &ResultBuilder::IsMember); Results.EnterNewScope(); if (const RecordType *Record = BaseType->getAs()) { + // Indicate that we are performing a member access, and the cv-qualifiers + // for the base object type. + Results.setObjectTypeQualifiers(BaseType.getQualifiers()); + // Access to a C/C++ class, struct, or union. Results.allowNestedNameSpecifiers(); CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer); + LookupVisibleDecls(Record->getDecl(), LookupMemberName, Consumer, + CodeCompleter->includeGlobals()); if (getLangOptions().CPlusPlus) { if (!Results.empty()) { @@ -2420,7 +2847,8 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, if (Class) { CodeCompletionDeclConsumer Consumer(Results, CurContext); Results.setFilter(&ResultBuilder::IsObjCIvar); - LookupVisibleDecls(Class, LookupMemberName, Consumer); + LookupVisibleDecls(Class, LookupMemberName, Consumer, + CodeCompleter->includeGlobals()); } } @@ -2429,27 +2857,35 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, ExprTy *BaseE, Results.ExitScope(); // Hand off the results found for code completion. - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext(CodeCompletionContext::CCC_MemberAccess, + BaseType), + Results.data(),Results.size()); } void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { if (!CodeCompleter) return; - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; ResultBuilder::LookupFilter Filter = 0; + enum CodeCompletionContext::Kind ContextKind + = CodeCompletionContext::CCC_Other; switch ((DeclSpec::TST)TagSpec) { case DeclSpec::TST_enum: Filter = &ResultBuilder::IsEnum; + ContextKind = CodeCompletionContext::CCC_EnumTag; break; case DeclSpec::TST_union: Filter = &ResultBuilder::IsUnion; + ContextKind = CodeCompletionContext::CCC_UnionTag; break; case DeclSpec::TST_struct: case DeclSpec::TST_class: Filter = &ResultBuilder::IsClassOrStruct; + ContextKind = CodeCompletionContext::CCC_ClassOrStructTag; break; default: @@ -2462,22 +2898,46 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { // First pass: look for tags. Results.setFilter(Filter); - LookupVisibleDecls(S, LookupTagName, Consumer); + LookupVisibleDecls(S, LookupTagName, Consumer, + CodeCompleter->includeGlobals()); - // Second pass: look for nested name specifiers. - Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); - LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer); + if (CodeCompleter->includeGlobals()) { + // Second pass: look for nested name specifiers. + Results.setFilter(&ResultBuilder::IsNestedNameSpecifier); + LookupVisibleDecls(S, LookupNestedNameSpecifierName, Consumer); + } - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, ContextKind, + Results.data(),Results.size()); +} + +void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + if (!(DS.getTypeQualifiers() & DeclSpec::TQ_const)) + Results.AddResult("const"); + if (!(DS.getTypeQualifiers() & DeclSpec::TQ_volatile)) + Results.AddResult("volatile"); + if (getLangOptions().C99 && + !(DS.getTypeQualifiers() & DeclSpec::TQ_restrict)) + Results.AddResult("restrict"); + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_TypeQualifiers, + Results.data(), Results.size()); } void Sema::CodeCompleteCase(Scope *S) { - if (getSwitchStack().empty() || !CodeCompleter) + if (getCurFunction()->SwitchStack.empty() || !CodeCompleter) return; - SwitchStmt *Switch = getSwitchStack().back(); - if (!Switch->getCond()->getType()->isEnumeralType()) + SwitchStmt *Switch = getCurFunction()->SwitchStack.back(); + if (!Switch->getCond()->getType()->isEnumeralType()) { + CodeCompleteExpressionData Data(Switch->getCond()->getType()); + Data.IntegralConstantExpression = true; + CodeCompleteExpression(S, Data); return; + } // Code-complete the cases of a switch statement over an enumeration type // by providing the list of @@ -2541,14 +3001,16 @@ void Sema::CodeCompleteCase(Scope *S) { if (EnumeratorsSeen.count(*E)) continue; - Results.AddResult(CodeCompleteConsumer::Result(*E, Qualifier), + Results.AddResult(CodeCompletionResult(*E, Qualifier), CurContext, 0, false); } Results.ExitScope(); if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Expression, + Results.data(),Results.size()); } namespace { @@ -2562,7 +3024,7 @@ namespace { bool operator()(const OverloadCandidate &X, const OverloadCandidate &Y) const { - return S.isBetterOverloadCandidate(X, Y, Loc); + return isBetterOverloadCandidate(S, X, Y, Loc); } }; } @@ -2594,7 +3056,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, // Ignore type-dependent call expressions entirely. if (!Fn || Fn->isTypeDependent() || anyNullArguments(Args, NumArgs) || Expr::hasAnyTypeDependentArguments(Args, NumArgs)) { - CodeCompleteOrdinaryName(S, CCC_Expression); + CodeCompleteOrdinaryName(S, PCC_Expression); return; } @@ -2678,7 +3140,7 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, } if (ParamType.isNull()) - CodeCompleteOrdinaryName(S, CCC_Expression); + CodeCompleteOrdinaryName(S, PCC_Expression); else CodeCompleteExpression(S, ParamType); @@ -2687,10 +3149,10 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn, Results.size()); } -void Sema::CodeCompleteInitializer(Scope *S, DeclPtrTy D) { - ValueDecl *VD = dyn_cast_or_null(D.getAs()); +void Sema::CodeCompleteInitializer(Scope *S, Decl *D) { + ValueDecl *VD = dyn_cast_or_null(D); if (!VD) { - CodeCompleteOrdinaryName(S, CCC_Expression); + CodeCompleteOrdinaryName(S, PCC_Expression); return; } @@ -2708,7 +3170,7 @@ void Sema::CodeCompleteReturn(Scope *S) { ResultType = Method->getResultType(); if (ResultType.isNull()) - CodeCompleteOrdinaryName(S, CCC_Expression); + CodeCompleteOrdinaryName(S, PCC_Expression); else CodeCompleteExpression(S, ResultType); } @@ -2717,7 +3179,7 @@ void Sema::CodeCompleteAssignmentRHS(Scope *S, ExprTy *LHS) { if (LHS) CodeCompleteExpression(S, static_cast(LHS)->getType()); else - CodeCompleteOrdinaryName(S, CCC_Expression); + CodeCompleteOrdinaryName(S, PCC_Expression); } void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, @@ -2735,16 +3197,29 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, return; ResultBuilder Results(*this); - CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer); + Results.EnterNewScope(); // The "template" keyword can follow "::" in the grammar, but only // put it into the grammar if the nested-name-specifier is dependent. NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); if (!Results.empty() && NNS->isDependent()) Results.AddResult("template"); + + // Add calls to overridden virtual functions, if there are any. + // + // FIXME: This isn't wonderful, because we don't know whether we're actually + // in a context that permits expressions. This is a general issue with + // qualified-id completions. + if (!EnteringContext) + MaybeAddOverrideCalls(*this, Ctx, Results); + Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer); + + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Name, + Results.data(),Results.size()); } void Sema::CodeCompleteUsing(Scope *S) { @@ -2756,15 +3231,18 @@ void Sema::CodeCompleteUsing(Scope *S) { // If we aren't in class scope, we could see the "namespace" keyword. if (!S->isClassScope()) - Results.AddResult(CodeCompleteConsumer::Result("namespace")); + Results.AddResult(CodeCompletionResult("namespace")); // After "using", we can see anything that would start a // nested-name-specifier. CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } void Sema::CodeCompleteUsingDirective(Scope *S) { @@ -2776,9 +3254,12 @@ void Sema::CodeCompleteUsingDirective(Scope *S) { ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); Results.EnterNewScope(); CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Namespace, + Results.data(),Results.size()); } void Sema::CodeCompleteNamespaceDecl(Scope *S) { @@ -2807,12 +3288,14 @@ void Sema::CodeCompleteNamespaceDecl(Scope *S) { for (std::map::iterator NS = OrigToLatest.begin(), NSEnd = OrigToLatest.end(); NS != NSEnd; ++NS) - Results.AddResult(CodeCompleteConsumer::Result(NS->second, 0), + Results.AddResult(CodeCompletionResult(NS->second, 0), CurContext, 0, false); Results.ExitScope(); } - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { @@ -2822,15 +3305,18 @@ void Sema::CodeCompleteNamespaceAliasDecl(Scope *S) { // After "namespace", we expect to see a namespace or alias. ResultBuilder Results(*this, &ResultBuilder::IsNamespaceOrAlias); CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Namespace, + Results.data(),Results.size()); } void Sema::CodeCompleteOperatorName(Scope *S) { if (!CodeCompleter) return; - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; ResultBuilder Results(*this, &ResultBuilder::IsType); Results.EnterNewScope(); @@ -2843,13 +3329,122 @@ void Sema::CodeCompleteOperatorName(Scope *S) { // Add any type names visible from the current scope Results.allowNestedNameSpecifiers(); CodeCompletionDeclConsumer Consumer(Results, CurContext); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); // Add any type specifiers AddTypeSpecifierResults(getLangOptions(), Results); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Type, + Results.data(),Results.size()); +} + +void Sema::CodeCompleteConstructorInitializer(Decl *ConstructorD, + CXXBaseOrMemberInitializer** Initializers, + unsigned NumInitializers) { + CXXConstructorDecl *Constructor + = static_cast(ConstructorD); + if (!Constructor) + return; + + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Fill in any already-initialized fields or base classes. + llvm::SmallPtrSet InitializedFields; + llvm::SmallPtrSet InitializedBases; + for (unsigned I = 0; I != NumInitializers; ++I) { + if (Initializers[I]->isBaseInitializer()) + InitializedBases.insert( + Context.getCanonicalType(QualType(Initializers[I]->getBaseClass(), 0))); + else + InitializedFields.insert(cast(Initializers[I]->getMember())); + } + + // Add completions for base classes. + bool SawLastInitializer = (NumInitializers == 0); + CXXRecordDecl *ClassDecl = Constructor->getParent(); + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(), + BaseEnd = ClassDecl->bases_end(); + Base != BaseEnd; ++Base) { + if (!InitializedBases.insert(Context.getCanonicalType(Base->getType()))) { + SawLastInitializer + = NumInitializers > 0 && + Initializers[NumInitializers - 1]->isBaseInitializer() && + Context.hasSameUnqualifiedType(Base->getType(), + QualType(Initializers[NumInitializers - 1]->getBaseClass(), 0)); + continue; + } + + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk( + Base->getType().getAsString(Context.PrintingPolicy)); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("args"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(CodeCompletionResult(Pattern, + SawLastInitializer? CCP_NextInitializer + : CCP_MemberDeclaration)); + SawLastInitializer = false; + } + + // Add completions for virtual base classes. + for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), + BaseEnd = ClassDecl->vbases_end(); + Base != BaseEnd; ++Base) { + if (!InitializedBases.insert(Context.getCanonicalType(Base->getType()))) { + SawLastInitializer + = NumInitializers > 0 && + Initializers[NumInitializers - 1]->isBaseInitializer() && + Context.hasSameUnqualifiedType(Base->getType(), + QualType(Initializers[NumInitializers - 1]->getBaseClass(), 0)); + continue; + } + + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk( + Base->getType().getAsString(Context.PrintingPolicy)); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("args"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(CodeCompletionResult(Pattern, + SawLastInitializer? CCP_NextInitializer + : CCP_MemberDeclaration)); + SawLastInitializer = false; + } + + // Add completions for members. + for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), + FieldEnd = ClassDecl->field_end(); + Field != FieldEnd; ++Field) { + if (!InitializedFields.insert(cast(Field->getCanonicalDecl()))) { + SawLastInitializer + = NumInitializers > 0 && + Initializers[NumInitializers - 1]->isMemberInitializer() && + Initializers[NumInitializers - 1]->getMember() == *Field; + continue; + } + + if (!Field->getDeclName()) + continue; + + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk(Field->getIdentifier()->getName()); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("args"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(CodeCompletionResult(Pattern, + SawLastInitializer? CCP_NextInitializer + : CCP_MemberDeclaration)); + SawLastInitializer = false; + } + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Name, + Results.data(), Results.size()); } // Macro that expands to @Keyword or Keyword, depending on whether NeedAt is @@ -2858,7 +3453,7 @@ void Sema::CodeCompleteOperatorName(Scope *S) { static void AddObjCImplementationResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; // Since we have an implementation, we can end it. Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end))); @@ -2883,7 +3478,7 @@ static void AddObjCImplementationResults(const LangOptions &LangOpts, static void AddObjCInterfaceResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; // Since we have an interface or protocol, we can end it. Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,end))); @@ -2901,7 +3496,7 @@ static void AddObjCInterfaceResults(const LangOptions &LangOpts, } static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; CodeCompletionString *Pattern = 0; // @class name ; @@ -2946,9 +3541,9 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { Results.AddResult(Result(Pattern)); } -void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, +void Sema::CodeCompleteObjCAtDirective(Scope *S, Decl *ObjCImpDecl, bool InInterface) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; ResultBuilder Results(*this); Results.EnterNewScope(); if (ObjCImpDecl) @@ -2958,11 +3553,13 @@ void Sema::CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl, else AddObjCTopLevelResults(Results, false); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; CodeCompletionString *Pattern = 0; // @encode ( type-name ) @@ -2991,7 +3588,7 @@ static void AddObjCExpressionResults(ResultBuilder &Results, bool NeedAt) { } static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; CodeCompletionString *Pattern = 0; if (Results.includeCodePatterns()) { @@ -3041,7 +3638,7 @@ static void AddObjCStatementResults(ResultBuilder &Results, bool NeedAt) { static void AddObjCVisibilityResults(const LangOptions &LangOpts, ResultBuilder &Results, bool NeedAt) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,private))); Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,protected))); Results.AddResult(Result(OBJC_AT_KEYWORD_NAME(NeedAt,public))); @@ -3054,7 +3651,9 @@ void Sema::CodeCompleteObjCAtVisibility(Scope *S) { Results.EnterNewScope(); AddObjCVisibilityResults(getLangOptions(), Results, false); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } void Sema::CodeCompleteObjCAtStatement(Scope *S) { @@ -3063,7 +3662,9 @@ void Sema::CodeCompleteObjCAtStatement(Scope *S) { AddObjCStatementResults(Results, false); AddObjCExpressionResults(Results, false); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } void Sema::CodeCompleteObjCAtExpression(Scope *S) { @@ -3071,7 +3672,9 @@ void Sema::CodeCompleteObjCAtExpression(Scope *S) { Results.EnterNewScope(); AddObjCExpressionResults(Results, false); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } /// \brief Determine whether the addition of the given flag to an Objective-C @@ -3110,37 +3713,39 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { unsigned Attributes = ODS.getPropertyAttributes(); - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; ResultBuilder Results(*this); Results.EnterNewScope(); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readonly)) - Results.AddResult(CodeCompleteConsumer::Result("readonly")); + Results.AddResult(CodeCompletionResult("readonly")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_assign)) - Results.AddResult(CodeCompleteConsumer::Result("assign")); + Results.AddResult(CodeCompletionResult("assign")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readwrite)) - Results.AddResult(CodeCompleteConsumer::Result("readwrite")); + Results.AddResult(CodeCompletionResult("readwrite")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_retain)) - Results.AddResult(CodeCompleteConsumer::Result("retain")); + Results.AddResult(CodeCompletionResult("retain")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_copy)) - Results.AddResult(CodeCompleteConsumer::Result("copy")); + Results.AddResult(CodeCompletionResult("copy")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic)) - Results.AddResult(CodeCompleteConsumer::Result("nonatomic")); + Results.AddResult(CodeCompletionResult("nonatomic")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) { CodeCompletionString *Setter = new CodeCompletionString; Setter->AddTypedTextChunk("setter"); Setter->AddTextChunk(" = "); Setter->AddPlaceholderChunk("method"); - Results.AddResult(CodeCompleteConsumer::Result(Setter)); + Results.AddResult(CodeCompletionResult(Setter)); } if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_getter)) { CodeCompletionString *Getter = new CodeCompletionString; Getter->AddTypedTextChunk("getter"); Getter->AddTextChunk(" = "); Getter->AddPlaceholderChunk("method"); - Results.AddResult(CodeCompleteConsumer::Result(Getter)); + Results.AddResult(CodeCompletionResult(Getter)); } Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } /// \brief Descripts the kind of Objective-C method that we want to find @@ -3151,26 +3756,33 @@ enum ObjCMethodKind { MK_OneArgSelector //< One-argument selector. }; -static bool isAcceptableObjCMethod(ObjCMethodDecl *Method, - ObjCMethodKind WantKind, - IdentifierInfo **SelIdents, - unsigned NumSelIdents) { - Selector Sel = Method->getSelector(); +static bool isAcceptableObjCSelector(Selector Sel, + ObjCMethodKind WantKind, + IdentifierInfo **SelIdents, + unsigned NumSelIdents) { if (NumSelIdents > Sel.getNumArgs()) return false; - + switch (WantKind) { - case MK_Any: break; - case MK_ZeroArgSelector: return Sel.isUnarySelector(); - case MK_OneArgSelector: return Sel.getNumArgs() == 1; + case MK_Any: break; + case MK_ZeroArgSelector: return Sel.isUnarySelector(); + case MK_OneArgSelector: return Sel.getNumArgs() == 1; } - + for (unsigned I = 0; I != NumSelIdents; ++I) if (SelIdents[I] != Sel.getIdentifierInfoForSlot(I)) return false; - + return true; } + +static bool isAcceptableObjCMethod(ObjCMethodDecl *Method, + ObjCMethodKind WantKind, + IdentifierInfo **SelIdents, + unsigned NumSelIdents) { + return isAcceptableObjCSelector(Method->getSelector(), WantKind, SelIdents, + NumSelIdents); +} /// \brief Add all of the Objective-C methods in the given Objective-C /// container to the set of results. @@ -3195,8 +3807,9 @@ static void AddObjCMethods(ObjCContainerDecl *Container, IdentifierInfo **SelIdents, unsigned NumSelIdents, DeclContext *CurContext, - ResultBuilder &Results) { - typedef CodeCompleteConsumer::Result Result; + ResultBuilder &Results, + bool InOriginalClass = true) { + typedef CodeCompletionResult Result; for (ObjCContainerDecl::method_iterator M = Container->meth_begin(), MEnd = Container->meth_end(); M != MEnd; ++M) { @@ -3209,6 +3822,8 @@ static void AddObjCMethods(ObjCContainerDecl *Container, Result R = Result(*M, 0); R.StartParameter = NumSelIdents; R.AllParametersAreInformative = (WantKind != MK_Any); + if (!InOriginalClass) + R.Priority += CCD_InBaseClass; Results.MaybeAddResult(R, CurContext); } } @@ -3223,13 +3838,13 @@ static void AddObjCMethods(ObjCContainerDecl *Container, E = Protocols.end(); I != E; ++I) AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, NumSelIdents, - CurContext, Results); + CurContext, Results, false); // Add methods in categories. for (ObjCCategoryDecl *CatDecl = IFace->getCategoryList(); CatDecl; CatDecl = CatDecl->getNextClassCategory()) { AddObjCMethods(CatDecl, WantInstanceMethods, WantKind, SelIdents, - NumSelIdents, CurContext, Results); + NumSelIdents, CurContext, Results, InOriginalClass); // Add a categories protocol methods. const ObjCList &Protocols @@ -3238,37 +3853,36 @@ static void AddObjCMethods(ObjCContainerDecl *Container, E = Protocols.end(); I != E; ++I) AddObjCMethods(*I, WantInstanceMethods, WantKind, SelIdents, - NumSelIdents, CurContext, Results); + NumSelIdents, CurContext, Results, false); // Add methods in category implementations. if (ObjCCategoryImplDecl *Impl = CatDecl->getImplementation()) AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, - NumSelIdents, CurContext, Results); + NumSelIdents, CurContext, Results, InOriginalClass); } // Add methods in superclass. if (IFace->getSuperClass()) AddObjCMethods(IFace->getSuperClass(), WantInstanceMethods, WantKind, - SelIdents, NumSelIdents, CurContext, Results); + SelIdents, NumSelIdents, CurContext, Results, false); // Add methods in our implementation, if any. if (ObjCImplementationDecl *Impl = IFace->getImplementation()) AddObjCMethods(Impl, WantInstanceMethods, WantKind, SelIdents, - NumSelIdents, CurContext, Results); + NumSelIdents, CurContext, Results, InOriginalClass); } -void Sema::CodeCompleteObjCPropertyGetter(Scope *S, DeclPtrTy ClassDecl, - DeclPtrTy *Methods, +void Sema::CodeCompleteObjCPropertyGetter(Scope *S, Decl *ClassDecl, + Decl **Methods, unsigned NumMethods) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; // Try to find the interface where getters might live. - ObjCInterfaceDecl *Class - = dyn_cast_or_null(ClassDecl.getAs()); + ObjCInterfaceDecl *Class = dyn_cast_or_null(ClassDecl); if (!Class) { if (ObjCCategoryDecl *Category - = dyn_cast_or_null(ClassDecl.getAs())) + = dyn_cast_or_null(ClassDecl)) Class = Category->getClassInterface(); if (!Class) @@ -3283,7 +3897,7 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S, DeclPtrTy ClassDecl, // pushed into DeclContexts early enough. Argh! for (unsigned I = 0; I != NumMethods; ++I) { if (ObjCMethodDecl *Method - = dyn_cast_or_null(Methods[I].getAs())) + = dyn_cast_or_null(Methods[I])) if (Method->isInstanceMethod() && isAcceptableObjCMethod(Method, MK_ZeroArgSelector, 0, 0)) { Result R = Result(Method, 0); @@ -3294,20 +3908,22 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S, DeclPtrTy ClassDecl, AddObjCMethods(Class, true, MK_ZeroArgSelector, 0, 0, CurContext, Results); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter,Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } -void Sema::CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ObjCImplDecl, - DeclPtrTy *Methods, +void Sema::CodeCompleteObjCPropertySetter(Scope *S, Decl *ObjCImplDecl, + Decl **Methods, unsigned NumMethods) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; // Try to find the interface where setters might live. ObjCInterfaceDecl *Class - = dyn_cast_or_null(ObjCImplDecl.getAs()); + = dyn_cast_or_null(ObjCImplDecl); if (!Class) { if (ObjCCategoryDecl *Category - = dyn_cast_or_null(ObjCImplDecl.getAs())) + = dyn_cast_or_null(ObjCImplDecl)) Class = Category->getClassInterface(); if (!Class) @@ -3322,7 +3938,7 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ObjCImplDecl, // pushed into DeclContexts early enough. Argh! for (unsigned I = 0; I != NumMethods; ++I) { if (ObjCMethodDecl *Method - = dyn_cast_or_null(Methods[I].getAs())) + = dyn_cast_or_null(Methods[I])) if (Method->isInstanceMethod() && isAcceptableObjCMethod(Method, MK_OneArgSelector, 0, 0)) { Result R = Result(Method, 0); @@ -3334,7 +3950,54 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S, DeclPtrTy ObjCImplDecl, AddObjCMethods(Class, true, MK_OneArgSelector, 0, 0, CurContext, Results); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter,Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS) { + typedef CodeCompletionResult Result; + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // Add context-sensitive, Objective-C parameter-passing keywords. + bool AddedInOut = false; + if ((DS.getObjCDeclQualifier() & + (ObjCDeclSpec::DQ_In | ObjCDeclSpec::DQ_Inout)) == 0) { + Results.AddResult("in"); + Results.AddResult("inout"); + AddedInOut = true; + } + if ((DS.getObjCDeclQualifier() & + (ObjCDeclSpec::DQ_Out | ObjCDeclSpec::DQ_Inout)) == 0) { + Results.AddResult("out"); + if (!AddedInOut) + Results.AddResult("inout"); + } + if ((DS.getObjCDeclQualifier() & + (ObjCDeclSpec::DQ_Bycopy | ObjCDeclSpec::DQ_Byref | + ObjCDeclSpec::DQ_Oneway)) == 0) { + Results.AddResult("bycopy"); + Results.AddResult("byref"); + Results.AddResult("oneway"); + } + + // Add various builtin type names and specifiers. + AddOrdinaryNameResults(PCC_Type, S, *this, Results); + Results.ExitScope(); + + // Add the various type names + Results.setFilter(&ResultBuilder::IsOrdinaryNonValueName); + CodeCompletionDeclConsumer Consumer(Results, CurContext); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); + + if (CodeCompleter->includeMacros()) + AddMacroResults(PP, Results); + + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Type, + Results.data(), Results.size()); } /// \brief When we have an expression with type "id", we may assume @@ -3407,28 +4070,138 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { .Default(0); } +// Add a special completion for a message send to "super", which fills in the +// most likely case of forwarding all of our arguments to the superclass +// function. +/// +/// \param S The semantic analysis object. +/// +/// \param S NeedSuperKeyword Whether we need to prefix this completion with +/// the "super" keyword. Otherwise, we just need to provide the arguments. +/// +/// \param SelIdents The identifiers in the selector that have already been +/// provided as arguments for a send to "super". +/// +/// \param NumSelIdents The number of identifiers in \p SelIdents. +/// +/// \param Results The set of results to augment. +/// +/// \returns the Objective-C method declaration that would be invoked by +/// this "super" completion. If NULL, no completion was added. +static ObjCMethodDecl *AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword, + IdentifierInfo **SelIdents, + unsigned NumSelIdents, + ResultBuilder &Results) { + ObjCMethodDecl *CurMethod = S.getCurMethodDecl(); + if (!CurMethod) + return 0; + + ObjCInterfaceDecl *Class = CurMethod->getClassInterface(); + if (!Class) + return 0; + + // Try to find a superclass method with the same selector. + ObjCMethodDecl *SuperMethod = 0; + while ((Class = Class->getSuperClass()) && !SuperMethod) + SuperMethod = Class->getMethod(CurMethod->getSelector(), + CurMethod->isInstanceMethod()); + + if (!SuperMethod) + return 0; + + // Check whether the superclass method has the same signature. + if (CurMethod->param_size() != SuperMethod->param_size() || + CurMethod->isVariadic() != SuperMethod->isVariadic()) + return 0; + + for (ObjCMethodDecl::param_iterator CurP = CurMethod->param_begin(), + CurPEnd = CurMethod->param_end(), + SuperP = SuperMethod->param_begin(); + CurP != CurPEnd; ++CurP, ++SuperP) { + // Make sure the parameter types are compatible. + if (!S.Context.hasSameUnqualifiedType((*CurP)->getType(), + (*SuperP)->getType())) + return 0; + + // Make sure we have a parameter name to forward! + if (!(*CurP)->getIdentifier()) + return 0; + } + + // We have a superclass method. Now, form the send-to-super completion. + CodeCompletionString *Pattern = new CodeCompletionString; + + // Give this completion a return type. + AddResultTypeChunk(S.Context, SuperMethod, Pattern); + + // If we need the "super" keyword, add it (plus some spacing). + if (NeedSuperKeyword) { + Pattern->AddTypedTextChunk("super"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + } + + Selector Sel = CurMethod->getSelector(); + if (Sel.isUnarySelector()) { + if (NeedSuperKeyword) + Pattern->AddTextChunk(Sel.getIdentifierInfoForSlot(0)->getName()); + else + Pattern->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName()); + } else { + ObjCMethodDecl::param_iterator CurP = CurMethod->param_begin(); + for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I, ++CurP) { + if (I > NumSelIdents) + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + + if (I < NumSelIdents) + Pattern->AddInformativeChunk( + Sel.getIdentifierInfoForSlot(I)->getName().str() + ":"); + else if (NeedSuperKeyword || I > NumSelIdents) { + Pattern->AddTextChunk( + Sel.getIdentifierInfoForSlot(I)->getName().str() + ":"); + Pattern->AddPlaceholderChunk((*CurP)->getIdentifier()->getName()); + } else { + Pattern->AddTypedTextChunk( + Sel.getIdentifierInfoForSlot(I)->getName().str() + ":"); + Pattern->AddPlaceholderChunk((*CurP)->getIdentifier()->getName()); + } + } + } + + Results.AddResult(CodeCompletionResult(Pattern, CCP_SuperCompletion, + SuperMethod->isInstanceMethod() + ? CXCursor_ObjCInstanceMethodDecl + : CXCursor_ObjCClassMethodDecl)); + return SuperMethod; +} + void Sema::CodeCompleteObjCMessageReceiver(Scope *S) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; ResultBuilder Results(*this); // Find anything that looks like it could be a message receiver. Results.setFilter(&ResultBuilder::IsObjCMessageReceiver); CodeCompletionDeclConsumer Consumer(Results, CurContext); Results.EnterNewScope(); - LookupVisibleDecls(S, LookupOrdinaryName, Consumer); + LookupVisibleDecls(S, LookupOrdinaryName, Consumer, + CodeCompleter->includeGlobals()); // If we are in an Objective-C method inside a class that has a superclass, // add "super" as an option. if (ObjCMethodDecl *Method = getCurMethodDecl()) if (ObjCInterfaceDecl *Iface = Method->getClassInterface()) - if (Iface->getSuperClass()) + if (Iface->getSuperClass()) { Results.AddResult(Result("super")); + + AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, 0, 0, Results); + } Results.ExitScope(); if (CodeCompleter->includeMacros()) AddMacroResults(PP, Results); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_ObjCMessageReceiver, + Results.data(), Results.size()); } @@ -3454,10 +4227,11 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, // an instance method. QualType SuperTy = Context.getObjCInterfaceType(CDecl); SuperTy = Context.getObjCObjectPointerType(SuperTy); - OwningExprResult Super + ExprResult Super = Owned(new (Context) ObjCSuperExpr(SuperLoc, SuperTy)); return CodeCompleteObjCInstanceMessage(S, (Expr *)Super.get(), - SelIdents, NumSelIdents); + SelIdents, NumSelIdents, + /*IsSuper=*/true); } // Fall through to send to the superclass in CDecl. @@ -3480,7 +4254,7 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, CXXScopeSpec SS; UnqualifiedId id; id.setIdentifier(Super, SuperLoc); - OwningExprResult SuperExpr = ActOnIdExpression(S, SS, id, false, false); + ExprResult SuperExpr = ActOnIdExpression(S, SS, id, false, false); return CodeCompleteObjCInstanceMessage(S, (Expr *)SuperExpr.get(), SelIdents, NumSelIdents); } @@ -3488,17 +4262,24 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, // Fall through } - TypeTy *Receiver = 0; + ParsedType Receiver; if (CDecl) - Receiver = Context.getObjCInterfaceType(CDecl).getAsOpaquePtr(); + Receiver = ParsedType::make(Context.getObjCInterfaceType(CDecl)); return CodeCompleteObjCClassMessage(S, Receiver, SelIdents, - NumSelIdents); + NumSelIdents, /*IsSuper=*/true); } -void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, +void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, IdentifierInfo **SelIdents, unsigned NumSelIdents) { - typedef CodeCompleteConsumer::Result Result; + CodeCompleteObjCClassMessage(S, Receiver, SelIdents, NumSelIdents, false); +} + +void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, + IdentifierInfo **SelIdents, + unsigned NumSelIdents, + bool IsSuper) { + typedef CodeCompletionResult Result; ObjCInterfaceDecl *CDecl = 0; // If the given name refers to an interface type, retrieve the @@ -3515,6 +4296,20 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, ResultBuilder Results(*this); Results.EnterNewScope(); + // If this is a send-to-super, try to add the special "super" send + // completion. + if (IsSuper) { + if (ObjCMethodDecl *SuperMethod + = AddSuperSendCompletion(*this, false, SelIdents, NumSelIdents, + Results)) + Results.Ignore(SuperMethod); + } + + // If we're inside an Objective-C method definition, prefer its selector to + // others. + if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) + Results.setPreferredSelector(CurMethod->getSelector()); + if (CDecl) AddObjCMethods(CDecl, false, MK_Any, SelIdents, NumSelIdents, CurContext, Results); @@ -3522,25 +4317,23 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, // We're messaging "id" as a type; provide all class/factory methods. // If we have an external source, load the entire class method - // pool from the PCH file. + // pool from the AST file. if (ExternalSource) { for (uint32_t I = 0, N = ExternalSource->GetNumExternalSelectors(); I != N; ++I) { Selector Sel = ExternalSource->GetExternalSelector(I); - if (Sel.isNull() || FactoryMethodPool.count(Sel) || - InstanceMethodPool.count(Sel)) + if (Sel.isNull() || MethodPool.count(Sel)) continue; - ReadMethodPool(Sel, /*isInstance=*/false); + ReadMethodPool(Sel); } } - for (llvm::DenseMap::iterator - M = FactoryMethodPool.begin(), - MEnd = FactoryMethodPool.end(); - M != MEnd; - ++M) { - for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method; + for (GlobalMethodPool::iterator M = MethodPool.begin(), + MEnd = MethodPool.end(); + M != MEnd; ++M) { + for (ObjCMethodList *MethList = &M->second.second; + MethList && MethList->Method; MethList = MethList->Next) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) @@ -3555,13 +4348,22 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, TypeTy *Receiver, } Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(), Results.size()); } void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, IdentifierInfo **SelIdents, unsigned NumSelIdents) { - typedef CodeCompleteConsumer::Result Result; + CodeCompleteObjCInstanceMessage(S, Receiver, SelIdents, NumSelIdents, false); +} + +void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, + IdentifierInfo **SelIdents, + unsigned NumSelIdents, + bool IsSuper) { + typedef CodeCompletionResult Result; Expr *RecExpr = static_cast(Receiver); @@ -3574,6 +4376,20 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, ResultBuilder Results(*this); Results.EnterNewScope(); + // If this is a send-to-super, try to add the special "super" send + // completion. + if (IsSuper) { + if (ObjCMethodDecl *SuperMethod + = AddSuperSendCompletion(*this, false, SelIdents, NumSelIdents, + Results)) + Results.Ignore(SuperMethod); + } + + // If we're inside an Objective-C method definition, prefer its selector to + // others. + if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) + Results.setPreferredSelector(CurMethod->getSelector()); + // If we're messaging an expression with type "id" or "Class", check // whether we know something special about the receiver that allows // us to assume a more-specific receiver type. @@ -3623,25 +4439,23 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, // about as code-completion results. // If we have an external source, load the entire class method - // pool from the PCH file. + // pool from the AST file. if (ExternalSource) { for (uint32_t I = 0, N = ExternalSource->GetNumExternalSelectors(); I != N; ++I) { Selector Sel = ExternalSource->GetExternalSelector(I); - if (Sel.isNull() || InstanceMethodPool.count(Sel) || - FactoryMethodPool.count(Sel)) + if (Sel.isNull() || MethodPool.count(Sel)) continue; - ReadMethodPool(Sel, /*isInstance=*/true); + ReadMethodPool(Sel); } } - for (llvm::DenseMap::iterator - M = InstanceMethodPool.begin(), - MEnd = InstanceMethodPool.end(); - M != MEnd; - ++M) { - for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method; + for (GlobalMethodPool::iterator M = MethodPool.begin(), + MEnd = MethodPool.end(); + M != MEnd; ++M) { + for (ObjCMethodList *MethList = &M->second.first; + MethList && MethList->Method; MethList = MethList->Next) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) @@ -3656,7 +4470,79 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, } Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); +} + +void Sema::CodeCompleteObjCForCollection(Scope *S, + DeclGroupPtrTy IterationVar) { + CodeCompleteExpressionData Data; + Data.ObjCCollection = true; + + if (IterationVar.getAsOpaquePtr()) { + DeclGroupRef DG = IterationVar.getAsVal(); + for (DeclGroupRef::iterator I = DG.begin(), End = DG.end(); I != End; ++I) { + if (*I) + Data.IgnoreDecls.push_back(*I); + } + } + + CodeCompleteExpression(S, Data); +} + +void Sema::CodeCompleteObjCSelector(Scope *S, IdentifierInfo **SelIdents, + unsigned NumSelIdents) { + // If we have an external source, load the entire class method + // pool from the AST file. + if (ExternalSource) { + for (uint32_t I = 0, N = ExternalSource->GetNumExternalSelectors(); + I != N; ++I) { + Selector Sel = ExternalSource->GetExternalSelector(I); + if (Sel.isNull() || MethodPool.count(Sel)) + continue; + + ReadMethodPool(Sel); + } + } + + ResultBuilder Results(*this); + Results.EnterNewScope(); + for (GlobalMethodPool::iterator M = MethodPool.begin(), + MEnd = MethodPool.end(); + M != MEnd; ++M) { + + Selector Sel = M->first; + if (!isAcceptableObjCSelector(Sel, MK_Any, SelIdents, NumSelIdents)) + continue; + + CodeCompletionString *Pattern = new CodeCompletionString; + if (Sel.isUnarySelector()) { + Pattern->AddTypedTextChunk(Sel.getIdentifierInfoForSlot(0)->getName()); + Results.AddResult(Pattern); + continue; + } + + std::string Accumulator; + for (unsigned I = 0, N = Sel.getNumArgs(); I != N; ++I) { + if (I == NumSelIdents) { + if (!Accumulator.empty()) { + Pattern->AddInformativeChunk(Accumulator); + Accumulator.clear(); + } + } + + Accumulator += Sel.getIdentifierInfoForSlot(I)->getName().str(); + Accumulator += ':'; + } + Pattern->AddTypedTextChunk(Accumulator); + Results.AddResult(Pattern); + } + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_SelectorName, + Results.data(), Results.size()); } /// \brief Add all of the protocol declarations that we find in the given @@ -3664,7 +4550,7 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, static void AddProtocolResults(DeclContext *Ctx, DeclContext *CurContext, bool OnlyForwardDeclarations, ResultBuilder &Results) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; for (DeclContext::decl_iterator D = Ctx->decls_begin(), DEnd = Ctx->decls_end(); @@ -3704,7 +4590,9 @@ void Sema::CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, Results); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_ObjCProtocolName, + Results.data(),Results.size()); } void Sema::CodeCompleteObjCProtocolDecl(Scope *) { @@ -3716,7 +4604,9 @@ void Sema::CodeCompleteObjCProtocolDecl(Scope *) { Results); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_ObjCProtocolName, + Results.data(),Results.size()); } /// \brief Add all of the Objective-C interface declarations that we find in @@ -3725,7 +4615,7 @@ static void AddInterfaceResults(DeclContext *Ctx, DeclContext *CurContext, bool OnlyForwardDeclarations, bool OnlyUnimplemented, ResultBuilder &Results) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; for (DeclContext::decl_iterator D = Ctx->decls_begin(), DEnd = Ctx->decls_end(); @@ -3757,7 +4647,9 @@ void Sema::CodeCompleteObjCInterfaceDecl(Scope *S) { false, Results); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, @@ -3776,7 +4668,9 @@ void Sema::CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, false, Results); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { @@ -3788,13 +4682,15 @@ void Sema::CodeCompleteObjCImplementationDecl(Scope *S) { true, Results); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; ResultBuilder Results(*this); @@ -3819,13 +4715,15 @@ void Sema::CodeCompleteObjCInterfaceCategory(Scope *S, Results.AddResult(Result(Category, 0), CurContext, 0, false); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } void Sema::CodeCompleteObjCImplementationCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc) { - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; // Find the corresponding interface. If we couldn't find the interface, the // program itself is ill-formed. However, we'll try to be helpful still by @@ -3856,16 +4754,18 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, } Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } -void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, DeclPtrTy ObjCImpDecl) { - typedef CodeCompleteConsumer::Result Result; +void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, Decl *ObjCImpDecl) { + typedef CodeCompletionResult Result; ResultBuilder Results(*this); // Figure out where this @synthesize lives. ObjCContainerDecl *Container - = dyn_cast_or_null(ObjCImpDecl.getAs()); + = dyn_cast_or_null(ObjCImpDecl); if (!Container || (!isa(Container) && !isa(Container))) @@ -3889,18 +4789,20 @@ void Sema::CodeCompleteObjCPropertyDefinition(Scope *S, DeclPtrTy ObjCImpDecl) { false, CurContext, Results); Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, IdentifierInfo *PropertyName, - DeclPtrTy ObjCImpDecl) { - typedef CodeCompleteConsumer::Result Result; + Decl *ObjCImpDecl) { + typedef CodeCompletionResult Result; ResultBuilder Results(*this); // Figure out where this @synthesize lives. ObjCContainerDecl *Container - = dyn_cast_or_null(ObjCImpDecl.getAs()); + = dyn_cast_or_null(ObjCImpDecl); if (!Container || (!isa(Container) && !isa(Container))) @@ -3927,10 +4829,15 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, } Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } -typedef llvm::DenseMap KnownMethodsMap; +// Mapping from selectors to the methods that implement that selector, along +// with the "in original class" flag. +typedef llvm::DenseMap > + KnownMethodsMap; /// \brief Find all of the methods that reside in the given container /// (and its superclasses, protocols, etc.) that meet the given @@ -3941,7 +4848,8 @@ static void FindImplementableMethods(ASTContext &Context, bool WantInstanceMethods, QualType ReturnType, bool IsInImplementation, - KnownMethodsMap &KnownMethods) { + KnownMethodsMap &KnownMethods, + bool InOriginalClass = true) { if (ObjCInterfaceDecl *IFace = dyn_cast(Container)) { // Recurse into protocols. const ObjCList &Protocols @@ -3950,14 +4858,16 @@ static void FindImplementableMethods(ASTContext &Context, E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods); + IsInImplementation, KnownMethods, + InOriginalClass); // If we're not in the implementation of a class, also visit the // superclass. if (!IsInImplementation && IFace->getSuperClass()) FindImplementableMethods(Context, IFace->getSuperClass(), WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods); + IsInImplementation, KnownMethods, + false); // Add methods from any class extensions (but not from categories; // those should go into category implementations). @@ -3965,7 +4875,8 @@ static void FindImplementableMethods(ASTContext &Context, Cat = Cat->getNextClassExtension()) FindImplementableMethods(Context, const_cast(Cat), WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods); + IsInImplementation, KnownMethods, + InOriginalClass); } if (ObjCCategoryDecl *Category = dyn_cast(Container)) { @@ -3976,7 +4887,8 @@ static void FindImplementableMethods(ASTContext &Context, E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods); + IsInImplementation, KnownMethods, + InOriginalClass); } if (ObjCProtocolDecl *Protocol = dyn_cast(Container)) { @@ -3987,7 +4899,7 @@ static void FindImplementableMethods(ASTContext &Context, E = Protocols.end(); I != E; ++I) FindImplementableMethods(Context, *I, WantInstanceMethods, ReturnType, - IsInImplementation, KnownMethods); + IsInImplementation, KnownMethods, false); } // Add methods in this container. This operation occurs last because @@ -4001,15 +4913,15 @@ static void FindImplementableMethods(ASTContext &Context, !Context.hasSameUnqualifiedType(ReturnType, (*M)->getResultType())) continue; - KnownMethods[(*M)->getSelector()] = *M; + KnownMethods[(*M)->getSelector()] = std::make_pair(*M, InOriginalClass); } } } void Sema::CodeCompleteObjCMethodDecl(Scope *S, bool IsInstanceMethod, - TypeTy *ReturnTy, - DeclPtrTy IDecl) { + ParsedType ReturnTy, + Decl *IDecl) { // Determine the return type of the method we're declaring, if // provided. QualType ReturnType = GetTypeFromParser(ReturnTy); @@ -4017,7 +4929,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, // Determine where we should start searching for methods, and where we ObjCContainerDecl *SearchDecl = 0, *CurrentDecl = 0; bool IsInImplementation = false; - if (Decl *D = IDecl.getAs()) { + if (Decl *D = IDecl) { if (ObjCImplementationDecl *Impl = dyn_cast(D)) { SearchDecl = Impl->getClassInterface(); CurrentDecl = Impl; @@ -4041,7 +4953,9 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, } if (!SearchDecl || !CurrentDecl) { - HandleCodeCompleteResults(this, CodeCompleter, 0, 0); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + 0, 0); return; } @@ -4064,7 +4978,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, } // Add declarations or definitions for each of the known methods. - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; ResultBuilder Results(*this); Results.EnterNewScope(); PrintingPolicy Policy(Context.PrintingPolicy); @@ -4072,7 +4986,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, for (KnownMethodsMap::iterator M = KnownMethods.begin(), MEnd = KnownMethods.end(); M != MEnd; ++M) { - ObjCMethodDecl *Method = M->second; + ObjCMethodDecl *Method = M->second.first; CodeCompletionString *Pattern = new CodeCompletionString; // If the result type was not already provided, add it to the @@ -4100,7 +5014,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Pattern->AddChunk(CodeCompletionString::CK_Colon); else if (I < Sel.getNumArgs()) { Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); - Pattern->AddTextChunk(Sel.getIdentifierInfoForSlot(1)->getName()); + Pattern->AddTextChunk(Sel.getIdentifierInfoForSlot(I)->getName()); Pattern->AddChunk(CodeCompletionString::CK_Colon); } else break; @@ -4113,14 +5027,14 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Pattern->AddChunk(CodeCompletionString::CK_RightParen); if (IdentifierInfo *Id = (*P)->getIdentifier()) - Pattern->AddTextChunk(Id->getName()); + Pattern->AddTextChunk(Id->getName()); } if (Method->isVariadic()) { if (Method->param_size() > 0) Pattern->AddChunk(CodeCompletionString::CK_Comma); Pattern->AddTextChunk("..."); - } + } if (IsInImplementation && Results.includeCodePatterns()) { // We will be defining the method here, so add a compound statement. @@ -4140,50 +5054,56 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Pattern->AddChunk(CodeCompletionString::CK_RightBrace); } - Results.AddResult(Result(Pattern)); + unsigned Priority = CCP_CodePattern; + if (!M->second.second) + Priority += CCD_InBaseClass; + + Results.AddResult(Result(Pattern, Priority, + Method->isInstanceMethod() + ? CXCursor_ObjCInstanceMethodDecl + : CXCursor_ObjCClassMethodDecl)); } Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); } void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, bool IsInstanceMethod, bool AtParameterName, - TypeTy *ReturnTy, + ParsedType ReturnTy, IdentifierInfo **SelIdents, unsigned NumSelIdents) { - llvm::DenseMap &Pool - = IsInstanceMethod? InstanceMethodPool : FactoryMethodPool; - // If we have an external source, load the entire class method - // pool from the PCH file. + // pool from the AST file. if (ExternalSource) { for (uint32_t I = 0, N = ExternalSource->GetNumExternalSelectors(); I != N; ++I) { Selector Sel = ExternalSource->GetExternalSelector(I); - if (Sel.isNull() || InstanceMethodPool.count(Sel) || - FactoryMethodPool.count(Sel)) + if (Sel.isNull() || MethodPool.count(Sel)) continue; - - ReadMethodPool(Sel, IsInstanceMethod); + + ReadMethodPool(Sel); } } // Build the set of methods we can see. - typedef CodeCompleteConsumer::Result Result; + typedef CodeCompletionResult Result; ResultBuilder Results(*this); if (ReturnTy) Results.setPreferredType(GetTypeFromParser(ReturnTy).getNonReferenceType()); - + Results.EnterNewScope(); - for (llvm::DenseMap::iterator M = Pool.begin(), - MEnd = Pool.end(); - M != MEnd; - ++M) { - for (ObjCMethodList *MethList = &M->second; MethList && MethList->Method; + for (GlobalMethodPool::iterator M = MethodPool.begin(), + MEnd = MethodPool.end(); + M != MEnd; ++M) { + for (ObjCMethodList *MethList = IsInstanceMethod ? &M->second.first : + &M->second.second; + MethList && MethList->Method; MethList = MethList->Next) { if (!isAcceptableObjCMethod(MethList->Method, MK_Any, SelIdents, NumSelIdents)) @@ -4212,5 +5132,270 @@ void Sema::CodeCompleteObjCMethodDeclSelector(Scope *S, } Results.ExitScope(); - HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + Results.data(),Results.size()); +} + +void Sema::CodeCompletePreprocessorDirective(bool InConditional) { + ResultBuilder Results(*this); + Results.EnterNewScope(); + + // #if + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("if"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("condition"); + Results.AddResult(Pattern); + + // #ifdef + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("ifdef"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("macro"); + Results.AddResult(Pattern); + + // #ifndef + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("ifndef"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("macro"); + Results.AddResult(Pattern); + + if (InConditional) { + // #elif + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("elif"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("condition"); + Results.AddResult(Pattern); + + // #else + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("else"); + Results.AddResult(Pattern); + + // #endif + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("endif"); + Results.AddResult(Pattern); + } + + // #include "header" + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("include"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("\""); + Pattern->AddPlaceholderChunk("header"); + Pattern->AddTextChunk("\""); + Results.AddResult(Pattern); + + // #include

+ Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("include"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("<"); + Pattern->AddPlaceholderChunk("header"); + Pattern->AddTextChunk(">"); + Results.AddResult(Pattern); + + // #define + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("define"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("macro"); + Results.AddResult(Pattern); + + // #define () + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("define"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("macro"); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("args"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Pattern); + + // #undef + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("undef"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("macro"); + Results.AddResult(Pattern); + + // #line + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("line"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("number"); + Results.AddResult(Pattern); + + // #line "filename" + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("line"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("number"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("\""); + Pattern->AddPlaceholderChunk("filename"); + Pattern->AddTextChunk("\""); + Results.AddResult(Pattern); + + // #error + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("error"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("message"); + Results.AddResult(Pattern); + + // #pragma + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("pragma"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("arguments"); + Results.AddResult(Pattern); + + if (getLangOptions().ObjC1) { + // #import "header" + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("import"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("\""); + Pattern->AddPlaceholderChunk("header"); + Pattern->AddTextChunk("\""); + Results.AddResult(Pattern); + + // #import
+ Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("import"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("<"); + Pattern->AddPlaceholderChunk("header"); + Pattern->AddTextChunk(">"); + Results.AddResult(Pattern); + } + + // #include_next "header" + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("include_next"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("\""); + Pattern->AddPlaceholderChunk("header"); + Pattern->AddTextChunk("\""); + Results.AddResult(Pattern); + + // #include_next
+ Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("include_next"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddTextChunk("<"); + Pattern->AddPlaceholderChunk("header"); + Pattern->AddTextChunk(">"); + Results.AddResult(Pattern); + + // #warning + Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("warning"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddPlaceholderChunk("message"); + Results.AddResult(Pattern); + + // Note: #ident and #sccs are such crazy anachronisms that we don't provide + // completions for them. And __include_macros is a Clang-internal extension + // that we don't want to encourage anyone to use. + + // FIXME: we don't support #assert or #unassert, so don't suggest them. + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_PreprocessorDirective, + Results.data(), Results.size()); +} + +void Sema::CodeCompleteInPreprocessorConditionalExclusion(Scope *S) { + CodeCompleteOrdinaryName(S, + S->getFnParent()? Sema::PCC_RecoveryInFunction + : Sema::PCC_Namespace); +} + +void Sema::CodeCompletePreprocessorMacroName(bool IsDefinition) { + ResultBuilder Results(*this); + if (!IsDefinition && (!CodeCompleter || CodeCompleter->includeMacros())) { + // Add just the names of macros, not their arguments. + Results.EnterNewScope(); + for (Preprocessor::macro_iterator M = PP.macro_begin(), + MEnd = PP.macro_end(); + M != MEnd; ++M) { + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk(M->first->getName()); + Results.AddResult(Pattern); + } + Results.ExitScope(); + } else if (IsDefinition) { + // FIXME: Can we detect when the user just wrote an include guard above? + } + + HandleCodeCompleteResults(this, CodeCompleter, + IsDefinition? CodeCompletionContext::CCC_MacroName + : CodeCompletionContext::CCC_MacroNameUse, + Results.data(), Results.size()); +} + +void Sema::CodeCompletePreprocessorExpression() { + ResultBuilder Results(*this); + + if (!CodeCompleter || CodeCompleter->includeMacros()) + AddMacroResults(PP, Results); + + // defined () + Results.EnterNewScope(); + CodeCompletionString *Pattern = new CodeCompletionString; + Pattern->AddTypedTextChunk("defined"); + Pattern->AddChunk(CodeCompletionString::CK_HorizontalSpace); + Pattern->AddChunk(CodeCompletionString::CK_LeftParen); + Pattern->AddPlaceholderChunk("macro"); + Pattern->AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Pattern); + Results.ExitScope(); + + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_PreprocessorExpression, + Results.data(), Results.size()); +} + +void Sema::CodeCompletePreprocessorMacroArgument(Scope *S, + IdentifierInfo *Macro, + MacroInfo *MacroInfo, + unsigned Argument) { + // FIXME: In the future, we could provide "overload" results, much like we + // do for function calls. + + CodeCompleteOrdinaryName(S, + S->getFnParent()? Sema::PCC_RecoveryInFunction + : Sema::PCC_Namespace); +} + +void Sema::CodeCompleteNaturalLanguage() { + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_NaturalLanguage, + 0, 0); +} + +void Sema::GatherGlobalCodeCompletions( + llvm::SmallVectorImpl &Results) { + ResultBuilder Builder(*this); + + if (!CodeCompleter || CodeCompleter->includeGlobals()) { + CodeCompletionDeclConsumer Consumer(Builder, + Context.getTranslationUnitDecl()); + LookupVisibleDecls(Context.getTranslationUnitDecl(), LookupAnyName, + Consumer); + } + + if (!CodeCompleter || CodeCompleter->includeMacros()) + AddMacroResults(PP, Builder); + + Results.clear(); + Results.insert(Results.end(), + Builder.data(), Builder.data() + Builder.size()); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c1c898f..f5e045a 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -11,19 +11,24 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "SemaInit.h" -#include "Lookup.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/CXXFieldCollector.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" -#include "clang/Parse/DeclSpec.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/ParsedTemplate.h" #include "clang/Parse/ParseDiagnostic.h" -#include "clang/Parse/Template.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -35,18 +40,10 @@ #include #include using namespace clang; +using namespace sema; -/// getDeclName - Return a pretty name for the specified decl if possible, or -/// an empty string if not. This is used for pretty crash reporting. -std::string Sema::getDeclName(DeclPtrTy d) { - Decl *D = d.getAs(); - if (NamedDecl *DN = dyn_cast_or_null(D)) - return DN->getQualifiedNameAsString(); - return ""; -} - -Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) { - return DeclGroupPtrTy::make(DeclGroupRef(Ptr.getAs())); +Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr) { + return DeclGroupPtrTy::make(DeclGroupRef(Ptr)); } /// \brief If the identifier refers to a type name within this scope, @@ -60,14 +57,14 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) { /// /// If name lookup results in an ambiguity, this routine will complain /// and then return NULL. -Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, CXXScopeSpec *SS, - bool isClassName, - TypeTy *ObjectTypePtr) { +ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, CXXScopeSpec *SS, + bool isClassName, + ParsedType ObjectTypePtr) { // Determine where we will perform name lookup. DeclContext *LookupCtx = 0; if (ObjectTypePtr) { - QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); + QualType ObjectType = ObjectTypePtr.get(); if (ObjectType->isRecordType()) LookupCtx = computeDeclContext(ObjectType); } else if (SS && SS->isNotEmpty()) { @@ -85,22 +82,22 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // We therefore do not perform any name lookup if the result would // refer to a member of an unknown specialization. if (!isClassName) - return 0; + return ParsedType(); // We know from the grammar that this name refers to a type, // so build a dependent node to describe the type. - return CheckTypenameType(ETK_None, - (NestedNameSpecifier *)SS->getScopeRep(), II, - SourceLocation(), SS->getRange(), NameLoc - ).getAsOpaquePtr(); + QualType T = + CheckTypenameType(ETK_None, SS->getScopeRep(), II, + SourceLocation(), SS->getRange(), NameLoc); + return ParsedType::make(T); } - return 0; + return ParsedType(); } if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS, LookupCtx)) - return 0; + return ParsedType(); } // FIXME: LookupNestedNameSpecifierName isn't the right kind of @@ -136,7 +133,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: Result.suppressDiagnostics(); - return 0; + return ParsedType(); case LookupResult::Ambiguous: // Recover from type-hiding ambiguities by hiding the type. We'll @@ -146,7 +143,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // that only makes sense if the identifier was treated like a type. if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding) { Result.suppressDiagnostics(); - return 0; + return ParsedType(); } // Look to see if we have a type anywhere in the list of results. @@ -168,7 +165,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // will produce the ambiguity, or will complain that it expected // a type name. Result.suppressDiagnostics(); - return 0; + return ParsedType(); } // We found a type within the ambiguous lookup; diagnose the @@ -199,10 +196,10 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, } else { // If it's not plausibly a type, suppress diagnostics. Result.suppressDiagnostics(); - return 0; + return ParsedType(); } - return T.getAsOpaquePtr(); + return ParsedType::make(T); } /// isTagName() - This method is called *for error recovery purposes only* @@ -233,9 +230,9 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, CXXScopeSpec *SS, - TypeTy *&SuggestedType) { + ParsedType &SuggestedType) { // We don't have anything to suggest (yet). - SuggestedType = 0; + SuggestedType = ParsedType(); // There may have been a typo in the name of the type. Look up typo // results, in case we have something that we can suggest. @@ -282,7 +279,8 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, CXXScopeSpec EmptySS; TemplateTy TemplateResult; bool MemberOfUnknownSpecialization; - if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult, + if (isTemplateName(S, SS ? *SS : EmptySS, /*hasTemplateKeyword=*/false, + Name, ParsedType(), true, TemplateResult, MemberOfUnknownSpecialization) == TNK_Type_template) { TemplateName TplName = TemplateResult.getAsVal(); Diag(IILoc, diag::err_template_missing_args) << TplName; @@ -343,8 +341,10 @@ DeclContext *Sema::getContainingDC(DeclContext *DC) { return DC; } + // ObjCMethodDecls are parsed (for some reason) outside the context + // of the class. if (isa(DC)) - return Context.getTranslationUnitDecl(); + return DC->getLexicalParent()->getLexicalParent(); return DC->getLexicalParent(); } @@ -360,6 +360,7 @@ void Sema::PopDeclContext() { assert(CurContext && "DeclContext imbalance!"); CurContext = getContainingDC(CurContext); + assert(CurContext && "Popped translation unit!"); } /// EnterDeclaratorContext - Used when we must lookup names in the context @@ -458,8 +459,8 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { IdentifierResolver::iterator I = IdResolver.begin(D->getDeclName()), IEnd = IdResolver.end(); for (; I != IEnd; ++I) { - if (S->isDeclScope(DeclPtrTy::make(*I)) && D->declarationReplaces(*I)) { - S->RemoveDecl(DeclPtrTy::make(*I)); + if (S->isDeclScope(*I) && D->declarationReplaces(*I)) { + S->RemoveDecl(*I); IdResolver.RemoveDecl(*I); // Should only need to replace one decl. @@ -467,7 +468,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { } } - S->AddDecl(DeclPtrTy::make(D)); + S->AddDecl(D); IdResolver.AddDecl(D); } @@ -475,6 +476,17 @@ bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) { return IdResolver.isDeclInScope(D, Ctx, Context, S); } +Scope *Sema::getScopeForDeclContext(Scope *S, DeclContext *DC) { + DeclContext *TargetDC = DC->getPrimaryContext(); + do { + if (DeclContext *ScopeDC = (DeclContext*) S->getEntity()) + if (ScopeDC->getPrimaryContext() == TargetDC) + return S; + } while ((S = S->getParent())); + + return 0; +} + static bool isOutOfScopePreviousDeclaration(NamedDecl *, DeclContext*, ASTContext&); @@ -517,6 +529,90 @@ static void RemoveUsingDecls(LookupResult &R) { F.done(); } +/// \brief Check for this common pattern: +/// @code +/// class S { +/// S(const S&); // DO NOT IMPLEMENT +/// void operator=(const S&); // DO NOT IMPLEMENT +/// }; +/// @endcode +static bool IsDisallowedCopyOrAssign(const CXXMethodDecl *D) { + // FIXME: Should check for private access too but access is set after we get + // the decl here. + if (D->isThisDeclarationADefinition()) + return false; + + if (const CXXConstructorDecl *CD = dyn_cast(D)) + return CD->isCopyConstructor(); + return D->isCopyAssignment(); +} + +bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { + assert(D); + + if (D->isInvalidDecl() || D->isUsed() || D->hasAttr()) + return false; + + // Ignore class templates. + if (D->getDeclContext()->isDependentContext()) + return false; + + // We warn for unused decls internal to the translation unit. + if (D->getLinkage() == ExternalLinkage) + return false; + + if (const FunctionDecl *FD = dyn_cast(D)) { + if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) + return false; + + if (const CXXMethodDecl *MD = dyn_cast(FD)) { + if (MD->isVirtual() || IsDisallowedCopyOrAssign(MD)) + return false; + } else { + // 'static inline' functions are used in headers; don't warn. + if (FD->getStorageClass() == SC_Static && + FD->isInlineSpecified()) + return false; + } + + if (FD->isThisDeclarationADefinition()) + return !Context.DeclMustBeEmitted(FD); + return true; + } + + if (const VarDecl *VD = dyn_cast(D)) { + if (VD->isStaticDataMember() && + VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) + return false; + + if ( VD->isFileVarDecl() && + !VD->getType().isConstant(Context)) + return !Context.DeclMustBeEmitted(VD); + } + + return false; + } + + void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { + if (!D) + return; + + if (const FunctionDecl *FD = dyn_cast(D)) { + const FunctionDecl *First = FD->getFirstDeclaration(); + if (FD != First && ShouldWarnIfUnusedFileScopedDecl(First)) + return; // First should already be in the vector. + } + + if (const VarDecl *VD = dyn_cast(D)) { + const VarDecl *First = VD->getFirstDeclaration(); + if (VD != First && ShouldWarnIfUnusedFileScopedDecl(First)) + return; // First should already be in the vector. + } + + if (ShouldWarnIfUnusedFileScopedDecl(D)) + UnusedFileScopedDecls.push_back(D); + } + static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (D->isInvalidDecl()) return false; @@ -585,7 +681,7 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end(); I != E; ++I) { - Decl *TmpD = (*I).getAs(); + Decl *TmpD = (*I); assert(TmpD && "This decl didn't get pushed??"); assert(isa(TmpD) && "Decl isn't NamedDecl?"); @@ -731,8 +827,8 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, FunctionDecl *New = FunctionDecl::Create(Context, Context.getTranslationUnitDecl(), Loc, II, R, /*TInfo=*/0, - FunctionDecl::Extern, - FunctionDecl::None, false, + SC_Extern, + SC_None, false, /*hasPrototype=*/true); New->setImplicit(); @@ -743,7 +839,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0, FT->getArgType(i), /*TInfo=*/0, - VarDecl::None, VarDecl::None, 0)); + SC_None, SC_None, 0)); New->setParams(Params.data(), Params.size()); } @@ -909,25 +1005,40 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { /// DeclhasAttr - returns true if decl Declaration already has the target /// attribute. static bool -DeclHasAttr(const Decl *decl, const Attr *target) { - for (const Attr *attr = decl->getAttrs(); attr; attr = attr->getNext()) - if (attr->getKind() == target->getKind()) +DeclHasAttr(const Decl *D, const Attr *A) { + const OwnershipAttr *OA = dyn_cast(A); + for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i) + if ((*i)->getKind() == A->getKind()) { + // FIXME: Don't hardcode this check + if (OA && isa(*i)) + return OA->getOwnKind() == cast(*i)->getOwnKind(); return true; + } return false; } -/// MergeAttributes - append attributes from the Old decl to the New one. -static void MergeAttributes(Decl *New, Decl *Old, ASTContext &C) { - for (const Attr *attr = Old->getAttrs(); attr; attr = attr->getNext()) { - if (!DeclHasAttr(New, attr) && attr->isMerged()) { - Attr *NewAttr = attr->clone(C); +/// MergeDeclAttributes - append attributes from the Old decl to the New one. +static void MergeDeclAttributes(Decl *New, Decl *Old, ASTContext &C) { + if (!Old->hasAttrs()) + return; + // Ensure that any moving of objects within the allocated map is done before + // we process them. + if (!New->hasAttrs()) + New->setAttrs(AttrVec()); + for (Decl::attr_iterator i = Old->attr_begin(), e = Old->attr_end(); i != e; + ++i) { + // FIXME: Make this more general than just checking for Overloadable. + if (!DeclHasAttr(New, *i) && (*i)->getKind() != attr::Overloadable) { + Attr *NewAttr = (*i)->clone(C); NewAttr->setInherited(true); New->addAttr(NewAttr); } } } +namespace { + /// Used in MergeFunctionDecl to keep track of function parameters in /// C. struct GNUCompatibleParamWarning { @@ -936,6 +1047,7 @@ struct GNUCompatibleParamWarning { QualType PromotedType; }; +} /// getSpecialMember - get the special member enum for a method. Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { @@ -960,7 +1072,7 @@ static bool canRedefineFunction(const FunctionDecl *FD, const LangOptions& LangOpts) { return (LangOpts.GNUMode && !LangOpts.C99 && !LangOpts.CPlusPlus && FD->isInlineSpecified() && - FD->getStorageClass() == FunctionDecl::Extern); + FD->getStorageClass() == SC_Extern); } /// MergeFunctionDecl - We just parsed a function 'New' from @@ -1014,8 +1126,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { // Don't complain about this if we're in GNU89 mode and the old function // is an extern inline function. if (!isa(New) && !isa(Old) && - New->getStorageClass() == FunctionDecl::Static && - Old->getStorageClass() != FunctionDecl::Static && + New->getStorageClass() == SC_Static && + Old->getStorageClass() != SC_Static && !canRedefineFunction(Old, getLangOptions())) { Diag(New->getLocation(), diag::err_static_non_static) << New; @@ -1196,7 +1308,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { ParmVarDecl *Param = ParmVarDecl::Create(Context, New, SourceLocation(), 0, *ParamType, /*TInfo=*/0, - VarDecl::None, VarDecl::None, + SC_None, SC_None, 0); Param->setImplicit(); Params.push_back(Param); @@ -1242,7 +1354,8 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { NewProto->getArgType(Idx))) { ArgTypes.push_back(NewParm->getType()); } else if (Context.typesAreCompatible(OldParm->getType(), - NewParm->getType())) { + NewParm->getType(), + /*CompareUnqualified=*/true)) { GNUCompatibleParamWarning Warn = { OldParm, NewParm, NewProto->getArgType(Idx) }; Warnings.push_back(Warn); @@ -1257,8 +1370,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { diag::ext_param_promoted_not_compatible_with_prototype) << Warnings[Warn].PromotedType << Warnings[Warn].OldParm->getType(); - Diag(Warnings[Warn].OldParm->getLocation(), - diag::note_previous_declaration); + if (Warnings[Warn].OldParm->getLocation().isValid()) + Diag(Warnings[Warn].OldParm->getLocation(), + diag::note_previous_declaration); } New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0], @@ -1309,11 +1423,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { /// \returns false bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { // Merge the attributes - MergeAttributes(New, Old, Context); + MergeDeclAttributes(New, Old, Context); // Merge the storage class. - if (Old->getStorageClass() != FunctionDecl::Extern && - Old->getStorageClass() != FunctionDecl::None) + if (Old->getStorageClass() != SC_Extern && + Old->getStorageClass() != SC_None) New->setStorageClass(Old->getStorageClass()); // Merge "pure" flag. @@ -1354,7 +1468,18 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return New->setInvalidDecl(); } - MergeAttributes(New, Old, Context); + // C++ [class.mem]p1: + // A member shall not be declared twice in the member-specification [...] + // + // Here, we need only consider static data members. + if (Old->isStaticDataMember() && !New->isOutOfLine()) { + Diag(New->getLocation(), diag::err_duplicate_member) + << New->getIdentifier(); + Diag(Old->getLocation(), diag::note_previous_declaration); + New->setInvalidDecl(); + } + + MergeDeclAttributes(New, Old, Context); // Merge the types QualType MergedT; @@ -1398,8 +1523,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { New->setType(MergedT); // C99 6.2.2p4: Check if we have a static decl followed by a non-static. - if (New->getStorageClass() == VarDecl::Static && - (Old->getStorageClass() == VarDecl::None || Old->hasExternalStorage())) { + if (New->getStorageClass() == SC_Static && + (Old->getStorageClass() == SC_None || Old->hasExternalStorage())) { Diag(New->getLocation(), diag::err_static_non_static) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); @@ -1415,8 +1540,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { // identifier has external linkage. if (New->hasExternalStorage() && Old->hasLinkage()) /* Okay */; - else if (New->getStorageClass() != VarDecl::Static && - Old->getStorageClass() == VarDecl::Static) { + else if (New->getStorageClass() != SC_Static && + Old->getStorageClass() == SC_Static) { Diag(New->getLocation(), diag::err_non_static_static) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); @@ -1475,8 +1600,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. -Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, - DeclSpec &DS) { +Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS) { // FIXME: Error on auto/register at file scope // FIXME: Error on inline/virtual/explicit // FIXME: Warn on useless __thread @@ -1489,10 +1614,10 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DS.getTypeSpecType() == DeclSpec::TST_struct || DS.getTypeSpecType() == DeclSpec::TST_union || DS.getTypeSpecType() == DeclSpec::TST_enum) { - TagD = static_cast(DS.getTypeRep()); + TagD = DS.getRepAsDecl(); if (!TagD) // We probably had an error - return DeclPtrTy(); + return 0; // Note that the above type specs guarantee that the // type rep is a Decl, whereas in many of the others @@ -1513,14 +1638,12 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, // If we're dealing with a class template decl, assume that the // template routines are handling it. if (TagD && isa(TagD)) - return DeclPtrTy(); + return 0; return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0)); } if (RecordDecl *Record = dyn_cast_or_null(Tag)) { - // If there are attributes in the DeclSpec, apply them to the record. - if (const AttributeList *AL = DS.getAttributes()) - ProcessDeclAttributeList(S, Record, AL); + ProcessDeclAttributeList(S, Record, DS.getAttributes()); if (!Record->getDeclName() && Record->isDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { @@ -1536,7 +1659,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, // about them. // FIXME: Should we support Microsoft's extensions in this area? if (Record->getDeclName() && getLangOptions().Microsoft) - return DeclPtrTy::make(Tag); + return Tag; } if (getLangOptions().CPlusPlus && @@ -1550,19 +1673,19 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, if (!DS.isMissingDeclaratorOk() && DS.getTypeSpecType() != DeclSpec::TST_error) { // Warn about typedefs of enums without names, since this is an - // extension in both Microsoft an GNU. + // extension in both Microsoft and GNU. if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef && Tag && isa(Tag)) { Diag(DS.getSourceRange().getBegin(), diag::ext_typedef_without_a_name) << DS.getSourceRange(); - return DeclPtrTy::make(Tag); + return Tag; } Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); } - return DeclPtrTy::make(Tag); + return TagD; } /// We are trying to inject an anonymous member into the given scope; @@ -1639,7 +1762,7 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, // considered to have been defined in the scope in which the // anonymous union is declared. Owner->makeDeclVisibleInContext(*F); - S->AddDecl(Sema::DeclPtrTy::make(*F)); + S->AddDecl(*F); SemaRef.IdResolver.AddDecl(*F); // That includes picking up the appropriate access specifier. @@ -1660,58 +1783,38 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, /// StorageClassSpecToVarDeclStorageClass - Maps a DeclSpec::SCS to /// a VarDecl::StorageClass. Any error reporting is up to the caller: -/// illegal input values are mapped to VarDecl::None. -/// If the input declaration context is a linkage specification -/// with no braces, then Extern is mapped to None. -static VarDecl::StorageClass -StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec, - DeclContext *DC) { +/// illegal input values are mapped to SC_None. +static StorageClass +StorageClassSpecToVarDeclStorageClass(DeclSpec::SCS StorageClassSpec) { switch (StorageClassSpec) { - case DeclSpec::SCS_unspecified: return VarDecl::None; - case DeclSpec::SCS_extern: - // If the current context is a C++ linkage specification - // having no braces, then the keyword "extern" is properly part - // of the linkage specification itself, rather than being - // the written storage class specifier. - return (DC && isa(DC) && - !cast(DC)->hasBraces()) - ? VarDecl::None : VarDecl::Extern; - case DeclSpec::SCS_static: return VarDecl::Static; - case DeclSpec::SCS_auto: return VarDecl::Auto; - case DeclSpec::SCS_register: return VarDecl::Register; - case DeclSpec::SCS_private_extern: return VarDecl::PrivateExtern; + case DeclSpec::SCS_unspecified: return SC_None; + case DeclSpec::SCS_extern: return SC_Extern; + case DeclSpec::SCS_static: return SC_Static; + case DeclSpec::SCS_auto: return SC_Auto; + case DeclSpec::SCS_register: return SC_Register; + case DeclSpec::SCS_private_extern: return SC_PrivateExtern; // Illegal SCSs map to None: error reporting is up to the caller. case DeclSpec::SCS_mutable: // Fall through. - case DeclSpec::SCS_typedef: return VarDecl::None; + case DeclSpec::SCS_typedef: return SC_None; } llvm_unreachable("unknown storage class specifier"); } /// StorageClassSpecToFunctionDeclStorageClass - Maps a DeclSpec::SCS to -/// a FunctionDecl::StorageClass. Any error reporting is up to the caller: -/// illegal input values are mapped to FunctionDecl::None. -/// If the input declaration context is a linkage specification -/// with no braces, then Extern is mapped to None. -static FunctionDecl::StorageClass -StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec, - DeclContext *DC) { +/// a StorageClass. Any error reporting is up to the caller: +/// illegal input values are mapped to SC_None. +static StorageClass +StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec) { switch (StorageClassSpec) { - case DeclSpec::SCS_unspecified: return FunctionDecl::None; - case DeclSpec::SCS_extern: - // If the current context is a C++ linkage specification - // having no braces, then the keyword "extern" is properly part - // of the linkage specification itself, rather than being - // the written storage class specifier. - return (DC && isa(DC) && - !cast(DC)->hasBraces()) - ? FunctionDecl::None : FunctionDecl::Extern; - case DeclSpec::SCS_static: return FunctionDecl::Static; - case DeclSpec::SCS_private_extern: return FunctionDecl::PrivateExtern; + case DeclSpec::SCS_unspecified: return SC_None; + case DeclSpec::SCS_extern: return SC_Extern; + case DeclSpec::SCS_static: return SC_Static; + case DeclSpec::SCS_private_extern: return SC_PrivateExtern; // Illegal SCSs map to None: error reporting is up to the caller. case DeclSpec::SCS_auto: // Fall through. case DeclSpec::SCS_mutable: // Fall through. case DeclSpec::SCS_register: // Fall through. - case DeclSpec::SCS_typedef: return FunctionDecl::None; + case DeclSpec::SCS_typedef: return SC_None; } llvm_unreachable("unknown storage class specifier"); } @@ -1720,9 +1823,9 @@ StorageClassSpecToFunctionDeclStorageClass(DeclSpec::SCS StorageClassSpec, /// anonymous structure or union. Anonymous unions are a C++ feature /// (C++ [class.union]) and a GNU C extension; anonymous structures /// are a GNU C and GNU C++ extension. -Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, - AccessSpecifier AS, - RecordDecl *Record) { +Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, + AccessSpecifier AS, + RecordDecl *Record) { DeclContext *Owner = Record->getDeclContext(); // Diagnose whether this anonymous struct/union is an extension. @@ -1782,6 +1885,9 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, << (int)Record->isUnion() << (int)(FD->getAccess() == AS_protected); Invalid = true; } + + if (CheckNontrivialField(FD)) + Invalid = true; } else if ((*Mem)->isImplicit()) { // Any implicit members are fine. } else if (isa(*Mem) && (*Mem)->getDeclContext() != Record) { @@ -1845,17 +1951,17 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, DeclSpec::SCS SCSpec = DS.getStorageClassSpec(); assert(SCSpec != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class VarDecl."); - VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0); + VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec); if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here Diag(Record->getLocation(), diag::err_mutable_nonmember); Invalid = true; - SC = VarDecl::None; + SC = SC_None; } SCSpec = DS.getStorageClassSpecAsWritten(); VarDecl::StorageClass SCAsWritten - = StorageClassSpecToVarDeclStorageClass(SCSpec, 0); + = StorageClassSpecToVarDeclStorageClass(SCSpec); Anon = VarDecl::Create(Context, Owner, Record->getLocation(), /*IdentifierInfo=*/0, @@ -1886,85 +1992,115 @@ Sema::DeclPtrTy Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, if (Invalid) Anon->setInvalidDecl(); - return DeclPtrTy::make(Anon); + return Anon; } /// GetNameForDeclarator - Determine the full declaration name for the /// given Declarator. -DeclarationName Sema::GetNameForDeclarator(Declarator &D) { +DeclarationNameInfo Sema::GetNameForDeclarator(Declarator &D) { return GetNameFromUnqualifiedId(D.getName()); } -/// \brief Retrieves the canonicalized name from a parsed unqualified-id. -DeclarationName Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { - switch (Name.getKind()) { - case UnqualifiedId::IK_Identifier: - return DeclarationName(Name.Identifier); - - case UnqualifiedId::IK_OperatorFunctionId: - return Context.DeclarationNames.getCXXOperatorName( - Name.OperatorFunctionId.Operator); - - case UnqualifiedId::IK_LiteralOperatorId: - return Context.DeclarationNames.getCXXLiteralOperatorName( - Name.Identifier); - - case UnqualifiedId::IK_ConversionFunctionId: { - QualType Ty = GetTypeFromParser(Name.ConversionFunctionId); - if (Ty.isNull()) - return DeclarationName(); - - return Context.DeclarationNames.getCXXConversionFunctionName( - Context.getCanonicalType(Ty)); - } - - case UnqualifiedId::IK_ConstructorName: { - QualType Ty = GetTypeFromParser(Name.ConstructorName); - if (Ty.isNull()) - return DeclarationName(); - - return Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(Ty)); - } - - case UnqualifiedId::IK_ConstructorTemplateId: { - // In well-formed code, we can only have a constructor - // template-id that refers to the current context, so go there - // to find the actual type being constructed. - CXXRecordDecl *CurClass = dyn_cast(CurContext); - if (!CurClass || CurClass->getIdentifier() != Name.TemplateId->Name) - return DeclarationName(); +/// \brief Retrieves the declaration name from a parsed unqualified-id. +DeclarationNameInfo +Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { + DeclarationNameInfo NameInfo; + NameInfo.setLoc(Name.StartLocation); - // Determine the type of the class being constructed. - QualType CurClassType = Context.getTypeDeclType(CurClass); + switch (Name.getKind()) { - // FIXME: Check two things: that the template-id names the same type as - // CurClassType, and that the template-id does not occur when the name - // was qualified. + case UnqualifiedId::IK_Identifier: + NameInfo.setName(Name.Identifier); + NameInfo.setLoc(Name.StartLocation); + return NameInfo; + + case UnqualifiedId::IK_OperatorFunctionId: + NameInfo.setName(Context.DeclarationNames.getCXXOperatorName( + Name.OperatorFunctionId.Operator)); + NameInfo.setLoc(Name.StartLocation); + NameInfo.getInfo().CXXOperatorName.BeginOpNameLoc + = Name.OperatorFunctionId.SymbolLocations[0]; + NameInfo.getInfo().CXXOperatorName.EndOpNameLoc + = Name.EndLocation.getRawEncoding(); + return NameInfo; + + case UnqualifiedId::IK_LiteralOperatorId: + NameInfo.setName(Context.DeclarationNames.getCXXLiteralOperatorName( + Name.Identifier)); + NameInfo.setLoc(Name.StartLocation); + NameInfo.setCXXLiteralOperatorNameLoc(Name.EndLocation); + return NameInfo; + + case UnqualifiedId::IK_ConversionFunctionId: { + TypeSourceInfo *TInfo; + QualType Ty = GetTypeFromParser(Name.ConversionFunctionId, &TInfo); + if (Ty.isNull()) + return DeclarationNameInfo(); + NameInfo.setName(Context.DeclarationNames.getCXXConversionFunctionName( + Context.getCanonicalType(Ty))); + NameInfo.setLoc(Name.StartLocation); + NameInfo.setNamedTypeInfo(TInfo); + return NameInfo; + } + + case UnqualifiedId::IK_ConstructorName: { + TypeSourceInfo *TInfo; + QualType Ty = GetTypeFromParser(Name.ConstructorName, &TInfo); + if (Ty.isNull()) + return DeclarationNameInfo(); + NameInfo.setName(Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(Ty))); + NameInfo.setLoc(Name.StartLocation); + NameInfo.setNamedTypeInfo(TInfo); + return NameInfo; + } + + case UnqualifiedId::IK_ConstructorTemplateId: { + // In well-formed code, we can only have a constructor + // template-id that refers to the current context, so go there + // to find the actual type being constructed. + CXXRecordDecl *CurClass = dyn_cast(CurContext); + if (!CurClass || CurClass->getIdentifier() != Name.TemplateId->Name) + return DeclarationNameInfo(); + + // Determine the type of the class being constructed. + QualType CurClassType = Context.getTypeDeclType(CurClass); + + // FIXME: Check two things: that the template-id names the same type as + // CurClassType, and that the template-id does not occur when the name + // was qualified. + + NameInfo.setName(Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(CurClassType))); + NameInfo.setLoc(Name.StartLocation); + // FIXME: should we retrieve TypeSourceInfo? + NameInfo.setNamedTypeInfo(0); + return NameInfo; + } + + case UnqualifiedId::IK_DestructorName: { + TypeSourceInfo *TInfo; + QualType Ty = GetTypeFromParser(Name.DestructorName, &TInfo); + if (Ty.isNull()) + return DeclarationNameInfo(); + NameInfo.setName(Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(Ty))); + NameInfo.setLoc(Name.StartLocation); + NameInfo.setNamedTypeInfo(TInfo); + return NameInfo; + } + + case UnqualifiedId::IK_TemplateId: { + TemplateName TName = Name.TemplateId->Template.get(); + SourceLocation TNameLoc = Name.TemplateId->TemplateNameLoc; + return Context.getNameForTemplate(TName, TNameLoc); + } + + } // switch (Name.getKind()) - return Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(CurClassType)); - } - - case UnqualifiedId::IK_DestructorName: { - QualType Ty = GetTypeFromParser(Name.DestructorName); - if (Ty.isNull()) - return DeclarationName(); - - return Context.DeclarationNames.getCXXDestructorName( - Context.getCanonicalType(Ty)); - } - - case UnqualifiedId::IK_TemplateId: { - TemplateName TName - = TemplateName::getFromVoidPointer(Name.TemplateId->Template); - return Context.getNameForTemplate(TName); - } - } - assert(false && "Unknown name kind"); - return DeclarationName(); + return DeclarationNameInfo(); } /// isNearlyMatchingFunction - Determine whether the C++ functions @@ -2007,11 +2143,10 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, switch (DS.getTypeSpecType()) { case DeclSpec::TST_typename: case DeclSpec::TST_typeofType: - case DeclSpec::TST_typeofExpr: case DeclSpec::TST_decltype: { // Grab the type from the parser. TypeSourceInfo *TSI = 0; - QualType T = S.GetTypeFromParser(DS.getTypeRep(), &TSI); + QualType T = S.GetTypeFromParser(DS.getRepAsType(), &TSI); if (T.isNull() || !T->isDependentType()) break; // Make sure there's a type source info. This isn't really much @@ -2025,8 +2160,16 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, if (!TSI) return true; // Store the new type back in the decl spec. - QualType LocType = S.CreateLocInfoType(TSI->getType(), TSI); - DS.UpdateTypeRep(LocType.getAsOpaquePtr()); + ParsedType LocType = S.CreateParsedType(TSI->getType(), TSI); + DS.UpdateTypeRep(LocType); + break; + } + + case DeclSpec::TST_typeofExpr: { + Expr *E = DS.getRepAsExpr(); + ExprResult Result = S.RebuildExprInCurrentInstantiation(E); + if (Result.isInvalid()) return true; + DS.UpdateExprRep(Result.get()); break; } @@ -2054,11 +2197,16 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, return false; } -Sema::DeclPtrTy -Sema::HandleDeclarator(Scope *S, Declarator &D, - MultiTemplateParamsArg TemplateParamLists, - bool IsFunctionDefinition) { - DeclarationName Name = GetNameForDeclarator(D); +Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { + return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false); +} + +Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, + MultiTemplateParamsArg TemplateParamLists, + bool IsFunctionDefinition) { + // TODO: consider using NameInfo for diagnostic. + DeclarationNameInfo NameInfo = GetNameForDeclarator(D); + DeclarationName Name = NameInfo.getName(); // All of these full declarators require an identifier. If it doesn't have // one, the ParsedFreeStandingDeclSpec action should be used. @@ -2067,7 +2215,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, Diag(D.getDeclSpec().getSourceRange().getBegin(), diag::err_declarator_need_ident) << D.getDeclSpec().getSourceRange() << D.getSourceRange(); - return DeclPtrTy(); + return 0; } // The scope passed in may not be a decl scope. Zip up the scope tree until @@ -2091,14 +2239,14 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, diag::err_template_qualified_declarator_no_match) << (NestedNameSpecifier*)D.getCXXScopeSpec().getScopeRep() << D.getCXXScopeSpec().getRange(); - return DeclPtrTy(); + return 0; } bool IsDependentContext = DC->isDependentContext(); if (!IsDependentContext && RequireCompleteDeclContext(D.getCXXScopeSpec(), DC)) - return DeclPtrTy(); + return 0; if (isa(DC) && !cast(DC)->hasDefinition()) { Diag(D.getIdentifierLoc(), @@ -2122,7 +2270,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType R = TInfo->getType(); - LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); // See if this is a redefinition of a variable in the same scope. @@ -2140,7 +2288,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, IsLinkageLookup = true; } else if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern) IsLinkageLookup = true; - else if (CurContext->getLookupContext()->isTranslationUnit() && + else if (CurContext->getRedeclContext()->isTranslationUnit() && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) IsLinkageLookup = true; @@ -2225,7 +2373,7 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { if (TemplateParamLists.size()) { Diag(D.getIdentifierLoc(), diag::err_template_typedef); - return DeclPtrTy(); + return 0; } New = ActOnTypedefDeclarator(S, D, DC, R, TInfo, Previous, Redeclaration); @@ -2240,14 +2388,14 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, } if (New == 0) - return DeclPtrTy(); + return 0; // If this has an identifier and is not an invalid redeclaration or // function template specialization, add it to the scope stack. - if (Name && !(Redeclaration && New->isInvalidDecl())) + if (New->getDeclName() && !(Redeclaration && New->isInvalidDecl())) PushOnScopeChains(New, S); - return DeclPtrTy::make(New); + return New; } /// TryToFixInvalidVariablyModifiedType - Helper method to turn variable array @@ -2255,20 +2403,26 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, /// be errors (for GCC compatibility). static QualType TryToFixInvalidVariablyModifiedType(QualType T, ASTContext &Context, - bool &SizeIsNegative) { + bool &SizeIsNegative, + llvm::APSInt &Oversized) { // This method tries to turn a variable array into a constant // array even when the size isn't an ICE. This is necessary // for compatibility with code that depends on gcc's buggy // constant expression folding, like struct {char x[(int)(char*)2];} SizeIsNegative = false; - + Oversized = 0; + + if (T->isDependentType()) + return QualType(); + QualifierCollector Qs; const Type *Ty = Qs.strip(T); if (const PointerType* PTy = dyn_cast(Ty)) { QualType Pointee = PTy->getPointeeType(); QualType FixedType = - TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative); + TryToFixInvalidVariablyModifiedType(Pointee, Context, SizeIsNegative, + Oversized); if (FixedType.isNull()) return FixedType; FixedType = Context.getPointerType(FixedType); return Qs.apply(FixedType); @@ -2287,15 +2441,24 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, !EvalResult.Val.isInt()) return QualType(); + // Check whether the array size is negative. llvm::APSInt &Res = EvalResult.Val.getInt(); - if (Res >= llvm::APSInt(Res.getBitWidth(), Res.isUnsigned())) { - // TODO: preserve the size expression in declarator info - return Context.getConstantArrayType(VLATy->getElementType(), - Res, ArrayType::Normal, 0); + if (Res.isSigned() && Res.isNegative()) { + SizeIsNegative = true; + return QualType(); } - SizeIsNegative = true; - return QualType(); + // Check whether the array is too large to be addressed. + unsigned ActiveSizeBits + = ConstantArrayType::getNumAddressingBits(Context, VLATy->getElementType(), + Res); + if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { + Oversized = Res; + return QualType(); + } + + return Context.getConstantArrayType(VLATy->getElementType(), + Res, ArrayType::Normal, 0); } /// \brief Register the given locally-scoped external C declaration so @@ -2320,11 +2483,11 @@ Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, if (S && IdResolver.ReplaceDecl(PrevDecl, ND)) { // The previous declaration was found on the identifer resolver // chain, so remove it from its scope. - while (S && !S->isDeclScope(DeclPtrTy::make(PrevDecl))) + while (S && !S->isDeclScope(PrevDecl)) S = S->getParent(); if (S) - S->RemoveDecl(DeclPtrTy::make(PrevDecl)); + S->RemoveDecl(PrevDecl); } } @@ -2382,24 +2545,20 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewTD, D); - // Merge the decl with the existing one if appropriate. If the decl is - // in an outer scope, it isn't the same thing. - FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false); - if (!Previous.empty()) { - Redeclaration = true; - MergeTypeDefDecl(NewTD, Previous); - } - // C99 6.7.7p2: If a typedef name specifies a variably modified type // then it shall have block scope. + // Note that variably modified types must be fixed before merging the decl so + // that redeclarations will match. QualType T = NewTD->getUnderlyingType(); if (T->isVariablyModifiedType()) { - FunctionNeedsScopeChecking() = true; + getCurFunction()->setHasBranchProtectedScope(); if (S->getFnParent() == 0) { bool SizeIsNegative; + llvm::APSInt Oversized; QualType FixedTy = - TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); + TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative, + Oversized); if (!FixedTy.isNull()) { Diag(D.getIdentifierLoc(), diag::warn_illegal_constant_array_size); NewTD->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(FixedTy)); @@ -2408,6 +2567,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(D.getIdentifierLoc(), diag::err_typecheck_negative_array_size); else if (T->isVariableArrayType()) Diag(D.getIdentifierLoc(), diag::err_vla_decl_in_file_scope); + else if (Oversized.getBoolValue()) + Diag(D.getIdentifierLoc(), diag::err_array_too_large) + << Oversized.toString(10); else Diag(D.getIdentifierLoc(), diag::err_vm_decl_in_file_scope); NewTD->setInvalidDecl(); @@ -2415,10 +2577,18 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } + // Merge the decl with the existing one if appropriate. If the decl is + // in an outer scope, it isn't the same thing. + FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false); + if (!Previous.empty()) { + Redeclaration = true; + MergeTypeDefDecl(NewTD, Previous); + } + // If this is the C FILE type, notify the AST context. if (IdentifierInfo *II = NewTD->getIdentifier()) if (!NewTD->isInvalidDecl() && - NewTD->getDeclContext()->getLookupContext()->isTranslationUnit()) { + NewTD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { if (II->isStr("FILE")) Context.setFILEDecl(NewTD); else if (II->isStr("jmp_buf")) @@ -2452,7 +2622,7 @@ static bool isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, ASTContext &Context) { if (!PrevDecl) - return 0; + return false; if (!PrevDecl->hasLinkage()) return false; @@ -2464,30 +2634,25 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, // outside the innermost enclosing namespace scope, the block // scope declaration declares that same entity and receives the // linkage of the previous declaration. - DeclContext *OuterContext = DC->getLookupContext(); + DeclContext *OuterContext = DC->getRedeclContext(); if (!OuterContext->isFunctionOrMethod()) // This rule only applies to block-scope declarations. return false; - else { - DeclContext *PrevOuterContext = PrevDecl->getDeclContext(); - if (PrevOuterContext->isRecord()) - // We found a member function: ignore it. - return false; - else { - // Find the innermost enclosing namespace for the new and - // previous declarations. - while (!OuterContext->isFileContext()) - OuterContext = OuterContext->getParent(); - while (!PrevOuterContext->isFileContext()) - PrevOuterContext = PrevOuterContext->getParent(); - - // The previous declaration is in a different namespace, so it - // isn't the same function. - if (OuterContext->getPrimaryContext() != - PrevOuterContext->getPrimaryContext()) - return false; - } - } + + DeclContext *PrevOuterContext = PrevDecl->getDeclContext(); + if (PrevOuterContext->isRecord()) + // We found a member function: ignore it. + return false; + + // Find the innermost enclosing namespace for the new and + // previous declarations. + OuterContext = OuterContext->getEnclosingNamespaceContext(); + PrevOuterContext = PrevOuterContext->getEnclosingNamespaceContext(); + + // The previous declaration is in a different namespace, so it + // isn't the same function. + if (!OuterContext->Equals(PrevOuterContext)) + return false; } return true; @@ -2506,7 +2671,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &Redeclaration) { - DeclarationName Name = GetNameForDeclarator(D); + DeclarationName Name = GetNameForDeclarator(D).getName(); // Check that there are no default arguments (C++ only). if (getLangOptions().CPlusPlus) @@ -2515,17 +2680,17 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); assert(SCSpec != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class VarDecl."); - VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec, 0); + VarDecl::StorageClass SC = StorageClassSpecToVarDeclStorageClass(SCSpec); if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here Diag(D.getIdentifierLoc(), diag::err_mutable_nonmember); D.setInvalidType(); - SC = VarDecl::None; + SC = SC_None; } SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); VarDecl::StorageClass SCAsWritten - = StorageClassSpecToVarDeclStorageClass(SCSpec, DC); + = StorageClassSpecToVarDeclStorageClass(SCSpec); IdentifierInfo *II = Name.getAsIdentifierInfo(); if (!II) { @@ -2539,11 +2704,11 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (!DC->isRecord() && S->getFnParent() == 0) { // C99 6.9p2: The storage-class specifiers auto and register shall not // appear in the declaration specifiers in an external declaration. - if (SC == VarDecl::Auto || SC == VarDecl::Register) { + if (SC == SC_Auto || SC == SC_Register) { // If this is a register variable with an asm label specified, then this // is a GNU extension. - if (SC == VarDecl::Register && D.getAsmLabel()) + if (SC == SC_Register && D.getAsmLabel()) Diag(D.getIdentifierLoc(), diag::err_unsupported_global_register); else Diag(D.getIdentifierLoc(), diag::err_typecheck_sclass_fscope); @@ -2552,14 +2717,14 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, } if (DC->isRecord() && !CurContext->isRecord()) { // This is an out-of-line definition of a static data member. - if (SC == VarDecl::Static) { + if (SC == SC_Static) { Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_out_of_line) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); - } else if (SC == VarDecl::None) - SC = VarDecl::Static; + } else if (SC == SC_None) + SC = SC_Static; } - if (SC == VarDecl::Static) { + if (SC == SC_Static) { if (const CXXRecordDecl *RD = dyn_cast(DC)) { if (RD->isLocalClass()) Diag(D.getIdentifierLoc(), @@ -2613,7 +2778,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, SetNestedNameSpecifier(NewVD, D); - if (NumMatchedTemplateParamLists > 0) { + if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) { NewVD->setTemplateParameterListsInfo(Context, NumMatchedTemplateParamLists, (TemplateParameterList**)TemplateParamLists.release()); @@ -2639,7 +2804,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast(E); - NewVD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getString())); + NewVD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), + Context, SE->getString())); } // Diagnose shadowed variables before filtering for scope. @@ -2679,6 +2845,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewVD->setInvalidDecl(); // attributes declared post-definition are currently ignored + // FIXME: This should be handled in attribute merging, not + // here. if (Previous.isSingleResult()) { VarDecl *Def = dyn_cast(Previous.getFoundDecl()); if (Def && (Def = Def->getDefinition()) && @@ -2694,6 +2862,13 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, !NewVD->isInvalidDecl()) RegisterLocallyScopedExternCDecl(NewVD, Previous, S); + // If there's a #pragma GCC visibility in scope, and this isn't a class + // member, set the visibility of this variable. + if (NewVD->getLinkage() == ExternalLinkage && !DC->isRecord()) + AddPushedVisibilityAttribute(NewVD); + + MarkUnusedFileScopedDecl(NewVD); + return NewVD; } @@ -2807,19 +2982,16 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, bool isVM = T->isVariablyModifiedType(); if (isVM || NewVD->hasAttr() || - NewVD->hasAttr() || - // FIXME: We need to diagnose jumps passed initialized variables in C++. - // However, this turns on the scope checker for everything with a variable - // which may impact compile time. See if we can find a better solution - // to this, perhaps only checking functions that contain gotos in C++? - (LangOpts.CPlusPlus && NewVD->hasLocalStorage())) - FunctionNeedsScopeChecking() = true; + NewVD->hasAttr()) + getCurFunction()->setHasBranchProtectedScope(); if ((isVM && NewVD->hasLinkage()) || (T->isVariableArrayType() && NewVD->hasGlobalStorage())) { bool SizeIsNegative; + llvm::APSInt Oversized; QualType FixedTy = - TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative); + TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative, + Oversized); if (FixedTy.isNull() && T->isVariableArrayType()) { const VariableArrayType *VAT = Context.getAsVariableArrayType(T); @@ -2830,7 +3002,7 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, if (NewVD->isFileVarDecl()) Diag(NewVD->getLocation(), diag::err_vla_decl_in_file_scope) << SizeRange; - else if (NewVD->getStorageClass() == VarDecl::Static) + else if (NewVD->getStorageClass() == SC_Static) Diag(NewVD->getLocation(), diag::err_vla_decl_has_static_storage) << SizeRange; else @@ -2970,8 +3142,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, bool IsFunctionDefinition, bool &Redeclaration) { assert(R.getTypePtr()->isFunctionType()); - DeclarationName Name = GetNameForDeclarator(D); - FunctionDecl::StorageClass SC = FunctionDecl::None; + // TODO: consider using NameInfo for diagnostic. + DeclarationNameInfo NameInfo = GetNameForDeclarator(D); + DeclarationName Name = NameInfo.getName(); + FunctionDecl::StorageClass SC = SC_None; switch (D.getDeclSpec().getStorageClassSpec()) { default: assert(0 && "Unknown storage class!"); case DeclSpec::SCS_auto: @@ -2981,10 +3155,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, diag::err_typecheck_sclass_func); D.setInvalidType(); break; - case DeclSpec::SCS_unspecified: SC = FunctionDecl::None; break; - case DeclSpec::SCS_extern: SC = FunctionDecl::Extern; break; + case DeclSpec::SCS_unspecified: SC = SC_None; break; + case DeclSpec::SCS_extern: SC = SC_Extern; break; case DeclSpec::SCS_static: { - if (CurContext->getLookupContext()->isFunctionOrMethod()) { + if (CurContext->getRedeclContext()->isFunctionOrMethod()) { // C99 6.7.1p5: // The declaration of an identifier for a function that has // block scope shall have no explicit storage-class specifier @@ -2992,12 +3166,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // See also (C++ [dcl.stc]p4). Diag(D.getDeclSpec().getStorageClassSpecLoc(), diag::err_static_block_func); - SC = FunctionDecl::None; + SC = SC_None; } else - SC = FunctionDecl::Static; + SC = SC_Static; break; } - case DeclSpec::SCS_private_extern: SC = FunctionDecl::PrivateExtern;break; + case DeclSpec::SCS_private_extern: SC = SC_PrivateExtern;break; } if (D.getDeclSpec().isThreadSpecified()) @@ -3010,7 +3184,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpecAsWritten(); FunctionDecl::StorageClass SCAsWritten - = StorageClassSpecToFunctionDeclStorageClass(SCSpec, DC); + = StorageClassSpecToFunctionDeclStorageClass(SCSpec); // Check that the return type is not an abstract class type. // For record types, this is done by the AbstractClassUsageDiagnoser once @@ -3050,7 +3224,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Create the new declaration NewFD = CXXConstructorDecl::Create(Context, cast(DC), - D.getIdentifierLoc(), Name, R, TInfo, + NameInfo, R, TInfo, isExplicit, isInline, /*isImplicitlyDeclared=*/false); } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { @@ -3060,7 +3234,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD = CXXDestructorDecl::Create(Context, cast(DC), - D.getIdentifierLoc(), Name, R, + NameInfo, R, isInline, /*isImplicitlyDeclared=*/false); NewFD->setTypeSourceInfo(TInfo); @@ -3085,7 +3259,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, CheckConversionDeclarator(D, R, SC); NewFD = CXXConversionDecl::Create(Context, cast(DC), - D.getIdentifierLoc(), Name, R, TInfo, + NameInfo, R, TInfo, isInline, isExplicit); isVirtualOkay = true; @@ -3103,7 +3277,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, return 0; } - bool isStatic = SC == FunctionDecl::Static; + bool isStatic = SC == SC_Static; // [class.free]p1: // Any allocation function for a class T is a static member @@ -3120,7 +3294,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // This is a C++ method declaration. NewFD = CXXMethodDecl::Create(Context, cast(DC), - D.getIdentifierLoc(), Name, R, TInfo, + NameInfo, R, TInfo, isStatic, SCAsWritten, isInline); isVirtualOkay = !isStatic; @@ -3137,8 +3311,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, (!isa(R.getTypePtr()) && R->isFunctionProtoType()); NewFD = FunctionDecl::Create(Context, DC, - D.getIdentifierLoc(), - Name, R, TInfo, SC, SCAsWritten, isInline, + NameInfo, R, TInfo, SC, SCAsWritten, isInline, HasPrototype); } @@ -3212,7 +3385,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } - if (NumMatchedTemplateParamLists > 0) { + if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) { NewFD->setTemplateParameterListsInfo(Context, NumMatchedTemplateParamLists, (TemplateParameterList**)TemplateParamLists.release()); @@ -3244,6 +3417,17 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } + // C++ [dcl.fct.spec]p3: + // The inline specifier shall not appear on a block scope function declaration. + if (isInline && !NewFD->isInvalidDecl() && getLangOptions().CPlusPlus) { + if (CurContext->isFunctionOrMethod()) { + // 'inline' is not allowed on block scope function declaration. + Diag(D.getDeclSpec().getInlineSpecLoc(), + diag::err_inline_declaration_block_scope) << Name + << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); + } + } + // C++ [dcl.fct.spec]p6: // The explicit specifier shall be used only in the declaration of a // constructor or conversion function within its class definition; see 12.3.1 @@ -3282,7 +3466,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD->setAccess(AS_public); } - if (SC == FunctionDecl::Static && isa(NewFD) && + if (SC == SC_Static && isa(NewFD) && !CurContext->isRecord()) { // C++ [class.static]p1: // A data or function member of a class may be declared static @@ -3300,7 +3484,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast(E); - NewFD->addAttr(::new (Context) AsmLabelAttr(Context, SE->getString())); + NewFD->addAttr(::new (Context) AsmLabelAttr(SE->getStrTokenLoc(0), Context, + SE->getString())); } // Copy the parameter declarations from the declarator D to the function @@ -3316,9 +3501,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // already checks for that case. if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && FTI.ArgInfo[0].Param && - FTI.ArgInfo[0].Param.getAs()->getType()->isVoidType()) { + cast(FTI.ArgInfo[0].Param)->getType()->isVoidType()) { // Empty arg list, don't push any params. - ParmVarDecl *Param = FTI.ArgInfo[0].Param.getAs(); + ParmVarDecl *Param = cast(FTI.ArgInfo[0].Param); // In C++, the empty parameter-type-list must be spelled "void"; a // typedef of void is not permitted. @@ -3328,7 +3513,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // FIXME: Leaks decl? } else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) { for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { - ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs(); + ParmVarDecl *Param = cast(FTI.ArgInfo[i].Param); assert(Param->getDeclContext() != NewFD && "Was set before ?"); Param->setDeclContext(NewFD); Params.push_back(Param); @@ -3479,14 +3664,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // definition (C++ [dcl.meaning]p1). // Note that this is not the case for explicit specializations of // function templates or member functions of class templates, per - // C++ [temp.expl.spec]p2. + // C++ [temp.expl.spec]p2. We also allow these declarations as an extension + // for compatibility with old SWIG code which likes to generate them. if (!IsFunctionDefinition && !isFriend && !isFunctionTemplateSpecialization && !isExplicitSpecialization) { - Diag(NewFD->getLocation(), diag::err_out_of_line_declaration) + Diag(NewFD->getLocation(), diag::ext_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); - NewFD->setInvalidDecl(); - } else if (!Redeclaration && - !(isFriend && CurContext->isDependentContext())) { + } + if (!Redeclaration && !(isFriend && CurContext->isDependentContext())) { // The user tried to provide an out-of-line definition for a // function that is a member of a class or namespace, but there // was no such member function declared (C++ [class.mfct]p2, @@ -3526,6 +3711,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, ProcessDeclAttributes(S, NewFD, D); // attributes declared post-definition are currently ignored + // FIXME: This should happen during attribute merging if (Redeclaration && Previous.isSingleResult()) { const FunctionDecl *Def; FunctionDecl *PrevFD = dyn_cast(Previous.getFoundDecl()); @@ -3537,7 +3723,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, AddKnownFunctionAttributes(NewFD); - if (OverloadableAttrRequired && !NewFD->getAttr()) { + if (OverloadableAttrRequired && !NewFD->hasAttr()) { // If a function name is overloadable in C, then every function // with that name must be marked "overloadable". Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing) @@ -3545,9 +3731,28 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (!Previous.empty()) Diag(Previous.getRepresentativeDecl()->getLocation(), diag::note_attribute_overloadable_prev_overload); - NewFD->addAttr(::new (Context) OverloadableAttr()); + NewFD->addAttr(::new (Context) OverloadableAttr(SourceLocation(), Context)); + } + + if (NewFD->hasAttr() && + !NewFD->getType()->getAs()) { + Diag(NewFD->getLocation(), + diag::err_attribute_overloadable_no_prototype) + << NewFD; + + // Turn this into a variadic function with no parameters. + const FunctionType *FT = NewFD->getType()->getAs(); + QualType R = Context.getFunctionType(FT->getResultType(), + 0, 0, true, 0, false, false, 0, 0, + FT->getExtInfo()); + NewFD->setType(R); } + // If there's a #pragma GCC visibility in scope, and this isn't a class + // member, set the visibility of this function. + if (NewFD->getLinkage() == ExternalLinkage && !DC->isRecord()) + AddPushedVisibilityAttribute(NewFD); + // If this is a locally-scoped extern C function, update the // map of such names. if (CurContext->isFunctionOrMethod() && NewFD->isExternC() @@ -3563,17 +3768,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (FunctionTemplate) return FunctionTemplate; - - // Keep track of static, non-inlined function definitions that - // have not been used. We will warn later. - // FIXME: Also include static functions declared but not defined. - if (!NewFD->isInvalidDecl() && IsFunctionDefinition - && !NewFD->isInlined() && NewFD->getLinkage() == InternalLinkage - && !NewFD->isUsed() && !NewFD->hasAttr() - && !NewFD->hasAttr() - && !NewFD->hasAttr()) - UnusedStaticFuncs.push_back(NewFD); - + MarkUnusedFileScopedDecl(NewFD); + return NewFD; } @@ -3597,8 +3793,14 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, bool &Redeclaration, bool &OverloadableAttrRequired) { // If NewFD is already known erroneous, don't do any of this checking. - if (NewFD->isInvalidDecl()) + if (NewFD->isInvalidDecl()) { + // If this is a class member, mark the class invalid immediately. + // This avoids some consistency errors later. + if (isa(NewFD)) + cast(NewFD)->getParent()->setInvalidDecl(); + return; + } if (NewFD->getResultType()->isVariablyModifiedType()) { // Functions returning a variably modified type violate C99 6.7.5.2p2 @@ -3634,27 +3836,9 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, Redeclaration = true; OldDecl = Previous.getFoundDecl(); } else { - if (!getLangOptions().CPlusPlus) { + if (!getLangOptions().CPlusPlus) OverloadableAttrRequired = true; - // Functions marked "overloadable" must have a prototype (that - // we can't get through declaration merging). - if (!NewFD->getType()->getAs()) { - Diag(NewFD->getLocation(), - diag::err_attribute_overloadable_no_prototype) - << NewFD; - Redeclaration = true; - - // Turn this into a variadic function with no parameters. - QualType R = Context.getFunctionType( - NewFD->getType()->getAs()->getResultType(), - 0, 0, true, 0, false, false, 0, 0, - FunctionType::ExtInfo()); - NewFD->setType(R); - return NewFD->setInvalidDecl(); - } - } - switch (CheckOverload(S, NewFD, Previous, OldDecl, /*NewIsUsingDecl*/ false)) { case Ovl_Match: @@ -3723,6 +3907,8 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, DeclarationName Name = Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(ClassType)); +// NewFD->getDeclName().dump(); +// Name.dump(); if (NewFD->getDeclName() != Name) { Diag(NewFD->getLocation(), diag::err_destructor_name); return NewFD->setInvalidDecl(); @@ -3750,12 +3936,6 @@ void Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, AddOverriddenMethods(Method->getParent(), Method); } - // Additional checks for the destructor; make sure we do this after we - // figure out whether the destructor is virtual. - if (CXXDestructorDecl *Destructor = dyn_cast(NewFD)) - if (!Destructor->getParent()->isDependentType()) - CheckDestructor(Destructor); - // Extra checking for C++ overloaded operators (C++ [over.oper]). if (NewFD->isOverloadedOperator() && CheckOverloadedOperatorDeclaration(NewFD)) @@ -3781,7 +3961,7 @@ void Sema::CheckMain(FunctionDecl* FD) { // shall not appear in a declaration of main. // static main is not an error under C99, but we should warn about it. bool isInline = FD->isInlineSpecified(); - bool isStatic = FD->getStorageClass() == FunctionDecl::Static; + bool isStatic = FD->getStorageClass() == SC_Static; if (isInline || isStatic) { unsigned diagID = diag::warn_unusual_main_decl; if (isInline || getLangOptions().CPlusPlus) @@ -3874,22 +4054,21 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { // "may accept other forms of constant expressions" exception. // (We never end up here for C++, so the constant expression // rules there don't matter.) - if (Init->isConstantInitializer(Context)) + if (Init->isConstantInitializer(Context, false)) return false; Diag(Init->getExprLoc(), diag::err_init_element_not_constant) << Init->getSourceRange(); return true; } -void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init) { - AddInitializerToDecl(dcl, move(init), /*DirectInit=*/false); +void Sema::AddInitializerToDecl(Decl *dcl, Expr *init) { + AddInitializerToDecl(dcl, init, /*DirectInit=*/false); } /// AddInitializerToDecl - Adds the initializer Init to the /// declaration dcl. If DirectInit is true, this is C++ direct /// initialization rather than copy initialization. -void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { - Decl *RealDecl = dcl.getAs(); +void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // If there is no declaration, there was an error parsing it. Just ignore // the initializer. if (RealDecl == 0) @@ -3900,7 +4079,6 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { // distinguish between a normal initializer and a pure-specifier. // Thus this grotesque test. IntegerLiteral *IL; - Expr *Init = static_cast(init.get()); if ((IL = dyn_cast(Init)) && IL->getValue() == 0 && Context.getCanonicalType(IL->getType()) == Context.IntTy) CheckPureMethod(Method, Init->getSourceRange()); @@ -3925,6 +4103,8 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { return; } + + // A definition must end up with a complete type, which means it must be // complete with the restriction that an array type might be completed by the // initializer; note that later code assumes this restriction. @@ -3951,11 +4131,28 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { VDecl->setInvalidDecl(); return; } + + // C++ [class.static.data]p4 + // If a static data member is of const integral or const + // enumeration type, its declaration in the class definition can + // specify a constant-initializer which shall be an integral + // constant expression (5.19). In that case, the member can appear + // in integral constant expressions. The member shall still be + // defined in a namespace scope if it is used in the program and the + // namespace scope definition shall not contain an initializer. + // + // We already performed a redefinition check above, but for static + // data members we also need to check whether there was an in-class + // declaration with an initializer. + const VarDecl* PrevInit = 0; + if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) { + Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); + Diag(PrevInit->getLocation(), diag::note_previous_definition); + return; + } - // Take ownership of the expression, now that we're sure we have somewhere - // to put it. - Expr *Init = init.takeAs(); - assert(Init && "missing initializer"); + if (getLangOptions().CPlusPlus && VDecl->hasLocalStorage()) + getCurFunction()->setHasBranchProtectedScope(); // Capture the variable that is being initialized and the style of // initialization. @@ -3978,8 +4175,8 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { VDecl->setInvalidDecl(); } else if (!VDecl->isInvalidDecl()) { InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); - OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, (void**)&Init, 1), + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, &Init, 1), &DclT); if (Result.isInvalid()) { VDecl->setInvalidDecl(); @@ -3991,7 +4188,7 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { // C++ 3.6.2p2, allow dynamic initialization of static initializers. // Don't check invalid declarations to avoid emitting useless diagnostics. if (!getLangOptions().CPlusPlus && !VDecl->isInvalidDecl()) { - if (VDecl->getStorageClass() == VarDecl::Static) // C99 6.7.8p4. + if (VDecl->getStorageClass() == SC_Static) // C99 6.7.8p4. CheckForConstantInitializer(Init, DclT); } } @@ -4039,18 +4236,18 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { << Init->getSourceRange(); VDecl->setInvalidDecl(); } else if (!VDecl->getType()->isDependentType()) - ImpCastExprToType(Init, VDecl->getType(), CastExpr::CK_IntegralCast); + ImpCastExprToType(Init, VDecl->getType(), CK_IntegralCast); } } } else if (VDecl->isFileVarDecl()) { - if (VDecl->getStorageClass() == VarDecl::Extern && + if (VDecl->getStorageClass() == SC_Extern && (!getLangOptions().CPlusPlus || !Context.getBaseElementType(VDecl->getType()).isConstQualified())) Diag(VDecl->getLocation(), diag::warn_extern_init); if (!VDecl->isInvalidDecl()) { InitializationSequence InitSeq(*this, Entity, Kind, &Init, 1); - OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, (void**)&Init, 1), + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, &Init, 1), &DclT); if (Result.isInvalid()) { VDecl->setInvalidDecl(); @@ -4081,6 +4278,14 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { VDecl->setInit(Init); if (getLangOptions().CPlusPlus) { + if (!VDecl->isInvalidDecl() && + !VDecl->getDeclContext()->isDependentContext() && + VDecl->hasGlobalStorage() && !VDecl->isStaticLocal() && + !Init->isConstantInitializer(Context, + VDecl->getType()->isReferenceType())) + Diag(VDecl->getLocation(), diag::warn_global_constructor) + << Init->getSourceRange(); + // Make sure we mark the destructor as used if necessary. QualType InitType = VDecl->getType(); while (const ArrayType *Array = Context.getAsArrayType(InitType)) @@ -4095,10 +4300,9 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) { /// ActOnInitializerError - Given that there was an error parsing an /// initializer for the given declaration, try to return to some form /// of sanity. -void Sema::ActOnInitializerError(DeclPtrTy dcl) { +void Sema::ActOnInitializerError(Decl *D) { // Our main concern here is re-establishing invariants like "a // variable's type is either dependent or complete". - Decl *D = dcl.getAs(); if (!D || D->isInvalidDecl()) return; VarDecl *VD = dyn_cast(D); @@ -4127,10 +4331,8 @@ void Sema::ActOnInitializerError(DeclPtrTy dcl) { // though. } -void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, +void Sema::ActOnUninitializedDecl(Decl *RealDecl, bool TypeContainsUndeducedAuto) { - Decl *RealDecl = dcl.getAs(); - // If there is no declaration, there was an error parsing it. Just ignore it. if (RealDecl == 0) return; @@ -4190,7 +4392,7 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, ArrayT->getElementType(), diag::err_illegal_decl_array_incomplete_type)) Var->setInvalidDecl(); - } else if (Var->getStorageClass() == VarDecl::Static) { + } else if (Var->getStorageClass() == SC_Static) { // C99 6.9.2p3: If the declaration of an identifier for an object is // a tentative definition and has internal linkage (C99 6.2.2p3), the // declared type shall not be an incomplete type. @@ -4221,15 +4423,15 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, return; } - // Provide a specific diagnostic for uninitialized variable - // definitions with reference type. - if (Type->isReferenceType()) { - Diag(Var->getLocation(), diag::err_reference_var_requires_init) - << Var->getDeclName() - << SourceRange(Var->getLocation(), Var->getLocation()); - Var->setInvalidDecl(); - return; - } + // Provide a specific diagnostic for uninitialized variable + // definitions with reference type. + if (Type->isReferenceType()) { + Diag(Var->getLocation(), diag::err_reference_var_requires_init) + << Var->getDeclName() + << SourceRange(Var->getLocation(), Var->getLocation()); + Var->setInvalidDecl(); + return; + } // Do not attempt to type-check the default initializer for a // variable with dependent type. @@ -4271,17 +4473,30 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, // program is ill-formed. // FIXME: DPG thinks it is very fishy that C++0x disables this. } else { + // Check for jumps past the implicit initializer. C++0x + // clarifies that this applies to a "variable with automatic + // storage duration", not a "local variable". + if (getLangOptions().CPlusPlus && Var->hasLocalStorage()) + getCurFunction()->setHasBranchProtectedScope(); + InitializedEntity Entity = InitializedEntity::InitializeVariable(Var); InitializationKind Kind = InitializationKind::CreateDefault(Var->getLocation()); InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); - OwningExprResult Init = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, 0, 0)); + ExprResult Init = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, 0, 0)); if (Init.isInvalid()) Var->setInvalidDecl(); - else if (Init.get()) + else if (Init.get()) { Var->setInit(MaybeCreateCXXExprWithTemporaries(Init.takeAs())); + + if (getLangOptions().CPlusPlus && !Var->isInvalidDecl() && + Var->hasGlobalStorage() && !Var->isStaticLocal() && + !Var->getDeclContext()->isDependentContext() && + !Var->getInit()->isConstantInitializer(Context, false)) + Diag(Var->getLocation(), diag::warn_global_constructor); + } } if (!Var->isInvalidDecl() && getLangOptions().CPlusPlus && Record) @@ -4289,16 +4504,16 @@ void Sema::ActOnUninitializedDecl(DeclPtrTy dcl, } } -Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, - DeclPtrTy *Group, - unsigned NumDecls) { +Sema::DeclGroupPtrTy +Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, + Decl **Group, unsigned NumDecls) { llvm::SmallVector Decls; if (DS.isTypeSpecOwned()) - Decls.push_back((Decl*)DS.getTypeRep()); + Decls.push_back(DS.getRepAsDecl()); for (unsigned i = 0; i != NumDecls; ++i) - if (Decl *D = Group[i].getAs()) + if (Decl *D = Group[i]) Decls.push_back(D); return DeclGroupPtrTy::make(DeclGroupRef::Create(Context, @@ -4308,16 +4523,15 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, /// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator() /// to introduce parameters into function prototype scope. -Sema::DeclPtrTy -Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { +Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { const DeclSpec &DS = D.getDeclSpec(); // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'. - VarDecl::StorageClass StorageClass = VarDecl::None; - VarDecl::StorageClass StorageClassAsWritten = VarDecl::None; + VarDecl::StorageClass StorageClass = SC_None; + VarDecl::StorageClass StorageClassAsWritten = SC_None; if (DS.getStorageClassSpec() == DeclSpec::SCS_register) { - StorageClass = VarDecl::Register; - StorageClassAsWritten = VarDecl::Register; + StorageClass = SC_Register; + StorageClassAsWritten = SC_Register; } else if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified) { Diag(DS.getStorageClassSpecLoc(), diag::err_invalid_storage_class_in_func_decl); @@ -4358,7 +4572,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); // Just pretend that we didn't see the previous declaration. PrevDecl = 0; - } else if (S->isDeclScope(DeclPtrTy::make(PrevDecl))) { + } else if (S->isDeclScope(PrevDecl)) { Diag(D.getIdentifierLoc(), diag::err_param_redefinition) << II; Diag(PrevDecl->getLocation(), diag::note_previous_declaration); @@ -4389,7 +4603,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { } // Add the parameter declaration into this scope. - S->AddDecl(DeclPtrTy::make(New)); + S->AddDecl(New); if (II) IdResolver.AddDecl(New); @@ -4398,7 +4612,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (New->hasAttr()) { Diag(New->getLocation(), diag::err_block_on_nonlocal); } - return DeclPtrTy::make(New); + return New; } /// \brief Synthesizes a variable for a parameter arising from a @@ -4408,11 +4622,31 @@ ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC, QualType T) { ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, 0, T, Context.getTrivialTypeSourceInfo(T, Loc), - VarDecl::None, VarDecl::None, 0); + SC_None, SC_None, 0); Param->setImplicit(); return Param; } +void Sema::DiagnoseUnusedParameters(ParmVarDecl * const *Param, + ParmVarDecl * const *ParamEnd) { + if (Diags.getDiagnosticLevel(diag::warn_unused_parameter) == + Diagnostic::Ignored) + return; + + // Don't diagnose unused-parameter errors in template instantiations; we + // will already have done so in the template itself. + if (!ActiveTemplateInstantiations.empty()) + return; + + for (; Param != ParamEnd; ++Param) { + if (!(*Param)->isUsed() && (*Param)->getDeclName() && + !(*Param)->hasAttr()) { + Diag((*Param)->getLocation(), diag::warn_unused_parameter) + << (*Param)->getDeclName(); + } + } +} + ParmVarDecl *Sema::CheckParameter(DeclContext *DC, TypeSourceInfo *TSInfo, QualType T, IdentifierInfo *Name, @@ -4487,8 +4721,8 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, } } -Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, - Declarator &D) { +Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, + Declarator &D) { assert(getCurFunctionDecl() == 0 && "Function parsing confused"); assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && "Not a function declarator!"); @@ -4500,9 +4734,9 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Scope *ParentScope = FnBodyScope->getParent(); - DeclPtrTy DP = HandleDeclarator(ParentScope, D, - MultiTemplateParamsArg(*this), - /*IsFunctionDefinition=*/true); + Decl *DP = HandleDeclarator(ParentScope, D, + MultiTemplateParamsArg(*this), + /*IsFunctionDefinition=*/true); return ActOnStartOfFunctionDef(FnBodyScope, DP); } @@ -4550,7 +4784,7 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) { return MissingPrototype; } -Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { +Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { // Clear the last template instantiation error context. LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation(); @@ -4558,11 +4792,10 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { return D; FunctionDecl *FD = 0; - if (FunctionTemplateDecl *FunTmpl - = dyn_cast(D.getAs())) + if (FunctionTemplateDecl *FunTmpl = dyn_cast(D)) FD = FunTmpl->getTemplatedDecl(); else - FD = cast(D.getAs()); + FD = cast(D); // Enter a new function scope PushFunctionScope(); @@ -4627,15 +4860,15 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { // Checking attributes of current function definition // dllimport attribute. - if (FD->getAttr() && - (!FD->getAttr())) { - // dllimport attribute cannot be applied to definition. - if (!(FD->getAttr())->isInherited()) { + DLLImportAttr *DA = FD->getAttr(); + if (DA && (!FD->getAttr())) { + // dllimport attribute cannot be directly applied to definition. + if (!DA->isInherited()) { Diag(FD->getLocation(), diag::err_attribute_can_be_applied_only_to_symbol_declaration) << "dllimport"; FD->setInvalidDecl(); - return DeclPtrTy::make(FD); + return FD; } // Visual C++ appears to not think this is an issue, so only issue @@ -4646,10 +4879,10 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { // emitted. Diag(FD->getLocation(), diag::warn_redeclaration_without_attribute_prev_attribute_ignored) - << FD->getNameAsCString() << "dllimport"; + << FD->getName() << "dllimport"; } } - return DeclPtrTy::make(FD); + return FD; } /// \brief Given the set of return statements within a function body, @@ -4668,9 +4901,11 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) { /// FIXME: Employ a smarter algorithm that accounts for multiple return /// statements and the lifetimes of the NRVO candidates. We should be able to /// find a maximal set of NRVO variables. -static void ComputeNRVO(Stmt *Body, ReturnStmt **Returns, unsigned NumReturns) { +static void ComputeNRVO(Stmt *Body, FunctionScopeInfo *Scope) { + ReturnStmt **Returns = Scope->Returns.data(); + const VarDecl *NRVOCandidate = 0; - for (unsigned I = 0; I != NumReturns; ++I) { + for (unsigned I = 0, E = Scope->Returns.size(); I != E; ++I) { if (!Returns[I]->getNRVOCandidate()) return; @@ -4684,15 +4919,12 @@ static void ComputeNRVO(Stmt *Body, ReturnStmt **Returns, unsigned NumReturns) { const_cast(NRVOCandidate)->setNRVOVariable(true); } -Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg) { +Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) { return ActOnFinishFunctionBody(D, move(BodyArg), false); } -Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, - bool IsInstantiation) { - Decl *dcl = D.getAs(); - Stmt *Body = BodyArg.takeAs(); - +Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, + bool IsInstantiation) { FunctionDecl *FD = 0; FunctionTemplateDecl *FunTmpl = dyn_cast_or_null(dcl); if (FunTmpl) @@ -4718,8 +4950,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, if (CXXConstructorDecl *Constructor = dyn_cast(FD)) MarkVTableUsed(FD->getLocation(), Constructor->getParent()); - ComputeNRVO(Body, FunctionScopes.back()->Returns.data(), - FunctionScopes.back()->Returns.size()); + ComputeNRVO(Body, getCurFunction()); } assert(FD == getCurFunctionDecl() && "Function parsing confused"); @@ -4730,15 +4961,15 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, if (!MD->isInvalidDecl()) DiagnoseUnusedParameters(MD->param_begin(), MD->param_end()); } else { - Body->Destroy(Context); - return DeclPtrTy(); + return 0; } // Verify and clean out per-function state. // Check goto/label use. + FunctionScopeInfo *CurFn = getCurFunction(); for (llvm::DenseMap::iterator - I = getLabelMap().begin(), E = getLabelMap().end(); I != E; ++I) { + I = CurFn->LabelMap.begin(), E = CurFn->LabelMap.end(); I != E; ++I) { LabelStmt *L = I->second; // Verify that we have no forward references left. If so, there was a goto @@ -4754,8 +4985,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // the function body so that they aren't leaked and that the AST is well // formed. if (Body == 0) { - // The whole function wasn't parsed correctly, just delete this. - L->Destroy(Context); + // The whole function wasn't parsed correctly. continue; } @@ -4785,14 +5015,18 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // Verify that that gotos and switch cases don't jump into scopes illegally. // Verify that that gotos and switch cases don't jump into scopes illegally. - if (FunctionNeedsScopeChecking() && + if (getCurFunction()->NeedsScopeChecking() && !dcl->isInvalidDecl() && !hasAnyErrorsInThisFunction()) DiagnoseInvalidJumps(Body); - if (CXXDestructorDecl *Destructor = dyn_cast(dcl)) + if (CXXDestructorDecl *Destructor = dyn_cast(dcl)) { + if (!Destructor->getParent()->isDependentType()) + CheckDestructor(Destructor); + MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); + } // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for @@ -4804,13 +5038,11 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // enabled. QualType ResultType; if (const FunctionDecl *FD = dyn_cast(dcl)) { - ResultType = FD->getResultType(); - } - else { + AnalysisWarnings.IssueWarnings(WP, FD); + } else { ObjCMethodDecl *MD = cast(dcl); - ResultType = MD->getResultType(); + AnalysisWarnings.IssueWarnings(WP, MD); } - AnalysisWarnings.IssueWarnings(WP, dcl); } assert(ExprTemporaries.empty() && "Leftover temporaries in function"); @@ -4826,8 +5058,8 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, // deletion in some later function. if (getDiagnostics().hasErrorOccurred()) ExprTemporaries.clear(); - - return D; + + return dcl; } /// ImplicitlyDefineFunction - An undeclared identifier was used in a function @@ -4873,8 +5105,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, DeclContext *PrevDC = CurContext; CurContext = Context.getTranslationUnitDecl(); - FunctionDecl *FD = - dyn_cast(ActOnDeclarator(TUScope, D).getAs()); + FunctionDecl *FD = dyn_cast(ActOnDeclarator(TUScope, D)); FD->setImplicit(); CurContext = PrevDC; @@ -4902,9 +5133,17 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { bool HasVAListArg; if (Context.BuiltinInfo.isPrintfLike(BuiltinID, FormatIdx, HasVAListArg)) { if (!FD->getAttr()) - FD->addAttr(::new (Context) FormatAttr(Context, "printf", FormatIdx+1, + FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context, + "printf", FormatIdx+1, HasVAListArg ? 0 : FormatIdx+2)); } + if (Context.BuiltinInfo.isScanfLike(BuiltinID, FormatIdx, + HasVAListArg)) { + if (!FD->getAttr()) + FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context, + "scanf", FormatIdx+1, + HasVAListArg ? 0 : FormatIdx+2)); + } // Mark const if we don't care about errno and that is the only // thing preventing the function from being const. This allows @@ -4912,15 +5151,15 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { if (!getLangOptions().MathErrno && Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) { if (!FD->getAttr()) - FD->addAttr(::new (Context) ConstAttr()); + FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context)); } if (Context.BuiltinInfo.isNoReturn(BuiltinID)) FD->setType(Context.getNoReturnType(FD->getType())); if (Context.BuiltinInfo.isNoThrow(BuiltinID)) - FD->addAttr(::new (Context) NoThrowAttr()); + FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context)); if (Context.BuiltinInfo.isConst(BuiltinID)) - FD->addAttr(::new (Context) ConstAttr()); + FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context)); } IdentifierInfo *Name = FD->getIdentifier(); @@ -4942,13 +5181,15 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { // FIXME: We known better than our headers. const_cast(Format)->setType(Context, "printf"); } else - FD->addAttr(::new (Context) FormatAttr(Context, "printf", 1, + FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context, + "printf", 1, Name->isStr("NSLogv") ? 0 : 2)); } else if (Name->isStr("asprintf") || Name->isStr("vasprintf")) { // FIXME: asprintf and vasprintf aren't C99 functions. Should they be // target-specific builtins, perhaps? if (!FD->getAttr()) - FD->addAttr(::new (Context) FormatAttr(Context, "printf", 2, + FD->addAttr(::new (Context) FormatAttr(FD->getLocation(), Context, + "printf", 2, Name->isStr("vasprintf") ? 0 : 3)); } } @@ -5031,7 +5272,7 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, /// former case, Name will be non-null. In the later case, Name will be null. /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a /// reference/declaration/definition of a tag. -Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, +Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, @@ -5063,7 +5304,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // This is a declaration or definition of a class template (which may // be a member of another template). if (Invalid) - return DeclPtrTy(); + return 0; OwnedDecl = false; DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc, @@ -5106,26 +5347,26 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, DC = computeDeclContext(SS, false); if (!DC) { IsDependent = true; - return DeclPtrTy(); + return 0; } } else { DC = computeDeclContext(SS, true); if (!DC) { Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec) << SS.getRange(); - return DeclPtrTy(); + return 0; } } if (RequireCompleteDeclContext(SS, DC)) - return DeclPtrTy::make((Decl *)0); + return 0; SearchDC = DC; // Look-up name inside 'foo::'. LookupQualifiedName(Previous, DC); if (Previous.isAmbiguous()) - return DeclPtrTy(); + return 0; if (Previous.empty()) { // Name lookup did not find anything. However, if the @@ -5135,7 +5376,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // this as a dependent elaborated-type-specifier. if (Previous.wasNotFoundInCurrentInstantiation()) { IsDependent = true; - return DeclPtrTy(); + return 0; } // A tag 'foo::bar' must already exist. @@ -5155,7 +5396,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // Note: there used to be some attempt at recovery here. if (Previous.isAmbiguous()) - return DeclPtrTy(); + return 0; if (!getLangOptions().CPlusPlus && TUK != TUK_Reference) { // FIXME: This makes sure that we ignore the contexts associated @@ -5176,7 +5417,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } if (getLangOptions().CPlusPlus && Name && DC && StdNamespace && - DC->Equals(StdNamespace) && Name->isStr("bad_alloc")) { + DC->Equals(getStdNamespace()) && Name->isStr("bad_alloc")) { // This is a declaration of or a reference to "std::bad_alloc". isStdBadAlloc = true; @@ -5184,7 +5425,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // std::bad_alloc has been implicitly declared (but made invisible to // name lookup). Fill in this implicit declaration as the previous // declaration, so that the declarations get chained appropriately. - Previous.addDecl(StdBadAlloc); + Previous.addDecl(getStdBadAlloc()); } } @@ -5271,11 +5512,12 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (const TagType *TT = TD->getUnderlyingType()->getAs()) { TagDecl *Tag = TT->getDecl(); if (Tag->getDeclName() == Name && - Tag->getDeclContext()->getLookupContext() - ->Equals(TD->getDeclContext()->getLookupContext())) { + Tag->getDeclContext()->getRedeclContext() + ->Equals(TD->getDeclContext()->getRedeclContext())) { PrevDecl = Tag; Previous.clear(); Previous.addDecl(Tag); + Previous.resolveKind(); } } } @@ -5321,7 +5563,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // need to be changed with DeclGroups. if ((TUK == TUK_Reference && !PrevTagDecl->getFriendObjectKind()) || TUK == TUK_Friend) - return DeclPtrTy::make(PrevTagDecl); + return PrevTagDecl; // Diagnose attempts to redefine a tag. if (TUK == TUK_Definition) { @@ -5475,7 +5717,7 @@ CreateNewDecl: New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc, cast_or_null(PrevDecl)); - if (isStdBadAlloc && (!StdBadAlloc || StdBadAlloc->isImplicit())) + if (isStdBadAlloc && (!StdBadAlloc || getStdBadAlloc()->isImplicit())) StdBadAlloc = cast(New); } else New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc, @@ -5549,7 +5791,7 @@ CreateNewDecl: if (PrevDecl) New->setAccess(PrevDecl->getAccess()); - DeclContext *DC = New->getDeclContext()->getLookupContext(); + DeclContext *DC = New->getDeclContext()->getRedeclContext(); DC->makeDeclVisibleInContext(New, /* Recoverable = */ false); if (Name) // can be null along some error paths if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) @@ -5564,26 +5806,26 @@ CreateNewDecl: // If this is the C FILE type, notify the AST context. if (IdentifierInfo *II = New->getIdentifier()) if (!New->isInvalidDecl() && - New->getDeclContext()->getLookupContext()->isTranslationUnit() && + New->getDeclContext()->getRedeclContext()->isTranslationUnit() && II->isStr("FILE")) Context.setFILEDecl(New); OwnedDecl = true; - return DeclPtrTy::make(New); + return New; } -void Sema::ActOnTagStartDefinition(Scope *S, DeclPtrTy TagD) { +void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { AdjustDeclIfTemplate(TagD); - TagDecl *Tag = cast(TagD.getAs()); + TagDecl *Tag = cast(TagD); // Enter the tag context. PushDeclContext(S, Tag); } -void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD, +void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, SourceLocation LBraceLoc) { AdjustDeclIfTemplate(TagD); - CXXRecordDecl *Record = cast(TagD.getAs()); + CXXRecordDecl *Record = cast(TagD); FieldCollector->StartClass(); @@ -5610,10 +5852,10 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, DeclPtrTy TagD, "Broken injected-class-name"); } -void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, +void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD, SourceLocation RBraceLoc) { AdjustDeclIfTemplate(TagD); - TagDecl *Tag = cast(TagD.getAs()); + TagDecl *Tag = cast(TagD); Tag->setRBraceLoc(RBraceLoc); if (isa(Tag)) @@ -5626,9 +5868,9 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, Consumer.HandleTagDeclDefinition(Tag); } -void Sema::ActOnTagDefinitionError(Scope *S, DeclPtrTy TagD) { +void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) { AdjustDeclIfTemplate(TagD); - TagDecl *Tag = cast(TagD.getAs()); + TagDecl *Tag = cast(TagD); Tag->setInvalidDecl(); // We're undoing ActOnTagStartDefinition here, not @@ -5711,13 +5953,13 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, /// ActOnField - Each field of a struct/union/class is passed into this in order /// to create a FieldDecl object for it. -Sema::DeclPtrTy Sema::ActOnField(Scope *S, DeclPtrTy TagD, +Decl *Sema::ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, Declarator &D, ExprTy *BitfieldWidth) { - FieldDecl *Res = HandleField(S, cast_or_null(TagD.getAs()), + FieldDecl *Res = HandleField(S, cast_or_null(TagD), DeclStart, D, static_cast(BitfieldWidth), AS_public); - return DeclPtrTy::make(Res); + return Res; } /// HandleField - Analyze a field of a C struct or a C++ data member. @@ -5739,9 +5981,17 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, if (D.getDeclSpec().isThreadSpecified()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread); + + // Check to see if this name was declared as a member previously + LookupResult Previous(*this, II, Loc, LookupMemberName, ForRedeclaration); + LookupName(Previous, S); + assert((Previous.empty() || Previous.isOverloadedResult() || + Previous.isSingleResult()) + && "Lookup of member name should be either overloaded, single or null"); - NamedDecl *PrevDecl = LookupSingleName(S, II, Loc, LookupMemberName, - ForRedeclaration); + // If the name is overloaded then get any declaration else get the single result + NamedDecl *PrevDecl = Previous.isOverloadedResult() ? + Previous.getRepresentativeDecl() : Previous.getAsSingle(); if (PrevDecl && PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. @@ -5804,21 +6054,29 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, QualType EltTy = Context.getBaseElementType(T); if (!EltTy->isDependentType() && - RequireCompleteType(Loc, EltTy, diag::err_field_incomplete)) + RequireCompleteType(Loc, EltTy, diag::err_field_incomplete)) { + // Fields of incomplete type force their record to be invalid. + Record->setInvalidDecl(); InvalidDecl = true; + } // C99 6.7.2.1p8: A member of a structure or union may have any type other // than a variably modified type. if (!InvalidDecl && T->isVariablyModifiedType()) { bool SizeIsNegative; + llvm::APSInt Oversized; QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context, - SizeIsNegative); + SizeIsNegative, + Oversized); if (!FixedTy.isNull()) { Diag(Loc, diag::warn_illegal_constant_array_size); T = FixedTy; } else { if (SizeIsNegative) Diag(Loc, diag::err_typecheck_negative_array_size); + else if (Oversized.getBoolValue()) + Diag(Loc, diag::err_array_too_large) + << Oversized.toString(10); else Diag(Loc, diag::err_typecheck_field_variable_size); InvalidDecl = true; @@ -5836,7 +6094,6 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, if (!InvalidDecl && BitWidth && VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth)) { InvalidDecl = true; - DeleteExpr(BitWidth); BitWidth = 0; ZeroWidth = false; } @@ -5877,6 +6134,8 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, CXXRecord->setPOD(false); if (!ZeroWidth) CXXRecord->setEmpty(false); + if (T->isReferenceType()) + CXXRecord->setHasTrivialConstructor(false); if (const RecordType *RT = EltTy->getAs()) { CXXRecordDecl* RDecl = cast(RT->getDecl()); @@ -5896,27 +6155,8 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // cannot be a member of a union, nor can an array of such // objects. // TODO: C++0x alters this restriction significantly. - if (Record->isUnion()) { - // We check for copy constructors before constructors - // because otherwise we'll never get complaints about - // copy constructors. - - CXXSpecialMember member = CXXInvalid; - if (!RDecl->hasTrivialCopyConstructor()) - member = CXXCopyConstructor; - else if (!RDecl->hasTrivialConstructor()) - member = CXXConstructor; - else if (!RDecl->hasTrivialCopyAssignment()) - member = CXXCopyAssignment; - else if (!RDecl->hasTrivialDestructor()) - member = CXXDestructor; - - if (member != CXXInvalid) { - Diag(Loc, diag::err_illegal_union_member) << Name << member; - DiagnoseNontrivial(RT, member); - NewFD->setInvalidDecl(); - } - } + if (Record->isUnion() && CheckNontrivialField(NewFD)) + NewFD->setInvalidDecl(); } } } @@ -5946,6 +6186,43 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, return NewFD; } +bool Sema::CheckNontrivialField(FieldDecl *FD) { + assert(FD); + assert(getLangOptions().CPlusPlus && "valid check only for C++"); + + if (FD->isInvalidDecl()) + return true; + + QualType EltTy = Context.getBaseElementType(FD->getType()); + if (const RecordType *RT = EltTy->getAs()) { + CXXRecordDecl* RDecl = cast(RT->getDecl()); + if (RDecl->getDefinition()) { + // We check for copy constructors before constructors + // because otherwise we'll never get complaints about + // copy constructors. + + CXXSpecialMember member = CXXInvalid; + if (!RDecl->hasTrivialCopyConstructor()) + member = CXXCopyConstructor; + else if (!RDecl->hasTrivialConstructor()) + member = CXXConstructor; + else if (!RDecl->hasTrivialCopyAssignment()) + member = CXXCopyAssignment; + else if (!RDecl->hasTrivialDestructor()) + member = CXXDestructor; + + if (member != CXXInvalid) { + Diag(FD->getLocation(), diag::err_illegal_union_or_anon_struct_member) + << (int)FD->getParent()->isUnion() << FD->getDeclName() << member; + DiagnoseNontrivial(RT, member); + return true; + } + } + } + + return false; +} + /// DiagnoseNontrivial - Given that a class has a non-trivial /// special member, figure out why. void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { @@ -6091,9 +6368,9 @@ TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { /// ActOnIvar - Each ivar field of an objective-c class is passed into this /// in order to create an IvarDecl object for it. -Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, +Decl *Sema::ActOnIvar(Scope *S, SourceLocation DeclStart, - DeclPtrTy IntfDecl, + Decl *IntfDecl, Declarator &D, ExprTy *BitfieldWidth, tok::ObjCKeywordKind Visibility) { @@ -6112,7 +6389,6 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, // 6.7.2.1p3, 6.7.2.1p4 if (VerifyBitField(Loc, II, T, BitWidth)) { D.setInvalidType(); - DeleteExpr(BitWidth); BitWidth = 0; } } else { @@ -6137,19 +6413,23 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, Visibility != tok::objc_not_keyword ? TranslateIvarVisibility(Visibility) : ObjCIvarDecl::None; // Must set ivar's DeclContext to its enclosing interface. - ObjCContainerDecl *EnclosingDecl = IntfDecl.getAs(); + ObjCContainerDecl *EnclosingDecl = cast(IntfDecl); ObjCContainerDecl *EnclosingContext; if (ObjCImplementationDecl *IMPDecl = dyn_cast(EnclosingDecl)) { + if (!LangOpts.ObjCNonFragileABI2) { // Case of ivar declared in an implementation. Context is that of its class. - EnclosingContext = IMPDecl->getClassInterface(); - assert(EnclosingContext && "Implementation has no class interface!"); + EnclosingContext = IMPDecl->getClassInterface(); + assert(EnclosingContext && "Implementation has no class interface!"); + } + else + EnclosingContext = EnclosingDecl; } else { if (ObjCCategoryDecl *CDecl = dyn_cast(EnclosingDecl)) { if (!LangOpts.ObjCNonFragileABI2 || !CDecl->IsClassExtension()) { Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension(); - return DeclPtrTy(); + return 0; } } EnclosingContext = EnclosingDecl; @@ -6180,19 +6460,59 @@ Sema::DeclPtrTy Sema::ActOnIvar(Scope *S, if (II) { // FIXME: When interfaces are DeclContexts, we'll need to add // these to the interface. - S->AddDecl(DeclPtrTy::make(NewID)); + S->AddDecl(NewID); IdResolver.AddDecl(NewID); } - return DeclPtrTy::make(NewID); + return NewID; +} + +/// ActOnLastBitfield - This routine handles synthesized bitfields rules for +/// class and class extensions. For every class @interface and class +/// extension @interface, if the last ivar is a bitfield of any type, +/// then add an implicit `char :0` ivar to the end of that interface. +void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Decl *EnclosingDecl, + llvm::SmallVectorImpl &AllIvarDecls) { + if (!LangOpts.ObjCNonFragileABI2 || AllIvarDecls.empty()) + return; + + Decl *ivarDecl = AllIvarDecls[AllIvarDecls.size()-1]; + ObjCIvarDecl *Ivar = cast(ivarDecl); + + if (!Ivar->isBitField()) + return; + uint64_t BitFieldSize = + Ivar->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + if (BitFieldSize == 0) + return; + ObjCInterfaceDecl *ID = dyn_cast(EnclosingDecl); + if (!ID) { + if (ObjCCategoryDecl *CD = dyn_cast(EnclosingDecl)) { + if (!CD->IsClassExtension()) + return; + } + // No need to add this to end of @implementation. + else + return; + } + // All conditions are met. Add a new bitfield to the tail end of ivars. + llvm::APInt Zero(Context.getTypeSize(Context.CharTy), 0); + Expr * BW = IntegerLiteral::Create(Context, Zero, Context.CharTy, DeclLoc); + + Ivar = ObjCIvarDecl::Create(Context, cast(EnclosingDecl), + DeclLoc, 0, + Context.CharTy, + Context.CreateTypeSourceInfo(Context.CharTy), + ObjCIvarDecl::Private, BW, + true); + AllIvarDecls.push_back(Ivar); } void Sema::ActOnFields(Scope* S, - SourceLocation RecLoc, DeclPtrTy RecDecl, - DeclPtrTy *Fields, unsigned NumFields, + SourceLocation RecLoc, Decl *EnclosingDecl, + Decl **Fields, unsigned NumFields, SourceLocation LBrac, SourceLocation RBrac, AttributeList *Attr) { - Decl *EnclosingDecl = RecDecl.getAs(); assert(EnclosingDecl && "missing record or interface decl"); // If the decl this is being inserted into is invalid, then it may be a @@ -6209,7 +6529,7 @@ void Sema::ActOnFields(Scope* S, RecordDecl *Record = dyn_cast(EnclosingDecl); for (unsigned i = 0; i != NumFields; ++i) { - FieldDecl *FD = cast(Fields[i].getAs()); + FieldDecl *FD = cast(Fields[i]); // Get the type for the field. Type *FDTy = FD->getType().getTypePtr(); @@ -6244,7 +6564,7 @@ void Sema::ActOnFields(Scope* S, EnclosingDecl->setInvalidDecl(); continue; } else if (FDTy->isIncompleteArrayType() && i == NumFields - 1 && - Record && Record->isStruct()) { + Record && !Record->isUnion()) { // Flexible array member. if (NumNamedMembers < 1) { Diag(FD->getLocation(), diag::err_flexible_array_empty_struct) @@ -6360,6 +6680,11 @@ void Sema::ActOnFields(Scope* S, if (Attr) ProcessDeclAttributeList(S, Record, Attr); + + // If there's a #pragma GCC visibility in scope, and this isn't a subclass, + // set the visibility of this record. + if (Record && !Record->getDeclContext()->isRecord()) + AddPushedVisibilityAttribute(Record); } /// \brief Determine whether the given integral value is representable within @@ -6405,9 +6730,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, EnumConstantDecl *LastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, - ExprArg val) { - Expr *Val = (Expr *)val.get(); - + Expr *Val) { unsigned IntWidth = Context.Target.getIntWidth(); llvm::APSInt EnumVal(IntWidth); QualType EltTy; @@ -6434,12 +6757,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, << (EnumVal.isUnsigned() || EnumVal.isNonNegative()); else if (!Context.hasSameType(Val->getType(), Context.IntTy)) { // Force the type of the expression to 'int'. - ImpCastExprToType(Val, Context.IntTy, CastExpr::CK_IntegralCast); - - if (Val != val.get()) { - val.release(); - val = Val; - } + ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast); } } @@ -6527,20 +6845,19 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, EnumVal.setIsSigned(EltTy->isSignedIntegerType()); } - val.release(); return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy, Val, EnumVal); } -Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl, - DeclPtrTy lastEnumConst, +Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, + Decl *lastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, SourceLocation EqualLoc, ExprTy *val) { - EnumDecl *TheEnumDecl = cast(theEnumDecl.getAs()); + EnumDecl *TheEnumDecl = cast(theEnumDecl); EnumConstantDecl *LastEnumConst = - cast_or_null(lastEnumConst.getAs()); + cast_or_null(lastEnumConst); Expr *Val = static_cast(val); // The scope passed in may not be a decl scope. Zip up the scope tree until @@ -6569,13 +6886,12 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl, else Diag(IdLoc, diag::err_redefinition) << Id; Diag(PrevDecl->getLocation(), diag::note_previous_definition); - if (Val) Val->Destroy(Context); - return DeclPtrTy(); + return 0; } } EnumConstantDecl *New = CheckEnumConstant(TheEnumDecl, LastEnumConst, - IdLoc, Id, Owned(Val)); + IdLoc, Id, Val); // Register this decl in the current scope stack. if (New) { @@ -6583,14 +6899,14 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl, PushOnScopeChains(New, S); } - return DeclPtrTy::make(New); + return New; } void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, - SourceLocation RBraceLoc, DeclPtrTy EnumDeclX, - DeclPtrTy *Elements, unsigned NumElements, + SourceLocation RBraceLoc, Decl *EnumDeclX, + Decl **Elements, unsigned NumElements, Scope *S, AttributeList *Attr) { - EnumDecl *Enum = cast(EnumDeclX.getAs()); + EnumDecl *Enum = cast(EnumDeclX); QualType EnumType = Context.getTypeDeclType(Enum); if (Attr) @@ -6599,7 +6915,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, if (Enum->isDependentType()) { for (unsigned i = 0; i != NumElements; ++i) { EnumConstantDecl *ECD = - cast_or_null(Elements[i].getAs()); + cast_or_null(Elements[i]); if (!ECD) continue; ECD->setType(EnumType); @@ -6626,7 +6942,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, for (unsigned i = 0; i != NumElements; ++i) { EnumConstantDecl *ECD = - cast_or_null(Elements[i].getAs()); + cast_or_null(Elements[i]); if (!ECD) continue; // Already issued a diagnostic. const llvm::APSInt &InitVal = ECD->getInitVal(); @@ -6728,8 +7044,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // Loop over all of the enumerator constants, changing their types to match // the type of the enum if needed. for (unsigned i = 0; i != NumElements; ++i) { - EnumConstantDecl *ECD = - cast_or_null(Elements[i].getAs()); + EnumConstantDecl *ECD = cast_or_null(Elements[i]); if (!ECD) continue; // Already issued a diagnostic. // Standard C says the enumerators have int type, but we allow, as an @@ -6772,11 +7087,11 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // Adjust the Expr initializer and type. if (ECD->getInitExpr()) - ECD->setInitExpr(new (Context) ImplicitCastExpr(NewTy, - CastExpr::CK_IntegralCast, - ECD->getInitExpr(), - CXXBaseSpecifierArray(), - /*isLvalue=*/false)); + ECD->setInitExpr(ImplicitCastExpr::Create(Context, NewTy, + CK_IntegralCast, + ECD->getInitExpr(), + /*base paths*/ 0, + VK_RValue)); if (getLangOptions().CPlusPlus) // C++ [dcl.enum]p4: Following the closing brace of an // enum-specifier, each enumerator has the type of its @@ -6790,14 +7105,13 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, NumPositiveBits, NumNegativeBits); } -Sema::DeclPtrTy Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, - ExprArg expr) { - StringLiteral *AsmString = cast(expr.takeAs()); +Decl *Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, Expr *expr) { + StringLiteral *AsmString = cast(expr); FileScopeAsmDecl *New = FileScopeAsmDecl::Create(Context, CurContext, Loc, AsmString); CurContext->addDecl(New); - return DeclPtrTy::make(New); + return New; } void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, @@ -6806,7 +7120,7 @@ void Sema::ActOnPragmaWeakID(IdentifierInfo* Name, Decl *PrevDecl = LookupSingleName(TUScope, Name, NameLoc, LookupOrdinaryName); if (PrevDecl) { - PrevDecl->addAttr(::new (Context) WeakAttr()); + PrevDecl->addAttr(::new (Context) WeakAttr(PragmaLoc, Context)); } else { (void)WeakUndeclaredIdentifiers.insert( std::pair diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 3b82f58..25af73a 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -11,15 +11,18 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" +#include "clang/Sema/SemaInternal.h" #include "TargetAttributesSema.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Parse/DeclSpec.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/DelayedDiagnostic.h" #include "llvm/ADT/StringExtras.h" using namespace clang; +using namespace sema; //===----------------------------------------------------------------------===// // Helper functions @@ -193,7 +196,7 @@ static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, // Instantiate/Install the vector type, and let Sema build the type for us. // This will run the reguired checks. - QualType T = S.BuildExtVectorType(curType, S.Owned(sizeExpr), Attr.getLoc()); + QualType T = S.BuildExtVectorType(curType, sizeExpr, Attr.getLoc()); if (!T.isNull()) { // FIXME: preserve the old source info. tDecl->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(T)); @@ -211,7 +214,7 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) { } if (TagDecl *TD = dyn_cast(d)) - TD->addAttr(::new (S.Context) PackedAttr); + TD->addAttr(::new (S.Context) PackedAttr(Attr.getLoc(), S.Context)); else if (FieldDecl *FD = dyn_cast(d)) { // If the alignment is less than or equal to 8 bits, the packed attribute // has no effect. @@ -220,7 +223,7 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type) << Attr.getName() << FD->getType(); else - FD->addAttr(::new (S.Context) PackedAttr); + FD->addAttr(::new (S.Context) PackedAttr(Attr.getLoc(), S.Context)); } else S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } @@ -235,7 +238,7 @@ static void HandleIBAction(Decl *d, const AttributeList &Attr, Sema &S) { // The IBAction attributes only apply to instance methods. if (ObjCMethodDecl *MD = dyn_cast(d)) if (MD->isInstanceMethod()) { - d->addAttr(::new (S.Context) IBActionAttr()); + d->addAttr(::new (S.Context) IBActionAttr(Attr.getLoc(), S.Context)); return; } @@ -252,7 +255,7 @@ static void HandleIBOutlet(Decl *d, const AttributeList &Attr, Sema &S) { // The IBOutlet attributes only apply to instance variables of // Objective-C classes. if (isa(d) || isa(d)) { - d->addAttr(::new (S.Context) IBOutletAttr()); + d->addAttr(::new (S.Context) IBOutletAttr(Attr.getLoc(), S.Context)); return; } @@ -263,7 +266,7 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr, Sema &S) { // The iboutletcollection attribute can have zero or one arguments. - if (Attr.getNumArgs() > 1) { + if (Attr.getParameterName() && Attr.getNumArgs() > 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } @@ -274,9 +277,41 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr, S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet) << Attr.getName(); return; } - - // FIXME: Eventually accept the type argument. - d->addAttr(::new (S.Context) IBOutletCollectionAttr()); + if (const ValueDecl *VD = dyn_cast(d)) + if (!VD->getType()->getAs()) { + S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type) + << VD->getType() << 0; + return; + } + if (const ObjCPropertyDecl *PD = dyn_cast(d)) + if (!PD->getType()->getAs()) { + S.Diag(Attr.getLoc(), diag::err_iboutletcollection_object_type) + << PD->getType() << 1; + return; + } + + IdentifierInfo *II = Attr.getParameterName(); + if (!II) + II = &S.Context.Idents.get("id"); + + ParsedType TypeRep = S.getTypeName(*II, Attr.getLoc(), + S.getScopeForContext(d->getDeclContext()->getParent())); + if (!TypeRep) { + S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II; + return; + } + QualType QT = TypeRep.get(); + // Diagnose use of non-object type in iboutletcollection attribute. + // FIXME. Gnu attribute extension ignores use of builtin types in + // attributes. So, __attribute__((iboutletcollection(char))) will be + // treated as __attribute__((iboutletcollection())). + if (!QT->isObjCIdType() && !QT->isObjCClassType() && + !QT->isObjCObjectType()) { + S.Diag(Attr.getLoc(), diag::err_iboutletcollection_type) << II; + return; + } + d->addAttr(::new (S.Context) IBOutletCollectionAttr(Attr.getLoc(), S.Context, + QT)); } static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -321,7 +356,7 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { QualType T = getFunctionOrMethodArgType(d, x); if (!T->isAnyPointerType() && !T->isBlockPointerType()) { // FIXME: Should also highlight argument in decl. - S.Diag(Attr.getLoc(), diag::err_nonnull_pointers_only) + S.Diag(Attr.getLoc(), diag::warn_nonnull_pointers_only) << "nonnull" << Ex->getSourceRange(); continue; } @@ -346,15 +381,162 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { unsigned* start = &NonNullArgs[0]; unsigned size = NonNullArgs.size(); - std::sort(start, start + size); - d->addAttr(::new (S.Context) NonNullAttr(S.Context, start, size)); + llvm::array_pod_sort(start, start + size); + d->addAttr(::new (S.Context) NonNullAttr(Attr.getLoc(), S.Context, start, + size)); +} + +static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) { + // This attribute must be applied to a function declaration. + // The first argument to the attribute must be a string, + // the name of the resource, for example "malloc". + // The following arguments must be argument indexes, the arguments must be + // of integer type for Returns, otherwise of pointer type. + // The difference between Holds and Takes is that a pointer may still be used + // after being held. free() should be __attribute((ownership_takes)), whereas + // a list append function may well be __attribute((ownership_holds)). + + if (!AL.getParameterName()) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_not_string) + << AL.getName()->getName() << 1; + return; + } + // Figure out our Kind, and check arguments while we're at it. + OwnershipAttr::OwnershipKind K; + switch (AL.getKind()) { + case AttributeList::AT_ownership_takes: + K = OwnershipAttr::Takes; + if (AL.getNumArgs() < 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << 2; + return; + } + break; + case AttributeList::AT_ownership_holds: + K = OwnershipAttr::Holds; + if (AL.getNumArgs() < 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << 2; + return; + } + break; + case AttributeList::AT_ownership_returns: + K = OwnershipAttr::Returns; + if (AL.getNumArgs() > 1) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) + << AL.getNumArgs() + 1; + return; + } + break; + default: + // This should never happen given how we are called. + llvm_unreachable("Unknown ownership attribute"); + } + + if (!isFunction(d) || !hasFunctionProto(d)) { + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) << AL.getName() + << 0 /*function*/; + return; + } + + unsigned NumArgs = getFunctionOrMethodNumArgs(d); + + llvm::StringRef Module = AL.getParameterName()->getName(); + + // Normalize the argument, __foo__ becomes foo. + if (Module.startswith("__") && Module.endswith("__")) + Module = Module.substr(2, Module.size() - 4); + + llvm::SmallVector OwnershipArgs; + + for (AttributeList::arg_iterator I = AL.arg_begin(), E = AL.arg_end(); I != E; + ++I) { + + Expr *IdxExpr = static_cast(*I); + llvm::APSInt ArgNum(32); + if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() + || !IdxExpr->isIntegerConstantExpr(ArgNum, S.Context)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_not_int) + << AL.getName()->getName() << IdxExpr->getSourceRange(); + continue; + } + + unsigned x = (unsigned) ArgNum.getZExtValue(); + + if (x > NumArgs || x < 1) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL.getName()->getName() << x << IdxExpr->getSourceRange(); + continue; + } + --x; + switch (K) { + case OwnershipAttr::Takes: + case OwnershipAttr::Holds: { + // Is the function argument a pointer type? + QualType T = getFunctionOrMethodArgType(d, x); + if (!T->isAnyPointerType() && !T->isBlockPointerType()) { + // FIXME: Should also highlight argument in decl. + S.Diag(AL.getLoc(), diag::err_ownership_type) + << ((K==OwnershipAttr::Takes)?"ownership_takes":"ownership_holds") + << "pointer" + << IdxExpr->getSourceRange(); + continue; + } + break; + } + case OwnershipAttr::Returns: { + if (AL.getNumArgs() > 1) { + // Is the function argument an integer type? + Expr *IdxExpr = static_cast(AL.getArg(0)); + llvm::APSInt ArgNum(32); + if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() + || !IdxExpr->isIntegerConstantExpr(ArgNum, S.Context)) { + S.Diag(AL.getLoc(), diag::err_ownership_type) + << "ownership_returns" << "integer" + << IdxExpr->getSourceRange(); + return; + } + } + break; + } + default: + llvm_unreachable("Unknown ownership attribute"); + } // switch + + // Check we don't have a conflict with another ownership attribute. + for (specific_attr_iterator + i = d->specific_attr_begin(), + e = d->specific_attr_end(); + i != e; ++i) { + if ((*i)->getOwnKind() != K) { + for (const unsigned *I = (*i)->args_begin(), *E = (*i)->args_end(); + I!=E; ++I) { + if (x == *I) { + S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) + << AL.getName()->getName() << "ownership_*"; + } + } + } + } + OwnershipArgs.push_back(x); + } + + unsigned* start = OwnershipArgs.data(); + unsigned size = OwnershipArgs.size(); + llvm::array_pod_sort(start, start + size); + + if (K != OwnershipAttr::Returns && OwnershipArgs.empty()) { + S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << 2; + return; + } + + d->addAttr(::new (S.Context) OwnershipAttr(AL.getLoc(), S.Context, K, Module, + start, size)); } static bool isStaticVarOrStaticFunciton(Decl *D) { if (VarDecl *VD = dyn_cast(D)) - return VD->getStorageClass() == VarDecl::Static; + return VD->getStorageClass() == SC_Static; if (FunctionDecl *FD = dyn_cast(D)) - return FD->getStorageClass() == FunctionDecl::Static; + return FD->getStorageClass() == SC_Static; return false; } @@ -375,13 +557,11 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) { // static int a __attribute__((weakref ("v2"))); // } // we reject them - if (const DeclContext *Ctx = d->getDeclContext()) { - Ctx = Ctx->getLookupContext(); - if (!isa(Ctx) && !isa(Ctx) ) { - S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) << - dyn_cast(d)->getNameAsString(); - return; - } + const DeclContext *Ctx = d->getDeclContext()->getRedeclContext(); + if (!Ctx->isFileContext()) { + S.Diag(Attr.getLoc(), diag::err_attribute_weakref_not_global_context) << + dyn_cast(d)->getNameAsString(); + return; } // The GCC manual says @@ -424,10 +604,10 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) { } // GCC will accept anything as the argument of weakref. Should we // check for an existing decl? - d->addAttr(::new (S.Context) AliasAttr(S.Context, Str->getString())); + d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, Str->getString())); } - d->addAttr(::new (S.Context) WeakRefAttr()); + d->addAttr(::new (S.Context) WeakRefAttr(Attr.getLoc(), S.Context)); } static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -449,7 +629,7 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { // FIXME: check if target symbol exists in current file - d->addAttr(::new (S.Context) AliasAttr(S.Context, Str->getString())); + d->addAttr(::new (S.Context) AliasAttr(Attr.getLoc(), S.Context, Str->getString())); } static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, @@ -466,7 +646,7 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, return; } - d->addAttr(::new (S.Context) AlwaysInlineAttr()); + d->addAttr(::new (S.Context) AlwaysInlineAttr(Attr.getLoc(), S.Context)); } static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -479,7 +659,7 @@ static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (const FunctionDecl *FD = dyn_cast(d)) { QualType RetTy = FD->getResultType(); if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) { - d->addAttr(::new (S.Context) MallocAttr()); + d->addAttr(::new (S.Context) MallocAttr(Attr.getLoc(), S.Context)); return; } } @@ -487,39 +667,75 @@ static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only); } -static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr, - Sema &S) { - // check the attribute arguments. +static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { + /* Diagnostics (if any) was emitted by Sema::ProcessFnAttr(). */ + assert(Attr.isInvalid() == false); + d->addAttr(::new (S.Context) NoReturnAttr(Attr.getLoc(), S.Context)); +} + +static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, + Sema &S) { + + // The checking path for 'noreturn' and 'analyzer_noreturn' are different + // because 'analyzer_noreturn' does not impact the type. + if (Attr.getNumArgs() != 0) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return false; + return; } - + if (!isFunctionOrMethod(d) && !isa(d)) { ValueDecl *VD = dyn_cast(d); if (VD == 0 || (!VD->getType()->isBlockPointerType() && !VD->getType()->isFunctionPointerType())) { S.Diag(Attr.getLoc(), Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type - : diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; - return false; + : diag::warn_attribute_wrong_decl_type) + << Attr.getName() << 0 /*function*/; + return; } } - - return true; -} - -static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { - /* Diagnostics (if any) was emitted by Sema::ProcessFnAttr(). */ - assert(Attr.isInvalid() == false); - d->addAttr(::new (S.Context) NoReturnAttr()); + + d->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getLoc(), S.Context)); } -static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, +// PS3 PPU-specific. +static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { - if (HandleCommonNoReturnAttr(d, Attr, S)) - d->addAttr(::new (S.Context) AnalyzerNoReturnAttr()); +/* + Returning a Vector Class in Registers + + According to the PPU ABI specifications, a class with a single member of vector type is returned in + memory when used as the return value of a function. This results in inefficient code when implementing + vector classes. To return the value in a single vector register, add the vecreturn attribute to the class + definition. This attribute is also applicable to struct types. + + Example: + + struct Vector + { + __vector float xyzw; + } __attribute__((vecreturn)); + + Vector Add(Vector lhs, Vector rhs) + { + Vector result; + result.xyzw = vec_add(lhs.xyzw, rhs.xyzw); + return result; // This will be returned in a register + } +*/ + if (!isa(d)) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) + << Attr.getName() << 9 /*class*/; + return; + } + + if (d->getAttr()) { + S.Diag(Attr.getLoc(), diag::err_repeat_attribute) << "vecreturn"; + return; + } + + d->addAttr(::new (S.Context) VecReturnAttr(Attr.getLoc(), S.Context)); } static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -545,7 +761,7 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) UnusedAttr()); + d->addAttr(::new (S.Context) UnusedAttr(Attr.getLoc(), S.Context)); } static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -566,7 +782,7 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) UsedAttr()); + d->addAttr(::new (S.Context) UsedAttr(Attr.getLoc(), S.Context)); } static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -596,7 +812,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) ConstructorAttr(priority)); + d->addAttr(::new (S.Context) ConstructorAttr(Attr.getLoc(), S.Context, priority)); } static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -626,7 +842,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) DestructorAttr(priority)); + d->addAttr(::new (S.Context) DestructorAttr(Attr.getLoc(), S.Context, priority)); } static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -636,7 +852,7 @@ static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) DeprecatedAttr()); + d->addAttr(::new (S.Context) DeprecatedAttr(Attr.getLoc(), S.Context)); } static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -646,7 +862,7 @@ static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) UnavailableAttr()); + d->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context)); } static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -667,22 +883,22 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) { } llvm::StringRef TypeStr = Str->getString(); - VisibilityAttr::VisibilityTypes type; + VisibilityAttr::VisibilityType type; if (TypeStr == "default") - type = VisibilityAttr::DefaultVisibility; + type = VisibilityAttr::Default; else if (TypeStr == "hidden") - type = VisibilityAttr::HiddenVisibility; + type = VisibilityAttr::Hidden; else if (TypeStr == "internal") - type = VisibilityAttr::HiddenVisibility; // FIXME + type = VisibilityAttr::Hidden; // FIXME else if (TypeStr == "protected") - type = VisibilityAttr::ProtectedVisibility; + type = VisibilityAttr::Protected; else { S.Diag(Attr.getLoc(), diag::warn_attribute_unknown_visibility) << TypeStr; return; } - d->addAttr(::new (S.Context) VisibilityAttr(type)); + d->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type)); } static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr, @@ -698,7 +914,7 @@ static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr, return; } - D->addAttr(::new (S.Context) ObjCExceptionAttr()); + D->addAttr(::new (S.Context) ObjCExceptionAttr(Attr.getLoc(), S.Context)); } static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) { @@ -714,7 +930,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) { return; } } - D->addAttr(::new (S.Context) ObjCNSObjectAttr()); + D->addAttr(::new (S.Context) ObjCNSObjectAttr(Attr.getLoc(), S.Context)); } static void @@ -729,7 +945,7 @@ HandleOverloadableAttr(Decl *D, const AttributeList &Attr, Sema &S) { return; } - D->addAttr(::new (S.Context) OverloadableAttr()); + D->addAttr(::new (S.Context) OverloadableAttr(Attr.getLoc(), S.Context)); } static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -744,7 +960,7 @@ static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - BlocksAttr::BlocksAttrTypes type; + BlocksAttr::BlockType type; if (Attr.getParameterName()->isStr("byref")) type = BlocksAttr::ByRef; else { @@ -753,7 +969,7 @@ static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) BlocksAttr(type)); + d->addAttr(::new (S.Context) BlocksAttr(Attr.getLoc(), S.Context, type)); } static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -846,7 +1062,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { << Attr.getName() << 6 /*function, method or block */; return; } - d->addAttr(::new (S.Context) SentinelAttr(sentinel, nullPos)); + d->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel, nullPos)); } static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) { @@ -874,7 +1090,7 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) return; } - D->addAttr(::new (S.Context) WarnUnusedResultAttr()); + D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getLoc(), S.Context)); } static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) { @@ -898,7 +1114,7 @@ static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) { return; } - D->addAttr(::new (S.Context) WeakAttr()); + D->addAttr(::new (S.Context) WeakAttr(Attr.getLoc(), S.Context)); } static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { @@ -934,7 +1150,7 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { return; } - D->addAttr(::new (S.Context) WeakImportAttr()); + D->addAttr(::new (S.Context) WeakImportAttr(Attr.getLoc(), S.Context)); } static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr, @@ -957,7 +1173,8 @@ static void HandleReqdWorkGroupSize(Decl *D, const AttributeList &Attr, } WGSize[i] = (unsigned) ArgNum.getZExtValue(); } - D->addAttr(::new (S.Context) ReqdWorkGroupSizeAttr(WGSize[0], WGSize[1], + D->addAttr(::new (S.Context) ReqdWorkGroupSizeAttr(Attr.getLoc(), S.Context, + WGSize[0], WGSize[1], WGSize[2])); } @@ -991,7 +1208,7 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { return; } - D->addAttr(::new (S.Context) SectionAttr(S.Context, SE->getString())); + D->addAttr(::new (S.Context) SectionAttr(Attr.getLoc(), S.Context, SE->getString())); } @@ -1002,7 +1219,7 @@ static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) NoThrowAttr()); + d->addAttr(::new (S.Context) NoThrowAttr(Attr.getLoc(), S.Context)); } static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1012,7 +1229,7 @@ static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) ConstAttr()); + d->addAttr(::new (S.Context) ConstAttr(Attr.getLoc(), S.Context)); } static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1022,7 +1239,7 @@ static void HandlePureAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) PureAttr()); + d->addAttr(::new (S.Context) PureAttr(Attr.getLoc(), S.Context)); } static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1080,7 +1297,7 @@ static void HandleCleanupAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) CleanupAttr(FD)); + d->addAttr(::new (S.Context) CleanupAttr(Attr.getLoc(), S.Context, FD)); } /// Handle __attribute__((format_arg((idx)))) attribute based on @@ -1143,7 +1360,7 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) FormatArgAttr(Idx.getZExtValue())); + d->addAttr(::new (S.Context) FormatArgAttr(Attr.getLoc(), S.Context, Idx.getZExtValue())); } enum FormatAttrKind { @@ -1225,7 +1442,7 @@ static void HandleInitPriorityAttr(Decl *d, const AttributeList &Attr, Attr.setInvalid(); return; } - d->addAttr(::new (S.Context) InitPriorityAttr(prioritynum)); + d->addAttr(::new (S.Context) InitPriorityAttr(Attr.getLoc(), S.Context, prioritynum)); } /// Handle __attribute__((format(type,idx,firstarg))) attributes based on @@ -1369,7 +1586,8 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) FormatAttr(S.Context, Format, Idx.getZExtValue(), + d->addAttr(::new (S.Context) FormatAttr(Attr.getLoc(), S.Context, Format, + Idx.getZExtValue(), FirstArg.getZExtValue())); } @@ -1438,7 +1656,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr, } } - RD->addAttr(::new (S.Context) TransparentUnionAttr()); + RD->addAttr(::new (S.Context) TransparentUnionAttr(Attr.getLoc(), S.Context)); } static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1456,7 +1674,7 @@ static void HandleAnnotateAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(ArgExpr->getLocStart(), diag::err_attribute_not_string) <<"annotate"; return; } - d->addAttr(::new (S.Context) AnnotateAttr(S.Context, SE->getString())); + d->addAttr(::new (S.Context) AnnotateAttr(Attr.getLoc(), S.Context, SE->getString())); } static void HandleAlignedAttr(Decl *D, const AttributeList &Attr, Sema &S) { @@ -1471,9 +1689,7 @@ static void HandleAlignedAttr(Decl *D, const AttributeList &Attr, Sema &S) { // weaker alignment, rather than being silently ignored. if (Attr.getNumArgs() == 0) { - // FIXME: This should be the target specific maximum alignment. - // (For now we just use 128 bits which is the maximum on X86). - D->addAttr(::new (S.Context) AlignedAttr(128)); + D->addAttr(::new (S.Context) AlignedAttr(Attr.getLoc(), S.Context, true, 0)); return; } @@ -1483,10 +1699,11 @@ static void HandleAlignedAttr(Decl *D, const AttributeList &Attr, Sema &S) { void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E) { if (E->isTypeDependent() || E->isValueDependent()) { // Save dependent expressions in the AST to be instantiated. - D->addAttr(::new (Context) AlignedAttr(E)); + D->addAttr(::new (Context) AlignedAttr(AttrLoc, Context, true, E)); return; } + // FIXME: Cache the number on the Attr object? llvm::APSInt Alignment(32); if (!E->isIntegerConstantExpr(Alignment, Context)) { Diag(AttrLoc, diag::err_attribute_argument_not_int) @@ -1499,7 +1716,14 @@ void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, Expr *E) { return; } - D->addAttr(::new (Context) AlignedAttr(Alignment.getZExtValue() * 8)); + D->addAttr(::new (Context) AlignedAttr(AttrLoc, Context, true, E)); +} + +void Sema::AddAlignedAttr(SourceLocation AttrLoc, Decl *D, TypeSourceInfo *TS) { + // FIXME: Cache the number on the Attr object if non-dependent? + // FIXME: Perform checking of type validity + D->addAttr(::new (Context) AlignedAttr(AttrLoc, Context, false, TS)); + return; } /// HandleModeAttr - This attribute modifies the width of a decl with primitive @@ -1686,7 +1910,7 @@ static void HandleNoDebugAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) NoDebugAttr()); + d->addAttr(::new (S.Context) NoDebugAttr(Attr.getLoc(), S.Context)); } static void HandleNoInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1702,7 +1926,7 @@ static void HandleNoInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) NoInlineAttr()); + d->addAttr(::new (S.Context) NoInlineAttr(Attr.getLoc(), S.Context)); } static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr, @@ -1719,7 +1943,7 @@ static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr, return; } - d->addAttr(::new (S.Context) NoInstrumentFunctionAttr()); + d->addAttr(::new (S.Context) NoInstrumentFunctionAttr(Attr.getLoc(), S.Context)); } static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1741,7 +1965,7 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) GNUInlineAttr()); + d->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context)); } static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1751,15 +1975,19 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) { switch (Attr.getKind()) { case AttributeList::AT_fastcall: - d->addAttr(::new (S.Context) FastCallAttr()); + d->addAttr(::new (S.Context) FastCallAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_stdcall: - d->addAttr(::new (S.Context) StdCallAttr()); + d->addAttr(::new (S.Context) StdCallAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_thiscall: - d->addAttr(::new (S.Context) ThisCallAttr()); + d->addAttr(::new (S.Context) ThisCallAttr(Attr.getLoc(), S.Context)); + return; case AttributeList::AT_cdecl: - d->addAttr(::new (S.Context) CDeclAttr()); + d->addAttr(::new (S.Context) CDeclAttr(Attr.getLoc(), S.Context)); + return; + case AttributeList::AT_pascal: + d->addAttr(::new (S.Context) PascalAttr(Attr.getLoc(), S.Context)); return; default: llvm_unreachable("unexpected attribute kind"); @@ -1801,7 +2029,8 @@ static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) RegparmAttr(NumParams.getZExtValue())); + d->addAttr(::new (S.Context) RegparmAttr(Attr.getLoc(), S.Context, + NumParams.getZExtValue())); } static void HandleFinalAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1827,7 +2056,7 @@ static void HandleFinalAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) FinalAttr()); + d->addAttr(::new (S.Context) FinalAttr(Attr.getLoc(), S.Context)); } //===----------------------------------------------------------------------===// @@ -1853,7 +2082,7 @@ static void HandleBaseCheckAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) BaseCheckAttr()); + d->addAttr(::new (S.Context) BaseCheckAttr(Attr.getLoc(), S.Context)); } static void HandleHidingAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1878,7 +2107,7 @@ static void HandleHidingAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) HidingAttr()); + d->addAttr(::new (S.Context) HidingAttr(Attr.getLoc(), S.Context)); } static void HandleOverrideAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -1903,7 +2132,7 @@ static void HandleOverrideAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - d->addAttr(::new (S.Context) OverrideAttr()); + d->addAttr(::new (S.Context) OverrideAttr(Attr.getLoc(), S.Context)); } //===----------------------------------------------------------------------===// @@ -1939,16 +2168,16 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr, assert(0 && "invalid ownership attribute"); return; case AttributeList::AT_cf_returns_not_retained: - d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr()); + d->addAttr(::new (S.Context) CFReturnsNotRetainedAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_ns_returns_not_retained: - d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr()); + d->addAttr(::new (S.Context) NSReturnsNotRetainedAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_cf_returns_retained: - d->addAttr(::new (S.Context) CFReturnsRetainedAttr()); + d->addAttr(::new (S.Context) CFReturnsRetainedAttr(Attr.getLoc(), S.Context)); return; case AttributeList::AT_ns_returns_retained: - d->addAttr(::new (S.Context) NSReturnsRetainedAttr()); + d->addAttr(::new (S.Context) NSReturnsRetainedAttr(Attr.getLoc(), S.Context)); return; }; } @@ -2009,9 +2238,14 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_mode: HandleModeAttr (D, Attr, S); break; case AttributeList::AT_malloc: HandleMallocAttr (D, Attr, S); break; case AttributeList::AT_nonnull: HandleNonNullAttr (D, Attr, S); break; + case AttributeList::AT_ownership_returns: + case AttributeList::AT_ownership_takes: + case AttributeList::AT_ownership_holds: + HandleOwnershipAttr (D, Attr, S); break; case AttributeList::AT_noreturn: HandleNoReturnAttr (D, Attr, S); break; case AttributeList::AT_nothrow: HandleNothrowAttr (D, Attr, S); break; case AttributeList::AT_override: HandleOverrideAttr (D, Attr, S); break; + case AttributeList::AT_vecreturn: HandleVecReturnAttr (D, Attr, S); break; // Checker-specific. case AttributeList::AT_ns_returns_not_retained: @@ -2063,6 +2297,7 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_cdecl: case AttributeList::AT_fastcall: case AttributeList::AT_thiscall: + case AttributeList::AT_pascal: HandleCallConvAttr(D, Attr, S); break; default: @@ -2087,7 +2322,7 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *Attr // but that looks really pointless. We reject it. if (D->hasAttr() && !D->hasAttr()) { Diag(AttrList->getLoc(), diag::err_attribute_weakref_without_alias) << - dyn_cast(D)->getNameAsString(); + dyn_cast(D)->getNameAsString(); return; } } @@ -2127,8 +2362,9 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) { if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...)) IdentifierInfo *NDId = ND->getIdentifier(); NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias()); - NewD->addAttr(::new (Context) AliasAttr(Context, NDId->getName())); - NewD->addAttr(::new (Context) WeakAttr()); + NewD->addAttr(::new (Context) AliasAttr(W.getLocation(), Context, + NDId->getName())); + NewD->addAttr(::new (Context) WeakAttr(W.getLocation(), Context)); WeakTopLevelDecl.push_back(NewD); // FIXME: "hideous" code from Sema::LazilyCreateBuiltin // to insert Decl at TU scope, sorry. @@ -2137,7 +2373,7 @@ void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) { PushOnScopeChains(NewD, S); CurContext = SavedContext; } else { // just add weak to existing - ND->addAttr(::new (Context) WeakAttr()); + ND->addAttr(::new (Context) WeakAttr(W.getLocation(), Context)); } } @@ -2179,12 +2415,12 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { /// /// The state token we use is the start index of this scope /// on the warning stack. -Action::ParsingDeclStackState Sema::PushParsingDeclaration() { +Sema::ParsingDeclStackState Sema::PushParsingDeclaration() { ParsingDeclDepth++; return (ParsingDeclStackState) DelayedDiagnostics.size(); } -void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) { +void Sema::PopParsingDeclaration(ParsingDeclStackState S, Decl *D) { assert(ParsingDeclDepth > 0 && "empty ParsingDeclaration stack"); ParsingDeclDepth--; @@ -2199,7 +2435,6 @@ void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) { // We only want to actually emit delayed diagnostics when we // successfully parsed a decl. - Decl *D = Ctx ? Ctx.getAs() : 0; if (D) { // We really do want to start with 0 here. We get one push for a // decl spec and another for each declarator; in a decl group like: @@ -2238,7 +2473,7 @@ static bool isDeclDeprecated(Decl *D) { return false; } -void Sema::HandleDelayedDeprecationCheck(Sema::DelayedDiagnostic &DD, +void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, Decl *Ctx) { if (isDeclDeprecated(Ctx)) return; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index bd97df2..63acdb5 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -11,9 +11,11 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "SemaInit.h" -#include "Lookup.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/CXXFieldCollector.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Lookup.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" @@ -23,10 +25,11 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Template.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/ParsedTemplate.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" #include #include @@ -108,7 +111,7 @@ namespace { } bool -Sema::SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg, +Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, SourceLocation EqualLoc) { if (RequireCompleteType(Param->getLocation(), Param->getType(), diag::err_typecheck_decl_incomplete_type)) { @@ -116,8 +119,6 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg, return true; } - Expr *Arg = (Expr *)DefaultArg.get(); - // C++ [dcl.fct.default]p5 // A default argument expression is implicitly converted (clause // 4) to the parameter type. The default argument expression has @@ -128,8 +129,8 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg, InitializationKind Kind = InitializationKind::CreateCopy(Param->getLocation(), EqualLoc); InitializationSequence InitSeq(*this, Entity, Kind, &Arg, 1); - OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, (void**)&Arg, 1)); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, &Arg, 1)); if (Result.isInvalid()) return true; Arg = Result.takeAs(); @@ -139,8 +140,6 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg, // Okay: add the default argument to the parameter Param->setDefaultArg(Arg); - DefaultArg.release(); - return false; } @@ -148,16 +147,14 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, ExprArg DefaultArg, /// provided for a function parameter is well-formed. If so, attach it /// to the parameter declaration. void -Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, - ExprArg defarg) { - if (!param || !defarg.get()) +Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, + Expr *DefaultArg) { + if (!param || !DefaultArg) return; - ParmVarDecl *Param = cast(param.getAs()); + ParmVarDecl *Param = cast(param); UnparsedDefaultArgLocs.erase(Param); - ExprOwningPtr DefaultArg(this, defarg.takeAs()); - // Default arguments are only permitted in C++ if (!getLangOptions().CPlusPlus) { Diag(EqualLoc, diag::err_param_default_argument) @@ -167,26 +164,26 @@ Sema::ActOnParamDefaultArgument(DeclPtrTy param, SourceLocation EqualLoc, } // Check that the default argument is well-formed - CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg.get(), this); - if (DefaultArgChecker.Visit(DefaultArg.get())) { + CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg, this); + if (DefaultArgChecker.Visit(DefaultArg)) { Param->setInvalidDecl(); return; } - SetParamDefaultArgument(Param, move(DefaultArg), EqualLoc); + SetParamDefaultArgument(Param, DefaultArg, EqualLoc); } /// ActOnParamUnparsedDefaultArgument - We've seen a default /// argument for a function parameter, but we can't parse it yet /// because we're inside a class definition. Note that this default /// argument will be parsed later. -void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param, +void Sema::ActOnParamUnparsedDefaultArgument(Decl *param, SourceLocation EqualLoc, SourceLocation ArgLoc) { if (!param) return; - ParmVarDecl *Param = cast(param.getAs()); + ParmVarDecl *Param = cast(param); if (Param) Param->setUnparsedDefaultArg(); @@ -195,11 +192,11 @@ void Sema::ActOnParamUnparsedDefaultArgument(DeclPtrTy param, /// ActOnParamDefaultArgumentError - Parsing or semantic analysis of /// the default argument for the parameter param failed. -void Sema::ActOnParamDefaultArgumentError(DeclPtrTy param) { +void Sema::ActOnParamDefaultArgumentError(Decl *param) { if (!param) return; - ParmVarDecl *Param = cast(param.getAs()); + ParmVarDecl *Param = cast(param); Param->setInvalidDecl(); @@ -224,7 +221,7 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { if (chunk.Kind == DeclaratorChunk::Function) { for (unsigned argIdx = 0, e = chunk.Fun.NumArgs; argIdx != e; ++argIdx) { ParmVarDecl *Param = - cast(chunk.Fun.ArgInfo[argIdx].Param.getAs()); + cast(chunk.Fun.ArgInfo[argIdx].Param); if (Param->hasUnparsedDefaultArg()) { CachedTokens *Toks = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens; Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc) @@ -412,8 +409,6 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { for (p = 0; p <= LastMissingDefaultArg; ++p) { ParmVarDecl *Param = FD->getParamDecl(p); if (Param->hasDefaultArg()) { - if (!Param->hasUnparsedDefaultArg()) - Param->getDefaultArg()->Destroy(Context); Param->setDefaultArg(0); } } @@ -449,8 +444,9 @@ CXXBaseSpecifier * Sema::CheckBaseSpecifier(CXXRecordDecl *Class, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - QualType BaseType, - SourceLocation BaseLoc) { + TypeSourceInfo *TInfo) { + QualType BaseType = TInfo->getType(); + // C++ [class.union]p1: // A union shall not have base classes. if (Class->isUnion()) { @@ -461,8 +457,10 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, if (BaseType->isDependentType()) return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, - Class->getTagKind() == TTK_Class, - Access, BaseType); + Class->getTagKind() == TTK_Class, + Access, TInfo); + + SourceLocation BaseLoc = TInfo->getTypeLoc().getBeginLoc(); // Base specifiers must be record types. if (!BaseType->isRecordType()) { @@ -482,8 +480,10 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, // defined class. if (RequireCompleteType(BaseLoc, BaseType, PDiag(diag::err_incomplete_base_class) - << SpecifierRange)) + << SpecifierRange)) { + Class->setInvalidDecl(); return 0; + } // If the base class is polymorphic or isn't empty, the new one is/isn't, too. RecordDecl *BaseDecl = BaseType->getAs()->getDecl(); @@ -502,11 +502,14 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, } SetClassDeclAttributesFromBase(Class, CXXBaseDecl, Virtual); + + if (BaseDecl->isInvalidDecl()) + Class->setInvalidDecl(); // Create the base specifier. return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, - Class->getTagKind() == TTK_Class, - Access, BaseType); + Class->getTagKind() == TTK_Class, + Access, TInfo); } void Sema::SetClassDeclAttributesFromBase(CXXRecordDecl *Class, @@ -581,22 +584,22 @@ void Sema::SetClassDeclAttributesFromBase(CXXRecordDecl *Class, /// example: /// class foo : public bar, virtual private baz { /// 'public bar' and 'virtual private baz' are each base-specifiers. -Sema::BaseResult -Sema::ActOnBaseSpecifier(DeclPtrTy classdecl, SourceRange SpecifierRange, +BaseResult +Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - TypeTy *basetype, SourceLocation BaseLoc) { + ParsedType basetype, SourceLocation BaseLoc) { if (!classdecl) return true; AdjustDeclIfTemplate(classdecl); - CXXRecordDecl *Class = dyn_cast(classdecl.getAs()); + CXXRecordDecl *Class = dyn_cast(classdecl); if (!Class) return true; - QualType BaseType = GetTypeFromParser(basetype); + TypeSourceInfo *TInfo = 0; + GetTypeFromParser(basetype, &TInfo); if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange, - Virtual, Access, - BaseType, BaseLoc)) + Virtual, Access, TInfo)) return BaseSpec; return true; @@ -664,13 +667,13 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, /// ActOnBaseSpecifiers - Attach the given base specifiers to the /// class, after checking whether there are any duplicate base /// classes. -void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, +void Sema::ActOnBaseSpecifiers(Decl *ClassDecl, BaseTy **Bases, unsigned NumBases) { if (!ClassDecl || !Bases || !NumBases) return; AdjustDeclIfTemplate(ClassDecl); - AttachBaseSpecifiers(cast(ClassDecl.getAs()), + AttachBaseSpecifiers(cast(ClassDecl), (CXXBaseSpecifier**)(Bases), NumBases); } @@ -719,7 +722,7 @@ bool Sema::IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths) { } void Sema::BuildBasePathArray(const CXXBasePaths &Paths, - CXXBaseSpecifierArray &BasePathArray) { + CXXCastPath &BasePathArray) { assert(BasePathArray.empty() && "Base path array must be empty!"); assert(Paths.isRecordingPaths() && "Must record paths!"); @@ -738,14 +741,14 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths, // Now add all bases. for (unsigned I = Start, E = Path.size(); I != E; ++I) - BasePathArray.push_back(Path[I].Base); + BasePathArray.push_back(const_cast(Path[I].Base)); } /// \brief Determine whether the given base path includes a virtual /// base class. -bool Sema::BasePathInvolvesVirtualBase(const CXXBaseSpecifierArray &BasePath) { - for (CXXBaseSpecifierArray::iterator B = BasePath.begin(), - BEnd = BasePath.end(); +bool Sema::BasePathInvolvesVirtualBase(const CXXCastPath &BasePath) { + for (CXXCastPath::const_iterator B = BasePath.begin(), + BEnd = BasePath.end(); B != BEnd; ++B) if ((*B)->isVirtual()) return true; @@ -767,7 +770,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name, - CXXBaseSpecifierArray *BasePath) { + CXXCastPath *BasePath) { // First, determine whether the path from Derived to Base is // ambiguous. This is slightly more expensive than checking whether // the Derived to Base conversion exists, because here we need to @@ -825,7 +828,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, bool Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, - CXXBaseSpecifierArray *BasePath, + CXXCastPath *BasePath, bool IgnoreAccess) { return CheckDerivedToBaseConversion(Derived, Base, IgnoreAccess ? 0 @@ -872,30 +875,31 @@ std::string Sema::getAmbiguousPathsDisplayString(CXXBasePaths &Paths) { //===----------------------------------------------------------------------===// /// ActOnAccessSpecifier - Parsed an access specifier followed by a colon. -Sema::DeclPtrTy -Sema::ActOnAccessSpecifier(AccessSpecifier Access, - SourceLocation ASLoc, SourceLocation ColonLoc) { +Decl *Sema::ActOnAccessSpecifier(AccessSpecifier Access, + SourceLocation ASLoc, + SourceLocation ColonLoc) { assert(Access != AS_none && "Invalid kind for syntactic access specifier!"); - AccessSpecDecl* ASDecl = AccessSpecDecl::Create(Context, Access, CurContext, + AccessSpecDecl *ASDecl = AccessSpecDecl::Create(Context, Access, CurContext, ASLoc, ColonLoc); CurContext->addHiddenDecl(ASDecl); - return DeclPtrTy::make(ASDecl); + return ASDecl; } /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member /// declarator is parsed. 'AS' is the access specifier, 'BW' specifies the /// bitfield width if there is one and 'InitExpr' specifies the initializer if /// any. -Sema::DeclPtrTy +Decl * Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, ExprTy *BW, ExprTy *InitExpr, bool IsDefinition, bool Deleted) { const DeclSpec &DS = D.getDeclSpec(); - DeclarationName Name = GetNameForDeclarator(D); + DeclarationNameInfo NameInfo = GetNameForDeclarator(D); + DeclarationName Name = NameInfo.getName(); + SourceLocation Loc = NameInfo.getLoc(); Expr *BitWidth = static_cast(BW); Expr *Init = static_cast(InitExpr); - SourceLocation Loc = D.getIdentifierLoc(); assert(isa(CurContext)); assert(!DS.isFriendSpecified()); @@ -905,7 +909,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, isFunc = true; else if (D.getNumTypeObjects() == 0 && D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_typename) { - QualType TDType = GetTypeFromParser(DS.getTypeRep()); + QualType TDType = GetTypeFromParser(DS.getRepAsType()); isFunc = TDType->isFunctionType(); } @@ -952,11 +956,9 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, AS); assert(Member && "HandleField never returns null"); } else { - Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition) - .getAs(); + Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition); if (!Member) { - if (BitWidth) DeleteExpr(BitWidth); - return DeclPtrTy(); + return 0; } // Non-instance-fields can't have a bitfield. @@ -980,7 +982,6 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, << BitWidth->getSourceRange(); } - DeleteExpr(BitWidth); BitWidth = 0; Member->setInvalidDecl(); } @@ -996,15 +997,15 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, assert((Name || isInstField) && "No identifier for non-field ?"); if (Init) - AddInitializerToDecl(DeclPtrTy::make(Member), ExprArg(*this, Init), false); + AddInitializerToDecl(Member, Init, false); if (Deleted) // FIXME: Source location is not very good. - SetDeclDeleted(DeclPtrTy::make(Member), D.getSourceRange().getBegin()); + SetDeclDeleted(Member, D.getSourceRange().getBegin()); if (isInstField) { FieldCollector->Add(cast(Member)); - return DeclPtrTy(); + return 0; } - return DeclPtrTy::make(Member); + return Member; } /// \brief Find the direct and/or virtual base specifiers that @@ -1053,12 +1054,12 @@ static bool FindBaseInitializer(Sema &SemaRef, } /// ActOnMemInitializer - Handle a C++ member initializer. -Sema::MemInitResult -Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, +MemInitResult +Sema::ActOnMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, - TypeTy *TemplateTypeTy, + ParsedType TemplateTypeTy, SourceLocation IdLoc, SourceLocation LParenLoc, ExprTy **Args, unsigned NumArgs, @@ -1070,7 +1071,7 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, AdjustDeclIfTemplate(ConstructorD); CXXConstructorDecl *Constructor - = dyn_cast(ConstructorD.getAs()); + = dyn_cast(ConstructorD); if (!Constructor) { // The user wrote a constructor initializer on a function that is // not a C++ constructor. Ignore the error for now, because we may @@ -1148,7 +1149,7 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD, CorrectTypo(R, S, &SS, ClassDecl, 0, CTC_NoKeywords) && R.isSingleResult()) { if (FieldDecl *Member = R.getAsSingle()) { - if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) { + if (Member->getDeclContext()->getRedeclContext()->Equals(ClassDecl)) { // We have found a non-static data member with a similar // name to what was typed; complain and initialize that // member. @@ -1259,7 +1260,7 @@ static bool InitExprContainsUninitializedFields(const Stmt *S, return false; } -Sema::MemInitResult +MemInitResult Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs, SourceLocation IdLoc, SourceLocation LParenLoc, @@ -1285,15 +1286,12 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, for (unsigned i = 0; i < NumArgs; i++) HasDependentArg |= Args[i]->isTypeDependent(); - QualType FieldType = Member->getType(); - if (const ArrayType *Array = Context.getAsArrayType(FieldType)) - FieldType = Array->getElementType(); - if (FieldType->isDependentType() || HasDependentArg) { + if (Member->getType()->isDependentType() || HasDependentArg) { // Can't check initialization for a member of dependent type or when // any of the arguments are type-dependent expressions. - OwningExprResult Init - = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc)); + Expr *Init + = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, + RParenLoc); // Erase any temporaries within this evaluation context; we're not // going to track them in the AST, since we'll be rebuilding the @@ -1304,7 +1302,7 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc, LParenLoc, - Init.takeAs(), + Init, RParenLoc); } @@ -1320,16 +1318,16 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs); - OwningExprResult MemberInit = + ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, - MultiExprArg(*this, (void**)Args, NumArgs), 0); + MultiExprArg(*this, Args, NumArgs), 0); if (MemberInit.isInvalid()) return true; // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. - MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit)); + MemberInit = MaybeCreateCXXExprWithTemporaries(MemberInit.get()); if (MemberInit.isInvalid()) return true; @@ -1345,22 +1343,21 @@ Sema::BuildMemberInitializer(FieldDecl *Member, Expr **Args, for (unsigned I = 0; I != NumArgs; ++I) Args[I]->Retain(); - OwningExprResult Init - = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, - RParenLoc)); + Expr *Init = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, + RParenLoc); return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc, LParenLoc, - Init.takeAs(), + Init, RParenLoc); } return new (Context) CXXBaseOrMemberInitializer(Context, Member, IdLoc, LParenLoc, - MemberInit.takeAs(), + MemberInit.get(), RParenLoc); } -Sema::MemInitResult +MemInitResult Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, Expr **Args, unsigned NumArgs, SourceLocation LParenLoc, SourceLocation RParenLoc, @@ -1413,7 +1410,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, if (Dependent) { // Can't check initialization for a base of dependent type or when // any of the arguments are type-dependent expressions. - OwningExprResult BaseInit + ExprResult BaseInit = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, RParenLoc)); @@ -1452,16 +1449,16 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs); - OwningExprResult BaseInit = + ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, - MultiExprArg(*this, (void**)Args, NumArgs), 0); + MultiExprArg(*this, Args, NumArgs), 0); if (BaseInit.isInvalid()) return true; // C++0x [class.base.init]p7: // The initialization of each base and member constitutes a // full-expression. - BaseInit = MaybeCreateCXXExprWithTemporaries(move(BaseInit)); + BaseInit = MaybeCreateCXXExprWithTemporaries(BaseInit.get()); if (BaseInit.isInvalid()) return true; @@ -1477,7 +1474,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, for (unsigned I = 0; I != NumArgs; ++I) Args[I]->Retain(); - OwningExprResult Init + ExprResult Init = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, RParenLoc)); return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo, @@ -1512,7 +1509,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, = InitializedEntity::InitializeBase(SemaRef.Context, BaseSpec, IsInheritedVirtualBase); - Sema::OwningExprResult BaseInit(SemaRef); + ExprResult BaseInit; switch (ImplicitInitKind) { case IIK_Default: { @@ -1520,7 +1517,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, = InitializationKind::CreateDefault(Constructor->getLocation()); InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, - Sema::MultiExprArg(SemaRef, 0, 0)); + MultiExprArg(SemaRef, 0, 0)); break; } @@ -1536,10 +1533,12 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, QualType ArgTy = SemaRef.Context.getQualifiedType(BaseSpec->getType().getUnqualifiedType(), ParamType.getQualifiers()); - SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy, - CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue=*/true, - CXXBaseSpecifierArray(BaseSpec)); + + CXXCastPath BasePath; + BasePath.push_back(BaseSpec); + SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy, + CK_UncheckedDerivedToBase, + VK_LValue, &BasePath); InitializationKind InitKind = InitializationKind::CreateDirect(Constructor->getLocation(), @@ -1547,16 +1546,18 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, &CopyCtorArg, 1); BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, - Sema::MultiExprArg(SemaRef, - (void**)&CopyCtorArg, 1)); + MultiExprArg(&CopyCtorArg, 1)); break; } case IIK_Move: assert(false && "Unhandled initializer kind!"); } + + if (BaseInit.isInvalid()) + return true; - BaseInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(BaseInit)); + BaseInit = SemaRef.MaybeCreateCXXExprWithTemporaries(BaseInit.get()); if (BaseInit.isInvalid()) return true; @@ -1596,8 +1597,8 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, Sema::LookupMemberName); MemberLookup.addDecl(Field, AS_public); MemberLookup.resolveKind(); - Sema::OwningExprResult CopyCtorArg - = SemaRef.BuildMemberReferenceExpr(SemaRef.Owned(MemberExprBase), + ExprResult CopyCtorArg + = SemaRef.BuildMemberReferenceExpr(MemberExprBase, ParamType, Loc, /*IsArrow=*/false, SS, @@ -1628,19 +1629,19 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc, IterationVarName, SizeType, SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc), - VarDecl::None, VarDecl::None); + SC_None, SC_None); IndexVariables.push_back(IterationVar); // Create a reference to the iteration variable. - Sema::OwningExprResult IterationVarRef + ExprResult IterationVarRef = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, Loc); assert(!IterationVarRef.isInvalid() && "Reference to invented variable cannot fail!"); // Subscript the array with this iteration variable. - CopyCtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(move(CopyCtorArg), + CopyCtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CopyCtorArg.take(), Loc, - move(IterationVarRef), + IterationVarRef.take(), Loc); if (CopyCtorArg.isInvalid()) return true; @@ -1667,10 +1668,10 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind, &CopyCtorArgE, 1); - Sema::OwningExprResult MemberInit + ExprResult MemberInit = InitSeq.Perform(SemaRef, Entities.back(), InitKind, - Sema::MultiExprArg(SemaRef, (void**)&CopyCtorArgE, 1)); - MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(MemberInit)); + MultiExprArg(&CopyCtorArgE, 1)); + MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(MemberInit.get()); if (MemberInit.isInvalid()) return true; @@ -1693,17 +1694,19 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationKind::CreateDefault(Loc); InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); - Sema::OwningExprResult MemberInit = - InitSeq.Perform(SemaRef, InitEntity, InitKind, - Sema::MultiExprArg(SemaRef, 0, 0)); - MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(move(MemberInit)); + ExprResult MemberInit = + InitSeq.Perform(SemaRef, InitEntity, InitKind, MultiExprArg()); + if (MemberInit.isInvalid()) + return true; + + MemberInit = SemaRef.MaybeCreateCXXExprWithTemporaries(MemberInit.get()); if (MemberInit.isInvalid()) return true; CXXMemberInit = new (SemaRef.Context) CXXBaseOrMemberInitializer(SemaRef.Context, Field, Loc, Loc, - MemberInit.takeAs(), + MemberInit.get(), Loc); return false; } @@ -1797,6 +1800,9 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, // Once we've initialized a field of an anonymous union, the union // field in the class is also initialized, so exit immediately. return false; + } else if ((*FA)->isAnonymousStructOrUnion()) { + if (CollectFieldInitializer(Info, Top, *FA)) + return true; } } @@ -2147,7 +2153,7 @@ bool CheckRedundantUnionInit(Sema &S, } /// ActOnMemInitializers - Handle the member initializers for a constructor. -void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, +void Sema::ActOnMemInitializers(Decl *ConstructorDecl, SourceLocation ColonLoc, MemInitTy **meminits, unsigned NumMemInits, bool AnyErrors) { @@ -2157,7 +2163,7 @@ void Sema::ActOnMemInitializers(DeclPtrTy ConstructorDecl, AdjustDeclIfTemplate(ConstructorDecl); CXXConstructorDecl *Constructor - = dyn_cast(ConstructorDecl.getAs()); + = dyn_cast(ConstructorDecl); if (!Constructor) { Diag(ColonLoc, diag::err_only_constructors_take_base_inits); @@ -2292,35 +2298,30 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, } } -void Sema::ActOnDefaultCtorInitializers(DeclPtrTy CDtorDecl) { +void Sema::ActOnDefaultCtorInitializers(Decl *CDtorDecl) { if (!CDtorDecl) return; if (CXXConstructorDecl *Constructor - = dyn_cast(CDtorDecl.getAs())) + = dyn_cast(CDtorDecl)) SetBaseOrMemberInitializers(Constructor, 0, 0, /*AnyErrors=*/false); } bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, - unsigned DiagID, AbstractDiagSelID SelID, - const CXXRecordDecl *CurrentRD) { + unsigned DiagID, AbstractDiagSelID SelID) { if (SelID == -1) - return RequireNonAbstractType(Loc, T, - PDiag(DiagID), CurrentRD); + return RequireNonAbstractType(Loc, T, PDiag(DiagID)); else - return RequireNonAbstractType(Loc, T, - PDiag(DiagID) << SelID, CurrentRD); + return RequireNonAbstractType(Loc, T, PDiag(DiagID) << SelID); } bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, - const PartialDiagnostic &PD, - const CXXRecordDecl *CurrentRD) { + const PartialDiagnostic &PD) { if (!getLangOptions().CPlusPlus) return false; if (const ArrayType *AT = Context.getAsArrayType(T)) - return RequireNonAbstractType(Loc, AT->getElementType(), PD, - CurrentRD); + return RequireNonAbstractType(Loc, AT->getElementType(), PD); if (const PointerType *PT = T->getAs()) { // Find the innermost pointer type. @@ -2328,7 +2329,7 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, PT = T; if (const ArrayType *AT = Context.getAsArrayType(PT->getPointeeType())) - return RequireNonAbstractType(Loc, AT->getElementType(), PD, CurrentRD); + return RequireNonAbstractType(Loc, AT->getElementType(), PD); } const RecordType *RT = T->getAs(); @@ -2337,22 +2338,27 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, const CXXRecordDecl *RD = cast(RT->getDecl()); - if (CurrentRD && CurrentRD != RD) - return false; - - // FIXME: is this reasonable? It matches current behavior, but.... - if (!RD->getDefinition()) + // We can't answer whether something is abstract until it has a + // definition. If it's currently being defined, we'll walk back + // over all the declarations when we have a full definition. + const CXXRecordDecl *Def = RD->getDefinition(); + if (!Def || Def->isBeingDefined()) return false; if (!RD->isAbstract()) return false; Diag(Loc, PD) << RD->getDeclName(); + DiagnoseAbstractType(RD); - // Check if we've already emitted the list of pure virtual functions for this - // class. + return true; +} + +void Sema::DiagnoseAbstractType(const CXXRecordDecl *RD) { + // Check if we've already emitted the list of pure virtual functions + // for this class. if (PureVirtualClassDiagSet && PureVirtualClassDiagSet->count(RD)) - return true; + return; CXXFinalOverriderMap FinalOverriders; RD->getFinalOverriders(FinalOverriders); @@ -2392,69 +2398,168 @@ bool Sema::RequireNonAbstractType(SourceLocation Loc, QualType T, if (!PureVirtualClassDiagSet) PureVirtualClassDiagSet.reset(new RecordDeclSetTy); PureVirtualClassDiagSet->insert(RD); - - return true; } namespace { - class AbstractClassUsageDiagnoser - : public DeclVisitor { - Sema &SemaRef; - CXXRecordDecl *AbstractClass; +struct AbstractUsageInfo { + Sema &S; + CXXRecordDecl *Record; + CanQualType AbstractType; + bool Invalid; + + AbstractUsageInfo(Sema &S, CXXRecordDecl *Record) + : S(S), Record(Record), + AbstractType(S.Context.getCanonicalType( + S.Context.getTypeDeclType(Record))), + Invalid(false) {} + + void DiagnoseAbstractType() { + if (Invalid) return; + S.DiagnoseAbstractType(Record); + Invalid = true; + } - bool VisitDeclContext(const DeclContext *DC) { - bool Invalid = false; + void CheckType(const NamedDecl *D, TypeLoc TL, Sema::AbstractDiagSelID Sel); +}; - for (CXXRecordDecl::decl_iterator I = DC->decls_begin(), - E = DC->decls_end(); I != E; ++I) - Invalid |= Visit(*I); +struct CheckAbstractUsage { + AbstractUsageInfo &Info; + const NamedDecl *Ctx; - return Invalid; + CheckAbstractUsage(AbstractUsageInfo &Info, const NamedDecl *Ctx) + : Info(Info), Ctx(Ctx) {} + + void Visit(TypeLoc TL, Sema::AbstractDiagSelID Sel) { + switch (TL.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: Check(cast(TL), Sel); break; +#include "clang/AST/TypeLocNodes.def" } + } - public: - AbstractClassUsageDiagnoser(Sema& SemaRef, CXXRecordDecl *ac) - : SemaRef(SemaRef), AbstractClass(ac) { - Visit(SemaRef.Context.getTranslationUnitDecl()); + void Check(FunctionProtoTypeLoc TL, Sema::AbstractDiagSelID Sel) { + Visit(TL.getResultLoc(), Sema::AbstractReturnType); + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { + TypeSourceInfo *TSI = TL.getArg(I)->getTypeSourceInfo(); + if (TSI) Visit(TSI->getTypeLoc(), Sema::AbstractParamType); } + } - bool VisitFunctionDecl(const FunctionDecl *FD) { - if (FD->isThisDeclarationADefinition()) { - // No need to do the check if we're in a definition, because it requires - // that the return/param types are complete. - // because that requires - return VisitDeclContext(FD); - } + void Check(ArrayTypeLoc TL, Sema::AbstractDiagSelID Sel) { + Visit(TL.getElementLoc(), Sema::AbstractArrayType); + } - // Check the return type. - QualType RTy = FD->getType()->getAs()->getResultType(); - bool Invalid = - SemaRef.RequireNonAbstractType(FD->getLocation(), RTy, - diag::err_abstract_type_in_decl, - Sema::AbstractReturnType, - AbstractClass); - - for (FunctionDecl::param_const_iterator I = FD->param_begin(), - E = FD->param_end(); I != E; ++I) { - const ParmVarDecl *VD = *I; - Invalid |= - SemaRef.RequireNonAbstractType(VD->getLocation(), - VD->getOriginalType(), - diag::err_abstract_type_in_decl, - Sema::AbstractParamType, - AbstractClass); - } + void Check(TemplateSpecializationTypeLoc TL, Sema::AbstractDiagSelID Sel) { + // Visit the type parameters from a permissive context. + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { + TemplateArgumentLoc TAL = TL.getArgLoc(I); + if (TAL.getArgument().getKind() == TemplateArgument::Type) + if (TypeSourceInfo *TSI = TAL.getTypeSourceInfo()) + Visit(TSI->getTypeLoc(), Sema::AbstractNone); + // TODO: other template argument types? + } + } - return Invalid; + // Visit pointee types from a permissive context. +#define CheckPolymorphic(Type) \ + void Check(Type TL, Sema::AbstractDiagSelID Sel) { \ + Visit(TL.getNextTypeLoc(), Sema::AbstractNone); \ + } + CheckPolymorphic(PointerTypeLoc) + CheckPolymorphic(ReferenceTypeLoc) + CheckPolymorphic(MemberPointerTypeLoc) + CheckPolymorphic(BlockPointerTypeLoc) + + /// Handle all the types we haven't given a more specific + /// implementation for above. + void Check(TypeLoc TL, Sema::AbstractDiagSelID Sel) { + // Every other kind of type that we haven't called out already + // that has an inner type is either (1) sugar or (2) contains that + // inner type in some way as a subobject. + if (TypeLoc Next = TL.getNextTypeLoc()) + return Visit(Next, Sel); + + // If there's no inner type and we're in a permissive context, + // don't diagnose. + if (Sel == Sema::AbstractNone) return; + + // Check whether the type matches the abstract type. + QualType T = TL.getType(); + if (T->isArrayType()) { + Sel = Sema::AbstractArrayType; + T = Info.S.Context.getBaseElementType(T); } + CanQualType CT = T->getCanonicalTypeUnqualified().getUnqualifiedType(); + if (CT != Info.AbstractType) return; - bool VisitDecl(const Decl* D) { - if (const DeclContext *DC = dyn_cast(D)) - return VisitDeclContext(DC); + // It matched; do some magic. + if (Sel == Sema::AbstractArrayType) { + Info.S.Diag(Ctx->getLocation(), diag::err_array_of_abstract_type) + << T << TL.getSourceRange(); + } else { + Info.S.Diag(Ctx->getLocation(), diag::err_abstract_type_in_decl) + << Sel << T << TL.getSourceRange(); + } + Info.DiagnoseAbstractType(); + } +}; - return false; +void AbstractUsageInfo::CheckType(const NamedDecl *D, TypeLoc TL, + Sema::AbstractDiagSelID Sel) { + CheckAbstractUsage(*this, D).Visit(TL, Sel); +} + +} + +/// Check for invalid uses of an abstract type in a method declaration. +static void CheckAbstractClassUsage(AbstractUsageInfo &Info, + CXXMethodDecl *MD) { + // No need to do the check on definitions, which require that + // the return/param types be complete. + if (MD->isThisDeclarationADefinition()) + return; + + // For safety's sake, just ignore it if we don't have type source + // information. This should never happen for non-implicit methods, + // but... + if (TypeSourceInfo *TSI = MD->getTypeSourceInfo()) + Info.CheckType(MD, TSI->getTypeLoc(), Sema::AbstractNone); +} + +/// Check for invalid uses of an abstract type within a class definition. +static void CheckAbstractClassUsage(AbstractUsageInfo &Info, + CXXRecordDecl *RD) { + for (CXXRecordDecl::decl_iterator + I = RD->decls_begin(), E = RD->decls_end(); I != E; ++I) { + Decl *D = *I; + if (D->isImplicit()) continue; + + // Methods and method templates. + if (isa(D)) { + CheckAbstractClassUsage(Info, cast(D)); + } else if (isa(D)) { + FunctionDecl *FD = cast(D)->getTemplatedDecl(); + CheckAbstractClassUsage(Info, cast(FD)); + + // Fields and static variables. + } else if (isa(D)) { + FieldDecl *FD = cast(D); + if (TypeSourceInfo *TSI = FD->getTypeSourceInfo()) + Info.CheckType(FD, TSI->getTypeLoc(), Sema::AbstractFieldType); + } else if (isa(D)) { + VarDecl *VD = cast(D); + if (TypeSourceInfo *TSI = VD->getTypeSourceInfo()) + Info.CheckType(VD, TSI->getTypeLoc(), Sema::AbstractVariableType); + + // Nested classes and class templates. + } else if (isa(D)) { + CheckAbstractClassUsage(Info, cast(D)); + } else if (isa(D)) { + CheckAbstractClassUsage(Info, + cast(D)->getTemplatedDecl()); } - }; + } } /// \brief Perform semantic checks on a class definition that has been @@ -2539,8 +2644,10 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } } - if (Record->isAbstract() && !Record->isInvalidDecl()) - (void)AbstractClassUsageDiagnoser(*this, Record); + if (Record->isAbstract() && !Record->isInvalidDecl()) { + AbstractUsageInfo Info(*this, Record); + CheckAbstractClassUsage(Info, Record); + } // If this is not an aggregate type and has no user-declared constructor, // complain about any non-static data members of reference or const scalar @@ -2571,7 +2678,7 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, - DeclPtrTy TagDecl, + Decl *TagDecl, SourceLocation LBrac, SourceLocation RBrac, AttributeList *AttrList) { @@ -2581,11 +2688,12 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, AdjustDeclIfTemplate(TagDecl); ActOnFields(S, RLoc, TagDecl, - (DeclPtrTy*)FieldCollector->getCurFields(), + // strict aliasing violation! + reinterpret_cast(FieldCollector->getCurFields()), FieldCollector->getCurNumFields(), LBrac, RBrac, AttrList); CheckCompletedCXXClass( - dyn_cast_or_null(TagDecl.getAs())); + dyn_cast_or_null(TagDecl)); } namespace { @@ -2682,8 +2790,7 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { } } -void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) { - Decl *D = TemplateD.getAs(); +void Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) { if (!D) return; @@ -2701,20 +2808,20 @@ void Sema::ActOnReenterTemplateScope(Scope *S, DeclPtrTy TemplateD) { Param != ParamEnd; ++Param) { NamedDecl *Named = cast(*Param); if (Named->getDeclName()) { - S->AddDecl(DeclPtrTy::make(Named)); + S->AddDecl(Named); IdResolver.AddDecl(Named); } } } -void Sema::ActOnStartDelayedMemberDeclarations(Scope *S, DeclPtrTy RecordD) { +void Sema::ActOnStartDelayedMemberDeclarations(Scope *S, Decl *RecordD) { if (!RecordD) return; AdjustDeclIfTemplate(RecordD); - CXXRecordDecl *Record = cast(RecordD.getAs()); + CXXRecordDecl *Record = cast(RecordD); PushDeclContext(S, Record); } -void Sema::ActOnFinishDelayedMemberDeclarations(Scope *S, DeclPtrTy RecordD) { +void Sema::ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *RecordD) { if (!RecordD) return; PopDeclContext(); } @@ -2727,7 +2834,7 @@ void Sema::ActOnFinishDelayedMemberDeclarations(Scope *S, DeclPtrTy RecordD) { /// Method declaration as if we had just parsed the qualified method /// name. However, it should not bring the parameters into scope; /// that will be performed by ActOnDelayedCXXMethodParameter. -void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) { +void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *MethodD) { } /// ActOnDelayedCXXMethodParameter - We've already started a delayed @@ -2735,18 +2842,18 @@ void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) { /// function parameter into scope for use in parsing later parts of /// the method declaration. For example, we could see an /// ActOnParamDefaultArgument event for this parameter. -void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy ParamD) { +void Sema::ActOnDelayedCXXMethodParameter(Scope *S, Decl *ParamD) { if (!ParamD) return; - ParmVarDecl *Param = cast(ParamD.getAs()); + ParmVarDecl *Param = cast(ParamD); // If this parameter has an unparsed default argument, clear it out // to make way for the parsed default argument. if (Param->hasUnparsedDefaultArg()) Param->setDefaultArg(0); - S->AddDecl(DeclPtrTy::make(Param)); + S->AddDecl(Param); if (Param->getDeclName()) IdResolver.AddDecl(Param); } @@ -2757,13 +2864,13 @@ void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclPtrTy ParamD) { /// ActOnStartOfFunctionDef action later (not necessarily /// immediately!) for this method, if it was also defined inside the /// class body. -void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) { +void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *MethodD) { if (!MethodD) return; AdjustDeclIfTemplate(MethodD); - FunctionDecl *Method = cast(MethodD.getAs()); + FunctionDecl *Method = cast(MethodD); // Now that we have our default arguments, check the constructor // again. It could produce additional diagnostics or affect whether @@ -2784,7 +2891,7 @@ void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclPtrTy MethodD) { /// will be updated to reflect a well-formed type for the constructor and /// returned. QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, - FunctionDecl::StorageClass &SC) { + StorageClass &SC) { bool isVirtual = D.getDeclSpec().isVirtualSpecified(); // C++ [class.ctor]p3: @@ -2799,13 +2906,13 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); } - if (SC == FunctionDecl::Static) { + if (SC == SC_Static) { if (!D.isInvalidType()) Diag(D.getIdentifierLoc(), diag::err_constructor_cannot_be) << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc()) << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); - SC = FunctionDecl::None; + SC = SC_None; } DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun; @@ -2879,8 +2986,9 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { ClassDecl->addedConstructor(Context, Constructor); } -/// CheckDestructor - Checks a fully-formed destructor for well-formedness, -/// issuing any diagnostics required. Returns true on error. +/// CheckDestructor - Checks a fully-formed destructor definition for +/// well-formedness, issuing any diagnostics required. Returns true +/// on error. bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) { CXXRecordDecl *RD = Destructor->getParent(); @@ -2911,7 +3019,7 @@ static inline bool FTIHasSingleVoidArgument(DeclaratorChunk::FunctionTypeInfo &FTI) { return (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && FTI.ArgInfo[0].Param && - FTI.ArgInfo[0].Param.getAs()->getType()->isVoidType()); + cast(FTI.ArgInfo[0].Param)->getType()->isVoidType()); } /// CheckDestructorDeclarator - Called by ActOnDeclarator to check @@ -2921,7 +3029,7 @@ FTIHasSingleVoidArgument(DeclaratorChunk::FunctionTypeInfo &FTI) { /// will be updated to reflect a well-formed type for the destructor and /// returned. QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, - FunctionDecl::StorageClass& SC) { + StorageClass& SC) { // C++ [class.dtor]p1: // [...] A typedef-name that names a class is a class-name // (7.1.3); however, a typedef-name that names a class shall not @@ -2940,14 +3048,14 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, // destructor can be invoked for a const, volatile or const // volatile object. A destructor shall not be declared const, // volatile or const volatile (9.3.2). - if (SC == FunctionDecl::Static) { + if (SC == SC_Static) { if (!D.isInvalidType()) Diag(D.getIdentifierLoc(), diag::err_destructor_cannot_be) << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc()) << SourceRange(D.getIdentifierLoc()) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); - SC = FunctionDecl::None; + SC = SC_None; } if (D.getDeclSpec().hasTypeSpecifier() && !D.isInvalidType()) { // Destructors don't have return types, but the parser will @@ -3015,18 +3123,18 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, /// false. Either way, the type @p R will be updated to reflect a /// well-formed type for the conversion operator. void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, - FunctionDecl::StorageClass& SC) { + StorageClass& SC) { // C++ [class.conv.fct]p1: // Neither parameter types nor return type can be specified. The // type of a conversion function (8.3.5) is "function taking no // parameter returning conversion-type-id." - if (SC == FunctionDecl::Static) { + if (SC == SC_Static) { if (!D.isInvalidType()) Diag(D.getIdentifierLoc(), diag::err_conv_function_not_member) << "static" << SourceRange(D.getDeclSpec().getStorageClassSpecLoc()) << SourceRange(D.getIdentifierLoc()); D.setInvalidType(); - SC = FunctionDecl::None; + SC = SC_None; } QualType ConvType = GetTypeFromParser(D.getName().ConversionFunctionId); @@ -3106,7 +3214,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, /// the declaration of the given C++ conversion function. This routine /// is responsible for recording the conversion function in the C++ /// class, if possible. -Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { +Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { assert(Conversion && "Expected to receive a conversion function declaration"); CXXRecordDecl *ClassDecl = cast(Conversion->getDeclContext()); @@ -3147,10 +3255,10 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { if (ClassDecl->replaceConversion( ConversionTemplate->getPreviousDeclaration(), ConversionTemplate)) - return DeclPtrTy::make(ConversionTemplate); + return ConversionTemplate; } else if (ClassDecl->replaceConversion(Conversion->getPreviousDeclaration(), Conversion)) - return DeclPtrTy::make(Conversion); + return Conversion; assert(Conversion->isInvalidDecl() && "Conversion should not get here."); } else if (FunctionTemplateDecl *ConversionTemplate = Conversion->getDescribedFunctionTemplate()) @@ -3158,28 +3266,36 @@ Sema::DeclPtrTy Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { else ClassDecl->addConversionFunction(Conversion); - return DeclPtrTy::make(Conversion); + return Conversion; } //===----------------------------------------------------------------------===// // Namespace Handling //===----------------------------------------------------------------------===// + + /// ActOnStartNamespaceDef - This is called at the start of a namespace /// definition. -Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, - SourceLocation IdentLoc, - IdentifierInfo *II, - SourceLocation LBrace, - AttributeList *AttrList) { - NamespaceDecl *Namespc = - NamespaceDecl::Create(Context, CurContext, IdentLoc, II); +Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, + SourceLocation InlineLoc, + SourceLocation IdentLoc, + IdentifierInfo *II, + SourceLocation LBrace, + AttributeList *AttrList) { + // anonymous namespace starts at its left brace + NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, + (II ? IdentLoc : LBrace) , II); Namespc->setLBracLoc(LBrace); + Namespc->setInline(InlineLoc.isValid()); Scope *DeclRegionScope = NamespcScope->getParent(); ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList); + if (const VisibilityAttr *attr = Namespc->getAttr()) + PushVisibilityAttr(attr); + if (II) { // C++ [namespace.def]p2: // The identifier in an original-namespace-definition shall not have been @@ -3194,15 +3310,25 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, if (NamespaceDecl *OrigNS = dyn_cast_or_null(PrevDecl)) { // This is an extended namespace definition. + if (Namespc->isInline() != OrigNS->isInline()) { + // inline-ness must match + Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch) + << Namespc->isInline(); + Diag(OrigNS->getLocation(), diag::note_previous_definition); + Namespc->setInvalidDecl(); + // Recover by ignoring the new namespace's inline status. + Namespc->setInline(OrigNS->isInline()); + } + // Attach this namespace decl to the chain of extended namespace // definitions. OrigNS->setNextNamespace(Namespc); Namespc->setOriginalNamespace(OrigNS->getOriginalNamespace()); // Remove the previous declaration from the scope. - if (DeclRegionScope->isDeclScope(DeclPtrTy::make(OrigNS))) { + if (DeclRegionScope->isDeclScope(OrigNS)) { IdResolver.RemoveDecl(OrigNS); - DeclRegionScope->RemoveDecl(DeclPtrTy::make(OrigNS)); + DeclRegionScope->RemoveDecl(OrigNS); } } else if (PrevDecl) { // This is an invalid name redefinition. @@ -3212,15 +3338,15 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, Namespc->setInvalidDecl(); // Continue on to push Namespc as current DeclContext and return it. } else if (II->isStr("std") && - CurContext->getLookupContext()->isTranslationUnit()) { + CurContext->getRedeclContext()->isTranslationUnit()) { // This is the first "real" definition of the namespace "std", so update // our cache of the "std" namespace to point at this definition. - if (StdNamespace) { + if (NamespaceDecl *StdNS = getStdNamespace()) { // We had already defined a dummy namespace "std". Link this new // namespace definition to the dummy namespace "std". - StdNamespace->setNextNamespace(Namespc); - StdNamespace->setLocation(IdentLoc); - Namespc->setOriginalNamespace(StdNamespace->getOriginalNamespace()); + StdNS->setNextNamespace(Namespc); + StdNS->setLocation(IdentLoc); + Namespc->setOriginalNamespace(StdNS->getOriginalNamespace()); } // Make our StdNamespace cache point at the first real definition of the @@ -3235,7 +3361,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // Link the anonymous namespace into its parent. NamespaceDecl *PrevDecl; - DeclContext *Parent = CurContext->getLookupContext(); + DeclContext *Parent = CurContext->getRedeclContext(); if (TranslationUnitDecl *TU = dyn_cast(Parent)) { PrevDecl = TU->getAnonymousNamespace(); TU->setAnonymousNamespace(Namespc); @@ -3251,6 +3377,16 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, assert(!PrevDecl->getNextNamespace()); Namespc->setOriginalNamespace(PrevDecl->getOriginalNamespace()); PrevDecl->setNextNamespace(Namespc); + + if (Namespc->isInline() != PrevDecl->isInline()) { + // inline-ness must match + Diag(Namespc->getLocation(), diag::err_inline_namespace_mismatch) + << Namespc->isInline(); + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + Namespc->setInvalidDecl(); + // Recover by ignoring the new namespace's inline status. + Namespc->setInline(PrevDecl->isInline()); + } } CurContext->addDecl(Namespc); @@ -3292,7 +3428,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // for the namespace has the declarations that showed up in that particular // namespace definition. PushDeclContext(NamespcScope, Namespc); - return DeclPtrTy::make(Namespc); + return Namespc; } /// getNamespaceDecl - Returns the namespace a decl represents. If the decl @@ -3305,30 +3441,41 @@ static inline NamespaceDecl *getNamespaceDecl(NamedDecl *D) { /// ActOnFinishNamespaceDef - This callback is called after a namespace is /// exited. Decl is the DeclTy returned by ActOnStartNamespaceDef. -void Sema::ActOnFinishNamespaceDef(DeclPtrTy D, SourceLocation RBrace) { - Decl *Dcl = D.getAs(); +void Sema::ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace) { NamespaceDecl *Namespc = dyn_cast_or_null(Dcl); assert(Namespc && "Invalid parameter, expected NamespaceDecl"); Namespc->setRBracLoc(RBrace); PopDeclContext(); + if (Namespc->hasAttr()) + PopPragmaVisibility(); +} + +CXXRecordDecl *Sema::getStdBadAlloc() const { + return cast_or_null( + StdBadAlloc.get(Context.getExternalSource())); +} + +NamespaceDecl *Sema::getStdNamespace() const { + return cast_or_null( + StdNamespace.get(Context.getExternalSource())); } /// \brief Retrieve the special "std" namespace, which may require us to /// implicitly define the namespace. -NamespaceDecl *Sema::getStdNamespace() { +NamespaceDecl *Sema::getOrCreateStdNamespace() { if (!StdNamespace) { // The "std" namespace has not yet been defined, so build one implicitly. StdNamespace = NamespaceDecl::Create(Context, Context.getTranslationUnitDecl(), SourceLocation(), &PP.getIdentifierTable().get("std")); - StdNamespace->setImplicit(true); + getStdNamespace()->setImplicit(true); } - return StdNamespace; + return getStdNamespace(); } -Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, +Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc, SourceLocation NamespcLoc, CXXScopeSpec &SS, @@ -3349,7 +3496,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName); LookupParsedName(R, S, &SS); if (R.isAmbiguous()) - return DeclPtrTy(); + return 0; if (R.empty()) { // Allow "using namespace std;" or "using namespace ::std;" even if @@ -3357,7 +3504,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, if ((!Qualifier || Qualifier->getKind() == NestedNameSpecifier::Global) && NamespcName->isStr("std")) { Diag(IdentLoc, diag::ext_using_undefined_std); - R.addDecl(getStdNamespace()); + R.addDecl(getOrCreateStdNamespace()); R.resolveKind(); } // Otherwise, attempt typo correction. @@ -3416,7 +3563,7 @@ Sema::DeclPtrTy Sema::ActOnUsingDirective(Scope *S, // FIXME: We ignore attributes for now. delete AttrList; - return DeclPtrTy::make(UDir); + return UDir; } void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { @@ -3428,11 +3575,11 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { else // Otherwise it is block-sope. using-directives will affect lookup // only to the end of scope. - S->PushUsingDirective(DeclPtrTy::make(UDir)); + S->PushUsingDirective(UDir); } -Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, +Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, bool HasUsingKeyword, SourceLocation UsingLoc, @@ -3457,22 +3604,23 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_constructor) << SS.getRange(); - return DeclPtrTy(); + return 0; case UnqualifiedId::IK_DestructorName: Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_destructor) << SS.getRange(); - return DeclPtrTy(); + return 0; case UnqualifiedId::IK_TemplateId: Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_template_id) << SourceRange(Name.TemplateId->LAngleLoc, Name.TemplateId->RAngleLoc); - return DeclPtrTy(); + return 0; } - - DeclarationName TargetName = GetNameFromUnqualifiedId(Name); + + DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); + DeclarationName TargetName = TargetNameInfo.getName(); if (!TargetName) - return DeclPtrTy(); + return 0; // Warn about using declarations. // TODO: store that the declaration was written without 'using' and @@ -3486,14 +3634,13 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, } NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS, - Name.getSourceRange().getBegin(), - TargetName, AttrList, + TargetNameInfo, AttrList, /* IsInstantiation */ false, IsTypeName, TypenameLoc); if (UD) PushOnScopeChains(UD, S, /*AddToContext*/ false); - return DeclPtrTy::make(UD); + return UD; } /// \brief Determine whether a using declaration considers the given @@ -3717,7 +3864,7 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { // ...and the scope, if applicable... if (S) { - S->RemoveDecl(DeclPtrTy::make(static_cast(Shadow))); + S->RemoveDecl(Shadow); IdResolver.RemoveDecl(Shadow); } @@ -3736,13 +3883,13 @@ void Sema::HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow) { NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, CXXScopeSpec &SS, - SourceLocation IdentLoc, - DeclarationName Name, + const DeclarationNameInfo &NameInfo, AttributeList *AttrList, bool IsInstantiation, bool IsTypeName, SourceLocation TypenameLoc) { assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); + SourceLocation IdentLoc = NameInfo.getLoc(); assert(IdentLoc.isValid() && "Invalid TargetName location."); // FIXME: We ignore attributes for now. @@ -3754,7 +3901,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, } // Do the redeclaration lookup in the current scope. - LookupResult Previous(*this, Name, IdentLoc, LookupUsingDeclName, + LookupResult Previous(*this, NameInfo, LookupUsingDeclName, ForRedeclaration); Previous.setHideTags(false); if (S) { @@ -3793,15 +3940,15 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, D = UnresolvedUsingTypenameDecl::Create(Context, CurContext, UsingLoc, TypenameLoc, SS.getRange(), NNS, - IdentLoc, Name); + IdentLoc, NameInfo.getName()); } else { D = UnresolvedUsingValueDecl::Create(Context, CurContext, - UsingLoc, SS.getRange(), NNS, - IdentLoc, Name); + UsingLoc, SS.getRange(), + NNS, NameInfo); } } else { - D = UsingDecl::Create(Context, CurContext, IdentLoc, - SS.getRange(), UsingLoc, NNS, Name, + D = UsingDecl::Create(Context, CurContext, + SS.getRange(), UsingLoc, NNS, NameInfo, IsTypeName); } D->setAccess(AS); @@ -3817,7 +3964,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, // Look up the target name. - LookupResult R(*this, Name, IdentLoc, LookupOrdinaryName); + LookupResult R(*this, NameInfo, LookupOrdinaryName); // Unlike most lookups, we don't always want to hide tag // declarations: tag names are visible through the using declaration @@ -3830,7 +3977,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, if (R.empty()) { Diag(IdentLoc, diag::err_no_member) - << Name << LookupContext << SS.getRange(); + << NameInfo.getName() << LookupContext << SS.getRange(); UD->setInvalidDecl(); return UD; } @@ -3894,7 +4041,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, // allowed. // // That's in non-member contexts. - if (!CurContext->getLookupContext()->isRecord()) + if (!CurContext->getRedeclContext()->isRecord()) return false; NestedNameSpecifier *Qual @@ -4069,7 +4216,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, return true; } -Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, +Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, @@ -4096,18 +4243,18 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, // declaration to maintain better source information. if (!R.isAmbiguous() && !R.empty() && AD->getNamespace()->Equals(getNamespaceDecl(R.getFoundDecl()))) - return DeclPtrTy(); + return 0; } unsigned DiagID = isa(PrevDecl) ? diag::err_redefinition : diag::err_redefinition_different_kind; Diag(AliasLoc, DiagID) << Alias; Diag(PrevDecl->getLocation(), diag::note_previous_definition); - return DeclPtrTy(); + return 0; } if (R.isAmbiguous()) - return DeclPtrTy(); + return 0; if (R.empty()) { if (DeclarationName Corrected = CorrectTypo(R, S, &SS, 0, false, @@ -4135,7 +4282,7 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, if (R.empty()) { Diag(NamespaceLoc, diag::err_expected_namespace_name) << SS.getRange(); - return DeclPtrTy(); + return 0; } } @@ -4146,7 +4293,7 @@ Sema::DeclPtrTy Sema::ActOnNamespaceAliasDef(Scope *S, IdentLoc, R.getFoundDecl()); PushOnScopeChains(AliasDecl, S); - return DeclPtrTy::make(AliasDecl); + return AliasDecl; } namespace { @@ -4242,9 +4389,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(ClassType); + DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation()); CXXConstructorDecl *DefaultCon - = CXXConstructorDecl::Create(Context, ClassDecl, - ClassDecl->getLocation(), Name, + = CXXConstructorDecl::Create(Context, ClassDecl, NameInfo, Context.getFunctionType(Context.VoidTy, 0, 0, false, 0, ExceptSpec.hasExceptionSpecification(), @@ -4348,9 +4495,9 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(ClassType); + DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation()); CXXDestructorDecl *Destructor - = CXXDestructorDecl::Create(Context, ClassDecl, - ClassDecl->getLocation(), Name, Ty, + = CXXDestructorDecl::Create(Context, ClassDecl, NameInfo, Ty, /*isInline=*/true, /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); @@ -4426,13 +4573,10 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, /// \param Depth Internal parameter recording the depth of the recursion. /// /// \returns A statement or a loop that copies the expressions. -static Sema::OwningStmtResult +static StmtResult BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, - Sema::OwningExprResult To, Sema::OwningExprResult From, + Expr *To, Expr *From, bool CopyingBaseSubobject, unsigned Depth = 0) { - typedef Sema::OwningStmtResult OwningStmtResult; - typedef Sema::OwningExprResult OwningExprResult; - // C++0x [class.copy]p30: // Each subobject is assigned in the manner appropriate to its type: // @@ -4489,21 +4633,21 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, T.getTypePtr())); // Create the reference to operator=. - OwningExprResult OpEqualRef - = S.BuildMemberReferenceExpr(move(To), T, Loc, /*isArrow=*/false, SS, + ExprResult OpEqualRef + = S.BuildMemberReferenceExpr(To, T, Loc, /*isArrow=*/false, SS, /*FirstQualifierInScope=*/0, OpLookup, /*TemplateArgs=*/0, /*SuppressQualifierCheck=*/true); if (OpEqualRef.isInvalid()) - return S.StmtError(); + return StmtError(); // Build the call to the assignment operator. - Expr *FromE = From.takeAs(); - OwningExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0, + + ExprResult Call = S.BuildCallToMemberFunction(/*Scope=*/0, OpEqualRef.takeAs(), - Loc, &FromE, 1, 0, Loc); + Loc, &From, 1, 0, Loc); if (Call.isInvalid()) - return S.StmtError(); + return StmtError(); return S.Owned(Call.takeAs()); } @@ -4512,12 +4656,9 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, // operator is used. const ConstantArrayType *ArrayTy = S.Context.getAsConstantArrayType(T); if (!ArrayTy) { - OwningExprResult Assignment = S.CreateBuiltinBinOp(Loc, - BinaryOperator::Assign, - To.takeAs(), - From.takeAs()); + ExprResult Assignment = S.CreateBuiltinBinOp(Loc, BO_Assign, To, From); if (Assignment.isInvalid()) - return S.StmtError(); + return StmtError(); return S.Owned(Assignment.takeAs()); } @@ -4543,11 +4684,11 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc, IterationVarName, SizeType, S.Context.getTrivialTypeSourceInfo(SizeType, Loc), - VarDecl::None, VarDecl::None); + SC_None, SC_None); // Initialize the iteration variable to zero. llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0); - IterationVar->setInit(new (S.Context) IntegerLiteral(Zero, SizeType, Loc)); + IterationVar->setInit(IntegerLiteral::Create(S.Context, Zero, SizeType, Loc)); // Create a reference to the iteration variable; we'll use this several // times throughout. @@ -4561,43 +4702,37 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, // Create the comparison against the array bound. llvm::APInt Upper = ArrayTy->getSize(); Upper.zextOrTrunc(S.Context.getTypeSize(SizeType)); - OwningExprResult Comparison - = S.Owned(new (S.Context) BinaryOperator(IterationVarRef->Retain(), - new (S.Context) IntegerLiteral(Upper, SizeType, Loc), - BinaryOperator::NE, S.Context.BoolTy, Loc)); + Expr *Comparison + = new (S.Context) BinaryOperator(IterationVarRef->Retain(), + IntegerLiteral::Create(S.Context, + Upper, SizeType, Loc), + BO_NE, S.Context.BoolTy, Loc); // Create the pre-increment of the iteration variable. - OwningExprResult Increment - = S.Owned(new (S.Context) UnaryOperator(IterationVarRef->Retain(), - UnaryOperator::PreInc, - SizeType, Loc)); + Expr *Increment + = new (S.Context) UnaryOperator(IterationVarRef->Retain(), + UO_PreInc, + SizeType, Loc); // Subscript the "from" and "to" expressions with the iteration variable. - From = S.CreateBuiltinArraySubscriptExpr(move(From), Loc, - S.Owned(IterationVarRef->Retain()), - Loc); - To = S.CreateBuiltinArraySubscriptExpr(move(To), Loc, - S.Owned(IterationVarRef->Retain()), - Loc); - assert(!From.isInvalid() && "Builtin subscripting can't fail!"); - assert(!To.isInvalid() && "Builtin subscripting can't fail!"); + From = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(From, Loc, + IterationVarRef, Loc)); + To = AssertSuccess(S.CreateBuiltinArraySubscriptExpr(To, Loc, + IterationVarRef, Loc)); // Build the copy for an individual element of the array. - OwningStmtResult Copy = BuildSingleCopyAssign(S, Loc, + StmtResult Copy = BuildSingleCopyAssign(S, Loc, ArrayTy->getElementType(), - move(To), move(From), + To, From, CopyingBaseSubobject, Depth+1); - if (Copy.isInvalid()) { - InitStmt->Destroy(S.Context); - return S.StmtError(); - } + if (Copy.isInvalid()) + return StmtError(); // Construct the loop that copies all elements of this array. - return S.ActOnForStmt(Loc, Loc, S.Owned(InitStmt), + return S.ActOnForStmt(Loc, Loc, InitStmt, S.MakeFullExpr(Comparison), - Sema::DeclPtrTy(), - S.MakeFullExpr(Increment), - Loc, move(Copy)); + 0, S.MakeFullExpr(Increment), + Loc, Copy.take()); } /// \brief Determine whether the given class has a copy assignment operator @@ -4747,8 +4882,9 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // An implicitly-declared copy assignment operator is an inline public // member of its class. DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); + DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation()); CXXMethodDecl *CopyAssignment - = CXXMethodDecl::Create(Context, ClassDecl, ClassDecl->getLocation(), Name, + = CXXMethodDecl::Create(Context, ClassDecl, NameInfo, Context.getFunctionType(RetType, &ArgType, 1, false, 0, ExceptSpec.hasExceptionSpecification(), @@ -4757,7 +4893,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { ExceptSpec.data(), FunctionType::ExtInfo()), /*TInfo=*/0, /*isStatic=*/false, - /*StorageClassAsWritten=*/FunctionDecl::None, + /*StorageClassAsWritten=*/SC_None, /*isInline=*/true); CopyAssignment->setAccess(AS_public); CopyAssignment->setImplicit(); @@ -4769,8 +4905,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { ClassDecl->getLocation(), /*Id=*/0, ArgType, /*TInfo=*/0, - VarDecl::None, - VarDecl::None, 0); + SC_None, + SC_None, 0); CopyAssignment->setParams(&FromParam, 1); // Note that we have added this copy-assignment operator. @@ -4814,7 +4950,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // which they were declared in the class definition. // The statements that form the synthesized function body. - ASTOwningVector<&ActionBase::DeleteStmt> Statements(*this); + ASTOwningVector Statements(*this); // The parameter for the "other" object, which we are copying from. ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0); @@ -4854,30 +4990,32 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, continue; } + CXXCastPath BasePath; + BasePath.push_back(Base); + // Construct the "from" expression, which is an implicit cast to the // appropriately-qualified base type. Expr *From = OtherRef->Retain(); ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals), - CastExpr::CK_UncheckedDerivedToBase, /*isLvalue=*/true, - CXXBaseSpecifierArray(Base)); + CK_UncheckedDerivedToBase, + VK_LValue, &BasePath); // Dereference "this". - OwningExprResult To = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref, - Owned(This->Retain())); + ExprResult To = CreateBuiltinUnaryOp(Loc, UO_Deref, This); // Implicitly cast "this" to the appropriately-qualified base type. Expr *ToE = To.takeAs(); ImpCastExprToType(ToE, Context.getCVRQualifiedType(BaseType, CopyAssignOperator->getTypeQualifiers()), - CastExpr::CK_UncheckedDerivedToBase, - /*isLvalue=*/true, CXXBaseSpecifierArray(Base)); + CK_UncheckedDerivedToBase, + VK_LValue, &BasePath); To = Owned(ToE); // Build the copy. - OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType, - move(To), Owned(From), - /*CopyingBaseSubobject=*/true); + StmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType, + To.get(), From, + /*CopyingBaseSubobject=*/true); if (Copy.isInvalid()) { Diag(CurrentLocation, diag::note_member_synthesized_at) << CXXCopyAssignment << Context.getTagDeclType(ClassDecl); @@ -4934,12 +5072,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, LookupMemberName); MemberLookup.addDecl(*Field); MemberLookup.resolveKind(); - OwningExprResult From = BuildMemberReferenceExpr(Owned(OtherRef->Retain()), - OtherRefType, + ExprResult From = BuildMemberReferenceExpr(OtherRef, OtherRefType, Loc, /*IsArrow=*/false, SS, 0, MemberLookup, 0); - OwningExprResult To = BuildMemberReferenceExpr(Owned(This->Retain()), - This->getType(), + ExprResult To = BuildMemberReferenceExpr(This, This->getType(), Loc, /*IsArrow=*/true, SS, 0, MemberLookup, 0); assert(!From.isInvalid() && "Implicit field reference cannot fail"); @@ -4967,8 +5103,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } // Take the address of the field references for "from" and "to". - From = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(From)); - To = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(To)); + From = CreateBuiltinUnaryOp(Loc, UO_AddrOf, From.get()); + To = CreateBuiltinUnaryOp(Loc, UO_AddrOf, To.get()); bool NeedsCollectableMemCpy = (BaseType->isRecordType() && @@ -5016,22 +5152,22 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, assert(BuiltinMemCpyRef && "Builtin reference cannot fail"); } - ASTOwningVector<&ActionBase::DeleteExpr> CallArgs(*this); + ASTOwningVector CallArgs(*this); CallArgs.push_back(To.takeAs()); CallArgs.push_back(From.takeAs()); - CallArgs.push_back(new (Context) IntegerLiteral(Size, SizeType, Loc)); + CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc)); llvm::SmallVector Commas; // FIXME: Silly Commas.push_back(Loc); Commas.push_back(Loc); - OwningExprResult Call = ExprError(); + ExprResult Call = ExprError(); if (NeedsCollectableMemCpy) Call = ActOnCallExpr(/*Scope=*/0, - Owned(CollectableMemCpyRef->Retain()), + CollectableMemCpyRef, Loc, move_arg(CallArgs), Commas.data(), Loc); else Call = ActOnCallExpr(/*Scope=*/0, - Owned(BuiltinMemCpyRef->Retain()), + BuiltinMemCpyRef, Loc, move_arg(CallArgs), Commas.data(), Loc); @@ -5041,8 +5177,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } // Build the copy of this field. - OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType, - move(To), move(From), + StmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType, + To.get(), From.get(), /*CopyingBaseSubobject=*/false); if (Copy.isInvalid()) { Diag(CurrentLocation, diag::note_member_synthesized_at) @@ -5057,10 +5193,9 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, if (!Invalid) { // Add a "return *this;" - OwningExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UnaryOperator::Deref, - Owned(This->Retain())); + ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This); - OwningStmtResult Return = ActOnReturnStmt(Loc, move(ThisObj)); + StmtResult Return = ActOnReturnStmt(Loc, ThisObj.get()); if (Return.isInvalid()) Invalid = true; else { @@ -5079,7 +5214,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, return; } - OwningStmtResult Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements), + StmtResult Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements), /*isStmtExpr=*/false); assert(!Body.isInvalid() && "Compound statement creation cannot fail"); CopyAssignOperator->setBody(Body.takeAs()); @@ -5220,9 +5355,9 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType)); + DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation()); CXXConstructorDecl *CopyConstructor - = CXXConstructorDecl::Create(Context, ClassDecl, - ClassDecl->getLocation(), Name, + = CXXConstructorDecl::Create(Context, ClassDecl, NameInfo, Context.getFunctionType(Context.VoidTy, &ArgType, 1, false, 0, @@ -5248,8 +5383,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ClassDecl->getLocation(), /*IdentifierInfo=*/0, ArgType, /*TInfo=*/0, - VarDecl::None, - VarDecl::None, 0); + SC_None, + SC_None, 0); CopyConstructor->setParams(&FromParam, 1); if (Scope *S = getScopeForContext(ClassDecl)) PushOnScopeChains(CopyConstructor, S, false); @@ -5288,12 +5423,12 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CopyConstructor->setUsed(); } -Sema::OwningExprResult +ExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, MultiExprArg ExprArgs, bool RequiresZeroInit, - CXXConstructExpr::ConstructionKind ConstructKind) { + unsigned ConstructKind) { bool Elidable = false; // C++0x [class.copy]p34: @@ -5309,6 +5444,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, if (Constructor->isCopyConstructor() && ExprArgs.size() >= 1) { Expr *SubExpr = ((Expr **)ExprArgs.get())[0]; Elidable = SubExpr->isTemporaryObject() && + ConstructKind == CXXConstructExpr::CK_Complete && Context.hasSameUnqualifiedType(SubExpr->getType(), Context.getTypeDeclType(Constructor->getParent())); } @@ -5320,27 +5456,28 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, /// BuildCXXConstructExpr - Creates a complete call to a constructor, /// including handling of its default argument expressions. -Sema::OwningExprResult +ExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg ExprArgs, bool RequiresZeroInit, - CXXConstructExpr::ConstructionKind ConstructKind) { + unsigned ConstructKind) { unsigned NumExprs = ExprArgs.size(); Expr **Exprs = (Expr **)ExprArgs.release(); MarkDeclarationReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, Constructor, Elidable, Exprs, NumExprs, - RequiresZeroInit, ConstructKind)); + RequiresZeroInit, + static_cast(ConstructKind))); } bool Sema::InitializeVarWithConstructor(VarDecl *VD, CXXConstructorDecl *Constructor, MultiExprArg Exprs) { - OwningExprResult TempResult = + ExprResult TempResult = BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor, - move(Exprs)); + move(Exprs), false, CXXConstructExpr::CK_Complete); if (TempResult.isInvalid()) return true; @@ -5362,19 +5499,21 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { PDiag(diag::err_access_dtor_var) << VD->getDeclName() << VD->getType()); + + if (!VD->isInvalidDecl() && VD->hasGlobalStorage()) + Diag(VD->getLocation(), diag::warn_global_destructor); } } /// AddCXXDirectInitializerToDecl - This action is called immediately after /// ActOnDeclarator, when a C++ direct initializer is present. /// e.g: "int x(1);" -void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, +void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, SourceLocation LParenLoc, MultiExprArg Exprs, SourceLocation *CommaLocs, SourceLocation RParenLoc) { assert(Exprs.size() != 0 && Exprs.get() && "missing expressions"); - Decl *RealDecl = Dcl.getAs(); // If there is no declaration, there was an error parsing it. Just ignore // the initializer. @@ -5402,9 +5541,6 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, // The form of initialization (using parentheses or '=') is generally // insignificant, but does matter when the entity being initialized has a // class type. - QualType DeclInitType = VDecl->getType(); - if (const ArrayType *Array = Context.getAsArrayType(DeclInitType)) - DeclInitType = Context.getBaseElementType(Array); if (!VDecl->getType()->isDependentType() && RequireCompleteType(VDecl->getLocation(), VDecl->getType(), @@ -5428,6 +5564,25 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, return; } + // C++ [class.static.data]p4 + // If a static data member is of const integral or const + // enumeration type, its declaration in the class definition can + // specify a constant-initializer which shall be an integral + // constant expression (5.19). In that case, the member can appear + // in integral constant expressions. The member shall still be + // defined in a namespace scope if it is used in the program and the + // namespace scope definition shall not contain an initializer. + // + // We already performed a redefinition check above, but for static + // data members we also need to check whether there was an in-class + // declaration with an initializer. + const VarDecl* PrevInit = 0; + if (VDecl->isStaticDataMember() && VDecl->getAnyInitializer(PrevInit)) { + Diag(VDecl->getLocation(), diag::err_redefinition) << VDecl->getDeclName(); + Diag(PrevInit->getLocation(), diag::note_previous_definition); + return; + } + // If either the declaration has a dependent type or if any of the // expressions is type-dependent, we represent the initialization // via a ParenListExpr for later use during template instantiation. @@ -5454,17 +5609,25 @@ void Sema::AddCXXDirectInitializerToDecl(DeclPtrTy Dcl, LParenLoc, RParenLoc); InitializationSequence InitSeq(*this, Entity, Kind, - (Expr**)Exprs.get(), Exprs.size()); - OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(Exprs)); + Exprs.get(), Exprs.size()); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(Exprs)); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; } - Result = MaybeCreateCXXExprWithTemporaries(move(Result)); + Result = MaybeCreateCXXExprWithTemporaries(Result.get()); VDecl->setInit(Result.takeAs()); VDecl->setCXXDirectInitializer(true); + if (!VDecl->isInvalidDecl() && + !VDecl->getDeclContext()->isDependentContext() && + VDecl->hasGlobalStorage() && + !VDecl->getInit()->isConstantInitializer(Context, + VDecl->getType()->isReferenceType())) + Diag(VDecl->getLocation(), diag::warn_global_constructor) + << VDecl->getInit()->getSourceRange(); + if (const RecordType *Record = VDecl->getType()->getAs()) FinalizeVarWithDestructor(VDecl, Record); } @@ -5478,7 +5641,7 @@ bool Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, MultiExprArg ArgsPtr, SourceLocation Loc, - ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs) { + ASTOwningVector &ConvertedArgs) { // FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall. unsigned NumArgs = ArgsPtr.size(); Expr **Args = (Expr **)ArgsPtr.get(); @@ -5508,7 +5671,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, static inline bool CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef, const FunctionDecl *FnDecl) { - const DeclContext *DC = FnDecl->getDeclContext()->getLookupContext(); + const DeclContext *DC = FnDecl->getDeclContext()->getRedeclContext(); if (isa(DC)) { return SemaRef.Diag(FnDecl->getLocation(), diag::err_operator_new_delete_declared_in_namespace) @@ -5516,7 +5679,7 @@ CheckOperatorNewDeleteDeclarationScope(Sema &SemaRef, } if (isa(DC) && - FnDecl->getStorageClass() == FunctionDecl::Static) { + FnDecl->getStorageClass() == SC_Static) { return SemaRef.Diag(FnDecl->getLocation(), diag::err_operator_new_delete_declared_static) << FnDecl->getDeclName(); @@ -5622,18 +5785,6 @@ CheckOperatorDeleteDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) { diag::err_operator_delete_param_type)) return true; - QualType FirstParamType = FnDecl->getParamDecl(0)->getType(); - if (FirstParamType->isDependentType()) - return SemaRef.Diag(FnDecl->getLocation(), - diag::err_operator_delete_dependent_param_type) - << FnDecl->getDeclName() << SemaRef.Context.VoidPtrTy; - - if (SemaRef.Context.getCanonicalType(FirstParamType) != - SemaRef.Context.VoidPtrTy) - return SemaRef.Diag(FnDecl->getLocation(), - diag::err_operator_delete_param_type) - << FnDecl->getDeclName() << SemaRef.Context.VoidPtrTy; - return false; } @@ -5891,7 +6042,7 @@ FinishedParams: /// by Lang/StrSize. LBraceLoc, if valid, provides the location of /// the '{' brace. Otherwise, this linkage specification does not /// have any braces. -Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S, +Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, SourceLocation LangLoc, llvm::StringRef Lang, @@ -5903,7 +6054,7 @@ Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S, Language = LinkageSpecDecl::lang_cxx; else { Diag(LangLoc, diag::err_bad_language); - return DeclPtrTy(); + return 0; } // FIXME: Add all the various semantics of linkage specifications @@ -5913,15 +6064,15 @@ Sema::DeclPtrTy Sema::ActOnStartLinkageSpecification(Scope *S, LBraceLoc.isValid()); CurContext->addDecl(D); PushDeclContext(S, D); - return DeclPtrTy::make(D); + return D; } -/// ActOnFinishLinkageSpecification - Completely the definition of +/// ActOnFinishLinkageSpecification - Complete the definition of /// the C++ linkage specification LinkageSpec. If RBraceLoc is /// valid, it's the position of the closing '}' brace in a linkage /// specification that uses braces. -Sema::DeclPtrTy Sema::ActOnFinishLinkageSpecification(Scope *S, - DeclPtrTy LinkageSpec, +Decl *Sema::ActOnFinishLinkageSpecification(Scope *S, + Decl *LinkageSpec, SourceLocation RBraceLoc) { if (LinkageSpec) PopDeclContext(); @@ -5983,9 +6134,30 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, AbstractVariableType)) Invalid = true; + // Only the non-fragile NeXT runtime currently supports C++ catches + // of ObjC types, and no runtime supports catching ObjC types by value. + if (!Invalid && getLangOptions().ObjC1) { + QualType T = ExDeclType; + if (const ReferenceType *RT = T->getAs()) + T = RT->getPointeeType(); + + if (T->isObjCObjectType()) { + Diag(Loc, diag::err_objc_object_catch); + Invalid = true; + } else if (T->isObjCObjectPointerType()) { + if (!getLangOptions().NeXTRuntime) { + Diag(Loc, diag::err_objc_pointer_cxx_catch_gnu); + Invalid = true; + } else if (!getLangOptions().ObjCNonFragileABI) { + Diag(Loc, diag::err_objc_pointer_cxx_catch_fragile); + Invalid = true; + } + } + } + VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc, - Name, ExDeclType, TInfo, VarDecl::None, - VarDecl::None); + Name, ExDeclType, TInfo, SC_None, + SC_None); ExDecl->setExceptionVariable(true); if (!Invalid) { @@ -6005,8 +6177,8 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, InitializationKind Kind = InitializationKind::CreateCopy(Loc, SourceLocation()); InitializationSequence InitSeq(*this, Entity, Kind, &ExDeclRef, 1); - OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, (void**)&ExDeclRef, 1)); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, &ExDeclRef, 1)); if (Result.isInvalid()) Invalid = true; else @@ -6022,7 +6194,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, /// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch /// handler. -Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { +Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType ExDeclType = TInfo->getType(); @@ -6033,7 +6205,7 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { ForRedeclaration)) { // The scope should be freshly made just for us. There is just no way // it contains any previous declaration. - assert(!S->isDeclScope(DeclPtrTy::make(PrevDecl))); + assert(!S->isDeclScope(PrevDecl)); if (PrevDecl->isTemplateParameter()) { // Maybe we will complain about the shadowed template parameter. DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); @@ -6061,22 +6233,20 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { CurContext->addDecl(ExDecl); ProcessDeclAttributes(S, ExDecl, D); - return DeclPtrTy::make(ExDecl); + return ExDecl; } -Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, - ExprArg assertexpr, - ExprArg assertmessageexpr) { - Expr *AssertExpr = (Expr *)assertexpr.get(); - StringLiteral *AssertMessage = - cast((Expr *)assertmessageexpr.get()); +Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, + Expr *AssertExpr, + Expr *AssertMessageExpr_) { + StringLiteral *AssertMessage = cast(AssertMessageExpr_); if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) { llvm::APSInt Value(32); if (!AssertExpr->isIntegerConstantExpr(Value, Context)) { Diag(AssertLoc, diag::err_static_assert_expression_is_not_constant) << AssertExpr->getSourceRange(); - return DeclPtrTy(); + return 0; } if (Value == 0) { @@ -6085,13 +6255,11 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, } } - assertexpr.release(); - assertmessageexpr.release(); Decl *Decl = StaticAssertDecl::Create(Context, CurContext, AssertLoc, AssertExpr, AssertMessage); CurContext->addDecl(Decl); - return DeclPtrTy::make(Decl); + return Decl; } /// \brief Perform semantic analysis of the given friend type declaration. @@ -6167,7 +6335,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation FriendLoc, /// We permit this as a special case; if there are any template /// parameters present at all, require proper matching, i.e. /// template <> template friend class A::B; -Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, +Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, MultiTemplateParamsArg TempParams) { SourceLocation Loc = DS.getSourceRange().getBegin(); @@ -6181,7 +6349,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, TypeSourceInfo *TSI = GetTypeForDeclarator(TheDeclarator, S); QualType T = TSI->getType(); if (TheDeclarator.isInvalidType()) - return DeclPtrTy(); + return 0; // This is definitely an error in C++98. It's probably meant to // be forbidden in C++0x, too, but the specification is just @@ -6200,7 +6368,7 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, if (TempParams.size() && !T->isElaboratedTypeSpecifier()) { Diag(Loc, diag::err_tagless_friend_type_template) << DS.getSourceRange(); - return DeclPtrTy(); + return 0; } // C++98 [class.friend]p1: A friend of a class is a function @@ -6225,18 +6393,17 @@ Sema::DeclPtrTy Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, D = CheckFriendTypeDecl(DS.getFriendSpecLoc(), TSI); if (!D) - return DeclPtrTy(); + return 0; D->setAccess(AS_public); CurContext->addDecl(D); - return DeclPtrTy::make(D); + return D; } -Sema::DeclPtrTy -Sema::ActOnFriendFunctionDecl(Scope *S, - Declarator &D, - bool IsDefinition, +Decl *Sema::ActOnFriendFunctionDecl(Scope *S, + Declarator &D, + bool IsDefinition, MultiTemplateParamsArg TemplateParams) { const DeclSpec &DS = D.getDeclSpec(); @@ -6262,7 +6429,7 @@ Sema::ActOnFriendFunctionDecl(Scope *S, // It might be worthwhile to try to recover by creating an // appropriate declaration. - return DeclPtrTy(); + return 0; } // C++ [namespace.memdef]p3 @@ -6281,7 +6448,8 @@ Sema::ActOnFriendFunctionDecl(Scope *S, // namespace scope are not considered. CXXScopeSpec &ScopeQual = D.getCXXScopeSpec(); - DeclarationName Name = GetNameForDeclarator(D); + DeclarationNameInfo NameInfo = GetNameForDeclarator(D); + DeclarationName Name = NameInfo.getName(); assert(Name); // The context we found the declaration in, or in which we should @@ -6291,14 +6459,14 @@ Sema::ActOnFriendFunctionDecl(Scope *S, // FIXME: handle local classes // Recover from invalid scope qualifiers as if they just weren't there. - LookupResult Previous(*this, Name, D.getIdentifierLoc(), LookupOrdinaryName, + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); if (!ScopeQual.isInvalid() && ScopeQual.isSet()) { DC = computeDeclContext(ScopeQual); // FIXME: handle dependent contexts - if (!DC) return DeclPtrTy(); - if (RequireCompleteDeclContext(ScopeQual, DC)) return DeclPtrTy(); + if (!DC) return 0; + if (RequireCompleteDeclContext(ScopeQual, DC)) return 0; LookupQualifiedName(Previous, DC); @@ -6308,7 +6476,8 @@ Sema::ActOnFriendFunctionDecl(Scope *S, LookupResult::Filter F = Previous.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); - if (!D->getDeclContext()->getLookupContext()->Equals(DC)) + if (!DC->InEnclosingNamespaceSetOf( + D->getDeclContext()->getRedeclContext())) F.erase(); } F.done(); @@ -6316,7 +6485,7 @@ Sema::ActOnFriendFunctionDecl(Scope *S, if (Previous.empty()) { D.setInvalidType(); Diag(Loc, diag::err_qualified_friend_not_found) << Name << T; - return DeclPtrTy(); + return 0; } // C++ [class.friend]p1: A friend of a class is a function or @@ -6368,7 +6537,7 @@ Sema::ActOnFriendFunctionDecl(Scope *S, Diag(Loc, diag::err_introducing_special_friend) << (D.getName().getKind() == UnqualifiedId::IK_ConstructorName ? 0 : D.getName().getKind() == UnqualifiedId::IK_DestructorName ? 1 : 2); - return DeclPtrTy(); + return 0; } } @@ -6377,7 +6546,7 @@ Sema::ActOnFriendFunctionDecl(Scope *S, move(TemplateParams), IsDefinition, Redeclaration); - if (!ND) return DeclPtrTy(); + if (!ND) return 0; assert(ND->getDeclContext() == DC); assert(ND->getLexicalDeclContext() == CurContext); @@ -6389,7 +6558,7 @@ Sema::ActOnFriendFunctionDecl(Scope *S, // Also update the scope-based lookup if the target context's // lookup context is in lexical scope. if (!CurContext->isDependentContext()) { - DC = DC->getLookupContext(); + DC = DC->getRedeclContext(); DC->makeDeclVisibleInContext(ND, /* Recoverable=*/ false); if (Scope *EnclosingScope = getScopeForDeclContext(S, DC)) PushOnScopeChains(ND, EnclosingScope, /*AddToContext=*/ false); @@ -6401,13 +6570,12 @@ Sema::ActOnFriendFunctionDecl(Scope *S, FrD->setAccess(AS_public); CurContext->addDecl(FrD); - return DeclPtrTy::make(ND); + return ND; } -void Sema::SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc) { - AdjustDeclIfTemplate(dcl); +void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { + AdjustDeclIfTemplate(Dcl); - Decl *Dcl = dcl.getAs(); FunctionDecl *Fn = dyn_cast(Dcl); if (!Fn) { Diag(DelLoc, diag::err_deleted_non_function); @@ -6575,9 +6743,8 @@ bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) { /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a /// static data member of class X, names should be looked up in the scope of /// class X. -void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) { +void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) { // If there is no declaration, there was an error parsing it. - Decl *D = Dcl.getAs(); if (D == 0) return; // We should only get called for declarations with scope specifiers, like: @@ -6587,10 +6754,9 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, DeclPtrTy Dcl) { } /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an -/// initializer for the out-of-line declaration 'Dcl'. -void Sema::ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl) { +/// initializer for the out-of-line declaration 'D'. +void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) { // If there is no declaration, there was an error parsing it. - Decl *D = Dcl.getAs(); if (D == 0) return; assert(D->isOutOfLine()); @@ -6600,8 +6766,7 @@ void Sema::ActOnCXXExitDeclInitializer(Scope *S, DeclPtrTy Dcl) { /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a /// C++ if/switch/while/for statement. /// e.g: "if (int x = f()) {...}" -Action::DeclResult -Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { +DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { // C++ 6.4p2: // The declarator shall not specify a function or an array. // The type-specifier-seq shall not contain typedef and shall not declare a @@ -6624,12 +6789,10 @@ Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { Diag(OwnedTag->getLocation(), diag::err_type_defined_in_condition); } - DeclPtrTy Dcl = ActOnDeclarator(S, D); + Decl *Dcl = ActOnDeclarator(S, D); if (!Dcl) return DeclResult(); - VarDecl *VD = cast(Dcl.getAs()); - VD->setDeclaredInCondition(true); return Dcl; } @@ -6775,8 +6938,6 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, e = RD->bases_end(); i != e; ++i) { const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); - if (i->isVirtual()) - continue; if (Base->getNumVBases() == 0) continue; MarkVirtualMembersReferenced(Loc, Base); @@ -6788,7 +6949,7 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { if (!getLangOptions().CPlusPlus) return; - if (const ObjCInterfaceDecl *OID = ObjCImplementation->getClassInterface()) { + if (ObjCInterfaceDecl *OID = ObjCImplementation->getClassInterface()) { llvm::SmallVector ivars; CollectIvarsToConstructOrDestruct(OID, ivars); if (ivars.empty()) @@ -6805,10 +6966,9 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { InitializationKind::CreateDefault(ObjCImplementation->getLocation()); InitializationSequence InitSeq(*this, InitEntity, InitKind, 0, 0); - Sema::OwningExprResult MemberInit = - InitSeq.Perform(*this, InitEntity, InitKind, - Sema::MultiExprArg(*this, 0, 0)); - MemberInit = MaybeCreateCXXExprWithTemporaries(move(MemberInit)); + ExprResult MemberInit = + InitSeq.Perform(*this, InitEntity, InitKind, MultiExprArg()); + MemberInit = MaybeCreateCXXExprWithTemporaries(MemberInit.get()); // Note, MemberInit could actually come back empty if no initialization // is required (e.g., because it would call a trivial default constructor) if (!MemberInit.get() || MemberInit.isInvalid()) diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 21aeb59..a6902a3 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -11,20 +11,24 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "Lookup.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/AST/Expr.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" -#include "clang/Parse/DeclSpec.h" +#include "clang/Sema/DeclSpec.h" +#include "llvm/ADT/DenseSet.h" + using namespace clang; /// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible /// and user declared, in the method definition's AST. -void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { +void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { assert(getCurMethodDecl() == 0 && "Method parsing confused"); - ObjCMethodDecl *MDecl = dyn_cast_or_null(D.getAs()); + ObjCMethodDecl *MDecl = dyn_cast_or_null(D); // If we don't have a valid method decl, simply return. if (!MDecl) @@ -32,10 +36,10 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { // Allow the rest of sema to find private method decl implementations. if (MDecl->isInstanceMethod()) - AddInstanceMethodToGlobalPool(MDecl); + AddInstanceMethodToGlobalPool(MDecl, true); else - AddFactoryMethodToGlobalPool(MDecl); - + AddFactoryMethodToGlobalPool(MDecl, true); + // Allow all of Sema to see that we are entering a method definition. PushDeclContext(FnBodyScope, MDecl); PushFunctionScope(); @@ -56,11 +60,11 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, DeclPtrTy D) { PushOnScopeChains(*PI, FnBodyScope); } -Sema::DeclPtrTy Sema:: +Decl *Sema:: ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperName, SourceLocation SuperLoc, - const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs, + Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList) { assert(ClassName && "Missing class identifier"); @@ -84,11 +88,14 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, // Return the previous class interface. // FIXME: don't leak the objects passed in! - return DeclPtrTy::make(IDecl); + return IDecl; } else { IDecl->setLocation(AtInterfaceLoc); IDecl->setForwardDecl(false); IDecl->setClassLoc(ClassLoc); + // If the forward decl was in a PCH, we need to write it again in a + // dependent AST file. + IDecl->setChangedSinceDeserialization(true); // Since this ObjCInterfaceDecl was created by a forward declaration, // we now add it to the DeclContext since it wasn't added before @@ -176,7 +183,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IDecl->setLocEnd(ClassLoc); } - /// Check then save referenced protocols. + // Check then save referenced protocols. if (NumProtoRefs) { IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, ProtoLocs, Context); @@ -184,16 +191,16 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, } CheckObjCDeclScope(IDecl); - return DeclPtrTy::make(IDecl); + return IDecl; } /// ActOnCompatiblityAlias - this action is called after complete parsing of /// @compatibility_alias declaration. It sets up the alias relationships. -Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, - IdentifierInfo *AliasName, - SourceLocation AliasLocation, - IdentifierInfo *ClassName, - SourceLocation ClassLocation) { +Decl *Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, + IdentifierInfo *AliasName, + SourceLocation AliasLocation, + IdentifierInfo *ClassName, + SourceLocation ClassLocation) { // Look for previous declaration of alias name NamedDecl *ADecl = LookupSingleName(TUScope, AliasName, AliasLocation, LookupOrdinaryName, ForRedeclaration); @@ -203,7 +210,7 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, else Diag(AliasLocation, diag::err_conflicting_aliasing_type) << AliasName; Diag(ADecl->getLocation(), diag::note_previous_declaration); - return DeclPtrTy(); + return 0; } // Check for class declaration NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, @@ -223,7 +230,7 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, Diag(ClassLocation, diag::warn_undef_interface) << ClassName; if (CDeclU) Diag(CDeclU->getLocation(), diag::note_previous_declaration); - return DeclPtrTy(); + return 0; } // Everything checked out, instantiate a new alias declaration AST. @@ -233,7 +240,7 @@ Sema::DeclPtrTy Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, if (!CheckObjCDeclScope(AliasDecl)) PushOnScopeChains(AliasDecl, TUScope); - return DeclPtrTy::make(AliasDecl); + return AliasDecl; } void Sema::CheckForwardProtocolDeclarationForCircularDependency( @@ -255,11 +262,11 @@ void Sema::CheckForwardProtocolDeclarationForCircularDependency( } } -Sema::DeclPtrTy +Decl * Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, - const DeclPtrTy *ProtoRefs, + Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, @@ -274,17 +281,19 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, Diag(PDecl->getLocation(), diag::note_previous_definition); // Just return the protocol we already had. // FIXME: don't leak the objects passed in! - return DeclPtrTy::make(PDecl); + return PDecl; } ObjCList PList; PList.set((ObjCProtocolDecl *const*)ProtoRefs, NumProtoRefs, Context); CheckForwardProtocolDeclarationForCircularDependency( ProtocolName, ProtocolLoc, PDecl->getLocation(), PList); - PList.Destroy(Context); // Make sure the cached decl gets a valid start location. PDecl->setLocation(AtProtoInterfaceLoc); PDecl->setForwardDecl(false); + CurContext->addDecl(PDecl); + // Repeat in dependent AST files. + PDecl->setChangedSinceDeserialization(true); } else { PDecl = ObjCProtocolDecl::Create(Context, CurContext, AtProtoInterfaceLoc,ProtocolName); @@ -301,7 +310,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, } CheckObjCDeclScope(PDecl); - return DeclPtrTy::make(PDecl); + return PDecl; } /// FindProtocolDeclaration - This routine looks up protocols and @@ -311,7 +320,7 @@ void Sema::FindProtocolDeclaration(bool WarnOnDeclarations, const IdentifierLocPair *ProtocolId, unsigned NumProtocols, - llvm::SmallVectorImpl &Protocols) { + llvm::SmallVectorImpl &Protocols) { for (unsigned i = 0; i != NumProtocols; ++i) { ObjCProtocolDecl *PDecl = LookupProtocol(ProtocolId[i].first, ProtocolId[i].second); @@ -340,7 +349,7 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations, if (WarnOnDeclarations && PDecl->isForwardDecl()) Diag(ProtocolId[i].second, diag::warn_undef_protocolref) << ProtocolId[i].first; - Protocols.push_back(DeclPtrTy::make(PDecl)); + Protocols.push_back(PDecl); } } @@ -374,7 +383,7 @@ void Sema::DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, } /// ActOnForwardProtocolDeclaration - Handle @protocol foo; -Action::DeclPtrTy +Decl * Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, const IdentifierLocPair *IdentList, unsigned NumElts, @@ -385,13 +394,18 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, for (unsigned i = 0; i != NumElts; ++i) { IdentifierInfo *Ident = IdentList[i].first; ObjCProtocolDecl *PDecl = LookupProtocol(Ident, IdentList[i].second); + bool isNew = false; if (PDecl == 0) { // Not already seen? PDecl = ObjCProtocolDecl::Create(Context, CurContext, IdentList[i].second, Ident); - PushOnScopeChains(PDecl, TUScope); + PushOnScopeChains(PDecl, TUScope, false); + isNew = true; } - if (attrList) + if (attrList) { ProcessDeclAttributeList(TUScope, PDecl, attrList); + if (!isNew) + PDecl->setChangedSinceDeserialization(true); + } Protocols.push_back(PDecl); ProtoLocs.push_back(IdentList[i].second); } @@ -402,15 +416,15 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, ProtoLocs.data()); CurContext->addDecl(PDecl); CheckObjCDeclScope(PDecl); - return DeclPtrTy::make(PDecl); + return PDecl; } -Sema::DeclPtrTy Sema:: +Decl *Sema:: ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CategoryName, SourceLocation CategoryLoc, - const DeclPtrTy *ProtoRefs, + Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc) { @@ -426,7 +440,7 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, ClassLoc, CategoryLoc, CategoryName); CDecl->setInvalidDecl(); Diag(ClassLoc, diag::err_undef_interface) << ClassName; - return DeclPtrTy::make(CDecl); + return CDecl; } if (!CategoryName && IDecl->getImplementation()) { @@ -471,18 +485,17 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, // Protocols in the class extension belong to the class. if (CDecl->IsClassExtension()) IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs, - NumProtoRefs, ProtoLocs, - Context); + NumProtoRefs, Context); } CheckObjCDeclScope(CDecl); - return DeclPtrTy::make(CDecl); + return CDecl; } /// ActOnStartCategoryImplementation - Perform semantic checks on the /// category implementation declaration and build an ObjCCategoryImplDecl /// object. -Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( +Decl *Sema::ActOnStartCategoryImplementation( SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc) { @@ -523,10 +536,10 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation( } CheckObjCDeclScope(CDecl); - return DeclPtrTy::make(CDecl); + return CDecl; } -Sema::DeclPtrTy Sema::ActOnStartClassImplementation( +Decl *Sema::ActOnStartClassImplementation( SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperClassname, @@ -617,7 +630,7 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( IDecl, SDecl); if (CheckObjCDeclScope(IMPDecl)) - return DeclPtrTy::make(IMPDecl); + return IMPDecl; // Check that there is no duplicate implementation of this class. if (IDecl->getImplementation()) { @@ -629,7 +642,7 @@ Sema::DeclPtrTy Sema::ActOnStartClassImplementation( IDecl->setImplementation(IMPDecl); PushOnScopeChains(IMPDecl, TUScope); } - return DeclPtrTy::make(IMPDecl); + return IMPDecl; } void Sema::CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, @@ -910,8 +923,9 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet &InsMap, } if (ObjCInterfaceDecl *I = dyn_cast (CDecl)) { // Check for any implementation of a methods declared in protocol. - for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(), - E = I->protocol_end(); PI != E; ++PI) + for (ObjCInterfaceDecl::all_protocol_iterator + PI = I->all_referenced_protocol_begin(), + E = I->all_referenced_protocol_end(); PI != E; ++PI) MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, IMPDecl, (*PI), IncompleteImpl, false); @@ -957,8 +971,9 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, // implemented in the implementation class. if (ObjCInterfaceDecl *I = dyn_cast (CDecl)) { - for (ObjCInterfaceDecl::protocol_iterator PI = I->protocol_begin(), - E = I->protocol_end(); PI != E; ++PI) + for (ObjCInterfaceDecl::all_protocol_iterator + PI = I->all_referenced_protocol_begin(), + E = I->all_referenced_protocol_end(); PI != E; ++PI) CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl, InsMap, ClsMap, I); // Check class extensions (unnamed categories) @@ -992,7 +1007,7 @@ void Sema::ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, } /// ActOnForwardClassDeclaration - -Action::DeclPtrTy +Decl * Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, IdentifierInfo **IdentList, SourceLocation *IdentLocs, @@ -1053,7 +1068,7 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, Interfaces.size()); CurContext->addDecl(CDecl); CheckObjCDeclScope(CDecl); - return DeclPtrTy::make(CDecl); + return CDecl; } @@ -1062,13 +1077,14 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, /// TODO: Handle protocol list; such as id in type comparisons bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, const ObjCMethodDecl *PrevMethod, - bool matchBasedOnSizeAndAlignment) { + bool matchBasedOnSizeAndAlignment, + bool matchBasedOnStrictEqulity) { QualType T1 = Context.getCanonicalType(Method->getResultType()); QualType T2 = Context.getCanonicalType(PrevMethod->getResultType()); if (T1 != T2) { // The result types are different. - if (!matchBasedOnSizeAndAlignment) + if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity) return false; // Incomplete types don't have a size and alignment. if (T1->isIncompleteType() || T2->isIncompleteType()) @@ -1088,7 +1104,7 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, T2 = Context.getCanonicalType((*PrevI)->getType()); if (T1 != T2) { // The result types are different. - if (!matchBasedOnSizeAndAlignment) + if (!matchBasedOnSizeAndAlignment || matchBasedOnStrictEqulity) return false; // Incomplete types don't have a size and alignment. if (T1->isIncompleteType() || T2->isIncompleteType()) @@ -1101,47 +1117,34 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, return true; } -/// \brief Read the contents of the instance and factory method pools -/// for a given selector from external storage. +/// \brief Read the contents of the method pool for a given selector from +/// external storage. /// -/// This routine should only be called once, when neither the instance -/// nor the factory method pool has an entry for this selector. -Sema::MethodPool::iterator Sema::ReadMethodPool(Selector Sel, - bool isInstance) { +/// This routine should only be called once, when the method pool has no entry +/// for this selector. +Sema::GlobalMethodPool::iterator Sema::ReadMethodPool(Selector Sel) { assert(ExternalSource && "We need an external AST source"); - assert(InstanceMethodPool.find(Sel) == InstanceMethodPool.end() && - "Selector data already loaded into the instance method pool"); - assert(FactoryMethodPool.find(Sel) == FactoryMethodPool.end() && - "Selector data already loaded into the factory method pool"); + assert(MethodPool.find(Sel) == MethodPool.end() && + "Selector data already loaded into the method pool"); // Read the method list from the external source. - std::pair Methods - = ExternalSource->ReadMethodPool(Sel); + GlobalMethods Methods = ExternalSource->ReadMethodPool(Sel); - if (isInstance) { - if (Methods.second.Method) - FactoryMethodPool[Sel] = Methods.second; - return InstanceMethodPool.insert(std::make_pair(Sel, Methods.first)).first; - } - - if (Methods.first.Method) - InstanceMethodPool[Sel] = Methods.first; - - return FactoryMethodPool.insert(std::make_pair(Sel, Methods.second)).first; + return MethodPool.insert(std::make_pair(Sel, Methods)).first; } -void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) { - llvm::DenseMap::iterator Pos - = InstanceMethodPool.find(Method->getSelector()); - if (Pos == InstanceMethodPool.end()) { - if (ExternalSource && !FactoryMethodPool.count(Method->getSelector())) - Pos = ReadMethodPool(Method->getSelector(), /*isInstance=*/true); +void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, + bool instance) { + GlobalMethodPool::iterator Pos = MethodPool.find(Method->getSelector()); + if (Pos == MethodPool.end()) { + if (ExternalSource) + Pos = ReadMethodPool(Method->getSelector()); else - Pos = InstanceMethodPool.insert(std::make_pair(Method->getSelector(), - ObjCMethodList())).first; + Pos = MethodPool.insert(std::make_pair(Method->getSelector(), + GlobalMethods())).first; } - - ObjCMethodList &Entry = Pos->second; + Method->setDefined(impl); + ObjCMethodList &Entry = instance ? Pos->second.first : Pos->second.second; if (Entry.Method == 0) { // Haven't seen a method with this selector name yet - add it. Entry.Method = Method; @@ -1152,8 +1155,10 @@ void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) { // We've seen a method with this name, see if we have already seen this type // signature. for (ObjCMethodList *List = &Entry; List; List = List->Next) - if (MatchTwoMethodDeclarations(Method, List->Method)) + if (MatchTwoMethodDeclarations(Method, List->Method)) { + List->Method->setDefined(impl); return; + } // We have a new signature for an existing method - add it. // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". @@ -1161,102 +1166,65 @@ void Sema::AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method) { Entry.Next = new (Mem) ObjCMethodList(Method, Entry.Next); } -// FIXME: Finish implementing -Wno-strict-selector-match. -ObjCMethodDecl *Sema::LookupInstanceMethodInGlobalPool(Selector Sel, - SourceRange R, - bool warn) { - llvm::DenseMap::iterator Pos - = InstanceMethodPool.find(Sel); - if (Pos == InstanceMethodPool.end()) { - if (ExternalSource && !FactoryMethodPool.count(Sel)) - Pos = ReadMethodPool(Sel, /*isInstance=*/true); +ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, + bool receiverIdOrClass, + bool warn, bool instance) { + GlobalMethodPool::iterator Pos = MethodPool.find(Sel); + if (Pos == MethodPool.end()) { + if (ExternalSource) + Pos = ReadMethodPool(Sel); else return 0; } - ObjCMethodList &MethList = Pos->second; - bool issueWarning = false; + ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; - if (MethList.Method && MethList.Next) { - for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) - // This checks if the methods differ by size & alignment. - if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true)) - issueWarning = warn; - } - if (issueWarning && (MethList.Method && MethList.Next)) { - Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; - Diag(MethList.Method->getLocStart(), diag::note_using) - << MethList.Method->getSourceRange(); - for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) - Diag(Next->Method->getLocStart(), diag::note_also_found) - << Next->Method->getSourceRange(); - } - return MethList.Method; -} + bool strictSelectorMatch = receiverIdOrClass && warn && + (Diags.getDiagnosticLevel(diag::warn_strict_multiple_method_decl) != + Diagnostic::Ignored); + if (warn && MethList.Method && MethList.Next) { + bool issueWarning = false; + if (strictSelectorMatch) + for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) { + // This checks if the methods differ in type mismatch. + if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, false, true)) + issueWarning = true; + } -void Sema::AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method) { - llvm::DenseMap::iterator Pos - = FactoryMethodPool.find(Method->getSelector()); - if (Pos == FactoryMethodPool.end()) { - if (ExternalSource && !InstanceMethodPool.count(Method->getSelector())) - Pos = ReadMethodPool(Method->getSelector(), /*isInstance=*/false); - else - Pos = FactoryMethodPool.insert(std::make_pair(Method->getSelector(), - ObjCMethodList())).first; - } + if (!issueWarning) + for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) { + // This checks if the methods differ by size & alignment. + if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true)) + issueWarning = true; + } - ObjCMethodList &FirstMethod = Pos->second; - if (!FirstMethod.Method) { - // Haven't seen a method with this selector name yet - add it. - FirstMethod.Method = Method; - FirstMethod.Next = 0; - } else { - // We've seen a method with this name, now check the type signature(s). - bool match = MatchTwoMethodDeclarations(Method, FirstMethod.Method); - - for (ObjCMethodList *Next = FirstMethod.Next; !match && Next; - Next = Next->Next) - match = MatchTwoMethodDeclarations(Method, Next->Method); - - if (!match) { - // We have a new signature for an existing method - add it. - // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". - ObjCMethodList *Mem = BumpAlloc.Allocate(); - ObjCMethodList *OMI = new (Mem) ObjCMethodList(Method, FirstMethod.Next); - FirstMethod.Next = OMI; + if (issueWarning) { + if (strictSelectorMatch) + Diag(R.getBegin(), diag::warn_strict_multiple_method_decl) << Sel << R; + else + Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; + Diag(MethList.Method->getLocStart(), diag::note_using) + << MethList.Method->getSourceRange(); + for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) + Diag(Next->Method->getLocStart(), diag::note_also_found) + << Next->Method->getSourceRange(); } } + return MethList.Method; } -ObjCMethodDecl *Sema::LookupFactoryMethodInGlobalPool(Selector Sel, - SourceRange R) { - llvm::DenseMap::iterator Pos - = FactoryMethodPool.find(Sel); - if (Pos == FactoryMethodPool.end()) { - if (ExternalSource && !InstanceMethodPool.count(Sel)) - Pos = ReadMethodPool(Sel, /*isInstance=*/false); - else - return 0; - } +ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) { + GlobalMethodPool::iterator Pos = MethodPool.find(Sel); + if (Pos == MethodPool.end()) + return 0; - ObjCMethodList &MethList = Pos->second; - bool issueWarning = false; + GlobalMethods &Methods = Pos->second; - if (MethList.Method && MethList.Next) { - for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) - // This checks if the methods differ by size & alignment. - if (!MatchTwoMethodDeclarations(MethList.Method, Next->Method, true)) - issueWarning = true; - } - if (issueWarning && (MethList.Method && MethList.Next)) { - Diag(R.getBegin(), diag::warn_multiple_method_decl) << Sel << R; - Diag(MethList.Method->getLocStart(), diag::note_using) - << MethList.Method->getSourceRange(); - for (ObjCMethodList *Next = MethList.Next; Next; Next = Next->Next) - Diag(Next->Method->getLocStart(), diag::note_also_found) - << Next->Method->getSourceRange(); - } - return MethList.Method; + if (Methods.first.Method && Methods.first.Method->isDefined()) + return Methods.first.Method; + if (Methods.second.Method && Methods.second.Method->isDefined()) + return Methods.second.Method; + return 0; } /// CompareMethodParamsInBaseAndSuper - This routine compares methods with @@ -1322,12 +1290,10 @@ void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, // Note: For class/category implemenations, allMethods/allProperties is // always null. void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, - DeclPtrTy classDecl, - DeclPtrTy *allMethods, unsigned allNum, - DeclPtrTy *allProperties, unsigned pNum, + Decl *ClassDecl, + Decl **allMethods, unsigned allNum, + Decl **allProperties, unsigned pNum, DeclGroupPtrTy *allTUVars, unsigned tuvNum) { - Decl *ClassDecl = classDecl.getAs(); - // FIXME: If we don't have a ClassDecl, we have an error. We should consider // always passing in a decl. If the decl has an error, isInvalidDecl() // should be true. @@ -1356,7 +1322,7 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, for (unsigned i = 0; i < allNum; i++ ) { ObjCMethodDecl *Method = - cast_or_null(allMethods[i].getAs()); + cast_or_null(allMethods[i]); if (!Method) continue; // Already issued a diagnostic. if (Method->isInstanceMethod()) { @@ -1403,14 +1369,14 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, // Compares properties declared in this class to those of its // super class. ComparePropertiesInBaseAndSuper(I); - CompareProperties(I, DeclPtrTy::make(I)); + CompareProperties(I, I); } else if (ObjCCategoryDecl *C = dyn_cast(ClassDecl)) { // Categories are used to extend the class by declaring new methods. // By the same token, they are also used to add new properties. No // need to compare the added property to those in the class. // Compare protocol properties with those in category - CompareProperties(C, DeclPtrTy::make(C)); + CompareProperties(C, C); if (C->IsClassExtension()) DiagnoseClassExtensionDupMethods(C, C->getClassInterface()); } @@ -1432,6 +1398,7 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, DefaultSynthesizeProperties(S, IC, IDecl); ImplMethodsVsClassMethods(S, IC, IDecl); AtomicPropertySetterGetterRules(IC, IDecl); + if (LangOpts.ObjCNonFragileABI2) while (IDecl->getSuperClass()) { DiagnoseDuplicateIvars(IDecl, IDecl->getSuperClass()); @@ -1491,19 +1458,20 @@ CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) { } static inline -bool containsInvalidMethodImplAttribute(const AttributeList *A) { +bool containsInvalidMethodImplAttribute(const AttrVec &A) { // The 'ibaction' attribute is allowed on method definitions because of // how the IBAction macro is used on both method declarations and definitions. // If the method definitions contains any other attributes, return true. - while (A && A->getKind() == AttributeList::AT_IBAction) - A = A->getNext(); - return A != NULL; + for (AttrVec::const_iterator i = A.begin(), e = A.end(); i != e; ++i) + if ((*i)->getKind() != attr::IBAction) + return true; + return false; } -Sema::DeclPtrTy Sema::ActOnMethodDeclaration( +Decl *Sema::ActOnMethodDeclaration( SourceLocation MethodLoc, SourceLocation EndLoc, - tok::TokenKind MethodType, DeclPtrTy classDecl, - ObjCDeclSpec &ReturnQT, TypeTy *ReturnType, + tok::TokenKind MethodType, Decl *ClassDecl, + ObjCDeclSpec &ReturnQT, ParsedType ReturnType, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). @@ -1511,13 +1479,11 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind, bool isVariadic) { - Decl *ClassDecl = classDecl.getAs(); - // Make sure we can establish a context for the method. if (!ClassDecl) { Diag(MethodLoc, diag::error_missing_method_context); - getLabelMap().clear(); - return DeclPtrTy(); + getCurFunction()->LabelMap.clear(); + return 0; } QualType resultDeclType; @@ -1530,7 +1496,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( if (resultDeclType->isObjCObjectType()) { Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value) << 0 << resultDeclType; - return DeclPtrTy(); + return 0; } } else // get the type for "id". resultDeclType = Context.getObjCIdType(); @@ -1540,7 +1506,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( ResultTInfo, cast(ClassDecl), MethodType == tok::minus, isVariadic, - false, + false, false, MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional : ObjCMethodDecl::Required); @@ -1563,7 +1529,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( ParmVarDecl* Param = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc, ArgInfo[i].Name, ArgType, DI, - VarDecl::None, VarDecl::None, 0); + SC_None, SC_None, 0); if (ArgType->isObjCObjectType()) { Diag(ArgInfo[i].NameLoc, @@ -1582,7 +1548,7 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( } for (unsigned i = 0, e = CNumArgs; i != e; ++i) { - ParmVarDecl *Param = CParamInfo[i].Param.getAs(); + ParmVarDecl *Param = cast(CParamInfo[i].Param); QualType ArgType = Param->getType(); if (ArgType.isNull()) ArgType = Context.getObjCIdType(); @@ -1596,7 +1562,8 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( Param->setInvalidDecl(); } Param->setDeclContext(ObjCMethod); - IdResolver.RemoveDecl(Param); + if (Param->getDeclName()) + IdResolver.RemoveDecl(Param); Params.push_back(Param); } @@ -1626,7 +1593,8 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( } InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel, MethodType == tok::minus); - if (containsInvalidMethodImplAttribute(AttrList)) + if (ObjCMethod->hasAttrs() && + containsInvalidMethodImplAttribute(ObjCMethod->getAttrs())) Diag(EndLoc, diag::warn_attribute_method_def); } else if (ObjCCategoryImplDecl *CatImpDecl = dyn_cast(ClassDecl)) { @@ -1637,7 +1605,8 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( PrevMethod = CatImpDecl->getClassMethod(Sel); CatImpDecl->addClassMethod(ObjCMethod); } - if (containsInvalidMethodImplAttribute(AttrList)) + if (ObjCMethod->hasAttrs() && + containsInvalidMethodImplAttribute(ObjCMethod->getAttrs())) Diag(EndLoc, diag::warn_attribute_method_def); } if (PrevMethod) { @@ -1649,14 +1618,16 @@ Sema::DeclPtrTy Sema::ActOnMethodDeclaration( // If the interface declared this method, and it was deprecated there, // mark it deprecated here. - if (InterfaceMD && InterfaceMD->hasAttr()) - ObjCMethod->addAttr(::new (Context) DeprecatedAttr()); + if (InterfaceMD) + if (Attr *DA = InterfaceMD->getAttr()) + ObjCMethod->addAttr(::new (Context) DeprecatedAttr(DA->getLocation(), + Context)); - return DeclPtrTy::make(ObjCMethod); + return ObjCMethod; } bool Sema::CheckObjCDeclScope(Decl *D) { - if (isa(CurContext->getLookupContext())) + if (isa(CurContext->getRedeclContext())) return false; Diag(D->getLocation(), diag::err_objc_decls_may_only_appear_in_global_scope); @@ -1667,9 +1638,9 @@ bool Sema::CheckObjCDeclScope(Decl *D) { /// Called whenever @defs(ClassName) is encountered in the source. Inserts the /// instance variables of ClassName into Decls. -void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, +void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, - llvm::SmallVectorImpl &Decls) { + llvm::SmallVectorImpl &Decls) { // Check that ClassName is a valid class ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName, DeclStart); if (!Class) { @@ -1682,25 +1653,25 @@ void Sema::ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, } // Collect the instance variables - llvm::SmallVector RecFields; - Context.CollectObjCIvars(Class, RecFields); + llvm::SmallVector Ivars; + Context.DeepCollectObjCIvars(Class, true, Ivars); // For each ivar, create a fresh ObjCAtDefsFieldDecl. - for (unsigned i = 0; i < RecFields.size(); i++) { - FieldDecl* ID = RecFields[i]; - RecordDecl *Record = dyn_cast(TagD.getAs()); + for (unsigned i = 0; i < Ivars.size(); i++) { + FieldDecl* ID = cast(Ivars[i]); + RecordDecl *Record = dyn_cast(TagD); Decl *FD = ObjCAtDefsFieldDecl::Create(Context, Record, ID->getLocation(), ID->getIdentifier(), ID->getType(), ID->getBitWidth()); - Decls.push_back(Sema::DeclPtrTy::make(FD)); + Decls.push_back(FD); } // Introduce all of these fields into the appropriate scope. - for (llvm::SmallVectorImpl::iterator D = Decls.begin(); + for (llvm::SmallVectorImpl::iterator D = Decls.begin(); D != Decls.end(); ++D) { - FieldDecl *FD = cast(D->getAs()); + FieldDecl *FD = cast(*D); if (getLangOptions().CPlusPlus) PushOnScopeChains(cast(FD), S); - else if (RecordDecl *Record = dyn_cast(TagD.getAs())) + else if (RecordDecl *Record = dyn_cast(TagD)) Record->addDecl(FD); } } @@ -1735,7 +1706,7 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, } VarDecl *New = VarDecl::Create(Context, CurContext, NameLoc, Name, T, TInfo, - VarDecl::None, VarDecl::None); + SC_None, SC_None); New->setExceptionVariable(true); if (Invalid) @@ -1743,7 +1714,7 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, return New; } -Sema::DeclPtrTy Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { +Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { const DeclSpec &DS = D.getDeclSpec(); // We allow the "register" storage class on exception variables because @@ -1788,7 +1759,7 @@ Sema::DeclPtrTy Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { } // Add the parameter declaration into this scope. - S->AddDecl(DeclPtrTy::make(New)); + S->AddDecl(New); if (D.getIdentifier()) IdResolver.AddDecl(New); @@ -1796,43 +1767,18 @@ Sema::DeclPtrTy Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { if (New->hasAttr()) Diag(New->getLocation(), diag::err_block_on_nonlocal); - return DeclPtrTy::make(New); + return New; } /// CollectIvarsToConstructOrDestruct - Collect those ivars which require /// initialization. -void Sema::CollectIvarsToConstructOrDestruct(const ObjCInterfaceDecl *OI, +void Sema::CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI, llvm::SmallVectorImpl &Ivars) { - for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(), - E = OI->ivar_end(); I != E; ++I) { - ObjCIvarDecl *Iv = (*I); + for (ObjCIvarDecl *Iv = OI->all_declared_ivar_begin(); Iv; + Iv= Iv->getNextIvar()) { QualType QT = Context.getBaseElementType(Iv->getType()); if (QT->isRecordType()) - Ivars.push_back(*I); - } - - // Find ivars to construct/destruct in class extension. - for (const ObjCCategoryDecl *CDecl = OI->getFirstClassExtension(); CDecl; - CDecl = CDecl->getNextClassExtension()) { - for (ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), - E = CDecl->ivar_end(); I != E; ++I) { - ObjCIvarDecl *Iv = (*I); - QualType QT = Context.getBaseElementType(Iv->getType()); - if (QT->isRecordType()) - Ivars.push_back(*I); - } - } - - // Also add any ivar defined in this class's implementation. This - // includes synthesized ivars. - if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) { - for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(), - E = ImplDecl->ivar_end(); I != E; ++I) { - ObjCIvarDecl *Iv = (*I); - QualType QT = Context.getBaseElementType(Iv->getType()); - if (QT->isRecordType()) - Ivars.push_back(*I); - } + Ivars.push_back(Iv); } } @@ -1849,3 +1795,15 @@ void ObjCImplementationDecl::setIvarInitializers(ASTContext &C, } } +void Sema::DiagnoseUseOfUnimplementedSelectors() { + if (ReferencedSelectors.empty()) + return; + for (llvm::DenseMap::iterator S = + ReferencedSelectors.begin(), + E = ReferencedSelectors.end(); S != E; ++S) { + Selector Sel = (*S).first; + if (!LookupImplementedMethodInGlobalPool(Sel)) + Diag((*S).second, diag::warn_unimplemented_selector) << Sel; + } + return; +} diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 34a479a..c902e77 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" +#include "clang/Sema/SemaInternal.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -261,6 +261,14 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec(); bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec(); + if (getLangOptions().Microsoft) { + // Treat throw(whatever) as throw(...) to be compatible with MS headers. + if (New->hasExceptionSpec() && New->getNumExceptions() > 0) + NewAny = true; + if (Old->hasExceptionSpec() && Old->getNumExceptions() > 0) + OldAny = true; + } + if (OldAny && NewAny) return false; if (OldAny || NewAny) { diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 5f46a97..80b4652 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -11,10 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "SemaInit.h" -#include "Lookup.h" -#include "AnalysisBasedWarnings.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/AnalysisBasedWarnings.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" @@ -29,11 +29,14 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Designator.h" -#include "clang/Parse/Scope.h" -#include "clang/Parse/Template.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Designator.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/Template.h" using namespace clang; +using namespace sema; /// \brief Determine whether the use of this declaration is valid, and @@ -59,7 +62,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc) { // See if the decl is unavailable if (D->getAttr()) { - Diag(Loc, diag::warn_unavailable) << D->getDeclName(); + Diag(Loc, diag::err_unavailable) << D->getDeclName(); Diag(D->getLocation(), diag::note_unavailable_here) << 0; } @@ -192,7 +195,7 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) { if (Ty->isFunctionType()) ImpCastExprToType(E, Context.getPointerType(Ty), - CastExpr::CK_FunctionToPointerDecay); + CK_FunctionToPointerDecay); else if (Ty->isArrayType()) { // In C90 mode, arrays only promote to pointers if the array expression is // an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has @@ -208,7 +211,7 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) { if (getLangOptions().C99 || getLangOptions().CPlusPlus || E->isLvalue(Context) == Expr::LV_Valid) ImpCastExprToType(E, Context.getArrayDecayedType(Ty), - CastExpr::CK_ArrayToPointerDecay); + CK_ArrayToPointerDecay); } } @@ -229,7 +232,7 @@ void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) { // If the lvalue has qualified type, the value has the unqualified // version of the type of the lvalue; otherwise, the value has the // type of the lvalue. - ImpCastExprToType(E, Ty.getUnqualifiedType(), CastExpr::CK_NoOp); + ImpCastExprToType(E, Ty.getUnqualifiedType(), CK_NoOp); } } @@ -258,12 +261,12 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) { // other types are unchanged by the integer promotions. QualType PTy = Context.isPromotableBitField(Expr); if (!PTy.isNull()) { - ImpCastExprToType(Expr, PTy, CastExpr::CK_IntegralCast); + ImpCastExprToType(Expr, PTy, CK_IntegralCast); return Expr; } if (Ty->isPromotableIntegerType()) { QualType PT = Context.getPromotedIntegerType(Ty); - ImpCastExprToType(Expr, PT, CastExpr::CK_IntegralCast); + ImpCastExprToType(Expr, PT, CK_IntegralCast); return Expr; } @@ -281,7 +284,7 @@ void Sema::DefaultArgumentPromotion(Expr *&Expr) { // If this is a 'float' (CVR qualified or typedef) promote to double. if (Ty->isSpecificBuiltinType(BuiltinType::Float)) return ImpCastExprToType(Expr, Context.DoubleTy, - CastExpr::CK_FloatingCast); + CK_FloatingCast); UsualUnaryConversions(Expr); } @@ -355,8 +358,8 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, QualType destType = Context.UsualArithmeticConversionsType(lhs, rhs); if (!isCompAssign) - ImpCastExprToType(lhsExpr, destType, CastExpr::CK_Unknown); - ImpCastExprToType(rhsExpr, destType, CastExpr::CK_Unknown); + ImpCastExprToType(lhsExpr, destType, CK_Unknown); + ImpCastExprToType(rhsExpr, destType, CK_Unknown); return destType; } @@ -371,7 +374,7 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, /// multiple tokens. However, the common case is that StringToks points to one /// string. /// -Action::OwningExprResult +ExprResult Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { assert(NumStringToks && "Must have at least one string!"); @@ -459,13 +462,20 @@ static bool ShouldSnapshotBlockValueReference(Sema &S, BlockScopeInfo *CurBlock, } +ExprResult +Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, + const CXXScopeSpec *SS) { + DeclarationNameInfo NameInfo(D->getDeclName(), Loc); + return BuildDeclRefExpr(D, Ty, NameInfo, SS); +} /// BuildDeclRefExpr - Build a DeclRefExpr. -Sema::OwningExprResult -Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, +ExprResult +Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, + const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS) { if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) { - Diag(Loc, + Diag(NameInfo.getLoc(), diag::err_auto_variable_cannot_appear_in_own_initializer) << D->getDeclName(); return ExprError(); @@ -479,7 +489,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, } else if (const CXXMethodDecl *MD = dyn_cast(CurContext)) { if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) { if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) { - Diag(Loc, diag::err_reference_to_local_var_in_enclosing_function) + Diag(NameInfo.getLoc(), + diag::err_reference_to_local_var_in_enclosing_function) << D->getIdentifier() << FD->getDeclName(); Diag(D->getLocation(), diag::note_local_variable_declared_here) << D->getIdentifier(); @@ -489,12 +500,12 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc, } } - MarkDeclarationReferenced(Loc, D); + MarkDeclarationReferenced(NameInfo.getLoc(), D); return Owned(DeclRefExpr::Create(Context, SS? (NestedNameSpecifier *)SS->getScopeRep() : 0, SS? SS->getRange() : SourceRange(), - D, Loc, Ty)); + D, NameInfo, Ty)); } /// \brief Given a field that represents a member of an anonymous @@ -535,7 +546,7 @@ VarDecl *Sema::BuildAnonymousStructUnionMemberPath(FieldDecl *Field, return BaseObject; } -Sema::OwningExprResult +ExprResult Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, FieldDecl *Field, Expr *BaseObjectExpr, @@ -553,7 +564,6 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, if (BaseObject) { // BaseObject is an anonymous struct/union variable (and is, // therefore, not part of another non-anonymous record). - if (BaseObjectExpr) BaseObjectExpr->Destroy(Context); MarkDeclarationReferenced(Loc, BaseObject); BaseObjectExpr = new (Context) DeclRefExpr(BaseObject,BaseObject->getType(), SourceLocation()); @@ -640,7 +650,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, return Owned(Result); } -/// Decomposes the given name into a DeclarationName, its location, and +/// Decomposes the given name into a DeclarationNameInfo, its location, and /// possibly a list of template arguments. /// /// If this produces template arguments, it is permitted to call @@ -652,8 +662,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, static void DecomposeUnqualifiedId(Sema &SemaRef, const UnqualifiedId &Id, TemplateArgumentListInfo &Buffer, - DeclarationName &Name, - SourceLocation &NameLoc, + DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *&TemplateArgs) { if (Id.getKind() == UnqualifiedId::IK_TemplateId) { Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc); @@ -665,15 +674,12 @@ static void DecomposeUnqualifiedId(Sema &SemaRef, SemaRef.translateTemplateArguments(TemplateArgsPtr, Buffer); TemplateArgsPtr.release(); - TemplateName TName = - Sema::TemplateTy::make(Id.TemplateId->Template).getAsVal(); - - Name = SemaRef.Context.getNameForTemplate(TName); - NameLoc = Id.TemplateId->TemplateNameLoc; + TemplateName TName = Id.TemplateId->Template.get(); + SourceLocation TNameLoc = Id.TemplateId->TemplateNameLoc; + NameInfo = SemaRef.Context.getNameForTemplate(TName, TNameLoc); TemplateArgs = &Buffer; } else { - Name = SemaRef.GetNameFromUnqualifiedId(Id); - NameLoc = Id.StartLocation; + NameInfo = SemaRef.GetNameFromUnqualifiedId(Id); TemplateArgs = 0; } } @@ -700,23 +706,6 @@ static bool IsFullyFormedScope(Sema &SemaRef, CXXRecordDecl *Record) { return true; } -/// Determines whether we can lookup this id-expression now or whether -/// we have to wait until template instantiation is complete. -static bool IsDependentIdExpression(Sema &SemaRef, const CXXScopeSpec &SS) { - DeclContext *DC = SemaRef.computeDeclContext(SS, false); - - // If the qualifier scope isn't computable, it's definitely dependent. - if (!DC) return true; - - // If the qualifier scope doesn't name a record, we can always look into it. - if (!isa(DC)) return false; - - // We can't look into record types unless they're fully-formed. - if (!IsFullyFormedScope(SemaRef, cast(DC))) return true; - - return false; -} - /// Determines if the given class is provably not derived from all of /// the prospective base classes. static bool IsProvablyNotDerivedFrom(Sema &SemaRef, @@ -905,25 +894,30 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, // TODO: fixit for inserting 'Base::' in the other cases. // Actually quite difficult! if (isInstance) { - Diag(R.getNameLoc(), diagnostic) << Name - << FixItHint::CreateInsertion(R.getNameLoc(), "this->"); - UnresolvedLookupExpr *ULE = cast( CallsUndergoingInstantiation.back()->getCallee()); - CXXMethodDecl *DepMethod = cast( + CXXMethodDecl *DepMethod = cast_or_null( CurMethod->getInstantiatedFromMemberFunction()); - QualType DepThisType = DepMethod->getThisType(Context); - CXXThisExpr *DepThis = new (Context) CXXThisExpr(R.getNameLoc(), - DepThisType, false); - TemplateArgumentListInfo TList; - if (ULE->hasExplicitTemplateArgs()) - ULE->copyTemplateArgumentsInto(TList); - CXXDependentScopeMemberExpr *DepExpr = - CXXDependentScopeMemberExpr::Create( - Context, DepThis, DepThisType, true, SourceLocation(), - ULE->getQualifier(), ULE->getQualifierRange(), NULL, Name, - R.getNameLoc(), &TList); - CallsUndergoingInstantiation.back()->setCallee(DepExpr); + if (DepMethod) { + Diag(R.getNameLoc(), diagnostic) << Name + << FixItHint::CreateInsertion(R.getNameLoc(), "this->"); + QualType DepThisType = DepMethod->getThisType(Context); + CXXThisExpr *DepThis = new (Context) CXXThisExpr( + R.getNameLoc(), DepThisType, false); + TemplateArgumentListInfo TList; + if (ULE->hasExplicitTemplateArgs()) + ULE->copyTemplateArgumentsInto(TList); + CXXDependentScopeMemberExpr *DepExpr = + CXXDependentScopeMemberExpr::Create( + Context, DepThis, DepThisType, true, SourceLocation(), + ULE->getQualifier(), ULE->getQualifierRange(), NULL, + R.getLookupNameInfo(), &TList); + CallsUndergoingInstantiation.back()->setCallee(DepExpr); + } else { + // FIXME: we should be able to handle this case too. It is correct + // to add this-> here. This is a workaround for PR7947. + Diag(R.getNameLoc(), diagnostic) << Name; + } } else { Diag(R.getNameLoc(), diagnostic) << Name; } @@ -935,6 +929,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, // Tell the callee to try to recover. return false; } + + R.clear(); } } @@ -1005,11 +1001,74 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, return true; } -Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, - CXXScopeSpec &SS, - UnqualifiedId &Id, - bool HasTrailingLParen, - bool isAddressOfOperand) { +static ObjCPropertyDecl *OkToSynthesizeProvisionalIvar(Sema &SemaRef, + IdentifierInfo *II, + SourceLocation NameLoc) { + ObjCMethodDecl *CurMeth = SemaRef.getCurMethodDecl(); + ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface(); + if (!IDecl) + return 0; + ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation(); + if (!ClassImpDecl) + return 0; + ObjCPropertyDecl *property = SemaRef.LookupPropertyDecl(IDecl, II); + if (!property) + return 0; + if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) + if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) + return 0; + return property; +} + +static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef, + LookupResult &Lookup, + IdentifierInfo *II, + SourceLocation NameLoc) { + ObjCMethodDecl *CurMeth = SemaRef.getCurMethodDecl(); + bool LookForIvars; + if (Lookup.empty()) + LookForIvars = true; + else if (CurMeth->isClassMethod()) + LookForIvars = false; + else + LookForIvars = (Lookup.isSingleResult() && + Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()); + if (!LookForIvars) + return 0; + + ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface(); + if (!IDecl) + return 0; + ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation(); + if (!ClassImpDecl) + return 0; + bool DynamicImplSeen = false; + ObjCPropertyDecl *property = SemaRef.LookupPropertyDecl(IDecl, II); + if (!property) + return 0; + if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) + DynamicImplSeen = + (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); + if (!DynamicImplSeen) { + QualType PropType = SemaRef.Context.getCanonicalType(property->getType()); + ObjCIvarDecl *Ivar = ObjCIvarDecl::Create(SemaRef.Context, ClassImpDecl, + NameLoc, + II, PropType, /*Dinfo=*/0, + ObjCIvarDecl::Protected, + (Expr *)0, true); + ClassImpDecl->addDecl(Ivar); + IDecl->makeDeclVisibleInContext(Ivar, false); + property->setPropertyIvarDecl(Ivar); + return Ivar; + } + return 0; +} + +ExprResult Sema::ActOnIdExpression(Scope *S, + CXXScopeSpec &SS, + UnqualifiedId &Id, + bool HasTrailingLParen, + bool isAddressOfOperand) { assert(!(isAddressOfOperand && HasTrailingLParen) && "cannot be direct & operand and have a trailing lparen"); @@ -1019,13 +1078,13 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, TemplateArgumentListInfo TemplateArgsBuffer; // Decompose the UnqualifiedId into the following data. - DeclarationName Name; - SourceLocation NameLoc; + DeclarationNameInfo NameInfo; const TemplateArgumentListInfo *TemplateArgs; - DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, - Name, NameLoc, TemplateArgs); + DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, NameInfo, TemplateArgs); + DeclarationName Name = NameInfo.getName(); IdentifierInfo *II = Name.getAsIdentifierInfo(); + SourceLocation NameLoc = NameInfo.getLoc(); // C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: @@ -1038,16 +1097,30 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // names a dependent type. // Determine whether this is a member of an unknown specialization; // we need to handle these differently. - if ((Name.getNameKind() == DeclarationName::CXXConversionFunctionName && - Name.getCXXNameType()->isDependentType()) || - (SS.isSet() && IsDependentIdExpression(*this, SS))) { - return ActOnDependentIdExpression(SS, Name, NameLoc, - isAddressOfOperand, - TemplateArgs); + bool DependentID = false; + if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName && + Name.getCXXNameType()->isDependentType()) { + DependentID = true; + } else if (SS.isSet()) { + DeclContext *DC = computeDeclContext(SS, false); + if (DC) { + if (RequireCompleteDeclContext(SS, DC)) + return ExprError(); + // FIXME: We should be checking whether DC is the current instantiation. + if (CXXRecordDecl *RD = dyn_cast(DC)) + DependentID = !IsFullyFormedScope(*this, RD); + } else { + DependentID = true; + } } + if (DependentID) { + return ActOnDependentIdExpression(SS, NameInfo, isAddressOfOperand, + TemplateArgs); + } + bool IvarLookupFollowUp = false; // Perform the required lookup. - LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); + LookupResult R(*this, NameInfo, LookupOrdinaryName); if (TemplateArgs) { // Lookup the template name again to correctly establish the context in // which it was found. This is really unfortunate as we already did the @@ -1058,18 +1131,26 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, MemberOfUnknownSpecialization); } else { - bool IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl()); + IvarLookupFollowUp = (!SS.isSet() && II && getCurMethodDecl()); LookupParsedName(R, S, &SS, !IvarLookupFollowUp); // If this reference is in an Objective-C method, then we need to do // some special Objective-C lookup, too. if (IvarLookupFollowUp) { - OwningExprResult E(LookupInObjCMethod(R, S, II, true)); + ExprResult E(LookupInObjCMethod(R, S, II, true)); if (E.isInvalid()) return ExprError(); Expr *Ex = E.takeAs(); if (Ex) return Owned(Ex); + // Synthesize ivars lazily + if (getLangOptions().ObjCNonFragileABI2) { + if (SynthesizeProvisionalIvar(*this, R, II, NameLoc)) + return ActOnIdExpression(S, SS, Id, HasTrailingLParen, + isAddressOfOperand); + } + // for further use, this must be set to false if in class method. + IvarLookupFollowUp = getCurMethodDecl()->isInstanceMethod(); } } @@ -1102,7 +1183,7 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, // reference the ivar. if (ObjCIvarDecl *Ivar = R.getAsSingle()) { R.clear(); - OwningExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier())); + ExprResult E(LookupInObjCMethod(R, S, Ivar->getIdentifier())); assert(E.isInvalid() || E.get()); return move(E); } @@ -1113,23 +1194,15 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, assert(!R.empty() || ADL); if (VarDecl *Var = R.getAsSingle()) { - // Warn about constructs like: - // if (void *X = foo()) { ... } else { X }. - // In the else block, the pointer is always false. - if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) { - Scope *CheckS = S; - while (CheckS && CheckS->getControlParent()) { - if ((CheckS->getFlags() & Scope::ElseScope) && - CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) { - ExprError(Diag(NameLoc, diag::warn_value_always_zero) - << Var->getDeclName() - << (Var->getType()->isPointerType() ? 2 : - Var->getType()->isBooleanType() ? 1 : 0)); - break; - } - - // Move to the parent of this scope. - CheckS = CheckS->getParent(); + if (getLangOptions().ObjCNonFragileABI && IvarLookupFollowUp && + !getLangOptions().ObjCNonFragileABI2 && + Var->isFileVarDecl()) { + ObjCPropertyDecl *Property = + OkToSynthesizeProvisionalIvar(*this, II, NameLoc); + if (Property) { + Diag(NameLoc, diag::warn_ivar_variable_conflict) << Var->getDeclName(); + Diag(Property->getLocation(), diag::note_property_declare); + Diag(Var->getLocation(), diag::note_global_declared_at); } } } else if (FunctionDecl *Func = R.getAsSingle()) { @@ -1152,15 +1225,43 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, } // Check whether this might be a C++ implicit instance member access. - // C++ [expr.prim.general]p6: - // Within the definition of a non-static member function, an - // identifier that names a non-static member is transformed to a - // class member access expression. - // But note that &SomeClass::foo is grammatically distinct, even - // though we don't parse it that way. + // C++ [class.mfct.non-static]p3: + // When an id-expression that is not part of a class member access + // syntax and not used to form a pointer to member is used in the + // body of a non-static member function of class X, if name lookup + // resolves the name in the id-expression to a non-static non-type + // member of some class C, the id-expression is transformed into a + // class member access expression using (*this) as the + // postfix-expression to the left of the . operator. + // + // But we don't actually need to do this for '&' operands if R + // resolved to a function or overloaded function set, because the + // expression is ill-formed if it actually works out to be a + // non-static member function: + // + // C++ [expr.ref]p4: + // Otherwise, if E1.E2 refers to a non-static member function. . . + // [t]he expression can be used only as the left-hand operand of a + // member function call. + // + // There are other safeguards against such uses, but it's important + // to get this right here so that we don't end up making a + // spuriously dependent expression if we're inside a dependent + // instance method. if (!R.empty() && (*R.begin())->isCXXClassMember()) { - bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty()); - if (!isAbstractMemberPointer) + bool MightBeImplicitMember; + if (!isAddressOfOperand) + MightBeImplicitMember = true; + else if (!SS.isEmpty()) + MightBeImplicitMember = false; + else if (R.isOverloadedResult()) + MightBeImplicitMember = false; + else if (R.isUnresolvableResult()) + MightBeImplicitMember = true; + else + MightBeImplicitMember = isa(R.getFoundDecl()); + + if (MightBeImplicitMember) return BuildPossibleImplicitMemberExpr(SS, R, TemplateArgs); } @@ -1171,7 +1272,7 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, } /// Builds an expression which might be an implicit member expression. -Sema::OwningExprResult +ExprResult Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { @@ -1210,25 +1311,25 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, /// declaration name, generally during template instantiation. /// There's a large number of things which don't need to be done along /// this path. -Sema::OwningExprResult +ExprResult Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, - DeclarationName Name, - SourceLocation NameLoc) { + const DeclarationNameInfo &NameInfo) { DeclContext *DC; if (!(DC = computeDeclContext(SS, false)) || DC->isDependentContext()) - return BuildDependentDeclRefExpr(SS, Name, NameLoc, 0); + return BuildDependentDeclRefExpr(SS, NameInfo, 0); if (RequireCompleteDeclContext(SS, DC)) return ExprError(); - LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); + LookupResult R(*this, NameInfo, LookupOrdinaryName); LookupQualifiedName(R, DC); if (R.isAmbiguous()) return ExprError(); if (R.empty()) { - Diag(NameLoc, diag::err_no_member) << Name << DC << SS.getRange(); + Diag(NameInfo.getLoc(), diag::err_no_member) + << NameInfo.getName() << DC << SS.getRange(); return ExprError(); } @@ -1243,7 +1344,7 @@ Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, /// actually quite a lot of extra work involved. /// /// Returns a null sentinel to indicate trivial success. -Sema::OwningExprResult +ExprResult Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, IdentifierInfo *II, bool AllowBuiltinCreation) { SourceLocation Loc = Lookup.getNameLoc(); @@ -1298,7 +1399,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, UnqualifiedId SelfName; SelfName.setIdentifier(&II, SourceLocation()); CXXScopeSpec SelfScopeSpec; - OwningExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, + ExprResult SelfExpr = ActOnIdExpression(S, SelfScopeSpec, SelfName, false, false); MarkDeclarationReferenced(Loc, IV); return Owned(new (Context) @@ -1403,9 +1504,8 @@ Sema::PerformObjectMemberConversion(Expr *&From, SourceRange FromRange = From->getSourceRange(); SourceLocation FromLoc = FromRange.getBegin(); - bool isLvalue - = (From->isLvalue(Context) == Expr::LV_Valid) && !PointerConversions; - + ExprValueKind VK = CastCategory(From); + // C++ [class.member.lookup]p8: // [...] Ambiguities can often be resolved by qualifying a name with its // class name. @@ -1435,15 +1535,15 @@ Sema::PerformObjectMemberConversion(Expr *&From, // type of the object type, in which case we just ignore it. // Otherwise build the appropriate casts. if (IsDerivedFrom(FromRecordType, QRecordType)) { - CXXBaseSpecifierArray BasePath; + CXXCastPath BasePath; if (CheckDerivedToBaseConversion(FromRecordType, QRecordType, FromLoc, FromRange, &BasePath)) return true; if (PointerConversions) QType = Context.getPointerType(QType); - ImpCastExprToType(From, QType, CastExpr::CK_UncheckedDerivedToBase, - isLvalue, BasePath); + ImpCastExprToType(From, QType, CK_UncheckedDerivedToBase, + VK, &BasePath); FromType = QType; FromRecordType = QRecordType; @@ -1471,7 +1571,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, // conversion is non-trivial. if (!Context.hasSameUnqualifiedType(FromRecordType, URecordType)) { assert(IsDerivedFrom(FromRecordType, URecordType)); - CXXBaseSpecifierArray BasePath; + CXXCastPath BasePath; if (CheckDerivedToBaseConversion(FromRecordType, URecordType, FromLoc, FromRange, &BasePath)) return true; @@ -1479,8 +1579,8 @@ Sema::PerformObjectMemberConversion(Expr *&From, QualType UType = URecordType; if (PointerConversions) UType = Context.getPointerType(UType); - ImpCastExprToType(From, UType, CastExpr::CK_UncheckedDerivedToBase, - isLvalue, BasePath); + ImpCastExprToType(From, UType, CK_UncheckedDerivedToBase, + VK, &BasePath); FromType = UType; FromRecordType = URecordType; } @@ -1490,14 +1590,14 @@ Sema::PerformObjectMemberConversion(Expr *&From, IgnoreAccess = true; } - CXXBaseSpecifierArray BasePath; + CXXCastPath BasePath; if (CheckDerivedToBaseConversion(FromRecordType, DestRecordType, FromLoc, FromRange, &BasePath, IgnoreAccess)) return true; - ImpCastExprToType(From, DestType, CastExpr::CK_UncheckedDerivedToBase, - isLvalue, BasePath); + ImpCastExprToType(From, DestType, CK_UncheckedDerivedToBase, + VK, &BasePath); return false; } @@ -1505,7 +1605,8 @@ Sema::PerformObjectMemberConversion(Expr *&From, static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, const CXXScopeSpec &SS, ValueDecl *Member, DeclAccessPair FoundDecl, - SourceLocation Loc, QualType Ty, + const DeclarationNameInfo &MemberNameInfo, + QualType Ty, const TemplateArgumentListInfo *TemplateArgs = 0) { NestedNameSpecifier *Qualifier = 0; SourceRange QualifierRange; @@ -1515,14 +1616,15 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, } return MemberExpr::Create(C, Base, isArrow, Qualifier, QualifierRange, - Member, FoundDecl, Loc, TemplateArgs, Ty); + Member, FoundDecl, MemberNameInfo, + TemplateArgs, Ty); } /// Builds an implicit member access expression. The current context /// is known to be an instance method, and the given unqualified lookup /// set is known to contain only instance members, at least one of which /// is from an appropriate type. -Sema::OwningExprResult +ExprResult Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, @@ -1551,7 +1653,7 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, This = new (Context) CXXThisExpr(Loc, ThisType, /*isImplicit=*/true); } - return BuildMemberReferenceExpr(ExprArg(*this, This), ThisType, + return BuildMemberReferenceExpr(This, ThisType, /*OpLoc*/ SourceLocation(), /*IsArrow*/ true, SS, @@ -1638,14 +1740,15 @@ static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) { return false; } -Sema::OwningExprResult +ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL) { // If this is a single, fully-resolved result and we don't need ADL, // just build an ordinary singleton decl ref. if (!NeedsADL && R.isSingleResult() && !R.getAsSingle()) - return BuildDeclarationNameExpr(SS, R.getNameLoc(), R.getFoundDecl()); + return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), + R.getFoundDecl()); // We only need to check the declaration if there's exactly one // result, because in the overloaded case the results can only be @@ -1664,8 +1767,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create(Context, Dependent, R.getNamingClass(), (NestedNameSpecifier*) SS.getScopeRep(), - SS.getRange(), - R.getLookupName(), R.getNameLoc(), + SS.getRange(), R.getLookupNameInfo(), NeedsADL, R.isOverloadedResult(), R.begin(), R.end()); @@ -1674,13 +1776,15 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, /// \brief Complete semantic analysis for a reference to the given declaration. -Sema::OwningExprResult +ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, - SourceLocation Loc, NamedDecl *D) { + const DeclarationNameInfo &NameInfo, + NamedDecl *D) { assert(D && "Cannot refer to a NULL declaration"); assert(!isa(D) && "Cannot refer unambiguously to a function template"); + SourceLocation Loc = NameInfo.getLoc(); if (CheckDeclInExpr(*this, Loc, D)) return ExprError(); @@ -1755,13 +1859,13 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, DeclRefExpr(const_cast(BDRE->getDecl()), T, SourceLocation()); - OwningExprResult Res = PerformCopyInitialization( + ExprResult Res = PerformCopyInitialization( InitializedEntity::InitializeBlock(VD->getLocation(), T, false), SourceLocation(), Owned(E)); if (!Res.isInvalid()) { - Res = MaybeCreateCXXExprWithTemporaries(move(Res)); + Res = MaybeCreateCXXExprWithTemporaries(Res.get()); Expr *Init = Res.takeAs(); BDRE->setCopyConstructorExpr(Init); } @@ -1772,10 +1876,11 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // If this reference is not in a block or if the referenced variable is // within the block, create a normal DeclRefExpr. - return BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc, &SS); + return BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), + NameInfo, &SS); } -Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, +ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { PredefinedExpr::IdentType IT; @@ -1790,6 +1895,8 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, // string. Decl *currentDecl = getCurFunctionOrMethodDecl(); + if (!currentDecl && getCurBlock()) + currentDecl = getCurBlock()->TheDecl; if (!currentDecl) { Diag(Loc, diag::ext_predef_outside_function); currentDecl = Context.getTranslationUnitDecl(); @@ -1808,7 +1915,7 @@ Sema::OwningExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, return Owned(new (Context) PredefinedExpr(Loc, ResTy, IT)); } -Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) { +ExprResult Sema::ActOnCharacterConstant(const Token &Tok) { llvm::SmallString<16> CharBuffer; bool Invalid = false; llvm::StringRef ThisTok = PP.getSpelling(Tok, CharBuffer, &Invalid); @@ -1835,13 +1942,13 @@ Sema::OwningExprResult Sema::ActOnCharacterConstant(const Token &Tok) { Ty, Tok.getLocation())); } -Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { +ExprResult Sema::ActOnNumericConstant(const Token &Tok) { // Fast path for a single digit (which is quite common). A single digit // cannot have a trigraph, escaped newline, radix prefix, or type suffix. if (Tok.getLength() == 1) { const char Val = PP.getSpellingOfSingleCharacterNumericConstant(Tok); unsigned IntSize = Context.Target.getIntWidth(); - return Owned(new (Context) IntegerLiteral(llvm::APInt(IntSize, Val-'0'), + return Owned(IntegerLiteral::Create(Context, llvm::APInt(IntSize, Val-'0'), Context.IntTy, Tok.getLocation())); } @@ -1899,7 +2006,7 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { } bool isExact = (result == APFloat::opOK); - Res = new (Context) FloatingLiteral(Val, isExact, Ty, Tok.getLocation()); + Res = FloatingLiteral::Create(Context, Val, isExact, Ty, Tok.getLocation()); } else if (!Literal.isIntegerLiteral()) { return ExprError(); @@ -1986,7 +2093,7 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { if (ResultVal.getBitWidth() != Width) ResultVal.trunc(Width); } - Res = new (Context) IntegerLiteral(ResultVal, Ty, Tok.getLocation()); + Res = IntegerLiteral::Create(Context, ResultVal, Ty, Tok.getLocation()); } // If this is an imaginary literal, create the ImaginaryLiteral wrapper. @@ -1997,9 +2104,8 @@ Action::OwningExprResult Sema::ActOnNumericConstant(const Token &Tok) { return Owned(Res); } -Action::OwningExprResult Sema::ActOnParenExpr(SourceLocation L, - SourceLocation R, ExprArg Val) { - Expr *E = Val.takeAs(); +ExprResult Sema::ActOnParenExpr(SourceLocation L, + SourceLocation R, Expr *E) { assert((E != 0) && "ActOnParenExpr() missing expr"); return Owned(new (Context) ParenExpr(L, R, E)); } @@ -2083,7 +2189,7 @@ bool Sema::CheckAlignOfExpr(Expr *E, SourceLocation OpLoc, } /// \brief Build a sizeof or alignof expression given a type operand. -Action::OwningExprResult +ExprResult Sema::CreateSizeOfAlignOfExpr(TypeSourceInfo *TInfo, SourceLocation OpLoc, bool isSizeOf, SourceRange R) { @@ -2104,7 +2210,7 @@ Sema::CreateSizeOfAlignOfExpr(TypeSourceInfo *TInfo, /// \brief Build a sizeof or alignof expression given an expression /// operand. -Action::OwningExprResult +ExprResult Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, bool isSizeOf, SourceRange R) { // Verify that the operand is valid. @@ -2132,7 +2238,7 @@ Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, /// ActOnSizeOfAlignOfExpr - Handle @c sizeof(type) and @c sizeof @c expr and /// the same for @c alignof and @c __alignof /// Note that the ArgRange is invalid if isType is false. -Action::OwningExprResult +ExprResult Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, void *TyOrEx, const SourceRange &ArgRange) { // If error parsing type, ignore. @@ -2140,17 +2246,14 @@ Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, if (isType) { TypeSourceInfo *TInfo; - (void) GetTypeFromParser(TyOrEx, &TInfo); + (void) GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrEx), &TInfo); return CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeof, ArgRange); } Expr *ArgEx = (Expr *)TyOrEx; - Action::OwningExprResult Result + ExprResult Result = CreateSizeOfAlignOfExpr(ArgEx, OpLoc, isSizeof, ArgEx->getSourceRange()); - if (Result.isInvalid()) - DeleteExpr(ArgEx); - return move(Result); } @@ -2174,32 +2277,31 @@ QualType Sema::CheckRealImagOperand(Expr *&V, SourceLocation Loc, bool isReal) { -Action::OwningExprResult +ExprResult Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, - tok::TokenKind Kind, ExprArg Input) { - UnaryOperator::Opcode Opc; + tok::TokenKind Kind, Expr *Input) { + UnaryOperatorKind Opc; switch (Kind) { default: assert(0 && "Unknown unary op!"); - case tok::plusplus: Opc = UnaryOperator::PostInc; break; - case tok::minusminus: Opc = UnaryOperator::PostDec; break; + case tok::plusplus: Opc = UO_PostInc; break; + case tok::minusminus: Opc = UO_PostDec; break; } - return BuildUnaryOp(S, OpLoc, Opc, move(Input)); + return BuildUnaryOp(S, OpLoc, Opc, Input); } -Action::OwningExprResult -Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, - ExprArg Idx, SourceLocation RLoc) { +ExprResult +Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, + Expr *Idx, SourceLocation RLoc) { // Since this might be a postfix expression, get rid of ParenListExprs. - Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); + ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base); + if (Result.isInvalid()) return ExprError(); + Base = Result.take(); - Expr *LHSExp = static_cast(Base.get()), - *RHSExp = static_cast(Idx.get()); + Expr *LHSExp = Base, *RHSExp = Idx; if (getLangOptions().CPlusPlus && (LHSExp->isTypeDependent() || RHSExp->isTypeDependent())) { - Base.release(); - Idx.release(); return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp, Context.DependentTy, RLoc)); } @@ -2209,18 +2311,18 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc, LHSExp->getType()->isEnumeralType() || RHSExp->getType()->isRecordType() || RHSExp->getType()->isEnumeralType())) { - return CreateOverloadedArraySubscriptExpr(LLoc, RLoc, move(Base),move(Idx)); + return CreateOverloadedArraySubscriptExpr(LLoc, RLoc, Base, Idx); } - return CreateBuiltinArraySubscriptExpr(move(Base), LLoc, move(Idx), RLoc); + return CreateBuiltinArraySubscriptExpr(Base, LLoc, Idx, RLoc); } -Action::OwningExprResult -Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc, - ExprArg Idx, SourceLocation RLoc) { - Expr *LHSExp = static_cast(Base.get()); - Expr *RHSExp = static_cast(Idx.get()); +ExprResult +Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, + Expr *Idx, SourceLocation RLoc) { + Expr *LHSExp = Base; + Expr *RHSExp = Idx; // Perform default conversions. if (!LHSExp->getType()->getAs()) @@ -2274,7 +2376,7 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc, Diag(LHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << LHSExp->getSourceRange(); ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy), - CastExpr::CK_ArrayToPointerDecay); + CK_ArrayToPointerDecay); LHSTy = LHSExp->getType(); BaseExpr = LHSExp; @@ -2285,7 +2387,7 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc, Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << RHSExp->getSourceRange(); ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy), - CastExpr::CK_ArrayToPointerDecay); + CK_ArrayToPointerDecay); RHSTy = RHSExp->getType(); BaseExpr = RHSExp; @@ -2296,8 +2398,7 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc, << LHSExp->getSourceRange() << RHSExp->getSourceRange()); } // C99 6.5.2.1p1 - if (!(IndexExpr->getType()->isIntegerType() && - IndexExpr->getType()->isScalarType()) && !IndexExpr->isTypeDependent()) + if (!IndexExpr->getType()->isIntegerType() && !IndexExpr->isTypeDependent()) return ExprError(Diag(LLoc, diag::err_typecheck_subscript_not_integer) << IndexExpr->getSourceRange()); @@ -2329,8 +2430,6 @@ Sema::CreateBuiltinArraySubscriptExpr(ExprArg Base, SourceLocation LLoc, return ExprError(); } - Base.release(); - Idx.release(); return Owned(new (Context) ArraySubscriptExpr(LHSExp, RHSExp, ResultType, RLoc)); } @@ -2377,7 +2476,7 @@ CheckExtVectorComponent(QualType baseType, SourceLocation OpLoc, // We didn't get to the end of the string. This means the component names // didn't come from the same set *or* we encountered an illegal name. Diag(OpLoc, diag::err_ext_vector_component_name_illegal) - << std::string(compStr,compStr+1) << SourceRange(CompLoc); + << llvm::StringRef(compStr, 1) << SourceRange(CompLoc); return QualType(); } @@ -2470,15 +2569,13 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy, return GDecl; } -Sema::OwningExprResult -Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType, +ExprResult +Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, - DeclarationName Name, SourceLocation NameLoc, + const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs) { - Expr *BaseExpr = Base.takeAs(); - // Even in dependent contexts, try to diagnose base expressions with // obviously wrong types, e.g.: // @@ -2493,24 +2590,24 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType, if (PT && (!getLangOptions().ObjC1 || PT->getPointeeType()->isRecordType())) { assert(BaseExpr && "cannot happen with implicit member accesses"); - Diag(NameLoc, diag::err_typecheck_member_reference_struct_union) + Diag(NameInfo.getLoc(), diag::err_typecheck_member_reference_struct_union) << BaseType << BaseExpr->getSourceRange(); return ExprError(); } } - assert(BaseType->isDependentType() || Name.isDependentName() || + assert(BaseType->isDependentType() || + NameInfo.getName().isDependentName() || isDependentScopeSpecifier(SS)); // Get the type being accessed in BaseType. If this is an arrow, the BaseExpr // must have pointer type, and the accessed type is the pointee. return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType, IsArrow, OpLoc, - static_cast(SS.getScopeRep()), + SS.getScopeRep(), SS.getRange(), FirstQualifierInScope, - Name, NameLoc, - TemplateArgs)); + NameInfo, TemplateArgs)); } /// We know that the given qualified member reference points only to @@ -2562,12 +2659,15 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, return false; // Note that we use the DC of the decl, not the underlying decl. - CXXRecordDecl *RecordD = cast((*I)->getDeclContext()); - while (RecordD->isAnonymousStructOrUnion()) - RecordD = cast(RecordD->getParent()); + DeclContext *DC = (*I)->getDeclContext(); + while (DC->isTransparentContext()) + DC = DC->getParent(); + if (!DC->isRecord()) + continue; + llvm::SmallPtrSet MemberRecord; - MemberRecord.insert(RecordD->getCanonicalDecl()); + MemberRecord.insert(cast(DC)->getCanonicalDecl()); if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord)) return false; @@ -2646,24 +2746,21 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, return false; } -Sema::OwningExprResult -Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, +ExprResult +Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, - DeclarationName Name, SourceLocation NameLoc, + const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs) { - Expr *Base = BaseArg.takeAs(); - if (BaseType->isDependentType() || (SS.isSet() && isDependentScopeSpecifier(SS))) - return ActOnDependentMemberExpr(ExprArg(*this, Base), BaseType, + return ActOnDependentMemberExpr(Base, BaseType, IsArrow, OpLoc, SS, FirstQualifierInScope, - Name, NameLoc, - TemplateArgs); + NameInfo, TemplateArgs); - LookupResult R(*this, Name, NameLoc, LookupMemberName); + LookupResult R(*this, NameInfo, LookupMemberName); // Implicit member accesses. if (!Base) { @@ -2676,9 +2773,9 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, // Explicit member accesses. } else { - OwningExprResult Result = + ExprResult Result = LookupMemberExpr(R, Base, IsArrow, OpLoc, - SS, /*ObjCImpDecl*/ DeclPtrTy(), TemplateArgs != 0); + SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0); if (Result.isInvalid()) { Owned(Base); @@ -2692,20 +2789,19 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType, BaseType = Base->getType(); } - return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType, + return BuildMemberReferenceExpr(Base, BaseType, OpLoc, IsArrow, SS, FirstQualifierInScope, R, TemplateArgs); } -Sema::OwningExprResult -Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, +ExprResult +Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, bool SuppressQualifierCheck) { - Expr *BaseExpr = Base.takeAs(); QualType BaseType = BaseExprType; if (IsArrow) { assert(BaseType->isPointerType()); @@ -2713,10 +2809,10 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, } R.setBaseObjectType(BaseType); - NestedNameSpecifier *Qualifier = - static_cast(SS.getScopeRep()); - DeclarationName MemberName = R.getLookupName(); - SourceLocation MemberLoc = R.getNameLoc(); + NestedNameSpecifier *Qualifier = SS.getScopeRep(); + const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo(); + DeclarationName MemberName = MemberNameInfo.getName(); + SourceLocation MemberLoc = MemberNameInfo.getLoc(); if (R.isAmbiguous()) return ExprError(); @@ -2765,7 +2861,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, BaseExpr, BaseExprType, IsArrow, OpLoc, Qualifier, SS.getRange(), - MemberName, MemberLoc, + MemberNameInfo, TemplateArgs, R.begin(), R.end()); return Owned(MemExpr); @@ -2787,7 +2883,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, if (!BaseExpr) { // If this is not an instance member, convert to a non-member access. if (!MemberDecl->isCXXInstanceMember()) - return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl); + return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl); SourceLocation Loc = R.getNameLoc(); if (SS.getRange().isValid()) @@ -2838,34 +2934,36 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, if (PerformObjectMemberConversion(BaseExpr, Qualifier, FoundDecl, FD)) return ExprError(); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - FD, FoundDecl, MemberLoc, MemberType)); + FD, FoundDecl, MemberNameInfo, + MemberType)); } if (VarDecl *Var = dyn_cast(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, Var); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - Var, FoundDecl, MemberLoc, + Var, FoundDecl, MemberNameInfo, Var->getType().getNonReferenceType())); } if (FunctionDecl *MemberFn = dyn_cast(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - MemberFn, FoundDecl, MemberLoc, + MemberFn, FoundDecl, MemberNameInfo, MemberFn->getType())); } if (EnumConstantDecl *Enum = dyn_cast(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - Enum, FoundDecl, MemberLoc, Enum->getType())); + Enum, FoundDecl, MemberNameInfo, + Enum->getType())); } Owned(BaseExpr); // We found something that we didn't expect. Complain. if (isa(MemberDecl)) - Diag(MemberLoc,diag::err_typecheck_member_reference_type) + Diag(MemberLoc, diag::err_typecheck_member_reference_type) << MemberName << BaseType << int(IsArrow); else Diag(MemberLoc, diag::err_typecheck_member_reference_unknown) @@ -2887,11 +2985,11 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, /// /// The ObjCImpDecl bit is a gross hack that will need to be properly /// fixed for ObjC++. -Sema::OwningExprResult +ExprResult Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, bool &IsArrow, SourceLocation OpLoc, CXXScopeSpec &SS, - DeclPtrTy ObjCImpDecl, bool HasTemplateArgs) { + Decl *ObjCImpDecl, bool HasTemplateArgs) { assert(BaseExpr && "no base expression"); // Perform default conversions. @@ -2921,8 +3019,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, << QualType(Fun, 0) << FixItHint::CreateInsertion(Loc, "()"); - OwningExprResult NewBase - = ActOnCallExpr(0, ExprArg(*this, BaseExpr), Loc, + ExprResult NewBase + = ActOnCallExpr(0, BaseExpr, Loc, MultiExprArg(*this, 0, 0), 0, Loc); BaseExpr = 0; if (NewBase.isInvalid()) @@ -2952,7 +3050,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // is a reference to 'isa'. if (BaseType != Context.ObjCIdRedefinitionType) { BaseType = Context.ObjCIdRedefinitionType; - ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast); + ImpCastExprToType(BaseExpr, BaseType, CK_BitCast); } } @@ -2963,7 +3061,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // is a reference to 'sel_id'. if (BaseType != Context.ObjCSelRedefinitionType) { BaseType = Context.ObjCSelRedefinitionType; - ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast); + ImpCastExprToType(BaseExpr, BaseType, CK_BitCast); } } @@ -3022,7 +3120,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (BaseType->isObjCClassType() && BaseType != Context.ObjCClassRedefinitionType) { BaseType = Context.ObjCClassRedefinitionType; - ImpCastExprToType(BaseExpr, BaseType, CastExpr::CK_BitCast); + ImpCastExprToType(BaseExpr, BaseType, CK_BitCast); } if (IsArrow) { @@ -3129,12 +3227,11 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // down the context as argument to this routine. Ideally, this context // need be passed down in the AST node and somehow calculated from the // AST for a function decl. - Decl *ImplDecl = ObjCImpDecl.getAs(); if (ObjCImplementationDecl *IMPD = - dyn_cast(ImplDecl)) + dyn_cast(ObjCImpDecl)) ClassOfMethodDecl = IMPD->getClassInterface(); else if (ObjCCategoryImplDecl* CatImplClass = - dyn_cast(ImplDecl)) + dyn_cast(ObjCImpDecl)) ClassOfMethodDecl = CatImplClass->getClassInterface(); } @@ -3235,12 +3332,12 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, /// \param ObjCImpDecl the current ObjC @implementation decl; /// this is an ugly hack around the fact that ObjC @implementations /// aren't properly put in the context chain -Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, +ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, UnqualifiedId &Id, - DeclPtrTy ObjCImpDecl, + Decl *ObjCImpDecl, bool HasTrailingLParen) { if (SS.isSet() && SS.isInvalid()) return ExprError(); @@ -3248,12 +3345,12 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, TemplateArgumentListInfo TemplateArgsBuffer; // Decompose the name into its component parts. - DeclarationName Name; - SourceLocation NameLoc; + DeclarationNameInfo NameInfo; const TemplateArgumentListInfo *TemplateArgs; DecomposeUnqualifiedId(*this, Id, TemplateArgsBuffer, - Name, NameLoc, TemplateArgs); + NameInfo, TemplateArgs); + DeclarationName Name = NameInfo.getName(); bool IsArrow = (OpKind == tok::arrow); NamedDecl *FirstQualifierInScope @@ -3261,19 +3358,18 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, static_cast(SS.getScopeRep()))); // This is a postfix expression, so get rid of ParenListExprs. - BaseArg = MaybeConvertParenListExprToParenExpr(S, move(BaseArg)); + ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base); + if (Result.isInvalid()) return ExprError(); + Base = Result.take(); - Expr *Base = BaseArg.takeAs(); - OwningExprResult Result(*this); if (Base->getType()->isDependentType() || Name.isDependentName() || isDependentScopeSpecifier(SS)) { - Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(), + Result = ActOnDependentMemberExpr(Base, Base->getType(), IsArrow, OpLoc, SS, FirstQualifierInScope, - Name, NameLoc, - TemplateArgs); + NameInfo, TemplateArgs); } else { - LookupResult R(*this, Name, NameLoc, LookupMemberName); + LookupResult R(*this, NameInfo, LookupMemberName); Result = LookupMemberExpr(R, Base, IsArrow, OpLoc, SS, ObjCImpDecl, TemplateArgs != 0); @@ -3289,12 +3385,12 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, // call now. if (!HasTrailingLParen && Id.getKind() == UnqualifiedId::IK_DestructorName) - return DiagnoseDtorReference(NameLoc, move(Result)); + return DiagnoseDtorReference(NameInfo.getLoc(), Result.get()); return move(Result); } - Result = BuildMemberReferenceExpr(ExprArg(*this, Base), Base->getType(), + Result = BuildMemberReferenceExpr(Base, Base->getType(), OpLoc, IsArrow, SS, FirstQualifierInScope, R, TemplateArgs); } @@ -3302,7 +3398,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg, return move(Result); } -Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, +ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param) { if (Param->hasUnparsedDefaultArg()) { @@ -3324,7 +3420,7 @@ Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, InstantiatingTemplate Inst(*this, CallLoc, Param, Innermost.first, Innermost.second); - OwningExprResult Result = SubstExpr(UninstExpr, ArgList); + ExprResult Result = SubstExpr(UninstExpr, ArgList); if (Result.isInvalid()) return ExprError(); @@ -3338,7 +3434,7 @@ Sema::OwningExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1); Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, (void**)&ResultE, 1)); + MultiExprArg(*this, &ResultE, 1)); if (Result.isInvalid()) return ExprError(); @@ -3457,7 +3553,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, InitializedEntity Entity = Param? InitializedEntity::InitializeParameter(Param) : InitializedEntity::InitializeParameter(ProtoArgType); - OwningExprResult ArgE = PerformCopyInitialization(Entity, + ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), Owned(Arg)); if (ArgE.isInvalid()) @@ -3467,7 +3563,7 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, } else { ParmVarDecl *Param = FDecl->getParamDecl(i); - OwningExprResult ArgExpr = + ExprResult ArgExpr = BuildCXXDefaultArgExpr(CallLoc, FDecl, Param); if (ArgExpr.isInvalid()) return true; @@ -3492,18 +3588,18 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. -Action::OwningExprResult -Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, +ExprResult +Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg args, SourceLocation *CommaLocs, SourceLocation RParenLoc) { unsigned NumArgs = args.size(); // Since this might be a postfix expression, get rid of ParenListExprs. - fn = MaybeConvertParenListExprToParenExpr(S, move(fn)); + ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Fn); + if (Result.isInvalid()) return ExprError(); + Fn = Result.take(); - Expr *Fn = fn.takeAs(); - Expr **Args = reinterpret_cast(args.release()); - assert(Fn && "no function call expression"); + Expr **Args = args.release(); if (getLangOptions().CPlusPlus) { // If this is a pseudo-destructor expression, build the call immediately. @@ -3515,9 +3611,6 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, SourceRange(Args[0]->getLocStart(), Args[NumArgs-1]->getLocEnd())); - for (unsigned I = 0; I != NumArgs; ++I) - Args[I]->Destroy(Context); - NumArgs = 0; } @@ -3572,27 +3665,27 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, // Determine whether this is a call to a pointer-to-member function. if (BinaryOperator *BO = dyn_cast(NakedFn)) { - if (BO->getOpcode() == BinaryOperator::PtrMemD || - BO->getOpcode() == BinaryOperator::PtrMemI) { + if (BO->getOpcode() == BO_PtrMemD || + BO->getOpcode() == BO_PtrMemI) { if (const FunctionProtoType *FPT = BO->getType()->getAs()) { QualType ResultTy = FPT->getCallResultType(Context); - ExprOwningPtr - TheCall(this, new (Context) CXXMemberCallExpr(Context, BO, Args, - NumArgs, ResultTy, - RParenLoc)); + CXXMemberCallExpr *TheCall + = new (Context) CXXMemberCallExpr(Context, BO, Args, + NumArgs, ResultTy, + RParenLoc); if (CheckCallReturnType(FPT->getResultType(), BO->getRHS()->getSourceRange().getBegin(), - TheCall.get(), 0)) + TheCall, 0)) return ExprError(); - if (ConvertArgumentsForCall(&*TheCall, BO, 0, FPT, Args, NumArgs, + if (ConvertArgumentsForCall(TheCall, BO, 0, FPT, Args, NumArgs, RParenLoc)) return ExprError(); - return Owned(MaybeBindToTemporary(TheCall.release()).release()); + return MaybeBindToTemporary(TheCall); } return ExprError(Diag(Fn->getLocStart(), diag::err_typecheck_call_not_function) @@ -3625,7 +3718,7 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc, /// block-pointer type. /// /// \param NDecl the declaration being called, if available -Sema::OwningExprResult +ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -3637,10 +3730,10 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // Make the call expr early, before semantic checks. This guarantees cleanup // of arguments and function on error. - ExprOwningPtr TheCall(this, new (Context) CallExpr(Context, Fn, - Args, NumArgs, - Context.BoolTy, - RParenLoc)); + CallExpr *TheCall = new (Context) CallExpr(Context, Fn, + Args, NumArgs, + Context.BoolTy, + RParenLoc); const FunctionType *FuncT; if (!Fn->getType()->isBlockPointerType()) { @@ -3661,7 +3754,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // Check for a valid return type if (CheckCallReturnType(FuncT->getResultType(), - Fn->getSourceRange().getBegin(), TheCall.get(), + Fn->getSourceRange().getBegin(), TheCall, FDecl)) return ExprError(); @@ -3669,7 +3762,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, TheCall->setType(FuncT->getCallResultType(Context)); if (const FunctionProtoType *Proto = dyn_cast(FuncT)) { - if (ConvertArgumentsForCall(&*TheCall, Fn, FDecl, Proto, Args, NumArgs, + if (ConvertArgumentsForCall(TheCall, Fn, FDecl, Proto, Args, NumArgs, RParenLoc)) return ExprError(); } else { @@ -3713,22 +3806,22 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, // Do special checking on direct calls to functions. if (FDecl) { - if (CheckFunctionCall(FDecl, TheCall.get())) + if (CheckFunctionCall(FDecl, TheCall)) return ExprError(); if (unsigned BuiltinID = FDecl->getBuiltinID()) - return CheckBuiltinFunctionCall(BuiltinID, TheCall.take()); + return CheckBuiltinFunctionCall(BuiltinID, TheCall); } else if (NDecl) { - if (CheckBlockCall(NDecl, TheCall.get())) + if (CheckBlockCall(NDecl, TheCall)) return ExprError(); } - return MaybeBindToTemporary(TheCall.take()); + return MaybeBindToTemporary(TheCall); } -Action::OwningExprResult -Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, - SourceLocation RParenLoc, ExprArg InitExpr) { +ExprResult +Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty, + SourceLocation RParenLoc, Expr *InitExpr) { assert((Ty != 0) && "ActOnCompoundLiteral(): missing type"); // FIXME: put back this assert when initializers are worked out. //assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression"); @@ -3738,14 +3831,13 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(literalType); - return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, move(InitExpr)); + return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, InitExpr); } -Action::OwningExprResult +ExprResult Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, - SourceLocation RParenLoc, ExprArg InitExpr) { + SourceLocation RParenLoc, Expr *literalExpr) { QualType literalType = TInfo->getType(); - Expr *literalExpr = static_cast(InitExpr.get()); if (literalType->isArrayType()) { if (literalType->isVariableArrayType()) @@ -3764,13 +3856,12 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, = InitializationKind::CreateCast(SourceRange(LParenLoc, RParenLoc), /*IsCStyleCast=*/true); InitializationSequence InitSeq(*this, Entity, Kind, &literalExpr, 1); - OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, (void**)&literalExpr, 1), + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, &literalExpr, 1), &literalType); if (Result.isInvalid()) return ExprError(); - InitExpr.release(); - literalExpr = static_cast(Result.get()); + literalExpr = Result.get(); bool isFileScope = getCurFunctionOrMethodDecl() == 0; if (isFileScope) { // 6.5.2.5p3 @@ -3778,17 +3869,15 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, return ExprError(); } - Result.release(); - return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, literalExpr, isFileScope)); } -Action::OwningExprResult +ExprResult Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, SourceLocation RBraceLoc) { unsigned NumInit = initlist.size(); - Expr **InitList = reinterpret_cast(initlist.release()); + Expr **InitList = initlist.release(); // Semantic analysis for initializers is done by ActOnDeclarator() and // CheckInitializer() - it requires knowledge of the object being intialized. @@ -3799,45 +3888,45 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, return Owned(E); } -static CastExpr::CastKind getScalarCastKind(ASTContext &Context, +static CastKind getScalarCastKind(ASTContext &Context, QualType SrcTy, QualType DestTy) { if (Context.hasSameUnqualifiedType(SrcTy, DestTy)) - return CastExpr::CK_NoOp; + return CK_NoOp; if (SrcTy->hasPointerRepresentation()) { if (DestTy->hasPointerRepresentation()) return DestTy->isObjCObjectPointerType() ? - CastExpr::CK_AnyPointerToObjCPointerCast : - CastExpr::CK_BitCast; + CK_AnyPointerToObjCPointerCast : + CK_BitCast; if (DestTy->isIntegerType()) - return CastExpr::CK_PointerToIntegral; + return CK_PointerToIntegral; } if (SrcTy->isIntegerType()) { if (DestTy->isIntegerType()) - return CastExpr::CK_IntegralCast; + return CK_IntegralCast; if (DestTy->hasPointerRepresentation()) - return CastExpr::CK_IntegralToPointer; + return CK_IntegralToPointer; if (DestTy->isRealFloatingType()) - return CastExpr::CK_IntegralToFloating; + return CK_IntegralToFloating; } if (SrcTy->isRealFloatingType()) { if (DestTy->isRealFloatingType()) - return CastExpr::CK_FloatingCast; + return CK_FloatingCast; if (DestTy->isIntegerType()) - return CastExpr::CK_FloatingToIntegral; + return CK_FloatingToIntegral; } // FIXME: Assert here. // assert(false && "Unhandled cast combination!"); - return CastExpr::CK_Unknown; + return CK_Unknown; } /// CheckCastTypes - Check type constraints for casting between types. bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, - CastExpr::CastKind& Kind, - CXXBaseSpecifierArray &BasePath, + CastKind& Kind, + CXXCastPath &BasePath, bool FunctionalStyle) { if (getLangOptions().CPlusPlus) return CXXCheckCStyleCast(TyR, castType, castExpr, Kind, BasePath, @@ -3849,10 +3938,14 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, // type needs to be scalar. if (castType->isVoidType()) { // Cast to void allows any expr type. - Kind = CastExpr::CK_ToVoid; + Kind = CK_ToVoid; return false; } + if (RequireCompleteType(TyR.getBegin(), castType, + diag::err_typecheck_cast_to_incomplete)) + return true; + if (!castType->isScalarType() && !castType->isVectorType()) { if (Context.hasSameUnqualifiedType(castType, castExpr->getType()) && (castType->isStructureType() || castType->isUnionType())) { @@ -3860,7 +3953,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, // FIXME: Check that the cast destination type is complete. Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar) << castType << castExpr->getSourceRange(); - Kind = CastExpr::CK_NoOp; + Kind = CK_NoOp; return false; } @@ -3880,7 +3973,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, if (Field == FieldEnd) return Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type) << castExpr->getType() << castExpr->getSourceRange(); - Kind = CastExpr::CK_ToUnion; + Kind = CK_ToUnion; return false; } @@ -3922,11 +4015,15 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Expr *&castExpr, } Kind = getScalarCastKind(Context, castExpr->getType(), castType); + + if (Kind == CK_Unknown || Kind == CK_BitCast) + CheckCastAlign(castExpr, castType, TyR); + return false; } bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, - CastExpr::CastKind &Kind) { + CastKind &Kind) { assert(VectorTy->isVectorType() && "Not a vector type!"); if (Ty->isVectorType() || Ty->isIntegerType()) { @@ -3941,12 +4038,12 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, diag::err_invalid_conversion_between_vector_and_scalar) << VectorTy << Ty << R; - Kind = CastExpr::CK_BitCast; + Kind = CK_BitCast; return false; } bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, - CastExpr::CastKind &Kind) { + CastKind &Kind) { assert(DestTy->isExtVectorType() && "Not an extended vector type!"); QualType SrcTy = CastExpr->getType(); @@ -3957,7 +4054,7 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy)) return Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors) << DestTy << SrcTy << R; - Kind = CastExpr::CK_BitCast; + Kind = CK_BitCast; return false; } @@ -3973,14 +4070,14 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, ImpCastExprToType(CastExpr, DestElemTy, getScalarCastKind(Context, SrcTy, DestElemTy)); - Kind = CastExpr::CK_VectorSplat; + Kind = CK_VectorSplat; return false; } -Action::OwningExprResult -Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, - SourceLocation RParenLoc, ExprArg Op) { - assert((Ty != 0) && (Op.get() != 0) && +ExprResult +Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, ParsedType Ty, + SourceLocation RParenLoc, Expr *castExpr) { + assert((Ty != 0) && (castExpr != 0) && "ActOnCastExpr(): missing type or expr"); TypeSourceInfo *castTInfo; @@ -3989,55 +4086,52 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty, castTInfo = Context.getTrivialTypeSourceInfo(castType); // If the Expr being casted is a ParenListExpr, handle it specially. - Expr *castExpr = (Expr *)Op.get(); if (isa(castExpr)) - return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op), + return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, castExpr, castTInfo); - return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, move(Op)); + return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, castExpr); } -Action::OwningExprResult +ExprResult Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, - SourceLocation RParenLoc, ExprArg Op) { - Expr *castExpr = static_cast(Op.get()); - - CastExpr::CastKind Kind = CastExpr::CK_Unknown; - CXXBaseSpecifierArray BasePath; + SourceLocation RParenLoc, Expr *castExpr) { + CastKind Kind = CK_Unknown; + CXXCastPath BasePath; if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr, Kind, BasePath)) return ExprError(); - Op.release(); - return Owned(new (Context) CStyleCastExpr( + return Owned(CStyleCastExpr::Create(Context, Ty->getType().getNonLValueExprType(Context), - Kind, castExpr, BasePath, Ty, - LParenLoc, RParenLoc)); + Kind, castExpr, &BasePath, Ty, + LParenLoc, RParenLoc)); } /// This is not an AltiVec-style cast, so turn the ParenListExpr into a sequence /// of comma binary operators. -Action::OwningExprResult -Sema::MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg EA) { - Expr *expr = EA.takeAs(); +ExprResult +Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *expr) { ParenListExpr *E = dyn_cast(expr); if (!E) return Owned(expr); - OwningExprResult Result(*this, E->getExpr(0)); + ExprResult Result(E->getExpr(0)); for (unsigned i = 1, e = E->getNumExprs(); i != e && !Result.isInvalid(); ++i) - Result = ActOnBinOp(S, E->getExprLoc(), tok::comma, move(Result), - Owned(E->getExpr(i))); + Result = ActOnBinOp(S, E->getExprLoc(), tok::comma, Result.get(), + E->getExpr(i)); - return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), move(Result)); + if (Result.isInvalid()) return ExprError(); + + return ActOnParenExpr(E->getLParenLoc(), E->getRParenLoc(), Result.get()); } -Action::OwningExprResult +ExprResult Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, - SourceLocation RParenLoc, ExprArg Op, + SourceLocation RParenLoc, Expr *Op, TypeSourceInfo *TInfo) { - ParenListExpr *PE = (ParenListExpr *)Op.get(); + ParenListExpr *PE = cast(Op); QualType Ty = TInfo->getType(); bool isAltiVecLiteral = false; @@ -4065,24 +4159,24 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, // FIXME: This means that pretty-printing the final AST will produce curly // braces instead of the original commas. - Op.release(); InitListExpr *E = new (Context) InitListExpr(Context, LParenLoc, &initExprs[0], initExprs.size(), RParenLoc); E->setType(Ty); - return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, Owned(E)); + return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, E); } else { // This is not an AltiVec-style cast, so turn the ParenListExpr into a // sequence of BinOp comma operators. - Op = MaybeConvertParenListExprToParenExpr(S, move(Op)); - return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, move(Op)); + ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Op); + if (Result.isInvalid()) return ExprError(); + return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Result.take()); } } -Action::OwningExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L, +ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L, SourceLocation R, MultiExprArg Val, - TypeTy *TypeOfCast) { + ParsedType TypeOfCast) { unsigned nexprs = Val.size(); Expr **exprs = reinterpret_cast(Val.release()); assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list"); @@ -4148,8 +4242,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (!RHSTy->isVoidType()) Diag(LHS->getLocStart(), diag::ext_typecheck_cond_one_void) << LHS->getSourceRange(); - ImpCastExprToType(LHS, Context.VoidTy, CastExpr::CK_ToVoid); - ImpCastExprToType(RHS, Context.VoidTy, CastExpr::CK_ToVoid); + ImpCastExprToType(LHS, Context.VoidTy, CK_ToVoid); + ImpCastExprToType(RHS, Context.VoidTy, CK_ToVoid); return Context.VoidTy; } // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has @@ -4157,12 +4251,12 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) && RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { // promote the null to a pointer. - ImpCastExprToType(RHS, LHSTy, CastExpr::CK_Unknown); + ImpCastExprToType(RHS, LHSTy, CK_Unknown); return LHSTy; } if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) && LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(LHS, RHSTy, CastExpr::CK_Unknown); + ImpCastExprToType(LHS, RHSTy, CK_Unknown); return RHSTy; } @@ -4178,8 +4272,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) { QualType destType = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast); - ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); + ImpCastExprToType(LHS, destType, CK_BitCast); + ImpCastExprToType(RHS, destType, CK_BitCast); return destType; } Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) @@ -4203,13 +4297,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. QualType incompatTy = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast); - ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast); + ImpCastExprToType(LHS, incompatTy, CK_BitCast); + ImpCastExprToType(RHS, incompatTy, CK_BitCast); return incompatTy; } // The block pointer types are compatible. - ImpCastExprToType(LHS, LHSTy, CastExpr::CK_BitCast); - ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); + ImpCastExprToType(LHS, LHSTy, CK_BitCast); + ImpCastExprToType(RHS, LHSTy, CK_BitCast); return LHSTy; } @@ -4226,9 +4320,9 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); // Add qualifiers if necessary. - ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp); + ImpCastExprToType(LHS, destType, CK_NoOp); // Promote to void*. - ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, destType, CK_BitCast); return destType; } if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) { @@ -4236,9 +4330,9 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); // Add qualifiers if necessary. - ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp); + ImpCastExprToType(RHS, destType, CK_NoOp); // Promote to void*. - ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast); + ImpCastExprToType(LHS, destType, CK_BitCast); return destType; } @@ -4254,8 +4348,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. QualType incompatTy = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast); - ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast); + ImpCastExprToType(LHS, incompatTy, CK_BitCast); + ImpCastExprToType(RHS, incompatTy, CK_BitCast); return incompatTy; } // The pointer types are compatible. @@ -4265,8 +4359,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // type. // FIXME: Need to calculate the composite type. // FIXME: Need to add qualifiers - ImpCastExprToType(LHS, LHSTy, CastExpr::CK_BitCast); - ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); + ImpCastExprToType(LHS, LHSTy, CK_BitCast); + ImpCastExprToType(RHS, LHSTy, CK_BitCast); return LHSTy; } @@ -4274,13 +4368,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (RHSTy->isPointerType() && LHSTy->isIntegerType()) { Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); - ImpCastExprToType(LHS, RHSTy, CastExpr::CK_IntegralToPointer); + ImpCastExprToType(LHS, RHSTy, CK_IntegralToPointer); return RHSTy; } if (LHSTy->isPointerType() && RHSTy->isIntegerType()) { Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); - ImpCastExprToType(RHS, LHSTy, CastExpr::CK_IntegralToPointer); + ImpCastExprToType(RHS, LHSTy, CK_IntegralToPointer); return LHSTy; } @@ -4302,34 +4396,34 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, // redefinition type if an attempt is made to access its fields. if (LHSTy->isObjCClassType() && (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { - ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, LHSTy, CK_BitCast); return LHSTy; } if (RHSTy->isObjCClassType() && (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) { - ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); + ImpCastExprToType(LHS, RHSTy, CK_BitCast); return RHSTy; } // And the same for struct objc_object* / id if (LHSTy->isObjCIdType() && (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { - ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, LHSTy, CK_BitCast); return LHSTy; } if (RHSTy->isObjCIdType() && (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) { - ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); + ImpCastExprToType(LHS, RHSTy, CK_BitCast); return RHSTy; } // And the same for struct objc_selector* / SEL if (Context.isObjCSelType(LHSTy) && (RHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { - ImpCastExprToType(RHS, LHSTy, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, LHSTy, CK_BitCast); return LHSTy; } if (Context.isObjCSelType(RHSTy) && (LHSTy.getDesugaredType() == Context.ObjCSelRedefinitionType)) { - ImpCastExprToType(LHS, RHSTy, CastExpr::CK_BitCast); + ImpCastExprToType(LHS, RHSTy, CK_BitCast); return RHSTy; } // Check constraints for Objective-C object pointers types. @@ -4378,13 +4472,13 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); QualType incompatTy = Context.getObjCIdType(); - ImpCastExprToType(LHS, incompatTy, CastExpr::CK_BitCast); - ImpCastExprToType(RHS, incompatTy, CastExpr::CK_BitCast); + ImpCastExprToType(LHS, incompatTy, CK_BitCast); + ImpCastExprToType(RHS, incompatTy, CK_BitCast); return incompatTy; } // The object pointer types are compatible. - ImpCastExprToType(LHS, compositeType, CastExpr::CK_BitCast); - ImpCastExprToType(RHS, compositeType, CastExpr::CK_BitCast); + ImpCastExprToType(LHS, compositeType, CK_BitCast); + ImpCastExprToType(RHS, compositeType, CK_BitCast); return compositeType; } // Check Objective-C object pointer types and 'void *' @@ -4395,9 +4489,9 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); // Add qualifiers if necessary. - ImpCastExprToType(LHS, destType, CastExpr::CK_NoOp); + ImpCastExprToType(LHS, destType, CK_NoOp); // Promote to void*. - ImpCastExprToType(RHS, destType, CastExpr::CK_BitCast); + ImpCastExprToType(RHS, destType, CK_BitCast); return destType; } if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) { @@ -4407,9 +4501,9 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); // Add qualifiers if necessary. - ImpCastExprToType(RHS, destType, CastExpr::CK_NoOp); + ImpCastExprToType(RHS, destType, CK_NoOp); // Promote to void*. - ImpCastExprToType(LHS, destType, CastExpr::CK_BitCast); + ImpCastExprToType(LHS, destType, CK_BitCast); return destType; } return QualType(); @@ -4417,30 +4511,27 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null /// in the case of a the GNU conditional expr extension. -Action::OwningExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, +ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, SourceLocation ColonLoc, - ExprArg Cond, ExprArg LHS, - ExprArg RHS) { - Expr *CondExpr = (Expr *) Cond.get(); - Expr *LHSExpr = (Expr *) LHS.get(), *RHSExpr = (Expr *) RHS.get(); - + Expr *CondExpr, Expr *LHSExpr, + Expr *RHSExpr) { // If this is the gnu "x ?: y" extension, analyze the types as though the LHS // was the condition. bool isLHSNull = LHSExpr == 0; - if (isLHSNull) - LHSExpr = CondExpr; + Expr *SAVEExpr = 0; + if (isLHSNull) { + LHSExpr = SAVEExpr = CondExpr; + } QualType result = CheckConditionalOperands(CondExpr, LHSExpr, RHSExpr, QuestionLoc); if (result.isNull()) return ExprError(); - Cond.release(); - LHS.release(); - RHS.release(); return Owned(new (Context) ConditionalOperator(CondExpr, QuestionLoc, - isLHSNull ? 0 : LHSExpr, - ColonLoc, RHSExpr, result)); + LHSExpr, ColonLoc, + RHSExpr, SAVEExpr, + result)); } // CheckPointerTypesForAssignment - This is a very tricky routine (despite @@ -4506,12 +4597,12 @@ Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) { // "unsigned char" on systems where "char" is unsigned. if (lhptee->isCharType()) lhptee = Context.UnsignedCharTy; - else if (lhptee->isSignedIntegerType()) + else if (lhptee->hasSignedIntegerRepresentation()) lhptee = Context.getCorrespondingUnsignedType(lhptee); if (rhptee->isCharType()) rhptee = Context.UnsignedCharTy; - else if (rhptee->isSignedIntegerType()) + else if (rhptee->hasSignedIntegerRepresentation()) rhptee = Context.getCorrespondingUnsignedType(rhptee); if (lhptee == rhptee) { @@ -4668,13 +4759,18 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) { } if (lhsType->isVectorType() || rhsType->isVectorType()) { - // If we are allowing lax vector conversions, and LHS and RHS are both - // vectors, the total size only needs to be the same. This is a bitcast; - // no bits are changed but the result type is different. - if (getLangOptions().LaxVectorConversions && - lhsType->isVectorType() && rhsType->isVectorType()) { - if (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType)) + if (lhsType->isVectorType() && rhsType->isVectorType()) { + // If we are allowing lax vector conversions, and LHS and RHS are both + // vectors, the total size only needs to be the same. This is a bitcast; + // no bits are changed but the result type is different. + if (getLangOptions().LaxVectorConversions && + (Context.getTypeSize(lhsType) == Context.getTypeSize(rhsType))) return IncompatibleVectors; + + // Allow assignments of an AltiVec vector type to an equivalent GCC + // vector type and vice versa + if (Context.areCompatibleVectorTypes(lhsType, rhsType)) + return Compatible; } return Incompatible; } @@ -4832,14 +4928,14 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) { // 2) null pointer constant if (FromType->isPointerType()) if (FromType->getAs()->getPointeeType()->isVoidType()) { - ImpCastExprToType(rExpr, it->getType(), CastExpr::CK_BitCast); + ImpCastExprToType(rExpr, it->getType(), CK_BitCast); InitField = *it; break; } if (rExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(rExpr, it->getType(), CastExpr::CK_IntegralToPointer); + ImpCastExprToType(rExpr, it->getType(), CK_IntegralToPointer); InitField = *it; break; } @@ -4883,14 +4979,14 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { lhsType->isBlockPointerType()) && rExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(rExpr, lhsType, CastExpr::CK_Unknown); + ImpCastExprToType(rExpr, lhsType, CK_Unknown); return Compatible; } // This check seems unnatural, however it is necessary to ensure the proper // conversion of functions/arrays. If the conversion were done for all // DeclExpr's (created by ActOnIdExpression), it would mess up the unary - // expressions that surpress this implicit conversion (&, sizeof). + // expressions that suppress this implicit conversion (&, sizeof). // // Suppress this for references: C++ 8.5.3p5. if (!lhsType->isReferenceType()) @@ -4907,7 +5003,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // does not have reference type. if (result != Incompatible && rExpr->getType() != lhsType) ImpCastExprToType(rExpr, lhsType.getNonLValueExprType(Context), - CastExpr::CK_Unknown); + CK_Unknown); return result; } @@ -4933,22 +5029,35 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { // Handle the case of a vector & extvector type of the same size and element // type. It would be nice if we only had one vector type someday. if (getLangOptions().LaxVectorConversions) { - // FIXME: Should we warn here? if (const VectorType *LV = lhsType->getAs()) { - if (const VectorType *RV = rhsType->getAs()) + if (const VectorType *RV = rhsType->getAs()) { if (LV->getElementType() == RV->getElementType() && LV->getNumElements() == RV->getNumElements()) { if (lhsType->isExtVectorType()) { - ImpCastExprToType(rex, lhsType, CastExpr::CK_BitCast); + ImpCastExprToType(rex, lhsType, CK_BitCast); return lhsType; } - ImpCastExprToType(lex, rhsType, CastExpr::CK_BitCast); + ImpCastExprToType(lex, rhsType, CK_BitCast); return rhsType; + } else if (Context.getTypeSize(lhsType) ==Context.getTypeSize(rhsType)){ + // If we are allowing lax vector conversions, and LHS and RHS are both + // vectors, the total size only needs to be the same. This is a + // bitcast; no bits are changed but the result type is different. + ImpCastExprToType(rex, lhsType, CK_BitCast); + return lhsType; } + } } } + // Handle the case of equivalent AltiVec and GCC vector types + if (lhsType->isVectorType() && rhsType->isVectorType() && + Context.areCompatibleVectorTypes(lhsType, rhsType)) { + ImpCastExprToType(lex, rhsType, CK_BitCast); + return rhsType; + } + // Canonicalize the ExtVector to the LHS, remember if we swapped so we can // swap back (so that we don't reverse the inputs to a subtract, for instance. bool swapped = false; @@ -4963,7 +5072,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { QualType EltTy = LV->getElementType(); if (EltTy->isIntegralType(Context) && rhsType->isIntegralType(Context)) { if (Context.getIntegerTypeOrder(EltTy, rhsType) >= 0) { - ImpCastExprToType(rex, lhsType, CastExpr::CK_IntegralCast); + ImpCastExprToType(rex, lhsType, CK_IntegralCast); if (swapped) std::swap(rex, lex); return lhsType; } @@ -4971,7 +5080,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { if (EltTy->isRealFloatingType() && rhsType->isScalarType() && rhsType->isRealFloatingType()) { if (Context.getFloatingTypeOrder(EltTy, rhsType) >= 0) { - ImpCastExprToType(rex, lhsType, CastExpr::CK_FloatingCast); + ImpCastExprToType(rex, lhsType, CK_FloatingCast); if (swapped) std::swap(rex, lex); return lhsType; } @@ -5008,7 +5117,8 @@ QualType Sema::CheckMultiplyDivideOperands( QualType Sema::CheckRemainderOperands( Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { - if (lex->getType()->isIntegerType() && rex->getType()->isIntegerType()) + if (lex->getType()->hasIntegerRepresentation() && + rex->getType()->hasIntegerRepresentation()) return CheckVectorOperands(Loc, lex, rex); return InvalidOperands(Loc, lex, rex); } @@ -5253,7 +5363,8 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { // C99 6.5.7p2: Each of the operands shall have integer type. - if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType()) + if (!lex->getType()->hasIntegerRepresentation() || + !rex->getType()->hasIntegerRepresentation()) return InvalidOperands(Loc, lex, rex); // Vector shifts promote their scalar inputs to vector type. @@ -5269,7 +5380,7 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, LHSTy = Context.getPromotedIntegerType(LHSTy); } if (!isCompAssign) - ImpCastExprToType(lex, LHSTy, CastExpr::CK_IntegralCast); + ImpCastExprToType(lex, LHSTy, CK_IntegralCast); UsualUnaryConversions(rex); @@ -5305,7 +5416,7 @@ static bool IsWithinTemplateSpecialization(Decl *D) { // C99 6.5.8, C++ [expr.rel] QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, unsigned OpaqueOpc, bool isRelational) { - BinaryOperator::Opcode Opc = (BinaryOperator::Opcode)OpaqueOpc; + BinaryOperatorKind Opc = (BinaryOperatorKind) OpaqueOpc; // Handle vector comparisons separately. if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) @@ -5334,19 +5445,19 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, !IsWithinTemplateSpecialization(DRL->getDecl())) { DiagRuntimeBehavior(Loc, PDiag(diag::warn_comparison_always) << 0 // self- - << (Opc == BinaryOperator::EQ - || Opc == BinaryOperator::LE - || Opc == BinaryOperator::GE)); + << (Opc == BO_EQ + || Opc == BO_LE + || Opc == BO_GE)); } else if (lType->isArrayType() && rType->isArrayType() && !DRL->getDecl()->getType()->isReferenceType() && !DRR->getDecl()->getType()->isReferenceType()) { // what is it always going to eval to? char always_evals_to; switch(Opc) { - case BinaryOperator::EQ: // e.g. array1 == array2 + case BO_EQ: // e.g. array1 == array2 always_evals_to = 0; // false break; - case BinaryOperator::NE: // e.g. array1 != array2 + case BO_NE: // e.g. array1 != array2 always_evals_to = 1; // true break; default: @@ -5386,12 +5497,12 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (literalString) { std::string resultComparison; switch (Opc) { - case BinaryOperator::LT: resultComparison = ") < 0"; break; - case BinaryOperator::GT: resultComparison = ") > 0"; break; - case BinaryOperator::LE: resultComparison = ") <= 0"; break; - case BinaryOperator::GE: resultComparison = ") >= 0"; break; - case BinaryOperator::EQ: resultComparison = ") == 0"; break; - case BinaryOperator::NE: resultComparison = ") != 0"; break; + case BO_LT: resultComparison = ") < 0"; break; + case BO_GT: resultComparison = ") > 0"; break; + case BO_LE: resultComparison = ") <= 0"; break; + case BO_GE: resultComparison = ") >= 0"; break; + case BO_EQ: resultComparison = ") == 0"; break; + case BO_NE: resultComparison = ") != 0"; break; default: assert(false && "Invalid comparison operator"); } @@ -5461,7 +5572,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (isSFINAEContext()) return QualType(); - ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); + ImpCastExprToType(rex, lType, CK_BitCast); return ResultTy; } } @@ -5487,8 +5598,8 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(lex, T, CastExpr::CK_BitCast); - ImpCastExprToType(rex, T, CastExpr::CK_BitCast); + ImpCastExprToType(lex, T, CK_BitCast); + ImpCastExprToType(rex, T, CK_BitCast); return ResultTy; } // C99 6.5.9p2 and C99 6.5.8p2 @@ -5513,7 +5624,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } if (LCanPointeeTy != RCanPointeeTy) - ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); + ImpCastExprToType(rex, lType, CK_BitCast); return ResultTy; } @@ -5523,13 +5634,19 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (RHSIsNull && (lType->isPointerType() || (!isRelational && lType->isMemberPointerType()))) { - ImpCastExprToType(rex, lType, CastExpr::CK_NullToMemberPointer); + ImpCastExprToType(rex, lType, + lType->isMemberPointerType() + ? CK_NullToMemberPointer + : CK_IntegralToPointer); return ResultTy; } if (LHSIsNull && (rType->isPointerType() || (!isRelational && rType->isMemberPointerType()))) { - ImpCastExprToType(lex, rType, CastExpr::CK_NullToMemberPointer); + ImpCastExprToType(lex, rType, + rType->isMemberPointerType() + ? CK_NullToMemberPointer + : CK_IntegralToPointer); return ResultTy; } @@ -5560,8 +5677,8 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(lex, T, CastExpr::CK_BitCast); - ImpCastExprToType(rex, T, CastExpr::CK_BitCast); + ImpCastExprToType(lex, T, CK_BitCast); + ImpCastExprToType(rex, T, CK_BitCast); return ResultTy; } @@ -5580,7 +5697,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); + ImpCastExprToType(rex, lType, CK_BitCast); return ResultTy; } // Allow block pointers to be compared with null pointer constants. @@ -5595,7 +5712,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); + ImpCastExprToType(rex, lType, CK_BitCast); return ResultTy; } @@ -5613,14 +5730,14 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); } - ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); + ImpCastExprToType(rex, lType, CK_BitCast); return ResultTy; } if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) { if (!Context.areComparableObjCPointerTypes(lType, rType)) Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) << lType << rType << lex->getSourceRange() << rex->getSourceRange(); - ImpCastExprToType(rex, lType, CastExpr::CK_BitCast); + ImpCastExprToType(rex, lType, CK_BitCast); return ResultTy; } } @@ -5648,21 +5765,21 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, } if (lType->isIntegerType()) - ImpCastExprToType(lex, rType, CastExpr::CK_IntegralToPointer); + ImpCastExprToType(lex, rType, CK_IntegralToPointer); else - ImpCastExprToType(rex, lType, CastExpr::CK_IntegralToPointer); + ImpCastExprToType(rex, lType, CK_IntegralToPointer); return ResultTy; } // Handle block pointers. if (!isRelational && RHSIsNull && lType->isBlockPointerType() && rType->isIntegerType()) { - ImpCastExprToType(rex, lType, CastExpr::CK_IntegralToPointer); + ImpCastExprToType(rex, lType, CK_IntegralToPointer); return ResultTy; } if (!isRelational && LHSIsNull && lType->isIntegerType() && rType->isBlockPointerType()) { - ImpCastExprToType(lex, rType, CastExpr::CK_IntegralToPointer); + ImpCastExprToType(lex, rType, CK_IntegralToPointer); return ResultTy; } return InvalidOperands(Loc, lex, rex); @@ -5707,7 +5824,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, // Return the type for the comparison, which is the same as vector type for // integer vectors, or an integer type of identical size and number of // elements for floating point vectors. - if (lType->isIntegerType()) + if (lType->hasIntegerRepresentation()) return lType; const VectorType *VTy = lType->getAs(); @@ -5724,8 +5841,13 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, inline QualType Sema::CheckBitwiseOperands( Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { - if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) - return CheckVectorOperands(Loc, lex, rex); + if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { + if (lex->getType()->hasIntegerRepresentation() && + rex->getType()->hasIntegerRepresentation()) + return CheckVectorOperands(Loc, lex, rex); + + return InvalidOperands(Loc, lex, rex); + } QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); @@ -5741,18 +5863,21 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] // bitwise one. We do this when the LHS is a non-bool integer and the RHS // is a constant. if (lex->getType()->isIntegerType() && !lex->getType()->isBooleanType() && - rex->getType()->isIntegerType() && rex->isEvaluatable(Context) && - // Don't warn if the RHS is a (constant folded) boolean expression like - // "sizeof(int) == 4". - !rex->isKnownToHaveBooleanValue() && + rex->getType()->isIntegerType() && !rex->isValueDependent() && // Don't warn in macros. - !Loc.isMacroID()) - Diag(Loc, diag::warn_logical_instead_of_bitwise) - << rex->getSourceRange() - << (Opc == BinaryOperator::LAnd ? "&&" : "||") - << (Opc == BinaryOperator::LAnd ? "&" : "|"); - - + !Loc.isMacroID()) { + // If the RHS can be constant folded, and if it constant folds to something + // that isn't 0 or 1 (which indicate a potential logical operation that + // happened to fold to true/false) then warn. + Expr::EvalResult Result; + if (rex->Evaluate(Result, Context) && !Result.HasSideEffects && + Result.Val.getInt() != 0 && Result.Val.getInt() != 1) { + Diag(Loc, diag::warn_logical_instead_of_bitwise) + << rex->getSourceRange() + << (Opc == BO_LAnd ? "&&" : "||") + << (Opc == BO_LAnd ? "&" : "|"); + } + } if (!Context.getLangOptions().CPlusPlus) { UsualUnaryConversions(lex); @@ -5907,8 +6032,8 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, if (ImplicitCastExpr *ICE = dyn_cast(RHSCheck)) RHSCheck = ICE->getSubExpr(); if (UnaryOperator *UO = dyn_cast(RHSCheck)) { - if ((UO->getOpcode() == UnaryOperator::Plus || - UO->getOpcode() == UnaryOperator::Minus) && + if ((UO->getOpcode() == UO_Plus || + UO->getOpcode() == UO_Minus) && Loc.isFileID() && UO->getOperatorLoc().isFileID() && // Only if the two operators are exactly adjacent. Loc.getFileLocWithOffset(1) == UO->getOperatorLoc() && @@ -5917,7 +6042,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, Loc.getFileLocWithOffset(2) != UO->getSubExpr()->getLocStart() && UO->getSubExpr()->getLocStart().isFileID()) { Diag(Loc, diag::warn_not_compound_assign) - << (UO->getOpcode() == UnaryOperator::Plus ? "+" : "-") + << (UO->getOpcode() == UO_Plus ? "+" : "-") << SourceRange(UO->getOperatorLoc(), UO->getOperatorLoc()); } } @@ -5938,7 +6063,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, // only handles the pattern "*null = whatever", which is a very syntactic // check. if (UnaryOperator *UO = dyn_cast(LHS->IgnoreParenCasts())) - if (UO->getOpcode() == UnaryOperator::Deref && + if (UO->getOpcode() == UO_Deref && UO->getSubExpr()->IgnoreParenCasts()-> isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) && !UO->getType().isVolatileQualified()) { @@ -6083,9 +6208,9 @@ static NamedDecl *getPrimaryDecl(Expr *E) { UnaryOperator *UO = cast(E); switch(UO->getOpcode()) { - case UnaryOperator::Real: - case UnaryOperator::Imag: - case UnaryOperator::Extension: + case UO_Real: + case UO_Imag: + case UO_Extension: return getPrimaryDecl(UO->getSubExpr()); default: return 0; @@ -6109,17 +6234,19 @@ static NamedDecl *getPrimaryDecl(Expr *E) { /// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue. /// In C++, the operand might be an overloaded function name, in which case /// we allow the '&' but retain the overloaded-function type. -QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { - // Make sure to ignore parentheses in subsequent checks - op = op->IgnoreParens(); - - if (op->isTypeDependent()) +QualType Sema::CheckAddressOfOperand(Expr *OrigOp, SourceLocation OpLoc) { + if (OrigOp->isTypeDependent()) return Context.DependentTy; + if (OrigOp->getType() == Context.OverloadTy) + return Context.OverloadTy; + + // Make sure to ignore parentheses in subsequent checks + Expr *op = OrigOp->IgnoreParens(); if (getLangOptions().C99) { // Implement C99-only parts of addressof rules. if (UnaryOperator* uOp = dyn_cast(op)) { - if (uOp->getOpcode() == UnaryOperator::Deref) + if (uOp->getOpcode() == UO_Deref) // Per C99 6.5.3.2, the address of a deref always returns a valid result // (assuming the deref expression is valid). return uOp->getSubExpr()->getType(); @@ -6130,32 +6257,41 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { NamedDecl *dcl = getPrimaryDecl(op); Expr::isLvalueResult lval = op->isLvalue(Context); - MemberExpr *ME = dyn_cast(op); - if (lval == Expr::LV_MemberFunction && ME && - isa(ME->getMemberDecl())) { - ValueDecl *dcl = cast(op)->getMemberDecl(); - // &f where f is a member of the current object, or &o.f, or &p->f - // All these are not allowed, and we need to catch them before the dcl - // branch of the if, below. - Diag(OpLoc, diag::err_unqualified_pointer_member_function) - << dcl; - // FIXME: Improve this diagnostic and provide a fixit. - - // Now recover by acting as if the function had been accessed qualified. - return Context.getMemberPointerType(op->getType(), - Context.getTypeDeclType(cast(dcl->getDeclContext())) - .getTypePtr()); - } - if (lval == Expr::LV_ClassTemporary) { Diag(OpLoc, isSFINAEContext()? diag::err_typecheck_addrof_class_temporary : diag::ext_typecheck_addrof_class_temporary) << op->getType() << op->getSourceRange(); if (isSFINAEContext()) return QualType(); - } else if (isa(op)) + } else if (isa(op)) { return Context.getPointerType(op->getType()); - else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) { + } else if (lval == Expr::LV_MemberFunction) { + // If it's an instance method, make a member pointer. + // The expression must have exactly the form &A::foo. + + // If the underlying expression isn't a decl ref, give up. + if (!isa(op)) { + Diag(OpLoc, diag::err_invalid_form_pointer_member_function) + << OrigOp->getSourceRange(); + return QualType(); + } + DeclRefExpr *DRE = cast(op); + CXXMethodDecl *MD = cast(DRE->getDecl()); + + // The id-expression was parenthesized. + if (OrigOp != DRE) { + Diag(OpLoc, diag::err_parens_pointer_member_function) + << OrigOp->getSourceRange(); + + // The method was named without a qualifier. + } else if (!DRE->getQualifier()) { + Diag(OpLoc, diag::err_unqualified_pointer_member_function) + << op->getSourceRange(); + } + + return Context.getMemberPointerType(op->getType(), + Context.getTypeDeclType(MD->getParent()).getTypePtr()); + } else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) { // C99 6.5.3.2p1 // The operand must be either an l-value or a function designator if (!op->getType()->isFunctionType()) { @@ -6183,13 +6319,14 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { // FIXME: Can LHS ever be null here? if (!CheckAddressOfOperand(CO->getTrueExpr(), OpLoc).isNull()) return CheckAddressOfOperand(CO->getFalseExpr(), OpLoc); - } else if (isa(op)) { - return Context.OverloadTy; } else if (dcl) { // C99 6.5.3.2p1 // We have an lvalue with a decl. Make sure the decl is not declared // with the register storage-class specifier. if (const VarDecl *vd = dyn_cast(dcl)) { - if (vd->getStorageClass() == VarDecl::Register) { + // in C++ it is not error to take address of a register + // variable (c++03 7.1.1P3) + if (vd->getStorageClass() == SC_Register && + !getLangOptions().CPlusPlus) { Diag(OpLoc, diag::err_typecheck_address_of) << "register variable" << op->getSourceRange(); return QualType(); @@ -6214,13 +6351,6 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { Context.getTypeDeclType(cast(Ctx)).getTypePtr()); } } - } else if (CXXMethodDecl *MD = dyn_cast(dcl)) { - // Okay: we can take the address of a function. - // As above. - if (isa(op) && cast(op)->getQualifier() && - MD->isInstance()) - return Context.getMemberPointerType(op->getType(), - Context.getTypeDeclType(MD->getParent()).getTypePtr()); } else if (!isa(dcl)) assert(0 && "Unknown/unexpected decl type"); } @@ -6233,6 +6363,8 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { } // If the operand has type "type", the result has type "pointer to type". + if (op->getType()->isObjCObjectType()) + return Context.getObjCObjectPointerType(op->getType()); return Context.getPointerType(op->getType()); } @@ -6264,63 +6396,63 @@ QualType Sema::CheckIndirectionOperand(Expr *Op, SourceLocation OpLoc) { return Result; } -static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode( +static inline BinaryOperatorKind ConvertTokenKindToBinaryOpcode( tok::TokenKind Kind) { - BinaryOperator::Opcode Opc; + BinaryOperatorKind Opc; switch (Kind) { default: assert(0 && "Unknown binop!"); - case tok::periodstar: Opc = BinaryOperator::PtrMemD; break; - case tok::arrowstar: Opc = BinaryOperator::PtrMemI; break; - case tok::star: Opc = BinaryOperator::Mul; break; - case tok::slash: Opc = BinaryOperator::Div; break; - case tok::percent: Opc = BinaryOperator::Rem; break; - case tok::plus: Opc = BinaryOperator::Add; break; - case tok::minus: Opc = BinaryOperator::Sub; break; - case tok::lessless: Opc = BinaryOperator::Shl; break; - case tok::greatergreater: Opc = BinaryOperator::Shr; break; - case tok::lessequal: Opc = BinaryOperator::LE; break; - case tok::less: Opc = BinaryOperator::LT; break; - case tok::greaterequal: Opc = BinaryOperator::GE; break; - case tok::greater: Opc = BinaryOperator::GT; break; - case tok::exclaimequal: Opc = BinaryOperator::NE; break; - case tok::equalequal: Opc = BinaryOperator::EQ; break; - case tok::amp: Opc = BinaryOperator::And; break; - case tok::caret: Opc = BinaryOperator::Xor; break; - case tok::pipe: Opc = BinaryOperator::Or; break; - case tok::ampamp: Opc = BinaryOperator::LAnd; break; - case tok::pipepipe: Opc = BinaryOperator::LOr; break; - case tok::equal: Opc = BinaryOperator::Assign; break; - case tok::starequal: Opc = BinaryOperator::MulAssign; break; - case tok::slashequal: Opc = BinaryOperator::DivAssign; break; - case tok::percentequal: Opc = BinaryOperator::RemAssign; break; - case tok::plusequal: Opc = BinaryOperator::AddAssign; break; - case tok::minusequal: Opc = BinaryOperator::SubAssign; break; - case tok::lesslessequal: Opc = BinaryOperator::ShlAssign; break; - case tok::greatergreaterequal: Opc = BinaryOperator::ShrAssign; break; - case tok::ampequal: Opc = BinaryOperator::AndAssign; break; - case tok::caretequal: Opc = BinaryOperator::XorAssign; break; - case tok::pipeequal: Opc = BinaryOperator::OrAssign; break; - case tok::comma: Opc = BinaryOperator::Comma; break; + case tok::periodstar: Opc = BO_PtrMemD; break; + case tok::arrowstar: Opc = BO_PtrMemI; break; + case tok::star: Opc = BO_Mul; break; + case tok::slash: Opc = BO_Div; break; + case tok::percent: Opc = BO_Rem; break; + case tok::plus: Opc = BO_Add; break; + case tok::minus: Opc = BO_Sub; break; + case tok::lessless: Opc = BO_Shl; break; + case tok::greatergreater: Opc = BO_Shr; break; + case tok::lessequal: Opc = BO_LE; break; + case tok::less: Opc = BO_LT; break; + case tok::greaterequal: Opc = BO_GE; break; + case tok::greater: Opc = BO_GT; break; + case tok::exclaimequal: Opc = BO_NE; break; + case tok::equalequal: Opc = BO_EQ; break; + case tok::amp: Opc = BO_And; break; + case tok::caret: Opc = BO_Xor; break; + case tok::pipe: Opc = BO_Or; break; + case tok::ampamp: Opc = BO_LAnd; break; + case tok::pipepipe: Opc = BO_LOr; break; + case tok::equal: Opc = BO_Assign; break; + case tok::starequal: Opc = BO_MulAssign; break; + case tok::slashequal: Opc = BO_DivAssign; break; + case tok::percentequal: Opc = BO_RemAssign; break; + case tok::plusequal: Opc = BO_AddAssign; break; + case tok::minusequal: Opc = BO_SubAssign; break; + case tok::lesslessequal: Opc = BO_ShlAssign; break; + case tok::greatergreaterequal: Opc = BO_ShrAssign; break; + case tok::ampequal: Opc = BO_AndAssign; break; + case tok::caretequal: Opc = BO_XorAssign; break; + case tok::pipeequal: Opc = BO_OrAssign; break; + case tok::comma: Opc = BO_Comma; break; } return Opc; } -static inline UnaryOperator::Opcode ConvertTokenKindToUnaryOpcode( +static inline UnaryOperatorKind ConvertTokenKindToUnaryOpcode( tok::TokenKind Kind) { - UnaryOperator::Opcode Opc; + UnaryOperatorKind Opc; switch (Kind) { default: assert(0 && "Unknown unary op!"); - case tok::plusplus: Opc = UnaryOperator::PreInc; break; - case tok::minusminus: Opc = UnaryOperator::PreDec; break; - case tok::amp: Opc = UnaryOperator::AddrOf; break; - case tok::star: Opc = UnaryOperator::Deref; break; - case tok::plus: Opc = UnaryOperator::Plus; break; - case tok::minus: Opc = UnaryOperator::Minus; break; - case tok::tilde: Opc = UnaryOperator::Not; break; - case tok::exclaim: Opc = UnaryOperator::LNot; break; - case tok::kw___real: Opc = UnaryOperator::Real; break; - case tok::kw___imag: Opc = UnaryOperator::Imag; break; - case tok::kw___extension__: Opc = UnaryOperator::Extension; break; + case tok::plusplus: Opc = UO_PreInc; break; + case tok::minusminus: Opc = UO_PreDec; break; + case tok::amp: Opc = UO_AddrOf; break; + case tok::star: Opc = UO_Deref; break; + case tok::plus: Opc = UO_Plus; break; + case tok::minus: Opc = UO_Minus; break; + case tok::tilde: Opc = UO_Not; break; + case tok::exclaim: Opc = UO_LNot; break; + case tok::kw___real: Opc = UO_Real; break; + case tok::kw___imag: Opc = UO_Imag; break; + case tok::kw___extension__: Opc = UO_Extension; break; } return Opc; } @@ -6328,106 +6460,111 @@ static inline UnaryOperator::Opcode ConvertTokenKindToUnaryOpcode( /// CreateBuiltinBinOp - Creates a new built-in binary operation with /// operator @p Opc at location @c TokLoc. This routine only supports /// built-in operations; ActOnBinOp handles overloaded operators. -Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, - unsigned Op, - Expr *lhs, Expr *rhs) { +ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, + unsigned Op, + Expr *lhs, Expr *rhs) { QualType ResultTy; // Result type of the binary operator. - BinaryOperator::Opcode Opc = (BinaryOperator::Opcode)Op; + BinaryOperatorKind Opc = (BinaryOperatorKind) Op; // The following two variables are used for compound assignment operators QualType CompLHSTy; // Type of LHS after promotions for computation QualType CompResultTy; // Type of computation result switch (Opc) { - case BinaryOperator::Assign: + case BO_Assign: ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, QualType()); break; - case BinaryOperator::PtrMemD: - case BinaryOperator::PtrMemI: + case BO_PtrMemD: + case BO_PtrMemI: ResultTy = CheckPointerToMemberOperands(lhs, rhs, OpLoc, - Opc == BinaryOperator::PtrMemI); + Opc == BO_PtrMemI); break; - case BinaryOperator::Mul: - case BinaryOperator::Div: + case BO_Mul: + case BO_Div: ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, false, - Opc == BinaryOperator::Div); + Opc == BO_Div); break; - case BinaryOperator::Rem: + case BO_Rem: ResultTy = CheckRemainderOperands(lhs, rhs, OpLoc); break; - case BinaryOperator::Add: + case BO_Add: ResultTy = CheckAdditionOperands(lhs, rhs, OpLoc); break; - case BinaryOperator::Sub: + case BO_Sub: ResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc); break; - case BinaryOperator::Shl: - case BinaryOperator::Shr: + case BO_Shl: + case BO_Shr: ResultTy = CheckShiftOperands(lhs, rhs, OpLoc); break; - case BinaryOperator::LE: - case BinaryOperator::LT: - case BinaryOperator::GE: - case BinaryOperator::GT: + case BO_LE: + case BO_LT: + case BO_GE: + case BO_GT: ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, true); break; - case BinaryOperator::EQ: - case BinaryOperator::NE: + case BO_EQ: + case BO_NE: ResultTy = CheckCompareOperands(lhs, rhs, OpLoc, Opc, false); break; - case BinaryOperator::And: - case BinaryOperator::Xor: - case BinaryOperator::Or: + case BO_And: + case BO_Xor: + case BO_Or: ResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc); break; - case BinaryOperator::LAnd: - case BinaryOperator::LOr: + case BO_LAnd: + case BO_LOr: ResultTy = CheckLogicalOperands(lhs, rhs, OpLoc, Opc); break; - case BinaryOperator::MulAssign: - case BinaryOperator::DivAssign: + case BO_MulAssign: + case BO_DivAssign: CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true, - Opc == BinaryOperator::DivAssign); + Opc == BO_DivAssign); CompLHSTy = CompResultTy; if (!CompResultTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); break; - case BinaryOperator::RemAssign: + case BO_RemAssign: CompResultTy = CheckRemainderOperands(lhs, rhs, OpLoc, true); CompLHSTy = CompResultTy; if (!CompResultTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); break; - case BinaryOperator::AddAssign: + case BO_AddAssign: CompResultTy = CheckAdditionOperands(lhs, rhs, OpLoc, &CompLHSTy); if (!CompResultTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); break; - case BinaryOperator::SubAssign: + case BO_SubAssign: CompResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc, &CompLHSTy); if (!CompResultTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); break; - case BinaryOperator::ShlAssign: - case BinaryOperator::ShrAssign: + case BO_ShlAssign: + case BO_ShrAssign: CompResultTy = CheckShiftOperands(lhs, rhs, OpLoc, true); CompLHSTy = CompResultTy; if (!CompResultTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); break; - case BinaryOperator::AndAssign: - case BinaryOperator::XorAssign: - case BinaryOperator::OrAssign: + case BO_AndAssign: + case BO_XorAssign: + case BO_OrAssign: CompResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc, true); CompLHSTy = CompResultTy; if (!CompResultTy.isNull()) ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); break; - case BinaryOperator::Comma: + case BO_Comma: ResultTy = CheckCommaOperands(lhs, rhs, OpLoc); break; } if (ResultTy.isNull()) return ExprError(); + if (ResultTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { + if (Opc >= BO_Assign && Opc <= BO_OrAssign) + Diag(OpLoc, diag::err_assignment_requires_nonfragile_object) + << ResultTy; + } if (CompResultTy.isNull()) return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, ResultTy, OpLoc)); else @@ -6479,7 +6616,7 @@ static void SuggestParentheses(Sema &Self, SourceLocation Loc, /// operators are mixed in a way that suggests that the programmer forgot that /// comparison operators have higher precedence. The most typical example of /// such code is "flags & 0x0020 != 0", which is equivalent to "flags & 1". -static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc, +static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, SourceLocation OpLoc,Expr *lhs,Expr *rhs){ typedef BinaryOperator BinOp; BinOp::Opcode lhsopc = static_cast(-1), @@ -6526,19 +6663,17 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc, /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky /// precedence. This currently diagnoses only "arg1 'bitwise' arg2 'eq' arg3". /// But it could also warn about arg1 && arg2 || arg3, as GCC 4.3+ does. -static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperator::Opcode Opc, +static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, SourceLocation OpLoc, Expr *lhs, Expr *rhs){ if (BinaryOperator::isBitwiseOp(Opc)) DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); } // Binary Operators. 'Tok' is the token for the operator. -Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, - tok::TokenKind Kind, - ExprArg LHS, ExprArg RHS) { - BinaryOperator::Opcode Opc = ConvertTokenKindToBinaryOpcode(Kind); - Expr *lhs = LHS.takeAs(), *rhs = RHS.takeAs(); - +ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, + tok::TokenKind Kind, + Expr *lhs, Expr *rhs) { + BinaryOperatorKind Opc = ConvertTokenKindToBinaryOpcode(Kind); assert((lhs != 0) && "ActOnBinOp(): missing left expression"); assert((rhs != 0) && "ActOnBinOp(): missing right expression"); @@ -6548,9 +6683,9 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, return BuildBinOp(S, TokLoc, Opc, lhs, rhs); } -Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, - BinaryOperator::Opcode Opc, - Expr *lhs, Expr *rhs) { +ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, + BinaryOperatorKind Opc, + Expr *lhs, Expr *rhs) { if (getLangOptions().CPlusPlus && (lhs->getType()->isOverloadableType() || rhs->getType()->isOverloadableType())) { @@ -6573,38 +6708,32 @@ Action::OwningExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, return CreateBuiltinBinOp(OpLoc, Opc, lhs, rhs); } -Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, +ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, unsigned OpcIn, - ExprArg InputArg) { - UnaryOperator::Opcode Opc = static_cast(OpcIn); + Expr *Input) { + UnaryOperatorKind Opc = static_cast(OpcIn); - // FIXME: Input is modified below, but InputArg is not updated appropriately. - Expr *Input = (Expr *)InputArg.get(); QualType resultType; switch (Opc) { - case UnaryOperator::OffsetOf: - assert(false && "Invalid unary operator"); - break; - - case UnaryOperator::PreInc: - case UnaryOperator::PreDec: - case UnaryOperator::PostInc: - case UnaryOperator::PostDec: + case UO_PreInc: + case UO_PreDec: + case UO_PostInc: + case UO_PostDec: resultType = CheckIncrementDecrementOperand(Input, OpLoc, - Opc == UnaryOperator::PreInc || - Opc == UnaryOperator::PostInc, - Opc == UnaryOperator::PreInc || - Opc == UnaryOperator::PreDec); + Opc == UO_PreInc || + Opc == UO_PostInc, + Opc == UO_PreInc || + Opc == UO_PreDec); break; - case UnaryOperator::AddrOf: + case UO_AddrOf: resultType = CheckAddressOfOperand(Input, OpLoc); break; - case UnaryOperator::Deref: + case UO_Deref: DefaultFunctionArrayLvalueConversion(Input); resultType = CheckIndirectionOperand(Input, OpLoc); break; - case UnaryOperator::Plus: - case UnaryOperator::Minus: + case UO_Plus: + case UO_Minus: UsualUnaryConversions(Input); resultType = Input->getType(); if (resultType->isDependentType()) @@ -6616,13 +6745,13 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, resultType->isEnumeralType()) break; else if (getLangOptions().CPlusPlus && // C++ [expr.unary.op]p6 - Opc == UnaryOperator::Plus && + Opc == UO_Plus && resultType->isPointerType()) break; return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input->getSourceRange()); - case UnaryOperator::Not: // bitwise complement + case UO_Not: // bitwise complement UsualUnaryConversions(Input); resultType = Input->getType(); if (resultType->isDependentType()) @@ -6632,11 +6761,11 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, // C99 does not support '~' for complex conjugation. Diag(OpLoc, diag::ext_integer_complement_complex) << resultType << Input->getSourceRange(); - else if (!resultType->isIntegerType()) + else if (!resultType->hasIntegerRepresentation()) return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input->getSourceRange()); break; - case UnaryOperator::LNot: // logical negation + case UO_LNot: // logical negation // Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5). DefaultFunctionArrayLvalueConversion(Input); resultType = Input->getType(); @@ -6649,27 +6778,25 @@ Action::OwningExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, // In C++, it's bool. C++ 5.3.1p8 resultType = getLangOptions().CPlusPlus ? Context.BoolTy : Context.IntTy; break; - case UnaryOperator::Real: - case UnaryOperator::Imag: - resultType = CheckRealImagOperand(Input, OpLoc, Opc == UnaryOperator::Real); + case UO_Real: + case UO_Imag: + resultType = CheckRealImagOperand(Input, OpLoc, Opc == UO_Real); break; - case UnaryOperator::Extension: + case UO_Extension: resultType = Input->getType(); break; } if (resultType.isNull()) return ExprError(); - InputArg.release(); return Owned(new (Context) UnaryOperator(Input, Opc, resultType, OpLoc)); } -Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, - UnaryOperator::Opcode Opc, - ExprArg input) { - Expr *Input = (Expr*)input.get(); +ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, + UnaryOperatorKind Opc, + Expr *Input) { if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType() && - Opc != UnaryOperator::Extension) { + UnaryOperator::getOverloadedOperator(Opc) != OO_None) { // Find all of the overloaded operators visible from this // point. We perform both an operator-name lookup from the local // scope and an argument-dependent lookup based on the types of @@ -6680,24 +6807,24 @@ Action::OwningExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, LookupOverloadedOperatorName(OverOp, S, Input->getType(), QualType(), Functions); - return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, move(input)); + return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, Input); } - return CreateBuiltinUnaryOp(OpLoc, Opc, move(input)); + return CreateBuiltinUnaryOp(OpLoc, Opc, Input); } // Unary Operators. 'Tok' is the token for the operator. -Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, - tok::TokenKind Op, ExprArg input) { - return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), move(input)); +ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Op, Expr *Input) { + return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), Input); } /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". -Sema::OwningExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, +ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, IdentifierInfo *LabelII) { // Look up the record for this label identifier. - LabelStmt *&LabelDecl = getLabelMap()[LabelII]; + LabelStmt *&LabelDecl = getCurFunction()->LabelMap[LabelII]; // If we haven't seen this label yet, create a forward reference. It // will be validated and/or cleaned up in ActOnFinishFunctionBody. @@ -6709,10 +6836,9 @@ Sema::OwningExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, Context.getPointerType(Context.VoidTy))); } -Sema::OwningExprResult -Sema::ActOnStmtExpr(SourceLocation LPLoc, StmtArg substmt, +ExprResult +Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, SourceLocation RPLoc) { // "({..})" - Stmt *SubStmt = static_cast(substmt.get()); assert(SubStmt && isa(SubStmt) && "Invalid action invocation!"); CompoundStmt *Compound = cast(SubStmt); @@ -6742,11 +6868,10 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, StmtArg substmt, // FIXME: Check that expression type is complete/non-abstract; statement // expressions are not lvalues. - substmt.release(); return Owned(new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc)); } -Sema::OwningExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, +ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, TypeSourceInfo *TInfo, OffsetOfComponent *CompPtr, unsigned NumComponents, @@ -6865,22 +6990,27 @@ Sema::OwningExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, Diag(MemberDecl->getLocation(), diag::note_bitfield_decl); return ExprError(); } - + + RecordDecl *Parent = MemberDecl->getParent(); + bool AnonStructUnion = Parent->isAnonymousStructOrUnion(); + if (AnonStructUnion) { + do { + Parent = cast(Parent->getParent()); + } while (Parent->isAnonymousStructOrUnion()); + } + // If the member was found in a base class, introduce OffsetOfNodes for // the base class indirections. CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/false); - if (IsDerivedFrom(CurrentType, - Context.getTypeDeclType(MemberDecl->getParent()), - Paths)) { + if (IsDerivedFrom(CurrentType, Context.getTypeDeclType(Parent), Paths)) { CXXBasePath &Path = Paths.front(); for (CXXBasePath::iterator B = Path.begin(), BEnd = Path.end(); B != BEnd; ++B) Comps.push_back(OffsetOfNode(B->Base)); } - - if (cast(MemberDecl->getDeclContext())-> - isAnonymousStructOrUnion()) { + + if (AnonStructUnion) { llvm::SmallVector Path; BuildAnonymousStructUnionMemberPath(MemberDecl, Path); unsigned n = Path.size(); @@ -6897,10 +7027,10 @@ Sema::OwningExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, Exprs.data(), Exprs.size(), RParenLoc)); } -Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, +ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc, SourceLocation TypeLoc, - TypeTy *argty, + ParsedType argty, OffsetOfComponent *CompPtr, unsigned NumComponents, SourceLocation RPLoc) { @@ -6910,151 +7040,32 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, if (ArgTy.isNull()) return ExprError(); - if (getLangOptions().CPlusPlus) { - if (!ArgTInfo) - ArgTInfo = Context.getTrivialTypeSourceInfo(ArgTy, TypeLoc); - - return BuildBuiltinOffsetOf(BuiltinLoc, ArgTInfo, CompPtr, NumComponents, - RPLoc); - } - - // FIXME: The code below is marked for death, once we have proper CodeGen - // support for non-constant OffsetOf expressions. - - bool Dependent = ArgTy->isDependentType(); - - // We must have at least one component that refers to the type, and the first - // one is known to be a field designator. Verify that the ArgTy represents - // a struct/union/class. - if (!Dependent && !ArgTy->isRecordType()) - return ExprError(Diag(TypeLoc, diag::err_offsetof_record_type) << ArgTy); - - // FIXME: Type must be complete per C99 7.17p3 because a declaring a variable - // with an incomplete type would be illegal. - - // Otherwise, create a null pointer as the base, and iteratively process - // the offsetof designators. - QualType ArgTyPtr = Context.getPointerType(ArgTy); - Expr* Res = new (Context) ImplicitValueInitExpr(ArgTyPtr); - Res = new (Context) UnaryOperator(Res, UnaryOperator::Deref, - ArgTy, SourceLocation()); - - // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a - // GCC extension, diagnose them. - // FIXME: This diagnostic isn't actually visible because the location is in - // a system header! - if (NumComponents != 1) - Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator) - << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd); - - if (!Dependent) { - bool DidWarnAboutNonPOD = false; - - if (RequireCompleteType(TypeLoc, Res->getType(), - diag::err_offsetof_incomplete_type)) - return ExprError(); - - // FIXME: Dependent case loses a lot of information here. And probably - // leaks like a sieve. - for (unsigned i = 0; i != NumComponents; ++i) { - const OffsetOfComponent &OC = CompPtr[i]; - if (OC.isBrackets) { - // Offset of an array sub-field. TODO: Should we allow vector elements? - const ArrayType *AT = Context.getAsArrayType(Res->getType()); - if (!AT) { - Res->Destroy(Context); - return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type) - << Res->getType()); - } - - // FIXME: C++: Verify that operator[] isn't overloaded. - - // Promote the array so it looks more like a normal array subscript - // expression. - DefaultFunctionArrayLvalueConversion(Res); - - // C99 6.5.2.1p1 - Expr *Idx = static_cast(OC.U.E); - // FIXME: Leaks Res - if (!Idx->isTypeDependent() && !Idx->getType()->isIntegerType()) - return ExprError(Diag(Idx->getLocStart(), - diag::err_typecheck_subscript_not_integer) - << Idx->getSourceRange()); - - Res = new (Context) ArraySubscriptExpr(Res, Idx, AT->getElementType(), - OC.LocEnd); - continue; - } - - const RecordType *RC = Res->getType()->getAs(); - if (!RC) { - Res->Destroy(Context); - return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type) - << Res->getType()); - } - - // Get the decl corresponding to this. - RecordDecl *RD = RC->getDecl(); - if (CXXRecordDecl *CRD = dyn_cast(RD)) { - if (!CRD->isPOD() && !DidWarnAboutNonPOD && - DiagRuntimeBehavior(BuiltinLoc, - PDiag(diag::warn_offsetof_non_pod_type) - << SourceRange(CompPtr[0].LocStart, OC.LocEnd) - << Res->getType())) - DidWarnAboutNonPOD = true; - } - - LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName); - LookupQualifiedName(R, RD); - - FieldDecl *MemberDecl = R.getAsSingle(); - // FIXME: Leaks Res - if (!MemberDecl) - return ExprError(Diag(BuiltinLoc, diag::err_no_member) - << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd)); - - // C99 7.17p3: - // (If the specified member is a bit-field, the behavior is undefined.) - // - // We diagnose this as an error. - if (MemberDecl->getBitWidth()) { - Diag(OC.LocEnd, diag::err_offsetof_bitfield) - << MemberDecl->getDeclName() - << SourceRange(BuiltinLoc, RPLoc); - Diag(MemberDecl->getLocation(), diag::note_bitfield_decl); - return ExprError(); - } - - // FIXME: C++: Verify that MemberDecl isn't a static field. - // FIXME: Verify that MemberDecl isn't a bitfield. - if (cast(MemberDecl->getDeclContext())->isAnonymousStructOrUnion()) { - Res = BuildAnonymousStructUnionMemberReference( - OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs(); - } else { - PerformObjectMemberConversion(Res, /*Qualifier=*/0, - *R.begin(), MemberDecl); - // MemberDecl->getType() doesn't get the right qualifiers, but it - // doesn't matter here. - Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd, - MemberDecl->getType().getNonReferenceType()); - } - } - } - - return Owned(new (Context) UnaryOperator(Res, UnaryOperator::OffsetOf, - Context.getSizeType(), BuiltinLoc)); + if (!ArgTInfo) + ArgTInfo = Context.getTrivialTypeSourceInfo(ArgTy, TypeLoc); + + return BuildBuiltinOffsetOf(BuiltinLoc, ArgTInfo, CompPtr, NumComponents, + RPLoc); } -Sema::OwningExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, - TypeTy *arg1,TypeTy *arg2, +ExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, + ParsedType arg1,ParsedType arg2, SourceLocation RPLoc) { - // FIXME: Preserve type source info. - QualType argT1 = GetTypeFromParser(arg1); - QualType argT2 = GetTypeFromParser(arg2); + TypeSourceInfo *argTInfo1; + QualType argT1 = GetTypeFromParser(arg1, &argTInfo1); + TypeSourceInfo *argTInfo2; + QualType argT2 = GetTypeFromParser(arg2, &argTInfo2); assert((!argT1.isNull() && !argT2.isNull()) && "Missing type argument(s)"); + return BuildTypesCompatibleExpr(BuiltinLoc, argTInfo1, argTInfo2, RPLoc); +} + +ExprResult +Sema::BuildTypesCompatibleExpr(SourceLocation BuiltinLoc, + TypeSourceInfo *argTInfo1, + TypeSourceInfo *argTInfo2, + SourceLocation RPLoc) { if (getLangOptions().CPlusPlus) { Diag(BuiltinLoc, diag::err_types_compatible_p_in_cplusplus) << SourceRange(BuiltinLoc, RPLoc); @@ -7062,17 +7073,14 @@ Sema::OwningExprResult Sema::ActOnTypesCompatibleExpr(SourceLocation BuiltinLoc, } return Owned(new (Context) TypesCompatibleExpr(Context.IntTy, BuiltinLoc, - argT1, argT2, RPLoc)); + argTInfo1, argTInfo2, RPLoc)); } -Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, - ExprArg cond, - ExprArg expr1, ExprArg expr2, - SourceLocation RPLoc) { - Expr *CondExpr = static_cast(cond.get()); - Expr *LHSExpr = static_cast(expr1.get()); - Expr *RHSExpr = static_cast(expr2.get()); +ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, + Expr *CondExpr, + Expr *LHSExpr, Expr *RHSExpr, + SourceLocation RPLoc) { assert((CondExpr && LHSExpr && RHSExpr) && "Missing type argument(s)"); QualType resType; @@ -7095,7 +7103,6 @@ Sema::OwningExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, : RHSExpr->isValueDependent(); } - cond.release(); expr1.release(); expr2.release(); return Owned(new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, RPLoc, resType->isDependentType(), @@ -7232,8 +7239,8 @@ void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) { /// ActOnBlockStmtExpr - This is called when the body of a block statement /// literal was successfully completed. ^(int x){...} -Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, - StmtArg body, Scope *CurScope) { +ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, + Stmt *Body, Scope *CurScope) { // If blocks are disabled, emit an error. if (!LangOpts.Blocks) Diag(CaretLoc, diag::err_blocks_disable); @@ -7295,10 +7302,10 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, BlockTy = Context.getBlockPointerType(BlockTy); // If needed, diagnose invalid gotos and switches in the block. - if (FunctionNeedsScopeChecking() && !hasAnyErrorsInThisFunction()) - DiagnoseInvalidJumps(static_cast(body.get())); + if (getCurFunction()->NeedsScopeChecking() && !hasAnyErrorsInThisFunction()) + DiagnoseInvalidJumps(cast(Body)); - BSI->TheDecl->setBody(body.takeAs()); + BSI->TheDecl->setBody(cast(Body)); bool Good = true; // Check goto/label use. @@ -7320,22 +7327,29 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, return ExprError(); } + BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy, + BSI->hasBlockDeclRefExprs); + // Issue any analysis-based warnings. const sema::AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy(); - AnalysisWarnings.IssueWarnings(WP, BSI->TheDecl, BlockTy); + AnalysisWarnings.IssueWarnings(WP, Result); - Expr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy, - BSI->hasBlockDeclRefExprs); PopFunctionOrBlockScope(); return Owned(Result); } -Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, - ExprArg expr, TypeTy *type, +ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, + Expr *expr, ParsedType type, SourceLocation RPLoc) { - QualType T = GetTypeFromParser(type); - Expr *E = static_cast(expr.get()); + TypeSourceInfo *TInfo; + QualType T = GetTypeFromParser(type, &TInfo); + return BuildVAArgExpr(BuiltinLoc, expr, TInfo, RPLoc); +} + +ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, + Expr *E, TypeSourceInfo *TInfo, + SourceLocation RPLoc) { Expr *OrigExpr = E; InitBuiltinVaListType(); @@ -7367,13 +7381,11 @@ Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, // FIXME: Check that type is complete/non-abstract // FIXME: Warn if a non-POD type is passed in. - expr.release(); - return Owned(new (Context) VAArgExpr(BuiltinLoc, E, - T.getNonLValueExprType(Context), - RPLoc)); + QualType T = TInfo->getType().getNonLValueExprType(Context); + return Owned(new (Context) VAArgExpr(BuiltinLoc, E, TInfo, RPLoc, T)); } -Sema::OwningExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { +ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { // The type of __null will be int or long, depending on the size of // pointers on the target. QualType Ty; @@ -7647,8 +7659,10 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (CXXConstructorDecl *Constructor = dyn_cast(D)) { unsigned TypeQuals; if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) { - if (!Constructor->isUsed(false)) - DefineImplicitDefaultConstructor(Loc, Constructor); + if (Constructor->getParent()->hasTrivialConstructor()) + return; + if (!Constructor->isUsed(false)) + DefineImplicitDefaultConstructor(Loc, Constructor); } else if (Constructor->isImplicit() && Constructor->isCopyConstructor(TypeQuals)) { if (!Constructor->isUsed(false)) @@ -7696,13 +7710,20 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { PendingLocalImplicitInstantiations.push_back(std::make_pair(Function, Loc)); else - PendingImplicitInstantiations.push_back(std::make_pair(Function, - Loc)); + PendingInstantiations.push_back(std::make_pair(Function, Loc)); + } + } else // Walk redefinitions, as some of them may be instantiable. + for (FunctionDecl::redecl_iterator i(Function->redecls_begin()), + e(Function->redecls_end()); i != e; ++i) { + if (!i->isUsed(false) && i->isImplicitlyInstantiable()) + MarkDeclarationReferenced(Loc, *i); } - } // FIXME: keep track of references to static functions - Function->setUsed(true); + + // Recursive functions should be marked when used from another function. + if (CurContext != Function) + Function->setUsed(true); return; } @@ -7716,7 +7737,7 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (MSInfo->getPointOfInstantiation().isInvalid() && MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) { MSInfo->setPointOfInstantiation(Loc); - PendingImplicitInstantiations.push_back(std::make_pair(Var, Loc)); + PendingInstantiations.push_back(std::make_pair(Var, Loc)); } } @@ -7836,7 +7857,7 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { if (isa(E)) { BinaryOperator *Op = cast(E); - if (Op->getOpcode() != BinaryOperator::Assign) + if (Op->getOpcode() != BO_Assign) return; // Greylist some idioms by putting them into a warning subcategory. @@ -7899,16 +7920,13 @@ bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { return false; } -Sema::OwningExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc, - ExprArg SubExpr) { - Expr *Sub = SubExpr.takeAs(); +ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc, + Expr *Sub) { if (!Sub) return ExprError(); - if (CheckBooleanCondition(Sub, Loc)) { - Sub->Destroy(Context); + if (CheckBooleanCondition(Sub, Loc)) return ExprError(); - } return Owned(Sub); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 090400f..5720d93 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -11,28 +11,31 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "SemaInit.h" -#include "Lookup.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedTemplate.h" +#include "clang/Sema/TemplateDeduction.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Template.h" #include "llvm/ADT/STLExtras.h" using namespace clang; - -Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, - IdentifierInfo &II, - SourceLocation NameLoc, - Scope *S, CXXScopeSpec &SS, - TypeTy *ObjectTypePtr, - bool EnteringContext) { +using namespace sema; + +ParsedType Sema::getDestructorName(SourceLocation TildeLoc, + IdentifierInfo &II, + SourceLocation NameLoc, + Scope *S, CXXScopeSpec &SS, + ParsedType ObjectTypePtr, + bool EnteringContext) { // Determine where to perform name lookup. // FIXME: This area of the standard is very messy, and the current @@ -149,7 +152,7 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, // FIXME: Should we be suppressing ambiguities here? if (Found.isAmbiguous()) - return 0; + return ParsedType(); if (TypeDecl *Type = Found.getAsSingle()) { QualType T = Context.getTypeDeclType(Type); @@ -158,7 +161,7 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, Context.hasSameUnqualifiedType(T, SearchType)) { // We found our type! - return T.getAsOpaquePtr(); + return ParsedType::make(T); } } @@ -191,7 +194,7 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, = dyn_cast(Record->getDecl())) { if (Spec->getSpecializedTemplate()->getCanonicalDecl() == Template->getCanonicalDecl()) - return MemberOfType.getAsOpaquePtr(); + return ParsedType::make(MemberOfType); } continue; @@ -210,7 +213,7 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, // specialized. if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) { if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl()) - return MemberOfType.getAsOpaquePtr(); + return ParsedType::make(MemberOfType); continue; } @@ -221,7 +224,7 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, = SpecName.getAsDependentTemplateName()) { if (DepTemplate->isIdentifier() && DepTemplate->getIdentifier() == Template->getIdentifier()) - return MemberOfType.getAsOpaquePtr(); + return ParsedType::make(MemberOfType); continue; } @@ -242,8 +245,10 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, Range = SourceRange(NameLoc); } - return CheckTypenameType(ETK_None, NNS, II, SourceLocation(), - Range, NameLoc).getAsOpaquePtr(); + QualType T = CheckTypenameType(ETK_None, NNS, II, + SourceLocation(), + Range, NameLoc); + return ParsedType::make(T); } if (ObjectTypePtr) @@ -252,11 +257,11 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, else Diag(NameLoc, diag::err_destructor_class_name); - return 0; + return ParsedType(); } /// \brief Build a C++ typeid expression with a type operand. -Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, +ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { @@ -279,12 +284,11 @@ Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, } /// \brief Build a C++ typeid expression with an expression operand. -Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, +ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, - ExprArg Operand, + Expr *E, SourceLocation RParenLoc) { bool isUnevaluatedOperand = true; - Expr *E = static_cast(Operand.get()); if (E && !E->isTypeDependent()) { QualType T = E->getType(); if (const RecordType *RecordT = T->getAs()) { @@ -296,10 +300,10 @@ Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, return ExprError(); // C++ [expr.typeid]p3: - // When typeid is applied to an expression other than an lvalue of a + // When typeid is applied to an expression other than an glvalue of a // polymorphic class type [...] [the] expression is an unevaluated // operand. [...] - if (RecordD->isPolymorphic() && E->isLvalue(Context) == Expr::LV_Valid) { + if (RecordD->isPolymorphic() && E->Classify(Context).isGLValue()) { isUnevaluatedOperand = false; // We require a vtable to query the type at run time. @@ -316,9 +320,7 @@ Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals); if (!Context.hasSameType(T, UnqualT)) { T = UnqualT; - ImpCastExprToType(E, UnqualT, CastExpr::CK_NoOp, E->isLvalue(Context)); - Operand.release(); - Operand = Owned(E); + ImpCastExprToType(E, UnqualT, CK_NoOp, CastCategory(E)); } } @@ -329,12 +331,12 @@ Sema::OwningExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, ExprEvalContexts.back().Context = Unevaluated; return Owned(new (Context) CXXTypeidExpr(TypeInfoType.withConst(), - Operand.takeAs(), + E, SourceRange(TypeidLoc, RParenLoc))); } /// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression); -Action::OwningExprResult +ExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { // Find the std::type_info type. @@ -343,7 +345,7 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); - LookupQualifiedName(R, StdNamespace); + LookupQualifiedName(R, getStdNamespace()); RecordDecl *TypeInfoRecordDecl = R.getAsSingle(); if (!TypeInfoRecordDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); @@ -353,7 +355,8 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, if (isType) { // The operand is a type; handle it as such. TypeSourceInfo *TInfo = 0; - QualType T = GetTypeFromParser(TyOrExpr, &TInfo); + QualType T = GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrExpr), + &TInfo); if (T.isNull()) return ExprError(); @@ -364,11 +367,11 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, } // The operand is an expression. - return BuildCXXTypeId(TypeInfoType, OpLoc, Owned((Expr*)TyOrExpr), RParenLoc); + return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } /// ActOnCXXBoolLiteral - Parse {true,false} literals. -Action::OwningExprResult +ExprResult Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { assert((Kind == tok::kw_true || Kind == tok::kw_false) && "Unknown C++ Boolean value!"); @@ -377,15 +380,14 @@ Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { } /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. -Action::OwningExprResult +ExprResult Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) { return Owned(new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc)); } /// ActOnCXXThrow - Parse throw expressions. -Action::OwningExprResult -Sema::ActOnCXXThrow(SourceLocation OpLoc, ExprArg E) { - Expr *Ex = E.takeAs(); +ExprResult +Sema::ActOnCXXThrow(SourceLocation OpLoc, Expr *Ex) { if (Ex && !Ex->isTypeDependent() && CheckCXXThrowOperand(OpLoc, Ex)) return ExprError(); return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc)); @@ -400,8 +402,8 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // the type from "array of T" or "function returning T" to "pointer to T" // or "pointer to function returning T", [...] if (E->getType().hasQualifiers()) - ImpCastExprToType(E, E->getType().getUnqualifiedType(), CastExpr::CK_NoOp, - E->isLvalue(Context) == Expr::LV_Valid); + ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp, + CastCategory(E)); DefaultFunctionArrayConversion(E); @@ -432,7 +434,7 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { InitializedEntity Entity = InitializedEntity::InitializeException(ThrowLoc, E->getType(), /*NRVO=*/false); - OwningExprResult Res = PerformCopyInitialization(Entity, + ExprResult Res = PerformCopyInitialization(Entity, SourceLocation(), Owned(E)); if (Res.isInvalid()) @@ -464,7 +466,7 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { return false; } -Action::OwningExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { +ExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { /// C++ 9.3.2: In the body of a non-static member function, the keyword this /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. @@ -483,8 +485,8 @@ Action::OwningExprResult Sema::ActOnCXXThis(SourceLocation ThisLoc) { /// Can be interpreted either as function-style casting ("int(x)") /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). -Action::OwningExprResult -Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, +ExprResult +Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, ParsedType TypeRep, SourceLocation LParenLoc, MultiExprArg exprs, SourceLocation *CommaLocs, @@ -532,19 +534,19 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, // corresponding cast expression. // if (NumExprs == 1) { - CastExpr::CastKind Kind = CastExpr::CK_Unknown; - CXXBaseSpecifierArray BasePath; + CastKind Kind = CK_Unknown; + CXXCastPath BasePath; if (CheckCastTypes(TypeRange, Ty, Exprs[0], Kind, BasePath, /*FunctionalStyle=*/true)) return ExprError(); exprs.release(); - return Owned(new (Context) CXXFunctionalCastExpr( + return Owned(CXXFunctionalCastExpr::Create(Context, Ty.getNonLValueExprType(Context), - TInfo, TyBeginLoc, Kind, - Exprs[0], BasePath, - RParenLoc)); + TInfo, TyBeginLoc, Kind, + Exprs[0], &BasePath, + RParenLoc)); } if (Ty->isRecordType()) { @@ -555,7 +557,7 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, : InitializationKind::CreateValue(TypeRange.getBegin(), LParenLoc, RParenLoc); InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs); - OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(exprs)); // FIXME: Improve AST representation? @@ -587,7 +589,7 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, /// or /// @code ::new Foo(23, "hello") @endcode /// For the interpretation of this heap of arguments, consult the base version. -Action::OwningExprResult +ExprResult Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, @@ -643,13 +645,13 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, AllocType, D.getSourceRange().getBegin(), R, - Owned(ArraySize), + ArraySize, ConstructorLParen, move(ConstructorArgs), ConstructorRParen); } -Sema::OwningExprResult +ExprResult Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, @@ -658,7 +660,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, QualType AllocType, SourceLocation TypeLoc, SourceRange TypeRange, - ExprArg ArraySizeE, + Expr *ArraySize, SourceLocation ConstructorLParen, MultiExprArg ConstructorArgs, SourceLocation ConstructorRParen) { @@ -667,12 +669,12 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, // Per C++0x [expr.new]p5, the type being constructed may be a // typedef of an array type. - if (!ArraySizeE.get()) { + if (!ArraySize) { if (const ConstantArrayType *Array = Context.getAsConstantArrayType(AllocType)) { - ArraySizeE = Owned(new (Context) IntegerLiteral(Array->getSize(), - Context.getSizeType(), - TypeRange.getEnd())); + ArraySize = IntegerLiteral::Create(Context, Array->getSize(), + Context.getSizeType(), + TypeRange.getEnd()); AllocType = Array->getElementType(); } } @@ -681,13 +683,12 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral // or enumeration type with a non-negative value." - Expr *ArraySize = (Expr *)ArraySizeE.get(); if (ArraySize && !ArraySize->isTypeDependent()) { QualType SizeType = ArraySize->getType(); - OwningExprResult ConvertedSize - = ConvertToIntegralOrEnumerationType(StartLoc, move(ArraySizeE), + ExprResult ConvertedSize + = ConvertToIntegralOrEnumerationType(StartLoc, ArraySize, PDiag(diag::err_array_size_not_integral), PDiag(diag::err_array_size_incomplete_type) << ArraySize->getSourceRange(), @@ -700,8 +701,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, if (ConvertedSize.isInvalid()) return ExprError(); - ArraySize = ConvertedSize.takeAs(); - ArraySizeE = Owned(ArraySize); + ArraySize = ConvertedSize.take(); SizeType = ArraySize->getType(); if (!SizeType->isIntegralOrEnumerationType()) return ExprError(); @@ -716,8 +716,20 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, llvm::APInt::getNullValue(Value.getBitWidth()), Value.isUnsigned())) return ExprError(Diag(ArraySize->getSourceRange().getBegin(), - diag::err_typecheck_negative_array_size) + diag::err_typecheck_negative_array_size) << ArraySize->getSourceRange()); + + if (!AllocType->isDependentType()) { + unsigned ActiveSizeBits + = ConstantArrayType::getNumAddressingBits(Context, AllocType, Value); + if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { + Diag(ArraySize->getSourceRange().getBegin(), + diag::err_array_too_large) + << Value.toString(10) + << ArraySize->getSourceRange(); + return ExprError(); + } + } } else if (TypeIdParens.isValid()) { // Can't have dynamic array size when the type-id is in parentheses. Diag(ArraySize->getLocStart(), diag::ext_new_paren_array_nonconst) @@ -730,7 +742,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } ImpCastExprToType(ArraySize, Context.getSizeType(), - CastExpr::CK_IntegralCast); + CK_IntegralCast); } FunctionDecl *OperatorNew = 0; @@ -768,7 +780,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, CXXConstructorDecl *Constructor = 0; Expr **ConsArgs = (Expr**)ConstructorArgs.get(); unsigned NumConsArgs = ConstructorArgs.size(); - ASTOwningVector<&ActionBase::DeleteExpr> ConvertedConstructorArgs(*this); + ASTOwningVector ConvertedConstructorArgs(*this); // Array 'new' can't have any initializers. if (NumConsArgs && (ResultType->isArrayType() || ArraySize)) { @@ -798,7 +810,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, AllocType); InitializationSequence InitSeq(*this, Entity, Kind, ConsArgs, NumConsArgs); - OwningExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, + ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, move(ConstructorArgs)); if (FullInit.isInvalid()) return ExprError(); @@ -839,7 +851,6 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, PlacementArgs.release(); ConstructorArgs.release(); - ArraySizeE.release(); // FIXME: The TypeSourceInfo should also be included in CXXNewExpr. return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew, @@ -911,7 +922,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // We don't care about the actual value of this argument. // FIXME: Should the Sema create the expression and embed it in the syntax // tree? Or should the consumer just recalculate the value? - IntegerLiteral Size(llvm::APInt::getNullValue( + IntegerLiteral Size(Context, llvm::APInt::getNullValue( Context.Target.getPointerWidth(0)), Context.getSizeType(), SourceLocation()); @@ -929,9 +940,11 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_Delete : OO_Delete); - if (AllocType->isRecordType() && !UseGlobal) { + QualType AllocElemType = Context.getBaseElementType(AllocType); + + if (AllocElemType->isRecordType() && !UseGlobal) { CXXRecordDecl *Record - = cast(AllocType->getAs()->getDecl()); + = cast(AllocElemType->getAs()->getDecl()); if (FindAllocationOverload(StartLoc, Range, NewName, &AllocArgs[0], AllocArgs.size(), Record, /*AllowMissing=*/true, OperatorNew)) @@ -969,9 +982,9 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // the allocated type is not a class type or array thereof, the // deallocation function’s name is looked up in the global scope. LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); - if (AllocType->isRecordType() && !UseGlobal) { + if (AllocElemType->isRecordType() && !UseGlobal) { CXXRecordDecl *RD - = cast(AllocType->getAs()->getDecl()); + = cast(AllocElemType->getAs()->getDecl()); LookupQualifiedName(FoundDelete, RD); } if (FoundDelete.isAmbiguous()) @@ -1115,7 +1128,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, // Do the resolution. OverloadCandidateSet::iterator Best; - switch(BestViableFunction(Candidates, StartLoc, Best)) { + switch (Candidates.BestViableFunction(*this, StartLoc, Best)) { case OR_Success: { // Got one! FunctionDecl *FnDecl = Best->Function; @@ -1125,7 +1138,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, // Watch out for variadic allocator function. unsigned NumArgsInFnDecl = FnDecl->getNumParams(); for (unsigned i = 0; (i < NumArgs && i < NumArgsInFnDecl); ++i) { - OwningExprResult Result + ExprResult Result = PerformCopyInitialization(InitializedEntity::InitializeParameter( FnDecl->getParamDecl(i)), SourceLocation(), @@ -1143,20 +1156,20 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, case OR_No_Viable_Function: Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) << Name << Range; - PrintOverloadCandidates(Candidates, OCD_AllCandidates, Args, NumArgs); + Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); return true; case OR_Ambiguous: Diag(StartLoc, diag::err_ovl_ambiguous_call) << Name << Range; - PrintOverloadCandidates(Candidates, OCD_ViableCandidates, Args, NumArgs); + Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs); return true; case OR_Deleted: Diag(StartLoc, diag::err_ovl_deleted_call) << Best->Function->isDeleted() << Name << Range; - PrintOverloadCandidates(Candidates, OCD_AllCandidates, Args, NumArgs); + Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); return true; } assert(false && "Unreachable, bad result from BestViableFunction"); @@ -1199,11 +1212,11 @@ void Sema::DeclareGlobalNewDelete() { // The "std::bad_alloc" class has not yet been declared, so build it // implicitly. StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, - getStdNamespace(), + getOrCreateStdNamespace(), SourceLocation(), &PP.getIdentifierTable().get("bad_alloc"), SourceLocation(), 0); - StdBadAlloc->setImplicit(true); + getStdBadAlloc()->setImplicit(true); } GlobalNewDeleteDeclared = true; @@ -1245,8 +1258,11 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, Context.getCanonicalType( Func->getParamDecl(0)->getType().getUnqualifiedType()); // FIXME: Do we need to check for default arguments here? - if (Func->getNumParams() == 1 && InitialParamType == Argument) + if (Func->getNumParams() == 1 && InitialParamType == Argument) { + if(AddMallocAttr && !Func->hasAttr()) + Func->addAttr(::new (Context) MallocAttr(SourceLocation(), Context)); return; + } } } } @@ -1257,7 +1273,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, Name.getCXXOverloadedOperator() == OO_Array_New); if (HasBadAllocExceptionSpec) { assert(StdBadAlloc && "Must have std::bad_alloc declared"); - BadAllocType = Context.getTypeDeclType(StdBadAlloc); + BadAllocType = Context.getTypeDeclType(getStdBadAlloc()); } QualType FnType = Context.getFunctionType(Return, &Argument, 1, false, 0, @@ -1267,23 +1283,23 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, FunctionType::ExtInfo()); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, - FnType, /*TInfo=*/0, FunctionDecl::None, - FunctionDecl::None, false, true); + FnType, /*TInfo=*/0, SC_None, + SC_None, false, true); Alloc->setImplicit(); if (AddMallocAttr) - Alloc->addAttr(::new (Context) MallocAttr()); + Alloc->addAttr(::new (Context) MallocAttr(SourceLocation(), Context)); ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), 0, Argument, /*TInfo=*/0, - VarDecl::None, - VarDecl::None, 0); + SC_None, + SC_None, 0); Alloc->setParams(&Param, 1); // FIXME: Also add this declaration to the IdentifierResolver, but // make sure it is at the end of the chain to coincide with the // global scope. - ((DeclContext *)TUScope->getEntity())->addDecl(Alloc); + Context.getTranslationUnitDecl()->addDecl(Alloc); } bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, @@ -1298,15 +1314,37 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, Found.suppressDiagnostics(); + llvm::SmallVector Matches; for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); F != FEnd; ++F) { - if (CXXMethodDecl *Delete = dyn_cast(*F)) - if (Delete->isUsualDeallocationFunction()) { - Operator = Delete; - CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(), - F.getPair()); - return false; - } + NamedDecl *ND = (*F)->getUnderlyingDecl(); + + // Ignore template operator delete members from the check for a usual + // deallocation function. + if (isa(ND)) + continue; + + if (cast(ND)->isUsualDeallocationFunction()) + Matches.push_back(F.getPair()); + } + + // There's exactly one suitable operator; pick it. + if (Matches.size() == 1) { + Operator = cast(Matches[0]->getUnderlyingDecl()); + CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(), + Matches[0]); + return false; + + // We found multiple suitable operators; complain about the ambiguity. + } else if (!Matches.empty()) { + Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) + << Name << RD; + + for (llvm::SmallVectorImpl::iterator + F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F) + Diag((*F)->getUnderlyingDecl()->getLocation(), + diag::note_member_declared_here) << Name; + return true; } // We did find operator delete/operator delete[] declarations, but @@ -1316,10 +1354,9 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, << Name << RD; for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); - F != FEnd; ++F) { - Diag((*F)->getLocation(), diag::note_member_declared_here) - << Name; - } + F != FEnd; ++F) + Diag((*F)->getUnderlyingDecl()->getLocation(), + diag::note_member_declared_here) << Name; return true; } @@ -1344,9 +1381,9 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, /// @code ::delete ptr; @endcode /// or /// @code delete [] ptr; @endcode -Action::OwningExprResult +ExprResult Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, - bool ArrayForm, ExprArg Operand) { + bool ArrayForm, Expr *Ex) { // C++ [expr.delete]p1: // The operand shall have a pointer type, or a class type having a single // conversion function to a pointer type. The result has type void. @@ -1355,11 +1392,14 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, FunctionDecl *OperatorDelete = 0; - Expr *Ex = (Expr *)Operand.get(); if (!Ex->isTypeDependent()) { QualType Type = Ex->getType(); if (const RecordType *Record = Type->getAs()) { + if (RequireCompleteType(StartLoc, Type, + PDiag(diag::err_delete_incomplete_class_type))) + return ExprError(); + llvm::SmallVector ObjectPtrConversions; CXXRecordDecl *RD = cast(Record->getDecl()); @@ -1378,18 +1418,16 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, QualType ConvType = Conv->getConversionType().getNonReferenceType(); if (const PointerType *ConvPtrType = ConvType->getAs()) - if (ConvPtrType->getPointeeType()->isObjectType()) + if (ConvPtrType->getPointeeType()->isIncompleteOrObjectType()) ObjectPtrConversions.push_back(Conv); } if (ObjectPtrConversions.size() == 1) { // We have a single conversion to a pointer-to-object type. Perform // that conversion. // TODO: don't redo the conversion calculation. - Operand.release(); if (!PerformImplicitConversion(Ex, ObjectPtrConversions.front()->getConversionType(), AA_Converting)) { - Operand = Owned(Ex); Type = Ex->getType(); } } @@ -1428,16 +1466,13 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // (5.2.11) of the pointer expression before it is used as the operand // of the delete-expression. ] ImpCastExprToType(Ex, Context.getPointerType(Context.VoidTy), - CastExpr::CK_NoOp); - - // Update the operand. - Operand.take(); - Operand = ExprArg(*this, Ex); + CK_NoOp); DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( ArrayForm ? OO_Array_Delete : OO_Delete); - if (const RecordType *RT = Pointee->getAs()) { + QualType PointeeElem = Context.getBaseElementType(Pointee); + if (const RecordType *RT = PointeeElem->getAs()) { CXXRecordDecl *RD = cast(RT->getDecl()); if (!UseGlobal && @@ -1465,14 +1500,13 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // FIXME: Check access and ambiguity of operator delete and destructor. } - Operand.release(); return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, OperatorDelete, Ex, StartLoc)); } /// \brief Check the use of the given variable as a C++ condition in an if, /// while, do-while, or switch statement. -Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, +ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, bool ConvertToBoolean) { QualType T = ConditionVar->getType(); @@ -1491,10 +1525,8 @@ Action::OwningExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, Expr *Condition = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar, ConditionVar->getLocation(), ConditionVar->getType().getNonReferenceType()); - if (ConvertToBoolean && CheckBooleanCondition(Condition, StmtLoc)) { - Condition->Destroy(Context); + if (ConvertToBoolean && CheckBooleanCondition(Condition, StmtLoc)) return ExprError(); - } return Owned(Condition); } @@ -1543,34 +1575,33 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { return false; } -static Sema::OwningExprResult BuildCXXCastArgument(Sema &S, - SourceLocation CastLoc, - QualType Ty, - CastExpr::CastKind Kind, - CXXMethodDecl *Method, - Sema::ExprArg Arg) { - Expr *From = Arg.takeAs(); - +static ExprResult BuildCXXCastArgument(Sema &S, + SourceLocation CastLoc, + QualType Ty, + CastKind Kind, + CXXMethodDecl *Method, + Expr *From) { switch (Kind) { default: assert(0 && "Unhandled cast kind!"); - case CastExpr::CK_ConstructorConversion: { - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); + case CK_ConstructorConversion: { + ASTOwningVector ConstructorArgs(S); if (S.CompleteConstructorCall(cast(Method), - Sema::MultiExprArg(S, (void **)&From, 1), + MultiExprArg(&From, 1), CastLoc, ConstructorArgs)) - return S.ExprError(); + return ExprError(); - Sema::OwningExprResult Result = + ExprResult Result = S.BuildCXXConstructExpr(CastLoc, Ty, cast(Method), - move_arg(ConstructorArgs)); + move_arg(ConstructorArgs), + /*ZeroInit*/ false, CXXConstructExpr::CK_Complete); if (Result.isInvalid()) - return S.ExprError(); + return ExprError(); return S.MaybeBindToTemporary(Result.takeAs()); } - case CastExpr::CK_UserDefinedConversion: { + case CK_UserDefinedConversion: { assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); // Create an implicit call expr that calls it. @@ -1601,10 +1632,10 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ImplicitConversionSequence::UserDefinedConversion: { FunctionDecl *FD = ICS.UserDefined.ConversionFunction; - CastExpr::CastKind CastKind = CastExpr::CK_Unknown; + CastKind CastKind = CK_Unknown; QualType BeforeToType; if (const CXXConversionDecl *Conv = dyn_cast(FD)) { - CastKind = CastExpr::CK_UserDefinedConversion; + CastKind = CK_UserDefinedConversion; // If the user-defined conversion is specified by a conversion function, // the initial standard conversion sequence converts the source type to @@ -1612,7 +1643,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, BeforeToType = Context.getTagDeclType(Conv->getParent()); } else if (const CXXConstructorDecl *Ctor = dyn_cast(FD)) { - CastKind = CastExpr::CK_ConstructorConversion; + CastKind = CK_ConstructorConversion; // Do no conversion if dealing with ... for the first conversion. if (!ICS.UserDefined.EllipsisConversion) { // If the user-defined conversion is specified by a constructor, the @@ -1631,12 +1662,12 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return true; } - OwningExprResult CastArg + ExprResult CastArg = BuildCXXCastArgument(*this, From->getLocStart(), ToType.getNonReferenceType(), CastKind, cast(FD), - Owned(From)); + From); if (CastArg.isInvalid()) return true; @@ -1648,7 +1679,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, } case ImplicitConversionSequence::AmbiguousConversion: - DiagnoseAmbiguousConversion(ICS, From->getExprLoc(), + ICS.DiagnoseAmbiguousConversion(*this, From->getExprLoc(), PDiag(diag::err_typecheck_ambiguous_condition) << From->getSourceRange()); return true; @@ -1685,25 +1716,29 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // FIXME: When can ToType be a reference type? assert(!ToType->isReferenceType()); if (SCS.Second == ICK_Derived_To_Base) { - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(*this); + ASTOwningVector ConstructorArgs(*this); if (CompleteConstructorCall(cast(SCS.CopyConstructor), - MultiExprArg(*this, (void **)&From, 1), + MultiExprArg(*this, &From, 1), /*FIXME:ConstructLoc*/SourceLocation(), ConstructorArgs)) return true; - OwningExprResult FromResult = + ExprResult FromResult = BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), ToType, SCS.CopyConstructor, - move_arg(ConstructorArgs)); + move_arg(ConstructorArgs), + /*ZeroInit*/ false, + CXXConstructExpr::CK_Complete); if (FromResult.isInvalid()) return true; From = FromResult.takeAs(); return false; } - OwningExprResult FromResult = + ExprResult FromResult = BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), ToType, SCS.CopyConstructor, - MultiExprArg(*this, (void**)&From, 1)); + MultiExprArg(*this, &From, 1), + /*ZeroInit*/ false, + CXXConstructExpr::CK_Complete); if (FromResult.isInvalid()) return true; @@ -1736,12 +1771,12 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Array_To_Pointer: FromType = Context.getArrayDecayedType(FromType); - ImpCastExprToType(From, FromType, CastExpr::CK_ArrayToPointerDecay); + ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay); break; case ICK_Function_To_Pointer: FromType = Context.getPointerType(FromType); - ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay); + ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay); break; default: @@ -1766,33 +1801,33 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return true; ImpCastExprToType(From, Context.getNoReturnType(From->getType(), false), - CastExpr::CK_NoOp); + CK_NoOp); break; case ICK_Integral_Promotion: case ICK_Integral_Conversion: - ImpCastExprToType(From, ToType, CastExpr::CK_IntegralCast); + ImpCastExprToType(From, ToType, CK_IntegralCast); break; case ICK_Floating_Promotion: case ICK_Floating_Conversion: - ImpCastExprToType(From, ToType, CastExpr::CK_FloatingCast); + ImpCastExprToType(From, ToType, CK_FloatingCast); break; case ICK_Complex_Promotion: case ICK_Complex_Conversion: - ImpCastExprToType(From, ToType, CastExpr::CK_Unknown); + ImpCastExprToType(From, ToType, CK_Unknown); break; case ICK_Floating_Integral: if (ToType->isRealFloatingType()) - ImpCastExprToType(From, ToType, CastExpr::CK_IntegralToFloating); + ImpCastExprToType(From, ToType, CK_IntegralToFloating); else - ImpCastExprToType(From, ToType, CastExpr::CK_FloatingToIntegral); + ImpCastExprToType(From, ToType, CK_FloatingToIntegral); break; case ICK_Compatible_Conversion: - ImpCastExprToType(From, ToType, CastExpr::CK_NoOp); + ImpCastExprToType(From, ToType, CK_NoOp); break; case ICK_Pointer_Conversion: { @@ -1805,36 +1840,36 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, } - CastExpr::CastKind Kind = CastExpr::CK_Unknown; - CXXBaseSpecifierArray BasePath; + CastKind Kind = CK_Unknown; + CXXCastPath BasePath; if (CheckPointerConversion(From, ToType, Kind, BasePath, IgnoreBaseAccess)) return true; - ImpCastExprToType(From, ToType, Kind, /*isLvalue=*/false, BasePath); + ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath); break; } case ICK_Pointer_Member: { - CastExpr::CastKind Kind = CastExpr::CK_Unknown; - CXXBaseSpecifierArray BasePath; + CastKind Kind = CK_Unknown; + CXXCastPath BasePath; if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, IgnoreBaseAccess)) return true; if (CheckExceptionSpecCompatibility(From, ToType)) return true; - ImpCastExprToType(From, ToType, Kind, /*isLvalue=*/false, BasePath); + ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath); break; } case ICK_Boolean_Conversion: { - CastExpr::CastKind Kind = CastExpr::CK_Unknown; + CastKind Kind = CK_Unknown; if (FromType->isMemberPointerType()) - Kind = CastExpr::CK_MemberPointerToBoolean; + Kind = CK_MemberPointerToBoolean; ImpCastExprToType(From, Context.BoolTy, Kind); break; } case ICK_Derived_To_Base: { - CXXBaseSpecifierArray BasePath; + CXXCastPath BasePath; if (CheckDerivedToBaseConversion(From->getType(), ToType.getNonReferenceType(), From->getLocStart(), @@ -1843,24 +1878,22 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, IgnoreBaseAccess)) return true; - ImpCastExprToType(From, ToType.getNonReferenceType(), - CastExpr::CK_DerivedToBase, - /*isLvalue=*/(From->getType()->isRecordType() && - From->isLvalue(Context) == Expr::LV_Valid), - BasePath); + ImpCastExprToType(From, ToType.getNonReferenceType(), + CK_DerivedToBase, CastCategory(From), + &BasePath); break; } case ICK_Vector_Conversion: - ImpCastExprToType(From, ToType, CastExpr::CK_BitCast); + ImpCastExprToType(From, ToType, CK_BitCast); break; case ICK_Vector_Splat: - ImpCastExprToType(From, ToType, CastExpr::CK_VectorSplat); + ImpCastExprToType(From, ToType, CK_VectorSplat); break; case ICK_Complex_Real: - ImpCastExprToType(From, ToType, CastExpr::CK_Unknown); + ImpCastExprToType(From, ToType, CK_Unknown); break; case ICK_Lvalue_To_Rvalue: @@ -1877,18 +1910,21 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // Nothing to do. break; - case ICK_Qualification: - // FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue - // references. + case ICK_Qualification: { + // The qualification keeps the category of the inner expression, unless the + // target type isn't a reference. + ExprValueKind VK = ToType->isReferenceType() ? + CastCategory(From) : VK_RValue; ImpCastExprToType(From, ToType.getNonLValueExprType(Context), - CastExpr::CK_NoOp, ToType->isLValueReferenceType()); + CK_NoOp, VK); if (SCS.DeprecatedStringLiteralToCharPtr) Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion) << ToType.getNonReferenceType(); break; - + } + default: assert(false && "Improper third standard conversion"); break; @@ -1897,10 +1933,10 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, return false; } -Sema::OwningExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT, +ExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait OTT, SourceLocation KWLoc, SourceLocation LParen, - TypeTy *Ty, + ParsedType Ty, SourceLocation RParen) { QualType T = GetTypeFromParser(Ty); @@ -1974,12 +2010,12 @@ QualType Sema::CheckPointerToMemberOperands( } // Cast LHS to type of use. QualType UseType = isIndirect ? Context.getPointerType(Class) : Class; - bool isLValue = !isIndirect && lex->isLvalue(Context) == Expr::LV_Valid; - - CXXBaseSpecifierArray BasePath; + ExprValueKind VK = + isIndirect ? VK_RValue : CastCategory(lex); + + CXXCastPath BasePath; BuildBasePathArray(Paths, BasePath); - ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue, - BasePath); + ImpCastExprToType(lex, UseType, CK_DerivedToBase, VK, &BasePath); } if (isa(rex->IgnoreParens())) { @@ -2108,7 +2144,7 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, Self.AddBuiltinOperatorCandidates(OO_Conditional, Loc, Args, 2, CandidateSet); OverloadCandidateSet::iterator Best; - switch (Self.BestViableFunction(CandidateSet, Loc, Best)) { + switch (CandidateSet.BestViableFunction(Self, Loc, Best)) { case OR_Success: // We found a match. Perform the conversions on the arguments and move on. if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0], @@ -2146,8 +2182,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) { InitializationKind Kind = InitializationKind::CreateCopy(E->getLocStart(), SourceLocation()); InitializationSequence InitSeq(Self, Entity, Kind, &E, 1); - Sema::OwningExprResult Result = InitSeq.Perform(Self, Entity, Kind, - Sema::MultiExprArg(Self, (void **)&E, 1)); + ExprResult Result = InitSeq.Perform(Self, Entity, Kind, MultiExprArg(&E, 1)); if (Result.isInvalid()) return true; @@ -2286,13 +2321,13 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (LTy->isRecordType()) { // The operands have class type. Make a temporary copy. InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); - OwningExprResult LHSCopy = PerformCopyInitialization(Entity, + ExprResult LHSCopy = PerformCopyInitialization(Entity, SourceLocation(), Owned(LHS)); if (LHSCopy.isInvalid()) return QualType(); - OwningExprResult RHSCopy = PerformCopyInitialization(Entity, + ExprResult RHSCopy = PerformCopyInitialization(Entity, SourceLocation(), Owned(RHS)); if (RHSCopy.isInvalid()) @@ -2385,16 +2420,16 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // the type of the other operand. if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (T2->isMemberPointerType()) - ImpCastExprToType(E1, T2, CastExpr::CK_NullToMemberPointer); + ImpCastExprToType(E1, T2, CK_NullToMemberPointer); else - ImpCastExprToType(E1, T2, CastExpr::CK_IntegralToPointer); + ImpCastExprToType(E1, T2, CK_IntegralToPointer); return T2; } if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (T1->isMemberPointerType()) - ImpCastExprToType(E2, T1, CastExpr::CK_NullToMemberPointer); + ImpCastExprToType(E2, T1, CK_NullToMemberPointer); else - ImpCastExprToType(E2, T1, CastExpr::CK_IntegralToPointer); + ImpCastExprToType(E2, T1, CK_IntegralToPointer); return T1; } @@ -2528,15 +2563,15 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, } // Convert E1 to Composite1 - OwningExprResult E1Result - = E1ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,(void**)&E1,1)); + ExprResult E1Result + = E1ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,&E1,1)); if (E1Result.isInvalid()) return QualType(); E1 = E1Result.takeAs(); // Convert E2 to Composite1 - OwningExprResult E2Result - = E2ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,(void**)&E2,1)); + ExprResult E2Result + = E2ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,&E2,1)); if (E2Result.isInvalid()) return QualType(); E2 = E2Result.takeAs(); @@ -2553,15 +2588,15 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, return QualType(); // Convert E1 to Composite2 - OwningExprResult E1Result - = E1ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, (void**)&E1, 1)); + ExprResult E1Result + = E1ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E1, 1)); if (E1Result.isInvalid()) return QualType(); E1 = E1Result.takeAs(); // Convert E2 to Composite2 - OwningExprResult E2Result - = E2ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, (void**)&E2, 1)); + ExprResult E2Result + = E2ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E2, 1)); if (E2Result.isInvalid()) return QualType(); E2 = E2Result.takeAs(); @@ -2569,7 +2604,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, return Composite2; } -Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { +ExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!Context.getLangOptions().CPlusPlus) return Owned(E); @@ -2579,34 +2614,22 @@ Sema::OwningExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!RT) return Owned(E); - // If this is the result of a call expression, our source might - // actually be a reference, in which case we shouldn't bind. + // If this is the result of a call or an Objective-C message send expression, + // our source might actually be a reference, in which case we shouldn't bind. if (CallExpr *CE = dyn_cast(E)) { - QualType Ty = CE->getCallee()->getType(); - if (const PointerType *PT = Ty->getAs()) - Ty = PT->getPointeeType(); - else if (const BlockPointerType *BPT = Ty->getAs()) - Ty = BPT->getPointeeType(); - - const FunctionType *FTy = Ty->getAs(); - if (FTy->getResultType()->isReferenceType()) + if (CE->getCallReturnType()->isReferenceType()) return Owned(E); + } else if (ObjCMessageExpr *ME = dyn_cast(E)) { + if (const ObjCMethodDecl *MD = ME->getMethodDecl()) { + if (MD->getResultType()->isReferenceType()) + return Owned(E); + } } - else if (ObjCMessageExpr *ME = dyn_cast(E)) { - QualType Ty = ME->getType(); - if (const PointerType *PT = Ty->getAs()) - Ty = PT->getPointeeType(); - else if (const BlockPointerType *BPT = Ty->getAs()) - Ty = BPT->getPointeeType(); - if (Ty->isReferenceType()) - return Owned(E); - } - // That should be enough to guarantee that this type is complete. // If it has a trivial destructor, we can avoid the extra copy. CXXRecordDecl *RD = cast(RT->getDecl()); - if (RD->hasTrivialDestructor()) + if (RD->isInvalidDecl() || RD->hasTrivialDestructor()) return Owned(E); CXXTemporary *Temp = CXXTemporary::Create(Context, LookupDestructor(RD)); @@ -2641,8 +2664,8 @@ Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr) { return E; } -Sema::OwningExprResult -Sema::MaybeCreateCXXExprWithTemporaries(OwningExprResult SubExpr) { +ExprResult +Sema::MaybeCreateCXXExprWithTemporaries(ExprResult SubExpr) { if (SubExpr.isInvalid()) return ExprError(); @@ -2665,17 +2688,16 @@ FullExpr Sema::CreateFullExpr(Expr *SubExpr) { return E; } -Sema::OwningExprResult -Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, - tok::TokenKind OpKind, TypeTy *&ObjectType, +ExprResult +Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, + tok::TokenKind OpKind, ParsedType &ObjectType, bool &MayBePseudoDestructor) { // Since this might be a postfix expression, get rid of ParenListExprs. - Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); + ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base); + if (Result.isInvalid()) return ExprError(); + Base = Result.get(); - Expr *BaseExpr = (Expr*)Base.get(); - assert(BaseExpr && "no record expansion"); - - QualType BaseType = BaseExpr->getType(); + QualType BaseType = Base->getType(); MayBePseudoDestructor = false; if (BaseType->isDependentType()) { // If we have a pointer to a dependent type and are using the -> operator, @@ -2685,9 +2707,9 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, if (const PointerType *Ptr = BaseType->getAs()) BaseType = Ptr->getPointeeType(); - ObjectType = BaseType.getAsOpaquePtr(); + ObjectType = ParsedType::make(BaseType); MayBePseudoDestructor = true; - return move(Base); + return Owned(Base); } // C++ [over.match.oper]p8: @@ -2700,13 +2722,13 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, CTypes.insert(Context.getCanonicalType(BaseType)); while (BaseType->isRecordType()) { - Base = BuildOverloadedArrowExpr(S, move(Base), OpLoc); - BaseExpr = (Expr*)Base.get(); - if (BaseExpr == NULL) + Result = BuildOverloadedArrowExpr(S, Base, OpLoc); + if (Result.isInvalid()) return ExprError(); - if (CXXOperatorCallExpr *OpCall = dyn_cast(BaseExpr)) + Base = Result.get(); + if (CXXOperatorCallExpr *OpCall = dyn_cast(Base)) Locations.push_back(OpCall->getDirectCallee()->getLocation()); - BaseType = BaseExpr->getType(); + BaseType = Base->getType(); CanQualType CBaseType = Context.getCanonicalType(BaseType); if (!CTypes.insert(CBaseType)) { Diag(OpLoc, diag::err_operator_arrow_circular); @@ -2731,9 +2753,9 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, // // This also indicates that we should be parsing a // pseudo-destructor-name. - ObjectType = 0; + ObjectType = ParsedType(); MayBePseudoDestructor = true; - return move(Base); + return Owned(Base); } // The object type must be complete (or dependent). @@ -2747,27 +2769,26 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, // unqualified-id, and the type of the object expression is of a class // type C (or of pointer to a class type C), the unqualified-id is looked // up in the scope of class C. [...] - ObjectType = BaseType.getAsOpaquePtr(); + ObjectType = ParsedType::make(BaseType); return move(Base); } -Sema::OwningExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc, - ExprArg MemExpr) { - Expr *E = (Expr *) MemExpr.get(); +ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc, + Expr *MemExpr) { SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(NameLoc); - Diag(E->getLocStart(), diag::err_dtor_expr_without_call) - << isa(E) + Diag(MemExpr->getLocStart(), diag::err_dtor_expr_without_call) + << isa(MemExpr) << FixItHint::CreateInsertion(ExpectedLParenLoc, "()"); return ActOnCallExpr(/*Scope*/ 0, - move(MemExpr), + MemExpr, /*LPLoc*/ ExpectedLParenLoc, - Sema::MultiExprArg(*this, 0, 0), + MultiExprArg(), /*CommaLocs*/ 0, /*RPLoc*/ ExpectedLParenLoc); } -Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, +ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, const CXXScopeSpec &SS, @@ -2782,12 +2803,11 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, // The left-hand side of the dot operator shall be of scalar type. The // left-hand side of the arrow operator shall be of pointer to scalar type. // This scalar type is the object type. - Expr *BaseE = (Expr *)Base.get(); - QualType ObjectType = BaseE->getType(); + QualType ObjectType = Base->getType(); if (OpKind == tok::arrow) { if (const PointerType *Ptr = ObjectType->getAs()) { ObjectType = Ptr->getPointeeType(); - } else if (!BaseE->isTypeDependent()) { + } else if (!Base->isTypeDependent()) { // The user wrote "p->" when she probably meant "p."; fix it. Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << ObjectType << true @@ -2801,7 +2821,7 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) { Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) - << ObjectType << BaseE->getSourceRange(); + << ObjectType << Base->getSourceRange(); return ExprError(); } @@ -2815,7 +2835,7 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, if (!DestructedType->isDependentType() && !ObjectType->isDependentType() && !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) - << ObjectType << DestructedType << BaseE->getSourceRange() + << ObjectType << DestructedType << Base->getSourceRange() << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); // Recover by setting the destructed type to the object type. @@ -2840,7 +2860,7 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(), diag::err_pseudo_dtor_type_mismatch) - << ObjectType << ScopeType << BaseE->getSourceRange() + << ObjectType << ScopeType << Base->getSourceRange() << ScopeTypeInfo->getTypeLoc().getLocalSourceRange(); ScopeType = QualType(); @@ -2848,25 +2868,22 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base, } } - OwningExprResult Result - = Owned(new (Context) CXXPseudoDestructorExpr(Context, - Base.takeAs(), - OpKind == tok::arrow, - OpLoc, - (NestedNameSpecifier *) SS.getScopeRep(), - SS.getRange(), - ScopeTypeInfo, - CCLoc, - TildeLoc, - Destructed)); + Expr *Result + = new (Context) CXXPseudoDestructorExpr(Context, Base, + OpKind == tok::arrow, OpLoc, + SS.getScopeRep(), SS.getRange(), + ScopeTypeInfo, + CCLoc, + TildeLoc, + Destructed); if (HasTrailingLParen) - return move(Result); + return Owned(Result); - return DiagnoseDtorReference(Destructed.getLocation(), move(Result)); + return DiagnoseDtorReference(Destructed.getLocation(), Result); } -Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, +ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, @@ -2882,13 +2899,11 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) && "Invalid second type name in pseudo-destructor"); - Expr *BaseE = (Expr *)Base.get(); - // C++ [expr.pseudo]p2: // The left-hand side of the dot operator shall be of scalar type. The // left-hand side of the arrow operator shall be of pointer to scalar type. // This scalar type is the object type. - QualType ObjectType = BaseE->getType(); + QualType ObjectType = Base->getType(); if (OpKind == tok::arrow) { if (const PointerType *Ptr = ObjectType->getAs()) { ObjectType = Ptr->getPointeeType(); @@ -2906,12 +2921,12 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, // Compute the object type that we should use for name lookup purposes. Only // record types and dependent types matter. - void *ObjectTypePtrForLookup = 0; + ParsedType ObjectTypePtrForLookup; if (!SS.isSet()) { - ObjectTypePtrForLookup = const_cast( - ObjectType->getAs()); - if (!ObjectTypePtrForLookup && ObjectType->isDependentType()) - ObjectTypePtrForLookup = Context.DependentTy.getAsOpaquePtr(); + if (const Type *T = ObjectType->getAs()) + ObjectTypePtrForLookup = ParsedType::make(QualType(T, 0)); + else if (ObjectType->isDependentType()) + ObjectTypePtrForLookup = ParsedType::make(Context.DependentTy); } // Convert the name of the type being destructed (following the ~) into a @@ -2920,9 +2935,9 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, TypeSourceInfo *DestructedTypeInfo = 0; PseudoDestructorTypeStorage Destructed; if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) { - TypeTy *T = getTypeName(*SecondTypeName.Identifier, - SecondTypeName.StartLocation, - S, &SS, true, ObjectTypePtrForLookup); + ParsedType T = getTypeName(*SecondTypeName.Identifier, + SecondTypeName.StartLocation, + S, &SS, true, ObjectTypePtrForLookup); if (!T && ((SS.isSet() && !computeDeclContext(SS, false)) || (!SS.isSet() && ObjectType->isDependentType()))) { @@ -2949,7 +2964,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), TemplateId->NumArgs); - TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + TypeResult T = ActOnTemplateIdType(TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, @@ -2976,9 +2991,9 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || FirstTypeName.Identifier) { if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) { - TypeTy *T = getTypeName(*FirstTypeName.Identifier, - FirstTypeName.StartLocation, - S, &SS, false, ObjectTypePtrForLookup); + ParsedType T = getTypeName(*FirstTypeName.Identifier, + FirstTypeName.StartLocation, + S, &SS, false, ObjectTypePtrForLookup); if (!T) { Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) @@ -2997,7 +3012,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), TemplateId->NumArgs); - TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), + TypeResult T = ActOnTemplateIdType(TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, @@ -3015,7 +3030,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, FirstTypeName.StartLocation); - return BuildPseudoDestructorExpr(move(Base), OpLoc, OpKind, SS, + return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, SS, ScopeTypeInfo, CCLoc, TildeLoc, Destructed, HasTrailingLParen); } @@ -3028,7 +3043,7 @@ CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, assert(0 && "Calling BuildCXXMemberCallExpr with invalid call?"); MemberExpr *ME = - new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method, + new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method, SourceLocation(), Method->getType()); QualType ResultType = Method->getCallResultType(); MarkDeclarationReferenced(Exp->getLocStart(), Method); @@ -3038,12 +3053,7 @@ CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, return CE; } -Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) { - Expr *FullExpr = Arg.takeAs(); - if (FullExpr) - FullExpr = MaybeCreateCXXExprWithTemporaries(FullExpr); - else - return ExprError(); - - return Owned(FullExpr); +ExprResult Sema::ActOnFinishFullExpr(Expr *FullExpr) { + if (!FullExpr) return ExprError(); + return MaybeCreateCXXExprWithTemporaries(FullExpr); } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 9f43471..b56159c 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -11,9 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "Lookup.h" -#include "SemaInit.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/Initialization.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprObjC.h" @@ -23,9 +24,9 @@ using namespace clang; -Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, - ExprTy **strings, - unsigned NumStrings) { +ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, + Expr **strings, + unsigned NumStrings) { StringLiteral **Strings = reinterpret_cast(strings); // Most ObjC strings are formed out of a single piece. However, we *can* @@ -50,14 +51,11 @@ Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, return true; } - // Get the string data. - StrBuf.append(S->getStrData(), S->getStrData()+S->getByteLength()); + // Append the string. + StrBuf += S->getString(); // Get the locations of the string tokens. StrLocs.append(S->tokloc_begin(), S->tokloc_end()); - - // Free the temporary string. - S->Destroy(Context); } // Create the aggregate string with the appropriate content and location @@ -135,11 +133,11 @@ Expr *Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, return new (Context) ObjCEncodeExpr(StrTy, EncodedTypeInfo, AtLoc, RParenLoc); } -Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, - SourceLocation EncodeLoc, - SourceLocation LParenLoc, - TypeTy *ty, - SourceLocation RParenLoc) { +ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, + SourceLocation EncodeLoc, + SourceLocation LParenLoc, + ParsedType ty, + SourceLocation RParenLoc) { // FIXME: Preserve type source info ? TypeSourceInfo *TInfo; QualType EncodedType = GetTypeFromParser(ty, &TInfo); @@ -150,28 +148,33 @@ Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, return BuildObjCEncodeExpression(AtLoc, TInfo, RParenLoc); } -Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, - SourceLocation AtLoc, - SourceLocation SelLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc) { +ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, + SourceLocation AtLoc, + SourceLocation SelLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LParenLoc, RParenLoc), false); + SourceRange(LParenLoc, RParenLoc), false, false); if (!Method) Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LParenLoc, RParenLoc)); if (!Method) Diag(SelLoc, diag::warn_undeclared_selector) << Sel; + llvm::DenseMap::iterator Pos + = ReferencedSelectors.find(Sel); + if (Pos == ReferencedSelectors.end()) + ReferencedSelectors.insert(std::make_pair(Sel, SelLoc)); + QualType Ty = Context.getObjCSelType(); return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc); } -Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, - SourceLocation AtLoc, - SourceLocation ProtoLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc) { +ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, + SourceLocation AtLoc, + SourceLocation ProtoLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { ObjCProtocolDecl* PDecl = LookupProtocol(ProtocolId, ProtoLoc); if (!PDecl) { Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId; @@ -239,7 +242,7 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, return true; InitializedEntity Entity = InitializedEntity::InitializeParameter(Param); - OwningExprResult ArgE = PerformCopyInitialization(Entity, + ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), Owned(argExpr->Retain())); if (ArgE.isInvalid()) @@ -329,7 +332,7 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel, /// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an /// objective C interface. This is a property reference expression. -Action::OwningExprResult Sema:: +ExprResult Sema:: HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Expr *BaseExpr, DeclarationName MemberName, SourceLocation MemberLoc) { @@ -431,7 +434,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, -Action::OwningExprResult Sema:: +ExprResult Sema:: ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, IdentifierInfo &propertyName, SourceLocation receiverNameLoc, @@ -529,8 +532,8 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, SourceLocation NameLoc, bool IsSuper, bool HasTrailingDot, - TypeTy *&ReceiverType) { - ReceiverType = 0; + ParsedType &ReceiverType) { + ReceiverType = ParsedType(); // If the identifier is "super" and there is no trailing dot, we're // messaging super. @@ -577,7 +580,7 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, // We have a class message, and T is the type we're // messaging. Build source-location information for it. TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc); - ReceiverType = CreateLocInfoType(T, TSInfo).getAsOpaquePtr(); + ReceiverType = CreateParsedType(T, TSInfo); return ObjCClassMessage; } } @@ -604,7 +607,7 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, QualType T = Context.getObjCInterfaceType(Class); TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(T, NameLoc); - ReceiverType = CreateLocInfoType(T, TSInfo).getAsOpaquePtr(); + ReceiverType = CreateParsedType(T, TSInfo); return ObjCClassMessage; } } else if (Result.empty() && Corrected.getAsIdentifierInfo() && @@ -622,7 +625,7 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, return ObjCInstanceMessage; } -Sema::OwningExprResult Sema::ActOnSuperMessage(Scope *S, +ExprResult Sema::ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, Selector Sel, SourceLocation LBracLoc, @@ -657,7 +660,7 @@ Sema::OwningExprResult Sema::ActOnSuperMessage(Scope *S, // message to the superclass instance. QualType SuperTy = Context.getObjCInterfaceType(Super); SuperTy = Context.getObjCObjectPointerType(SuperTy); - return BuildInstanceMessage(ExprArg(*this), SuperTy, SuperLoc, + return BuildInstanceMessage(0, SuperTy, SuperLoc, Sel, /*Method=*/0, LBracLoc, RBracLoc, move(Args)); } @@ -698,7 +701,7 @@ Sema::OwningExprResult Sema::ActOnSuperMessage(Scope *S, /// \param RBrac The location of the closing square bracket ']'. /// /// \param Args The message arguments. -Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, +ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, @@ -757,11 +760,8 @@ Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, unsigned NumArgs = ArgsIn.size(); Expr **Args = reinterpret_cast(ArgsIn.release()); if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, true, - LBracLoc, RBracLoc, ReturnType)) { - for (unsigned I = 0; I != NumArgs; ++I) - Args[I]->Destroy(Context); + LBracLoc, RBracLoc, ReturnType)) return ExprError(); - } // Construct the appropriate ObjCMessageExpr. Expr *Result; @@ -780,8 +780,8 @@ Sema::OwningExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, // ActOnClassMessage - used for both unary and keyword messages. // ArgExprs is optional - if it is present, the number of expressions // is obtained from Sel.getNumArgs(). -Sema::OwningExprResult Sema::ActOnClassMessage(Scope *S, - TypeTy *Receiver, +ExprResult Sema::ActOnClassMessage(Scope *S, + ParsedType Receiver, Selector Sel, SourceLocation LBracLoc, SourceLocation SelectorLoc, @@ -829,7 +829,7 @@ Sema::OwningExprResult Sema::ActOnClassMessage(Scope *S, /// \param RBrac The location of the closing square bracket ']'. /// /// \param Args The message arguments. -Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, +ExprResult Sema::BuildInstanceMessage(Expr *Receiver, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, @@ -839,7 +839,6 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, MultiExprArg ArgsIn) { // If we have a receiver expression, perform appropriate promotions // and determine receiver type. - Expr *Receiver = ReceiverE.takeAs(); if (Receiver) { if (Receiver->isTypeDependent()) { // If the receiver is type-dependent, we can't type-check anything @@ -864,13 +863,16 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, if (!Method) { // Handle messages to id. - if (ReceiverType->isObjCIdType() || ReceiverType->isBlockPointerType() || + bool receiverIsId = ReceiverType->isObjCIdType(); + if (receiverIsId || ReceiverType->isBlockPointerType() || (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) { Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); + SourceRange(LBracLoc, RBracLoc), + receiverIsId); if (!Method) Method = LookupFactoryMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); + SourceRange(LBracLoc, RBracLoc), + receiverIsId); } else if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) { // Handle messages to Class. @@ -892,12 +894,14 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, // If not messaging 'self', look for any factory method named 'Sel'. if (!Receiver || !isSelfExpr(Receiver)) { Method = LookupFactoryMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); + SourceRange(LBracLoc, RBracLoc), + true); if (!Method) { // If no class (factory) method was found, check if an _instance_ // method of the same name exists in the root class only. Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); + SourceRange(LBracLoc, RBracLoc), + true); if (Method) if (const ObjCInterfaceDecl *ID = dyn_cast(Method->getDeclContext())) { @@ -931,7 +935,7 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, ClassDecl = OCIType->getInterfaceDecl(); // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be // faster than the following method (which can do *many* linear searches). - // The idea is to add class info to InstanceMethodPool. + // The idea is to add class info to MethodPool. Method = ClassDecl->lookupInstanceMethod(Sel); if (!Method) { @@ -952,7 +956,7 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, // compatibility. FIXME: should we deviate?? if (OCIType->qual_empty()) { Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); + SourceRange(LBracLoc, RBracLoc)); if (Method && !OCIType->getInterfaceDecl()->isForwardDecl()) Diag(Loc, diag::warn_maynot_respond) << OCIType->getInterfaceDecl()->getIdentifier() << Sel; @@ -962,19 +966,18 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, if (Method && DiagnoseUseOfDecl(Method, Loc)) return ExprError(); } else if (!Context.getObjCIdType().isNull() && - (ReceiverType->isPointerType() || - (ReceiverType->isIntegerType() && - ReceiverType->isScalarType()))) { + (ReceiverType->isPointerType() || + ReceiverType->isIntegerType())) { // Implicitly convert integers and pointers to 'id' but emit a warning. Diag(Loc, diag::warn_bad_receiver_type) << ReceiverType << Receiver->getSourceRange(); if (ReceiverType->isPointerType()) ImpCastExprToType(Receiver, Context.getObjCIdType(), - CastExpr::CK_BitCast); + CK_BitCast); else ImpCastExprToType(Receiver, Context.getObjCIdType(), - CastExpr::CK_IntegralToPointer); + CK_IntegralToPointer); ReceiverType = Receiver->getType(); } else if (getLangOptions().CPlusPlus && @@ -983,7 +986,7 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, Receiver = ICE->getSubExpr(); ReceiverType = Receiver->getType(); } - return BuildInstanceMessage(Owned(Receiver), + return BuildInstanceMessage(Receiver, ReceiverType, SuperLoc, Sel, @@ -1030,18 +1033,17 @@ Sema::OwningExprResult Sema::BuildInstanceMessage(ExprArg ReceiverE, // ActOnInstanceMessage - used for both unary and keyword messages. // ArgExprs is optional - if it is present, the number of expressions // is obtained from Sel.getNumArgs(). -Sema::OwningExprResult Sema::ActOnInstanceMessage(Scope *S, - ExprArg ReceiverE, - Selector Sel, - SourceLocation LBracLoc, - SourceLocation SelectorLoc, - SourceLocation RBracLoc, - MultiExprArg Args) { - Expr *Receiver = static_cast(ReceiverE.get()); +ExprResult Sema::ActOnInstanceMessage(Scope *S, + Expr *Receiver, + Selector Sel, + SourceLocation LBracLoc, + SourceLocation SelectorLoc, + SourceLocation RBracLoc, + MultiExprArg Args) { if (!Receiver) return ExprError(); - return BuildInstanceMessage(move(ReceiverE), Receiver->getType(), + return BuildInstanceMessage(Receiver, Receiver->getType(), /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0, LBracLoc, RBracLoc, move(Args)); } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 7ad1775..a28fd7f 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -15,12 +15,13 @@ // //===----------------------------------------------------------------------===// -#include "SemaInit.h" -#include "Lookup.h" -#include "Sema.h" +#include "clang/Sema/Designator.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Lex/Preprocessor.h" -#include "clang/Parse/Designator.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/TypeLoc.h" @@ -263,9 +264,8 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field, return; } - Sema::OwningExprResult MemberInit - = InitSeq.Perform(SemaRef, MemberEntity, Kind, - Sema::MultiExprArg(SemaRef, 0, 0)); + ExprResult MemberInit + = InitSeq.Perform(SemaRef, MemberEntity, Kind, MultiExprArg()); if (MemberInit.isInvalid()) { hadError = true; return; @@ -373,9 +373,8 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, return; } - Sema::OwningExprResult ElementInit - = InitSeq.Perform(SemaRef, ElementEntity, Kind, - Sema::MultiExprArg(SemaRef, 0, 0)); + ExprResult ElementInit + = InitSeq.Perform(SemaRef, ElementEntity, Kind, MultiExprArg()); if (ElementInit.isInvalid()) { hadError = true; return; @@ -678,9 +677,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, InitializationSequence Seq(SemaRef, Entity, Kind, &expr, 1); if (Seq) { - Sema::OwningExprResult Result = - Seq.Perform(SemaRef, Entity, Kind, - Sema::MultiExprArg(SemaRef, (void **)&expr, 1)); + ExprResult Result = + Seq.Perform(SemaRef, Entity, Kind, MultiExprArg(&expr, 1)); if (Result.isInvalid()) hadError = true; @@ -740,13 +738,13 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, unsigned &StructuredIndex) { if (Index < IList->getNumInits()) { Expr *expr = IList->getInit(Index); - if (isa(expr)) { - SemaRef.Diag(IList->getLocStart(), - diag::err_many_braces_around_scalar_init) - << IList->getSourceRange(); - hadError = true; - ++Index; - ++StructuredIndex; + if (InitListExpr *SubIList = dyn_cast(expr)) { + SemaRef.Diag(SubIList->getLocStart(), + diag::warn_many_braces_around_scalar_init) + << SubIList->getSourceRange(); + + CheckScalarType(Entity, SubIList, DeclType, Index, StructuredList, + StructuredIndex); return; } else if (isa(expr)) { SemaRef.Diag(expr->getSourceRange().getBegin(), @@ -758,7 +756,7 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, return; } - Sema::OwningExprResult Result = + ExprResult Result = SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), SemaRef.Owned(expr)); @@ -805,7 +803,7 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity, return; } - Sema::OwningExprResult Result = + ExprResult Result = SemaRef.PerformCopyInitialization(Entity, expr->getLocStart(), SemaRef.Owned(expr)); @@ -1367,7 +1365,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, if (SemaRef.CorrectTypo(R, /*Scope=*/0, /*SS=*/0, RT->getDecl(), false, Sema::CTC_NoKeywords) && (ReplacementField = R.getAsSingle()) && - ReplacementField->getDeclContext()->getLookupContext() + ReplacementField->getDeclContext()->getRedeclContext() ->Equals(RT->getDecl())) { SemaRef.Diag(D->getFieldLoc(), diag::err_field_designator_unknown_suggest) @@ -1813,10 +1811,10 @@ CheckArrayDesignatorExpr(Sema &S, Expr *Index, llvm::APSInt &Value) { return false; } -Sema::OwningExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, +ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, SourceLocation Loc, bool GNUSyntax, - OwningExprResult Init) { + ExprResult Init) { typedef DesignatedInitExpr::Designator ASTDesignator; bool Invalid = false; @@ -2021,18 +2019,21 @@ void InitializationSequence::Step::Destroy() { switch (Kind) { case SK_ResolveAddressOfOverloadedFunction: case SK_CastDerivedToBaseRValue: + case SK_CastDerivedToBaseXValue: case SK_CastDerivedToBaseLValue: case SK_BindReference: case SK_BindReferenceToTemporary: case SK_ExtraneousCopyToTemporary: case SK_UserConversion: case SK_QualificationConversionRValue: + case SK_QualificationConversionXValue: case SK_QualificationConversionLValue: case SK_ListInitialization: case SK_ConstructorInitialization: case SK_ZeroInitialization: case SK_CAssignment: case SK_StringInit: + case SK_ObjCObjectConversion: break; case SK_ConversionSequence: @@ -2091,9 +2092,14 @@ void InitializationSequence::AddAddressOverloadResolutionStep( } void InitializationSequence::AddDerivedToBaseCastStep(QualType BaseType, - bool IsLValue) { + ExprValueKind VK) { Step S; - S.Kind = IsLValue? SK_CastDerivedToBaseLValue : SK_CastDerivedToBaseRValue; + switch (VK) { + case VK_RValue: S.Kind = SK_CastDerivedToBaseRValue; break; + case VK_XValue: S.Kind = SK_CastDerivedToBaseXValue; break; + case VK_LValue: S.Kind = SK_CastDerivedToBaseLValue; break; + default: llvm_unreachable("No such category"); + } S.Type = BaseType; Steps.push_back(S); } @@ -2125,10 +2131,20 @@ void InitializationSequence::AddUserConversionStep(FunctionDecl *Function, } void InitializationSequence::AddQualificationConversionStep(QualType Ty, - bool IsLValue) { + ExprValueKind VK) { Step S; - S.Kind = IsLValue? SK_QualificationConversionLValue - : SK_QualificationConversionRValue; + S.Kind = SK_QualificationConversionRValue; // work around a gcc warning + switch (VK) { + case VK_RValue: + S.Kind = SK_QualificationConversionRValue; + break; + case VK_XValue: + S.Kind = SK_QualificationConversionXValue; + break; + case VK_LValue: + S.Kind = SK_QualificationConversionLValue; + break; + } S.Type = Ty; Steps.push_back(S); } @@ -2184,6 +2200,13 @@ void InitializationSequence::AddStringInitStep(QualType T) { Steps.push_back(S); } +void InitializationSequence::AddObjCObjectConversionStep(QualType T) { + Step S; + S.Kind = SK_ObjCObjectConversion; + S.Type = T; + Steps.push_back(S); +} + void InitializationSequence::SetOverloadFailure(FailureKind Failure, OverloadingResult Result) { SequenceKind = FailedSequence; @@ -2258,10 +2281,13 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, QualType T2 = cv2T2.getUnqualifiedType(); bool DerivedToBase; + bool ObjCConversion; assert(!S.CompareReferenceRelationship(Initializer->getLocStart(), - T1, T2, DerivedToBase) && + T1, T2, DerivedToBase, + ObjCConversion) && "Must have incompatible references when binding via conversion"); (void)DerivedToBase; + (void)ObjCConversion; // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. @@ -2278,6 +2304,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, // The type we're converting to is a class type. Enumerate its constructors // to see if there is a suitable conversion. CXXRecordDecl *T1RecordDecl = cast(T1RecordType->getDecl()); + DeclContext::lookup_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = S.LookupConstructors(T1RecordDecl); Con != ConEnd; ++Con) { @@ -2305,6 +2332,8 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, } } } + if (T1RecordType && T1RecordType->getDecl()->isInvalidDecl()) + return OR_No_Viable_Function; const RecordType *T2RecordType = 0; if ((T2RecordType = T2->getAs()) && @@ -2352,13 +2381,15 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, } } } + if (T2RecordType && T2RecordType->getDecl()->isInvalidDecl()) + return OR_No_Viable_Function; SourceLocation DeclLoc = Initializer->getLocStart(); // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; if (OverloadingResult Result - = S.BestViableFunction(CandidateSet, DeclLoc, Best)) + = CandidateSet.BestViableFunction(S, DeclLoc, Best)) return Result; FunctionDecl *Function = Best->Function; @@ -2375,11 +2406,18 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, // Determine whether we need to perform derived-to-base or // cv-qualification adjustments. + ExprValueKind VK = VK_RValue; + if (T2->isLValueReferenceType()) + VK = VK_LValue; + else if (const RValueReferenceType *RRef = T2->getAs()) + VK = RRef->getPointeeType()->isFunctionType() ? VK_LValue : VK_XValue; + bool NewDerivedToBase = false; + bool NewObjCConversion = false; Sema::ReferenceCompareResult NewRefRelationship = S.CompareReferenceRelationship(DeclLoc, T1, T2.getNonLValueExprType(S.Context), - NewDerivedToBase); + NewDerivedToBase, NewObjCConversion); if (NewRefRelationship == Sema::Ref_Incompatible) { // If the type we've converted to is not reference-related to the // type we're looking for, then there is another conversion step @@ -2394,10 +2432,14 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, Sequence.AddDerivedToBaseCastStep( S.Context.getQualifiedType(T1, T2.getNonReferenceType().getQualifiers()), - /*isLValue=*/true); - + VK); + else if (NewObjCConversion) + Sequence.AddObjCObjectConversionStep( + S.Context.getQualifiedType(T1, + T2.getNonReferenceType().getQualifiers())); + if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers()) - Sequence.AddQualificationConversionStep(cv1T1, T2->isReferenceType()); + Sequence.AddQualificationConversionStep(cv1T1, VK); Sequence.AddReferenceBindingStep(cv1T1, !T2->isReferenceType()); return OR_Success; @@ -2443,9 +2485,11 @@ static void TryReferenceInitialization(Sema &S, bool isLValueRef = DestType->isLValueReferenceType(); bool isRValueRef = !isLValueRef; bool DerivedToBase = false; + bool ObjCConversion = false; Expr::Classification InitCategory = Initializer->Classify(S.Context); Sema::ReferenceCompareResult RefRelationship - = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase); + = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase, + ObjCConversion); // C++0x [dcl.init.ref]p5: // A reference to type "cv1 T1" is initialized by an expression of type @@ -2472,9 +2516,13 @@ static void TryReferenceInitialization(Sema &S, if (DerivedToBase) Sequence.AddDerivedToBaseCastStep( S.Context.getQualifiedType(T1, T2Quals), - /*isLValue=*/true); + VK_LValue); + else if (ObjCConversion) + Sequence.AddObjCObjectConversionStep( + S.Context.getQualifiedType(T1, T2Quals)); + if (T1Quals != T2Quals) - Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/true); + Sequence.AddQualificationConversionStep(cv1T1, VK_LValue); bool BindingTemporary = T1Quals.hasConst() && !T1Quals.hasVolatile() && (Initializer->getBitField() || Initializer->refersToVectorElement()); Sequence.AddReferenceBindingStep(cv1T1, BindingTemporary); @@ -2531,6 +2579,7 @@ static void TryReferenceInitialization(Sema &S, // - [If T1 is not a function type], if T2 is a class type and if (!T1Function && T2->isRecordType()) { + bool isXValue = InitCategory.isXValue(); // - the initializer expression is an rvalue and "cv1 T1" is // reference-compatible with "cv2 T2", or if (InitCategory.isRValue() && @@ -2550,10 +2599,15 @@ static void TryReferenceInitialization(Sema &S, if (DerivedToBase) Sequence.AddDerivedToBaseCastStep( S.Context.getQualifiedType(T1, T2Quals), - /*isLValue=*/false); + isXValue ? VK_XValue : VK_RValue); + else if (ObjCConversion) + Sequence.AddObjCObjectConversionStep( + S.Context.getQualifiedType(T1, T2Quals)); + if (T1Quals != T2Quals) - Sequence.AddQualificationConversionStep(cv1T1, /*IsLValue=*/false); - Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); + Sequence.AddQualificationConversionStep(cv1T1, + isXValue ? VK_XValue : VK_RValue); + Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/!isXValue); return; } @@ -2717,7 +2771,7 @@ static void TryConstructorInitialization(Sema &S, // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; if (OverloadingResult Result - = S.BestViableFunction(CandidateSet, DeclLoc, Best)) { + = CandidateSet.BestViableFunction(S, DeclLoc, Best)) { Sequence.SetOverloadFailure( InitializationSequence::FK_ConstructorOverloadFailed, Result); @@ -2803,8 +2857,8 @@ static void TryDefaultInitialization(Sema &S, // constructor for T is called (and the initialization is ill-formed if // T has no accessible default constructor); if (DestType->isRecordType() && S.getLangOptions().CPlusPlus) { - return TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType, - Sequence); + TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType, Sequence); + return; } // - otherwise, no initialization is performed. @@ -2927,7 +2981,7 @@ static void TryUserDefinedConversion(Sema &S, // Perform overload resolution. If it fails, return the failed result. OverloadCandidateSet::iterator Best; if (OverloadingResult Result - = S.BestViableFunction(CandidateSet, DeclLoc, Best)) { + = CandidateSet.BestViableFunction(S, DeclLoc, Best)) { Sequence.SetOverloadFailure( InitializationSequence::FK_UserConversionOverloadFailed, Result); @@ -2969,24 +3023,6 @@ static void TryUserDefinedConversion(Sema &S, } } -bool Sema::TryImplicitConversion(InitializationSequence &Sequence, - const InitializedEntity &Entity, - Expr *Initializer, - bool SuppressUserConversions, - bool AllowExplicitConversions, - bool InOverloadResolution) { - ImplicitConversionSequence ICS - = TryImplicitConversion(Initializer, Entity.getType(), - SuppressUserConversions, - AllowExplicitConversions, - InOverloadResolution); - if (ICS.isBad()) return true; - - // Perform the actual conversion. - Sequence.AddConversionSequenceStep(ICS, Entity.getType()); - return false; -} - InitializationSequence::InitializationSequence(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -3239,10 +3275,10 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { /// \returns An expression that copies the initializer expression into /// a temporary object, or an error expression if a copy could not be /// created. -static Sema::OwningExprResult CopyObject(Sema &S, +static ExprResult CopyObject(Sema &S, QualType T, const InitializedEntity &Entity, - Sema::OwningExprResult CurInit, + ExprResult CurInit, bool IsExtraneousCopy) { // Determine which class type we're copying to. Expr *CurInitExpr = (Expr *)CurInit.get(); @@ -3318,7 +3354,7 @@ static Sema::OwningExprResult CopyObject(Sema &S, } OverloadCandidateSet::iterator Best; - switch (S.BestViableFunction(CandidateSet, Loc, Best)) { + switch (CandidateSet.BestViableFunction(S, Loc, Best)) { case OR_Success: break; @@ -3328,19 +3364,17 @@ static Sema::OwningExprResult CopyObject(Sema &S, : diag::err_temp_copy_no_viable) << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange(); - S.PrintOverloadCandidates(CandidateSet, Sema::OCD_AllCandidates, - &CurInitExpr, 1); + CandidateSet.NoteCandidates(S, OCD_AllCandidates, &CurInitExpr, 1); if (!IsExtraneousCopy || S.isSFINAEContext()) - return S.ExprError(); + return ExprError(); return move(CurInit); case OR_Ambiguous: S.Diag(Loc, diag::err_temp_copy_ambiguous) << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange(); - S.PrintOverloadCandidates(CandidateSet, Sema::OCD_ViableCandidates, - &CurInitExpr, 1); - return S.ExprError(); + CandidateSet.NoteCandidates(S, OCD_ViableCandidates, &CurInitExpr, 1); + return ExprError(); case OR_Deleted: S.Diag(Loc, diag::err_temp_copy_deleted) @@ -3348,11 +3382,11 @@ static Sema::OwningExprResult CopyObject(Sema &S, << CurInitExpr->getSourceRange(); S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) << Best->Function->isDeleted(); - return S.ExprError(); + return ExprError(); } CXXConstructorDecl *Constructor = cast(Best->Function); - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); + ASTOwningVector ConstructorArgs(S); CurInit.release(); // Ownership transferred into MultiExprArg, below. S.CheckConstructorAccess(Loc, Constructor, Entity, @@ -3387,16 +3421,15 @@ static Sema::OwningExprResult CopyObject(Sema &S, // Determine the arguments required to actually perform the // constructor call (we might have derived-to-base conversions, or // the copy constructor may have default arguments). - if (S.CompleteConstructorCall(Constructor, - Sema::MultiExprArg(S, - (void **)&CurInitExpr, - 1), + if (S.CompleteConstructorCall(Constructor, MultiExprArg(&CurInitExpr, 1), Loc, ConstructorArgs)) - return S.ExprError(); + return ExprError(); // Actually perform the constructor call. CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable, - move_arg(ConstructorArgs)); + move_arg(ConstructorArgs), + /*ZeroInit*/ false, + CXXConstructExpr::CK_Complete); // If we're supposed to bind temporaries, do so. if (!CurInit.isInvalid() && shouldBindAsTemporary(Entity)) @@ -3418,16 +3451,16 @@ void InitializationSequence::PrintInitLocationNote(Sema &S, } } -Action::OwningExprResult +ExprResult InitializationSequence::Perform(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, - Action::MultiExprArg Args, + MultiExprArg Args, QualType *ResultType) { if (SequenceKind == FailedSequence) { unsigned NumArgs = Args.size(); Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs); - return S.ExprError(); + return ExprError(); } if (SequenceKind == DependentSequence) { @@ -3471,7 +3504,7 @@ InitializationSequence::Perform(Sema &S, } if (Kind.getKind() == InitializationKind::IK_Copy || Kind.isExplicitCast()) - return Sema::OwningExprResult(S, Args.release()[0]); + return ExprResult(Args.release()[0]); if (Args.size() == 0) return S.Owned((Expr *)0); @@ -3495,7 +3528,7 @@ InitializationSequence::Perform(Sema &S, *ResultType = Entity.getDecl() ? Entity.getDecl()->getType() : Entity.getType(); - Sema::OwningExprResult CurInit = S.Owned((Expr *)0); + ExprResult CurInit = S.Owned((Expr *)0); assert(!Steps.empty() && "Cannot have an empty initialization sequence"); @@ -3505,21 +3538,24 @@ InitializationSequence::Perform(Sema &S, switch (Steps.front().Kind) { case SK_ResolveAddressOfOverloadedFunction: case SK_CastDerivedToBaseRValue: + case SK_CastDerivedToBaseXValue: case SK_CastDerivedToBaseLValue: case SK_BindReference: case SK_BindReferenceToTemporary: case SK_ExtraneousCopyToTemporary: case SK_UserConversion: case SK_QualificationConversionLValue: + case SK_QualificationConversionXValue: case SK_QualificationConversionRValue: case SK_ConversionSequence: case SK_ListInitialization: case SK_CAssignment: case SK_StringInit: + case SK_ObjCObjectConversion: assert(Args.size() == 1); - CurInit = Sema::OwningExprResult(S, ((Expr **)(Args.get()))[0]->Retain()); + CurInit = ExprResult(((Expr **)(Args.get()))[0]->Retain()); if (CurInit.isInvalid()) - return S.ExprError(); + return ExprError(); break; case SK_ConstructorInitialization: @@ -3533,7 +3569,7 @@ InitializationSequence::Perform(Sema &S, for (step_iterator Step = step_begin(), StepEnd = step_end(); Step != StepEnd; ++Step) { if (CurInit.isInvalid()) - return S.ExprError(); + return ExprError(); Expr *CurInitExpr = (Expr *)CurInit.get(); QualType SourceType = CurInitExpr? CurInitExpr->getType() : QualType(); @@ -3550,11 +3586,12 @@ InitializationSequence::Perform(Sema &S, break; case SK_CastDerivedToBaseRValue: + case SK_CastDerivedToBaseXValue: case SK_CastDerivedToBaseLValue: { // We have a derived-to-base cast that produces either an rvalue or an // lvalue. Perform that cast. - CXXBaseSpecifierArray BasePath; + CXXCastPath BasePath; // Casts to inaccessible base classes are allowed with C-style casts. bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); @@ -3562,7 +3599,7 @@ InitializationSequence::Perform(Sema &S, CurInitExpr->getLocStart(), CurInitExpr->getSourceRange(), &BasePath, IgnoreBaseAccess)) - return S.ExprError(); + return ExprError(); if (S.BasePathInvolvesVirtualBase(BasePath)) { QualType T = SourceType; @@ -3573,11 +3610,17 @@ InitializationSequence::Perform(Sema &S, cast(RecordTy->getDecl())); } - CurInit = S.Owned(new (S.Context) ImplicitCastExpr(Step->Type, - CastExpr::CK_DerivedToBase, - (Expr*)CurInit.release(), - BasePath, - Step->Kind == SK_CastDerivedToBaseLValue)); + ExprValueKind VK = + Step->Kind == SK_CastDerivedToBaseLValue ? + VK_LValue : + (Step->Kind == SK_CastDerivedToBaseXValue ? + VK_XValue : + VK_RValue); + CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, + Step->Type, + CK_DerivedToBase, + CurInit.get(), + &BasePath, VK)); break; } @@ -3589,7 +3632,7 @@ InitializationSequence::Perform(Sema &S, << BitField->getDeclName() << CurInitExpr->getSourceRange(); S.Diag(BitField->getLocation(), diag::note_bitfield_decl); - return S.ExprError(); + return ExprError(); } if (CurInitExpr->refersToVectorElement()) { @@ -3598,14 +3641,14 @@ InitializationSequence::Perform(Sema &S, << Entity.getType().isVolatileQualified() << CurInitExpr->getSourceRange(); PrintInitLocationNote(S, Entity); - return S.ExprError(); + return ExprError(); } // Reference binding does not have any corresponding ASTs. // Check exception specifications if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType)) - return S.ExprError(); + return ExprError(); break; @@ -3614,7 +3657,7 @@ InitializationSequence::Perform(Sema &S, // Check exception specifications if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType)) - return S.ExprError(); + return ExprError(); break; @@ -3626,7 +3669,7 @@ InitializationSequence::Perform(Sema &S, case SK_UserConversion: { // We have a user-defined conversion that invokes either a constructor // or a conversion function. - CastExpr::CastKind CastKind = CastExpr::CK_Unknown; + CastKind CastKind = CK_Unknown; bool IsCopy = false; FunctionDecl *Fn = Step->Function.Function; DeclAccessPair FoundFn = Step->Function.FoundDecl; @@ -3634,30 +3677,30 @@ InitializationSequence::Perform(Sema &S, bool IsLvalue = false; if (CXXConstructorDecl *Constructor = dyn_cast(Fn)) { // Build a call to the selected constructor. - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); + ASTOwningVector ConstructorArgs(S); SourceLocation Loc = CurInitExpr->getLocStart(); CurInit.release(); // Ownership transferred into MultiExprArg, below. // Determine the arguments required to actually perform the constructor // call. if (S.CompleteConstructorCall(Constructor, - Sema::MultiExprArg(S, - (void **)&CurInitExpr, - 1), + MultiExprArg(&CurInitExpr, 1), Loc, ConstructorArgs)) - return S.ExprError(); + return ExprError(); // Build the an expression that constructs a temporary. CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, - move_arg(ConstructorArgs)); + move_arg(ConstructorArgs), + /*ZeroInit*/ false, + CXXConstructExpr::CK_Complete); if (CurInit.isInvalid()) - return S.ExprError(); + return ExprError(); S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity, FoundFn.getAccess()); S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); - CastKind = CastExpr::CK_ConstructorConversion; + CastKind = CK_ConstructorConversion; QualType Class = S.Context.getTypeDeclType(Constructor->getParent()); if (S.Context.hasSameUnqualifiedType(SourceType, Class) || S.IsDerivedFrom(SourceType, Class)) @@ -3677,7 +3720,7 @@ InitializationSequence::Perform(Sema &S, // we don't want to turn off access control here for c-style casts. if (S.PerformObjectArgumentInitialization(CurInitExpr, /*Qualifier=*/0, FoundFn, Conversion)) - return S.ExprError(); + return ExprError(); // Do a little dance to make sure that CurInit has the proper // pointer. @@ -3687,9 +3730,9 @@ InitializationSequence::Perform(Sema &S, CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, FoundFn, Conversion)); if (CurInit.isInvalid() || !CurInit.get()) - return S.ExprError(); + return ExprError(); - CastKind = CastExpr::CK_UserDefinedConversion; + CastKind = CK_UserDefinedConversion; CreatedObject = Conversion->getResultType()->isRecordType(); } @@ -3711,35 +3754,41 @@ InitializationSequence::Perform(Sema &S, } CurInitExpr = CurInit.takeAs(); - CurInit = S.Owned(new (S.Context) ImplicitCastExpr(CurInitExpr->getType(), - CastKind, - CurInitExpr, - CXXBaseSpecifierArray(), - IsLvalue)); + // FIXME: xvalues + CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, + CurInitExpr->getType(), + CastKind, CurInitExpr, 0, + IsLvalue ? VK_LValue : VK_RValue)); if (RequiresCopy) CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity, move(CurInit), /*IsExtraneousCopy=*/false); - + break; } - + case SK_QualificationConversionLValue: - case SK_QualificationConversionRValue: + case SK_QualificationConversionXValue: + case SK_QualificationConversionRValue: { // Perform a qualification conversion; these can never go wrong. - S.ImpCastExprToType(CurInitExpr, Step->Type, - CastExpr::CK_NoOp, - Step->Kind == SK_QualificationConversionLValue); + ExprValueKind VK = + Step->Kind == SK_QualificationConversionLValue ? + VK_LValue : + (Step->Kind == SK_QualificationConversionXValue ? + VK_XValue : + VK_RValue); + S.ImpCastExprToType(CurInitExpr, Step->Type, CK_NoOp, VK); CurInit.release(); CurInit = S.Owned(CurInitExpr); break; - + } + case SK_ConversionSequence: { bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); if (S.PerformImplicitConversion(CurInitExpr, Step->Type, *Step->ICS, Sema::AA_Converting, IgnoreBaseAccess)) - return S.ExprError(); + return ExprError(); CurInit.release(); CurInit = S.Owned(CurInitExpr); @@ -3750,7 +3799,7 @@ InitializationSequence::Perform(Sema &S, InitListExpr *InitList = cast(CurInitExpr); QualType Ty = Step->Type; if (S.CheckInitList(Entity, InitList, ResultType? *ResultType : Ty)) - return S.ExprError(); + return ExprError(); CurInit.release(); CurInit = S.Owned(InitList); @@ -3763,16 +3812,29 @@ InitializationSequence::Perform(Sema &S, = cast(Step->Function.Function); // Build a call to the selected constructor. - ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(S); - SourceLocation Loc = Kind.getLocation(); - + ASTOwningVector ConstructorArgs(S); + SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid()) + ? Kind.getEqualLoc() + : Kind.getLocation(); + + if (Kind.getKind() == InitializationKind::IK_Default) { + // Force even a trivial, implicit default constructor to be + // semantically checked. We do this explicitly because we don't build + // the definition for completely trivial constructors. + CXXRecordDecl *ClassDecl = Constructor->getParent(); + assert(ClassDecl && "No parent class for constructor."); + if (Constructor->isImplicit() && Constructor->isDefaultConstructor() && + ClassDecl->hasTrivialConstructor() && !Constructor->isUsed(false)) + S.DefineImplicitDefaultConstructor(Loc, Constructor); + } + // Determine the arguments required to actually perform the constructor // call. if (S.CompleteConstructorCall(Constructor, move(Args), Loc, ConstructorArgs)) - return S.ExprError(); + return ExprError(); - // Build the expression that constructs a temporary. + if (Entity.getKind() == InitializedEntity::EK_Temporary && NumArgs != 1 && // FIXME: Hack to work around cast weirdness (Kind.getKind() == InitializationKind::IK_Direct || @@ -3780,11 +3842,11 @@ InitializationSequence::Perform(Sema &S, // An explicitly-constructed temporary, e.g., X(1, 2). unsigned NumExprs = ConstructorArgs.size(); Expr **Exprs = (Expr **)ConstructorArgs.take(); - S.MarkDeclarationReferenced(Kind.getLocation(), Constructor); + S.MarkDeclarationReferenced(Loc, Constructor); CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context, Constructor, Entity.getType(), - Kind.getLocation(), + Loc, Exprs, NumExprs, Kind.getParenRange().getEnd(), @@ -3815,7 +3877,7 @@ InitializationSequence::Perform(Sema &S, ConstructKind); } if (CurInit.isInvalid()) - return S.ExprError(); + return ExprError(); // Only check access if all of that succeeded. S.CheckConstructorAccess(Loc, Constructor, Entity, @@ -3867,7 +3929,7 @@ InitializationSequence::Perform(Sema &S, getAssignmentAction(Entity), &Complained)) { PrintInitLocationNote(S, Entity); - return S.ExprError(); + return ExprError(); } else if (Complained) PrintInitLocationNote(S, Entity); @@ -3881,6 +3943,14 @@ InitializationSequence::Perform(Sema &S, CheckStringInit(CurInitExpr, ResultType ? *ResultType : Ty, S); break; } + + case SK_ObjCObjectConversion: + S.ImpCastExprToType(CurInitExpr, Step->Type, + CK_ObjCObjectLValueCast, + S.CastCategory(CurInitExpr)); + CurInit.release(); + CurInit = S.Owned(CurInitExpr); + break; } } @@ -3937,16 +4007,14 @@ bool InitializationSequence::Diagnose(Sema &S, << DestType << Args[0]->getType() << Args[0]->getSourceRange(); - S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_ViableCandidates, - Args, NumArgs); + FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, Args, NumArgs); break; case OR_No_Viable_Function: S.Diag(Kind.getLocation(), diag::err_typecheck_nonviable_condition) << Args[0]->getType() << DestType.getNonReferenceType() << Args[0]->getSourceRange(); - S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates, - Args, NumArgs); + FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args, NumArgs); break; case OR_Deleted: { @@ -3954,9 +4022,8 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->getType() << DestType.getNonReferenceType() << Args[0]->getSourceRange(); OverloadCandidateSet::iterator Best; - OverloadingResult Ovl = S.BestViableFunction(FailedCandidateSet, - Kind.getLocation(), - Best); + OverloadingResult Ovl + = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best); if (Ovl == OR_Deleted) { S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) << Best->Function->isDeleted(); @@ -4049,8 +4116,8 @@ bool InitializationSequence::Diagnose(Sema &S, case OR_Ambiguous: S.Diag(Kind.getLocation(), diag::err_ovl_ambiguous_init) << DestType << ArgsRange; - S.PrintOverloadCandidates(FailedCandidateSet, - Sema::OCD_ViableCandidates, Args, NumArgs); + FailedCandidateSet.NoteCandidates(S, OCD_ViableCandidates, + Args, NumArgs); break; case OR_No_Viable_Function: @@ -4095,17 +4162,15 @@ bool InitializationSequence::Diagnose(Sema &S, S.Diag(Kind.getLocation(), diag::err_ovl_no_viable_function_in_init) << DestType << ArgsRange; - S.PrintOverloadCandidates(FailedCandidateSet, Sema::OCD_AllCandidates, - Args, NumArgs); + FailedCandidateSet.NoteCandidates(S, OCD_AllCandidates, Args, NumArgs); break; case OR_Deleted: { S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init) << true << DestType << ArgsRange; OverloadCandidateSet::iterator Best; - OverloadingResult Ovl = S.BestViableFunction(FailedCandidateSet, - Kind.getLocation(), - Best); + OverloadingResult Ovl + = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best); if (Ovl == OR_Deleted) { S.Diag(Best->Function->getLocation(), diag::note_unavailable_here) << Best->Function->isDeleted(); @@ -4288,6 +4353,10 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { OS << "derived-to-base case (rvalue" << S->Type.getAsString() << ")"; break; + case SK_CastDerivedToBaseXValue: + OS << "derived-to-base case (xvalue" << S->Type.getAsString() << ")"; + break; + case SK_CastDerivedToBaseLValue: OS << "derived-to-base case (lvalue" << S->Type.getAsString() << ")"; break; @@ -4307,10 +4376,13 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { case SK_UserConversion: OS << "user-defined conversion via " << S->Function.Function; break; - + case SK_QualificationConversionRValue: OS << "qualification conversion (rvalue)"; + case SK_QualificationConversionXValue: + OS << "qualification conversion (xvalue)"; + case SK_QualificationConversionLValue: OS << "qualification conversion (lvalue)"; break; @@ -4340,6 +4412,10 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { case SK_StringInit: OS << "string initialization"; break; + + case SK_ObjCObjectConversion: + OS << "Objective-C object conversion"; + break; } } } @@ -4351,10 +4427,10 @@ void InitializationSequence::dump() const { //===----------------------------------------------------------------------===// // Initialization helper functions //===----------------------------------------------------------------------===// -Sema::OwningExprResult +ExprResult Sema::PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, - OwningExprResult Init) { + ExprResult Init) { if (Init.isInvalid()) return ExprError(); @@ -4368,6 +4444,5 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity, EqualLoc); InitializationSequence Seq(*this, Entity, Kind, &InitE, 1); Init.release(); - return Seq.Perform(*this, Entity, Kind, - MultiExprArg(*this, (void**)&InitE, 1)); + return Seq.Perform(*this, Entity, Kind, MultiExprArg(&InitE, 1)); } diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h deleted file mode 100644 index 44c36a7..0000000 --- a/lib/Sema/SemaInit.h +++ /dev/null @@ -1,765 +0,0 @@ -//===--- SemaInit.h - Semantic Analysis for Initializers --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides supporting data types for initialization of objects. -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_SEMA_INIT_H -#define LLVM_CLANG_SEMA_INIT_H - -#include "SemaOverload.h" -#include "clang/AST/Type.h" -#include "clang/AST/UnresolvedSet.h" -#include "clang/Parse/Action.h" -#include "clang/Basic/SourceLocation.h" -#include "llvm/ADT/PointerIntPair.h" -#include "llvm/ADT/SmallVector.h" -#include - -namespace llvm { - class raw_ostream; -} - -namespace clang { - -class CXXBaseSpecifier; -class DeclaratorDecl; -class DeclaratorInfo; -class FieldDecl; -class FunctionDecl; -class ParmVarDecl; -class Sema; -class TypeLoc; -class VarDecl; - -/// \brief Describes an entity that is being initialized. -class InitializedEntity { -public: - /// \brief Specifies the kind of entity being initialized. - enum EntityKind { - /// \brief The entity being initialized is a variable. - EK_Variable, - /// \brief The entity being initialized is a function parameter. - EK_Parameter, - /// \brief The entity being initialized is the result of a function call. - EK_Result, - /// \brief The entity being initialized is an exception object that - /// is being thrown. - EK_Exception, - /// \brief The entity being initialized is a non-static data member - /// subobject. - EK_Member, - /// \brief The entity being initialized is an element of an array. - EK_ArrayElement, - /// \brief The entity being initialized is an object (or array of - /// objects) allocated via new. - EK_New, - /// \brief The entity being initialized is a temporary object. - EK_Temporary, - /// \brief The entity being initialized is a base member subobject. - EK_Base, - /// \brief The entity being initialized is an element of a vector. - /// or vector. - EK_VectorElement, - /// \brief The entity being initialized is a field of block descriptor for - /// the copied-in c++ object. - EK_BlockElement - }; - -private: - /// \brief The kind of entity being initialized. - EntityKind Kind; - - /// \brief If non-NULL, the parent entity in which this - /// initialization occurs. - const InitializedEntity *Parent; - - /// \brief The type of the object or reference being initialized. - QualType Type; - - union { - /// \brief When Kind == EK_Variable, EK_Parameter, or EK_Member, - /// the VarDecl, ParmVarDecl, or FieldDecl, respectively. - DeclaratorDecl *VariableOrMember; - - struct { - /// \brief When Kind == EK_Result, EK_Exception, or EK_New, the - /// location of the 'return', 'throw', or 'new' keyword, - /// respectively. When Kind == EK_Temporary, the location where - /// the temporary is being created. - unsigned Location; - - /// \brief Whether the - bool NRVO; - } LocAndNRVO; - - /// \brief When Kind == EK_Base, the base specifier that provides the - /// base class. The lower bit specifies whether the base is an inherited - /// virtual base. - uintptr_t Base; - - /// \brief When Kind == EK_ArrayElement or EK_VectorElement, the - /// index of the array or vector element being initialized. - unsigned Index; - }; - - InitializedEntity() { } - - /// \brief Create the initialization entity for a variable. - InitializedEntity(VarDecl *Var) - : Kind(EK_Variable), Parent(0), Type(Var->getType()), - VariableOrMember(reinterpret_cast(Var)) { } - - /// \brief Create the initialization entity for a parameter. - InitializedEntity(ParmVarDecl *Parm) - : Kind(EK_Parameter), Parent(0), Type(Parm->getType().getUnqualifiedType()), - VariableOrMember(reinterpret_cast(Parm)) { } - - /// \brief Create the initialization entity for the result of a - /// function, throwing an object, performing an explicit cast, or - /// initializing a parameter for which there is no declaration. - InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type, - bool NRVO = false) - : Kind(Kind), Parent(0), Type(Type) - { - LocAndNRVO.Location = Loc.getRawEncoding(); - LocAndNRVO.NRVO = NRVO; - } - - /// \brief Create the initialization entity for a member subobject. - InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent) - : Kind(EK_Member), Parent(Parent), Type(Member->getType()), - VariableOrMember(reinterpret_cast(Member)) { } - - /// \brief Create the initialization entity for an array element. - InitializedEntity(ASTContext &Context, unsigned Index, - const InitializedEntity &Parent); - -public: - /// \brief Create the initialization entity for a variable. - static InitializedEntity InitializeVariable(VarDecl *Var) { - return InitializedEntity(Var); - } - - /// \brief Create the initialization entity for a parameter. - static InitializedEntity InitializeParameter(ParmVarDecl *Parm) { - return InitializedEntity(Parm); - } - - /// \brief Create the initialization entity for a parameter that is - /// only known by its type. - static InitializedEntity InitializeParameter(QualType Type) { - InitializedEntity Entity; - Entity.Kind = EK_Parameter; - Entity.Type = Type; - Entity.Parent = 0; - Entity.VariableOrMember = 0; - return Entity; - } - - /// \brief Create the initialization entity for the result of a function. - static InitializedEntity InitializeResult(SourceLocation ReturnLoc, - QualType Type, bool NRVO) { - return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO); - } - - static InitializedEntity InitializeBlock(SourceLocation BlockVarLoc, - QualType Type, bool NRVO) { - return InitializedEntity(EK_BlockElement, BlockVarLoc, Type, NRVO); - } - - /// \brief Create the initialization entity for an exception object. - static InitializedEntity InitializeException(SourceLocation ThrowLoc, - QualType Type, bool NRVO) { - return InitializedEntity(EK_Exception, ThrowLoc, Type, NRVO); - } - - /// \brief Create the initialization entity for an object allocated via new. - static InitializedEntity InitializeNew(SourceLocation NewLoc, QualType Type) { - return InitializedEntity(EK_New, NewLoc, Type); - } - - /// \brief Create the initialization entity for a temporary. - static InitializedEntity InitializeTemporary(QualType Type) { - return InitializedEntity(EK_Temporary, SourceLocation(), Type); - } - - /// \brief Create the initialization entity for a base class subobject. - static InitializedEntity InitializeBase(ASTContext &Context, - CXXBaseSpecifier *Base, - bool IsInheritedVirtualBase); - - /// \brief Create the initialization entity for a member subobject. - static InitializedEntity InitializeMember(FieldDecl *Member, - const InitializedEntity *Parent = 0) { - return InitializedEntity(Member, Parent); - } - - /// \brief Create the initialization entity for an array element. - static InitializedEntity InitializeElement(ASTContext &Context, - unsigned Index, - const InitializedEntity &Parent) { - return InitializedEntity(Context, Index, Parent); - } - - /// \brief Determine the kind of initialization. - EntityKind getKind() const { return Kind; } - - /// \brief Retrieve the parent of the entity being initialized, when - /// the initialization itself is occuring within the context of a - /// larger initialization. - const InitializedEntity *getParent() const { return Parent; } - - /// \brief Retrieve type being initialized. - QualType getType() const { return Type; } - - /// \brief Retrieve the name of the entity being initialized. - DeclarationName getName() const; - - /// \brief Retrieve the variable, parameter, or field being - /// initialized. - DeclaratorDecl *getDecl() const; - - /// \brief Determine whether this initialization allows the named return - /// value optimization, which also applies to thrown objects. - bool allowsNRVO() const; - - /// \brief Retrieve the base specifier. - CXXBaseSpecifier *getBaseSpecifier() const { - assert(getKind() == EK_Base && "Not a base specifier"); - return reinterpret_cast(Base & ~0x1); - } - - /// \brief Return whether the base is an inherited virtual base. - bool isInheritedVirtualBase() const { - assert(getKind() == EK_Base && "Not a base specifier"); - return Base & 0x1; - } - - /// \brief Determine the location of the 'return' keyword when initializing - /// the result of a function call. - SourceLocation getReturnLoc() const { - assert(getKind() == EK_Result && "No 'return' location!"); - return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); - } - - /// \brief Determine the location of the 'throw' keyword when initializing - /// an exception object. - SourceLocation getThrowLoc() const { - assert(getKind() == EK_Exception && "No 'throw' location!"); - return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); - } - - /// \brief If this is already the initializer for an array or vector - /// element, sets the element index. - void setElementIndex(unsigned Index) { - assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement); - this->Index = Index; - } -}; - -/// \brief Describes the kind of initialization being performed, along with -/// location information for tokens related to the initialization (equal sign, -/// parentheses). -class InitializationKind { -public: - /// \brief The kind of initialization being performed. - enum InitKind { - IK_Direct, ///< Direct initialization - IK_Copy, ///< Copy initialization - IK_Default, ///< Default initialization - IK_Value ///< Value initialization - }; - -private: - /// \brief The kind of initialization that we're storing. - enum StoredInitKind { - SIK_Direct = IK_Direct, ///< Direct initialization - SIK_Copy = IK_Copy, ///< Copy initialization - SIK_Default = IK_Default, ///< Default initialization - SIK_Value = IK_Value, ///< Value initialization - SIK_ImplicitValue, ///< Implicit value initialization - SIK_DirectCast, ///< Direct initialization due to a cast - /// \brief Direct initialization due to a C-style or functional cast. - SIK_DirectCStyleOrFunctionalCast - }; - - /// \brief The kind of initialization being performed. - StoredInitKind Kind; - - /// \brief The source locations involved in the initialization. - SourceLocation Locations[3]; - - InitializationKind(StoredInitKind Kind, SourceLocation Loc1, - SourceLocation Loc2, SourceLocation Loc3) - : Kind(Kind) - { - Locations[0] = Loc1; - Locations[1] = Loc2; - Locations[2] = Loc3; - } - -public: - /// \brief Create a direct initialization. - static InitializationKind CreateDirect(SourceLocation InitLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc) { - return InitializationKind(SIK_Direct, InitLoc, LParenLoc, RParenLoc); - } - - /// \brief Create a direct initialization due to a cast. - static InitializationKind CreateCast(SourceRange TypeRange, - bool IsCStyleCast) { - return InitializationKind(IsCStyleCast? SIK_DirectCStyleOrFunctionalCast - : SIK_DirectCast, - TypeRange.getBegin(), TypeRange.getBegin(), - TypeRange.getEnd()); - } - - /// \brief Create a copy initialization. - static InitializationKind CreateCopy(SourceLocation InitLoc, - SourceLocation EqualLoc) { - return InitializationKind(SIK_Copy, InitLoc, EqualLoc, EqualLoc); - } - - /// \brief Create a default initialization. - static InitializationKind CreateDefault(SourceLocation InitLoc) { - return InitializationKind(SIK_Default, InitLoc, InitLoc, InitLoc); - } - - /// \brief Create a value initialization. - static InitializationKind CreateValue(SourceLocation InitLoc, - SourceLocation LParenLoc, - SourceLocation RParenLoc, - bool isImplicit = false) { - return InitializationKind(isImplicit? SIK_ImplicitValue : SIK_Value, - InitLoc, LParenLoc, RParenLoc); - } - - /// \brief Determine the initialization kind. - InitKind getKind() const { - if (Kind > SIK_ImplicitValue) - return IK_Direct; - if (Kind == SIK_ImplicitValue) - return IK_Value; - - return (InitKind)Kind; - } - - /// \brief Determine whether this initialization is an explicit cast. - bool isExplicitCast() const { - return Kind == SIK_DirectCast || Kind == SIK_DirectCStyleOrFunctionalCast; - } - - /// \brief Determine whether this initialization is a C-style cast. - bool isCStyleOrFunctionalCast() const { - return Kind == SIK_DirectCStyleOrFunctionalCast; - } - - /// \brief Determine whether this initialization is an implicit - /// value-initialization, e.g., as occurs during aggregate - /// initialization. - bool isImplicitValueInit() const { return Kind == SIK_ImplicitValue; } - - /// \brief Retrieve the location at which initialization is occurring. - SourceLocation getLocation() const { return Locations[0]; } - - /// \brief Retrieve the source range that covers the initialization. - SourceRange getRange() const { - return SourceRange(Locations[0], Locations[2]); - } - - /// \brief Retrieve the location of the equal sign for copy initialization - /// (if present). - SourceLocation getEqualLoc() const { - assert(Kind == SIK_Copy && "Only copy initialization has an '='"); - return Locations[1]; - } - - /// \brief Retrieve the source range containing the locations of the open - /// and closing parentheses for value and direct initializations. - SourceRange getParenRange() const { - assert((getKind() == IK_Direct || Kind == SIK_Value) && - "Only direct- and value-initialization have parentheses"); - return SourceRange(Locations[1], Locations[2]); - } -}; - -/// \brief Describes the sequence of initializations required to initialize -/// a given object or reference with a set of arguments. -class InitializationSequence { -public: - /// \brief Describes the kind of initialization sequence computed. - /// - /// FIXME: Much of this information is in the initialization steps... why is - /// it duplicated here? - enum SequenceKind { - /// \brief A failed initialization sequence. The failure kind tells what - /// happened. - FailedSequence = 0, - - /// \brief A dependent initialization, which could not be - /// type-checked due to the presence of dependent types or - /// dependently-type expressions. - DependentSequence, - - /// \brief A user-defined conversion sequence. - UserDefinedConversion, - - /// \brief A constructor call. - ConstructorInitialization, - - /// \brief A reference binding. - ReferenceBinding, - - /// \brief List initialization - ListInitialization, - - /// \brief Zero-initialization. - ZeroInitialization, - - /// \brief No initialization required. - NoInitialization, - - /// \brief Standard conversion sequence. - StandardConversion, - - /// \brief C conversion sequence. - CAssignment, - - /// \brief String initialization - StringInit - }; - - /// \brief Describes the kind of a particular step in an initialization - /// sequence. - enum StepKind { - /// \brief Resolve the address of an overloaded function to a specific - /// function declaration. - SK_ResolveAddressOfOverloadedFunction, - /// \brief Perform a derived-to-base cast, producing an rvalue. - SK_CastDerivedToBaseRValue, - /// \brief Perform a derived-to-base cast, producing an lvalue. - SK_CastDerivedToBaseLValue, - /// \brief Reference binding to an lvalue. - SK_BindReference, - /// \brief Reference binding to a temporary. - SK_BindReferenceToTemporary, - /// \brief An optional copy of a temporary object to another - /// temporary object, which is permitted (but not required) by - /// C++98/03 but not C++0x. - SK_ExtraneousCopyToTemporary, - /// \brief Perform a user-defined conversion, either via a conversion - /// function or via a constructor. - SK_UserConversion, - /// \brief Perform a qualification conversion, producing an rvalue. - SK_QualificationConversionRValue, - /// \brief Perform a qualification conversion, producing an lvalue. - SK_QualificationConversionLValue, - /// \brief Perform an implicit conversion sequence. - SK_ConversionSequence, - /// \brief Perform list-initialization - SK_ListInitialization, - /// \brief Perform initialization via a constructor. - SK_ConstructorInitialization, - /// \brief Zero-initialize the object - SK_ZeroInitialization, - /// \brief C assignment - SK_CAssignment, - /// \brief Initialization by string - SK_StringInit - }; - - /// \brief A single step in the initialization sequence. - class Step { - public: - /// \brief The kind of conversion or initialization step we are taking. - StepKind Kind; - - // \brief The type that results from this initialization. - QualType Type; - - union { - /// \brief When Kind == SK_ResolvedOverloadedFunction or Kind == - /// SK_UserConversion, the function that the expression should be - /// resolved to or the conversion function to call, respectively. - /// - /// Always a FunctionDecl. - /// For conversion decls, the naming class is the source type. - /// For construct decls, the naming class is the target type. - struct { - FunctionDecl *Function; - DeclAccessPair FoundDecl; - } Function; - - /// \brief When Kind = SK_ConversionSequence, the implicit conversion - /// sequence - ImplicitConversionSequence *ICS; - }; - - void Destroy(); - }; - -private: - /// \brief The kind of initialization sequence computed. - enum SequenceKind SequenceKind; - - /// \brief Steps taken by this initialization. - llvm::SmallVector Steps; - -public: - /// \brief Describes why initialization failed. - enum FailureKind { - /// \brief Too many initializers provided for a reference. - FK_TooManyInitsForReference, - /// \brief Array must be initialized with an initializer list. - FK_ArrayNeedsInitList, - /// \brief Array must be initialized with an initializer list or a - /// string literal. - FK_ArrayNeedsInitListOrStringLiteral, - /// \brief Cannot resolve the address of an overloaded function. - FK_AddressOfOverloadFailed, - /// \brief Overloading due to reference initialization failed. - FK_ReferenceInitOverloadFailed, - /// \brief Non-const lvalue reference binding to a temporary. - FK_NonConstLValueReferenceBindingToTemporary, - /// \brief Non-const lvalue reference binding to an lvalue of unrelated - /// type. - FK_NonConstLValueReferenceBindingToUnrelated, - /// \brief Rvalue reference binding to an lvalue. - FK_RValueReferenceBindingToLValue, - /// \brief Reference binding drops qualifiers. - FK_ReferenceInitDropsQualifiers, - /// \brief Reference binding failed. - FK_ReferenceInitFailed, - /// \brief Implicit conversion failed. - FK_ConversionFailed, - /// \brief Too many initializers for scalar - FK_TooManyInitsForScalar, - /// \brief Reference initialization from an initializer list - FK_ReferenceBindingToInitList, - /// \brief Initialization of some unused destination type with an - /// initializer list. - FK_InitListBadDestinationType, - /// \brief Overloading for a user-defined conversion failed. - FK_UserConversionOverloadFailed, - /// \brief Overloaded for initialization by constructor failed. - FK_ConstructorOverloadFailed, - /// \brief Default-initialization of a 'const' object. - FK_DefaultInitOfConst, - /// \brief Initialization of an incomplete type. - FK_Incomplete - }; - -private: - /// \brief The reason why initialization failued. - FailureKind Failure; - - /// \brief The failed result of overload resolution. - OverloadingResult FailedOverloadResult; - - /// \brief The candidate set created when initialization failed. - OverloadCandidateSet FailedCandidateSet; - - /// \brief Prints a follow-up note that highlights the location of - /// the initialized entity, if it's remote. - void PrintInitLocationNote(Sema &S, const InitializedEntity &Entity); - -public: - /// \brief Try to perform initialization of the given entity, creating a - /// record of the steps required to perform the initialization. - /// - /// The generated initialization sequence will either contain enough - /// information to diagnose - /// - /// \param S the semantic analysis object. - /// - /// \param Entity the entity being initialized. - /// - /// \param Kind the kind of initialization being performed. - /// - /// \param Args the argument(s) provided for initialization. - /// - /// \param NumArgs the number of arguments provided for initialization. - InitializationSequence(Sema &S, - const InitializedEntity &Entity, - const InitializationKind &Kind, - Expr **Args, - unsigned NumArgs); - - ~InitializationSequence(); - - /// \brief Perform the actual initialization of the given entity based on - /// the computed initialization sequence. - /// - /// \param S the semantic analysis object. - /// - /// \param Entity the entity being initialized. - /// - /// \param Kind the kind of initialization being performed. - /// - /// \param Args the argument(s) provided for initialization, ownership of - /// which is transfered into the routine. - /// - /// \param ResultType if non-NULL, will be set to the type of the - /// initialized object, which is the type of the declaration in most - /// cases. However, when the initialized object is a variable of - /// incomplete array type and the initializer is an initializer - /// list, this type will be set to the completed array type. - /// - /// \returns an expression that performs the actual object initialization, if - /// the initialization is well-formed. Otherwise, emits diagnostics - /// and returns an invalid expression. - Action::OwningExprResult Perform(Sema &S, - const InitializedEntity &Entity, - const InitializationKind &Kind, - Action::MultiExprArg Args, - QualType *ResultType = 0); - - /// \brief Diagnose an potentially-invalid initialization sequence. - /// - /// \returns true if the initialization sequence was ill-formed, - /// false otherwise. - bool Diagnose(Sema &S, - const InitializedEntity &Entity, - const InitializationKind &Kind, - Expr **Args, unsigned NumArgs); - - /// \brief Determine the kind of initialization sequence computed. - enum SequenceKind getKind() const { return SequenceKind; } - - /// \brief Set the kind of sequence computed. - void setSequenceKind(enum SequenceKind SK) { SequenceKind = SK; } - - /// \brief Determine whether the initialization sequence is valid. - operator bool() const { return SequenceKind != FailedSequence; } - - typedef llvm::SmallVector::const_iterator step_iterator; - step_iterator step_begin() const { return Steps.begin(); } - step_iterator step_end() const { return Steps.end(); } - - /// \brief Determine whether this initialization is a direct reference - /// binding (C++ [dcl.init.ref]). - bool isDirectReferenceBinding() const; - - /// \brief Determine whether this initialization failed due to an ambiguity. - bool isAmbiguous() const; - - /// \brief Determine whether this initialization is direct call to a - /// constructor. - bool isConstructorInitialization() const; - - /// \brief Add a new step in the initialization that resolves the address - /// of an overloaded function to a specific function declaration. - /// - /// \param Function the function to which the overloaded function reference - /// resolves. - void AddAddressOverloadResolutionStep(FunctionDecl *Function, - DeclAccessPair Found); - - /// \brief Add a new step in the initialization that performs a derived-to- - /// base cast. - /// - /// \param BaseType the base type to which we will be casting. - /// - /// \param IsLValue true if the result of this cast will be treated as - /// an lvalue. - void AddDerivedToBaseCastStep(QualType BaseType, bool IsLValue); - - /// \brief Add a new step binding a reference to an object. - /// - /// \param BindingTemporary True if we are binding a reference to a temporary - /// object (thereby extending its lifetime); false if we are binding to an - /// lvalue or an lvalue treated as an rvalue. - /// - /// \param UnnecessaryCopy True if we should check for a copy - /// constructor for a completely unnecessary but - void AddReferenceBindingStep(QualType T, bool BindingTemporary); - - /// \brief Add a new step that makes an extraneous copy of the input - /// to a temporary of the same class type. - /// - /// This extraneous copy only occurs during reference binding in - /// C++98/03, where we are permitted (but not required) to introduce - /// an extra copy. At a bare minimum, we must check that we could - /// call the copy constructor, and produce a diagnostic if the copy - /// constructor is inaccessible or no copy constructor matches. - // - /// \param T The type of the temporary being created. - void AddExtraneousCopyToTemporary(QualType T); - - /// \brief Add a new step invoking a conversion function, which is either - /// a constructor or a conversion function. - void AddUserConversionStep(FunctionDecl *Function, - DeclAccessPair FoundDecl, - QualType T); - - /// \brief Add a new step that performs a qualification conversion to the - /// given type. - void AddQualificationConversionStep(QualType Ty, bool IsLValue); - - /// \brief Add a new step that applies an implicit conversion sequence. - void AddConversionSequenceStep(const ImplicitConversionSequence &ICS, - QualType T); - - /// \brief Add a list-initialiation step - void AddListInitializationStep(QualType T); - - /// \brief Add a constructor-initialization step. - void AddConstructorInitializationStep(CXXConstructorDecl *Constructor, - AccessSpecifier Access, - QualType T); - - /// \brief Add a zero-initialization step. - void AddZeroInitializationStep(QualType T); - - /// \brief Add a C assignment step. - // - // FIXME: It isn't clear whether this should ever be needed; - // ideally, we would handle everything needed in C in the common - // path. However, that isn't the case yet. - void AddCAssignmentStep(QualType T); - - /// \brief Add a string init step. - void AddStringInitStep(QualType T); - - /// \brief Note that this initialization sequence failed. - void SetFailed(FailureKind Failure) { - SequenceKind = FailedSequence; - this->Failure = Failure; - } - - /// \brief Note that this initialization sequence failed due to failed - /// overload resolution. - void SetOverloadFailure(FailureKind Failure, OverloadingResult Result); - - /// \brief Retrieve a reference to the candidate set when overload - /// resolution fails. - OverloadCandidateSet &getFailedCandidateSet() { - return FailedCandidateSet; - } - - /// \brief Determine why initialization failed. - FailureKind getFailureKind() const { - assert(getKind() == FailedSequence && "Not an initialization failure!"); - return Failure; - } - - /// \brief Dump a representation of this initialization sequence to - /// the given stream, for debugging purposes. - void dump(llvm::raw_ostream &OS) const; - - /// \brief Dump a representation of this initialization sequence to - /// standard error, for debugging purposes. - void dump() const; -}; - -} // end namespace clang - -#endif // LLVM_CLANG_SEMA_INIT_H diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 2e65183..306e95a 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -11,8 +11,13 @@ // Objective-C++. // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "Lookup.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/TemplateDeduction.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" @@ -21,9 +26,9 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" -#include "clang/Parse/DeclSpec.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/LangOptions.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/ErrorHandling.h" @@ -35,6 +40,7 @@ #include using namespace clang; +using namespace sema; namespace { class UnqualUsingEntry { @@ -100,7 +106,7 @@ namespace { End = S->using_directives_end(); for (; I != End; ++I) - visit(I->getAs(), InnermostFileDC); + visit(*I, InnermostFileDC); } } } @@ -254,6 +260,12 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, case Sema::LookupObjCProtocolName: IDNS = Decl::IDNS_ObjCProtocol; break; + + case Sema::LookupAnyName: + IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member + | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol + | Decl::IDNS_Type; + break; } return IDNS; } @@ -267,7 +279,7 @@ void LookupResult::configure() { // operators, make sure that the implicitly-declared new and delete // operators can be found. if (!isForRedeclaration()) { - switch (Name.getCXXOverloadedOperator()) { + switch (NameInfo.getName().getCXXOverloadedOperator()) { case OO_New: case OO_Delete: case OO_Array_New: @@ -281,6 +293,22 @@ void LookupResult::configure() { } } +#ifndef NDEBUG +void LookupResult::sanity() const { + assert(ResultKind != NotFound || Decls.size() == 0); + assert(ResultKind != Found || Decls.size() == 1); + assert(ResultKind != FoundOverloaded || Decls.size() > 1 || + (Decls.size() == 1 && + isa((*begin())->getUnderlyingDecl()))); + assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved()); + assert(ResultKind != Ambiguous || Decls.size() > 1 || + (Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects)); + assert((Paths != NULL) == (ResultKind == Ambiguous && + (Ambiguity == AmbiguousBaseSubobjectTypes || + Ambiguity == AmbiguousBaseSubobjects))); +} +#endif + // Necessary because CXXBasePaths is not complete in Sema.h void LookupResult::deletePaths(CXXBasePaths *Paths) { delete Paths; @@ -311,7 +339,8 @@ void LookupResult::resolveKind() { if (ResultKind == Ambiguous) return; llvm::SmallPtrSet Unique; - + llvm::SmallPtrSet UniqueTypes; + bool Ambiguous = false; bool HasTag = false, HasFunction = false, HasNonFunction = false; bool HasFunctionTemplate = false, HasUnresolved = false; @@ -323,32 +352,49 @@ void LookupResult::resolveKind() { NamedDecl *D = Decls[I]->getUnderlyingDecl(); D = cast(D->getCanonicalDecl()); + // Redeclarations of types via typedef can occur both within a scope + // and, through using declarations and directives, across scopes. There is + // no ambiguity if they all refer to the same type, so unique based on the + // canonical type. + if (TypeDecl *TD = dyn_cast(D)) { + if (!TD->getDeclContext()->isRecord()) { + QualType T = SemaRef.Context.getTypeDeclType(TD); + if (!UniqueTypes.insert(SemaRef.Context.getCanonicalType(T))) { + // The type is not unique; pull something off the back and continue + // at this index. + Decls[I] = Decls[--N]; + continue; + } + } + } + if (!Unique.insert(D)) { // If it's not unique, pull something off the back (and // continue at this index). Decls[I] = Decls[--N]; + continue; + } + + // Otherwise, do some decl type analysis and then continue. + + if (isa(D)) { + HasUnresolved = true; + } else if (isa(D)) { + if (HasTag) + Ambiguous = true; + UniqueTagIndex = I; + HasTag = true; + } else if (isa(D)) { + HasFunction = true; + HasFunctionTemplate = true; + } else if (isa(D)) { + HasFunction = true; } else { - // Otherwise, do some decl type analysis and then continue. - - if (isa(D)) { - HasUnresolved = true; - } else if (isa(D)) { - if (HasTag) - Ambiguous = true; - UniqueTagIndex = I; - HasTag = true; - } else if (isa(D)) { - HasFunction = true; - HasFunctionTemplate = true; - } else if (isa(D)) { - HasFunction = true; - } else { - if (HasNonFunction) - Ambiguous = true; - HasNonFunction = true; - } - I++; + if (HasNonFunction) + Ambiguous = true; + HasNonFunction = true; } + I++; } // C++ [basic.scope.hiding]p2: @@ -451,6 +497,10 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) { /// the class at this point. static bool CanDeclareSpecialMemberFunction(ASTContext &Context, const CXXRecordDecl *Class) { + // Don't do it if the class is invalid. + if (Class->isInvalidDecl()) + return false; + // We need to have a definition for the class. if (!Class->getDefinition() || Class->isDependentContext()) return false; @@ -608,7 +658,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // result), perform template argument deduction and place the // specialization into the result set. We do this to avoid forcing all // callers to perform special deduction for conversion functions. - Sema::TemplateDeductionInfo Info(R.getSema().Context, R.getNameLoc()); + TemplateDeductionInfo Info(R.getSema().Context, R.getNameLoc()); FunctionDecl *Specialization = 0; const FunctionProtoType *ConvProto @@ -783,7 +833,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // Check whether the IdResolver has anything in this scope. bool Found = false; - for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) { + for (; I != IEnd && S->isDeclScope(*I); ++I) { if (R.isAcceptableDecl(*I)) { Found = true; R.addDecl(*I); @@ -881,7 +931,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { for (; S; S = S->getParent()) { // Check whether the IdResolver has anything in this scope. bool Found = false; - for (; I != IEnd && S->isDeclScope(DeclPtrTy::make(*I)); ++I) { + for (; I != IEnd && S->isDeclScope(*I); ++I) { if (R.isAcceptableDecl(*I)) { // We found something. Look for anything else in our scope // with this same name and in an acceptable identifier @@ -1017,7 +1067,7 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { if (NameKind == LookupRedeclarationWithLinkage) { // Determine whether this (or a previous) declaration is // out-of-scope. - if (!LeftStartingScope && !S->isDeclScope(DeclPtrTy::make(*I))) + if (!LeftStartingScope && !S->isDeclScope(*I)) LeftStartingScope = true; // If we found something outside of our starting scope that @@ -1034,14 +1084,14 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { // Figure out what scope the identifier is in. while (!(S->getFlags() & Scope::DeclScope) || - !S->isDeclScope(DeclPtrTy::make(*I))) + !S->isDeclScope(*I)) S = S->getParent(); // Find the last declaration in this scope (with the same // name, naturally). IdentifierResolver::iterator LastI = I; for (++LastI; LastI != IEnd; ++LastI) { - if (!S->isDeclScope(DeclPtrTy::make(*LastI))) + if (!S->isDeclScope(*LastI)) break; R.addDecl(*LastI); } @@ -1177,6 +1227,17 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, return Found; } +/// \brief Callback that looks for any member of a class with the given name. +static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { + RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); + + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); + Path.Decls = BaseRecord->lookup(N); + return Path.Decls.first != Path.Decls.second; +} + /// \brief Perform qualified name lookup into a given context. /// /// Qualified name lookup (C++ [basic.lookup.qual]) is used to find @@ -1272,6 +1333,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, BaseCallback = &CXXRecordDecl::FindTagMember; break; + case LookupAnyName: + BaseCallback = &LookupAnyMember; + break; + case LookupUsingDeclName: // This lookup is for redeclarations only. @@ -1554,7 +1619,11 @@ static void CollectEnclosingNamespace(Sema::AssociatedNamespaceSet &Namespaces, // We don't use DeclContext::getEnclosingNamespaceContext() as this may // be a locally scoped record. - while (Ctx->isRecord() || Ctx->isTransparentContext()) + // We skip out of inline namespaces. The innermost non-inline namespace + // contains all names of all its nested inline namespaces anyway, so we can + // replace the entire inline namespace tree with its root. + while (Ctx->isRecord() || Ctx->isTransparentContext() || + Ctx->isInlineNamespace()) Ctx = Ctx->getParent(); if (Ctx->isFileContext()) @@ -1894,7 +1963,7 @@ Sema::FindAssociatedClassesAndNamespaces(Expr **Args, unsigned NumArgs, // parameter types and return type. Arg = Arg->IgnoreParens(); if (UnaryOperator *unaryOp = dyn_cast(Arg)) - if (unaryOp->getOpcode() == UnaryOperator::AddrOf) + if (unaryOp->getOpcode() == UO_AddrOf) Arg = unaryOp->getSubExpr(); UnresolvedLookupExpr *ULE = dyn_cast(Arg); @@ -2201,6 +2270,10 @@ public: return !VisitedContexts.insert(Ctx); } + bool alreadyVisitedContext(DeclContext *Ctx) { + return VisitedContexts.count(Ctx); + } + /// \brief Determine whether the given declaration is hidden in the /// current scope. /// @@ -2354,9 +2427,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, Visited.add(ND); } - // Visit transparent contexts inside this context. + // Visit transparent contexts and inline namespaces inside this context. if (DeclContext *InnerCtx = dyn_cast(*D)) { - if (InnerCtx->isTransparentContext()) + if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup, InBaseClass, Consumer, Visited); } @@ -2429,8 +2502,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, } // Traverse protocols. - for (ObjCInterfaceDecl::protocol_iterator I = IFace->protocol_begin(), - E = IFace->protocol_end(); I != E; ++I) { + for (ObjCInterfaceDecl::all_protocol_iterator + I = IFace->all_referenced_protocol_begin(), + E = IFace->all_referenced_protocol_end(); I != E; ++I) { ShadowContextRAII Shadow(Visited); LookupVisibleDecls(*I, Result, QualifiedNameLookup, false, Consumer, Visited); @@ -2481,12 +2555,14 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, if (!S) return; - if (!S->getEntity() || !S->getParent() || + if (!S->getEntity() || + (!S->getParent() && + !Visited.alreadyVisitedContext((DeclContext *)S->getEntity())) || ((DeclContext *)S->getEntity())->isFunctionOrMethod()) { // Walk through the declarations in this Scope. for (Scope::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); D != DEnd; ++D) { - if (NamedDecl *ND = dyn_cast((Decl *)((*D).get()))) + if (NamedDecl *ND = dyn_cast(*D)) if (Result.isAcceptableDecl(ND)) { Consumer.FoundDecl(ND, Visited.checkHidden(ND), false); Visited.add(ND); @@ -2559,7 +2635,8 @@ static void LookupVisibleDecls(Scope *S, LookupResult &Result, } void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, - VisibleDeclConsumer &Consumer) { + VisibleDeclConsumer &Consumer, + bool IncludeGlobalScope) { // Determine the set of using directives available during // unqualified name lookup. Scope *Initial = S; @@ -2576,14 +2653,19 @@ void Sema::LookupVisibleDecls(Scope *S, LookupNameKind Kind, // Look for visible declarations. LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); VisibleDeclsRecord Visited; + if (!IncludeGlobalScope) + Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); ::LookupVisibleDecls(Initial, Result, UDirs, Consumer, Visited); } void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, - VisibleDeclConsumer &Consumer) { + VisibleDeclConsumer &Consumer, + bool IncludeGlobalScope) { LookupResult Result(*this, DeclarationName(), SourceLocation(), Kind); VisibleDeclsRecord Visited; + if (!IncludeGlobalScope) + Visited.visitedContext(Context.getTranslationUnitDecl()); ShadowContextRAII Shadow(Visited); ::LookupVisibleDecls(Ctx, Result, /*QualifiedNameLookup=*/true, /*InBaseClass=*/false, Consumer, Visited); @@ -2911,7 +2993,7 @@ DeclarationName Sema::CorrectTypo(LookupResult &Res, Scope *S, CXXScopeSpec *SS, if (S && S->getContinueParent()) Consumer.addKeywordResult(Context, "continue"); - if (!getSwitchStack().empty()) { + if (!getCurFunction()->SwitchStack.empty()) { Consumer.addKeywordResult(Context, "case"); Consumer.addKeywordResult(Context, "default"); } diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index ff60599..7181d58 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -12,9 +12,11 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "SemaInit.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Initialization.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/ExprObjC.h" +#include "llvm/ADT/DenseSet.h" using namespace clang; @@ -22,14 +24,14 @@ using namespace clang; // Grammar actions. //===----------------------------------------------------------------------===// -Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, - FieldDeclarator &FD, - ObjCDeclSpec &ODS, - Selector GetterSel, - Selector SetterSel, - DeclPtrTy ClassCategory, - bool *isOverridingProperty, - tok::ObjCKeywordKind MethodImplKind) { +Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, + FieldDeclarator &FD, + ObjCDeclSpec &ODS, + Selector GetterSel, + Selector SetterSel, + Decl *ClassCategory, + bool *isOverridingProperty, + tok::ObjCKeywordKind MethodImplKind) { unsigned Attributes = ODS.getPropertyAttributes(); bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || // default is readwrite! @@ -45,15 +47,15 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, QualType T = TSI->getType(); if (T->isReferenceType()) { Diag(AtLoc, diag::error_reference_property); - return DeclPtrTy(); + return 0; } // Proceed with constructing the ObjCPropertDecls. ObjCContainerDecl *ClassDecl = - cast(ClassCategory.getAs()); + cast(ClassCategory); if (ObjCCategoryDecl *CDecl = dyn_cast(ClassDecl)) if (CDecl->IsClassExtension()) { - DeclPtrTy Res = HandlePropertyInClassExtension(S, CDecl, AtLoc, + Decl *Res = HandlePropertyInClassExtension(S, CDecl, AtLoc, FD, GetterSel, SetterSel, isAssign, isReadWrite, Attributes, @@ -64,16 +66,16 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, return Res; } - DeclPtrTy Res = DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD, - GetterSel, SetterSel, - isAssign, isReadWrite, - Attributes, TSI, MethodImplKind)); + Decl *Res = CreatePropertyDecl(S, ClassDecl, AtLoc, FD, + GetterSel, SetterSel, + isAssign, isReadWrite, + Attributes, TSI, MethodImplKind); // Validate the attributes on the @property. CheckObjCPropertyAttributes(Res, AtLoc, Attributes); return Res; } -Sema::DeclPtrTy +Decl * Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, SourceLocation AtLoc, FieldDeclarator &FD, Selector GetterSel, Selector SetterSel, @@ -92,7 +94,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) { Diag(AtLoc, diag::err_duplicate_property); Diag(prevDecl->getLocation(), diag::note_property_declare); - return DeclPtrTy(); + return 0; } // Create a new ObjCPropertyDecl with the DeclContext being @@ -113,7 +115,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, if (!CCPrimary) { Diag(CDecl->getLocation(), diag::err_continuation_class); *isOverridingProperty = true; - return DeclPtrTy(); + return 0; } // Find the property in continuation class's primary class only. @@ -136,7 +138,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, // is not what it was meant for. However, gcc supports it and so should we. // Make sure setter/getters are declared here. ProcessPropertyDecl(PDecl, CCPrimary); - return DeclPtrTy::make(PDecl); + return PDecl; } @@ -165,13 +167,13 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, setPropertyAttributes((ObjCDeclSpec::ObjCPropertyAttributeKind) PIkind); - DeclPtrTy ProtocolPtrTy = + Decl *ProtocolPtrTy = ActOnProperty(S, AtLoc, FD, ProtocolPropertyODS, PIDecl->getGetterName(), PIDecl->getSetterName(), - DeclPtrTy::make(CCPrimary), isOverridingProperty, + CCPrimary, isOverridingProperty, MethodImplKind); - PIDecl = cast(ProtocolPtrTy.getAs()); + PIDecl = cast(ProtocolPtrTy); } PIDecl->makeitReadWriteAttribute(); if (Attributes & ObjCDeclSpec::DQ_PR_retain) @@ -187,7 +189,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl, *isOverridingProperty = true; // Make sure setter decl is synthesized, and added to primary class's list. ProcessPropertyDecl(PIDecl, CCPrimary); - return DeclPtrTy(); + return 0; } ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, @@ -289,19 +291,19 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, /// builds the AST node for a property implementation declaration; declared /// as @synthesize or @dynamic. /// -Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, - SourceLocation AtLoc, - SourceLocation PropertyLoc, - bool Synthesize, - DeclPtrTy ClassCatImpDecl, - IdentifierInfo *PropertyId, - IdentifierInfo *PropertyIvar) { +Decl *Sema::ActOnPropertyImplDecl(Scope *S, + SourceLocation AtLoc, + SourceLocation PropertyLoc, + bool Synthesize, + Decl *ClassCatImpDecl, + IdentifierInfo *PropertyId, + IdentifierInfo *PropertyIvar) { ObjCContainerDecl *ClassImpDecl = - cast_or_null(ClassCatImpDecl.getAs()); + cast_or_null(ClassCatImpDecl); // Make sure we have a context for the property implementation declaration. if (!ClassImpDecl) { Diag(AtLoc, diag::error_missing_property_context); - return DeclPtrTy(); + return 0; } ObjCPropertyDecl *property = 0; ObjCInterfaceDecl* IDecl = 0; @@ -320,25 +322,25 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, property = IDecl->FindPropertyDeclaration(PropertyId); if (!property) { Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName(); - return DeclPtrTy(); + return 0; } if (const ObjCCategoryDecl *CD = dyn_cast(property->getDeclContext())) { if (!CD->IsClassExtension()) { Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName(); Diag(property->getLocation(), diag::note_property_declare); - return DeclPtrTy(); + return 0; } } } else if ((CatImplClass = dyn_cast(ClassImpDecl))) { if (Synthesize) { Diag(AtLoc, diag::error_synthesize_category_decl); - return DeclPtrTy(); + return 0; } IDecl = CatImplClass->getClassInterface(); if (!IDecl) { Diag(AtLoc, diag::error_missing_property_interface); - return DeclPtrTy(); + return 0; } ObjCCategoryDecl *Category = IDecl->FindCategoryDeclaration(CatImplClass->getIdentifier()); @@ -346,17 +348,17 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, // If category for this implementation not found, it is an error which // has already been reported eralier. if (!Category) - return DeclPtrTy(); + return 0; // Look for this property declaration in @implementation's category property = Category->FindPropertyDeclaration(PropertyId); if (!property) { Diag(PropertyLoc, diag::error_bad_category_property_decl) << Category->getDeclName(); - return DeclPtrTy(); + return 0; } } else { Diag(AtLoc, diag::error_bad_property_context); - return DeclPtrTy(); + return 0; } ObjCIvarDecl *Ivar = 0; // Check that we have a valid, previously declared ivar for @synthesize @@ -372,7 +374,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, PropertyLoc, PropertyIvar, PropType, /*Dinfo=*/0, ObjCIvarDecl::Protected, - (Expr *)0); + (Expr *)0, true); ClassImpDecl->addDecl(Ivar); IDecl->makeDeclVisibleInContext(Ivar, false); property->setPropertyIvarDecl(Ivar); @@ -387,7 +389,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, << property->getDeclName() << Ivar->getDeclName() << ClassDeclared->getDeclName(); Diag(Ivar->getLocation(), diag::note_previous_access_declaration) - << Ivar << Ivar->getNameAsCString(); + << Ivar << Ivar->getName(); // Note! I deliberately want it to fall thru so more errors are caught. } QualType IvarType = Context.getCanonicalType(Ivar->getType()); @@ -464,7 +466,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, Expr *IvarRefExpr = new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc, SelfExpr, true, true); - OwningExprResult Res = + ExprResult Res = PerformCopyInitialization(InitializedEntity::InitializeResult( SourceLocation(), getterMethod->getResultType(), @@ -494,8 +496,8 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, ParmVarDecl *Param = (*P); Expr *rhs = new (Context) DeclRefExpr(Param,Param->getType(), SourceLocation()); - OwningExprResult Res = BuildBinOp(S, SourceLocation(), - BinaryOperator::Assign, lhs, rhs); + ExprResult Res = BuildBinOp(S, SourceLocation(), + BO_Assign, lhs, rhs); PIDecl->setSetterCXXAssignment(Res.takeAs()); } } @@ -514,9 +516,29 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, = IC->FindPropertyImplDecl(PropertyId)) { Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; Diag(PPIDecl->getLocation(), diag::note_previous_declaration); - return DeclPtrTy(); + return 0; } IC->addPropertyImplementation(PIDecl); + if (getLangOptions().ObjCNonFragileABI2) { + // Diagnose if an ivar was lazily synthesdized due to a previous + // use and if 1) property is @dynamic or 2) property is synthesized + // but it requires an ivar of different name. + ObjCInterfaceDecl *ClassDeclared; + ObjCIvarDecl *Ivar = 0; + if (!Synthesize) + Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared); + else { + if (PropertyIvar && PropertyIvar != PropertyId) + Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared); + } + // Issue diagnostics only if Ivar belongs to current class. + if (Ivar && Ivar->getSynthesize() && + IC->getClassInterface() == ClassDeclared) { + Diag(Ivar->getLocation(), diag::err_undeclared_var_use) + << PropertyId; + Ivar->setInvalidDecl(); + } + } } else { if (Synthesize) if (ObjCPropertyImplDecl *PPIDecl = @@ -531,12 +553,12 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, CatImplClass->FindPropertyImplDecl(PropertyId)) { Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; Diag(PPIDecl->getLocation(), diag::note_previous_declaration); - return DeclPtrTy(); + return 0; } CatImplClass->addPropertyImplementation(PIDecl); } - return DeclPtrTy::make(PIDecl); + return PIDecl; } //===----------------------------------------------------------------------===// @@ -680,9 +702,8 @@ Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl, /// declared in 'ClassOrProtocol' objects (which can be a class or an /// inherited protocol with the list of properties for class/category 'CDecl' /// -void Sema::CompareProperties(Decl *CDecl, - DeclPtrTy ClassOrProtocol) { - Decl *ClassDecl = ClassOrProtocol.getAs(); +void Sema::CompareProperties(Decl *CDecl, Decl *ClassOrProtocol) { + Decl *ClassDecl = ClassOrProtocol; ObjCInterfaceDecl *IDecl = dyn_cast_or_null(CDecl); if (!IDecl) { @@ -699,7 +720,7 @@ void Sema::CompareProperties(Decl *CDecl, // their properties with those in the category. for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(), E = CatDecl->protocol_end(); P != E; ++P) - CompareProperties(CatDecl, DeclPtrTy::make(*P)); + CompareProperties(CatDecl, *P); } else { ObjCProtocolDecl *MD = cast(ClassDecl); for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), @@ -710,16 +731,18 @@ void Sema::CompareProperties(Decl *CDecl, } if (ObjCInterfaceDecl *MDecl = dyn_cast(ClassDecl)) { - for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(), - E = MDecl->protocol_end(); P != E; ++P) + for (ObjCInterfaceDecl::all_protocol_iterator + P = MDecl->all_referenced_protocol_begin(), + E = MDecl->all_referenced_protocol_end(); P != E; ++P) // Match properties of class IDecl with those of protocol (*P). MatchOneProtocolPropertiesInClass(IDecl, *P); // Go thru the list of protocols for this class and recursively match // their properties with those declared in the class. - for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(), - E = IDecl->protocol_end(); P != E; ++P) - CompareProperties(IDecl, DeclPtrTy::make(*P)); + for (ObjCInterfaceDecl::all_protocol_iterator + P = IDecl->all_referenced_protocol_begin(), + E = IDecl->all_referenced_protocol_end(); P != E; ++P) + CompareProperties(IDecl, *P); } else { ObjCProtocolDecl *MD = cast(ClassDecl); for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(), @@ -791,8 +814,9 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, PropMap[Prop->getIdentifier()] = Prop; } // scan through class's protocols. - for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), - E = IDecl->protocol_end(); PI != E; ++PI) + for (ObjCInterfaceDecl::all_protocol_iterator + PI = IDecl->all_referenced_protocol_begin(), + E = IDecl->all_referenced_protocol_end(); PI != E; ++PI) CollectImmediateProperties((*PI), PropMap, SuperPropMap); } if (ObjCCategoryDecl *CATDecl = dyn_cast(CDecl)) { @@ -803,7 +827,7 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, PropMap[Prop->getIdentifier()] = Prop; } // scan through class's protocols. - for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(), + for (ObjCCategoryDecl::protocol_iterator PI = CATDecl->protocol_begin(), E = CATDecl->protocol_end(); PI != E; ++PI) CollectImmediateProperties((*PI), PropMap, SuperPropMap); } @@ -838,8 +862,9 @@ static void CollectClassPropertyImplementations(ObjCContainerDecl *CDecl, ObjCPropertyDecl *Prop = (*P); PropMap[Prop->getIdentifier()] = Prop; } - for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), - E = IDecl->protocol_end(); PI != E; ++PI) + for (ObjCInterfaceDecl::all_protocol_iterator + PI = IDecl->all_referenced_protocol_begin(), + E = IDecl->all_referenced_protocol_end(); PI != E; ++PI) CollectClassPropertyImplementations((*PI), PropMap); } else if (ObjCProtocolDecl *PDecl = dyn_cast(CDecl)) { @@ -881,8 +906,9 @@ ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, return Prop; } // scan through class's protocols. - for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(), - E = IDecl->protocol_end(); PI != E; ++PI) { + for (ObjCInterfaceDecl::all_protocol_iterator + PI = IDecl->all_referenced_protocol_begin(), + E = IDecl->all_referenced_protocol_end(); PI != E; ++PI) { ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II); if (Prop) return Prop; @@ -933,9 +959,15 @@ void Sema::DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, // Property may have been synthesized by user. if (IMPDecl->FindPropertyImplDecl(Prop->getIdentifier())) continue; + if (IMPDecl->getInstanceMethod(Prop->getGetterName())) { + if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly) + continue; + if (IMPDecl->getInstanceMethod(Prop->getSetterName())) + continue; + } ActOnPropertyImplDecl(S, IMPDecl->getLocation(), IMPDecl->getLocation(), - true, DeclPtrTy::make(IMPDecl), + true, IMPDecl, Prop->getIdentifier(), Prop->getIdentifier()); } } @@ -1066,7 +1098,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, // for this class. GetterMethod = ObjCMethodDecl::Create(Context, property->getLocation(), property->getLocation(), property->getGetterName(), - property->getType(), 0, CD, true, false, true, + property->getType(), 0, CD, true, false, true, + false, (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) ? ObjCMethodDecl::Optional : @@ -1094,6 +1127,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, property->getLocation(), property->getSetterName(), Context.VoidTy, 0, CD, true, false, true, + false, (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) ? ObjCMethodDecl::Optional : @@ -1105,8 +1139,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, property->getIdentifier(), property->getType(), /*TInfo=*/0, - VarDecl::None, - VarDecl::None, + SC_None, + SC_None, 0); SetterMethod->setMethodParams(Context, &Argument, 1, 1); CD->addDecl(SetterMethod); @@ -1138,11 +1172,10 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, AddInstanceMethodToGlobalPool(SetterMethod); } -void Sema::CheckObjCPropertyAttributes(DeclPtrTy PropertyPtrTy, +void Sema::CheckObjCPropertyAttributes(Decl *PDecl, SourceLocation Loc, unsigned &Attributes) { // FIXME: Improve the reported location. - Decl *PDecl = PropertyPtrTy.getAs(); if (!PDecl) return; diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index c4ab906..11b4bb3 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -11,13 +11,16 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "Lookup.h" -#include "SemaInit.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Template.h" +#include "clang/Sema/TemplateDeduction.h" #include "clang/Basic/Diagnostic.h" #include "clang/Lex/Preprocessor.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/TypeOrdering.h" @@ -27,6 +30,34 @@ #include namespace clang { +using namespace sema; + +static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, + bool InOverloadResolution, + StandardConversionSequence &SCS); +static OverloadingResult +IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, + UserDefinedConversionSequence& User, + OverloadCandidateSet& Conversions, + bool AllowExplicit); + + +static ImplicitConversionSequence::CompareKind +CompareStandardConversionSequences(Sema &S, + const StandardConversionSequence& SCS1, + const StandardConversionSequence& SCS2); + +static ImplicitConversionSequence::CompareKind +CompareQualificationConversions(Sema &S, + const StandardConversionSequence& SCS1, + const StandardConversionSequence& SCS2); + +static ImplicitConversionSequence::CompareKind +CompareDerivedToBaseConversions(Sema &S, + const StandardConversionSequence& SCS1, + const StandardConversionSequence& SCS2); + + /// GetConversionCategory - Retrieve the implicit conversion /// category corresponding to the given implicit conversion kind. @@ -298,7 +329,7 @@ namespace { OverloadCandidate::DeductionFailureInfo static MakeDeductionFailureInfo(ASTContext &Context, Sema::TemplateDeductionResult TDK, - Sema::TemplateDeductionInfo &Info) { + TemplateDeductionInfo &Info) { OverloadCandidate::DeductionFailureInfo Result; Result.Result = static_cast(TDK); Result.Data = 0; @@ -315,7 +346,7 @@ static MakeDeductionFailureInfo(ASTContext &Context, break; case Sema::TDK_Inconsistent: - case Sema::TDK_InconsistentQuals: { + case Sema::TDK_Underqualified: { // FIXME: Should allocate from normal heap so that we can free this later. DFIParamWithArguments *Saved = new (Context) DFIParamWithArguments; Saved->Param = Info.Param; @@ -348,7 +379,7 @@ void OverloadCandidate::DeductionFailureInfo::Destroy() { break; case Sema::TDK_Inconsistent: - case Sema::TDK_InconsistentQuals: + case Sema::TDK_Underqualified: // FIXME: Destroy the data? Data = 0; break; @@ -380,7 +411,7 @@ OverloadCandidate::DeductionFailureInfo::getTemplateParameter() { return TemplateParameter::getFromOpaqueValue(Data); case Sema::TDK_Inconsistent: - case Sema::TDK_InconsistentQuals: + case Sema::TDK_Underqualified: return static_cast(Data)->Param; // Unhandled @@ -402,7 +433,7 @@ OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() { case Sema::TDK_Incomplete: case Sema::TDK_InvalidExplicitArguments: case Sema::TDK_Inconsistent: - case Sema::TDK_InconsistentQuals: + case Sema::TDK_Underqualified: return 0; case Sema::TDK_SubstitutionFailure: @@ -429,7 +460,7 @@ const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() { return 0; case Sema::TDK_Inconsistent: - case Sema::TDK_InconsistentQuals: + case Sema::TDK_Underqualified: return &static_cast(Data)->FirstArg; // Unhandled @@ -454,7 +485,7 @@ OverloadCandidate::DeductionFailureInfo::getSecondArg() { return 0; case Sema::TDK_Inconsistent: - case Sema::TDK_InconsistentQuals: + case Sema::TDK_Underqualified: return &static_cast(Data)->SecondArg; // Unhandled @@ -573,6 +604,11 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, bool UseUsingDeclRules) { + // If both of the functions are extern "C", then they are not + // overloads. + if (Old->isExternC() && New->isExternC()) + return false; + FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate(); FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate(); @@ -669,40 +705,34 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, /// not permitted. /// If @p AllowExplicit, then explicit user-defined conversions are /// permitted. -ImplicitConversionSequence -Sema::TryImplicitConversion(Expr* From, QualType ToType, - bool SuppressUserConversions, - bool AllowExplicit, - bool InOverloadResolution) { +static ImplicitConversionSequence +TryImplicitConversion(Sema &S, Expr *From, QualType ToType, + bool SuppressUserConversions, + bool AllowExplicit, + bool InOverloadResolution) { ImplicitConversionSequence ICS; - if (IsStandardConversion(From, ToType, InOverloadResolution, ICS.Standard)) { + if (IsStandardConversion(S, From, ToType, InOverloadResolution, + ICS.Standard)) { ICS.setStandard(); return ICS; } - if (!getLangOptions().CPlusPlus) { + if (!S.getLangOptions().CPlusPlus) { ICS.setBad(BadConversionSequence::no_conversion, From, ToType); return ICS; } - if (SuppressUserConversions) { - // C++ [over.ics.user]p4: - // A conversion of an expression of class type to the same class - // type is given Exact Match rank, and a conversion of an - // expression of class type to a base class of that type is - // given Conversion rank, in spite of the fact that a copy/move - // constructor (i.e., a user-defined conversion function) is - // called for those cases. - QualType FromType = From->getType(); - if (!ToType->getAs() || !FromType->getAs() || - !(Context.hasSameUnqualifiedType(FromType, ToType) || - IsDerivedFrom(FromType, ToType))) { - // We're not in the case above, so there is no conversion that - // we can perform. - ICS.setBad(BadConversionSequence::no_conversion, From, ToType); - return ICS; - } - + // C++ [over.ics.user]p4: + // A conversion of an expression of class type to the same class + // type is given Exact Match rank, and a conversion of an + // expression of class type to a base class of that type is + // given Conversion rank, in spite of the fact that a copy/move + // constructor (i.e., a user-defined conversion function) is + // called for those cases. + QualType FromType = From->getType(); + if (ToType->getAs() && FromType->getAs() && + (S.Context.hasSameUnqualifiedType(FromType, ToType) || + S.IsDerivedFrom(FromType, ToType))) { ICS.setStandard(); ICS.Standard.setAsIdentityConversion(); ICS.Standard.setFromType(FromType); @@ -713,18 +743,25 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, // exists. When we actually perform initialization, we'll find the // appropriate constructor to copy the returned object, if needed. ICS.Standard.CopyConstructor = 0; - + // Determine whether this is considered a derived-to-base conversion. - if (!Context.hasSameUnqualifiedType(FromType, ToType)) + if (!S.Context.hasSameUnqualifiedType(FromType, ToType)) ICS.Standard.Second = ICK_Derived_To_Base; - + + return ICS; + } + + if (SuppressUserConversions) { + // We're not in the case above, so there is no conversion that + // we can perform. + ICS.setBad(BadConversionSequence::no_conversion, From, ToType); return ICS; } // Attempt user-defined conversion. OverloadCandidateSet Conversions(From->getExprLoc()); OverloadingResult UserDefResult - = IsUserDefinedConversion(From, ToType, ICS.UserDefined, Conversions, + = IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions, AllowExplicit); if (UserDefResult == OR_Success) { @@ -739,10 +776,11 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, if (CXXConstructorDecl *Constructor = dyn_cast(ICS.UserDefined.ConversionFunction)) { QualType FromCanon - = Context.getCanonicalType(From->getType().getUnqualifiedType()); - QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType(); + = S.Context.getCanonicalType(From->getType().getUnqualifiedType()); + QualType ToCanon + = S.Context.getCanonicalType(ToType).getUnqualifiedType(); if (Constructor->isCopyConstructor() && - (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon))) { + (FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) { // Turn this into a "standard" conversion sequence, so that it // gets ranked with standard conversion sequences. ICS.setStandard(); @@ -780,6 +818,24 @@ Sema::TryImplicitConversion(Expr* From, QualType ToType, return ICS; } +bool Sema::TryImplicitConversion(InitializationSequence &Sequence, + const InitializedEntity &Entity, + Expr *Initializer, + bool SuppressUserConversions, + bool AllowExplicitConversions, + bool InOverloadResolution) { + ImplicitConversionSequence ICS + = clang::TryImplicitConversion(*this, Initializer, Entity.getType(), + SuppressUserConversions, + AllowExplicitConversions, + InOverloadResolution); + if (ICS.isBad()) return true; + + // Perform the actual conversion. + Sequence.AddConversionSequenceStep(ICS, Entity.getType()); + return false; +} + /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType. Returns true if there was an /// error, false otherwise. The expression From is replaced with the @@ -797,10 +853,10 @@ bool Sema::PerformImplicitConversion(Expr *&From, QualType ToType, AssignmentAction Action, bool AllowExplicit, ImplicitConversionSequence& ICS) { - ICS = TryImplicitConversion(From, ToType, - /*SuppressUserConversions=*/false, - AllowExplicit, - /*InOverloadResolution=*/false); + ICS = clang::TryImplicitConversion(*this, From, ToType, + /*SuppressUserConversions=*/false, + AllowExplicit, + /*InOverloadResolution=*/false); return PerformImplicitConversion(From, ToType, ICS, Action); } @@ -850,16 +906,20 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType, return true; } } - - // If lax vector conversions are permitted and the vector types are of the - // same size, we can perform the conversion. - if (Context.getLangOptions().LaxVectorConversions && - FromType->isVectorType() && ToType->isVectorType() && - Context.getTypeSize(FromType) == Context.getTypeSize(ToType)) { - ICK = ICK_Vector_Conversion; - return true; + + // We can perform the conversion between vector types in the following cases: + // 1)vector types are equivalent AltiVec and GCC vector types + // 2)lax vector conversions are permitted and the vector types are of the + // same size + if (ToType->isVectorType() && FromType->isVectorType()) { + if (Context.areCompatibleVectorTypes(FromType, ToType) || + (Context.getLangOptions().LaxVectorConversions && + (Context.getTypeSize(FromType) == Context.getTypeSize(ToType)))) { + ICK = ICK_Vector_Conversion; + return true; + } } - + return false; } @@ -871,12 +931,11 @@ static bool IsVectorConversion(ASTContext &Context, QualType FromType, /// contain the standard conversion sequence required to perform this /// conversion and this routine will return true. Otherwise, this /// routine will return false and the value of SCS is unspecified. -bool -Sema::IsStandardConversion(Expr* From, QualType ToType, - bool InOverloadResolution, - StandardConversionSequence &SCS) { +static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, + bool InOverloadResolution, + StandardConversionSequence &SCS) { QualType FromType = From->getType(); - + // Standard conversions (C++ [conv]) SCS.setAsIdentityConversion(); SCS.DeprecatedStringLiteralToCharPtr = false; @@ -887,7 +946,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // There are no standard conversions for class types in C++, so // abort early. When overloading in C, however, we do permit if (FromType->isRecordType() || ToType->isRecordType()) { - if (getLangOptions().CPlusPlus) + if (S.getLangOptions().CPlusPlus) return false; // When we're overloading in C, we allow, as standard conversions, @@ -897,19 +956,19 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // array-to-pointer conversion, or function-to-pointer conversion // (C++ 4p1). - if (FromType == Context.OverloadTy) { + if (FromType == S.Context.OverloadTy) { DeclAccessPair AccessPair; if (FunctionDecl *Fn - = ResolveAddressOfOverloadedFunction(From, ToType, false, - AccessPair)) { + = S.ResolveAddressOfOverloadedFunction(From, ToType, false, + AccessPair)) { // We were able to resolve the address of the overloaded function, // so we can convert to the type of that function. FromType = Fn->getType(); if (CXXMethodDecl *Method = dyn_cast(Fn)) { if (!Method->isStatic()) { Type *ClassType - = Context.getTypeDeclType(Method->getParent()).getTypePtr(); - FromType = Context.getMemberPointerType(FromType, ClassType); + = S.Context.getTypeDeclType(Method->getParent()).getTypePtr(); + FromType = S.Context.getMemberPointerType(FromType, ClassType); } } @@ -917,12 +976,12 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // function, update the type of the resulting expression accordingly. if (FromType->getAs()) if (UnaryOperator *UnOp = dyn_cast(From->IgnoreParens())) - if (UnOp->getOpcode() == UnaryOperator::AddrOf) - FromType = Context.getPointerType(FromType); + if (UnOp->getOpcode() == UO_AddrOf) + FromType = S.Context.getPointerType(FromType); // Check that we've computed the proper type after overload resolution. - assert(Context.hasSameType(FromType, - FixOverloadedFunctionReference(From, AccessPair, Fn)->getType())); + assert(S.Context.hasSameType(FromType, + S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType())); } else { return false; } @@ -930,10 +989,10 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // Lvalue-to-rvalue conversion (C++ 4.1): // An lvalue (3.10) of a non-function, non-array type T can be // converted to an rvalue. - Expr::isLvalueResult argIsLvalue = From->isLvalue(Context); + Expr::isLvalueResult argIsLvalue = From->isLvalue(S.Context); if (argIsLvalue == Expr::LV_Valid && !FromType->isFunctionType() && !FromType->isArrayType() && - Context.getCanonicalType(FromType) != Context.OverloadTy) { + S.Context.getCanonicalType(FromType) != S.Context.OverloadTy) { SCS.First = ICK_Lvalue_To_Rvalue; // If T is a non-class type, the type of the rvalue is the @@ -948,9 +1007,9 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // An lvalue or rvalue of type "array of N T" or "array of unknown // bound of T" can be converted to an rvalue of type "pointer to // T" (C++ 4.2p1). - FromType = Context.getArrayDecayedType(FromType); + FromType = S.Context.getArrayDecayedType(FromType); - if (IsStringLiteralToNonConstPointerConversion(From, ToType)) { + if (S.IsStringLiteralToNonConstPointerConversion(From, ToType)) { // This conversion is deprecated. (C++ D.4). SCS.DeprecatedStringLiteralToCharPtr = true; @@ -970,7 +1029,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // An lvalue of function type T can be converted to an rvalue of // type "pointer to T." The result is a pointer to the // function. (C++ 4.3p1). - FromType = Context.getPointerType(FromType); + FromType = S.Context.getPointerType(FromType); } else { // We don't require any conversions for the first step. SCS.First = ICK_Identity; @@ -985,24 +1044,24 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // conversion. bool IncompatibleObjC = false; ImplicitConversionKind SecondICK = ICK_Identity; - if (Context.hasSameUnqualifiedType(FromType, ToType)) { + if (S.Context.hasSameUnqualifiedType(FromType, ToType)) { // The unqualified versions of the types are the same: there's no // conversion to do. SCS.Second = ICK_Identity; - } else if (IsIntegralPromotion(From, FromType, ToType)) { + } else if (S.IsIntegralPromotion(From, FromType, ToType)) { // Integral promotion (C++ 4.5). SCS.Second = ICK_Integral_Promotion; FromType = ToType.getUnqualifiedType(); - } else if (IsFloatingPointPromotion(FromType, ToType)) { + } else if (S.IsFloatingPointPromotion(FromType, ToType)) { // Floating point promotion (C++ 4.6). SCS.Second = ICK_Floating_Promotion; FromType = ToType.getUnqualifiedType(); - } else if (IsComplexPromotion(FromType, ToType)) { + } else if (S.IsComplexPromotion(FromType, ToType)) { // Complex promotion (Clang extension) SCS.Second = ICK_Complex_Promotion; FromType = ToType.getUnqualifiedType(); } else if (FromType->isIntegralOrEnumerationType() && - ToType->isIntegralType(Context)) { + ToType->isIntegralType(S.Context)) { // Integral conversions (C++ 4.7). SCS.Second = ICK_Integral_Conversion; FromType = ToType.getUnqualifiedType(); @@ -1020,19 +1079,19 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, SCS.Second = ICK_Floating_Conversion; FromType = ToType.getUnqualifiedType(); } else if ((FromType->isRealFloatingType() && - ToType->isIntegralType(Context) && !ToType->isBooleanType()) || + ToType->isIntegralType(S.Context) && !ToType->isBooleanType()) || (FromType->isIntegralOrEnumerationType() && ToType->isRealFloatingType())) { // Floating-integral conversions (C++ 4.9). SCS.Second = ICK_Floating_Integral; FromType = ToType.getUnqualifiedType(); - } else if (IsPointerConversion(From, FromType, ToType, InOverloadResolution, - FromType, IncompatibleObjC)) { + } else if (S.IsPointerConversion(From, FromType, ToType, InOverloadResolution, + FromType, IncompatibleObjC)) { // Pointer conversions (C++ 4.10). SCS.Second = ICK_Pointer_Conversion; SCS.IncompatibleObjC = IncompatibleObjC; - } else if (IsMemberPointerConversion(From, FromType, ToType, - InOverloadResolution, FromType)) { + } else if (S.IsMemberPointerConversion(From, FromType, ToType, + InOverloadResolution, FromType)) { // Pointer to member conversions (4.11). SCS.Second = ICK_Pointer_Member; } else if (ToType->isBooleanType() && @@ -1044,16 +1103,16 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, FromType->isNullPtrType())) { // Boolean conversions (C++ 4.12). SCS.Second = ICK_Boolean_Conversion; - FromType = Context.BoolTy; - } else if (IsVectorConversion(Context, FromType, ToType, SecondICK)) { + FromType = S.Context.BoolTy; + } else if (IsVectorConversion(S.Context, FromType, ToType, SecondICK)) { SCS.Second = SecondICK; FromType = ToType.getUnqualifiedType(); - } else if (!getLangOptions().CPlusPlus && - Context.typesAreCompatible(ToType, FromType)) { + } else if (!S.getLangOptions().CPlusPlus && + S.Context.typesAreCompatible(ToType, FromType)) { // Compatible conversions (Clang extension for C function overloading) SCS.Second = ICK_Compatible_Conversion; FromType = ToType.getUnqualifiedType(); - } else if (IsNoReturnConversion(Context, FromType, ToType, FromType)) { + } else if (IsNoReturnConversion(S.Context, FromType, ToType, FromType)) { // Treat a conversion that strips "noreturn" as an identity conversion. SCS.Second = ICK_NoReturn_Adjustment; } else { @@ -1065,11 +1124,11 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, QualType CanonFrom; QualType CanonTo; // The third conversion can be a qualification conversion (C++ 4p1). - if (IsQualificationConversion(FromType, ToType)) { + if (S.IsQualificationConversion(FromType, ToType)) { SCS.Third = ICK_Qualification; FromType = ToType; - CanonFrom = Context.getCanonicalType(FromType); - CanonTo = Context.getCanonicalType(ToType); + CanonFrom = S.Context.getCanonicalType(FromType); + CanonTo = S.Context.getCanonicalType(ToType); } else { // No conversion required SCS.Third = ICK_Identity; @@ -1078,8 +1137,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // [...] Any difference in top-level cv-qualification is // subsumed by the initialization itself and does not constitute // a conversion. [...] - CanonFrom = Context.getCanonicalType(FromType); - CanonTo = Context.getCanonicalType(ToType); + CanonFrom = S.Context.getCanonicalType(FromType); + CanonTo = S.Context.getCanonicalType(ToType); if (CanonFrom.getLocalUnqualifiedType() == CanonTo.getLocalUnqualifiedType() && (CanonFrom.getLocalCVRQualifiers() != CanonTo.getLocalCVRQualifiers() @@ -1397,10 +1456,16 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, QualType FromPointeeType = FromTypePtr->getPointeeType(); + // If the unqualified pointee types are the same, this can't be a + // pointer conversion, so don't do all of the work below. + if (Context.hasSameUnqualifiedType(FromPointeeType, ToPointeeType)) + return false; + // An rvalue of type "pointer to cv T," where T is an object type, // can be converted to an rvalue of type "pointer to cv void" (C++ // 4.10p2). - if (FromPointeeType->isObjectType() && ToPointeeType->isVoidType()) { + if (FromPointeeType->isIncompleteOrObjectType() && + ToPointeeType->isVoidType()) { ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, ToPointeeType, ToType, Context); @@ -1657,8 +1722,8 @@ bool Sema::FunctionArgTypesAreEqual(FunctionProtoType* OldType, /// true. It returns true and produces a diagnostic if there was an /// error, or returns false otherwise. bool Sema::CheckPointerConversion(Expr *From, QualType ToType, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray& BasePath, + CastKind &Kind, + CXXCastPath& BasePath, bool IgnoreBaseAccess) { QualType FromType = From->getType(); @@ -1684,7 +1749,7 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, return true; // The conversion was successful. - Kind = CastExpr::CK_DerivedToBase; + Kind = CK_DerivedToBase; } } if (const ObjCObjectPointerType *FromPtrType = @@ -1749,8 +1814,8 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, /// true and produces a diagnostic if there was an error, or returns false /// otherwise. bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, - CastExpr::CastKind &Kind, - CXXBaseSpecifierArray &BasePath, + CastKind &Kind, + CXXCastPath &BasePath, bool IgnoreBaseAccess) { QualType FromType = From->getType(); const MemberPointerType *FromPtrType = FromType->getAs(); @@ -1759,7 +1824,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, assert(From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull) && "Expr must be null pointer constant!"); - Kind = CastExpr::CK_NullToMemberPointer; + Kind = CK_NullToMemberPointer; return false; } @@ -1803,7 +1868,7 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType, // Must be a base to derived member conversion. BuildBasePathArray(Paths, BasePath); - Kind = CastExpr::CK_BaseToDerivedMemberPointer; + Kind = CK_BaseToDerivedMemberPointer; return false; } @@ -1869,10 +1934,11 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) { /// \param AllowExplicit true if the conversion should consider C++0x /// "explicit" conversion functions as well as non-explicit conversion /// functions (C++0x [class.conv.fct]p2). -OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, - UserDefinedConversionSequence& User, - OverloadCandidateSet& CandidateSet, - bool AllowExplicit) { +static OverloadingResult +IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, + UserDefinedConversionSequence& User, + OverloadCandidateSet& CandidateSet, + bool AllowExplicit) { // Whether we will only visit constructors. bool ConstructorsOnly = false; @@ -1887,17 +1953,17 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, // functions are all the converting constructors (12.3.1) of // that class. The argument list is the expression-list within // the parentheses of the initializer. - if (Context.hasSameUnqualifiedType(ToType, From->getType()) || + if (S.Context.hasSameUnqualifiedType(ToType, From->getType()) || (From->getType()->getAs() && - IsDerivedFrom(From->getType(), ToType))) + S.IsDerivedFrom(From->getType(), ToType))) ConstructorsOnly = true; - if (RequireCompleteType(From->getLocStart(), ToType, PDiag())) { + if (S.RequireCompleteType(From->getLocStart(), ToType, S.PDiag())) { // We're not going to find any constructors. } else if (CXXRecordDecl *ToRecordDecl = dyn_cast(ToRecordType->getDecl())) { DeclContext::lookup_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = LookupConstructors(ToRecordDecl); + for (llvm::tie(Con, ConEnd) = S.LookupConstructors(ToRecordDecl); Con != ConEnd; ++Con) { NamedDecl *D = *Con; DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); @@ -1915,16 +1981,18 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, if (!Constructor->isInvalidDecl() && Constructor->isConvertingConstructor(AllowExplicit)) { if (ConstructorTmpl) - AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, - /*ExplicitArgs*/ 0, - &From, 1, CandidateSet, - /*SuppressUserConversions=*/!ConstructorsOnly); + S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, + /*ExplicitArgs*/ 0, + &From, 1, CandidateSet, + /*SuppressUserConversions=*/ + !ConstructorsOnly); else // Allow one user-defined conversion when user specifies a // From->ToType conversion via an static cast (c-style, etc). - AddOverloadCandidate(Constructor, FoundDecl, - &From, 1, CandidateSet, - /*SuppressUserConversions=*/!ConstructorsOnly); + S.AddOverloadCandidate(Constructor, FoundDecl, + &From, 1, CandidateSet, + /*SuppressUserConversions=*/ + !ConstructorsOnly); } } } @@ -1932,8 +2000,8 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, // Enumerate conversion functions, if we're allowed to. if (ConstructorsOnly) { - } else if (RequireCompleteType(From->getLocStart(), From->getType(), - PDiag(0) << From->getSourceRange())) { + } else if (S.RequireCompleteType(From->getLocStart(), From->getType(), + S.PDiag(0) << From->getSourceRange())) { // No conversion functions from incomplete types. } else if (const RecordType *FromRecordType = From->getType()->getAs()) { @@ -1959,80 +2027,79 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType, if (AllowExplicit || !Conv->isExplicit()) { if (ConvTemplate) - AddTemplateConversionCandidate(ConvTemplate, FoundDecl, - ActingContext, From, ToType, - CandidateSet); + S.AddTemplateConversionCandidate(ConvTemplate, FoundDecl, + ActingContext, From, ToType, + CandidateSet); else - AddConversionCandidate(Conv, FoundDecl, ActingContext, - From, ToType, CandidateSet); + S.AddConversionCandidate(Conv, FoundDecl, ActingContext, + From, ToType, CandidateSet); } } } } OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, From->getLocStart(), Best)) { - case OR_Success: - // Record the standard conversion we used and the conversion function. - if (CXXConstructorDecl *Constructor - = dyn_cast(Best->Function)) { - // C++ [over.ics.user]p1: - // If the user-defined conversion is specified by a - // constructor (12.3.1), the initial standard conversion - // sequence converts the source type to the type required by - // the argument of the constructor. - // - QualType ThisType = Constructor->getThisType(Context); - if (Best->Conversions[0].isEllipsis()) - User.EllipsisConversion = true; - else { - User.Before = Best->Conversions[0].Standard; - User.EllipsisConversion = false; - } - User.ConversionFunction = Constructor; - User.After.setAsIdentityConversion(); - User.After.setFromType( - ThisType->getAs()->getPointeeType()); - User.After.setAllToTypes(ToType); - return OR_Success; - } else if (CXXConversionDecl *Conversion - = dyn_cast(Best->Function)) { - // C++ [over.ics.user]p1: - // - // [...] If the user-defined conversion is specified by a - // conversion function (12.3.2), the initial standard - // conversion sequence converts the source type to the - // implicit object parameter of the conversion function. + switch (CandidateSet.BestViableFunction(S, From->getLocStart(), Best)) { + case OR_Success: + // Record the standard conversion we used and the conversion function. + if (CXXConstructorDecl *Constructor + = dyn_cast(Best->Function)) { + // C++ [over.ics.user]p1: + // If the user-defined conversion is specified by a + // constructor (12.3.1), the initial standard conversion + // sequence converts the source type to the type required by + // the argument of the constructor. + // + QualType ThisType = Constructor->getThisType(S.Context); + if (Best->Conversions[0].isEllipsis()) + User.EllipsisConversion = true; + else { User.Before = Best->Conversions[0].Standard; - User.ConversionFunction = Conversion; User.EllipsisConversion = false; - - // C++ [over.ics.user]p2: - // The second standard conversion sequence converts the - // result of the user-defined conversion to the target type - // for the sequence. Since an implicit conversion sequence - // is an initialization, the special rules for - // initialization by user-defined conversion apply when - // selecting the best user-defined conversion for a - // user-defined conversion sequence (see 13.3.3 and - // 13.3.3.1). - User.After = Best->FinalConversion; - return OR_Success; - } else { - assert(false && "Not a constructor or conversion function?"); - return OR_No_Viable_Function; } - - case OR_No_Viable_Function: + User.ConversionFunction = Constructor; + User.After.setAsIdentityConversion(); + User.After.setFromType(ThisType->getAs()->getPointeeType()); + User.After.setAllToTypes(ToType); + return OR_Success; + } else if (CXXConversionDecl *Conversion + = dyn_cast(Best->Function)) { + // C++ [over.ics.user]p1: + // + // [...] If the user-defined conversion is specified by a + // conversion function (12.3.2), the initial standard + // conversion sequence converts the source type to the + // implicit object parameter of the conversion function. + User.Before = Best->Conversions[0].Standard; + User.ConversionFunction = Conversion; + User.EllipsisConversion = false; + + // C++ [over.ics.user]p2: + // The second standard conversion sequence converts the + // result of the user-defined conversion to the target type + // for the sequence. Since an implicit conversion sequence + // is an initialization, the special rules for + // initialization by user-defined conversion apply when + // selecting the best user-defined conversion for a + // user-defined conversion sequence (see 13.3.3 and + // 13.3.3.1). + User.After = Best->FinalConversion; + return OR_Success; + } else { + llvm_unreachable("Not a constructor or conversion function?"); return OR_No_Viable_Function; - case OR_Deleted: - // No conversion here! We're done. - return OR_Deleted; - - case OR_Ambiguous: - return OR_Ambiguous; } + case OR_No_Viable_Function: + return OR_No_Viable_Function; + case OR_Deleted: + // No conversion here! We're done. + return OR_Deleted; + + case OR_Ambiguous: + return OR_Ambiguous; + } + return OR_No_Viable_Function; } @@ -2041,7 +2108,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { ImplicitConversionSequence ICS; OverloadCandidateSet CandidateSet(From->getExprLoc()); OverloadingResult OvResult = - IsUserDefinedConversion(From, ToType, ICS.UserDefined, + IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined, CandidateSet, false); if (OvResult == OR_Ambiguous) Diag(From->getSourceRange().getBegin(), @@ -2053,16 +2120,17 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { << From->getType() << ToType << From->getSourceRange(); else return false; - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &From, 1); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, &From, 1); return true; } /// CompareImplicitConversionSequences - Compare two implicit /// conversion sequences to determine whether one is better than the /// other or if they are indistinguishable (C++ 13.3.3.2). -ImplicitConversionSequence::CompareKind -Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, - const ImplicitConversionSequence& ICS2) +static ImplicitConversionSequence::CompareKind +CompareImplicitConversionSequences(Sema &S, + const ImplicitConversionSequence& ICS1, + const ImplicitConversionSequence& ICS2) { // (C++ 13.3.3.2p2): When comparing the basic forms of implicit // conversion sequences (as defined in 13.3.3.1) @@ -2092,7 +2160,7 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, // indistinguishable conversion sequences unless one of the // following rules apply: (C++ 13.3.3.2p3): if (ICS1.isStandard()) - return CompareStandardConversionSequences(ICS1.Standard, ICS2.Standard); + return CompareStandardConversionSequences(S, ICS1.Standard, ICS2.Standard); else if (ICS1.isUserDefined()) { // User-defined conversion sequence U1 is a better conversion // sequence than another user-defined conversion sequence U2 if @@ -2102,7 +2170,8 @@ Sema::CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1, // U2 (C++ 13.3.3.2p3). if (ICS1.UserDefined.ConversionFunction == ICS2.UserDefined.ConversionFunction) - return CompareStandardConversionSequences(ICS1.UserDefined.After, + return CompareStandardConversionSequences(S, + ICS1.UserDefined.After, ICS2.UserDefined.After); } @@ -2168,9 +2237,10 @@ compareStandardConversionSubsets(ASTContext &Context, /// CompareStandardConversionSequences - Compare two standard /// conversion sequences to determine whether one is better than the /// other or if they are indistinguishable (C++ 13.3.3.2p3). -ImplicitConversionSequence::CompareKind -Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, - const StandardConversionSequence& SCS2) +static ImplicitConversionSequence::CompareKind +CompareStandardConversionSequences(Sema &S, + const StandardConversionSequence& SCS1, + const StandardConversionSequence& SCS2) { // Standard conversion sequence S1 is a better conversion sequence // than standard conversion sequence S2 if (C++ 13.3.3.2p3): @@ -2181,7 +2251,7 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // sequence is considered to be a subsequence of any // non-identity conversion sequence) or, if not that, if (ImplicitConversionSequence::CompareKind CK - = compareStandardConversionSubsets(Context, SCS1, SCS2)) + = compareStandardConversionSubsets(S.Context, SCS1, SCS2)) return CK; // -- the rank of S1 is better than the rank of S2 (by the rules @@ -2212,9 +2282,9 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // void*, and conversion of A* to void* is better than conversion // of B* to void*. bool SCS1ConvertsToVoid - = SCS1.isPointerConversionToVoidPointer(Context); + = SCS1.isPointerConversionToVoidPointer(S.Context); bool SCS2ConvertsToVoid - = SCS2.isPointerConversionToVoidPointer(Context); + = SCS2.isPointerConversionToVoidPointer(S.Context); if (SCS1ConvertsToVoid != SCS2ConvertsToVoid) { // Exactly one of the conversion sequences is a conversion to // a void pointer; it's the worse conversion. @@ -2224,7 +2294,7 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // Neither conversion sequence converts to a void pointer; compare // their derived-to-base conversions. if (ImplicitConversionSequence::CompareKind DerivedCK - = CompareDerivedToBaseConversions(SCS1, SCS2)) + = CompareDerivedToBaseConversions(S, SCS1, SCS2)) return DerivedCK; } else if (SCS1ConvertsToVoid && SCS2ConvertsToVoid) { // Both conversion sequences are conversions to void @@ -2236,18 +2306,18 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // Adjust the types we're converting from via the array-to-pointer // conversion, if we need to. if (SCS1.First == ICK_Array_To_Pointer) - FromType1 = Context.getArrayDecayedType(FromType1); + FromType1 = S.Context.getArrayDecayedType(FromType1); if (SCS2.First == ICK_Array_To_Pointer) - FromType2 = Context.getArrayDecayedType(FromType2); + FromType2 = S.Context.getArrayDecayedType(FromType2); QualType FromPointee1 = FromType1->getAs()->getPointeeType().getUnqualifiedType(); QualType FromPointee2 = FromType2->getAs()->getPointeeType().getUnqualifiedType(); - if (IsDerivedFrom(FromPointee2, FromPointee1)) + if (S.IsDerivedFrom(FromPointee2, FromPointee1)) return ImplicitConversionSequence::Better; - else if (IsDerivedFrom(FromPointee1, FromPointee2)) + else if (S.IsDerivedFrom(FromPointee1, FromPointee2)) return ImplicitConversionSequence::Worse; // Objective-C++: If one interface is more specific than the @@ -2255,9 +2325,9 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, const ObjCObjectType* FromIface1 = FromPointee1->getAs(); const ObjCObjectType* FromIface2 = FromPointee2->getAs(); if (FromIface1 && FromIface1) { - if (Context.canAssignObjCInterfaces(FromIface2, FromIface1)) + if (S.Context.canAssignObjCInterfaces(FromIface2, FromIface1)) return ImplicitConversionSequence::Better; - else if (Context.canAssignObjCInterfaces(FromIface1, FromIface2)) + else if (S.Context.canAssignObjCInterfaces(FromIface1, FromIface2)) return ImplicitConversionSequence::Worse; } } @@ -2265,7 +2335,7 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // Compare based on qualification conversions (C++ 13.3.3.2p3, // bullet 3). if (ImplicitConversionSequence::CompareKind QualCK - = CompareQualificationConversions(SCS1, SCS2)) + = CompareQualificationConversions(S, SCS1, SCS2)) return QualCK; if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) { @@ -2289,18 +2359,18 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, // to which the reference initialized by S1 refers. QualType T1 = SCS1.getToType(2); QualType T2 = SCS2.getToType(2); - T1 = Context.getCanonicalType(T1); - T2 = Context.getCanonicalType(T2); + T1 = S.Context.getCanonicalType(T1); + T2 = S.Context.getCanonicalType(T2); Qualifiers T1Quals, T2Quals; - QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals); - QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals); + QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals); + QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals); if (UnqualT1 == UnqualT2) { // If the type is an array type, promote the element qualifiers to the type // for comparison. if (isa(T1) && T1Quals) - T1 = Context.getQualifiedType(UnqualT1, T1Quals); + T1 = S.Context.getQualifiedType(UnqualT1, T1Quals); if (isa(T2) && T2Quals) - T2 = Context.getQualifiedType(UnqualT2, T2Quals); + T2 = S.Context.getQualifiedType(UnqualT2, T2Quals); if (T2.isMoreQualifiedThan(T1)) return ImplicitConversionSequence::Better; else if (T1.isMoreQualifiedThan(T2)) @@ -2315,8 +2385,9 @@ Sema::CompareStandardConversionSequences(const StandardConversionSequence& SCS1, /// sequences to determine whether they can be ranked based on their /// qualification conversions (C++ 13.3.3.2p3 bullet 3). ImplicitConversionSequence::CompareKind -Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, - const StandardConversionSequence& SCS2) { +CompareQualificationConversions(Sema &S, + const StandardConversionSequence& SCS1, + const StandardConversionSequence& SCS2) { // C++ 13.3.3.2p3: // -- S1 and S2 differ only in their qualification conversion and // yield similar types T1 and T2 (C++ 4.4), respectively, and the @@ -2331,11 +2402,11 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, // conversion (!) QualType T1 = SCS1.getToType(2); QualType T2 = SCS2.getToType(2); - T1 = Context.getCanonicalType(T1); - T2 = Context.getCanonicalType(T2); + T1 = S.Context.getCanonicalType(T1); + T2 = S.Context.getCanonicalType(T2); Qualifiers T1Quals, T2Quals; - QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals); - QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals); + QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals); + QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals); // If the types are the same, we won't learn anything by unwrapped // them. @@ -2345,13 +2416,13 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, // If the type is an array type, promote the element qualifiers to the type // for comparison. if (isa(T1) && T1Quals) - T1 = Context.getQualifiedType(UnqualT1, T1Quals); + T1 = S.Context.getQualifiedType(UnqualT1, T1Quals); if (isa(T2) && T2Quals) - T2 = Context.getQualifiedType(UnqualT2, T2Quals); + T2 = S.Context.getQualifiedType(UnqualT2, T2Quals); ImplicitConversionSequence::CompareKind Result = ImplicitConversionSequence::Indistinguishable; - while (Context.UnwrapSimilarPointerTypes(T1, T2)) { + while (S.Context.UnwrapSimilarPointerTypes(T1, T2)) { // Within each iteration of the loop, we check the qualifiers to // determine if this still looks like a qualification // conversion. Then, if all is well, we unwrap one more level of @@ -2386,7 +2457,7 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, } // If the types after this point are equivalent, we're done. - if (Context.hasSameUnqualifiedType(T1, T2)) + if (S.Context.hasSameUnqualifiedType(T1, T2)) break; } @@ -2416,8 +2487,9 @@ Sema::CompareQualificationConversions(const StandardConversionSequence& SCS1, /// [over.ics.rank]p4b3). As part of these checks, we also look at /// conversions between Objective-C interface types. ImplicitConversionSequence::CompareKind -Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, - const StandardConversionSequence& SCS2) { +CompareDerivedToBaseConversions(Sema &S, + const StandardConversionSequence& SCS1, + const StandardConversionSequence& SCS2) { QualType FromType1 = SCS1.getFromType(); QualType ToType1 = SCS1.getToType(1); QualType FromType2 = SCS2.getFromType(); @@ -2426,15 +2498,15 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, // Adjust the types we're converting from via the array-to-pointer // conversion, if we need to. if (SCS1.First == ICK_Array_To_Pointer) - FromType1 = Context.getArrayDecayedType(FromType1); + FromType1 = S.Context.getArrayDecayedType(FromType1); if (SCS2.First == ICK_Array_To_Pointer) - FromType2 = Context.getArrayDecayedType(FromType2); + FromType2 = S.Context.getArrayDecayedType(FromType2); // Canonicalize all of the types. - FromType1 = Context.getCanonicalType(FromType1); - ToType1 = Context.getCanonicalType(ToType1); - FromType2 = Context.getCanonicalType(FromType2); - ToType2 = Context.getCanonicalType(ToType2); + FromType1 = S.Context.getCanonicalType(FromType1); + ToType1 = S.Context.getCanonicalType(ToType1); + FromType2 = S.Context.getCanonicalType(FromType2); + ToType2 = S.Context.getCanonicalType(ToType2); // C++ [over.ics.rank]p4b3: // @@ -2466,30 +2538,30 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, // -- conversion of C* to B* is better than conversion of C* to A*, if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) { - if (IsDerivedFrom(ToPointee1, ToPointee2)) + if (S.IsDerivedFrom(ToPointee1, ToPointee2)) return ImplicitConversionSequence::Better; - else if (IsDerivedFrom(ToPointee2, ToPointee1)) + else if (S.IsDerivedFrom(ToPointee2, ToPointee1)) return ImplicitConversionSequence::Worse; if (ToIface1 && ToIface2) { - if (Context.canAssignObjCInterfaces(ToIface2, ToIface1)) + if (S.Context.canAssignObjCInterfaces(ToIface2, ToIface1)) return ImplicitConversionSequence::Better; - else if (Context.canAssignObjCInterfaces(ToIface1, ToIface2)) + else if (S.Context.canAssignObjCInterfaces(ToIface1, ToIface2)) return ImplicitConversionSequence::Worse; } } // -- conversion of B* to A* is better than conversion of C* to A*, if (FromPointee1 != FromPointee2 && ToPointee1 == ToPointee2) { - if (IsDerivedFrom(FromPointee2, FromPointee1)) + if (S.IsDerivedFrom(FromPointee2, FromPointee1)) return ImplicitConversionSequence::Better; - else if (IsDerivedFrom(FromPointee1, FromPointee2)) + else if (S.IsDerivedFrom(FromPointee1, FromPointee2)) return ImplicitConversionSequence::Worse; if (FromIface1 && FromIface2) { - if (Context.canAssignObjCInterfaces(FromIface1, FromIface2)) + if (S.Context.canAssignObjCInterfaces(FromIface1, FromIface2)) return ImplicitConversionSequence::Better; - else if (Context.canAssignObjCInterfaces(FromIface2, FromIface1)) + else if (S.Context.canAssignObjCInterfaces(FromIface2, FromIface1)) return ImplicitConversionSequence::Worse; } } @@ -2517,16 +2589,16 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, QualType ToPointee2 = QualType(ToPointeeType2, 0).getUnqualifiedType(); // conversion of A::* to B::* is better than conversion of A::* to C::*, if (FromPointee1 == FromPointee2 && ToPointee1 != ToPointee2) { - if (IsDerivedFrom(ToPointee1, ToPointee2)) + if (S.IsDerivedFrom(ToPointee1, ToPointee2)) return ImplicitConversionSequence::Worse; - else if (IsDerivedFrom(ToPointee2, ToPointee1)) + else if (S.IsDerivedFrom(ToPointee2, ToPointee1)) return ImplicitConversionSequence::Better; } // conversion of B::* to C::* is better than conversion of A::* to C::* if (ToPointee1 == ToPointee2 && FromPointee1 != FromPointee2) { - if (IsDerivedFrom(FromPointee1, FromPointee2)) + if (S.IsDerivedFrom(FromPointee1, FromPointee2)) return ImplicitConversionSequence::Better; - else if (IsDerivedFrom(FromPointee2, FromPointee1)) + else if (S.IsDerivedFrom(FromPointee2, FromPointee1)) return ImplicitConversionSequence::Worse; } } @@ -2536,11 +2608,11 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, // -- binding of an expression of type C to a reference of type // B& is better than binding an expression of type C to a // reference of type A&, - if (Context.hasSameUnqualifiedType(FromType1, FromType2) && - !Context.hasSameUnqualifiedType(ToType1, ToType2)) { - if (IsDerivedFrom(ToType1, ToType2)) + if (S.Context.hasSameUnqualifiedType(FromType1, FromType2) && + !S.Context.hasSameUnqualifiedType(ToType1, ToType2)) { + if (S.IsDerivedFrom(ToType1, ToType2)) return ImplicitConversionSequence::Better; - else if (IsDerivedFrom(ToType2, ToType1)) + else if (S.IsDerivedFrom(ToType2, ToType1)) return ImplicitConversionSequence::Worse; } @@ -2548,11 +2620,11 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, // -- binding of an expression of type B to a reference of type // A& is better than binding an expression of type C to a // reference of type A&, - if (!Context.hasSameUnqualifiedType(FromType1, FromType2) && - Context.hasSameUnqualifiedType(ToType1, ToType2)) { - if (IsDerivedFrom(FromType2, FromType1)) + if (!S.Context.hasSameUnqualifiedType(FromType1, FromType2) && + S.Context.hasSameUnqualifiedType(ToType1, ToType2)) { + if (S.IsDerivedFrom(FromType2, FromType1)) return ImplicitConversionSequence::Better; - else if (IsDerivedFrom(FromType1, FromType2)) + else if (S.IsDerivedFrom(FromType1, FromType2)) return ImplicitConversionSequence::Worse; } } @@ -2570,7 +2642,8 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1, Sema::ReferenceCompareResult Sema::CompareReferenceRelationship(SourceLocation Loc, QualType OrigT1, QualType OrigT2, - bool& DerivedToBase) { + bool &DerivedToBase, + bool &ObjCConversion) { assert(!OrigT1->isReferenceType() && "T1 must be the pointee type of the reference type"); assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type"); @@ -2585,11 +2658,17 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is // reference-related to "cv2 T2" if T1 is the same type as T2, or // T1 is a base class of T2. - if (UnqualT1 == UnqualT2) - DerivedToBase = false; - else if (!RequireCompleteType(Loc, OrigT2, PDiag()) && + DerivedToBase = false; + ObjCConversion = false; + if (UnqualT1 == UnqualT2) { + // Nothing to do. + } else if (!RequireCompleteType(Loc, OrigT2, PDiag()) && IsDerivedFrom(UnqualT2, UnqualT1)) DerivedToBase = true; + else if (UnqualT1->isObjCObjectOrInterfaceType() && + UnqualT2->isObjCObjectOrInterfaceType() && + Context.canBindObjCObjectType(UnqualT1, UnqualT2)) + ObjCConversion = true; else return Ref_Incompatible; @@ -2618,16 +2697,21 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, return Ref_Related; } -/// \brief Look for a user-defined conversion to an lvalue reference-compatible +/// \brief Look for a user-defined conversion to an value reference-compatible /// with DeclType. Return true if something definite is found. static bool -FindConversionToLValue(Sema &S, ImplicitConversionSequence &ICS, - QualType DeclType, SourceLocation DeclLoc, - Expr *Init, QualType T2, bool AllowExplicit) { +FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, + QualType DeclType, SourceLocation DeclLoc, + Expr *Init, QualType T2, bool AllowRvalues, + bool AllowExplicit) { assert(T2->isRecordType() && "Can only find conversions of record types."); CXXRecordDecl *T2RecordDecl = dyn_cast(T2->getAs()->getDecl()); + QualType ToType + = AllowRvalues? DeclType->getAs()->getPointeeType() + : DeclType; + OverloadCandidateSet CandidateSet(DeclLoc); const UnresolvedSetImpl *Conversions = T2RecordDecl->getVisibleConversionFunctions(); @@ -2646,25 +2730,44 @@ FindConversionToLValue(Sema &S, ImplicitConversionSequence &ICS, else Conv = cast(D); - // If the conversion function doesn't return a reference type, - // it can't be considered for this conversion. An rvalue reference - // is only acceptable if its referencee is a function type. - const ReferenceType *RefType = - Conv->getConversionType()->getAs(); - if (RefType && (RefType->isLValueReferenceType() || - RefType->getPointeeType()->isFunctionType()) && - (AllowExplicit || !Conv->isExplicit())) { - if (ConvTemplate) - S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, - Init, DeclType, CandidateSet); - else - S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, - DeclType, CandidateSet); + // If this is an explicit conversion, and we're not allowed to consider + // explicit conversions, skip it. + if (!AllowExplicit && Conv->isExplicit()) + continue; + + if (AllowRvalues) { + bool DerivedToBase = false; + bool ObjCConversion = false; + if (!ConvTemplate && + S.CompareReferenceRelationship(DeclLoc, + Conv->getConversionType().getNonReferenceType().getUnqualifiedType(), + DeclType.getNonReferenceType().getUnqualifiedType(), + DerivedToBase, ObjCConversion) + == Sema::Ref_Incompatible) + continue; + } else { + // If the conversion function doesn't return a reference type, + // it can't be considered for this conversion. An rvalue reference + // is only acceptable if its referencee is a function type. + + const ReferenceType *RefType = + Conv->getConversionType()->getAs(); + if (!RefType || + (!RefType->isLValueReferenceType() && + !RefType->getPointeeType()->isFunctionType())) + continue; } + + if (ConvTemplate) + S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC, + Init, ToType, CandidateSet); + else + S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init, + ToType, CandidateSet); } OverloadCandidateSet::iterator Best; - switch (S.BestViableFunction(CandidateSet, DeclLoc, Best)) { + switch (CandidateSet.BestViableFunction(S, DeclLoc, Best)) { case OR_Success: // C++ [over.ics.ref]p1: // @@ -2736,9 +2839,11 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // Compute some basic properties of the types and the initializer. bool isRValRef = DeclType->isRValueReferenceType(); bool DerivedToBase = false; + bool ObjCConversion = false; Expr::Classification InitCategory = Init->Classify(S.Context); Sema::ReferenceCompareResult RefRelationship - = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); + = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase, + ObjCConversion); // C++0x [dcl.init.ref]p5: @@ -2764,7 +2869,9 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // derived-to-base Conversion (13.3.3.1). ICS.setStandard(); ICS.Standard.First = ICK_Identity; - ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; + ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base + : ObjCConversion? ICK_Compatible_Conversion + : ICK_Identity; ICS.Standard.Third = ICK_Identity; ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); ICS.Standard.setToType(0, T2); @@ -2792,8 +2899,9 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, if (!SuppressUserConversions && T2->isRecordType() && !S.RequireCompleteType(DeclLoc, T2, 0) && RefRelationship == Sema::Ref_Incompatible) { - if (FindConversionToLValue(S, ICS, DeclType, DeclLoc, - Init, T2, AllowExplicit)) + if (FindConversionForRefInit(S, ICS, DeclType, DeclLoc, + Init, T2, /*AllowRvalues=*/false, + AllowExplicit)) return ICS; } } @@ -2845,26 +2953,37 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // that is the result of the conversion in the second case // (or, in either case, to the appropriate base class // subobject of the object). - // - // We're only checking the first case here, which is a direct - // binding in C++0x but not in C++03. - if (InitCategory.isRValue() && T2->isRecordType() && - RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { - ICS.setStandard(); - ICS.Standard.First = ICK_Identity; - ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; - ICS.Standard.Third = ICK_Identity; - ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS.Standard.setToType(0, T2); - ICS.Standard.setToType(1, T1); - ICS.Standard.setToType(2, T1); - ICS.Standard.ReferenceBinding = true; - ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x; - ICS.Standard.RRefBinding = isRValRef; - ICS.Standard.CopyConstructor = 0; - return ICS; + if (T2->isRecordType()) { + // First case: "cv1 T1" is reference-compatible with "cv2 T2". This is a + // direct binding in C++0x but not in C++03. + if (InitCategory.isRValue() && + RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + ICS.setStandard(); + ICS.Standard.First = ICK_Identity; + ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base + : ObjCConversion? ICK_Compatible_Conversion + : ICK_Identity; + ICS.Standard.Third = ICK_Identity; + ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); + ICS.Standard.setToType(0, T2); + ICS.Standard.setToType(1, T1); + ICS.Standard.setToType(2, T1); + ICS.Standard.ReferenceBinding = true; + ICS.Standard.DirectBinding = S.getLangOptions().CPlusPlus0x; + ICS.Standard.RRefBinding = isRValRef; + ICS.Standard.CopyConstructor = 0; + return ICS; + } + + // Second case: not reference-related. + if (RefRelationship == Sema::Ref_Incompatible && + !S.RequireCompleteType(DeclLoc, T2, 0) && + FindConversionForRefInit(S, ICS, DeclType, DeclLoc, + Init, T2, /*AllowRvalues=*/true, + AllowExplicit)) + return ICS; } - + // -- Otherwise, a temporary of type "cv1 T1" is created and // initialized from the initializer expression using the // rules for a non-reference copy initialization (8.5). The @@ -2899,9 +3018,9 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType, // the argument expression. Any difference in top-level // cv-qualification is subsumed by the initialization itself // and does not constitute a conversion. - ICS = S.TryImplicitConversion(Init, T1, SuppressUserConversions, - /*AllowExplicit=*/false, - /*InOverloadResolution=*/false); + ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions, + /*AllowExplicit=*/false, + /*InOverloadResolution=*/false); // Of course, that's still a reference binding. if (ICS.isStandard()) { @@ -2930,25 +3049,25 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType, SuppressUserConversions, /*AllowExplicit=*/false); - return S.TryImplicitConversion(From, ToType, - SuppressUserConversions, - /*AllowExplicit=*/false, - InOverloadResolution); + return TryImplicitConversion(S, From, ToType, + SuppressUserConversions, + /*AllowExplicit=*/false, + InOverloadResolution); } /// TryObjectArgumentInitialization - Try to initialize the object /// parameter of the given member function (@c Method) from the /// expression @p From. -ImplicitConversionSequence -Sema::TryObjectArgumentInitialization(QualType OrigFromType, - CXXMethodDecl *Method, - CXXRecordDecl *ActingContext) { - QualType ClassType = Context.getTypeDeclType(ActingContext); +static ImplicitConversionSequence +TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, + CXXMethodDecl *Method, + CXXRecordDecl *ActingContext) { + QualType ClassType = S.Context.getTypeDeclType(ActingContext); // [class.dtor]p2: A destructor can be invoked for a const, volatile or // const volatile object. unsigned Quals = isa(Method) ? Qualifiers::Const | Qualifiers::Volatile : Method->getTypeQualifiers(); - QualType ImplicitParamType = Context.getCVRQualifiedType(ClassType, Quals); + QualType ImplicitParamType = S.Context.getCVRQualifiedType(ClassType, Quals); // Set up the conversion sequence as a "bad" conversion, to allow us // to exit early. @@ -2972,7 +3091,7 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType, // First check the qualifiers. We don't care about lvalue-vs-rvalue // with the implicit object parameter (C++ [over.match.funcs]p5). - QualType FromTypeCanon = Context.getCanonicalType(FromType); + QualType FromTypeCanon = S.Context.getCanonicalType(FromType); if (ImplicitParamType.getCVRQualifiers() != FromTypeCanon.getLocalCVRQualifiers() && !ImplicitParamType.isAtLeastAsQualifiedAs(FromTypeCanon)) { @@ -2983,11 +3102,11 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType, // Check that we have either the same type or a derived type. It // affects the conversion rank. - QualType ClassTypeCanon = Context.getCanonicalType(ClassType); + QualType ClassTypeCanon = S.Context.getCanonicalType(ClassType); ImplicitConversionKind SecondKind; if (ClassTypeCanon == FromTypeCanon.getLocalUnqualifiedType()) { SecondKind = ICK_Identity; - } else if (IsDerivedFrom(FromType, ClassType)) + } else if (S.IsDerivedFrom(FromType, ClassType)) SecondKind = ICK_Derived_To_Base; else { ICS.setBad(BadConversionSequence::unrelated_class, @@ -3030,7 +3149,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, // Note that we always use the true parent context when performing // the actual argument initialization. ImplicitConversionSequence ICS - = TryObjectArgumentInitialization(From->getType(), Method, + = TryObjectArgumentInitialization(*this, From->getType(), Method, Method->getParent()); if (ICS.isBad()) return Diag(From->getSourceRange().getBegin(), @@ -3041,16 +3160,17 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, return PerformObjectMemberConversion(From, Qualifier, FoundDecl, Method); if (!Context.hasSameType(From->getType(), DestType)) - ImpCastExprToType(From, DestType, CastExpr::CK_NoOp, - /*isLvalue=*/!From->getType()->isPointerType()); + ImpCastExprToType(From, DestType, CK_NoOp, + From->getType()->isPointerType() ? VK_RValue : VK_LValue); return false; } /// TryContextuallyConvertToBool - Attempt to contextually convert the /// expression From to bool (C++0x [conv]p3). -ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) { +static ImplicitConversionSequence +TryContextuallyConvertToBool(Sema &S, Expr *From) { // FIXME: This is pretty broken. - return TryImplicitConversion(From, Context.BoolTy, + return TryImplicitConversion(S, From, S.Context.BoolTy, // FIXME: Are these flags correct? /*SuppressUserConversions=*/false, /*AllowExplicit=*/true, @@ -3060,7 +3180,7 @@ ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) { /// PerformContextuallyConvertToBool - Perform a contextual conversion /// of the expression From to bool (C++0x [conv]p3). bool Sema::PerformContextuallyConvertToBool(Expr *&From) { - ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From); + ImplicitConversionSequence ICS = TryContextuallyConvertToBool(*this, From); if (!ICS.isBad()) return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting); @@ -3073,20 +3193,21 @@ bool Sema::PerformContextuallyConvertToBool(Expr *&From) { /// TryContextuallyConvertToObjCId - Attempt to contextually convert the /// expression From to 'id'. -ImplicitConversionSequence Sema::TryContextuallyConvertToObjCId(Expr *From) { - QualType Ty = Context.getObjCIdType(); - return TryImplicitConversion(From, Ty, - // FIXME: Are these flags correct? - /*SuppressUserConversions=*/false, - /*AllowExplicit=*/true, - /*InOverloadResolution=*/false); +static ImplicitConversionSequence +TryContextuallyConvertToObjCId(Sema &S, Expr *From) { + QualType Ty = S.Context.getObjCIdType(); + return TryImplicitConversion(S, From, Ty, + // FIXME: Are these flags correct? + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/true, + /*InOverloadResolution=*/false); } - + /// PerformContextuallyConvertToObjCId - Perform a contextual conversion /// of the expression From to 'id'. bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) { QualType Ty = Context.getObjCIdType(); - ImplicitConversionSequence ICS = TryContextuallyConvertToObjCId(From); + ImplicitConversionSequence ICS = TryContextuallyConvertToObjCId(*this, From); if (!ICS.isBad()) return PerformImplicitConversion(From, Ty, ICS, AA_Converting); return true; @@ -3128,8 +3249,8 @@ bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) { /// /// \returns The expression, converted to an integral or enumeration type if /// successful. -Sema::OwningExprResult -Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, ExprArg FromE, +ExprResult +Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *From, const PartialDiagnostic &NotIntDiag, const PartialDiagnostic &IncompleteDiag, const PartialDiagnostic &ExplicitConvDiag, @@ -3137,16 +3258,14 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, ExprArg FromE, const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &AmbigNote, const PartialDiagnostic &ConvDiag) { - Expr *From = static_cast(FromE.get()); - // We can't perform any more checking for type-dependent expressions. if (From->isTypeDependent()) - return move(FromE); + return Owned(From); // If the expression already has integral or enumeration type, we're golden. QualType T = From->getType(); if (T->isIntegralOrEnumerationType()) - return move(FromE); + return Owned(From); // FIXME: Check for missing '()' if T is a function type? @@ -3156,12 +3275,12 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, ExprArg FromE, if (!RecordTy || !getLangOptions().CPlusPlus) { Diag(Loc, NotIntDiag) << T << From->getSourceRange(); - return move(FromE); + return Owned(From); } // We must have a complete class type. if (RequireCompleteType(Loc, T, IncompleteDiag)) - return move(FromE); + return Owned(From); // Look for a conversion to an integral or enumeration type. UnresolvedSet<4> ViableConversions; @@ -3213,8 +3332,7 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, ExprArg FromE, return ExprError(); CheckMemberOperatorAccess(From->getExprLoc(), From, 0, Found); - From = BuildCXXMemberCallExpr(FromE.takeAs(), Found, Conversion); - FromE = Owned(From); + From = BuildCXXMemberCallExpr(From, Found, Conversion); } // We'll complain below about a non-integral condition type. @@ -3237,9 +3355,8 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, ExprArg FromE, << T << ConvTy->isEnumeralType() << ConvTy << From->getSourceRange(); } - From = BuildCXXMemberCallExpr(FromE.takeAs(), Found, + From = BuildCXXMemberCallExpr(From, Found, cast(Found->getUnderlyingDecl())); - FromE = Owned(From); break; } @@ -3253,14 +3370,14 @@ Sema::ConvertToIntegralOrEnumerationType(SourceLocation Loc, ExprArg FromE, Diag(Conv->getLocation(), AmbigNote) << ConvTy->isEnumeralType() << ConvTy; } - return move(FromE); + return Owned(From); } if (!From->getType()->isIntegralOrEnumerationType()) Diag(Loc, NotIntDiag) << From->getType() << From->getSourceRange(); - return move(FromE); + return Owned(From); } /// AddOverloadCandidate - Adds the given function to the set of @@ -3306,7 +3423,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, return; // Overload resolution is always an unevaluated context. - EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated); + EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); if (CXXConstructorDecl *Constructor = dyn_cast(Function)){ // C++ [class.copy]p3: @@ -3469,7 +3586,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, return; // Overload resolution is always an unevaluated context. - EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated); + EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); // Add this candidate CandidateSet.push_back(OverloadCandidate()); @@ -3513,7 +3630,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // Determine the implicit conversion sequence for the object // parameter. Candidate.Conversions[0] - = TryObjectArgumentInitialization(ObjectType, Method, ActingContext); + = TryObjectArgumentInitialization(*this, ObjectType, Method, + ActingContext); if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; @@ -3666,7 +3784,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, return; // Overload resolution is always an unevaluated context. - EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated); + EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); // Add this candidate CandidateSet.push_back(OverloadCandidate()); @@ -3678,25 +3796,32 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, Candidate.FinalConversion.setAsIdentityConversion(); Candidate.FinalConversion.setFromType(ConvType); Candidate.FinalConversion.setAllToTypes(ToType); + Candidate.Viable = true; + Candidate.Conversions.resize(1); + // C++ [over.match.funcs]p4: + // For conversion functions, the function is considered to be a member of + // the class of the implicit implied object argument for the purpose of + // defining the type of the implicit object parameter. + // // Determine the implicit conversion sequence for the implicit // object parameter. - Candidate.Viable = true; - Candidate.Conversions.resize(1); + QualType ImplicitParamType = From->getType(); + if (const PointerType *FromPtrType = ImplicitParamType->getAs()) + ImplicitParamType = FromPtrType->getPointeeType(); + CXXRecordDecl *ConversionContext + = cast(ImplicitParamType->getAs()->getDecl()); + Candidate.Conversions[0] - = TryObjectArgumentInitialization(From->getType(), Conversion, - ActingContext); - // Conversion functions to a different type in the base class is visible in - // the derived class. So, a derived to base conversion should not participate - // in overload resolution. - if (Candidate.Conversions[0].Standard.Second == ICK_Derived_To_Base) - Candidate.Conversions[0].Standard.Second = ICK_Identity; + = TryObjectArgumentInitialization(*this, From->getType(), Conversion, + ConversionContext); + if (Candidate.Conversions[0].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; return; } - + // We won't go through a user-define type conversion function to convert a // derived to base as such conversions are given Conversion Rank. They only // go through a copy constructor. 13.3.3.1.2-p4 [over.ics.user] @@ -3719,9 +3844,10 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // well-formed. DeclRefExpr ConversionRef(Conversion, Conversion->getType(), From->getLocStart()); - ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()), - CastExpr::CK_FunctionToPointerDecay, - &ConversionRef, CXXBaseSpecifierArray(), false); + ImplicitCastExpr ConversionFn(ImplicitCastExpr::OnStack, + Context.getPointerType(Conversion->getType()), + CK_FunctionToPointerDecay, + &ConversionRef, VK_RValue); // Note that it is safe to allocate CallExpr on the stack here because // there are 0 arguments (i.e., nothing is allocated using ASTContext's @@ -3819,7 +3945,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, return; // Overload resolution is always an unevaluated context. - EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated); + EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); CandidateSet.push_back(OverloadCandidate()); OverloadCandidate& Candidate = CandidateSet.back(); @@ -3834,7 +3960,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, // Determine the implicit conversion sequence for the implicit // object parameter. ImplicitConversionSequence ObjectInit - = TryObjectArgumentInitialization(ObjectType, Conversion, ActingContext); + = TryObjectArgumentInitialization(*this, ObjectType, Conversion, + ActingContext); if (ObjectInit.isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; @@ -3925,9 +4052,6 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, // candidates, non-member candidates and built-in candidates, are // constructed as follows: QualType T1 = Args[0]->getType(); - QualType T2; - if (NumArgs > 1) - T2 = Args[1]->getType(); // -- If T1 is a class type, the set of member candidates is the // result of the qualified lookup of T1::operator@ @@ -3966,7 +4090,7 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, bool IsAssignmentOperator, unsigned NumContextualBoolArguments) { // Overload resolution is always an unevaluated context. - EnterExpressionEvaluationContext Unevaluated(*this, Action::Unevaluated); + EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); // Add this candidate CandidateSet.push_back(OverloadCandidate()); @@ -3999,7 +4123,8 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, if (ArgIdx < NumContextualBoolArguments) { assert(ParamTys[ArgIdx] == Context.BoolTy && "Contextual conversion to bool requires bool type"); - Candidate.Conversions[ArgIdx] = TryContextuallyConvertToBool(Args[ArgIdx]); + Candidate.Conversions[ArgIdx] + = TryContextuallyConvertToBool(*this, Args[ArgIdx]); } else { Candidate.Conversions[ArgIdx] = TryCopyInitialization(*this, Args[ArgIdx], ParamTys[ArgIdx], @@ -4100,11 +4225,21 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, // Insert this type. if (!PointerTypes.insert(Ty)) return false; - + + QualType PointeeTy; const PointerType *PointerTy = Ty->getAs(); - assert(PointerTy && "type was not a pointer type!"); - - QualType PointeeTy = PointerTy->getPointeeType(); + bool buildObjCPtr = false; + if (!PointerTy) { + if (const ObjCObjectPointerType *PTy = Ty->getAs()) { + PointeeTy = PTy->getPointeeType(); + buildObjCPtr = true; + } + else + assert(false && "type was not a pointer type!"); + } + else + PointeeTy = PointerTy->getPointeeType(); + // Don't add qualified variants of arrays. For one, they're not allowed // (the qualifier would sink to the element type), and for another, the // only overload situation where it matters is subscript or pointer +- int, @@ -4125,7 +4260,10 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, if ((CVR & Qualifiers::Volatile) && !hasVolatile) continue; if ((CVR & Qualifiers::Restrict) && !hasRestrict) continue; QualType QPointeeTy = Context.getCVRQualifiedType(PointeeTy, CVR); - PointerTypes.insert(Context.getPointerType(QPointeeTy)); + if (!buildObjCPtr) + PointerTypes.insert(Context.getPointerType(QPointeeTy)); + else + PointerTypes.insert(Context.getObjCObjectPointerType(QPointeeTy)); } return true; @@ -4200,10 +4338,9 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, // If we're dealing with an array type, decay to the pointer. if (Ty->isArrayType()) Ty = SemaRef.Context.getArrayDecayedType(Ty); - - if (const PointerType *PointerTy = Ty->getAs()) { - QualType PointeeTy = PointerTy->getPointeeType(); - + if (Ty->isObjCIdType() || Ty->isObjCClassType()) + PointerTypes.insert(Ty); + else if (Ty->getAs() || Ty->getAs()) { // Insert our type, and its more-qualified variants, into the set // of types. if (!AddPointerWithMoreQualifiedTypeVariants(Ty, VisibleQuals)) @@ -4479,7 +4616,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); Ptr != CandidateTypes.pointer_end(); ++Ptr) { // Skip pointer types that aren't pointers to object types. - if (!(*Ptr)->getAs()->getPointeeType()->isObjectType()) + if (!(*Ptr)->getPointeeType()->isIncompleteOrObjectType()) continue; QualType ParamTypes[2] = { @@ -4519,7 +4656,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); Ptr != CandidateTypes.pointer_end(); ++Ptr) { QualType ParamTy = *Ptr; - QualType PointeeTy = ParamTy->getAs()->getPointeeType(); + QualType PointeeTy = ParamTy->getPointeeType(); AddBuiltinCandidate(Context.getLValueReferenceType(PointeeTy), &ParamTy, Args, 1, CandidateSet); } @@ -5000,7 +5137,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(); Ptr != CandidateTypes.pointer_end(); ++Ptr) { QualType ParamTypes[2] = { *Ptr, Context.getPointerDiffType() }; - QualType PointeeType = (*Ptr)->getAs()->getPointeeType(); + QualType PointeeType = (*Ptr)->getPointeeType(); QualType ResultTy = Context.getLValueReferenceType(PointeeType); // T& operator[](T*, ptrdiff_t) @@ -5028,18 +5165,16 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, QualType C1Ty = (*Ptr); QualType C1; QualifierCollector Q1; - if (const PointerType *PointerTy = C1Ty->getAs()) { - C1 = QualType(Q1.strip(PointerTy->getPointeeType()), 0); - if (!isa(C1)) - continue; - // heuristic to reduce number of builtin candidates in the set. - // Add volatile/restrict version only if there are conversions to a - // volatile/restrict type. - if (!VisibleTypeConversionsQuals.hasVolatile() && Q1.hasVolatile()) - continue; - if (!VisibleTypeConversionsQuals.hasRestrict() && Q1.hasRestrict()) - continue; - } + C1 = QualType(Q1.strip(C1Ty->getPointeeType()), 0); + if (!isa(C1)) + continue; + // heuristic to reduce number of builtin candidates in the set. + // Add volatile/restrict version only if there are conversions to a + // volatile/restrict type. + if (!VisibleTypeConversionsQuals.hasVolatile() && Q1.hasVolatile()) + continue; + if (!VisibleTypeConversionsQuals.hasRestrict() && Q1.hasRestrict()) + continue; for (BuiltinCandidateTypeSet::iterator MemPtr = CandidateTypes.member_pointer_begin(), MemPtrEnd = CandidateTypes.member_pointer_end(); @@ -5148,9 +5283,10 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, /// isBetterOverloadCandidate - Determines whether the first overload /// candidate is a better candidate than the second (C++ 13.3.3p1). bool -Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, - const OverloadCandidate& Cand2, - SourceLocation Loc) { +isBetterOverloadCandidate(Sema &S, + const OverloadCandidate& Cand1, + const OverloadCandidate& Cand2, + SourceLocation Loc) { // Define viable functions to be better candidates than non-viable // functions. if (!Cand2.Viable) @@ -5176,7 +5312,8 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, assert(Cand2.Conversions.size() == NumArgs && "Overload candidate mismatch"); bool HasBetterConversion = false; for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) { - switch (CompareImplicitConversionSequences(Cand1.Conversions[ArgIdx], + switch (CompareImplicitConversionSequences(S, + Cand1.Conversions[ArgIdx], Cand2.Conversions[ArgIdx])) { case ImplicitConversionSequence::Better: // Cand1 has a better conversion sequence. @@ -5211,9 +5348,9 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, if (Cand1.Function && Cand1.Function->getPrimaryTemplate() && Cand2.Function && Cand2.Function->getPrimaryTemplate()) if (FunctionTemplateDecl *BetterTemplate - = getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(), - Cand2.Function->getPrimaryTemplate(), - Loc, + = S.getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(), + Cand2.Function->getPrimaryTemplate(), + Loc, isa(Cand1.Function)? TPOC_Conversion : TPOC_Call)) return BetterTemplate == Cand1.Function->getPrimaryTemplate(); @@ -5227,7 +5364,8 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, if (Cand1.Function && Cand2.Function && isa(Cand1.Function) && isa(Cand2.Function)) { - switch (CompareStandardConversionSequences(Cand1.FinalConversion, + switch (CompareStandardConversionSequences(S, + Cand1.FinalConversion, Cand2.FinalConversion)) { case ImplicitConversionSequence::Better: // Cand1 has a better conversion sequence. @@ -5258,32 +5396,28 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1, /// function, Best points to the candidate function found. /// /// \returns The result of overload resolution. -OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, - SourceLocation Loc, - OverloadCandidateSet::iterator& Best) { +OverloadingResult +OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, + iterator& Best) { // Find the best viable function. - Best = CandidateSet.end(); - for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); - Cand != CandidateSet.end(); ++Cand) { - if (Cand->Viable) { - if (Best == CandidateSet.end() || - isBetterOverloadCandidate(*Cand, *Best, Loc)) + Best = end(); + for (iterator Cand = begin(); Cand != end(); ++Cand) { + if (Cand->Viable) + if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc)) Best = Cand; - } } // If we didn't find any viable functions, abort. - if (Best == CandidateSet.end()) + if (Best == end()) return OR_No_Viable_Function; // Make sure that this function is better than every other viable // function. If not, we have an ambiguity. - for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); - Cand != CandidateSet.end(); ++Cand) { + for (iterator Cand = begin(); Cand != end(); ++Cand) { if (Cand->Viable && Cand != Best && - !isBetterOverloadCandidate(*Best, *Cand, Loc)) { - Best = CandidateSet.end(); + !isBetterOverloadCandidate(S, *Best, *Cand, Loc)) { + Best = end(); return OR_Ambiguous; } } @@ -5301,7 +5435,7 @@ OverloadingResult Sema::BestViableFunction(OverloadCandidateSet& CandidateSet, // (clause 13), user-defined conversions (12.3.2), allocation function for // placement new (5.3.4), as well as non-default initialization (8.5). if (Best->Function) - MarkDeclarationReferenced(Loc, Best->Function); + S.MarkDeclarationReferenced(Loc, Best->Function); return OR_Success; } @@ -5365,14 +5499,15 @@ void Sema::NoteOverloadCandidate(FunctionDecl *Fn) { /// Diagnoses an ambiguous conversion. The partial diagnostic is the /// "lead" diagnostic; it will be given two arguments, the source and /// target types of the conversion. -void Sema::DiagnoseAmbiguousConversion(const ImplicitConversionSequence &ICS, - SourceLocation CaretLoc, - const PartialDiagnostic &PDiag) { - Diag(CaretLoc, PDiag) - << ICS.Ambiguous.getFromType() << ICS.Ambiguous.getToType(); +void ImplicitConversionSequence::DiagnoseAmbiguousConversion( + Sema &S, + SourceLocation CaretLoc, + const PartialDiagnostic &PDiag) const { + S.Diag(CaretLoc, PDiag) + << Ambiguous.getFromType() << Ambiguous.getToType(); for (AmbiguousConversionSequence::const_iterator - I = ICS.Ambiguous.begin(), E = ICS.Ambiguous.end(); I != E; ++I) { - NoteOverloadCandidate(*I); + I = Ambiguous.begin(), E = Ambiguous.end(); I != E; ++I) { + S.NoteOverloadCandidate(*I); } } @@ -5589,8 +5724,31 @@ void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, return; } - case Sema::TDK_Inconsistent: - case Sema::TDK_InconsistentQuals: { + case Sema::TDK_Underqualified: { + assert(ParamD && "no parameter found for bad qualifiers deduction result"); + TemplateTypeParmDecl *TParam = cast(ParamD); + + QualType Param = Cand->DeductionFailure.getFirstArg()->getAsType(); + + // Param will have been canonicalized, but it should just be a + // qualified version of ParamD, so move the qualifiers to that. + QualifierCollector Qs(S.Context); + Qs.strip(Param); + QualType NonCanonParam = Qs.apply(TParam->getTypeForDecl()); + assert(S.Context.hasSameType(Param, NonCanonParam)); + + // Arg has also been canonicalized, but there's nothing we can do + // about that. It also doesn't matter as much, because it won't + // have any template parameters in it (because deduction isn't + // done on dependent types). + QualType Arg = Cand->DeductionFailure.getSecondArg()->getAsType(); + + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_underqualified) + << ParamD->getDeclName() << Arg << NonCanonParam; + return; + } + + case Sema::TDK_Inconsistent: { assert(ParamD && "no parameter found for inconsistent deduction result"); int which = 0; if (isa(ParamD)) @@ -5779,7 +5937,7 @@ void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc, if (ICS.isBad()) break; // all meaningless after first invalid if (!ICS.isAmbiguous()) continue; - S.DiagnoseAmbiguousConversion(ICS, OpLoc, + ICS.DiagnoseAmbiguousConversion(S, OpLoc, S.PDiag(diag::note_ambiguous_type_conversion)); } } @@ -5808,8 +5966,8 @@ struct CompareOverloadCandidatesForDisplay { // TODO: introduce a tri-valued comparison for overload // candidates. Would be more worthwhile if we had a sort // that could exploit it. - if (S.isBetterOverloadCandidate(*L, *R, SourceLocation())) return true; - if (S.isBetterOverloadCandidate(*R, *L, SourceLocation())) return false; + if (isBetterOverloadCandidate(S, *L, *R, SourceLocation())) return true; + if (isBetterOverloadCandidate(S, *R, *L, SourceLocation())) return false; } else if (R->Viable) return false; @@ -5838,8 +5996,9 @@ struct CompareOverloadCandidatesForDisplay { int leftBetter = 0; unsigned I = (L->IgnoreObjectArgument || R->IgnoreObjectArgument); for (unsigned E = L->Conversions.size(); I != E; ++I) { - switch (S.CompareImplicitConversionSequences(L->Conversions[I], - R->Conversions[I])) { + switch (CompareImplicitConversionSequences(S, + L->Conversions[I], + R->Conversions[I])) { case ImplicitConversionSequence::Better: leftBetter++; break; @@ -5947,23 +6106,20 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, /// PrintOverloadCandidates - When overload resolution fails, prints /// diagnostic messages containing the candidates in the candidate /// set. -void -Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, - OverloadCandidateDisplayKind OCD, - Expr **Args, unsigned NumArgs, - const char *Opc, - SourceLocation OpLoc) { +void OverloadCandidateSet::NoteCandidates(Sema &S, + OverloadCandidateDisplayKind OCD, + Expr **Args, unsigned NumArgs, + const char *Opc, + SourceLocation OpLoc) { // Sort the candidates by viability and position. Sorting directly would // be prohibitive, so we make a set of pointers and sort those. llvm::SmallVector Cands; - if (OCD == OCD_AllCandidates) Cands.reserve(CandidateSet.size()); - for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), - LastCand = CandidateSet.end(); - Cand != LastCand; ++Cand) { + if (OCD == OCD_AllCandidates) Cands.reserve(size()); + for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) { if (Cand->Viable) Cands.push_back(Cand); else if (OCD == OCD_AllCandidates) { - CompleteNonViableCandidate(*this, Cand, Args, NumArgs); + CompleteNonViableCandidate(S, Cand, Args, NumArgs); if (Cand->Function || Cand->IsSurrogate) Cands.push_back(Cand); // Otherwise, this a non-viable builtin candidate. We do not, in general, @@ -5972,12 +6128,12 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, } std::sort(Cands.begin(), Cands.end(), - CompareOverloadCandidatesForDisplay(*this)); + CompareOverloadCandidatesForDisplay(S)); bool ReportedAmbiguousConversions = false; llvm::SmallVectorImpl::iterator I, E; - const Diagnostic::OverloadsShown ShowOverloads = Diags.getShowOverloads(); + const Diagnostic::OverloadsShown ShowOverloads = S.Diags.getShowOverloads(); unsigned CandsShown = 0; for (I = Cands.begin(), E = Cands.end(); I != E; ++I) { OverloadCandidate *Cand = *I; @@ -5991,9 +6147,9 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, ++CandsShown; if (Cand->Function) - NoteFunctionCandidate(*this, Cand, Args, NumArgs); + NoteFunctionCandidate(S, Cand, Args, NumArgs); else if (Cand->IsSurrogate) - NoteSurrogateCandidate(*this, Cand); + NoteSurrogateCandidate(S, Cand); else { assert(Cand->Viable && "Non-viable built-in candidates are not added to Cands."); @@ -6004,17 +6160,17 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, // FIXME: It's quite possible for different conversions to see // different ambiguities, though. if (!ReportedAmbiguousConversions) { - NoteAmbiguousUserConversions(*this, OpLoc, Cand); + NoteAmbiguousUserConversions(S, OpLoc, Cand); ReportedAmbiguousConversions = true; } // If this is a viable builtin, print it. - NoteBuiltinOperatorCandidate(*this, Opc, OpLoc, Cand); + NoteBuiltinOperatorCandidate(S, Opc, OpLoc, Cand); } } if (I != E) - Diag(OpLoc, diag::note_ovl_too_many_candidates) << int(E - I); + S.Diag(OpLoc, diag::note_ovl_too_many_candidates) << int(E - I); } static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) { @@ -6061,12 +6217,13 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // C++ [over.over]p1: // [...] The overloaded function name can be preceded by the & // operator. - OverloadExpr *OvlExpr = OverloadExpr::find(From).getPointer(); - TemplateArgumentListInfo ETABuffer, *ExplicitTemplateArgs = 0; - if (OvlExpr->hasExplicitTemplateArgs()) { - OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer); - ExplicitTemplateArgs = &ETABuffer; - } + // However, remember whether the expression has member-pointer form: + // C++ [expr.unary.op]p4: + // A pointer to member is only formed when an explicit & is used + // and its operand is a qualified-id not enclosed in + // parentheses. + OverloadExpr::FindResult Ovl = OverloadExpr::find(From); + OverloadExpr *OvlExpr = Ovl.Expression; // We expect a pointer or reference to function, or a function pointer. FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType(); @@ -6078,6 +6235,25 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, return 0; } + // If the overload expression doesn't have the form of a pointer to + // member, don't try to convert it to a pointer-to-member type. + if (IsMember && !Ovl.HasFormOfMemberPointer) { + if (!Complain) return 0; + + // TODO: Should we condition this on whether any functions might + // have matched, or is it more appropriate to do that in callers? + // TODO: a fixit wouldn't hurt. + Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier) + << ToType << OvlExpr->getSourceRange(); + return 0; + } + + TemplateArgumentListInfo ETABuffer, *ExplicitTemplateArgs = 0; + if (OvlExpr->hasExplicitTemplateArgs()) { + OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer); + ExplicitTemplateArgs = &ETABuffer; + } + assert(From->getType() == Context.OverloadTy); // Look through all of the overloaded functions, searching for one @@ -6267,7 +6443,7 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) { if (From->getType() != Context.OverloadTy) return 0; - OverloadExpr *OvlExpr = OverloadExpr::find(From).getPointer(); + OverloadExpr *OvlExpr = OverloadExpr::find(From).Expression; // If we didn't actually find any template-ids, we're done. if (!OvlExpr->hasExplicitTemplateArgs()) @@ -6405,18 +6581,10 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, PartialOverloading); } -static Sema::OwningExprResult Destroy(Sema &SemaRef, Expr *Fn, - Expr **Args, unsigned NumArgs) { - Fn->Destroy(SemaRef.Context); - for (unsigned Arg = 0; Arg < NumArgs; ++Arg) - Args[Arg]->Destroy(SemaRef.Context); - return SemaRef.ExprError(); -} - /// Attempts to recover from a call where no functions were found. /// /// Returns true if new candidates were found. -static Sema::OwningExprResult +static ExprResult BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, @@ -6440,13 +6608,13 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, LookupResult R(SemaRef, ULE->getName(), ULE->getNameLoc(), Sema::LookupOrdinaryName); if (SemaRef.DiagnoseEmptyLookup(S, SS, R, Sema::CTC_Expression)) - return Destroy(SemaRef, Fn, Args, NumArgs); + return ExprError(); assert(!R.empty() && "lookup results empty despite recovery"); // Build an implicit member call if appropriate. Just drop the // casts and such from the call, we don't really care. - Sema::OwningExprResult NewFn = SemaRef.ExprError(); + ExprResult NewFn = ExprError(); if ((*R.begin())->isCXXClassMember()) NewFn = SemaRef.BuildPossibleImplicitMemberExpr(SS, R, ExplicitTemplateArgs); else if (ExplicitTemplateArgs) @@ -6455,15 +6623,13 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, NewFn = SemaRef.BuildDeclarationNameExpr(SS, R, false); if (NewFn.isInvalid()) - return Destroy(SemaRef, Fn, Args, NumArgs); - - Fn->Destroy(SemaRef.Context); + return ExprError(); // This shouldn't cause an infinite loop because we're giving it // an expression with non-empty lookup results, which should never // end up here. - return SemaRef.ActOnCallExpr(/*Scope*/ 0, move(NewFn), LParenLoc, - Sema::MultiExprArg(SemaRef, (void**) Args, NumArgs), + return SemaRef.ActOnCallExpr(/*Scope*/ 0, NewFn.take(), LParenLoc, + MultiExprArg(Args, NumArgs), CommaLocs, RParenLoc); } @@ -6474,7 +6640,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, /// the function declaration produced by overload /// resolution. Otherwise, emits diagnostics, deletes all of the /// arguments and Fn, and returns NULL. -Sema::OwningExprResult +ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -6512,7 +6678,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, CommaLocs, RParenLoc); OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) { + switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) { case OR_Success: { FunctionDecl *FDecl = Best->Function; CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); @@ -6525,13 +6691,13 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_no_viable_function_in_call) << ULE->getName() << Fn->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); break; case OR_Ambiguous: Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_ambiguous_call) << ULE->getName() << Fn->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs); + CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs); break; case OR_Deleted: @@ -6539,15 +6705,11 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, << Best->Function->isDeleted() << ULE->getName() << Fn->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); break; } - // Overload resolution failed. Destroy all of the subexpressions and - // return NULL. - Fn->Destroy(Context); - for (unsigned Arg = 0; Arg < NumArgs; ++Arg) - Args[Arg]->Destroy(Context); + // Overload resolution failed. return ExprError(); } @@ -6572,16 +6734,17 @@ static bool IsOverloaded(const UnresolvedSetImpl &Functions) { /// by CreateOverloadedUnaryOp(). /// /// \param input The input argument. -Sema::OwningExprResult +ExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, const UnresolvedSetImpl &Fns, - ExprArg input) { + Expr *Input) { UnaryOperator::Opcode Opc = static_cast(OpcIn); - Expr *Input = (Expr *)input.get(); OverloadedOperatorKind Op = UnaryOperator::getOverloadedOperator(Opc); assert(Op != OO_None && "Invalid opcode for overloaded unary operator"); DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); + // TODO: provide better source location info. + DeclarationNameInfo OpNameInfo(OpName, OpLoc); Expr *Args[2] = { Input, 0 }; unsigned NumArgs = 1; @@ -6589,16 +6752,16 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // For post-increment and post-decrement, add the implicit '0' as // the second argument, so that we know this is a post-increment or // post-decrement. - if (Opc == UnaryOperator::PostInc || Opc == UnaryOperator::PostDec) { + if (Opc == UO_PostInc || Opc == UO_PostDec) { llvm::APSInt Zero(Context.getTypeSize(Context.IntTy), false); - Args[1] = new (Context) IntegerLiteral(Zero, Context.IntTy, - SourceLocation()); + Args[1] = IntegerLiteral::Create(Context, Zero, Context.IntTy, + SourceLocation()); NumArgs = 2; } if (Input->isTypeDependent()) { if (Fns.empty()) - return Owned(new (Context) UnaryOperator(input.takeAs(), + return Owned(new (Context) UnaryOperator(Input, Opc, Context.DependentTy, OpLoc)); @@ -6606,10 +6769,9 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, - 0, SourceRange(), OpName, OpLoc, + 0, SourceRange(), OpNameInfo, /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); - input.release(); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, &Args[0], NumArgs, Context.DependentTy, @@ -6636,7 +6798,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // Perform overload resolution. OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, OpLoc, Best)) { + switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) { case OR_Success: { // We found a built-in operator or an overloaded operator. FunctionDecl *FnDecl = Best->Function; @@ -6654,16 +6816,14 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, return ExprError(); } else { // Convert the arguments. - OwningExprResult InputInit + ExprResult InputInit = PerformCopyInitialization(InitializedEntity::InitializeParameter( FnDecl->getParamDecl(0)), SourceLocation(), - move(input)); + Input); if (InputInit.isInvalid()) return ExprError(); - - input = move(InputInit); - Input = (Expr *)input.get(); + Input = InputInit.take(); } DiagnoseUseOfDecl(Best->FoundDecl, OpLoc); @@ -6676,17 +6836,16 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, SourceLocation()); UsualUnaryConversions(FnExpr); - input.release(); Args[0] = Input; - ExprOwningPtr TheCall(this, + CallExpr *TheCall = new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, - Args, NumArgs, ResultTy, OpLoc)); + Args, NumArgs, ResultTy, OpLoc); - if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(), + if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, FnDecl)) return ExprError(); - return MaybeBindToTemporary(TheCall.release()); + return MaybeBindToTemporary(TheCall); } else { // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in @@ -6708,8 +6867,9 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, Diag(OpLoc, diag::err_ovl_ambiguous_oper) << UnaryOperator::getOpcodeStr(Opc) << Input->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs, - UnaryOperator::getOpcodeStr(Opc), OpLoc); + CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, + Args, NumArgs, + UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); case OR_Deleted: @@ -6717,15 +6877,14 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, << Best->Function->isDeleted() << UnaryOperator::getOpcodeStr(Opc) << Input->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); return ExprError(); } // Either we found no viable overloaded operator or we matched a // built-in operator. In either case, fall through to trying to // build a built-in operation. - input.release(); - return CreateBuiltinUnaryOp(OpLoc, Opc, Owned(Input)); + return CreateBuiltinUnaryOp(OpLoc, Opc, Input); } /// \brief Create a binary operation that may resolve to an overloaded @@ -6745,7 +6904,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, /// /// \param LHS Left-hand argument. /// \param RHS Right-hand argument. -Sema::OwningExprResult +ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, unsigned OpcIn, const UnresolvedSetImpl &Fns, @@ -6763,7 +6922,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, if (Fns.empty()) { // If there are no functions to store, just build a dependent // BinaryOperator or CompoundAssignment. - if (Opc <= BinaryOperator::Assign || Opc > BinaryOperator::OrAssign) + if (Opc <= BO_Assign || Opc > BO_OrAssign) return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc, Context.DependentTy, OpLoc)); @@ -6776,9 +6935,11 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // FIXME: save results of ADL from here? CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators + // TODO: provide better source location info in DNLoc component. + DeclarationNameInfo OpNameInfo(OpName, OpLoc); UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, - 0, SourceRange(), OpName, OpLoc, + 0, SourceRange(), OpNameInfo, /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, @@ -6789,7 +6950,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // If this is the .* operator, which is not overloadable, just // create a built-in binary operator. - if (Opc == BinaryOperator::PtrMemD) + if (Opc == BO_PtrMemD) return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); // If this is the assignment operator, we only perform overload resolution @@ -6798,7 +6959,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // various built-in candidates, but as DR507 points out, this can lead to // problems. So we do it this way, which pretty much follows what GCC does. // Note that we go the traditional code path for compound assignment forms. - if (Opc==BinaryOperator::Assign && !Args[0]->getType()->isOverloadableType()) + if (Opc == BO_Assign && !Args[0]->getType()->isOverloadableType()) return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); // Build an empty overload set. @@ -6821,7 +6982,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Perform overload resolution. OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, OpLoc, Best)) { + switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) { case OR_Success: { // We found a built-in operator or an overloaded operator. FunctionDecl *FnDecl = Best->Function; @@ -6835,7 +6996,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Best->Access is only meaningful for class members. CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Best->FoundDecl); - OwningExprResult Arg1 + ExprResult Arg1 = PerformCopyInitialization( InitializedEntity::InitializeParameter( FnDecl->getParamDecl(0)), @@ -6851,7 +7012,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Args[1] = RHS = Arg1.takeAs(); } else { // Convert the arguments. - OwningExprResult Arg0 + ExprResult Arg0 = PerformCopyInitialization( InitializedEntity::InitializeParameter( FnDecl->getParamDecl(0)), @@ -6860,7 +7021,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, if (Arg0.isInvalid()) return ExprError(); - OwningExprResult Arg1 + ExprResult Arg1 = PerformCopyInitialization( InitializedEntity::InitializeParameter( FnDecl->getParamDecl(1)), @@ -6884,16 +7045,15 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, OpLoc); UsualUnaryConversions(FnExpr); - ExprOwningPtr - TheCall(this, new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, - Args, 2, ResultTy, - OpLoc)); + CXXOperatorCallExpr *TheCall = + new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, + Args, 2, ResultTy, OpLoc); - if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall.get(), + if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, FnDecl)) return ExprError(); - return MaybeBindToTemporary(TheCall.release()); + return MaybeBindToTemporary(TheCall); } else { // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in @@ -6913,15 +7073,15 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // If the operator is the operator , [...] and there are no // viable functions, then the operator is assumed to be the // built-in operator and interpreted according to clause 5. - if (Opc == BinaryOperator::Comma) + if (Opc == BO_Comma) break; // For class as left operand for assignment or compound assigment operator // do not fall through to handling in built-in, but report that no overloaded // assignment operator found - OwningExprResult Result = ExprError(); + ExprResult Result = ExprError(); if (Args[0]->getType()->isRecordType() && - Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign) { + Opc >= BO_Assign && Opc <= BO_OrAssign) { Diag(OpLoc, diag::err_ovl_no_viable_oper) << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); @@ -6933,8 +7093,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, assert(Result.isInvalid() && "C++ binary operator overloading is missing candidates!"); if (Result.isInvalid()) - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2, - BinaryOperator::getOpcodeStr(Opc), OpLoc); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2, + BinaryOperator::getOpcodeStr(Opc), OpLoc); return move(Result); } @@ -6942,8 +7102,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Diag(OpLoc, diag::err_ovl_ambiguous_oper) << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, 2, - BinaryOperator::getOpcodeStr(Opc), OpLoc); + CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, 2, + BinaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); case OR_Deleted: @@ -6951,7 +7111,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, << Best->Function->isDeleted() << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2); return ExprError(); } @@ -6959,12 +7119,11 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); } -Action::OwningExprResult +ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, SourceLocation RLoc, - ExprArg Base, ExprArg Idx) { - Expr *Args[2] = { static_cast(Base.get()), - static_cast(Idx.get()) }; + Expr *Base, Expr *Idx) { + Expr *Args[2] = { Base, Idx }; DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Subscript); @@ -6973,16 +7132,17 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, if (Args[0]->isTypeDependent() || Args[1]->isTypeDependent()) { CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators + // CHECKME: no 'operator' keyword? + DeclarationNameInfo OpNameInfo(OpName, LLoc); + OpNameInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc)); UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, /*Dependent*/ true, NamingClass, - 0, SourceRange(), OpName, LLoc, + 0, SourceRange(), OpNameInfo, /*ADL*/ true, /*Overloaded*/ false, UnresolvedSetIterator(), UnresolvedSetIterator()); // Can't add any actual overloads yet - Base.release(); - Idx.release(); return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript, Fn, Args, 2, Context.DependentTy, @@ -7002,7 +7162,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // Perform overload resolution. OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, LLoc, Best)) { + switch (CandidateSet.BestViableFunction(*this, LLoc, Best)) { case OR_Success: { // We found a built-in operator or an overloaded operator. FunctionDecl *FnDecl = Best->Function; @@ -7021,7 +7181,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, return ExprError(); // Convert the arguments. - OwningExprResult InputInit + ExprResult InputInit = PerformCopyInitialization(InitializedEntity::InitializeParameter( FnDecl->getParamDecl(0)), SourceLocation(), @@ -7041,18 +7201,16 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, LLoc); UsualUnaryConversions(FnExpr); - Base.release(); - Idx.release(); - ExprOwningPtr - TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Subscript, - FnExpr, Args, 2, - ResultTy, RLoc)); + CXXOperatorCallExpr *TheCall = + new (Context) CXXOperatorCallExpr(Context, OO_Subscript, + FnExpr, Args, 2, + ResultTy, RLoc); - if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall.get(), + if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall, FnDecl)) return ExprError(); - return MaybeBindToTemporary(TheCall.release()); + return MaybeBindToTemporary(TheCall); } else { // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in @@ -7076,32 +7234,29 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, Diag(LLoc, diag::err_ovl_no_viable_subscript) << Args[0]->getType() << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2, - "[]", LLoc); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2, + "[]", LLoc); return ExprError(); } case OR_Ambiguous: Diag(LLoc, diag::err_ovl_ambiguous_oper) << "[]" << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, 2, - "[]", LLoc); + CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, 2, + "[]", LLoc); return ExprError(); case OR_Deleted: Diag(LLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << "[]" << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, 2, - "[]", LLoc); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2, + "[]", LLoc); return ExprError(); } // We matched a built-in operator; build it. - Base.release(); - Idx.release(); - return CreateBuiltinArraySubscriptExpr(Owned(Args[0]), LLoc, - Owned(Args[1]), RLoc); + return CreateBuiltinArraySubscriptExpr(Args[0], LLoc, Args[1], RLoc); } /// BuildCallToMemberFunction - Build a call to a member @@ -7111,7 +7266,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, /// parameter). The caller needs to validate that the member /// expression refers to a member function or an overloaded member /// function. -Sema::OwningExprResult +ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation *CommaLocs, @@ -7174,7 +7329,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, DeclarationName DeclName = UnresExpr->getMemberName(); OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) { + switch (CandidateSet.BestViableFunction(*this, UnresExpr->getLocStart(), + Best)) { case OR_Success: Method = cast(Best->Function); FoundDecl = Best->FoundDecl; @@ -7186,14 +7342,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Diag(UnresExpr->getMemberLoc(), diag::err_ovl_no_viable_member_function_in_call) << DeclName << MemExprE->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); // FIXME: Leaking incoming expressions! return ExprError(); case OR_Ambiguous: Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call) << DeclName << MemExprE->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); // FIXME: Leaking incoming expressions! return ExprError(); @@ -7201,7 +7357,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call) << Best->Function->isDeleted() << DeclName << MemExprE->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); // FIXME: Leaking incoming expressions! return ExprError(); } @@ -7219,15 +7375,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, } assert(Method && "Member call to something that isn't a method?"); - ExprOwningPtr - TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExprE, Args, - NumArgs, - Method->getCallResultType(), - RParenLoc)); + CXXMemberCallExpr *TheCall = + new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs, + Method->getCallResultType(), + RParenLoc); // Check for a valid return type. if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(), - TheCall.get(), Method)) + TheCall, Method)) return ExprError(); // Convert the object argument (for a non-static member function call). @@ -7242,21 +7397,21 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // Convert the rest of the arguments const FunctionProtoType *Proto = Method->getType()->getAs(); - if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs, + if (ConvertArgumentsForCall(TheCall, MemExpr, Method, Proto, Args, NumArgs, RParenLoc)) return ExprError(); - if (CheckFunctionCall(Method, TheCall.get())) + if (CheckFunctionCall(Method, TheCall)) return ExprError(); - return MaybeBindToTemporary(TheCall.release()); + return MaybeBindToTemporary(TheCall); } /// BuildCallToObjectOfClassType - Build a call to an object of class /// type (C++ [over.call.object]), which can end up invoking an /// overloaded function call operator (@c operator()) or performing a /// user-defined conversion on the object argument. -Sema::ExprResult +ExprResult Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, @@ -7338,7 +7493,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Perform overload resolution. OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, Object->getLocStart(), Best)) { + switch (CandidateSet.BestViableFunction(*this, Object->getLocStart(), + Best)) { case OR_Success: // Overload resolution succeeded; we'll build the appropriate call // below. @@ -7353,14 +7509,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, Diag(Object->getSourceRange().getBegin(), diag::err_ovl_no_viable_object_call) << Object->getType() << Object->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); break; case OR_Ambiguous: Diag(Object->getSourceRange().getBegin(), diag::err_ovl_ambiguous_object_call) << Object->getType() << Object->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, Args, NumArgs); + CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs); break; case OR_Deleted: @@ -7368,18 +7524,12 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, diag::err_ovl_deleted_object_call) << Best->Function->isDeleted() << Object->getType() << Object->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, Args, NumArgs); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); break; } - if (Best == CandidateSet.end()) { - // We had an error; delete all of the subexpressions and return - // the error. - Object->Destroy(Context); - for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) - Args[ArgIdx]->Destroy(Context); + if (Best == CandidateSet.end()) return true; - } if (Best->Function == 0) { // Since there is no function declaration, this is one of the @@ -7400,9 +7550,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Best->FoundDecl, Conv); - return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc, - MultiExprArg(*this, (ExprTy**)Args, NumArgs), - CommaLocs, RParenLoc).result(); + return ActOnCallExpr(S, CE, LParenLoc, MultiExprArg(Args, NumArgs), + CommaLocs, RParenLoc); } CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); @@ -7438,13 +7587,13 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Once we've built TheCall, all of the expressions are properly // owned. QualType ResultTy = Method->getCallResultType(); - ExprOwningPtr - TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn, - MethodArgs, NumArgs + 1, - ResultTy, RParenLoc)); + CXXOperatorCallExpr *TheCall = + new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn, + MethodArgs, NumArgs + 1, + ResultTy, RParenLoc); delete [] MethodArgs; - if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall.get(), + if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall, Method)) return true; @@ -7471,15 +7620,15 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Pass the argument. - OwningExprResult InputInit + ExprResult InputInit = PerformCopyInitialization(InitializedEntity::InitializeParameter( Method->getParamDecl(i)), - SourceLocation(), Owned(Arg)); + SourceLocation(), Arg); IsError |= InputInit.isInvalid(); Arg = InputInit.takeAs(); } else { - OwningExprResult DefArg + ExprResult DefArg = BuildCXXDefaultArgExpr(LParenLoc, Method, Method->getParamDecl(i)); if (DefArg.isInvalid()) { IsError = true; @@ -7504,18 +7653,17 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, if (IsError) return true; - if (CheckFunctionCall(Method, TheCall.get())) + if (CheckFunctionCall(Method, TheCall)) return true; - return MaybeBindToTemporary(TheCall.release()).result(); + return MaybeBindToTemporary(TheCall); } /// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator-> /// (if one exists), where @c Base is an expression of class type and /// @c Member is the name of the member we're trying to find. -Sema::OwningExprResult -Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { - Expr *Base = static_cast(BaseIn.get()); +ExprResult +Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { assert(Base->getType()->isRecordType() && "left-hand side must have class type"); SourceLocation Loc = Base->getExprLoc(); @@ -7547,7 +7695,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { // Perform overload resolution. OverloadCandidateSet::iterator Best; - switch (BestViableFunction(CandidateSet, OpLoc, Best)) { + switch (CandidateSet.BestViableFunction(*this, OpLoc, Best)) { case OR_Success: // Overload resolution succeeded; we'll build the call below. break; @@ -7559,20 +7707,20 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { else Diag(OpLoc, diag::err_ovl_no_viable_oper) << "operator->" << Base->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &Base, 1); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, &Base, 1); return ExprError(); case OR_Ambiguous: Diag(OpLoc, diag::err_ovl_ambiguous_oper) << "->" << Base->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_ViableCandidates, &Base, 1); + CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, &Base, 1); return ExprError(); case OR_Deleted: Diag(OpLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << "->" << Base->getSourceRange(); - PrintOverloadCandidates(CandidateSet, OCD_AllCandidates, &Base, 1); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, &Base, 1); return ExprError(); } @@ -7585,23 +7733,20 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { Best->FoundDecl, Method)) return ExprError(); - // No concerns about early exits now. - BaseIn.release(); - // Build the operator call. Expr *FnExpr = new (Context) DeclRefExpr(Method, Method->getType(), SourceLocation()); UsualUnaryConversions(FnExpr); QualType ResultTy = Method->getCallResultType(); - ExprOwningPtr - TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, - &Base, 1, ResultTy, OpLoc)); + CXXOperatorCallExpr *TheCall = + new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, + &Base, 1, ResultTy, OpLoc); - if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall.get(), + if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall, Method)) return ExprError(); - return move(TheCall); + return Owned(TheCall); } /// FixOverloadedFunctionReference - E is an expression that refers to @@ -7626,17 +7771,18 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, assert(Context.hasSameType(ICE->getSubExpr()->getType(), SubExpr->getType()) && "Implicit cast type cannot be determined from overload"); + assert(ICE->path_empty() && "fixing up hierarchy conversion?"); if (SubExpr == ICE->getSubExpr()) return ICE->Retain(); - return new (Context) ImplicitCastExpr(ICE->getType(), - ICE->getCastKind(), - SubExpr, CXXBaseSpecifierArray(), - ICE->isLvalueCast()); + return ImplicitCastExpr::Create(Context, ICE->getType(), + ICE->getCastKind(), + SubExpr, 0, + ICE->getValueKind()); } if (UnaryOperator *UnOp = dyn_cast(E)) { - assert(UnOp->getOpcode() == UnaryOperator::AddrOf && + assert(UnOp->getOpcode() == UO_AddrOf && "Can only take the address of an overloaded function"); if (CXXMethodDecl *Method = dyn_cast(Fn)) { if (Method->isStatic()) { @@ -7664,7 +7810,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, QualType MemPtrType = Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr()); - return new (Context) UnaryOperator(SubExpr, UnaryOperator::AddrOf, + return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType, UnOp->getOperatorLoc()); } } @@ -7673,7 +7819,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, if (SubExpr == UnOp->getSubExpr()) return UnOp->Retain(); - return new (Context) UnaryOperator(SubExpr, UnaryOperator::AddrOf, + return new (Context) UnaryOperator(SubExpr, UO_AddrOf, Context.getPointerType(SubExpr->getType()), UnOp->getOperatorLoc()); } @@ -7732,7 +7878,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, MemExpr->getQualifierRange(), Fn, Found, - MemExpr->getMemberLoc(), + MemExpr->getMemberNameInfo(), TemplateArgs, Fn->getType()); } @@ -7741,9 +7887,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, return E->Retain(); } -Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E, - DeclAccessPair Found, - FunctionDecl *Fn) { +ExprResult Sema::FixOverloadedFunctionReference(ExprResult E, + DeclAccessPair Found, + FunctionDecl *Fn) { return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Found, Fn)); } diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h deleted file mode 100644 index eb4fc65..0000000 --- a/lib/Sema/SemaOverload.h +++ /dev/null @@ -1,617 +0,0 @@ -//===--- Overload.h - C++ Overloading ---------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the data structures and types used in C++ -// overload resolution. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_SEMA_OVERLOAD_H -#define LLVM_CLANG_SEMA_OVERLOAD_H - -#include "clang/AST/Decl.h" -#include "clang/AST/DeclTemplate.h" -#include "clang/AST/Expr.h" -#include "clang/AST/TemplateBase.h" -#include "clang/AST/Type.h" -#include "clang/AST/UnresolvedSet.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" - -namespace clang { - class ASTContext; - class CXXConstructorDecl; - class CXXConversionDecl; - class FunctionDecl; - - /// OverloadingResult - Capture the result of performing overload - /// resolution. - enum OverloadingResult { - OR_Success, ///< Overload resolution succeeded. - OR_No_Viable_Function, ///< No viable function found. - OR_Ambiguous, ///< Ambiguous candidates found. - OR_Deleted ///< Succeeded, but refers to a deleted function. - }; - - /// ImplicitConversionKind - The kind of implicit conversion used to - /// convert an argument to a parameter's type. The enumerator values - /// match with Table 9 of (C++ 13.3.3.1.1) and are listed such that - /// better conversion kinds have smaller values. - enum ImplicitConversionKind { - ICK_Identity = 0, ///< Identity conversion (no conversion) - ICK_Lvalue_To_Rvalue, ///< Lvalue-to-rvalue conversion (C++ 4.1) - ICK_Array_To_Pointer, ///< Array-to-pointer conversion (C++ 4.2) - ICK_Function_To_Pointer, ///< Function-to-pointer (C++ 4.3) - ICK_NoReturn_Adjustment, ///< Removal of noreturn from a type (Clang) - ICK_Qualification, ///< Qualification conversions (C++ 4.4) - ICK_Integral_Promotion, ///< Integral promotions (C++ 4.5) - ICK_Floating_Promotion, ///< Floating point promotions (C++ 4.6) - ICK_Complex_Promotion, ///< Complex promotions (Clang extension) - ICK_Integral_Conversion, ///< Integral conversions (C++ 4.7) - ICK_Floating_Conversion, ///< Floating point conversions (C++ 4.8) - ICK_Complex_Conversion, ///< Complex conversions (C99 6.3.1.6) - ICK_Floating_Integral, ///< Floating-integral conversions (C++ 4.9) - ICK_Pointer_Conversion, ///< Pointer conversions (C++ 4.10) - ICK_Pointer_Member, ///< Pointer-to-member conversions (C++ 4.11) - ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12) - ICK_Compatible_Conversion, ///< Conversions between compatible types in C99 - ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics]) - ICK_Vector_Conversion, ///< Vector conversions - ICK_Vector_Splat, ///< A vector splat from an arithmetic type - ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7) - ICK_Num_Conversion_Kinds ///< The number of conversion kinds - }; - - /// ImplicitConversionCategory - The category of an implicit - /// conversion kind. The enumerator values match with Table 9 of - /// (C++ 13.3.3.1.1) and are listed such that better conversion - /// categories have smaller values. - enum ImplicitConversionCategory { - ICC_Identity = 0, ///< Identity - ICC_Lvalue_Transformation, ///< Lvalue transformation - ICC_Qualification_Adjustment, ///< Qualification adjustment - ICC_Promotion, ///< Promotion - ICC_Conversion ///< Conversion - }; - - ImplicitConversionCategory - GetConversionCategory(ImplicitConversionKind Kind); - - /// ImplicitConversionRank - The rank of an implicit conversion - /// kind. The enumerator values match with Table 9 of (C++ - /// 13.3.3.1.1) and are listed such that better conversion ranks - /// have smaller values. - enum ImplicitConversionRank { - ICR_Exact_Match = 0, ///< Exact Match - ICR_Promotion, ///< Promotion - ICR_Conversion, ///< Conversion - ICR_Complex_Real_Conversion ///< Complex <-> Real conversion - }; - - ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind); - - /// StandardConversionSequence - represents a standard conversion - /// sequence (C++ 13.3.3.1.1). A standard conversion sequence - /// contains between zero and three conversions. If a particular - /// conversion is not needed, it will be set to the identity conversion - /// (ICK_Identity). Note that the three conversions are - /// specified as separate members (rather than in an array) so that - /// we can keep the size of a standard conversion sequence to a - /// single word. - struct StandardConversionSequence { - /// First -- The first conversion can be an lvalue-to-rvalue - /// conversion, array-to-pointer conversion, or - /// function-to-pointer conversion. - ImplicitConversionKind First : 8; - - /// Second - The second conversion can be an integral promotion, - /// floating point promotion, integral conversion, floating point - /// conversion, floating-integral conversion, pointer conversion, - /// pointer-to-member conversion, or boolean conversion. - ImplicitConversionKind Second : 8; - - /// Third - The third conversion can be a qualification conversion. - ImplicitConversionKind Third : 8; - - /// Deprecated - Whether this the deprecated conversion of a - /// string literal to a pointer to non-const character data - /// (C++ 4.2p2). - bool DeprecatedStringLiteralToCharPtr : 1; - - /// IncompatibleObjC - Whether this is an Objective-C conversion - /// that we should warn about (if we actually use it). - bool IncompatibleObjC : 1; - - /// ReferenceBinding - True when this is a reference binding - /// (C++ [over.ics.ref]). - bool ReferenceBinding : 1; - - /// DirectBinding - True when this is a reference binding that is a - /// direct binding (C++ [dcl.init.ref]). - bool DirectBinding : 1; - - /// RRefBinding - True when this is a reference binding of an rvalue - /// reference to an rvalue (C++0x [over.ics.rank]p3b4). - bool RRefBinding : 1; - - /// FromType - The type that this conversion is converting - /// from. This is an opaque pointer that can be translated into a - /// QualType. - void *FromTypePtr; - - /// ToType - The types that this conversion is converting to in - /// each step. This is an opaque pointer that can be translated - /// into a QualType. - void *ToTypePtrs[3]; - - /// CopyConstructor - The copy constructor that is used to perform - /// this conversion, when the conversion is actually just the - /// initialization of an object via copy constructor. Such - /// conversions are either identity conversions or derived-to-base - /// conversions. - CXXConstructorDecl *CopyConstructor; - - void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } - void setToType(unsigned Idx, QualType T) { - assert(Idx < 3 && "To type index is out of range"); - ToTypePtrs[Idx] = T.getAsOpaquePtr(); - } - void setAllToTypes(QualType T) { - ToTypePtrs[0] = T.getAsOpaquePtr(); - ToTypePtrs[1] = ToTypePtrs[0]; - ToTypePtrs[2] = ToTypePtrs[0]; - } - - QualType getFromType() const { - return QualType::getFromOpaquePtr(FromTypePtr); - } - QualType getToType(unsigned Idx) const { - assert(Idx < 3 && "To type index is out of range"); - return QualType::getFromOpaquePtr(ToTypePtrs[Idx]); - } - - void setAsIdentityConversion(); - - bool isIdentityConversion() const { - return First == ICK_Identity && Second == ICK_Identity && - Third == ICK_Identity; - } - - ImplicitConversionRank getRank() const; - bool isPointerConversionToBool() const; - bool isPointerConversionToVoidPointer(ASTContext& Context) const; - void DebugPrint() const; - }; - - /// UserDefinedConversionSequence - Represents a user-defined - /// conversion sequence (C++ 13.3.3.1.2). - struct UserDefinedConversionSequence { - /// Before - Represents the standard conversion that occurs before - /// the actual user-defined conversion. (C++ 13.3.3.1.2p1): - /// - /// If the user-defined conversion is specified by a constructor - /// (12.3.1), the initial standard conversion sequence converts - /// the source type to the type required by the argument of the - /// constructor. If the user-defined conversion is specified by - /// a conversion function (12.3.2), the initial standard - /// conversion sequence converts the source type to the implicit - /// object parameter of the conversion function. - StandardConversionSequence Before; - - /// EllipsisConversion - When this is true, it means user-defined - /// conversion sequence starts with a ... (elipsis) conversion, instead of - /// a standard conversion. In this case, 'Before' field must be ignored. - // FIXME. I much rather put this as the first field. But there seems to be - // a gcc code gen. bug which causes a crash in a test. Putting it here seems - // to work around the crash. - bool EllipsisConversion : 1; - - /// After - Represents the standard conversion that occurs after - /// the actual user-defined conversion. - StandardConversionSequence After; - - /// ConversionFunction - The function that will perform the - /// user-defined conversion. - FunctionDecl* ConversionFunction; - - void DebugPrint() const; - }; - - /// Represents an ambiguous user-defined conversion sequence. - struct AmbiguousConversionSequence { - typedef llvm::SmallVector ConversionSet; - - void *FromTypePtr; - void *ToTypePtr; - char Buffer[sizeof(ConversionSet)]; - - QualType getFromType() const { - return QualType::getFromOpaquePtr(FromTypePtr); - } - QualType getToType() const { - return QualType::getFromOpaquePtr(ToTypePtr); - } - void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } - void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); } - - ConversionSet &conversions() { - return *reinterpret_cast(Buffer); - } - - const ConversionSet &conversions() const { - return *reinterpret_cast(Buffer); - } - - void addConversion(FunctionDecl *D) { - conversions().push_back(D); - } - - typedef ConversionSet::iterator iterator; - iterator begin() { return conversions().begin(); } - iterator end() { return conversions().end(); } - - typedef ConversionSet::const_iterator const_iterator; - const_iterator begin() const { return conversions().begin(); } - const_iterator end() const { return conversions().end(); } - - void construct(); - void destruct(); - void copyFrom(const AmbiguousConversionSequence &); - }; - - /// BadConversionSequence - Records information about an invalid - /// conversion sequence. - struct BadConversionSequence { - enum FailureKind { - no_conversion, - unrelated_class, - suppressed_user, - bad_qualifiers - }; - - // This can be null, e.g. for implicit object arguments. - Expr *FromExpr; - - FailureKind Kind; - - private: - // The type we're converting from (an opaque QualType). - void *FromTy; - - // The type we're converting to (an opaque QualType). - void *ToTy; - - public: - void init(FailureKind K, Expr *From, QualType To) { - init(K, From->getType(), To); - FromExpr = From; - } - void init(FailureKind K, QualType From, QualType To) { - Kind = K; - FromExpr = 0; - setFromType(From); - setToType(To); - } - - QualType getFromType() const { return QualType::getFromOpaquePtr(FromTy); } - QualType getToType() const { return QualType::getFromOpaquePtr(ToTy); } - - void setFromExpr(Expr *E) { - FromExpr = E; - setFromType(E->getType()); - } - void setFromType(QualType T) { FromTy = T.getAsOpaquePtr(); } - void setToType(QualType T) { ToTy = T.getAsOpaquePtr(); } - }; - - /// ImplicitConversionSequence - Represents an implicit conversion - /// sequence, which may be a standard conversion sequence - /// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2), - /// or an ellipsis conversion sequence (C++ 13.3.3.1.3). - struct ImplicitConversionSequence { - /// Kind - The kind of implicit conversion sequence. BadConversion - /// specifies that there is no conversion from the source type to - /// the target type. AmbiguousConversion represents the unique - /// ambiguous conversion (C++0x [over.best.ics]p10). - enum Kind { - StandardConversion = 0, - UserDefinedConversion, - AmbiguousConversion, - EllipsisConversion, - BadConversion - }; - - private: - enum { - Uninitialized = BadConversion + 1 - }; - - /// ConversionKind - The kind of implicit conversion sequence. - unsigned ConversionKind; - - void setKind(Kind K) { - destruct(); - ConversionKind = K; - } - - void destruct() { - if (ConversionKind == AmbiguousConversion) Ambiguous.destruct(); - } - - public: - union { - /// When ConversionKind == StandardConversion, provides the - /// details of the standard conversion sequence. - StandardConversionSequence Standard; - - /// When ConversionKind == UserDefinedConversion, provides the - /// details of the user-defined conversion sequence. - UserDefinedConversionSequence UserDefined; - - /// When ConversionKind == AmbiguousConversion, provides the - /// details of the ambiguous conversion. - AmbiguousConversionSequence Ambiguous; - - /// When ConversionKind == BadConversion, provides the details - /// of the bad conversion. - BadConversionSequence Bad; - }; - - ImplicitConversionSequence() : ConversionKind(Uninitialized) {} - ~ImplicitConversionSequence() { - destruct(); - } - ImplicitConversionSequence(const ImplicitConversionSequence &Other) - : ConversionKind(Other.ConversionKind) - { - switch (ConversionKind) { - case Uninitialized: break; - case StandardConversion: Standard = Other.Standard; break; - case UserDefinedConversion: UserDefined = Other.UserDefined; break; - case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break; - case EllipsisConversion: break; - case BadConversion: Bad = Other.Bad; break; - } - } - - ImplicitConversionSequence & - operator=(const ImplicitConversionSequence &Other) { - destruct(); - new (this) ImplicitConversionSequence(Other); - return *this; - } - - Kind getKind() const { - assert(isInitialized() && "querying uninitialized conversion"); - return Kind(ConversionKind); - } - - /// \brief Return a ranking of the implicit conversion sequence - /// kind, where smaller ranks represent better conversion - /// sequences. - /// - /// In particular, this routine gives user-defined conversion - /// sequences and ambiguous conversion sequences the same rank, - /// per C++ [over.best.ics]p10. - unsigned getKindRank() const { - switch (getKind()) { - case StandardConversion: - return 0; - - case UserDefinedConversion: - case AmbiguousConversion: - return 1; - - case EllipsisConversion: - return 2; - - case BadConversion: - return 3; - } - - return 3; - } - - bool isBad() const { return getKind() == BadConversion; } - bool isStandard() const { return getKind() == StandardConversion; } - bool isEllipsis() const { return getKind() == EllipsisConversion; } - bool isAmbiguous() const { return getKind() == AmbiguousConversion; } - bool isUserDefined() const { return getKind() == UserDefinedConversion; } - - /// Determines whether this conversion sequence has been - /// initialized. Most operations should never need to query - /// uninitialized conversions and should assert as above. - bool isInitialized() const { return ConversionKind != Uninitialized; } - - /// Sets this sequence as a bad conversion for an explicit argument. - void setBad(BadConversionSequence::FailureKind Failure, - Expr *FromExpr, QualType ToType) { - setKind(BadConversion); - Bad.init(Failure, FromExpr, ToType); - } - - /// Sets this sequence as a bad conversion for an implicit argument. - void setBad(BadConversionSequence::FailureKind Failure, - QualType FromType, QualType ToType) { - setKind(BadConversion); - Bad.init(Failure, FromType, ToType); - } - - void setStandard() { setKind(StandardConversion); } - void setEllipsis() { setKind(EllipsisConversion); } - void setUserDefined() { setKind(UserDefinedConversion); } - void setAmbiguous() { - if (ConversionKind == AmbiguousConversion) return; - ConversionKind = AmbiguousConversion; - Ambiguous.construct(); - } - - // The result of a comparison between implicit conversion - // sequences. Use Sema::CompareImplicitConversionSequences to - // actually perform the comparison. - enum CompareKind { - Better = -1, - Indistinguishable = 0, - Worse = 1 - }; - - void DebugPrint() const; - }; - - enum OverloadFailureKind { - ovl_fail_too_many_arguments, - ovl_fail_too_few_arguments, - ovl_fail_bad_conversion, - ovl_fail_bad_deduction, - - /// This conversion candidate was not considered because it - /// duplicates the work of a trivial or derived-to-base - /// conversion. - ovl_fail_trivial_conversion, - - /// This conversion candidate is not viable because its result - /// type is not implicitly convertible to the desired type. - ovl_fail_bad_final_conversion, - - /// This conversion function template specialization candidate is not - /// viable because the final conversion was not an exact match. - ovl_fail_final_conversion_not_exact - }; - - /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). - struct OverloadCandidate { - /// Function - The actual function that this candidate - /// represents. When NULL, this is a built-in candidate - /// (C++ [over.oper]) or a surrogate for a conversion to a - /// function pointer or reference (C++ [over.call.object]). - FunctionDecl *Function; - - /// FoundDecl - The original declaration that was looked up / - /// invented / otherwise found, together with its access. - /// Might be a UsingShadowDecl or a FunctionTemplateDecl. - DeclAccessPair FoundDecl; - - // BuiltinTypes - Provides the return and parameter types of a - // built-in overload candidate. Only valid when Function is NULL. - struct { - QualType ResultTy; - QualType ParamTypes[3]; - } BuiltinTypes; - - /// Surrogate - The conversion function for which this candidate - /// is a surrogate, but only if IsSurrogate is true. - CXXConversionDecl *Surrogate; - - /// Conversions - The conversion sequences used to convert the - /// function arguments to the function parameters. - llvm::SmallVector Conversions; - - /// Viable - True to indicate that this overload candidate is viable. - bool Viable; - - /// IsSurrogate - True to indicate that this candidate is a - /// surrogate for a conversion to a function pointer or reference - /// (C++ [over.call.object]). - bool IsSurrogate; - - /// IgnoreObjectArgument - True to indicate that the first - /// argument's conversion, which for this function represents the - /// implicit object argument, should be ignored. This will be true - /// when the candidate is a static member function (where the - /// implicit object argument is just a placeholder) or a - /// non-static member function when the call doesn't have an - /// object argument. - bool IgnoreObjectArgument; - - /// FailureKind - The reason why this candidate is not viable. - /// Actually an OverloadFailureKind. - unsigned char FailureKind; - - /// A structure used to record information about a failed - /// template argument deduction. - struct DeductionFailureInfo { - // A Sema::TemplateDeductionResult. - unsigned Result; - - /// \brief Opaque pointer containing additional data about - /// this deduction failure. - void *Data; - - /// \brief Retrieve the template parameter this deduction failure - /// refers to, if any. - TemplateParameter getTemplateParameter(); - - /// \brief Retrieve the template argument list associated with this - /// deduction failure, if any. - TemplateArgumentList *getTemplateArgumentList(); - - /// \brief Return the first template argument this deduction failure - /// refers to, if any. - const TemplateArgument *getFirstArg(); - - /// \brief Return the second template argument this deduction failure - /// refers to, if any. - const TemplateArgument *getSecondArg(); - - /// \brief Free any memory associated with this deduction failure. - void Destroy(); - }; - - union { - DeductionFailureInfo DeductionFailure; - - /// FinalConversion - For a conversion function (where Function is - /// a CXXConversionDecl), the standard conversion that occurs - /// after the call to the overload candidate to convert the result - /// of calling the conversion function to the required type. - StandardConversionSequence FinalConversion; - }; - - /// hasAmbiguousConversion - Returns whether this overload - /// candidate requires an ambiguous conversion or not. - bool hasAmbiguousConversion() const { - for (llvm::SmallVectorImpl::const_iterator - I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { - if (!I->isInitialized()) return false; - if (I->isAmbiguous()) return true; - } - return false; - } - }; - - /// OverloadCandidateSet - A set of overload candidates, used in C++ - /// overload resolution (C++ 13.3). - class OverloadCandidateSet : public llvm::SmallVector { - typedef llvm::SmallVector inherited; - llvm::SmallPtrSet Functions; - - SourceLocation Loc; - - OverloadCandidateSet(const OverloadCandidateSet &); - OverloadCandidateSet &operator=(const OverloadCandidateSet &); - - public: - OverloadCandidateSet(SourceLocation Loc) : Loc(Loc) {} - - SourceLocation getLocation() const { return Loc; } - - /// \brief Determine when this overload candidate will be new to the - /// overload set. - bool isNewCandidate(Decl *F) { - return Functions.insert(F->getCanonicalDecl()); - } - - /// \brief Clear out all of the candidates. - void clear(); - - ~OverloadCandidateSet() { clear(); } - }; -} // end namespace clang - -#endif // LLVM_CLANG_SEMA_OVERLOAD_H diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 9c8f48b..083e4db 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -11,8 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "Sema.h" -#include "SemaInit.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/Initialization.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -26,19 +28,11 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" using namespace clang; +using namespace sema; -Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) { - Expr *E = expr->takeAs(); +StmtResult Sema::ActOnExprStmt(FullExprArg expr) { + Expr *E = expr.get(); assert(E && "ActOnExprStmt(): missing expression"); - if (E->getType()->isObjCObjectType()) { - if (LangOpts.ObjCNonFragileABI) - Diag(E->getLocEnd(), diag::err_indirection_requires_nonfragile_object) - << E->getType(); - else - Diag(E->getLocEnd(), diag::err_direct_interface_unsupported) - << E->getType(); - return StmtError(); - } // C99 6.8.3p2: The expression in an expression statement is evaluated as a // void expression for its side effects. Conversion to void allows any // operand, even incomplete types. @@ -48,11 +42,11 @@ Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) { } -Sema::OwningStmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc) { +StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc) { return Owned(new (Context) NullStmt(SemiLoc)); } -Sema::OwningStmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, +StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc, SourceLocation EndLoc) { DeclGroupRef DG = dg.getAsVal(); @@ -141,10 +135,10 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } } - Diag(Loc, DiagID) << R1 << R2; + DiagRuntimeBehavior(Loc, PDiag(DiagID) << R1 << R2); } -Action::OwningStmtResult +StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, MultiStmtArg elts, bool isStmtExpr) { unsigned NumElts = elts.size(); @@ -179,70 +173,60 @@ Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, return Owned(new (Context) CompoundStmt(Context, Elts, NumElts, L, R)); } -Action::OwningStmtResult -Sema::ActOnCaseStmt(SourceLocation CaseLoc, ExprArg lhsval, - SourceLocation DotDotDotLoc, ExprArg rhsval, +StmtResult +Sema::ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, + SourceLocation DotDotDotLoc, Expr *RHSVal, SourceLocation ColonLoc) { - assert((lhsval.get() != 0) && "missing expression in case statement"); + assert((LHSVal != 0) && "missing expression in case statement"); // C99 6.8.4.2p3: The expression shall be an integer constant. // However, GCC allows any evaluatable integer expression. - Expr *LHSVal = static_cast(lhsval.get()); if (!LHSVal->isTypeDependent() && !LHSVal->isValueDependent() && VerifyIntegerConstantExpression(LHSVal)) return StmtError(); // GCC extension: The expression shall be an integer constant. - Expr *RHSVal = static_cast(rhsval.get()); if (RHSVal && !RHSVal->isTypeDependent() && !RHSVal->isValueDependent() && VerifyIntegerConstantExpression(RHSVal)) { RHSVal = 0; // Recover by just forgetting about it. - rhsval = 0; } - if (getSwitchStack().empty()) { + if (getCurFunction()->SwitchStack.empty()) { Diag(CaseLoc, diag::err_case_not_in_switch); return StmtError(); } - // Only now release the smart pointers. - lhsval.release(); - rhsval.release(); CaseStmt *CS = new (Context) CaseStmt(LHSVal, RHSVal, CaseLoc, DotDotDotLoc, ColonLoc); - getSwitchStack().back()->addSwitchCase(CS); + getCurFunction()->SwitchStack.back()->addSwitchCase(CS); return Owned(CS); } /// ActOnCaseStmtBody - This installs a statement as the body of a case. -void Sema::ActOnCaseStmtBody(StmtTy *caseStmt, StmtArg subStmt) { +void Sema::ActOnCaseStmtBody(Stmt *caseStmt, Stmt *SubStmt) { CaseStmt *CS = static_cast(caseStmt); - Stmt *SubStmt = subStmt.takeAs(); CS->setSubStmt(SubStmt); } -Action::OwningStmtResult +StmtResult Sema::ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, - StmtArg subStmt, Scope *CurScope) { - Stmt *SubStmt = subStmt.takeAs(); - - if (getSwitchStack().empty()) { + Stmt *SubStmt, Scope *CurScope) { + if (getCurFunction()->SwitchStack.empty()) { Diag(DefaultLoc, diag::err_default_not_in_switch); return Owned(SubStmt); } DefaultStmt *DS = new (Context) DefaultStmt(DefaultLoc, ColonLoc, SubStmt); - getSwitchStack().back()->addSwitchCase(DS); + getCurFunction()->SwitchStack.back()->addSwitchCase(DS); return Owned(DS); } -Action::OwningStmtResult +StmtResult Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, - SourceLocation ColonLoc, StmtArg subStmt) { - Stmt *SubStmt = subStmt.takeAs(); + SourceLocation ColonLoc, Stmt *SubStmt) { // Look up the record for this label identifier. - LabelStmt *&LabelDecl = getLabelMap()[II]; + LabelStmt *&LabelDecl = getCurFunction()->LabelMap[II]; // If not forward referenced or defined already, just create a new LabelStmt. if (LabelDecl == 0) @@ -265,15 +249,15 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, IdentifierInfo *II, return Owned(LabelDecl); } -Action::OwningStmtResult -Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar, - StmtArg ThenVal, SourceLocation ElseLoc, - StmtArg ElseVal) { - OwningExprResult CondResult(CondVal.release()); +StmtResult +Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, + Stmt *thenStmt, SourceLocation ElseLoc, + Stmt *elseStmt) { + ExprResult CondResult(CondVal.release()); VarDecl *ConditionVar = 0; - if (CondVar.get()) { - ConditionVar = CondVar.getAs(); + if (CondVar) { + ConditionVar = cast(CondVar); CondResult = CheckConditionVariable(ConditionVar, IfLoc, true); if (CondResult.isInvalid()) return StmtError(); @@ -282,22 +266,19 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, DeclPtrTy CondVar, if (!ConditionExpr) return StmtError(); - Stmt *thenStmt = ThenVal.takeAs(); DiagnoseUnusedExprResult(thenStmt); // Warn if the if block has a null body without an else value. // this helps prevent bugs due to typos, such as // if (condition); // do_stuff(); - if (!ElseVal.get()) { + if (!elseStmt) { if (NullStmt* stmt = dyn_cast(thenStmt)) Diag(stmt->getSemiLoc(), diag::warn_empty_if_body); } - Stmt *elseStmt = ElseVal.takeAs(); DiagnoseUnusedExprResult(elseStmt); - CondResult.release(); return Owned(new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr, thenStmt, ElseLoc, elseStmt)); } @@ -404,64 +385,63 @@ static QualType GetTypeBeforeIntegralPromotion(const Expr* expr) { return expr->getType(); } -Action::OwningStmtResult -Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, ExprArg Cond, - DeclPtrTy CondVar) { +StmtResult +Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, + Decl *CondVar) { + ExprResult CondResult; + VarDecl *ConditionVar = 0; - if (CondVar.get()) { - ConditionVar = CondVar.getAs(); - OwningExprResult CondE = CheckConditionVariable(ConditionVar, SourceLocation(), false); - if (CondE.isInvalid()) + if (CondVar) { + ConditionVar = cast(CondVar); + CondResult = CheckConditionVariable(ConditionVar, SourceLocation(), false); + if (CondResult.isInvalid()) return StmtError(); - Cond = move(CondE); + Cond = CondResult.release(); } - if (!Cond.get()) + if (!Cond) return StmtError(); - Expr *CondExpr = static_cast(Cond.get()); - OwningExprResult ConvertedCond - = ConvertToIntegralOrEnumerationType(SwitchLoc, move(Cond), + CondResult + = ConvertToIntegralOrEnumerationType(SwitchLoc, Cond, PDiag(diag::err_typecheck_statement_requires_integer), PDiag(diag::err_switch_incomplete_class_type) - << CondExpr->getSourceRange(), + << Cond->getSourceRange(), PDiag(diag::err_switch_explicit_conversion), PDiag(diag::note_switch_conversion), PDiag(diag::err_switch_multiple_conversions), PDiag(diag::note_switch_conversion), PDiag(0)); - if (ConvertedCond.isInvalid()) - return StmtError(); + if (CondResult.isInvalid()) return StmtError(); + Cond = CondResult.take(); - CondExpr = ConvertedCond.takeAs(); - - if (!CondVar.get()) { - CondExpr = MaybeCreateCXXExprWithTemporaries(CondExpr); - if (!CondExpr) + if (!CondVar) { + CondResult = MaybeCreateCXXExprWithTemporaries(Cond); + if (CondResult.isInvalid()) return StmtError(); + Cond = CondResult.take(); } + + getCurFunction()->setHasBranchIntoScope(); - SwitchStmt *SS = new (Context) SwitchStmt(Context, ConditionVar, CondExpr); - getSwitchStack().push_back(SS); + SwitchStmt *SS = new (Context) SwitchStmt(Context, ConditionVar, Cond); + getCurFunction()->SwitchStack.push_back(SS); return Owned(SS); } -Action::OwningStmtResult -Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, - StmtArg Body) { - Stmt *BodyStmt = Body.takeAs(); - - SwitchStmt *SS = getSwitchStack().back(); - assert(SS == (SwitchStmt*)Switch.get() && "switch stack missing push/pop!"); +StmtResult +Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, + Stmt *BodyStmt) { + SwitchStmt *SS = cast(Switch); + assert(SS == getCurFunction()->SwitchStack.back() && + "switch stack missing push/pop!"); SS->setBody(BodyStmt, SwitchLoc); - getSwitchStack().pop_back(); + getCurFunction()->SwitchStack.pop_back(); - if (SS->getCond() == 0) { - SS->Destroy(Context); + if (SS->getCond() == 0) return StmtError(); - } Expr *CondExpr = SS->getCond(); Expr *CondExprBeforePromotion = CondExpr; @@ -556,7 +536,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // If the LHS is not the same type as the condition, insert an implicit // cast. - ImpCastExprToType(Lo, CondType, CastExpr::CK_IntegralCast); + ImpCastExprToType(Lo, CondType, CK_IntegralCast); CS->setLHS(Lo); // If this is a case range, remember it in CaseRanges, otherwise CaseVals. @@ -635,7 +615,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, // If the LHS is not the same type as the condition, insert an implicit // cast. - ImpCastExprToType(Hi, CondType, CastExpr::CK_IntegralCast); + ImpCastExprToType(Hi, CondType, CK_IntegralCast); CR->setRHS(Hi); // If the low value is bigger than the high value, the case is empty. @@ -804,65 +784,55 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, StmtArg Switch, if (CaseListIsErroneous) return StmtError(); - Switch.release(); return Owned(SS); } -Action::OwningStmtResult +StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, - DeclPtrTy CondVar, StmtArg Body) { - OwningExprResult CondResult(Cond.release()); + Decl *CondVar, Stmt *Body) { + ExprResult CondResult(Cond.release()); VarDecl *ConditionVar = 0; - if (CondVar.get()) { - ConditionVar = CondVar.getAs(); + if (CondVar) { + ConditionVar = cast(CondVar); CondResult = CheckConditionVariable(ConditionVar, WhileLoc, true); if (CondResult.isInvalid()) return StmtError(); } - Expr *ConditionExpr = CondResult.takeAs(); + Expr *ConditionExpr = CondResult.take(); if (!ConditionExpr) return StmtError(); - Stmt *bodyStmt = Body.takeAs(); - DiagnoseUnusedExprResult(bodyStmt); + DiagnoseUnusedExprResult(Body); - CondResult.release(); return Owned(new (Context) WhileStmt(Context, ConditionVar, ConditionExpr, - bodyStmt, WhileLoc)); + Body, WhileLoc)); } -Action::OwningStmtResult -Sema::ActOnDoStmt(SourceLocation DoLoc, StmtArg Body, +StmtResult +Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, SourceLocation WhileLoc, SourceLocation CondLParen, - ExprArg Cond, SourceLocation CondRParen) { - Expr *condExpr = Cond.takeAs(); - assert(condExpr && "ActOnDoStmt(): missing expression"); + Expr *Cond, SourceLocation CondRParen) { + assert(Cond && "ActOnDoStmt(): missing expression"); - if (CheckBooleanCondition(condExpr, DoLoc)) { - Cond = condExpr; + if (CheckBooleanCondition(Cond, DoLoc)) return StmtError(); - } - condExpr = MaybeCreateCXXExprWithTemporaries(condExpr); - if (!condExpr) + ExprResult CondResult = MaybeCreateCXXExprWithTemporaries(Cond); + if (CondResult.isInvalid()) return StmtError(); + Cond = CondResult.take(); - Stmt *bodyStmt = Body.takeAs(); - DiagnoseUnusedExprResult(bodyStmt); + DiagnoseUnusedExprResult(Body); - Cond.release(); - return Owned(new (Context) DoStmt(bodyStmt, condExpr, DoLoc, - WhileLoc, CondRParen)); + return Owned(new (Context) DoStmt(Body, Cond, DoLoc, WhileLoc, CondRParen)); } -Action::OwningStmtResult +StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - StmtArg first, FullExprArg second, DeclPtrTy secondVar, + Stmt *First, FullExprArg second, Decl *secondVar, FullExprArg third, - SourceLocation RParenLoc, StmtArg body) { - Stmt *First = static_cast(first.get()); - + SourceLocation RParenLoc, Stmt *Body) { if (!getLangOptions().CPlusPlus) { if (DeclStmt *DS = dyn_cast_or_null(First)) { // C99 6.8.5p3: The declaration part of a 'for' statement shall only @@ -880,38 +850,32 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, } } - OwningExprResult SecondResult(second.release()); + ExprResult SecondResult(second.release()); VarDecl *ConditionVar = 0; - if (secondVar.get()) { - ConditionVar = secondVar.getAs(); + if (secondVar) { + ConditionVar = cast(secondVar); SecondResult = CheckConditionVariable(ConditionVar, ForLoc, true); if (SecondResult.isInvalid()) return StmtError(); } Expr *Third = third.release().takeAs(); - Stmt *Body = static_cast(body.get()); DiagnoseUnusedExprResult(First); DiagnoseUnusedExprResult(Third); DiagnoseUnusedExprResult(Body); - first.release(); - body.release(); return Owned(new (Context) ForStmt(Context, First, - SecondResult.takeAs(), ConditionVar, + SecondResult.take(), ConditionVar, Third, Body, ForLoc, LParenLoc, RParenLoc)); } -Action::OwningStmtResult +StmtResult Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - StmtArg first, ExprArg second, - SourceLocation RParenLoc, StmtArg body) { - Stmt *First = static_cast(first.get()); - Expr *Second = static_cast(second.get()); - Stmt *Body = static_cast(body.get()); + Stmt *First, Expr *Second, + SourceLocation RParenLoc, Stmt *Body) { if (First) { QualType FirstType; if (DeclStmt *DS = dyn_cast(First)) { @@ -950,19 +914,39 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, if (!SecondType->isObjCObjectPointerType()) Diag(ForLoc, diag::err_collection_expr_type) << SecondType << Second->getSourceRange(); + else if (const ObjCObjectPointerType *OPT = + SecondType->getAsObjCInterfacePointerType()) { + llvm::SmallVector KeyIdents; + IdentifierInfo* selIdent = + &Context.Idents.get("countByEnumeratingWithState"); + KeyIdents.push_back(selIdent); + selIdent = &Context.Idents.get("objects"); + KeyIdents.push_back(selIdent); + selIdent = &Context.Idents.get("count"); + KeyIdents.push_back(selIdent); + Selector CSelector = Context.Selectors.getSelector(3, &KeyIdents[0]); + if (ObjCInterfaceDecl *IDecl = OPT->getInterfaceDecl()) { + if (!IDecl->isForwardDecl() && + !IDecl->lookupInstanceMethod(CSelector)) { + // Must further look into private implementation methods. + if (!LookupPrivateInstanceMethod(CSelector, IDecl)) + Diag(ForLoc, diag::warn_collection_expr_type) + << SecondType << CSelector << Second->getSourceRange(); + } + } + } } - first.release(); - second.release(); - body.release(); return Owned(new (Context) ObjCForCollectionStmt(First, Second, Body, ForLoc, RParenLoc)); } -Action::OwningStmtResult +StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, IdentifierInfo *LabelII) { // Look up the record for this label identifier. - LabelStmt *&LabelDecl = getLabelMap()[LabelII]; + LabelStmt *&LabelDecl = getCurFunction()->LabelMap[LabelII]; + + getCurFunction()->setHasBranchIntoScope(); // If we haven't seen this label yet, create a forward reference. if (LabelDecl == 0) @@ -971,11 +955,10 @@ Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, return Owned(new (Context) GotoStmt(LabelDecl, GotoLoc, LabelLoc)); } -Action::OwningStmtResult +StmtResult Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, - ExprArg DestExp) { + Expr *E) { // Convert operand to void* - Expr* E = DestExp.takeAs(); if (!E->isTypeDependent()) { QualType ETy = E->getType(); QualType DestTy = Context.getPointerType(Context.VoidTy.withConst()); @@ -984,10 +967,13 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, if (DiagnoseAssignmentResult(ConvTy, StarLoc, DestTy, ETy, E, AA_Passing)) return StmtError(); } + + getCurFunction()->setHasIndirectGoto(); + return Owned(new (Context) IndirectGotoStmt(GotoLoc, StarLoc, E)); } -Action::OwningStmtResult +StmtResult Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) { Scope *S = CurScope->getContinueParent(); if (!S) { @@ -998,7 +984,7 @@ Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) { return Owned(new (Context) ContinueStmt(ContinueLoc)); } -Action::OwningStmtResult +StmtResult Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { Scope *S = CurScope->getBreakParent(); if (!S) { @@ -1050,7 +1036,7 @@ static const VarDecl *getNRVOCandidate(ASTContext &Ctx, QualType RetType, /// ActOnBlockReturnStmt - Utility routine to figure out block's return type. /// -Action::OwningStmtResult +StmtResult Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // If this is the first return we've seen in the block, infer the type of // the block from it. @@ -1086,7 +1072,6 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (CurBlock->ReturnType->isVoidType()) { if (RetValExp) { Diag(ReturnLoc, diag::err_return_block_has_expr); - RetValExp->Destroy(Context); RetValExp = 0; } Result = new (Context) ReturnStmt(ReturnLoc, RetValExp, 0); @@ -1105,7 +1090,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp); - OwningExprResult Res = PerformCopyInitialization( + ExprResult Res = PerformCopyInitialization( InitializedEntity::InitializeResult(ReturnLoc, FnRetType, NRVOCandidate != 0), @@ -1136,9 +1121,8 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { return Owned(Result); } -Action::OwningStmtResult -Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { - Expr *RetValExp = rex.takeAs(); +StmtResult +Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (getCurBlock()) return ActOnBlockReturnStmt(ReturnLoc, RetValExp); @@ -1197,7 +1181,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. NRVOCandidate = getNRVOCandidate(Context, FnRetType, RetValExp); - OwningExprResult Res = PerformCopyInitialization( + ExprResult Res = PerformCopyInitialization( InitializedEntity::InitializeResult(ReturnLoc, FnRetType, NRVOCandidate != 0), @@ -1261,7 +1245,7 @@ static bool CheckAsmLValue(const Expr *E, Sema &S) { } -Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, +StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, @@ -1269,15 +1253,15 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, IdentifierInfo **Names, MultiExprArg constraints, MultiExprArg exprs, - ExprArg asmString, + Expr *asmString, MultiExprArg clobbers, SourceLocation RParenLoc, bool MSAsm) { unsigned NumClobbers = clobbers.size(); StringLiteral **Constraints = reinterpret_cast(constraints.get()); - Expr **Exprs = reinterpret_cast(exprs.get()); - StringLiteral *AsmString = cast((Expr *)asmString.get()); + Expr **Exprs = exprs.get(); + StringLiteral *AsmString = cast(asmString); StringLiteral **Clobbers = reinterpret_cast(clobbers.get()); llvm::SmallVector OutputConstraintInfos; @@ -1373,10 +1357,6 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, diag::err_asm_unknown_register_name) << Clobber); } - constraints.release(); - exprs.release(); - asmString.release(); - clobbers.release(); AsmStmt *NS = new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm, NumOutputs, NumInputs, Names, Constraints, Exprs, @@ -1388,7 +1368,6 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) { Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID) << AsmString->getSourceRange(); - DeleteStmt(NS); return StmtError(); } @@ -1479,45 +1458,41 @@ Sema::OwningStmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, diag::err_asm_tying_incompatible_types) << InTy << OutTy << OutputExpr->getSourceRange() << InputExpr->getSourceRange(); - DeleteStmt(NS); return StmtError(); } return Owned(NS); } -Action::OwningStmtResult +StmtResult Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc, - SourceLocation RParen, DeclPtrTy Parm, - StmtArg Body) { - VarDecl *Var = cast_or_null(Parm.getAs()); + SourceLocation RParen, Decl *Parm, + Stmt *Body) { + VarDecl *Var = cast_or_null(Parm); if (Var && Var->isInvalidDecl()) return StmtError(); - return Owned(new (Context) ObjCAtCatchStmt(AtLoc, RParen, Var, - Body.takeAs())); + return Owned(new (Context) ObjCAtCatchStmt(AtLoc, RParen, Var, Body)); } -Action::OwningStmtResult -Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, StmtArg Body) { - return Owned(new (Context) ObjCAtFinallyStmt(AtLoc, - static_cast(Body.release()))); +StmtResult +Sema::ActOnObjCAtFinallyStmt(SourceLocation AtLoc, Stmt *Body) { + return Owned(new (Context) ObjCAtFinallyStmt(AtLoc, Body)); } -Action::OwningStmtResult -Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, StmtArg Try, - MultiStmtArg CatchStmts, StmtArg Finally) { - FunctionNeedsScopeChecking() = true; +StmtResult +Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, + MultiStmtArg CatchStmts, Stmt *Finally) { + getCurFunction()->setHasBranchProtectedScope(); unsigned NumCatchStmts = CatchStmts.size(); - return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try.takeAs(), - (Stmt **)CatchStmts.release(), + return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try, + CatchStmts.release(), NumCatchStmts, - Finally.takeAs())); + Finally)); } -Sema::OwningStmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, - ExprArg ThrowE) { - Expr *Throw = static_cast(ThrowE.get()); +StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, + Expr *Throw) { if (Throw) { QualType ThrowType = Throw->getType(); // Make sure the expression type is an ObjC pointer or "void *". @@ -1530,13 +1505,13 @@ Sema::OwningStmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, } } - return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowE.takeAs())); + return Owned(new (Context) ObjCAtThrowStmt(AtLoc, Throw)); } -Action::OwningStmtResult -Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg Throw, +StmtResult +Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, Scope *CurScope) { - if (!Throw.get()) { + if (!Throw) { // @throw without an expression designates a rethrow (which much occur // in the context of an @catch clause). Scope *AtCatchParent = CurScope; @@ -1546,16 +1521,15 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg Throw, return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch)); } - return BuildObjCAtThrowStmt(AtLoc, move(Throw)); + return BuildObjCAtThrowStmt(AtLoc, Throw); } -Action::OwningStmtResult -Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr, - StmtArg SynchBody) { - FunctionNeedsScopeChecking() = true; +StmtResult +Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr, + Stmt *SyncBody) { + getCurFunction()->setHasBranchProtectedScope(); // Make sure the expression type is an ObjC pointer or "void *". - Expr *SyncExpr = static_cast(SynchExpr.get()); if (!SyncExpr->getType()->isDependentType() && !SyncExpr->getType()->isObjCObjectPointerType()) { const PointerType *PT = SyncExpr->getType()->getAs(); @@ -1564,22 +1538,22 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprArg SynchExpr, << SyncExpr->getType() << SyncExpr->getSourceRange()); } - return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc, - SynchExpr.takeAs(), - SynchBody.takeAs())); + return Owned(new (Context) ObjCAtSynchronizedStmt(AtLoc, SyncExpr, SyncBody)); } /// ActOnCXXCatchBlock - Takes an exception declaration and a handler block /// and creates a proper catch handler from them. -Action::OwningStmtResult -Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, DeclPtrTy ExDecl, - StmtArg HandlerBlock) { +StmtResult +Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, Decl *ExDecl, + Stmt *HandlerBlock) { // There's nothing to test that ActOnExceptionDecl didn't already test. return Owned(new (Context) CXXCatchStmt(CatchLoc, - cast_or_null(ExDecl.getAs()), - HandlerBlock.takeAs())); + cast_or_null(ExDecl), + HandlerBlock)); } +namespace { + class TypeWithHandler { QualType t; CXXCatchStmt *stmt; @@ -1602,22 +1576,23 @@ public: return t == other.t; } - QualType getQualType() const { return t; } CXXCatchStmt *getCatchStmt() const { return stmt; } SourceLocation getTypeSpecStartLoc() const { return stmt->getExceptionDecl()->getTypeSpecStartLoc(); } }; +} + /// ActOnCXXTryBlock - Takes a try compound-statement and a number of /// handlers and creates a try statement from them. -Action::OwningStmtResult -Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock, +StmtResult +Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, MultiStmtArg RawHandlers) { unsigned NumHandlers = RawHandlers.size(); assert(NumHandlers > 0 && "The parser shouldn't call this if there are no handlers."); - Stmt **Handlers = reinterpret_cast(RawHandlers.get()); + Stmt **Handlers = RawHandlers.get(); llvm::SmallVector TypesWithHandlers; @@ -1657,15 +1632,14 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock, } } + getCurFunction()->setHasBranchProtectedScope(); + // FIXME: We should detect handlers that cannot catch anything because an // earlier handler catches a superclass. Need to find a method that is not // quadratic for this. // Neither of these are explicitly forbidden, but every compiler detects them // and warns. - FunctionNeedsScopeChecking() = true; - RawHandlers.release(); - return Owned(CXXTryStmt::Create(Context, TryLoc, - static_cast(TryBlock.release()), + return Owned(CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers, NumHandlers)); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f121954..0fc8392 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -9,20 +9,24 @@ // This file implements semantic analysis for C++ templates. //===----------------------------------------------------------------------===/ -#include "Sema.h" -#include "Lookup.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/Template.h" +#include "clang/Sema/TemplateDeduction.h" #include "TreeTransform.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" -#include "clang/Parse/DeclSpec.h" -#include "clang/Parse/Template.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/ParsedTemplate.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/PartialDiagnostic.h" #include "llvm/ADT/StringExtras.h" using namespace clang; +using namespace sema; /// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, @@ -88,8 +92,13 @@ static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) { filter.erase(); continue; } - - filter.replace(Repl); + + // FIXME: we promote access to public here as a workaround to + // the fact that LookupResult doesn't let us remember that we + // found this template through a particular injected class name, + // which means we end up doing nasty things to the invariants. + // Pretending that access is public is *much* safer. + filter.replace(Repl, AS_public); } } filter.done(); @@ -97,8 +106,9 @@ static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) { TemplateNameKind Sema::isTemplateName(Scope *S, CXXScopeSpec &SS, + bool hasTemplateKeyword, UnqualifiedId &Name, - TypeTy *ObjectTypePtr, + ParsedType ObjectTypePtr, bool EnteringContext, TemplateTy &TemplateResult, bool &MemberOfUnknownSpecialization) { @@ -125,15 +135,21 @@ TemplateNameKind Sema::isTemplateName(Scope *S, return TNK_Non_template; } - QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); + QualType ObjectType = ObjectTypePtr.get(); LookupResult R(*this, TName, Name.getSourceRange().getBegin(), LookupOrdinaryName); - R.suppressDiagnostics(); LookupTemplateName(R, S, SS, ObjectType, EnteringContext, MemberOfUnknownSpecialization); - if (R.empty() || R.isAmbiguous()) + if (R.empty()) return TNK_Non_template; + if (R.isAmbiguous()) { + // Suppress diagnostics; we'll redo this lookup later. + R.suppressDiagnostics(); + + // FIXME: we might have ambiguous templates, in which case we + // should at least parse them properly! return TNK_Non_template; + } TemplateName Template; TemplateNameKind TemplateKind; @@ -144,20 +160,27 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // template name in other ways. Template = Context.getOverloadedTemplateName(R.begin(), R.end()); TemplateKind = TNK_Function_template; + + // We'll do this lookup again later. + R.suppressDiagnostics(); } else { TemplateDecl *TD = cast((*R.begin())->getUnderlyingDecl()); if (SS.isSet() && !SS.isInvalid()) { NestedNameSpecifier *Qualifier = static_cast(SS.getScopeRep()); - Template = Context.getQualifiedTemplateName(Qualifier, false, TD); + Template = Context.getQualifiedTemplateName(Qualifier, + hasTemplateKeyword, TD); } else { Template = TemplateName(TD); } - if (isa(TD)) + if (isa(TD)) { TemplateKind = TNK_Function_template; - else { + + // We'll do this lookup again later. + R.suppressDiagnostics(); + } else { assert(isa(TD) || isa(TD)); TemplateKind = TNK_Type_template; } @@ -238,13 +261,10 @@ void Sema::LookupTemplateName(LookupResult &Found, // expression. If the identifier is not found, it is then looked up in // the context of the entire postfix-expression and shall name a class // or function template. - // - // FIXME: When we're instantiating a template, do we actually have to - // look in the scope of the template? Seems fishy... if (S) LookupName(Found, S); ObjectTypeSearchedInScope = true; } - } else if (isDependent) { + } else if (isDependent && (!S || ObjectType.isNull())) { // We cannot look into a dependent object type or nested nme // specifier. MemberOfUnknownSpecialization = true; @@ -282,8 +302,11 @@ void Sema::LookupTemplateName(LookupResult &Found, } FilterAcceptableTemplateNames(Context, Found); - if (Found.empty()) + if (Found.empty()) { + if (isDependent) + MemberOfUnknownSpecialization = true; return; + } if (S && !ObjectType.isNull() && !ObjectTypeSearchedInScope) { // C++ [basic.lookup.classref]p1: @@ -330,10 +353,9 @@ void Sema::LookupTemplateName(LookupResult &Found, /// ActOnDependentIdExpression - Handle a dependent id-expression that /// was just parsed. This is only possible with an explicit scope /// specifier naming a dependent type. -Sema::OwningExprResult +ExprResult Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, - DeclarationName Name, - SourceLocation NameLoc, + const DeclarationNameInfo &NameInfo, bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs) { NestedNameSpecifier *Qualifier @@ -356,22 +378,21 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, /*Op*/ SourceLocation(), Qualifier, SS.getRange(), FirstQualifierInScope, - Name, NameLoc, + NameInfo, TemplateArgs)); } - return BuildDependentDeclRefExpr(SS, Name, NameLoc, TemplateArgs); + return BuildDependentDeclRefExpr(SS, NameInfo, TemplateArgs); } -Sema::OwningExprResult +ExprResult Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS, - DeclarationName Name, - SourceLocation NameLoc, + const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs) { return Owned(DependentScopeDeclRefExpr::Create(Context, static_cast(SS.getScopeRep()), SS.getRange(), - Name, NameLoc, + NameInfo, TemplateArgs)); } @@ -398,9 +419,9 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { /// AdjustDeclIfTemplate - If the given decl happens to be a template, reset /// the parameter D to reference the templated declaration and return a pointer /// to the template declaration. Otherwise, do nothing to D and return null. -TemplateDecl *Sema::AdjustDeclIfTemplate(DeclPtrTy &D) { - if (TemplateDecl *Temp = dyn_cast_or_null(D.getAs())) { - D = DeclPtrTy::make(Temp->getTemplatedDecl()); +TemplateDecl *Sema::AdjustDeclIfTemplate(Decl *&D) { + if (TemplateDecl *Temp = dyn_cast_or_null(D)) { + D = Temp->getTemplatedDecl(); return Temp; } return 0; @@ -424,8 +445,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, } case ParsedTemplateArgument::Template: { - TemplateName Template - = TemplateName::getFromVoidPointer(Arg.getAsTemplate().get()); + TemplateName Template = Arg.getAsTemplate().get(); return TemplateArgumentLoc(TemplateArgument(Template), Arg.getScopeSpec().getRange(), Arg.getLocation()); @@ -454,14 +474,14 @@ void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn, /// ParamName is the location of the parameter name (if any). /// If the type parameter has a default argument, it will be added /// later via ActOnTypeParameterDefault. -Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, - SourceLocation EllipsisLoc, - SourceLocation KeyLoc, - IdentifierInfo *ParamName, - SourceLocation ParamNameLoc, - unsigned Depth, unsigned Position, - SourceLocation EqualLoc, - TypeTy *DefaultArg) { +Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, + SourceLocation EllipsisLoc, + SourceLocation KeyLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, unsigned Position, + SourceLocation EqualLoc, + ParsedType DefaultArg) { assert(S->isTemplateParamScope() && "Template type parameter not in template parameter scope!"); bool Invalid = false; @@ -488,7 +508,7 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, if (ParamName) { // Add the template parameter into the current scope. - S->AddDecl(DeclPtrTy::make(Param)); + S->AddDecl(Param); IdResolver.AddDecl(Param); } @@ -504,19 +524,19 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, // template-parameter that is not a template parameter pack. if (Ellipsis) { Diag(EqualLoc, diag::err_template_param_pack_default_arg); - return DeclPtrTy::make(Param); + return Param; } // Check the template argument itself. if (CheckTemplateArgument(Param, DefaultTInfo)) { Param->setInvalidDecl(); - return DeclPtrTy::make(Param);; + return Param; } Param->setDefaultArgument(DefaultTInfo, false); } - return DeclPtrTy::make(Param); + return Param; } /// \brief Check that the type of a non-type template parameter is @@ -542,9 +562,7 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { // -- integral or enumeration type, if (T->isIntegralOrEnumerationType() || // -- pointer to object or pointer to function, - (T->isPointerType() && - (T->getAs()->getPointeeType()->isObjectType() || - T->getAs()->getPointeeType()->isFunctionType())) || + T->isPointerType() || // -- reference to object or reference to function, T->isReferenceType() || // -- pointer to member. @@ -571,11 +589,11 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { return QualType(); } -Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, - unsigned Depth, - unsigned Position, - SourceLocation EqualLoc, - ExprArg DefaultArg) { +Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, + unsigned Depth, + unsigned Position, + SourceLocation EqualLoc, + Expr *Default) { TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType T = TInfo->getType(); @@ -608,35 +626,35 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, if (D.getIdentifier()) { // Add the template parameter into the current scope. - S->AddDecl(DeclPtrTy::make(Param)); + S->AddDecl(Param); IdResolver.AddDecl(Param); } // Check the well-formedness of the default template argument, if provided. - if (Expr *Default = static_cast(DefaultArg.get())) { + if (Default) { TemplateArgument Converted; if (CheckTemplateArgument(Param, Param->getType(), Default, Converted)) { Param->setInvalidDecl(); - return DeclPtrTy::make(Param);; + return Param; } - Param->setDefaultArgument(DefaultArg.takeAs(), false); + Param->setDefaultArgument(Default, false); } - return DeclPtrTy::make(Param); + return Param; } /// ActOnTemplateTemplateParameter - Called when a C++ template template /// parameter (e.g. T in template