Просмотр исходного кода

Create a single global for the PrintInt format string. (#5275)

Create a single global for the PrintInt format string. Cleaner tests.
Alina Sbirlea 1 год назад
Родитель
Сommit
7da972b773

+ 11 - 0
toolchain/lower/file_context.h

@@ -97,6 +97,14 @@ class FileContext {
   auto global_variables() -> const Map<SemIR::InstId, llvm::GlobalVariable*>& {
     return global_variables_;
   }
+  auto printf_int_format_string() -> llvm::Value* {
+    return printf_int_format_string_;
+  }
+  auto SetPrintfIntFormatString(llvm::Value* printf_int_format_string) {
+    CARBON_CHECK(!printf_int_format_string_,
+                 "PrintInt formatting string already generated");
+    printf_int_format_string_ = printf_int_format_string;
+  }
 
  private:
   struct FunctionTypeInfo {
@@ -208,6 +216,9 @@ class FileContext {
 
   // Maps global variables to their lowered variant.
   Map<SemIR::InstId, llvm::GlobalVariable*> global_variables_;
+
+  // Global format string for `printf.int.format` used by the PrintInt builtin.
+  llvm::Value* printf_int_format_string_ = nullptr;
 };
 
 }  // namespace Carbon::Lower

+ 11 - 0
toolchain/lower/function_context.h

@@ -135,6 +135,17 @@ class FunctionContext {
   auto builder() -> llvm::IRBuilderBase& { return builder_; }
   auto sem_ir() -> const SemIR::File& { return file_context_->sem_ir(); }
 
+  // TODO: could template on BuiltinFunctionKind if more format
+  // globals are eventually needed.
+  auto printf_int_format_string() -> llvm::Value* {
+    auto* format_string = file_context_->printf_int_format_string();
+    if (!format_string) {
+      format_string = builder().CreateGlobalString("%d\n", "printf.int.format");
+      file_context_->SetPrintfIntFormatString(format_string);
+    }
+    return format_string;
+  }
+
  private:
   // Custom instruction inserter for our IR builder. Automatically names
   // instructions.

+ 1 - 2
toolchain/lower/handle_call.cpp

@@ -183,8 +183,7 @@ static auto HandleBuiltinCall(FunctionContext& context, SemIR::InstId inst_id,
       llvm::FunctionCallee printf =
           context.llvm_module().getOrInsertFunction("printf", printf_type);
 
-      llvm::Value* format_string =
-          context.builder().CreateGlobalString("%d\n", "printf.int.format");
+      llvm::Value* format_string = context.printf_int_format_string();
       llvm::Value* arg_value = context.builder().CreateSExtOrTrunc(
           context.GetValue(arg_ids[0]), i32_type);
       context.SetLocal(inst_id, context.builder().CreateCall(

+ 1 - 2
toolchain/lower/testdata/function/generic/call_different_impls.carbon

@@ -35,7 +35,6 @@ fn Run() {
 // CHECK:STDOUT: source_filename = "call_different_impls.carbon"
 // CHECK:STDOUT:
 // CHECK:STDOUT: @printf.int.format = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
-// CHECK:STDOUT: @printf.int.format.1 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
 // CHECK:STDOUT:
 // CHECK:STDOUT: define void @"_CF.X.Main:I.Main"() !dbg !4 {
 // CHECK:STDOUT: entry:
@@ -45,7 +44,7 @@ fn Run() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: define void @"_CF.Y.Main:I.Main"() !dbg !9 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format.1, i32 2), !dbg !10
+// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 2), !dbg !10
 // CHECK:STDOUT:   ret void, !dbg !11
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 7 - 16
toolchain/lower/testdata/function/generic/call_recursive_diamond.carbon

@@ -54,19 +54,10 @@ fn M() {
   A(ptr_f64, 0);
 }
 
-// TODO: Duplicate printf int format constants
-
 // CHECK:STDOUT: ; ModuleID = 'call_recursive_diamond.carbon'
 // CHECK:STDOUT: source_filename = "call_recursive_diamond.carbon"
 // CHECK:STDOUT:
 // CHECK:STDOUT: @printf.int.format = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
-// CHECK:STDOUT: @printf.int.format.1 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
-// CHECK:STDOUT: @printf.int.format.2 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
-// CHECK:STDOUT: @printf.int.format.3 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
-// CHECK:STDOUT: @printf.int.format.4 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
-// CHECK:STDOUT: @printf.int.format.5 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
-// CHECK:STDOUT: @printf.int.format.6 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
-// CHECK:STDOUT: @printf.int.format.7 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
 // CHECK:STDOUT:
 // CHECK:STDOUT: define void @_CM.Main() !dbg !4 {
 // CHECK:STDOUT: entry:
@@ -191,49 +182,49 @@ fn M() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: define i32 @_CC.Main.b88d1103f417c6d4(i32 %x, i32 %count) !dbg !62 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format.1, i32 2), !dbg !63
+// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 2), !dbg !63
 // CHECK:STDOUT:   %D.call = call i32 @_CD.Main.b88d1103f417c6d4(i32 %x, i32 %count), !dbg !64
 // CHECK:STDOUT:   ret i32 %D.call, !dbg !65
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: define double @_CB.Main.66be507887ceee78(double %x, i32 %count) !dbg !66 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format.2, i32 1), !dbg !67
+// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 1), !dbg !67
 // CHECK:STDOUT:   %D.call = call double @_CD.Main.66be507887ceee78(double %x, i32 %count), !dbg !68
 // CHECK:STDOUT:   ret double %D.call, !dbg !69
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: define double @_CC.Main.66be507887ceee78(double %x, i32 %count) !dbg !70 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format.3, i32 2), !dbg !71
+// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 2), !dbg !71
 // CHECK:STDOUT:   %D.call = call double @_CD.Main.66be507887ceee78(double %x, i32 %count), !dbg !72
 // CHECK:STDOUT:   ret double %D.call, !dbg !73
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: define ptr @_CB.Main.e8193710fd35b608(ptr %x, i32 %count) !dbg !74 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format.4, i32 1), !dbg !75
+// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 1), !dbg !75
 // CHECK:STDOUT:   %D.call = call ptr @_CD.Main.e8193710fd35b608(ptr %x, i32 %count), !dbg !76
 // CHECK:STDOUT:   ret ptr %D.call, !dbg !77
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: define ptr @_CC.Main.e8193710fd35b608(ptr %x, i32 %count) !dbg !78 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format.5, i32 2), !dbg !79
+// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 2), !dbg !79
 // CHECK:STDOUT:   %D.call = call ptr @_CD.Main.e8193710fd35b608(ptr %x, i32 %count), !dbg !80
 // CHECK:STDOUT:   ret ptr %D.call, !dbg !81
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: define ptr @_CB.Main.04bf2edaaa84aa22(ptr %x, i32 %count) !dbg !82 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format.6, i32 1), !dbg !83
+// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 1), !dbg !83
 // CHECK:STDOUT:   %D.call = call ptr @_CD.Main.04bf2edaaa84aa22(ptr %x, i32 %count), !dbg !84
 // CHECK:STDOUT:   ret ptr %D.call, !dbg !85
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: define ptr @_CC.Main.04bf2edaaa84aa22(ptr %x, i32 %count) !dbg !86 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format.7, i32 2), !dbg !87
+// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 2), !dbg !87
 // CHECK:STDOUT:   %D.call = call ptr @_CD.Main.04bf2edaaa84aa22(ptr %x, i32 %count), !dbg !88
 // CHECK:STDOUT:   ret ptr %D.call, !dbg !89
 // CHECK:STDOUT: }

