Skip to content

Commit 9dff0b3

Browse files
committed
Add test cases and polish change
1 parent 34aeb64 commit 9dff0b3

File tree

5 files changed

+172
-16
lines changed

5 files changed

+172
-16
lines changed

llvm/docs/LangRef.rst

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2637,18 +2637,17 @@ For example:
26372637
This attribute indicates that outlining passes should not modify the
26382638
function.
26392639

2640-
``"modular-format"="<type>,<string_idx>,<first_idx_to_check>,<modular_impl_fn>,<impl_name>,<aspects...>"``
2640+
``"modular-format"="<type>,<string_idx>,<first_arg_idx>,<modular_impl_fn>,<impl_name>,<aspects...>"``
26412641
This attribute indicates that the implementation is modular on a particular
2642-
format string argument . When the argument for a given call is constant, the
2643-
compiler may redirect the call to a modular implementation function
2644-
instead.
2645-
2646-
The compiler also emits relocations to report various aspects of the format
2647-
string and arguments that were present. The compiler reports an aspect by
2648-
issuing a relocation for the symbol `<impl_name>_<aspect>``. This arranges
2649-
for code and data needed to support the aspect of the implementation to be
2650-
brought into the link to satisfy weak references in the modular
2651-
implemenation function.
2642+
format string argument. If the compiler can determine that not all aspects
2643+
of the implementation are needed, it can report which aspects were needed
2644+
and redirect the call to a modular implementation function instead.
2645+
2646+
The compiler reports that an implementation aspect is needed by issuing a
2647+
relocation for the symbol `<impl_name>_<aspect>``. This arranges for code
2648+
and data needed to support the aspect of the implementation to be brought
2649+
into the link to satisfy weak references in the modular implemenation
2650+
function.
26522651

26532652
The first three arguments have the same semantics as the arguments to the C
26542653
``format`` attribute.

llvm/lib/IR/Verifier.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2522,6 +2522,20 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
25222522
CheckFailed("invalid value for 'denormal-fp-math-f32' attribute: " + S,
25232523
V);
25242524
}
2525+
2526+
if (auto A = Attrs.getFnAttr("modular-format"); A.isValid()) {
2527+
StringRef S = A.getValueAsString();
2528+
SmallVector<StringRef> Args;
2529+
S.split(Args, ',');
2530+
Check(Args.size() >= 5,
2531+
"modular-format attribute requires at least 5 arguments", V);
2532+
unsigned FirstArgIdx;
2533+
Check(!Args[2].getAsInteger(10, FirstArgIdx),
2534+
"modular-format attribute first arg index is not an integer", V);
2535+
unsigned UpperBound = FT->getNumParams() + (FT->isVarArg() ? 1 : 0);
2536+
Check(FirstArgIdx > 0 && FirstArgIdx <= UpperBound,
2537+
"modular-format attribute first arg index is out of bounds", V);
2538+
}
25252539
}
25262540

