Daniel Thornburgh c9ff2df8c3
[IR] "modular-format" attribute for functions using format strings (#147429)
A new InstCombine transform uses this attribute to rewrite calls to a
modular version of the implementation along with llvm.reloc.none
relocations against aspects of the implementation needed by the call.

This change only adds support for the 'float' aspect, but it also builds
the structure needed for others.

See issue #146159
2025-11-11 11:52:56 -08:00

106 lines
3.9 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; Test that the modular format string library call simplifier works correctly.
;
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
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"
@.str.int = constant [3 x i8] c"%d\00"
@.str.float = constant [3 x i8] c"%f\00"
@.str.multi = constant [6 x i8] c"%f %d\00"
@.str.noargs = constant [1 x i8] c"\00"
;; No aspects are specified, so no transformation occurs.
define void @test_basic(i32 %arg) {
; CHECK-LABEL: @test_basic(
; CHECK-NEXT: call void (ptr, ...) @basic(ptr nonnull @.str.int, i32 [[ARG:%.*]])
; CHECK-NEXT: ret void
;
call void (ptr, ...) @basic(ptr @.str.int, i32 %arg)
ret void
}
declare void @basic(ptr, ...) #0
;; The "float" aspect is present and needed, so no transformation occurs.
define void @test_float_present(double %arg) {
; CHECK-LABEL: @test_float_present(
; CHECK-NEXT: call void (ptr, ...) @float_present(ptr nonnull @.str.float, double [[ARG:%.*]])
; CHECK-NEXT: ret void
;
call void (ptr, ...) @float_present(ptr @.str.float, double %arg)
ret void
}
declare void @float_present(ptr, ...) #1
;; The "float" aspect is present but not needed, so the call is transformed.
define void @test_float_absent(i32 %arg) {
; CHECK-LABEL: @test_float_absent(
; CHECK-NEXT: call void (ptr, ...) @float_present_mod(ptr nonnull @.str.int, i32 [[ARG:%.*]])
; CHECK-NEXT: ret void
;
call void (ptr, ...) @float_absent(ptr @.str.int, i32 %arg)
ret void
}
declare void @float_absent(ptr, ...) #1
;; Unknown aspects are always considered needed, so no transformation occurs.
define void @test_unknown_aspects(i32 %arg) {
; CHECK-LABEL: @test_unknown_aspects(
; CHECK-NEXT: call void (ptr, ...) @unknown_aspects(ptr nonnull @.str.int, i32 [[ARG:%.*]])
; CHECK-NEXT: ret void
;
call void (ptr, ...) @unknown_aspects(ptr @.str.int, i32 %arg)
ret void
}
declare void @unknown_aspects(ptr, ...) #2
;; The call has no arguments to check, so the "float" aspect is not needed and
;; the call is transformed.
define void @test_no_args_to_check() {
; CHECK-LABEL: @test_no_args_to_check(
; CHECK-NEXT: call void (ptr, ...) @float_present_mod(ptr nonnull @.str.noargs)
; CHECK-NEXT: ret void
;
call void (ptr, ...) @no_args_to_check(ptr @.str.noargs)
ret void
}
declare void @no_args_to_check(ptr, ...) #1
;; The first argument index is not 2. The "float" aspect is needed, so no
;; transformation occurs.
define void @test_first_arg_idx(i32 %ignored, double %arg) {
; CHECK-LABEL: @test_first_arg_idx(
; CHECK-NEXT: call void (i32, ptr, ...) @first_arg_idx(i32 [[IGNORED:%.*]], ptr nonnull @.str.float, double [[ARG:%.*]])
; CHECK-NEXT: ret void
;
call void (i32, ptr, ...) @first_arg_idx(i32 %ignored, ptr @.str.float, double %arg)
ret void
}
declare void @first_arg_idx(i32, ptr, ...) #3
;; One aspect ("unknown") is needed, but one ("float") is not. The call is
;; transformed, and a reference to the needed aspect is emitted.
define void @test_partial_aspects(i32 %arg) {
; CHECK-LABEL: @test_partial_aspects(
; CHECK-NEXT: call void (ptr, ...) @multiple_aspects_mod(ptr nonnull @.str.int, i32 [[ARG:%.*]])
; CHECK-NEXT: call void @llvm.reloc.none(metadata !"basic_impl_unknown")
; CHECK-NEXT: ret void
;
call void (ptr, ...) @partial_aspects(ptr @.str.int, i32 %arg)
ret void
}
declare void @partial_aspects(ptr, ...) #4
attributes #0 = { "modular-format"="printf,1,2,basic_mod,basic_impl" }
attributes #1 = { "modular-format"="printf,1,2,float_present_mod,basic_impl,float" }
attributes #2 = { "modular-format"="printf,1,2,unknown_aspects_mod,basic_impl,unknown1,unknown2" }
attributes #3 = { "modular-format"="printf,2,3,first_arg_idx_mod,basic_impl,float" }
attributes #4 = { "modular-format"="printf,1,2,multiple_aspects_mod,basic_impl,float,unknown" }