+ 1 - 2
toolchain/lower/testdata/function/generic/call_recursive_impl.carbon

@@ -43,7 +43,6 @@ fn Run() {
 // CHECK:STDOUT: source_filename = "call_recursive_impl.carbon"
 // CHECK:STDOUT:
 // CHECK:STDOUT: @printf.int.format = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
-// CHECK:STDOUT: @printf.int.format.1 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
 // CHECK:STDOUT:
 // CHECK:STDOUT: define void @"_CF.X.Main:I.Main"() !dbg !4 {
 // CHECK:STDOUT: entry:
@@ -53,7 +52,7 @@ fn Run() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: define void @"_CF.Y.Main:I.Main"() !dbg !9 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format.1, i32 2), !dbg !10
+// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 2), !dbg !10
 // CHECK:STDOUT:   ret void, !dbg !11
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 3 - 7
toolchain/lower/testdata/function/generic/call_recursive_sccs_deep.carbon

@@ -80,15 +80,11 @@ fn M() {
   A(ptr_f64, 0);
 }
 
-// TODO: Duplicate printf int format constants
 
 // CHECK:STDOUT: ; ModuleID = 'call_recursive_sccs_deep.carbon'
 // CHECK:STDOUT: source_filename = "call_recursive_sccs_deep.carbon"
 // CHECK:STDOUT:
 // CHECK:STDOUT: @printf.int.format = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
-// CHECK:STDOUT: @printf.int.format.1 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
-// CHECK:STDOUT: @printf.int.format.2 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
-// CHECK:STDOUT: @printf.int.format.3 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
 // CHECK:STDOUT:
 // CHECK:STDOUT: define void @_CM.Main() !dbg !4 {
 // CHECK:STDOUT: entry:
@@ -289,7 +285,7 @@ fn M() {
 // CHECK:STDOUT:   br i1 %int.less_eq, label %if.then, label %if.else, !dbg !102
 // CHECK:STDOUT:
 // CHECK:STDOUT: if.then:                                          ; preds = %entry
-// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format.1, i32 %count), !dbg !103
+// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 %count), !dbg !103
 // CHECK:STDOUT:   %int.sadd = add i32 %count, 1, !dbg !104
 // CHECK:STDOUT:   call void @_CB.Main.66be507887ceee78(double %x, i32 %int.sadd), !dbg !105
 // CHECK:STDOUT:   br label %if.else, !dbg !106
@@ -316,7 +312,7 @@ fn M() {
 // CHECK:STDOUT:   br i1 %int.less_eq, label %if.then, label %if.else, !dbg !116
 // CHECK:STDOUT:
 // CHECK:STDOUT: if.then:                                          ; preds = %entry
-// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format.2, i32 %count), !dbg !117
+// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 %count), !dbg !117
 // CHECK:STDOUT:   %int.sadd = add i32 %count, 1, !dbg !118
 // CHECK:STDOUT:   call void @_CB.Main.e8193710fd35b608(ptr %x, i32 %int.sadd), !dbg !119
 // CHECK:STDOUT:   br label %if.else, !dbg !120
@@ -343,7 +339,7 @@ fn M() {
 // CHECK:STDOUT:   br i1 %int.less_eq, label %if.then, label %if.else, !dbg !130
 // CHECK:STDOUT:
 // CHECK:STDOUT: if.then:                                          ; preds = %entry
-// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format.3, i32 %count), !dbg !131
+// CHECK:STDOUT:   %print.int = call i32 (ptr, ...) @printf(ptr @printf.int.format, i32 %count), !dbg !131
 // CHECK:STDOUT:   %int.sadd = add i32 %count, 1, !dbg !132
 // CHECK:STDOUT:   call void @_CB.Main.04bf2edaaa84aa22(ptr %x, i32 %int.sadd), !dbg !133
 // CHECK:STDOUT:   br label %if.else, !dbg !134