25272541
void Verifier::verifyFunctionMetadata(

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4009,12 +4009,10 @@ static Value *optimizeModularFormat(CallInst *CI, IRBuilderBase &B) {
40094009
SmallVector<StringRef> Args(
40104010
llvm::split(CI->getFnAttr("modular-format").getValueAsString(), ','));
40114011
// TODO: Make use of the first two arguments
4012-
// TODO: Error handling
40134012
unsigned FirstArgIdx;
4014-
if (!llvm::to_integer(Args[2], FirstArgIdx))
4015-
return nullptr;
4016-
if (FirstArgIdx == 0)
4017-
return nullptr;
4013+
[[maybe_unused]] bool Error;
4014+
Error = Args[2].getAsInteger(10, FirstArgIdx);
4015+
assert(!Error && "invalid first arg index");
40184016
--FirstArgIdx;
40194017
StringRef FnName = Args[3];
40204018
StringRef ImplName = Args[4];
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; Test that the modular format string library call simplifier works correctly.
3+
;
4+
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
5+
6+
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
7+
8+
@.str.int = constant [3 x i8] c"%d\00"
9+
@.str.float = constant [3 x i8] c"%f\00"
10+
@.str.multi = constant [6 x i8] c"%f %d\00"
11+
@.str.multifp = constant [6 x i8] c"%f %f\00"
12+
@.str.noargs = constant [1 x i8] c"\00"
13+
14+
; Basic Transformation
15+
define void @test_basic(i32 %arg) {
16+
; CHECK-LABEL: @test_basic(
17+
; CHECK-NEXT: call void (ptr, ...) @basic_mod(ptr nonnull @.str.int, i32 [[ARG:%.*]])
18+
; CHECK-NEXT: ret void
19+
;
20+
call void (ptr, ...) @basic(ptr @.str.int, i32 %arg)
21+
ret void
22+
}
23+
24+
declare void @basic(ptr, ...) "modular-format"="printf,1,2,basic_mod,basic_impl"
25+
; "float" Aspect - Present
26+
define void @test_float_present(double %arg) {
27+
; CHECK-LABEL: @test_float_present(
28+
; CHECK-NEXT: call void (ptr, ...) @float_present_mod(ptr nonnull @.str.float, double [[ARG:%.*]])
29+
; CHECK-NEXT: call void @llvm.reloc.none(ptr nonnull @basic_impl_float)
30+
; CHECK-NEXT: ret void
31+
;
32+
call void (ptr, ...) @float_present(ptr @.str.float, double %arg)
33+
ret void
34+
}
35+
36+
declare void @float_present(ptr, ...) #0
37+
38+
; Unknown Aspects
39+
define void @test_unknown_aspects(i32 %arg) {
40+
; CHECK-LABEL: @test_unknown_aspects(
41+
; CHECK-NEXT: call void (ptr, ...) @unknown_aspects_mod(ptr nonnull @.str.int, i32 [[ARG:%.*]])
42+
; CHECK-NEXT: call void @llvm.reloc.none(ptr nonnull @basic_impl_unknown1)
43+
; CHECK-NEXT: call void @llvm.reloc.none(ptr nonnull @basic_impl_unknown2)
44+
; CHECK-NEXT: ret void
45+
;
46+
call void (ptr, ...) @unknown_aspects(ptr @.str.int, i32 %arg)
47+
ret void
48+
}
49+
50+
declare void @unknown_aspects(ptr, ...) "modular-format"="printf,1,2,unknown_aspects_mod,basic_impl,unknown1,unknown2"
51+
52+
; Multiple Aspects
53+
define void @test_multiple_aspects(double %arg1, i32 %arg2) {
54+
; CHECK-LABEL: @test_multiple_aspects(
55+
; CHECK-NEXT: call void (ptr, ...) @multiple_aspects_mod(ptr nonnull @.str.multi, double [[ARG1:%.*]], i32 [[ARG2:%.*]])
56+
; CHECK-NEXT: call void @llvm.reloc.none(ptr nonnull @basic_impl_float)
57+
; CHECK-NEXT: call void @llvm.reloc.none(ptr nonnull @basic_impl_unknown)
58+
; CHECK-NEXT: ret void
59+
;
60+
call void (ptr, ...) @multiple_aspects(ptr @.str.multi, double %arg1, i32 %arg2)
61+
ret void
62+
}
63+
64+
declare void @multiple_aspects(ptr, ...) "modular-format"="printf,1,2,multiple_aspects_mod,basic_impl,float,unknown"
65+
66+
; Multiple Floating-Point Arguments
67+
define void @test_multiple_fp_args(double %arg1, float %arg2) {
68+
; CHECK-LABEL: @test_multiple_fp_args(
69+
; CHECK-NEXT: call void (ptr, ...) @float_present_mod(ptr nonnull @.str.multifp, double [[ARG1:%.*]], float [[ARG2:%.*]])
70+
; CHECK-NEXT: call void @llvm.reloc.none(ptr nonnull @basic_impl_float)
71+
; CHECK-NEXT: ret void
72+
;
73+
call void (ptr, ...) @multiple_fp_args(ptr @.str.multifp, double %arg1, float %arg2)
74+
ret void
75+
}
76+
77+
declare void @multiple_fp_args(ptr, ...) #0
78+
79+
; No Arguments to Check
80+
define void @test_no_args_to_check() {
81+
; CHECK-LABEL: @test_no_args_to_check(
82+
; CHECK-NEXT: call void (ptr, ...) @float_present_mod(ptr nonnull @.str.noargs)
83+
; CHECK-NEXT: ret void
84+
;
85+
call void (ptr, ...) @no_args_to_check(ptr @.str.noargs)
86+
ret void
87+
}
88+
89+
declare void @no_args_to_check(ptr, ...) #0
90+
91+
; First argument index != 2
92+
define void @test_first_arg_idx(i32 %ignored, double %arg) {
93+
; CHECK-LABEL: @test_first_arg_idx(
94+
; CHECK-NEXT: call void (i32, ptr, ...) @first_arg_idx_mod(i32 [[IGNORED:%.*]], ptr nonnull @.str.float, double [[ARG:%.*]])
95+
; CHECK-NEXT: call void @llvm.reloc.none(ptr nonnull @basic_impl_float)
96+
; CHECK-NEXT: ret void
97+
;
98+
call void (i32, ptr, ...) @first_arg_idx(i32 %ignored, ptr @.str.float, double %arg)
99+
ret void
100+
}
101+
102+
declare void @first_arg_idx(i32, ptr, ...) "modular-format"="printf,2,3,first_arg_idx_mod,basic_impl,float"
103+
104+
attributes #0 = { "modular-format"="printf,1,2,float_present_mod,basic_impl,float" }
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
2+
3+
define void @test_too_few_arguments(i32 %arg, ...) "modular-format"="printf,1,2,basic_mod" {
4+
ret void
5+
}
6+
; CHECK: modular-format attribute requires at least 5 arguments
7+
; CHECK-NEXT: ptr @test_too_few_arguments
8+
9+
define void @test_first_arg_index_not_integer(i32 %arg, ...) "modular-format"="printf,1,foo,basic_mod,basic_impl" {
10+
ret void
11+
}
12+
; CHECK: modular-format attribute first arg index is not an integer
13+
; CHECK-NEXT: ptr @test_first_arg_index_not_integer
14+
15+
define void @test_first_arg_index_zero(i32 %arg) "modular-format"="printf,1,0,basic_mod,basic_impl" {
16+
ret void
17+
}
18+
; CHECK: modular-format attribute first arg index is out of bounds
19+
; CHECK-NEXT: ptr @test_first_arg_index_zero
20+
21+
define void @test_first_arg_index_out_of_bounds(i32 %arg) "modular-format"="printf,1,2,basic_mod,basic_impl" {
22+
ret void
23+
}
24+
; CHECK: modular-format attribute first arg index is out of bounds
25+
; CHECK-NEXT: ptr @test_first_arg_index_out_of_bounds
26+
27+
define void @test_first_arg_index_out_of_bounds_varargs(i32 %arg, ...) "modular-format"="printf,1,3,basic_mod,basic_impl" {
28+
ret void
29+
}
30+
; CHECK: modular-format attribute first arg index is out of bounds
31+
; CHECK-NEXT: ptr @test_first_arg_index_out_of_bounds_varargs
32+
33+
; CHECK-NOT: ptr @test_first_arg_index_in_bounds
34+
define void @test_first_arg_index_in_bounds(i32 %arg) "modular-format"="printf,1,1,basic_mod,basic_impl" {
35+
ret void
36+
}
37+
38+
; CHECK-NOT: ptr @test_first_arg_index_in_bounds_varargs
39+
define void @test_first_arg_index_in_bounds_varargs(i32 %arg, ...) "modular-format"="printf,1,2,basic_mod,basic_impl" {
40+
ret void
41+
}

0 commit comments

Comments
 (0)