const Expr *E = nullptr;
Optional<OSLogBufferItem::Kind> Kind;
Optional<unsigned> Size;
+ Optional<const Expr *> Count;
+ Optional<const Expr *> Precision;
+ Optional<const Expr *> FieldWidth;
unsigned char Flags = 0;
};
SmallVector<ArgData, 4> ArgsData;
ArgsData.back().Size = precision.getConstantAmount();
break;
case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"
- ArgsData.back().Kind = OSLogBufferItem::CountKind;
+ ArgsData.back().Count = Args[precision.getArgIndex()];
break;
case clang::analyze_format_string::OptionalAmount::Invalid:
return false;
ArgsData.back().Size = precision.getConstantAmount();
break;
case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"
- ArgsData.back().Kind = OSLogBufferItem::CountKind;
+ ArgsData.back().Count = Args[precision.getArgIndex()];
break;
case clang::analyze_format_string::OptionalAmount::Invalid:
return false;
break;
}
default:
+ if (FS.getPrecision().hasDataArgument()) {
+ ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
+ }
break;
}
+ if (FS.getFieldWidth().hasDataArgument()) {
+ ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
+ }
if (FS.isPrivate()) {
ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
Layout.Items.clear();
for (auto &Data : ArgsData) {
+ if (Data.FieldWidth) {
+ CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
+ Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth,
+ Size, 0);
+ }
+ if (Data.Precision) {
+ CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType());
+ Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision,
+ Size, 0);
+ }
+ if (Data.Count) {
+ // "%.*P" has an extra "count" that we insert before the argument.
+ CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
+ Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size,
+ 0);
+ }
if (Data.Size)
Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),
Data.Flags);
__builtin_os_log_format(buf, "%S", str);
}
+// CHECK-LABEL: define void @test_builtin_os_log_precision_width
+// CHECK: (i8* [[BUF:%.*]], i8* [[DATA:%.*]], i32 [[PRECISION:%.*]], i32 [[WIDTH:%.*]])
+void test_builtin_os_log_precision_width(void *buf, const char *data,
+ int precision, int width) {
+ volatile int len;
+ // CHECK: store i8* [[BUF]], i8** [[BUF_ADDR:%.*]], align 8
+ // CHECK: store i8* [[DATA]], i8** [[DATA_ADDR:%.*]], align 8
+ // CHECK: store i32 [[PRECISION]], i32* [[PRECISION_ADDR:%.*]], align 4
+ // CHECK: store i32 [[WIDTH]], i32* [[WIDTH_ADDR:%.*]], align 4
+
+ // CHECK: store volatile i32 24,
+ len = __builtin_os_log_format_buffer_size("Hello %*.*s World", precision, width, data);
+
+ // CHECK: [[BUF2:%.*]] = load i8*, i8** [[BUF_ADDR]]
+ // CHECK: [[SUMMARY:%.*]] = getelementptr i8, i8* [[BUF2]], i64 0
+ // CHECK: store i8 2, i8* [[SUMMARY]]
+ // CHECK: [[NUM_ARGS:%.*]] = getelementptr i8, i8* [[BUF2]], i64 1
+ // CHECK: store i8 3, i8* [[NUM_ARGS]]
+
+ // CHECK: [[ARG1_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 2
+ // CHECK: store i8 0, i8* [[ARG1_DESC]]
+ // CHECK: [[ARG1_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 3
+ // CHECK: store i8 4, i8* [[ARG1_SIZE]]
+ // CHECK: [[ARG1:%.*]] = getelementptr i8, i8* [[BUF2]], i64 4
+ // CHECK: [[ARG1_INT:%.*]] = bitcast i8* [[ARG1]] to i32*
+ // CHECK: [[ARG1_VAL:%.*]] = load i32, i32* [[PRECISION_ADDR]]
+ // CHECK: store i32 [[ARG1_VAL]], i32* [[ARG1_INT]]
+
+ // CHECK: [[ARG2_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 8
+ // CHECK: store i8 16, i8* [[ARG2_DESC]]
+ // CHECK: [[ARG2_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 9
+ // CHECK: store i8 4, i8* [[ARG2_SIZE]]
+ // CHECK: [[ARG2:%.*]] = getelementptr i8, i8* [[BUF2]], i64 10
+ // CHECK: [[ARG2_INT:%.*]] = bitcast i8* [[ARG2]] to i32*
+ // CHECK: [[ARG2_VAL:%.*]] = load i32, i32* [[WIDTH_ADDR]]
+ // CHECK: store i32 [[ARG2_VAL]], i32* [[ARG2_INT]]
+
+ // CHECK: [[ARG3_DESC:%.*]] = getelementptr i8, i8* [[BUF2]], i64 14
+ // CHECK: store i8 32, i8* [[ARG3_DESC]]
+ // CHECK: [[ARG3_SIZE:%.*]] = getelementptr i8, i8* [[BUF2]], i64 15
+ // CHECK: store i8 8, i8* [[ARG3_SIZE]]
+ // CHECK: [[ARG3:%.*]] = getelementptr i8, i8* [[BUF2]], i64 16
+ // CHECK: [[ARG3_PTR:%.*]] = bitcast i8* [[ARG3]] to i8**
+ // CHECK: [[DATA2:%.*]] = load i8*, i8** [[DATA_ADDR]]
+ // CHECK: store i8* [[DATA2]], i8** [[ARG3_PTR]]
+
+ __builtin_os_log_format(buf, "Hello %*.*s World", precision, width, data);
+}
+
// CHECK-LABEL: define void @test_builtin_os_log_percent
// CHECK: (i8* [[BUF:%.*]], i8* [[DATA1:%.*]], i8* [[DATA2:%.*]])
// Check that the %% which does not consume any argument is correctly handled