We found that the IR IRGen emits when expanding __builtin_os_log_format is quite big and has a lot of redundancy.
For example, when clang compiles the following code:
void foo1(void *buf) { __builtin_os_log_format(buf, "%d %d", 11, 22); }
The IR looks like this:
define void @foo1(i8* %buf) #0 { entry: %buf.addr = alloca i8*, align 8 store i8* %buf, i8** %buf.addr, align 8 %0 = load i8*, i8** %buf.addr, align 8 %summary = getelementptr i8, i8* %0, i64 0 store i8 0, i8* %summary, align 1 %numArgs = getelementptr i8, i8* %0, i64 1 store i8 2, i8* %numArgs, align 1 %argDescriptor = getelementptr i8, i8* %0, i64 2 store i8 0, i8* %argDescriptor, align 1 %argSize = getelementptr i8, i8* %0, i64 3 store i8 4, i8* %argSize, align 1 %1 = getelementptr i8, i8* %0, i64 4 %2 = bitcast i8* %1 to i32* store i32 11, i32* %2, align 1 %argDescriptor1 = getelementptr i8, i8* %0, i64 8 store i8 0, i8* %argDescriptor1, align 1 %argSize2 = getelementptr i8, i8* %0, i64 9 store i8 4, i8* %argSize2, align 1 %3 = getelementptr i8, i8* %0, i64 10 %4 = bitcast i8* %3 to i32* store i32 22, i32* %4, align 1 ret void }
The IR generated when compiling a similar call like "__builtin_os_log_format(buf, "%d %d", 33, 44)" is almost the same except for the values of the integer constants stored, so there is an opportunity for code reductionton here.
To reduce code size, this patch modifies IRGen to emit a helper function that can be used by different call sites that call __builtin_os_log_format in a program. When compiling with -Oz, the generated helper function is marked as linkonce_odr, hidden, and noinline so that the linker can merge identical helper functions from different translation units. When compiling with other optimization levels, the function is marked as 'internal' and the generated IR should look mostly the same after inlining.
This patch also fixes a bug where the generated IR writes past the buffer when %m is the last directive. For example, the size of 'buf' in the following code is 4 but IRGen emits a store that writes a 4-byte value at buf+4.
char buf[__builtin_os_log_format_buffer_size("%m")]; __builtin_os_log_format(buf, "%m");
Original patch was written by Duncan.
rdar://problem/34065973
dar://problem/34196543