asb created this revision.
asb added reviewers: reames, craig.topper, luismarques, kito-cheng.
Herald added subscribers: wingo, sunshaoce, pmatos, VincentWu, StephenFan, 
vkmr, frasercrmck, evandro, apazos, sameer.abuasal, s.egerton, Jim, benna, 
psnobl, jocewei, PkmX, the_o, brucehoult, MartinMosbeck, rogfer01, 
edward-jones, zzheng, jrtc27, shiva0217, niosHD, sabuasal, simoncook, 
johnrusso, rbar, arichardson.
Herald added a project: All.
asb requested review of this revision.
Herald added subscribers: pcwang-thead, eopXD, MaskRay.

I think our current set of ABI test files is organised about as well as it can 
be when relying on manual editing, but maintenance is error-prone and tedious. 
Having files containing tests that have the same signature for the ABIs 
indicated in the filename simplifies some things, but can create additional 
work when adding a new test that has behaviour that's worth testing across 
multiple ABI combinations. It's also not easy to tell at a glance whether a 
given function signature is tested across a sufficient set of ABIs, as you may 
need to look in multiple files to check for this.

This patch isn't ready for committing, and I don't propose committing it in its 
current form. As I've had to do some work on update_cc_test_checks.py to make 
it suitable for generating our ABI tests (see D133943 
<https://reviews.llvm.org/D133943>) and will need to do further work to 
finalise this work, I wanted to get some feedback on the proposed direction.

This patch demonstrates the proposed direction I'd like to take these ABI tests 
in, with some caveats:

- Due to an update_cc_test_checks.py bug I haven't spent the time to track down 
and fix yet, I have to include at least one line from the function body for it 
to merge CHECK lines with the same content. I'd anticipate fixing this if we're 
agreed this is the right direction.
- riscv-abi.cpp is now generated using update_cc_test_checks.py, and also 
demonstrates the style of tests I'd like to move to - where all ABI variants 
are tested in a single file (potentially split by language features if it 
becomes too large) and we rely on update_cc_test_checks.py merging common CHECK 
lines for us.
- The riscv32-*abi.c tests are all regenerated using update_cc_test_checks.py. 
This represents the first step of my proposed changes - the next step would be 
to combine into one (or a small number of files based on language features / 
aspect of the ABI rather than target ABI variant) and use multiple RUN lines 
with overlapping check prefixes much like riscv-abi.cpp
  - It _probably_ makes sense to combine riscv32-*abi.c and riscv64*-abi.c 
tests - I've just made a start with riscv32* so as to get something for quick 
feedback

So - how do people feel about this direction? Potential options:

- Don't change existing tests and don't move to update_cc_test_checks
- Convert current tests to update_cc_test_checks but don't pursue any further 
refactoring/merging
- Convert current tests to update_cc_test_checks and then pursue something like 
I suggest above, combining more tests in the style of riscv-abi.cpp


https://reviews.llvm.org/D134050

Files:
  clang/test/CodeGen/RISCV/riscv-abi.cpp
  clang/test/CodeGen/RISCV/riscv32-ilp32-abi.c
  clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-abi.c
  clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-ilp32d-abi.c
  clang/test/CodeGen/RISCV/riscv32-ilp32d-abi.c
  clang/test/CodeGen/RISCV/riscv32-ilp32f-abi.c
  clang/test/CodeGen/RISCV/riscv32-ilp32f-ilp32d-abi.c
  clang/test/CodeGen/RISCV/riscv32-vararg.c

Index: clang/test/CodeGen/RISCV/riscv32-vararg.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/RISCV/riscv32-vararg.c
@@ -0,0 +1,294 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature
+// RUN: %clang_cc1 -triple riscv32 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \
+// RUN:     | FileCheck %s
+// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm %s -o - \
+// RUN:     | FileCheck %s
+
+#include <stddef.h>
+#include <stdint.h>
+
+struct tiny {
+  uint8_t a, b, c, d;
+};
+struct small {
+  int32_t a, *b;
+};
+struct small_aligned {
+  int64_t a;
+};
+struct large {
+  int32_t a, b, c, d;
+};
+
+// Ensure that ABI lowering happens as expected for vararg calls. For RV32
+// with the base integer calling convention there will be no observable
+// differences in the lowered IR for a call with varargs vs without.
+
+int f_va_callee(int, ...);
+
+// CHECK-LABEL: define dso_local void @f_va_caller
+// CHECK-SAME: () #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_TINY:%.*]], align 1
+// CHECK-NEXT:    [[DOTCOMPOUNDLITERAL1:%.*]] = alloca [[STRUCT_SMALL:%.*]], align 4
+// CHECK-NEXT:    [[DOTCOMPOUNDLITERAL4:%.*]] = alloca [[STRUCT_SMALL_ALIGNED:%.*]], align 8
+// CHECK-NEXT:    [[DOTCOMPOUNDLITERAL6:%.*]] = alloca [[STRUCT_LARGE:%.*]], align 4
+// CHECK-NEXT:    [[BYVAL_TEMP:%.*]] = alloca [[STRUCT_LARGE]], align 4
+// CHECK-NEXT:    [[A:%.*]] = getelementptr inbounds [[STRUCT_TINY]], ptr [[DOTCOMPOUNDLITERAL]], i32 0, i32 0
+// CHECK-NEXT:    store i8 6, ptr [[A]], align 1
+// CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds [[STRUCT_TINY]], ptr [[DOTCOMPOUNDLITERAL]], i32 0, i32 1
+// CHECK-NEXT:    store i8 7, ptr [[B]], align 1
+// CHECK-NEXT:    [[C:%.*]] = getelementptr inbounds [[STRUCT_TINY]], ptr [[DOTCOMPOUNDLITERAL]], i32 0, i32 2
+// CHECK-NEXT:    store i8 8, ptr [[C]], align 1
+// CHECK-NEXT:    [[D:%.*]] = getelementptr inbounds [[STRUCT_TINY]], ptr [[DOTCOMPOUNDLITERAL]], i32 0, i32 3
+// CHECK-NEXT:    store i8 9, ptr [[D]], align 1
+// CHECK-NEXT:    [[A2:%.*]] = getelementptr inbounds [[STRUCT_SMALL]], ptr [[DOTCOMPOUNDLITERAL1]], i32 0, i32 0
+// CHECK-NEXT:    store i32 10, ptr [[A2]], align 4
+// CHECK-NEXT:    [[B3:%.*]] = getelementptr inbounds [[STRUCT_SMALL]], ptr [[DOTCOMPOUNDLITERAL1]], i32 0, i32 1
+// CHECK-NEXT:    store ptr null, ptr [[B3]], align 4
+// CHECK-NEXT:    [[A5:%.*]] = getelementptr inbounds [[STRUCT_SMALL_ALIGNED]], ptr [[DOTCOMPOUNDLITERAL4]], i32 0, i32 0
+// CHECK-NEXT:    store i64 11, ptr [[A5]], align 8
+// CHECK-NEXT:    [[A7:%.*]] = getelementptr inbounds [[STRUCT_LARGE]], ptr [[DOTCOMPOUNDLITERAL6]], i32 0, i32 0
+// CHECK-NEXT:    store i32 12, ptr [[A7]], align 4
+// CHECK-NEXT:    [[B8:%.*]] = getelementptr inbounds [[STRUCT_LARGE]], ptr [[DOTCOMPOUNDLITERAL6]], i32 0, i32 1
+// CHECK-NEXT:    store i32 13, ptr [[B8]], align 4
+// CHECK-NEXT:    [[C9:%.*]] = getelementptr inbounds [[STRUCT_LARGE]], ptr [[DOTCOMPOUNDLITERAL6]], i32 0, i32 2
+// CHECK-NEXT:    store i32 14, ptr [[C9]], align 4
+// CHECK-NEXT:    [[D10:%.*]] = getelementptr inbounds [[STRUCT_LARGE]], ptr [[DOTCOMPOUNDLITERAL6]], i32 0, i32 3
+// CHECK-NEXT:    store i32 15, ptr [[D10]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[DOTCOMPOUNDLITERAL]], align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = load [2 x i32], ptr [[DOTCOMPOUNDLITERAL1]], align 4
+// CHECK-NEXT:    [[COERCE_DIVE:%.*]] = getelementptr inbounds [[STRUCT_SMALL_ALIGNED]], ptr [[DOTCOMPOUNDLITERAL4]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP2:%.*]] = load i64, ptr [[COERCE_DIVE]], align 8
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[BYVAL_TEMP]], ptr align 4 [[DOTCOMPOUNDLITERAL6]], i32 16, i1 false)
+// CHECK-NEXT:    [[CALL:%.*]] = call i32 (i32, ...) @f_va_callee(i32 noundef 1, i32 noundef 2, i64 noundef 3, double noundef 4.000000e+00, double noundef 5.000000e+00, i32 [[TMP0]], [2 x i32] [[TMP1]], i64 [[TMP2]], ptr noundef [[BYVAL_TEMP]])
+// CHECK-NEXT:    ret void
+//
+void f_va_caller(void) {
+  f_va_callee(1, 2, 3LL, 4.0f, 5.0, (struct tiny){6, 7, 8, 9},
+              (struct small){10, NULL}, (struct small_aligned){11},
+              (struct large){12, 13, 14, 15});
+}
+
+// CHECK-LABEL: define dso_local i32 @f_va_1
+// CHECK-SAME: (ptr noundef [[FMT:%.*]], ...) #[[ATTR0]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[FMT_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    [[VA:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    [[V:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store ptr [[FMT]], ptr [[FMT_ADDR]], align 4
+// CHECK-NEXT:    call void @llvm.va_start(ptr [[VA]])
+// CHECK-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// CHECK-NEXT:    store ptr [[ARGP_NEXT]], ptr [[VA]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARGP_CUR]], align 4
+// CHECK-NEXT:    store i32 [[TMP0]], ptr [[V]], align 4
+// CHECK-NEXT:    call void @llvm.va_end(ptr [[VA]])
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[V]], align 4
+// CHECK-NEXT:    ret i32 [[TMP1]]
+//
+int f_va_1(char *fmt, ...) {
+  __builtin_va_list va;
+
+  __builtin_va_start(va, fmt);
+  int v = __builtin_va_arg(va, int);
+  __builtin_va_end(va);
+
+  return v;
+}
+
+// An "aligned" register pair (where the first register is even-numbered) is
+// used to pass varargs with 2x xlen alignment and 2x xlen size. Ensure the
+// correct offsets are used.
+
+// CHECK-LABEL: define dso_local double @f_va_2
+// CHECK-SAME: (ptr noundef [[FMT:%.*]], ...) #[[ATTR0]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[FMT_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    [[VA:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    [[V:%.*]] = alloca double, align 8
+// CHECK-NEXT:    store ptr [[FMT]], ptr [[FMT_ADDR]], align 4
+// CHECK-NEXT:    call void @llvm.va_start(ptr [[VA]])
+// CHECK-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[ARGP_CUR]] to i32
+// CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[TMP0]], 7
+// CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], -8
+// CHECK-NEXT:    [[ARGP_CUR_ALIGNED:%.*]] = inttoptr i32 [[TMP2]] to ptr
+// CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i32 8
+// CHECK-NEXT:    store ptr [[ARGP_NEXT]], ptr [[VA]], align 4
+// CHECK-NEXT:    [[TMP3:%.*]] = load double, ptr [[ARGP_CUR_ALIGNED]], align 8
+// CHECK-NEXT:    store double [[TMP3]], ptr [[V]], align 8
+// CHECK-NEXT:    call void @llvm.va_end(ptr [[VA]])
+// CHECK-NEXT:    [[TMP4:%.*]] = load double, ptr [[V]], align 8
+// CHECK-NEXT:    ret double [[TMP4]]
+//
+double f_va_2(char *fmt, ...) {
+  __builtin_va_list va;
+
+  __builtin_va_start(va, fmt);
+  double v = __builtin_va_arg(va, double);
+  __builtin_va_end(va);
+
+  return v;
+}
+
+// Two "aligned" register pairs.
+
+// CHECK-LABEL: define dso_local double @f_va_3
+// CHECK-SAME: (ptr noundef [[FMT:%.*]], ...) #[[ATTR0]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[FMT_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    [[VA:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    [[V:%.*]] = alloca double, align 8
+// CHECK-NEXT:    [[W:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[X:%.*]] = alloca double, align 8
+// CHECK-NEXT:    store ptr [[FMT]], ptr [[FMT_ADDR]], align 4
+// CHECK-NEXT:    call void @llvm.va_start(ptr [[VA]])
+// CHECK-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[ARGP_CUR]] to i32
+// CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[TMP0]], 7
+// CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], -8
+// CHECK-NEXT:    [[ARGP_CUR_ALIGNED:%.*]] = inttoptr i32 [[TMP2]] to ptr
+// CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR_ALIGNED]], i32 8
+// CHECK-NEXT:    store ptr [[ARGP_NEXT]], ptr [[VA]], align 4
+// CHECK-NEXT:    [[TMP3:%.*]] = load double, ptr [[ARGP_CUR_ALIGNED]], align 8
+// CHECK-NEXT:    store double [[TMP3]], ptr [[V]], align 8
+// CHECK-NEXT:    [[ARGP_CUR1:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-NEXT:    [[ARGP_NEXT2:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR1]], i32 4
+// CHECK-NEXT:    store ptr [[ARGP_NEXT2]], ptr [[VA]], align 4
+// CHECK-NEXT:    [[TMP4:%.*]] = load i32, ptr [[ARGP_CUR1]], align 4
+// CHECK-NEXT:    store i32 [[TMP4]], ptr [[W]], align 4
+// CHECK-NEXT:    [[ARGP_CUR3:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-NEXT:    [[TMP5:%.*]] = ptrtoint ptr [[ARGP_CUR3]] to i32
+// CHECK-NEXT:    [[TMP6:%.*]] = add i32 [[TMP5]], 7
+// CHECK-NEXT:    [[TMP7:%.*]] = and i32 [[TMP6]], -8
+// CHECK-NEXT:    [[ARGP_CUR3_ALIGNED:%.*]] = inttoptr i32 [[TMP7]] to ptr
+// CHECK-NEXT:    [[ARGP_NEXT4:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR3_ALIGNED]], i32 8
+// CHECK-NEXT:    store ptr [[ARGP_NEXT4]], ptr [[VA]], align 4
+// CHECK-NEXT:    [[TMP8:%.*]] = load double, ptr [[ARGP_CUR3_ALIGNED]], align 8
+// CHECK-NEXT:    store double [[TMP8]], ptr [[X]], align 8
+// CHECK-NEXT:    call void @llvm.va_end(ptr [[VA]])
+// CHECK-NEXT:    [[TMP9:%.*]] = load double, ptr [[V]], align 8
+// CHECK-NEXT:    [[TMP10:%.*]] = load double, ptr [[X]], align 8
+// CHECK-NEXT:    [[ADD:%.*]] = fadd double [[TMP9]], [[TMP10]]
+// CHECK-NEXT:    ret double [[ADD]]
+//
+double f_va_3(char *fmt, ...) {
+  __builtin_va_list va;
+
+  __builtin_va_start(va, fmt);
+  double v = __builtin_va_arg(va, double);
+  int w = __builtin_va_arg(va, int);
+  double x = __builtin_va_arg(va, double);
+  __builtin_va_end(va);
+
+  return v + x;
+}
+
+// CHECK-LABEL: define dso_local i32 @f_va_4
+// CHECK-SAME: (ptr noundef [[FMT:%.*]], ...) #[[ATTR0]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[FMT_ADDR:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    [[VA:%.*]] = alloca ptr, align 4
+// CHECK-NEXT:    [[V:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[LD:%.*]] = alloca fp128, align 16
+// CHECK-NEXT:    [[TS:%.*]] = alloca [[STRUCT_TINY:%.*]], align 1
+// CHECK-NEXT:    [[SS:%.*]] = alloca [[STRUCT_SMALL:%.*]], align 4
+// CHECK-NEXT:    [[LS:%.*]] = alloca [[STRUCT_LARGE:%.*]], align 4
+// CHECK-NEXT:    [[RET:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store ptr [[FMT]], ptr [[FMT_ADDR]], align 4
+// CHECK-NEXT:    call void @llvm.va_start(ptr [[VA]])
+// CHECK-NEXT:    [[ARGP_CUR:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR]], i32 4
+// CHECK-NEXT:    store ptr [[ARGP_NEXT]], ptr [[VA]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARGP_CUR]], align 4
+// CHECK-NEXT:    store i32 [[TMP0]], ptr [[V]], align 4
+// CHECK-NEXT:    [[ARGP_CUR1:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-NEXT:    [[ARGP_NEXT2:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR1]], i32 4
+// CHECK-NEXT:    store ptr [[ARGP_NEXT2]], ptr [[VA]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr [[ARGP_CUR1]], align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = load fp128, ptr [[TMP1]], align 16
+// CHECK-NEXT:    store fp128 [[TMP2]], ptr [[LD]], align 16
+// CHECK-NEXT:    [[ARGP_CUR3:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-NEXT:    [[ARGP_NEXT4:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR3]], i32 4
+// CHECK-NEXT:    store ptr [[ARGP_NEXT4]], ptr [[VA]], align 4
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[TS]], ptr align 4 [[ARGP_CUR3]], i32 4, i1 false)
+// CHECK-NEXT:    [[ARGP_CUR5:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-NEXT:    [[ARGP_NEXT6:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR5]], i32 8
+// CHECK-NEXT:    store ptr [[ARGP_NEXT6]], ptr [[VA]], align 4
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[SS]], ptr align 4 [[ARGP_CUR5]], i32 8, i1 false)
+// CHECK-NEXT:    [[ARGP_CUR7:%.*]] = load ptr, ptr [[VA]], align 4
+// CHECK-NEXT:    [[ARGP_NEXT8:%.*]] = getelementptr inbounds i8, ptr [[ARGP_CUR7]], i32 4
+// CHECK-NEXT:    store ptr [[ARGP_NEXT8]], ptr [[VA]], align 4
+// CHECK-NEXT:    [[TMP3:%.*]] = load ptr, ptr [[ARGP_CUR7]], align 4
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[LS]], ptr align 4 [[TMP3]], i32 16, i1 false)
+// CHECK-NEXT:    call void @llvm.va_end(ptr [[VA]])
+// CHECK-NEXT:    [[TMP4:%.*]] = load i32, ptr [[V]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = sitofp i32 [[TMP4]] to fp128
+// CHECK-NEXT:    [[TMP5:%.*]] = load fp128, ptr [[LD]], align 16
+// CHECK-NEXT:    [[ADD:%.*]] = fadd fp128 [[CONV]], [[TMP5]]
+// CHECK-NEXT:    [[CONV9:%.*]] = fptosi fp128 [[ADD]] to i32
+// CHECK-NEXT:    store i32 [[CONV9]], ptr [[RET]], align 4
+// CHECK-NEXT:    [[TMP6:%.*]] = load i32, ptr [[RET]], align 4
+// CHECK-NEXT:    [[A:%.*]] = getelementptr inbounds [[STRUCT_TINY]], ptr [[TS]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP7:%.*]] = load i8, ptr [[A]], align 1
+// CHECK-NEXT:    [[CONV10:%.*]] = zext i8 [[TMP7]] to i32
+// CHECK-NEXT:    [[ADD11:%.*]] = add nsw i32 [[TMP6]], [[CONV10]]
+// CHECK-NEXT:    [[B:%.*]] = getelementptr inbounds [[STRUCT_TINY]], ptr [[TS]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP8:%.*]] = load i8, ptr [[B]], align 1
+// CHECK-NEXT:    [[CONV12:%.*]] = zext i8 [[TMP8]] to i32
+// CHECK-NEXT:    [[ADD13:%.*]] = add nsw i32 [[ADD11]], [[CONV12]]
+// CHECK-NEXT:    [[C:%.*]] = getelementptr inbounds [[STRUCT_TINY]], ptr [[TS]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP9:%.*]] = load i8, ptr [[C]], align 1
+// CHECK-NEXT:    [[CONV14:%.*]] = zext i8 [[TMP9]] to i32
+// CHECK-NEXT:    [[ADD15:%.*]] = add nsw i32 [[ADD13]], [[CONV14]]
+// CHECK-NEXT:    [[D:%.*]] = getelementptr inbounds [[STRUCT_TINY]], ptr [[TS]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP10:%.*]] = load i8, ptr [[D]], align 1
+// CHECK-NEXT:    [[CONV16:%.*]] = zext i8 [[TMP10]] to i32
+// CHECK-NEXT:    [[ADD17:%.*]] = add nsw i32 [[ADD15]], [[CONV16]]
+// CHECK-NEXT:    store i32 [[ADD17]], ptr [[RET]], align 4
+// CHECK-NEXT:    [[TMP11:%.*]] = load i32, ptr [[RET]], align 4
+// CHECK-NEXT:    [[A18:%.*]] = getelementptr inbounds [[STRUCT_SMALL]], ptr [[SS]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP12:%.*]] = load i32, ptr [[A18]], align 4
+// CHECK-NEXT:    [[ADD19:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
+// CHECK-NEXT:    [[B20:%.*]] = getelementptr inbounds [[STRUCT_SMALL]], ptr [[SS]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP13:%.*]] = load ptr, ptr [[B20]], align 4
+// CHECK-NEXT:    [[TMP14:%.*]] = ptrtoint ptr [[TMP13]] to i32
+// CHECK-NEXT:    [[ADD21:%.*]] = add nsw i32 [[ADD19]], [[TMP14]]
+// CHECK-NEXT:    store i32 [[ADD21]], ptr [[RET]], align 4
+// CHECK-NEXT:    [[TMP15:%.*]] = load i32, ptr [[RET]], align 4
+// CHECK-NEXT:    [[A22:%.*]] = getelementptr inbounds [[STRUCT_LARGE]], ptr [[LS]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP16:%.*]] = load i32, ptr [[A22]], align 4
+// CHECK-NEXT:    [[ADD23:%.*]] = add nsw i32 [[TMP15]], [[TMP16]]
+// CHECK-NEXT:    [[B24:%.*]] = getelementptr inbounds [[STRUCT_LARGE]], ptr [[LS]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP17:%.*]] = load i32, ptr [[B24]], align 4
+// CHECK-NEXT:    [[ADD25:%.*]] = add nsw i32 [[ADD23]], [[TMP17]]
+// CHECK-NEXT:    [[C26:%.*]] = getelementptr inbounds [[STRUCT_LARGE]], ptr [[LS]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP18:%.*]] = load i32, ptr [[C26]], align 4
+// CHECK-NEXT:    [[ADD27:%.*]] = add nsw i32 [[ADD25]], [[TMP18]]
+// CHECK-NEXT:    [[D28:%.*]] = getelementptr inbounds [[STRUCT_LARGE]], ptr [[LS]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP19:%.*]] = load i32, ptr [[D28]], align 4
+// CHECK-NEXT:    [[ADD29:%.*]] = add nsw i32 [[ADD27]], [[TMP19]]
+// CHECK-NEXT:    store i32 [[ADD29]], ptr [[RET]], align 4
+// CHECK-NEXT:    [[TMP20:%.*]] = load i32, ptr [[RET]], align 4
+// CHECK-NEXT:    ret i32 [[TMP20]]
+//
+int f_va_4(char *fmt, ...) {
+  __builtin_va_list va;
+
+  __builtin_va_start(va, fmt);
+  int v = __builtin_va_arg(va, int);
+  long double ld = __builtin_va_arg(va, long double);
+  struct tiny ts = __builtin_va_arg(va, struct tiny);
+  struct small ss = __builtin_va_arg(va, struct small);
+  struct large ls = __builtin_va_arg(va, struct large);
+  __builtin_va_end(va);
+
+  int ret = (int)((long double)v + ld);
+  ret = ret + ts.a + ts.b + ts.c + ts.d;
+  ret = ret + ss.a + (int)ss.b;
+  ret = ret + ls.a + ls.b + ls.c + ls.d;
+
+  return ret;
+}
Index: clang/test/CodeGen/RISCV/riscv32-ilp32f-ilp32d-abi.c
===================================================================
--- clang/test/CodeGen/RISCV/riscv32-ilp32f-ilp32d-abi.c
+++ clang/test/CodeGen/RISCV/riscv32-ilp32f-ilp32d-abi.c
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -no-opaque-pointers -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --filter "^define |^entry:"
+// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
-// RUN: %clang_cc1 -no-opaque-pointers -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm %s -o - \
+// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
 
 #include <stdint.h>
@@ -11,7 +12,10 @@
 // Floats are passed in FPRs, so argument 'i' will be passed zero-extended
 // because it will be passed in a GPR.
 
-// CHECK: define{{.*}} void @f_fpr_tracking(float noundef %a, float noundef %b, float noundef %c, float noundef %d, float noundef %e, float noundef %f, float noundef %g, float noundef %h, i8 noundef zeroext %i)
+// CHECK-LABEL: define dso_local void @f_fpr_tracking
+// CHECK-SAME: (float noundef [[A:%.*]], float noundef [[B:%.*]], float noundef [[C:%.*]], float noundef [[D:%.*]], float noundef [[E:%.*]], float noundef [[F:%.*]], float noundef [[G:%.*]], float noundef [[H:%.*]], i8 noundef zeroext [[I:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK:  entry:
+//
 void f_fpr_tracking(float a, float b, float c, float d, float e, float f,
                     float g, float h, uint8_t i) {}
 
@@ -27,10 +31,16 @@
 
 struct float_s { float f; };
 
-// CHECK: define{{.*}} void @f_float_s_arg(float %0)
+// CHECK-LABEL: define dso_local void @f_float_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_float_s_arg(struct float_s a) {}
 
-// CHECK: define{{.*}} float @f_ret_float_s()
+// CHECK-LABEL: define dso_local float @f_ret_float_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct float_s f_ret_float_s(void) {
   return (struct float_s){1.0};
 }
@@ -41,18 +51,30 @@
 struct zbf_float_s { int : 0; float f; };
 struct zbf_float_zbf_s { int : 0; float f; int : 0; };
 
-// CHECK: define{{.*}} void @f_zbf_float_s_arg(float %0)
+// CHECK-LABEL: define dso_local void @f_zbf_float_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_zbf_float_s_arg(struct zbf_float_s a) {}
 
-// CHECK: define{{.*}} float @f_ret_zbf_float_s()
+// CHECK-LABEL: define dso_local float @f_ret_zbf_float_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct zbf_float_s f_ret_zbf_float_s(void) {
   return (struct zbf_float_s){1.0};
 }
 
-// CHECK: define{{.*}} void @f_zbf_float_zbf_s_arg(float %0)
+// CHECK-LABEL: define dso_local void @f_zbf_float_zbf_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_zbf_float_zbf_s_arg(struct zbf_float_zbf_s a) {}
 
-// CHECK: define{{.*}} float @f_ret_zbf_float_zbf_s()
+// CHECK-LABEL: define dso_local float @f_ret_zbf_float_zbf_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct zbf_float_zbf_s f_ret_zbf_float_zbf_s(void) {
   return (struct zbf_float_zbf_s){1.0};
 }
@@ -62,15 +84,24 @@
 
 struct float_float_s { float f; float g; };
 
-// CHECK: define{{.*}} void @f_float_float_s_arg(float %0, float %1)
+// CHECK-LABEL: define dso_local void @f_float_float_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_float_float_s_arg(struct float_float_s a) {}
 
-// CHECK: define{{.*}} { float, float } @f_ret_float_float_s()
+// CHECK-LABEL: define dso_local { float, float } @f_ret_float_float_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct float_float_s f_ret_float_float_s(void) {
   return (struct float_float_s){1.0, 2.0};
 }
 
-// CHECK: define{{.*}} void @f_float_float_s_arg_insufficient_fprs(float noundef %a, float noundef %b, float noundef %c, float noundef %d, float noundef %e, float noundef %f, float noundef %g, [2 x i32] %h.coerce)
+// CHECK-LABEL: define dso_local void @f_float_float_s_arg_insufficient_fprs
+// CHECK-SAME: (float noundef [[A:%.*]], float noundef [[B:%.*]], float noundef [[C:%.*]], float noundef [[D:%.*]], float noundef [[E:%.*]], float noundef [[F:%.*]], float noundef [[G:%.*]], [2 x i32] [[H_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_float_float_s_arg_insufficient_fprs(float a, float b, float c, float d,
     float e, float f, float g, struct float_float_s h) {}
 
@@ -85,42 +116,72 @@
 struct float_int64bf_s { float f; int64_t i : 32; };
 struct float_int8_zbf_s { float f; int8_t i; int : 0; };
 
-// CHECK: define{{.*}} void @f_float_int8_s_arg(float %0, i8 %1)
+// CHECK-LABEL: define dso_local void @f_float_int8_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_float_int8_s_arg(struct float_int8_s a) {}
 
-// CHECK: define{{.*}} { float, i8 } @f_ret_float_int8_s()
+// CHECK-LABEL: define dso_local { float, i8 } @f_ret_float_int8_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct float_int8_s f_ret_float_int8_s(void) {
   return (struct float_int8_s){1.0, 2};
 }
 
-// CHECK: define{{.*}} void @f_float_uint8_s_arg(float %0, i8 %1)
+// CHECK-LABEL: define dso_local void @f_float_uint8_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_float_uint8_s_arg(struct float_uint8_s a) {}
 
-// CHECK: define{{.*}} { float, i8 } @f_ret_float_uint8_s()
+// CHECK-LABEL: define dso_local { float, i8 } @f_ret_float_uint8_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct float_uint8_s f_ret_float_uint8_s(void) {
   return (struct float_uint8_s){1.0, 2};
 }
 
-// CHECK: define{{.*}} void @f_float_int32_s_arg(float %0, i32 %1)
+// CHECK-LABEL: define dso_local void @f_float_int32_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_float_int32_s_arg(struct float_int32_s a) {}
 
-// CHECK: define{{.*}} { float, i32 } @f_ret_float_int32_s()
+// CHECK-LABEL: define dso_local { float, i32 } @f_ret_float_int32_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct float_int32_s f_ret_float_int32_s(void) {
   return (struct float_int32_s){1.0, 2};
 }
 
-// CHECK: define{{.*}} void @f_float_int64_s_arg(%struct.float_int64_s* noundef %a)
+// CHECK-LABEL: define dso_local void @f_float_int64_s_arg
+// CHECK-SAME: (ptr noundef [[A:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_float_int64_s_arg(struct float_int64_s a) {}
 
-// CHECK: define{{.*}} void @f_ret_float_int64_s(%struct.float_int64_s* noalias sret(%struct.float_int64_s) align 8 %agg.result)
+// CHECK-LABEL: define dso_local void @f_ret_float_int64_s
+// CHECK-SAME: (ptr noalias sret([[STRUCT_FLOAT_INT64_S:%.*]]) align 8 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct float_int64_s f_ret_float_int64_s(void) {
   return (struct float_int64_s){1.0, 2};
 }
 
-// CHECK: define{{.*}} void @f_float_int64bf_s_arg(float %0, i32 %1)
+// CHECK-LABEL: define dso_local void @f_float_int64bf_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_float_int64bf_s_arg(struct float_int64bf_s a) {}
 
-// CHECK: define{{.*}} { float, i32 } @f_ret_float_int64bf_s()
+// CHECK-LABEL: define dso_local { float, i32 } @f_ret_float_int64bf_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct float_int64bf_s f_ret_float_int64bf_s(void) {
   return (struct float_int64bf_s){1.0, 2};
 }
@@ -128,39 +189,63 @@
 // The zero-width bitfield means the struct can't be passed according to the
 // floating point calling convention.
 
-// CHECK: define{{.*}} void @f_float_int8_zbf_s(float %0, i8 %1)
+// CHECK-LABEL: define dso_local void @f_float_int8_zbf_s
+// CHECK-SAME: (float [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_float_int8_zbf_s(struct float_int8_zbf_s a) {}
 
-// CHECK: define{{.*}} { float, i8 } @f_ret_float_int8_zbf_s()
+// CHECK-LABEL: define dso_local { float, i8 } @f_ret_float_int8_zbf_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct float_int8_zbf_s f_ret_float_int8_zbf_s(void) {
   return (struct float_int8_zbf_s){1.0, 2};
 }
 
-// CHECK: define{{.*}} void @f_float_int8_s_arg_insufficient_gprs(i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d, i32 noundef %e, i32 noundef %f, i32 noundef %g, i32 noundef %h, [2 x i32] %i.coerce)
+// CHECK-LABEL: define dso_local void @f_float_int8_s_arg_insufficient_gprs
+// CHECK-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], i32 noundef [[C:%.*]], i32 noundef [[D:%.*]], i32 noundef [[E:%.*]], i32 noundef [[F:%.*]], i32 noundef [[G:%.*]], i32 noundef [[H:%.*]], [2 x i32] [[I_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_float_int8_s_arg_insufficient_gprs(int a, int b, int c, int d, int e,
                                           int f, int g, int h, struct float_int8_s i) {}
 
-// CHECK: define{{.*}} void @f_struct_float_int8_insufficient_fprs(float noundef %a, float noundef %b, float noundef %c, float noundef %d, float noundef %e, float noundef %f, float noundef %g, float noundef %h, [2 x i32] %i.coerce)
+// CHECK-LABEL: define dso_local void @f_struct_float_int8_insufficient_fprs
+// CHECK-SAME: (float noundef [[A:%.*]], float noundef [[B:%.*]], float noundef [[C:%.*]], float noundef [[D:%.*]], float noundef [[E:%.*]], float noundef [[F:%.*]], float noundef [[G:%.*]], float noundef [[H:%.*]], [2 x i32] [[I_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_struct_float_int8_insufficient_fprs(float a, float b, float c, float d,
                                            float e, float f, float g, float h, struct float_int8_s i) {}
 
 // Complex floating-point values or structs containing a single complex
 // floating-point value should be passed as if it were an fp+fp struct.
 
-// CHECK: define{{.*}} void @f_floatcomplex(float noundef %a.coerce0, float noundef %a.coerce1)
+// CHECK-LABEL: define dso_local void @f_floatcomplex
+// CHECK-SAME: (float noundef [[A_COERCE0:%.*]], float noundef [[A_COERCE1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_floatcomplex(float __complex__ a) {}
 
-// CHECK: define{{.*}} { float, float } @f_ret_floatcomplex()
+// CHECK-LABEL: define dso_local { float, float } @f_ret_floatcomplex
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 float __complex__ f_ret_floatcomplex(void) {
   return 1.0;
 }
 
 struct floatcomplex_s { float __complex__ c; };
 
-// CHECK: define{{.*}} void @f_floatcomplex_s_arg(float %0, float %1)
+// CHECK-LABEL: define dso_local void @f_floatcomplex_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_floatcomplex_s_arg(struct floatcomplex_s a) {}
 
-// CHECK: define{{.*}} { float, float } @f_ret_floatcomplex_s()
+// CHECK-LABEL: define dso_local { float, float } @f_ret_floatcomplex_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct floatcomplex_s f_ret_floatcomplex_s(void) {
   return (struct floatcomplex_s){1.0};
 }
@@ -170,60 +255,96 @@
 
 struct floatarr1_s { float a[1]; };
 
-// CHECK: define{{.*}} void @f_floatarr1_s_arg(float %0)
+// CHECK-LABEL: define dso_local void @f_floatarr1_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_floatarr1_s_arg(struct floatarr1_s a) {}
 
-// CHECK: define{{.*}} float @f_ret_floatarr1_s()
+// CHECK-LABEL: define dso_local float @f_ret_floatarr1_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct floatarr1_s f_ret_floatarr1_s(void) {
   return (struct floatarr1_s){{1.0}};
 }
 
 struct floatarr2_s { float a[2]; };
 
-// CHECK: define{{.*}} void @f_floatarr2_s_arg(float %0, float %1)
+// CHECK-LABEL: define dso_local void @f_floatarr2_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_floatarr2_s_arg(struct floatarr2_s a) {}
 
-// CHECK: define{{.*}} { float, float } @f_ret_floatarr2_s()
+// CHECK-LABEL: define dso_local { float, float } @f_ret_floatarr2_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct floatarr2_s f_ret_floatarr2_s(void) {
   return (struct floatarr2_s){{1.0, 2.0}};
 }
 
 struct floatarr2_tricky1_s { struct { float f[1]; } g[2]; };
 
-// CHECK: define{{.*}} void @f_floatarr2_tricky1_s_arg(float %0, float %1)
+// CHECK-LABEL: define dso_local void @f_floatarr2_tricky1_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_floatarr2_tricky1_s_arg(struct floatarr2_tricky1_s a) {}
 
-// CHECK: define{{.*}} { float, float } @f_ret_floatarr2_tricky1_s()
+// CHECK-LABEL: define dso_local { float, float } @f_ret_floatarr2_tricky1_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct floatarr2_tricky1_s f_ret_floatarr2_tricky1_s(void) {
   return (struct floatarr2_tricky1_s){{{{1.0}}, {{2.0}}}};
 }
 
 struct floatarr2_tricky2_s { struct {}; struct { float f[1]; } g[2]; };
 
-// CHECK: define{{.*}} void @f_floatarr2_tricky2_s_arg(float %0, float %1)
+// CHECK-LABEL: define dso_local void @f_floatarr2_tricky2_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_floatarr2_tricky2_s_arg(struct floatarr2_tricky2_s a) {}
 
-// CHECK: define{{.*}} { float, float } @f_ret_floatarr2_tricky2_s()
+// CHECK-LABEL: define dso_local { float, float } @f_ret_floatarr2_tricky2_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct floatarr2_tricky2_s f_ret_floatarr2_tricky2_s(void) {
   return (struct floatarr2_tricky2_s){{}, {{{1.0}}, {{2.0}}}};
 }
 
 struct floatarr2_tricky3_s { union {}; struct { float f[1]; } g[2]; };
 
-// CHECK: define{{.*}} void @f_floatarr2_tricky3_s_arg(float %0, float %1)
+// CHECK-LABEL: define dso_local void @f_floatarr2_tricky3_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_floatarr2_tricky3_s_arg(struct floatarr2_tricky3_s a) {}
 
-// CHECK: define{{.*}} { float, float } @f_ret_floatarr2_tricky3_s()
+// CHECK-LABEL: define dso_local { float, float } @f_ret_floatarr2_tricky3_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct floatarr2_tricky3_s f_ret_floatarr2_tricky3_s(void) {
   return (struct floatarr2_tricky3_s){{}, {{{1.0}}, {{2.0}}}};
 }
 
 struct floatarr2_tricky4_s { union {}; struct { struct {}; float f[1]; } g[2]; };
 
-// CHECK: define{{.*}} void @f_floatarr2_tricky4_s_arg(float %0, float %1)
+// CHECK-LABEL: define dso_local void @f_floatarr2_tricky4_s_arg
+// CHECK-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_floatarr2_tricky4_s_arg(struct floatarr2_tricky4_s a) {}
 
-// CHECK: define{{.*}} { float, float } @f_ret_floatarr2_tricky4_s()
+// CHECK-LABEL: define dso_local { float, float } @f_ret_floatarr2_tricky4_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct floatarr2_tricky4_s f_ret_floatarr2_tricky4_s(void) {
   return (struct floatarr2_tricky4_s){{}, {{{}, {1.0}}, {{}, {2.0}}}};
 }
@@ -233,30 +354,48 @@
 
 struct int_float_int_s { int a; float b; int c; };
 
-// CHECK: define{{.*}} void @f_int_float_int_s_arg(%struct.int_float_int_s* noundef %a)
+// CHECK-LABEL: define dso_local void @f_int_float_int_s_arg
+// CHECK-SAME: (ptr noundef [[A:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_int_float_int_s_arg(struct int_float_int_s a) {}
 
-// CHECK: define{{.*}} void @f_ret_int_float_int_s(%struct.int_float_int_s* noalias sret(%struct.int_float_int_s) align 4 %agg.result)
+// CHECK-LABEL: define dso_local void @f_ret_int_float_int_s
+// CHECK-SAME: (ptr noalias sret([[STRUCT_INT_FLOAT_INT_S:%.*]]) align 4 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct int_float_int_s f_ret_int_float_int_s(void) {
   return (struct int_float_int_s){1, 2.0, 3};
 }
 
 struct int64_float_s { int64_t a; float b; };
 
-// CHECK: define{{.*}} void @f_int64_float_s_arg(%struct.int64_float_s* noundef %a)
+// CHECK-LABEL: define dso_local void @f_int64_float_s_arg
+// CHECK-SAME: (ptr noundef [[A:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_int64_float_s_arg(struct int64_float_s a) {}
 
-// CHECK: define{{.*}} void @f_ret_int64_float_s(%struct.int64_float_s* noalias sret(%struct.int64_float_s) align 8 %agg.result)
+// CHECK-LABEL: define dso_local void @f_ret_int64_float_s
+// CHECK-SAME: (ptr noalias sret([[STRUCT_INT64_FLOAT_S:%.*]]) align 8 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct int64_float_s f_ret_int64_float_s(void) {
   return (struct int64_float_s){1, 2.0};
 }
 
 struct char_char_float_s { char a; char b; float c; };
 
-// CHECK-LABEL: define{{.*}} void @f_char_char_float_s_arg([2 x i32] %a.coerce)
+// CHECK-LABEL: define dso_local void @f_char_char_float_s_arg
+// CHECK-SAME: ([2 x i32] [[A_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_char_char_float_s_arg(struct char_char_float_s a) {}
 
-// CHECK: define{{.*}} [2 x i32] @f_ret_char_char_float_s()
+// CHECK-LABEL: define dso_local [2 x i32] @f_ret_char_char_float_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct char_char_float_s f_ret_char_char_float_s(void) {
   return (struct char_char_float_s){1, 2, 3.0};
 }
@@ -266,10 +405,16 @@
 
 union float_u { float a; };
 
-// CHECK: define{{.*}} void @f_float_u_arg(i32 %a.coerce)
+// CHECK-LABEL: define dso_local void @f_float_u_arg
+// CHECK-SAME: (i32 [[A_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_float_u_arg(union float_u a) {}
 
-// CHECK: define{{.*}} i32 @f_ret_float_u()
+// CHECK-LABEL: define dso_local i32 @f_ret_float_u
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 union float_u f_ret_float_u(void) {
   return (union float_u){1.0};
 }
Index: clang/test/CodeGen/RISCV/riscv32-ilp32f-abi.c
===================================================================
--- clang/test/CodeGen/RISCV/riscv32-ilp32f-abi.c
+++ clang/test/CodeGen/RISCV/riscv32-ilp32f-abi.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -no-opaque-pointers -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --filter "^define |^entry:"
+// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
 
 #include <stdint.h>
@@ -6,27 +7,42 @@
 // Doubles are still passed in GPRs, so the 'e' argument will be anyext as
 // GPRs are exhausted.
 
-// CHECK: define{{.*}} void @f_fpr_tracking(double noundef %a, double noundef %b, double noundef %c, double noundef %d, i8 noundef %e)
+// CHECK-LABEL: define dso_local void @f_fpr_tracking
+// CHECK-SAME: (double noundef [[A:%.*]], double noundef [[B:%.*]], double noundef [[C:%.*]], double noundef [[D:%.*]], i8 noundef [[E:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK:  entry:
+//
 void f_fpr_tracking(double a, double b, double c, double d, int8_t e) {}
 
 // Lowering for doubles is unnmodified, as 64 > FLEN.
 
 struct double_s { double d; };
 
-// CHECK: define{{.*}} void @f_double_s_arg(i64 %a.coerce)
+// CHECK-LABEL: define dso_local void @f_double_s_arg
+// CHECK-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_s_arg(struct double_s a) {}
 
-// CHECK: define{{.*}} i64 @f_ret_double_s()
+// CHECK-LABEL: define dso_local i64 @f_ret_double_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct double_s f_ret_double_s(void) {
   return (struct double_s){1.0};
 }
 
 struct double_double_s { double d; double e; };
 
-// CHECK: define{{.*}} void @f_double_double_s_arg(%struct.double_double_s* noundef %a)
+// CHECK-LABEL: define dso_local void @f_double_double_s_arg
+// CHECK-SAME: (ptr noundef [[A:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_double_s_arg(struct double_double_s a) {}
 
-// CHECK: define{{.*}} void @f_ret_double_double_s(%struct.double_double_s* noalias sret(%struct.double_double_s) align 8 %agg.result)
+// CHECK-LABEL: define dso_local void @f_ret_double_double_s
+// CHECK-SAME: (ptr noalias sret([[STRUCT_DOUBLE_DOUBLE_S:%.*]]) align 8 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct double_double_s f_ret_double_double_s(void) {
   return (struct double_double_s){1.0, 2.0};
 }
@@ -35,10 +51,16 @@
 
 struct int_double_s { int a; double b; };
 
-// CHECK: define{{.*}} void @f_int_double_s_arg(%struct.int_double_s* noundef %a)
+// CHECK-LABEL: define dso_local void @f_int_double_s_arg
+// CHECK-SAME: (ptr noundef [[A:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_int_double_s_arg(struct int_double_s a) {}
 
-// CHECK: define{{.*}} void @f_ret_int_double_s(%struct.int_double_s* noalias sret(%struct.int_double_s) align 8 %agg.result)
+// CHECK-LABEL: define dso_local void @f_ret_int_double_s
+// CHECK-SAME: (ptr noalias sret([[STRUCT_INT_DOUBLE_S:%.*]]) align 8 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct int_double_s f_ret_int_double_s(void) {
   return (struct int_double_s){1, 2.0};
 }
Index: clang/test/CodeGen/RISCV/riscv32-ilp32d-abi.c
===================================================================
--- clang/test/CodeGen/RISCV/riscv32-ilp32d-abi.c
+++ clang/test/CodeGen/RISCV/riscv32-ilp32d-abi.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -no-opaque-pointers -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm %s -o - \
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --filter "^define |^entry:"
+// RUN: %clang_cc1 -triple riscv32 -target-feature +d -target-feature +f -target-abi ilp32d -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
 
 #include <stdint.h>
@@ -9,7 +10,10 @@
 // Doubles are passed in FPRs, so argument 'i' will be passed zero-extended
 // because it will be passed in a GPR.
 
-// CHECK: define{{.*}} void @f_fpr_tracking(double noundef %a, double noundef %b, double noundef %c, double noundef %d, double noundef %e, double noundef %f, double noundef %g, double noundef %h, i8 noundef zeroext %i)
+// CHECK-LABEL: define dso_local void @f_fpr_tracking
+// CHECK-SAME: (double noundef [[A:%.*]], double noundef [[B:%.*]], double noundef [[C:%.*]], double noundef [[D:%.*]], double noundef [[E:%.*]], double noundef [[F:%.*]], double noundef [[G:%.*]], double noundef [[H:%.*]], i8 noundef zeroext [[I:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK:  entry:
+//
 void f_fpr_tracking(double a, double b, double c, double d, double e, double f,
                     double g, double h, uint8_t i) {}
 
@@ -25,10 +29,16 @@
 
 struct double_s { double f; };
 
-// CHECK: define{{.*}} void @f_double_s_arg(double %0)
+// CHECK-LABEL: define dso_local void @f_double_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_s_arg(struct double_s a) {}
 
-// CHECK: define{{.*}} double @f_ret_double_s()
+// CHECK-LABEL: define dso_local double @f_ret_double_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct double_s f_ret_double_s(void) {
   return (struct double_s){1.0};
 }
@@ -39,18 +49,30 @@
 struct zbf_double_s { int : 0; double f; };
 struct zbf_double_zbf_s { int : 0; double f; int : 0; };
 
-// CHECK: define{{.*}} void @f_zbf_double_s_arg(double %0)
+// CHECK-LABEL: define dso_local void @f_zbf_double_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_zbf_double_s_arg(struct zbf_double_s a) {}
 
-// CHECK: define{{.*}} double @f_ret_zbf_double_s()
+// CHECK-LABEL: define dso_local double @f_ret_zbf_double_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct zbf_double_s f_ret_zbf_double_s(void) {
   return (struct zbf_double_s){1.0};
 }
 
-// CHECK: define{{.*}} void @f_zbf_double_zbf_s_arg(double %0)
+// CHECK-LABEL: define dso_local void @f_zbf_double_zbf_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_zbf_double_zbf_s_arg(struct zbf_double_zbf_s a) {}
 
-// CHECK: define{{.*}} double @f_ret_zbf_double_zbf_s()
+// CHECK-LABEL: define dso_local double @f_ret_zbf_double_zbf_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct zbf_double_zbf_s f_ret_zbf_double_zbf_s(void) {
   return (struct zbf_double_zbf_s){1.0};
 }
@@ -61,23 +83,38 @@
 struct double_double_s { double f; double g; };
 struct double_float_s { double f; float g; };
 
-// CHECK: define{{.*}} void @f_double_double_s_arg(double %0, double %1)
+// CHECK-LABEL: define dso_local void @f_double_double_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_double_s_arg(struct double_double_s a) {}
 
-// CHECK: define{{.*}} { double, double } @f_ret_double_double_s()
+// CHECK-LABEL: define dso_local { double, double } @f_ret_double_double_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct double_double_s f_ret_double_double_s(void) {
   return (struct double_double_s){1.0, 2.0};
 }
 
-// CHECK: define{{.*}} void @f_double_float_s_arg(double %0, float %1)
+// CHECK-LABEL: define dso_local void @f_double_float_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_float_s_arg(struct double_float_s a) {}
 
-// CHECK: define{{.*}} { double, float } @f_ret_double_float_s()
+// CHECK-LABEL: define dso_local { double, float } @f_ret_double_float_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct double_float_s f_ret_double_float_s(void) {
   return (struct double_float_s){1.0, 2.0};
 }
 
-// CHECK: define{{.*}} void @f_double_double_s_arg_insufficient_fprs(float noundef %a, double noundef %b, double noundef %c, double noundef %d, double noundef %e, double noundef %f, double noundef %g, %struct.double_double_s* noundef %h)
+// CHECK-LABEL: define dso_local void @f_double_double_s_arg_insufficient_fprs
+// CHECK-SAME: (float noundef [[A:%.*]], double noundef [[B:%.*]], double noundef [[C:%.*]], double noundef [[D:%.*]], double noundef [[E:%.*]], double noundef [[F:%.*]], double noundef [[G:%.*]], ptr noundef [[H:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_double_s_arg_insufficient_fprs(float a, double b, double c, double d,
     double e, double f, double g, struct double_double_s h) {}
 
@@ -92,42 +129,72 @@
 struct double_int64bf_s { double f; int64_t i : 32; };
 struct double_int8_zbf_s { double f; int8_t i; int : 0; };
 
-// CHECK: define{{.*}} void @f_double_int8_s_arg(double %0, i8 %1)
+// CHECK-LABEL: define dso_local void @f_double_int8_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_int8_s_arg(struct double_int8_s a) {}
 
-// CHECK: define{{.*}} { double, i8 } @f_ret_double_int8_s()
+// CHECK-LABEL: define dso_local { double, i8 } @f_ret_double_int8_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct double_int8_s f_ret_double_int8_s(void) {
   return (struct double_int8_s){1.0, 2};
 }
 
-// CHECK: define{{.*}} void @f_double_uint8_s_arg(double %0, i8 %1)
+// CHECK-LABEL: define dso_local void @f_double_uint8_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_uint8_s_arg(struct double_uint8_s a) {}
 
-// CHECK: define{{.*}} { double, i8 } @f_ret_double_uint8_s()
+// CHECK-LABEL: define dso_local { double, i8 } @f_ret_double_uint8_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct double_uint8_s f_ret_double_uint8_s(void) {
   return (struct double_uint8_s){1.0, 2};
 }
 
-// CHECK: define{{.*}} void @f_double_int32_s_arg(double %0, i32 %1)
+// CHECK-LABEL: define dso_local void @f_double_int32_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_int32_s_arg(struct double_int32_s a) {}
 
-// CHECK: define{{.*}} { double, i32 } @f_ret_double_int32_s()
+// CHECK-LABEL: define dso_local { double, i32 } @f_ret_double_int32_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct double_int32_s f_ret_double_int32_s(void) {
   return (struct double_int32_s){1.0, 2};
 }
 
-// CHECK: define{{.*}} void @f_double_int64_s_arg(%struct.double_int64_s* noundef %a)
+// CHECK-LABEL: define dso_local void @f_double_int64_s_arg
+// CHECK-SAME: (ptr noundef [[A:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_int64_s_arg(struct double_int64_s a) {}
 
-// CHECK: define{{.*}} void @f_ret_double_int64_s(%struct.double_int64_s* noalias sret(%struct.double_int64_s) align 8 %agg.result)
+// CHECK-LABEL: define dso_local void @f_ret_double_int64_s
+// CHECK-SAME: (ptr noalias sret([[STRUCT_DOUBLE_INT64_S:%.*]]) align 8 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct double_int64_s f_ret_double_int64_s(void) {
   return (struct double_int64_s){1.0, 2};
 }
 
-// CHECK: define{{.*}} void @f_double_int64bf_s_arg(double %0, i32 %1)
+// CHECK-LABEL: define dso_local void @f_double_int64bf_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_int64bf_s_arg(struct double_int64bf_s a) {}
 
-// CHECK: define{{.*}} { double, i32 } @f_ret_double_int64bf_s()
+// CHECK-LABEL: define dso_local { double, i32 } @f_ret_double_int64bf_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct double_int64bf_s f_ret_double_int64bf_s(void) {
   return (struct double_int64bf_s){1.0, 2};
 }
@@ -135,39 +202,63 @@
 // The zero-width bitfield means the struct can't be passed according to the
 // floating point calling convention.
 
-// CHECK: define{{.*}} void @f_double_int8_zbf_s(double %0, i8 %1)
+// CHECK-LABEL: define dso_local void @f_double_int8_zbf_s
+// CHECK-SAME: (double [[TMP0:%.*]], i8 [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_int8_zbf_s(struct double_int8_zbf_s a) {}
 
-// CHECK: define{{.*}} { double, i8 } @f_ret_double_int8_zbf_s()
+// CHECK-LABEL: define dso_local { double, i8 } @f_ret_double_int8_zbf_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct double_int8_zbf_s f_ret_double_int8_zbf_s(void) {
   return (struct double_int8_zbf_s){1.0, 2};
 }
 
-// CHECK: define{{.*}} void @f_double_int8_s_arg_insufficient_gprs(i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d, i32 noundef %e, i32 noundef %f, i32 noundef %g, i32 noundef %h, %struct.double_int8_s* noundef %i)
+// CHECK-LABEL: define dso_local void @f_double_int8_s_arg_insufficient_gprs
+// CHECK-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], i32 noundef [[C:%.*]], i32 noundef [[D:%.*]], i32 noundef [[E:%.*]], i32 noundef [[F:%.*]], i32 noundef [[G:%.*]], i32 noundef [[H:%.*]], ptr noundef [[I:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_int8_s_arg_insufficient_gprs(int a, int b, int c, int d, int e,
                                           int f, int g, int h, struct double_int8_s i) {}
 
-// CHECK: define{{.*}} void @f_struct_double_int8_insufficient_fprs(float noundef %a, double noundef %b, double noundef %c, double noundef %d, double noundef %e, double noundef %f, double noundef %g, double noundef %h, %struct.double_int8_s* noundef %i)
+// CHECK-LABEL: define dso_local void @f_struct_double_int8_insufficient_fprs
+// CHECK-SAME: (float noundef [[A:%.*]], double noundef [[B:%.*]], double noundef [[C:%.*]], double noundef [[D:%.*]], double noundef [[E:%.*]], double noundef [[F:%.*]], double noundef [[G:%.*]], double noundef [[H:%.*]], ptr noundef [[I:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_struct_double_int8_insufficient_fprs(float a, double b, double c, double d,
                                            double e, double f, double g, double h, struct double_int8_s i) {}
 
 // Complex floating-point values or structs containing a single complex
 // floating-point value should be passed as if it were an fp+fp struct.
 
-// CHECK: define{{.*}} void @f_doublecomplex(double noundef %a.coerce0, double noundef %a.coerce1)
+// CHECK-LABEL: define dso_local void @f_doublecomplex
+// CHECK-SAME: (double noundef [[A_COERCE0:%.*]], double noundef [[A_COERCE1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_doublecomplex(double __complex__ a) {}
 
-// CHECK: define{{.*}} { double, double } @f_ret_doublecomplex()
+// CHECK-LABEL: define dso_local { double, double } @f_ret_doublecomplex
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 double __complex__ f_ret_doublecomplex(void) {
   return 1.0;
 }
 
 struct doublecomplex_s { double __complex__ c; };
 
-// CHECK: define{{.*}} void @f_doublecomplex_s_arg(double %0, double %1)
+// CHECK-LABEL: define dso_local void @f_doublecomplex_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_doublecomplex_s_arg(struct doublecomplex_s a) {}
 
-// CHECK: define{{.*}} { double, double } @f_ret_doublecomplex_s()
+// CHECK-LABEL: define dso_local { double, double } @f_ret_doublecomplex_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct doublecomplex_s f_ret_doublecomplex_s(void) {
   return (struct doublecomplex_s){1.0};
 }
@@ -177,60 +268,96 @@
 
 struct doublearr1_s { double a[1]; };
 
-// CHECK: define{{.*}} void @f_doublearr1_s_arg(double %0)
+// CHECK-LABEL: define dso_local void @f_doublearr1_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_doublearr1_s_arg(struct doublearr1_s a) {}
 
-// CHECK: define{{.*}} double @f_ret_doublearr1_s()
+// CHECK-LABEL: define dso_local double @f_ret_doublearr1_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct doublearr1_s f_ret_doublearr1_s(void) {
   return (struct doublearr1_s){{1.0}};
 }
 
 struct doublearr2_s { double a[2]; };
 
-// CHECK: define{{.*}} void @f_doublearr2_s_arg(double %0, double %1)
+// CHECK-LABEL: define dso_local void @f_doublearr2_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_doublearr2_s_arg(struct doublearr2_s a) {}
 
-// CHECK: define{{.*}} { double, double } @f_ret_doublearr2_s()
+// CHECK-LABEL: define dso_local { double, double } @f_ret_doublearr2_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct doublearr2_s f_ret_doublearr2_s(void) {
   return (struct doublearr2_s){{1.0, 2.0}};
 }
 
 struct doublearr2_tricky1_s { struct { double f[1]; } g[2]; };
 
-// CHECK: define{{.*}} void @f_doublearr2_tricky1_s_arg(double %0, double %1)
+// CHECK-LABEL: define dso_local void @f_doublearr2_tricky1_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_doublearr2_tricky1_s_arg(struct doublearr2_tricky1_s a) {}
 
-// CHECK: define{{.*}} { double, double } @f_ret_doublearr2_tricky1_s()
+// CHECK-LABEL: define dso_local { double, double } @f_ret_doublearr2_tricky1_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct doublearr2_tricky1_s f_ret_doublearr2_tricky1_s(void) {
   return (struct doublearr2_tricky1_s){{{{1.0}}, {{2.0}}}};
 }
 
 struct doublearr2_tricky2_s { struct {}; struct { double f[1]; } g[2]; };
 
-// CHECK: define{{.*}} void @f_doublearr2_tricky2_s_arg(double %0, double %1)
+// CHECK-LABEL: define dso_local void @f_doublearr2_tricky2_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_doublearr2_tricky2_s_arg(struct doublearr2_tricky2_s a) {}
 
-// CHECK: define{{.*}} { double, double } @f_ret_doublearr2_tricky2_s()
+// CHECK-LABEL: define dso_local { double, double } @f_ret_doublearr2_tricky2_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct doublearr2_tricky2_s f_ret_doublearr2_tricky2_s(void) {
   return (struct doublearr2_tricky2_s){{}, {{{1.0}}, {{2.0}}}};
 }
 
 struct doublearr2_tricky3_s { union {}; struct { double f[1]; } g[2]; };
 
-// CHECK: define{{.*}} void @f_doublearr2_tricky3_s_arg(double %0, double %1)
+// CHECK-LABEL: define dso_local void @f_doublearr2_tricky3_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_doublearr2_tricky3_s_arg(struct doublearr2_tricky3_s a) {}
 
-// CHECK: define{{.*}} { double, double } @f_ret_doublearr2_tricky3_s()
+// CHECK-LABEL: define dso_local { double, double } @f_ret_doublearr2_tricky3_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct doublearr2_tricky3_s f_ret_doublearr2_tricky3_s(void) {
   return (struct doublearr2_tricky3_s){{}, {{{1.0}}, {{2.0}}}};
 }
 
 struct doublearr2_tricky4_s { union {}; struct { struct {}; double f[1]; } g[2]; };
 
-// CHECK: define{{.*}} void @f_doublearr2_tricky4_s_arg(double %0, double %1)
+// CHECK-LABEL: define dso_local void @f_doublearr2_tricky4_s_arg
+// CHECK-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_doublearr2_tricky4_s_arg(struct doublearr2_tricky4_s a) {}
 
-// CHECK: define{{.*}} { double, double } @f_ret_doublearr2_tricky4_s()
+// CHECK-LABEL: define dso_local { double, double } @f_ret_doublearr2_tricky4_s
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct doublearr2_tricky4_s f_ret_doublearr2_tricky4_s(void) {
   return (struct doublearr2_tricky4_s){{}, {{{}, {1.0}}, {{}, {2.0}}}};
 }
@@ -240,30 +367,48 @@
 
 struct int_double_int_s { int a; double b; int c; };
 
-// CHECK: define{{.*}} void @f_int_double_int_s_arg(%struct.int_double_int_s* noundef %a)
+// CHECK-LABEL: define dso_local void @f_int_double_int_s_arg
+// CHECK-SAME: (ptr noundef [[A:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_int_double_int_s_arg(struct int_double_int_s a) {}
 
-// CHECK: define{{.*}} void @f_ret_int_double_int_s(%struct.int_double_int_s* noalias sret(%struct.int_double_int_s) align 8 %agg.result)
+// CHECK-LABEL: define dso_local void @f_ret_int_double_int_s
+// CHECK-SAME: (ptr noalias sret([[STRUCT_INT_DOUBLE_INT_S:%.*]]) align 8 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct int_double_int_s f_ret_int_double_int_s(void) {
   return (struct int_double_int_s){1, 2.0, 3};
 }
 
 struct int64_double_s { int64_t a; double b; };
 
-// CHECK: define{{.*}} void @f_int64_double_s_arg(%struct.int64_double_s* noundef %a)
+// CHECK-LABEL: define dso_local void @f_int64_double_s_arg
+// CHECK-SAME: (ptr noundef [[A:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_int64_double_s_arg(struct int64_double_s a) {}
 
-// CHECK: define{{.*}} void @f_ret_int64_double_s(%struct.int64_double_s* noalias sret(%struct.int64_double_s) align 8 %agg.result)
+// CHECK-LABEL: define dso_local void @f_ret_int64_double_s
+// CHECK-SAME: (ptr noalias sret([[STRUCT_INT64_DOUBLE_S:%.*]]) align 8 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct int64_double_s f_ret_int64_double_s(void) {
   return (struct int64_double_s){1, 2.0};
 }
 
 struct char_char_double_s { char a; char b; double c; };
 
-// CHECK-LABEL: define{{.*}} void @f_char_char_double_s_arg(%struct.char_char_double_s* noundef %a)
+// CHECK-LABEL: define dso_local void @f_char_char_double_s_arg
+// CHECK-SAME: (ptr noundef [[A:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_char_char_double_s_arg(struct char_char_double_s a) {}
 
-// CHECK: define{{.*}} void @f_ret_char_char_double_s(%struct.char_char_double_s* noalias sret(%struct.char_char_double_s) align 8 %agg.result)
+// CHECK-LABEL: define dso_local void @f_ret_char_char_double_s
+// CHECK-SAME: (ptr noalias sret([[STRUCT_CHAR_CHAR_DOUBLE_S:%.*]]) align 8 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct char_char_double_s f_ret_char_char_double_s(void) {
   return (struct char_char_double_s){1, 2, 3.0};
 }
@@ -273,10 +418,16 @@
 
 union double_u { double a; };
 
-// CHECK: define{{.*}} void @f_double_u_arg(i64 %a.coerce)
+// CHECK-LABEL: define dso_local void @f_double_u_arg
+// CHECK-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_double_u_arg(union double_u a) {}
 
-// CHECK: define{{.*}} i64 @f_ret_double_u()
+// CHECK-LABEL: define dso_local i64 @f_ret_double_u
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 union double_u f_ret_double_u(void) {
   return (union double_u){1.0};
 }
@@ -287,19 +438,28 @@
 // returned in registers). This includes complex doubles, which are treated as
 // double+double structs by the ABI.
 
-// CHECK: define{{.*}} { double, i32 } @f_ret_double_int32_s_double_int32_s_just_sufficient_gprs(i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d, i32 noundef %e, i32 noundef %f, i32 noundef %g, double %0, i32 %1)
+// CHECK-LABEL: define dso_local { double, i32 } @f_ret_double_int32_s_double_int32_s_just_sufficient_gprs
+// CHECK-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], i32 noundef [[C:%.*]], i32 noundef [[D:%.*]], i32 noundef [[E:%.*]], i32 noundef [[F:%.*]], i32 noundef [[G:%.*]], double [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct double_int32_s f_ret_double_int32_s_double_int32_s_just_sufficient_gprs(
     int a, int b, int c, int d, int e, int f, int g, struct double_int32_s h) {
   return (struct double_int32_s){1.0, 2};
 }
 
-// CHECK: define{{.*}} { double, double } @f_ret_double_double_s_double_int32_s_just_sufficient_gprs(i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d, i32 noundef %e, i32 noundef %f, i32 noundef %g, double %0, i32 %1)
+// CHECK-LABEL: define dso_local { double, double } @f_ret_double_double_s_double_int32_s_just_sufficient_gprs
+// CHECK-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], i32 noundef [[C:%.*]], i32 noundef [[D:%.*]], i32 noundef [[E:%.*]], i32 noundef [[F:%.*]], i32 noundef [[G:%.*]], double [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct double_double_s f_ret_double_double_s_double_int32_s_just_sufficient_gprs(
     int a, int b, int c, int d, int e, int f, int g, struct double_int32_s h) {
   return (struct double_double_s){1.0, 2.0};
 }
 
-// CHECK: define{{.*}} { double, double } @f_ret_doublecomplex_double_int32_s_just_sufficient_gprs(i32 noundef %a, i32 noundef %b, i32 noundef %c, i32 noundef %d, i32 noundef %e, i32 noundef %f, i32 noundef %g, double %0, i32 %1)
+// CHECK-LABEL: define dso_local { double, double } @f_ret_doublecomplex_double_int32_s_just_sufficient_gprs
+// CHECK-SAME: (i32 noundef [[A:%.*]], i32 noundef [[B:%.*]], i32 noundef [[C:%.*]], i32 noundef [[D:%.*]], i32 noundef [[E:%.*]], i32 noundef [[F:%.*]], i32 noundef [[G:%.*]], double [[TMP0:%.*]], i32 [[TMP1:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 double __complex__ f_ret_doublecomplex_double_int32_s_just_sufficient_gprs(
     int a, int b, int c, int d, int e, int f, int g, struct double_int32_s h) {
   return 1.0;
Index: clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-ilp32d-abi.c
===================================================================
--- clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-ilp32d-abi.c
+++ clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-ilp32d-abi.c
@@ -1,3 +1,4 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --filter "^define |^entry:"
 // RUN: %clang_cc1 -no-opaque-pointers -triple riscv32 -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -no-opaque-pointers -triple riscv32 -emit-llvm -fforce-enable-int128 %s -o - \
 // RUN:   | FileCheck %s -check-prefixes=CHECK,CHECK-FORCEINT128
@@ -12,57 +13,93 @@
 #include <stddef.h>
 #include <stdint.h>
 
-// CHECK-LABEL: define{{.*}} void @f_void()
+// CHECK-LABEL: define dso_local void @f_void
+// CHECK-SAME: () #[[ATTR0:[0-9]+]] {
+// CHECK:  entry:
+//
 void f_void(void) {}
 
 // Scalar arguments and return values smaller than the word size are extended
 // according to the sign of their type, up to 32 bits
 
-// CHECK-LABEL: define{{.*}} zeroext i1 @f_scalar_0(i1 noundef zeroext %x)
+// CHECK-LABEL: define dso_local zeroext i1 @f_scalar_0
+// CHECK-SAME: (i1 noundef zeroext [[X:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 _Bool f_scalar_0(_Bool x) { return x; }
 
-// CHECK-LABEL: define{{.*}} signext i8 @f_scalar_1(i8 noundef signext %x)
+// CHECK-LABEL: define dso_local signext i8 @f_scalar_1
+// CHECK-SAME: (i8 noundef signext [[X:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 int8_t f_scalar_1(int8_t x) { return x; }
 
-// CHECK-LABEL: define{{.*}} zeroext i8 @f_scalar_2(i8 noundef zeroext %x)
+// CHECK-LABEL: define dso_local zeroext i8 @f_scalar_2
+// CHECK-SAME: (i8 noundef zeroext [[X:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 uint8_t f_scalar_2(uint8_t x) { return x; }
 
-// CHECK-LABEL: define{{.*}} i32 @f_scalar_3(i32 noundef %x)
+// CHECK-LABEL: define dso_local i32 @f_scalar_3
+// CHECK-SAME: (i32 noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 int32_t f_scalar_3(int32_t x) { return x; }
 
-// CHECK-LABEL: define{{.*}} i64 @f_scalar_4(i64 noundef %x)
+// CHECK-LABEL: define dso_local i64 @f_scalar_4
+// CHECK-SAME: (i64 noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 int64_t f_scalar_4(int64_t x) { return x; }
 
 #ifdef __SIZEOF_INT128__
-// CHECK-FORCEINT128-LABEL: define{{.*}} i128 @f_scalar_5(i128 noundef %x)
+// CHECK-FORCEINT128-LABEL: define dso_local i128 @f_scalar_5
+// CHECK-FORCEINT128-SAME: (i128 noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK-FORCEINT128:  entry:
+//
 __int128_t f_scalar_5(__int128_t x) { return x; }
 #endif
 
-// CHECK-LABEL: define{{.*}} float @f_fp_scalar_1(float noundef %x)
+// CHECK-LABEL: define dso_local float @f_fp_scalar_1
+// CHECK-SAME: (float noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 float f_fp_scalar_1(float x) { return x; }
 
-// CHECK-LABEL: define{{.*}} double @f_fp_scalar_2(double noundef %x)
+// CHECK-LABEL: define dso_local double @f_fp_scalar_2
+// CHECK-SAME: (double noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 double f_fp_scalar_2(double x) { return x; }
 
 // Scalars larger than 2*xlen are passed/returned indirect. However, the
 // RISC-V LLVM backend can handle this fine, so the function doesn't need to
 // be modified.
 
-// CHECK-LABEL: define{{.*}} fp128 @f_fp_scalar_3(fp128 noundef %x)
+// CHECK-LABEL: define dso_local fp128 @f_fp_scalar_3
+// CHECK-SAME: (fp128 noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 long double f_fp_scalar_3(long double x) { return x; }
 
 // Empty structs or unions are ignored.
 
 struct empty_s {};
 
-// CHECK-LABEL: define{{.*}} void @f_agg_empty_struct()
+// CHECK-LABEL: define dso_local void @f_agg_empty_struct
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct empty_s f_agg_empty_struct(struct empty_s x) {
   return x;
 }
 
 union empty_u {};
 
-// CHECK-LABEL: define{{.*}} void @f_agg_empty_union()
+// CHECK-LABEL: define dso_local void @f_agg_empty_union
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 union empty_u f_agg_empty_union(union empty_u x) {
   return x;
 }
@@ -74,13 +111,19 @@
   uint8_t a, b, c, d;
 };
 
-// CHECK-LABEL: define{{.*}} void @f_agg_tiny(i32 %x.coerce)
+// CHECK-LABEL: define dso_local void @f_agg_tiny
+// CHECK-SAME: (i32 [[X_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_agg_tiny(struct tiny x) {
   x.a += x.b;
   x.c += x.d;
 }
 
-// CHECK-LABEL: define{{.*}} i32 @f_agg_tiny_ret()
+// CHECK-LABEL: define dso_local i32 @f_agg_tiny_ret
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct tiny f_agg_tiny_ret(void) {
   return (struct tiny){1, 2, 3, 4};
 }
@@ -88,23 +131,35 @@
 typedef uint8_t v4i8 __attribute__((vector_size(4)));
 typedef int32_t v1i32 __attribute__((vector_size(4)));
 
-// CHECK-LABEL: define{{.*}} void @f_vec_tiny_v4i8(i32 noundef %x.coerce)
+// CHECK-LABEL: define dso_local void @f_vec_tiny_v4i8
+// CHECK-SAME: (i32 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_vec_tiny_v4i8(v4i8 x) {
   x[0] = x[1];
   x[2] = x[3];
 }
 
-// CHECK-LABEL: define{{.*}} i32 @f_vec_tiny_v4i8_ret()
+// CHECK-LABEL: define dso_local i32 @f_vec_tiny_v4i8_ret
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 v4i8 f_vec_tiny_v4i8_ret(void) {
   return (v4i8){1, 2, 3, 4};
 }
 
-// CHECK-LABEL: define{{.*}} void @f_vec_tiny_v1i32(i32 noundef %x.coerce)
+// CHECK-LABEL: define dso_local void @f_vec_tiny_v1i32
+// CHECK-SAME: (i32 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_vec_tiny_v1i32(v1i32 x) {
   x[0] = 114;
 }
 
-// CHECK-LABEL: define{{.*}} i32 @f_vec_tiny_v1i32_ret()
+// CHECK-LABEL: define dso_local i32 @f_vec_tiny_v1i32_ret
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 v1i32 f_vec_tiny_v1i32_ret(void) {
   return (v1i32){1};
 }
@@ -113,13 +168,19 @@
   int32_t a, *b;
 };
 
-// CHECK-LABEL: define{{.*}} void @f_agg_small([2 x i32] %x.coerce)
+// CHECK-LABEL: define dso_local void @f_agg_small
+// CHECK-SAME: ([2 x i32] [[X_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_agg_small(struct small x) {
   x.a += *x.b;
   x.b = &x.a;
 }
 
-// CHECK-LABEL: define{{.*}} [2 x i32] @f_agg_small_ret()
+// CHECK-LABEL: define dso_local [2 x i32] @f_agg_small_ret
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct small f_agg_small_ret(void) {
   return (struct small){1, 0};
 }
@@ -127,22 +188,34 @@
 typedef uint8_t v8i8 __attribute__((vector_size(8)));
 typedef int64_t v1i64 __attribute__((vector_size(8)));
 
-// CHECK-LABEL: define{{.*}} void @f_vec_small_v8i8(i64 noundef %x.coerce)
+// CHECK-LABEL: define dso_local void @f_vec_small_v8i8
+// CHECK-SAME: (i64 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_vec_small_v8i8(v8i8 x) {
   x[0] = x[7];
 }
 
-// CHECK-LABEL: define{{.*}} i64 @f_vec_small_v8i8_ret()
+// CHECK-LABEL: define dso_local i64 @f_vec_small_v8i8_ret
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 v8i8 f_vec_small_v8i8_ret(void) {
   return (v8i8){1, 2, 3, 4, 5, 6, 7, 8};
 }
 
-// CHECK-LABEL: define{{.*}} void @f_vec_small_v1i64(i64 noundef %x.coerce)
+// CHECK-LABEL: define dso_local void @f_vec_small_v1i64
+// CHECK-SAME: (i64 noundef [[X_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_vec_small_v1i64(v1i64 x) {
   x[0] = 114;
 }
 
-// CHECK-LABEL: define{{.*}} i64 @f_vec_small_v1i64_ret()
+// CHECK-LABEL: define dso_local i64 @f_vec_small_v1i64_ret
+// CHECK-SAME: () #[[ATTR0]] {
+// CHECK:  entry:
+//
 v1i64 f_vec_small_v1i64_ret(void) {
   return (v1i64){1};
 }
@@ -155,12 +228,18 @@
   int64_t a;
 };
 
-// CHECK-LABEL: define{{.*}} void @f_agg_small_aligned(i64 %x.coerce)
+// CHECK-LABEL: define dso_local void @f_agg_small_aligned
+// CHECK-SAME: (i64 [[X_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_agg_small_aligned(struct small_aligned x) {
   x.a += x.a;
 }
 
-// CHECK-LABEL: define{{.*}} i64 @f_agg_small_aligned_ret(i64 %x.coerce)
+// CHECK-LABEL: define dso_local i64 @f_agg_small_aligned_ret
+// CHECK-SAME: (i64 [[X_COERCE:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct small_aligned f_agg_small_aligned_ret(struct small_aligned x) {
   return (struct small_aligned){10};
 }
@@ -170,26 +249,38 @@
   int32_t a, b, c, d;
 };
 
-// CHECK-LABEL: define{{.*}} void @f_agg_large(%struct.large* noundef %x)
+// CHECK-LABEL: define dso_local void @f_agg_large
+// CHECK-SAME: (%struct.large* noundef [[X:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_agg_large(struct large x) {
   x.a = x.b + x.c + x.d;
 }
 
 // The address where the struct should be written to will be the first
 // argument
-// CHECK-LABEL: define{{.*}} void @f_agg_large_ret(%struct.large* noalias sret(%struct.large) align 4 %agg.result, i32 noundef %i, i8 noundef signext %j)
+// CHECK-LABEL: define dso_local void @f_agg_large_ret
+// CHECK-SAME: (%struct.large* noalias sret([[STRUCT_LARGE:%.*]]) align 4 [[AGG_RESULT:%.*]], i32 noundef [[I:%.*]], i8 noundef signext [[J:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct large f_agg_large_ret(int32_t i, int8_t j) {
   return (struct large){1, 2, 3, 4};
 }
 
 typedef unsigned char v16i8 __attribute__((vector_size(16)));
 
-// CHECK-LABEL: define{{.*}} void @f_vec_large_v16i8(<16 x i8>* noundef %0)
+// CHECK-LABEL: define dso_local void @f_vec_large_v16i8
+// CHECK-SAME: (<16 x i8>* noundef [[TMP0:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_vec_large_v16i8(v16i8 x) {
   x[0] = x[7];
 }
 
-// CHECK-LABEL: define{{.*}} void @f_vec_large_v16i8_ret(<16 x i8>* noalias sret(<16 x i8>) align 16 %agg.result)
+// CHECK-LABEL: define dso_local void @f_vec_large_v16i8_ret
+// CHECK-SAME: (<16 x i8>* noalias sret(<16 x i8>) align 16 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 v16i8 f_vec_large_v16i8_ret(void) {
   return (v16i8){1, 2, 3, 4, 5, 6, 7, 8};
 }
@@ -197,7 +288,10 @@
 // Scalars passed on the stack should not have signext/zeroext attributes
 // (they are anyext).
 
-// CHECK-LABEL: define{{.*}} i32 @f_scalar_stack_1(i32 %a.coerce, [2 x i32] %b.coerce, i64 %c.coerce, %struct.large* noundef %d, i8 noundef zeroext %e, i8 noundef signext %f, i8 noundef %g, i8 noundef %h)
+// CHECK-LABEL: define dso_local i32 @f_scalar_stack_1
+// CHECK-SAME: (i32 [[A_COERCE:%.*]], [2 x i32] [[B_COERCE:%.*]], i64 [[C_COERCE:%.*]], %struct.large* noundef [[D:%.*]], i8 noundef zeroext [[E:%.*]], i8 noundef signext [[F:%.*]], i8 noundef [[G:%.*]], i8 noundef [[H:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 int f_scalar_stack_1(struct tiny a, struct small b, struct small_aligned c,
                      struct large d, uint8_t e, int8_t f, uint8_t g, int8_t h) {
   return g + h;
@@ -207,13 +301,19 @@
 // the presence of large return values that consume a register due to the need
 // to pass a pointer.
 
-// CHECK-LABEL: define{{.*}} void @f_scalar_stack_2(%struct.large* noalias sret(%struct.large) align 4 %agg.result, i32 noundef %a, i64 noundef %b, i64 noundef %c, fp128 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g)
+// CHECK-LABEL: define dso_local void @f_scalar_stack_2
+// CHECK-SAME: (%struct.large* noalias sret([[STRUCT_LARGE:%.*]]) align 4 [[AGG_RESULT:%.*]], i32 noundef [[A:%.*]], i64 noundef [[B:%.*]], i64 noundef [[C:%.*]], fp128 noundef [[D:%.*]], i8 noundef zeroext [[E:%.*]], i8 noundef [[F:%.*]], i8 noundef [[G:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct large f_scalar_stack_2(int32_t a, int64_t b, int64_t c, long double d,
                               uint8_t e, int8_t f, uint8_t g) {
   return (struct large){a, e, f, g};
 }
 
-// CHECK-LABEL: define{{.*}} fp128 @f_scalar_stack_4(i32 noundef %a, i64 noundef %b, i64 noundef %c, fp128 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g)
+// CHECK-LABEL: define dso_local fp128 @f_scalar_stack_4
+// CHECK-SAME: (i32 noundef [[A:%.*]], i64 noundef [[B:%.*]], i64 noundef [[C:%.*]], fp128 noundef [[D:%.*]], i8 noundef zeroext [[E:%.*]], i8 noundef [[F:%.*]], i8 noundef [[G:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 long double f_scalar_stack_4(int32_t a, int64_t b, int64_t c, long double d,
                              uint8_t e, int8_t f, uint8_t g) {
   return d;
@@ -222,210 +322,16 @@
 // Aggregates and >=XLen scalars passed on the stack should be lowered just as
 // they would be if passed via registers.
 
-// CHECK-LABEL: define{{.*}} void @f_scalar_stack_5(double noundef %a, i64 noundef %b, double noundef %c, i64 noundef %d, i32 noundef %e, i64 noundef %f, float noundef %g, double noundef %h, fp128 noundef %i)
+// CHECK-LABEL: define dso_local void @f_scalar_stack_5
+// CHECK-SAME: (double noundef [[A:%.*]], i64 noundef [[B:%.*]], double noundef [[C:%.*]], i64 noundef [[D:%.*]], i32 noundef [[E:%.*]], i64 noundef [[F:%.*]], float noundef [[G:%.*]], double noundef [[H:%.*]], fp128 noundef [[I:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_scalar_stack_5(double a, int64_t b, double c, int64_t d, int e,
                       int64_t f, float g, double h, long double i) {}
 
-// CHECK-LABEL: define{{.*}} void @f_agg_stack(double noundef %a, i64 noundef %b, double noundef %c, i64 noundef %d, i32 %e.coerce, [2 x i32] %f.coerce, i64 %g.coerce, %struct.large* noundef %h)
+// CHECK-LABEL: define dso_local void @f_agg_stack
+// CHECK-SAME: (double noundef [[A:%.*]], i64 noundef [[B:%.*]], double noundef [[C:%.*]], i64 noundef [[D:%.*]], i32 [[E_COERCE:%.*]], [2 x i32] [[F_COERCE:%.*]], i64 [[G_COERCE:%.*]], %struct.large* noundef [[H:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_agg_stack(double a, int64_t b, double c, int64_t d, struct tiny e,
                  struct small f, struct small_aligned g, struct large h) {}
-
-// Ensure that ABI lowering happens as expected for vararg calls. For RV32
-// with the base integer calling convention there will be no observable
-// differences in the lowered IR for a call with varargs vs without.
-
-int f_va_callee(int, ...);
-
-// CHECK-LABEL: define{{.*}} void @f_va_caller()
-// CHECK: call i32 (i32, ...) @f_va_callee(i32 noundef 1, i32 noundef 2, i64 noundef 3, double noundef 4.000000e+00, double noundef 5.000000e+00, i32 {{%.*}}, [2 x i32] {{%.*}}, i64 {{%.*}}, %struct.large* noundef {{%.*}})
-void f_va_caller(void) {
-  f_va_callee(1, 2, 3LL, 4.0f, 5.0, (struct tiny){6, 7, 8, 9},
-              (struct small){10, NULL}, (struct small_aligned){11},
-              (struct large){12, 13, 14, 15});
-}
-
-// CHECK-LABEL: define{{.*}} i32 @f_va_1(i8* noundef %fmt, ...) {{.*}} {
-// CHECK:   [[FMT_ADDR:%.*]] = alloca i8*, align 4
-// CHECK:   [[VA:%.*]] = alloca i8*, align 4
-// CHECK:   [[V:%.*]] = alloca i32, align 4
-// CHECK:   store i8* %fmt, i8** [[FMT_ADDR]], align 4
-// CHECK:   [[VA1:%.*]] = bitcast i8** [[VA]] to i8*
-// CHECK:   call void @llvm.va_start(i8* [[VA1]])
-// CHECK:   [[ARGP_CUR:%.*]] = load i8*, i8** [[VA]], align 4
-// CHECK:   [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[ARGP_CUR]], i32 4
-// CHECK:   store i8* [[ARGP_NEXT]], i8** [[VA]], align 4
-// CHECK:   [[TMP0:%.*]] = bitcast i8* [[ARGP_CUR]] to i32*
-// CHECK:   [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4
-// CHECK:   store i32 [[TMP1]], i32* [[V]], align 4
-// CHECK:   [[VA2:%.*]] = bitcast i8** [[VA]] to i8*
-// CHECK:   call void @llvm.va_end(i8* [[VA2]])
-// CHECK:   [[TMP2:%.*]] = load i32, i32* [[V]], align 4
-// CHECK:   ret i32 [[TMP2]]
-// CHECK: }
-int f_va_1(char *fmt, ...) {
-  __builtin_va_list va;
-
-  __builtin_va_start(va, fmt);
-  int v = __builtin_va_arg(va, int);
-  __builtin_va_end(va);
-
-  return v;
-}
-
-// An "aligned" register pair (where the first register is even-numbered) is
-// used to pass varargs with 2x xlen alignment and 2x xlen size. Ensure the
-// correct offsets are used.
-
-// CHECK-LABEL: @f_va_2(
-// CHECK:         [[FMT_ADDR:%.*]] = alloca i8*, align 4
-// CHECK-NEXT:    [[VA:%.*]] = alloca i8*, align 4
-// CHECK-NEXT:    [[V:%.*]] = alloca double, align 8
-// CHECK-NEXT:    store i8* [[FMT:%.*]], i8** [[FMT_ADDR]], align 4
-// CHECK-NEXT:    [[VA1:%.*]] = bitcast i8** [[VA]] to i8*
-// CHECK-NEXT:    call void @llvm.va_start(i8* [[VA1]])
-// CHECK-NEXT:    [[ARGP_CUR:%.*]] = load i8*, i8** [[VA]], align 4
-// CHECK-NEXT:    [[TMP0:%.*]] = ptrtoint i8* [[ARGP_CUR]] to i32
-// CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[TMP0]], 7
-// CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], -8
-// CHECK-NEXT:    [[ARGP_CUR_ALIGNED:%.*]] = inttoptr i32 [[TMP2]] to i8*
-// CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[ARGP_CUR_ALIGNED]], i32 8
-// CHECK-NEXT:    store i8* [[ARGP_NEXT]], i8** [[VA]], align 4
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[ARGP_CUR_ALIGNED]] to double*
-// CHECK-NEXT:    [[TMP4:%.*]] = load double, double* [[TMP3]], align 8
-// CHECK-NEXT:    store double [[TMP4]], double* [[V]], align 8
-// CHECK-NEXT:    [[VA2:%.*]] = bitcast i8** [[VA]] to i8*
-// CHECK-NEXT:    call void @llvm.va_end(i8* [[VA2]])
-// CHECK-NEXT:    [[TMP5:%.*]] = load double, double* [[V]], align 8
-// CHECK-NEXT:    ret double [[TMP5]]
-double f_va_2(char *fmt, ...) {
-  __builtin_va_list va;
-
-  __builtin_va_start(va, fmt);
-  double v = __builtin_va_arg(va, double);
-  __builtin_va_end(va);
-
-  return v;
-}
-
-// Two "aligned" register pairs.
-
-// CHECK-LABEL: @f_va_3(
-// CHECK:         [[FMT_ADDR:%.*]] = alloca i8*, align 4
-// CHECK-NEXT:    [[VA:%.*]] = alloca i8*, align 4
-// CHECK-NEXT:    [[V:%.*]] = alloca double, align 8
-// CHECK-NEXT:    [[W:%.*]] = alloca i32, align 4
-// CHECK-NEXT:    [[X:%.*]] = alloca double, align 8
-// CHECK-NEXT:    store i8* [[FMT:%.*]], i8** [[FMT_ADDR]], align 4
-// CHECK-NEXT:    [[VA1:%.*]] = bitcast i8** [[VA]] to i8*
-// CHECK-NEXT:    call void @llvm.va_start(i8* [[VA1]])
-// CHECK-NEXT:    [[ARGP_CUR:%.*]] = load i8*, i8** [[VA]], align 4
-// CHECK-NEXT:    [[TMP0:%.*]] = ptrtoint i8* [[ARGP_CUR]] to i32
-// CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[TMP0]], 7
-// CHECK-NEXT:    [[TMP2:%.*]] = and i32 [[TMP1]], -8
-// CHECK-NEXT:    [[ARGP_CUR_ALIGNED:%.*]] = inttoptr i32 [[TMP2]] to i8*
-// CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[ARGP_CUR_ALIGNED]], i32 8
-// CHECK-NEXT:    store i8* [[ARGP_NEXT]], i8** [[VA]], align 4
-// CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[ARGP_CUR_ALIGNED]] to double*
-// CHECK-NEXT:    [[TMP4:%.*]] = load double, double* [[TMP3]], align 8
-// CHECK-NEXT:    store double [[TMP4]], double* [[V]], align 8
-// CHECK-NEXT:    [[ARGP_CUR2:%.*]] = load i8*, i8** [[VA]], align 4
-// CHECK-NEXT:    [[ARGP_NEXT3:%.*]] = getelementptr inbounds i8, i8* [[ARGP_CUR2]], i32 4
-// CHECK-NEXT:    store i8* [[ARGP_NEXT3]], i8** [[VA]], align 4
-// CHECK-NEXT:    [[TMP5:%.*]] = bitcast i8* [[ARGP_CUR2]] to i32*
-// CHECK-NEXT:    [[TMP6:%.*]] = load i32, i32* [[TMP5]], align 4
-// CHECK-NEXT:    store i32 [[TMP6]], i32* [[W]], align 4
-// CHECK-NEXT:    [[ARGP_CUR4:%.*]] = load i8*, i8** [[VA]], align 4
-// CHECK-NEXT:    [[TMP7:%.*]] = ptrtoint i8* [[ARGP_CUR4]] to i32
-// CHECK-NEXT:    [[TMP8:%.*]] = add i32 [[TMP7]], 7
-// CHECK-NEXT:    [[TMP9:%.*]] = and i32 [[TMP8]], -8
-// CHECK-NEXT:    [[ARGP_CUR4_ALIGNED:%.*]] = inttoptr i32 [[TMP9]] to i8*
-// CHECK-NEXT:    [[ARGP_NEXT5:%.*]] = getelementptr inbounds i8, i8* [[ARGP_CUR4_ALIGNED]], i32 8
-// CHECK-NEXT:    store i8* [[ARGP_NEXT5]], i8** [[VA]], align 4
-// CHECK-NEXT:    [[TMP10:%.*]] = bitcast i8* [[ARGP_CUR4_ALIGNED]] to double*
-// CHECK-NEXT:    [[TMP11:%.*]] = load double, double* [[TMP10]], align 8
-// CHECK-NEXT:    store double [[TMP11]], double* [[X]], align 8
-// CHECK-NEXT:    [[VA6:%.*]] = bitcast i8** [[VA]] to i8*
-// CHECK-NEXT:    call void @llvm.va_end(i8* [[VA6]])
-// CHECK-NEXT:    [[TMP12:%.*]] = load double, double* [[V]], align 8
-// CHECK-NEXT:    [[TMP13:%.*]] = load double, double* [[X]], align 8
-// CHECK-NEXT:    [[ADD:%.*]] = fadd double [[TMP12]], [[TMP13]]
-// CHECK-NEXT:    ret double [[ADD]]
-double f_va_3(char *fmt, ...) {
-  __builtin_va_list va;
-
-  __builtin_va_start(va, fmt);
-  double v = __builtin_va_arg(va, double);
-  int w = __builtin_va_arg(va, int);
-  double x = __builtin_va_arg(va, double);
-  __builtin_va_end(va);
-
-  return v + x;
-}
-
-// CHECK-LABEL: define{{.*}} i32 @f_va_4(i8* noundef %fmt, ...) {{.*}} {
-// CHECK:         [[FMT_ADDR:%.*]] = alloca i8*, align 4
-// CHECK-NEXT:    [[VA:%.*]] = alloca i8*, align 4
-// CHECK-NEXT:    [[V:%.*]] = alloca i32, align 4
-// CHECK-NEXT:    [[LD:%.*]] = alloca fp128, align 16
-// CHECK-NEXT:    [[TS:%.*]] = alloca [[STRUCT_TINY:%.*]], align 1
-// CHECK-NEXT:    [[SS:%.*]] = alloca [[STRUCT_SMALL:%.*]], align 4
-// CHECK-NEXT:    [[LS:%.*]] = alloca [[STRUCT_LARGE:%.*]], align 4
-// CHECK-NEXT:    [[RET:%.*]] = alloca i32, align 4
-// CHECK-NEXT:    store i8* [[FMT:%.*]], i8** [[FMT_ADDR]], align 4
-// CHECK-NEXT:    [[VA1:%.*]] = bitcast i8** [[VA]] to i8*
-// CHECK-NEXT:    call void @llvm.va_start(i8* [[VA1]])
-// CHECK-NEXT:    [[ARGP_CUR:%.*]] = load i8*, i8** [[VA]], align 4
-// CHECK-NEXT:    [[ARGP_NEXT:%.*]] = getelementptr inbounds i8, i8* [[ARGP_CUR]], i32 4
-// CHECK-NEXT:    store i8* [[ARGP_NEXT]], i8** [[VA]], align 4
-// CHECK-NEXT:    [[TMP0:%.*]] = bitcast i8* [[ARGP_CUR]] to i32*
-// CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4
-// CHECK-NEXT:    store i32 [[TMP1]], i32* [[V]], align 4
-// CHECK-NEXT:    [[ARGP_CUR2:%.*]] = load i8*, i8** [[VA]], align 4
-// CHECK-NEXT:    [[ARGP_NEXT3:%.*]] = getelementptr inbounds i8, i8* [[ARGP_CUR2]], i32 4
-// CHECK-NEXT:    store i8* [[ARGP_NEXT3]], i8** [[VA]], align 4
-// CHECK-NEXT:    [[TMP2:%.*]] = bitcast i8* [[ARGP_CUR2]] to fp128**
-// CHECK-NEXT:    [[TMP3:%.*]] = load fp128*, fp128** [[TMP2]], align 4
-// CHECK-NEXT:    [[TMP4:%.*]] = load fp128, fp128* [[TMP3]], align 16
-// CHECK-NEXT:    store fp128 [[TMP4]], fp128* [[LD]], align 16
-// CHECK-NEXT:    [[ARGP_CUR4:%.*]] = load i8*, i8** [[VA]], align 4
-// CHECK-NEXT:    [[ARGP_NEXT5:%.*]] = getelementptr inbounds i8, i8* [[ARGP_CUR4]], i32 4
-// CHECK-NEXT:    store i8* [[ARGP_NEXT5]], i8** [[VA]], align 4
-// CHECK-NEXT:    [[TMP5:%.*]] = bitcast i8* [[ARGP_CUR4]] to %struct.tiny*
-// CHECK-NEXT:    [[TMP6:%.*]] = bitcast %struct.tiny* [[TS]] to i8*
-// CHECK-NEXT:    [[TMP7:%.*]] = bitcast %struct.tiny* [[TMP5]] to i8*
-// CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 1 [[TMP6]], i8* align 4 [[TMP7]], i32 4, i1 false)
-// CHECK-NEXT:    [[ARGP_CUR6:%.*]] = load i8*, i8** [[VA]], align 4
-// CHECK-NEXT:    [[ARGP_NEXT7:%.*]] = getelementptr inbounds i8, i8* [[ARGP_CUR6]], i32 8
-// CHECK-NEXT:    store i8* [[ARGP_NEXT7]], i8** [[VA]], align 4
-// CHECK-NEXT:    [[TMP8:%.*]] = bitcast i8* [[ARGP_CUR6]] to %struct.small*
-// CHECK-NEXT:    [[TMP9:%.*]] = bitcast %struct.small* [[SS]] to i8*
-// CHECK-NEXT:    [[TMP10:%.*]] = bitcast %struct.small* [[TMP8]] to i8*
-// CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[TMP9]], i8* align 4 [[TMP10]], i32 8, i1 false)
-// CHECK-NEXT:    [[ARGP_CUR8:%.*]] = load i8*, i8** [[VA]], align 4
-// CHECK-NEXT:    [[ARGP_NEXT9:%.*]] = getelementptr inbounds i8, i8* [[ARGP_CUR8]], i32 4
-// CHECK-NEXT:    store i8* [[ARGP_NEXT9]], i8** [[VA]], align 4
-// CHECK-NEXT:    [[TMP11:%.*]] = bitcast i8* [[ARGP_CUR8]] to %struct.large**
-// CHECK-NEXT:    [[TMP12:%.*]] = load %struct.large*, %struct.large** [[TMP11]], align 4
-// CHECK-NEXT:    [[TMP13:%.*]] = bitcast %struct.large* [[LS]] to i8*
-// CHECK-NEXT:    [[TMP14:%.*]] = bitcast %struct.large* [[TMP12]] to i8*
-// CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 [[TMP13]], i8* align 4 [[TMP14]], i32 16, i1 false)
-// CHECK-NEXT:    [[VA10:%.*]] = bitcast i8** [[VA]] to i8*
-// CHECK-NEXT:    call void @llvm.va_end(i8* [[VA10]])
-int f_va_4(char *fmt, ...) {
-  __builtin_va_list va;
-
-  __builtin_va_start(va, fmt);
-  int v = __builtin_va_arg(va, int);
-  long double ld = __builtin_va_arg(va, long double);
-  struct tiny ts = __builtin_va_arg(va, struct tiny);
-  struct small ss = __builtin_va_arg(va, struct small);
-  struct large ls = __builtin_va_arg(va, struct large);
-  __builtin_va_end(va);
-
-  int ret = (int)((long double)v + ld);
-  ret = ret + ts.a + ts.b + ts.c + ts.d;
-  ret = ret + ss.a + (int)ss.b;
-  ret = ret + ls.a + ls.b + ls.c + ls.d;
-
-  return ret;
-}
Index: clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-abi.c
===================================================================
--- clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-abi.c
+++ clang/test/CodeGen/RISCV/riscv32-ilp32-ilp32f-abi.c
@@ -1,5 +1,6 @@
-// RUN: %clang_cc1 -no-opaque-pointers -triple riscv32 -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -no-opaque-pointers -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --filter "^define |^entry:"
+// RUN: %clang_cc1 -triple riscv32 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \
 // RUN:     | FileCheck %s
 
 // This file contains test cases that will have the same output for the ilp32
@@ -27,7 +28,10 @@
 // Scalars passed on the stack should not have signext/zeroext attributes
 // (they are anyext).
 
-// CHECK-LABEL: define{{.*}} i32 @f_scalar_stack_1(i32 noundef %a, i64 noundef %b, i32 noundef %c, double noundef %d, fp128 noundef %e, i8 noundef zeroext %f, i8 noundef %g, i8 noundef %h)
+// CHECK-LABEL: define dso_local i32 @f_scalar_stack_1
+// CHECK-SAME: (i32 noundef [[A:%.*]], i64 noundef [[B:%.*]], i32 noundef [[C:%.*]], double noundef [[D:%.*]], fp128 noundef [[E:%.*]], i8 noundef zeroext [[F:%.*]], i8 noundef [[G:%.*]], i8 noundef [[H:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK:  entry:
+//
 int f_scalar_stack_1(int32_t a, int64_t b, int32_t c, double d, long double e,
                      uint8_t f, int8_t g, uint8_t h) {
   return g + h;
@@ -37,7 +41,10 @@
 // the presence of large return values that consume a register due to the need
 // to pass a pointer.
 
-// CHECK-LABEL: define{{.*}} void @f_scalar_stack_2(%struct.large* noalias sret(%struct.large) align 4 %agg.result, i32 noundef %a, i64 noundef %b, double noundef %c, fp128 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g)
+// CHECK-LABEL: define dso_local void @f_scalar_stack_2
+// CHECK-SAME: (ptr noalias sret([[STRUCT_LARGE:%.*]]) align 4 [[AGG_RESULT:%.*]], i32 noundef [[A:%.*]], i64 noundef [[B:%.*]], double noundef [[C:%.*]], fp128 noundef [[D:%.*]], i8 noundef zeroext [[E:%.*]], i8 noundef [[F:%.*]], i8 noundef [[G:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct large f_scalar_stack_2(int32_t a, int64_t b, double c, long double d,
                               uint8_t e, int8_t f, uint8_t g) {
   return (struct large){a, e, f, g};
@@ -46,10 +53,16 @@
 // Aggregates and >=XLen scalars passed on the stack should be lowered just as
 // they would be if passed via registers.
 
-// CHECK-LABEL: define{{.*}} void @f_scalar_stack_3(double noundef %a, i64 noundef %b, double noundef %c, i64 noundef %d, i32 noundef %e, i64 noundef %f, i32 noundef %g, double noundef %h, fp128 noundef %i)
+// CHECK-LABEL: define dso_local void @f_scalar_stack_3
+// CHECK-SAME: (double noundef [[A:%.*]], i64 noundef [[B:%.*]], double noundef [[C:%.*]], i64 noundef [[D:%.*]], i32 noundef [[E:%.*]], i64 noundef [[F:%.*]], i32 noundef [[G:%.*]], double noundef [[H:%.*]], fp128 noundef [[I:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_scalar_stack_3(double a, int64_t b, double c, int64_t d, int e,
                       int64_t f, int32_t g, double h, long double i) {}
 
-// CHECK-LABEL: define{{.*}} void @f_agg_stack(double noundef %a, i64 noundef %b, double noundef %c, i64 noundef %d, i32 %e.coerce, [2 x i32] %f.coerce, i64 %g.coerce, %struct.large* noundef %h)
+// CHECK-LABEL: define dso_local void @f_agg_stack
+// CHECK-SAME: (double noundef [[A:%.*]], i64 noundef [[B:%.*]], double noundef [[C:%.*]], i64 noundef [[D:%.*]], i32 [[E_COERCE:%.*]], [2 x i32] [[F_COERCE:%.*]], i64 [[G_COERCE:%.*]], ptr noundef [[H:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_agg_stack(double a, int64_t b, double c, int64_t d, struct tiny e,
                  struct small f, struct small_aligned g, struct large h) {}
Index: clang/test/CodeGen/RISCV/riscv32-ilp32-abi.c
===================================================================
--- clang/test/CodeGen/RISCV/riscv32-ilp32-abi.c
+++ clang/test/CodeGen/RISCV/riscv32-ilp32-abi.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -no-opaque-pointers -triple riscv32 -emit-llvm %s -o - | FileCheck %s
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --filter "^define |^entry:"
+// RUN: %clang_cc1 -triple riscv32 -emit-llvm %s -o - | FileCheck %s
 
 // This file contains test cases that will have different output for ilp32 vs
 // the other 32-bit ABIs.
@@ -25,7 +26,10 @@
 // Scalars passed on the stack should not have signext/zeroext attributes
 // (they are anyext).
 
-// CHECK-LABEL: define{{.*}} i32 @f_scalar_stack_1(i32 noundef %a, i64 noundef %b, float noundef %c, double noundef %d, fp128 noundef %e, i8 noundef zeroext %f, i8 noundef %g, i8 noundef %h)
+// CHECK-LABEL: define dso_local i32 @f_scalar_stack_1
+// CHECK-SAME: (i32 noundef [[A:%.*]], i64 noundef [[B:%.*]], float noundef [[C:%.*]], double noundef [[D:%.*]], fp128 noundef [[E:%.*]], i8 noundef zeroext [[F:%.*]], i8 noundef [[G:%.*]], i8 noundef [[H:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK:  entry:
+//
 int f_scalar_stack_1(int32_t a, int64_t b, float c, double d, long double e,
                      uint8_t f, int8_t g, uint8_t h) {
   return g + h;
@@ -35,7 +39,10 @@
 // the presence of large return values that consume a register due to the need
 // to pass a pointer.
 
-// CHECK-LABEL: define{{.*}} void @f_scalar_stack_2(%struct.large* noalias sret(%struct.large) align 4 %agg.result, float noundef %a, i64 noundef %b, double noundef %c, fp128 noundef %d, i8 noundef zeroext %e, i8 noundef %f, i8 noundef %g)
+// CHECK-LABEL: define dso_local void @f_scalar_stack_2
+// CHECK-SAME: (ptr noalias sret([[STRUCT_LARGE:%.*]]) align 4 [[AGG_RESULT:%.*]], float noundef [[A:%.*]], i64 noundef [[B:%.*]], double noundef [[C:%.*]], fp128 noundef [[D:%.*]], i8 noundef zeroext [[E:%.*]], i8 noundef [[F:%.*]], i8 noundef [[G:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 struct large f_scalar_stack_2(float a, int64_t b, double c, long double d,
                               uint8_t e, int8_t f, uint8_t g) {
   return (struct large){a, e, f, g};
@@ -44,10 +51,16 @@
 // Aggregates and >=XLen scalars passed on the stack should be lowered just as
 // they would be if passed via registers.
 
-// CHECK-LABEL: define{{.*}} void @f_scalar_stack_3(double noundef %a, i64 noundef %b, double noundef %c, i64 noundef %d, i32 noundef %e, i64 noundef %f, float noundef %g, double noundef %h, fp128 noundef %i)
+// CHECK-LABEL: define dso_local void @f_scalar_stack_3
+// CHECK-SAME: (double noundef [[A:%.*]], i64 noundef [[B:%.*]], double noundef [[C:%.*]], i64 noundef [[D:%.*]], i32 noundef [[E:%.*]], i64 noundef [[F:%.*]], float noundef [[G:%.*]], double noundef [[H:%.*]], fp128 noundef [[I:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_scalar_stack_3(double a, int64_t b, double c, int64_t d, int e,
                       int64_t f, float g, double h, long double i) {}
 
-// CHECK-LABEL: define{{.*}} void @f_agg_stack(double noundef %a, i64 noundef %b, double noundef %c, i64 noundef %d, i32 %e.coerce, [2 x i32] %f.coerce, i64 %g.coerce, %struct.large* noundef %h)
+// CHECK-LABEL: define dso_local void @f_agg_stack
+// CHECK-SAME: (double noundef [[A:%.*]], i64 noundef [[B:%.*]], double noundef [[C:%.*]], i64 noundef [[D:%.*]], i32 [[E_COERCE:%.*]], [2 x i32] [[F_COERCE:%.*]], i64 [[G_COERCE:%.*]], ptr noundef [[H:%.*]]) #[[ATTR0]] {
+// CHECK:  entry:
+//
 void f_agg_stack(double a, int64_t b, double c, int64_t d, struct tiny e,
                  struct small f, struct small_aligned g, struct large h) {}
Index: clang/test/CodeGen/RISCV/riscv-abi.cpp
===================================================================
--- clang/test/CodeGen/RISCV/riscv-abi.cpp
+++ clang/test/CodeGen/RISCV/riscv-abi.cpp
@@ -1,3 +1,4 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --filter "^define |^entry:"
 // RUN: %clang_cc1 -triple riscv32 -emit-llvm %s -o - \
 // RUN:   | FileCheck -check-prefixes=ILP32-ILP32F-ILP32D,ILP32-ILP32F,ILP32 %s
 // RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \
@@ -25,8 +26,14 @@
   int32_t i2;
 };
 
-// ILP32-ILP32F-ILP32D-LABEL: define{{.*}} [2 x i32] @_Z30int32_int32_struct_inheritance14child1_int32_s([2 x i32] %a.coerce)
-// LP64-LP64F-LP64D-LABEL: define{{.*}} i64 @_Z30int32_int32_struct_inheritance14child1_int32_s(i64 %a.coerce)
+// ILP32-ILP32F-ILP32D-LABEL: define dso_local [2 x i32] @_Z30int32_int32_struct_inheritance14child1_int32_s
+// ILP32-ILP32F-ILP32D-SAME: ([2 x i32] [[A_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
+// ILP32-ILP32F-ILP32D:  entry:
+//
+// LP64-LP64F-LP64D-LABEL: define dso_local i64 @_Z30int32_int32_struct_inheritance14child1_int32_s
+// LP64-LP64F-LP64D-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0:[0-9]+]] {
+// LP64-LP64F-LP64D:  entry:
+//
 struct child1_int32_s int32_int32_struct_inheritance(struct child1_int32_s a) {
   return a;
 }
@@ -39,10 +46,22 @@
   float f1;
 };
 
-// ILP32: define{{.*}} [2 x i32] @_Z30int32_float_struct_inheritance14child2_float_s([2 x i32] %a.coerce)
-// ILP32F-ILP32D: define{{.*}} { i32, float } @_Z30int32_float_struct_inheritance14child2_float_s(i32 %0, float %1)
-// LP64: define{{.*}} i64 @_Z30int32_float_struct_inheritance14child2_float_s(i64 %a.coerce)
-// LP64F-LP64D: define{{.*}} { i32, float } @_Z30int32_float_struct_inheritance14child2_float_s(i32 %0, float %1)
+// ILP32-LABEL: define dso_local [2 x i32] @_Z30int32_float_struct_inheritance14child2_float_s
+// ILP32-SAME: ([2 x i32] [[A_COERCE:%.*]]) #[[ATTR0]] {
+// ILP32:  entry:
+//
+// ILP32F-ILP32D-LABEL: define dso_local { i32, float } @_Z30int32_float_struct_inheritance14child2_float_s
+// ILP32F-ILP32D-SAME: (i32 [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
+// ILP32F-ILP32D:  entry:
+//
+// LP64-LABEL: define dso_local i64 @_Z30int32_float_struct_inheritance14child2_float_s
+// LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
+// LP64:  entry:
+//
+// LP64F-LP64D-LABEL: define dso_local { i32, float } @_Z30int32_float_struct_inheritance14child2_float_s
+// LP64F-LP64D-SAME: (i32 [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
+// LP64F-LP64D:  entry:
+//
 struct child2_float_s int32_float_struct_inheritance(struct child2_float_s a) {
   return a;
 }
@@ -55,9 +74,18 @@
   int64_t i1;
 };
 
-// ILP32-ILP32F-ILP32D-LABEL: define{{.*}} void @_Z30float_int64_struct_inheritance14child3_int64_s(ptr noalias sret(%struct.child3_int64_s)
-// LP64-LABEL: define{{.*}} [2 x i64] @_Z30float_int64_struct_inheritance14child3_int64_s([2 x i64] %a.coerce)
-// LP64F-LP64D-LABEL: define{{.*}} { float, i64 } @_Z30float_int64_struct_inheritance14child3_int64_s(float %0, i64 %1)
+// ILP32-ILP32F-ILP32D-LABEL: define dso_local void @_Z30float_int64_struct_inheritance14child3_int64_s
+// ILP32-ILP32F-ILP32D-SAME: (ptr noalias sret([[STRUCT_CHILD3_INT64_S:%.*]]) align 8 [[AGG_RESULT:%.*]], ptr noundef [[A:%.*]]) #[[ATTR0]] {
+// ILP32-ILP32F-ILP32D:  entry:
+//
+// LP64-LABEL: define dso_local [2 x i64] @_Z30float_int64_struct_inheritance14child3_int64_s
+// LP64-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
+// LP64:  entry:
+//
+// LP64F-LP64D-LABEL: define dso_local { float, i64 } @_Z30float_int64_struct_inheritance14child3_int64_s
+// LP64F-LP64D-SAME: (float [[TMP0:%.*]], i64 [[TMP1:%.*]]) #[[ATTR0]] {
+// LP64F-LP64D:  entry:
+//
 struct child3_int64_s float_int64_struct_inheritance(struct child3_int64_s a) {
   return a;
 }
@@ -70,10 +98,22 @@
   double d1;
 };
 
-// ILP32-ILP32F-LABEL: define{{.*}} void @_Z32double_double_struct_inheritance15child4_double_s(ptr noalias sret(%struct.child4_double_s)
-// ILP32D-LABEL: define{{.*}} { double, double } @_Z32double_double_struct_inheritance15child4_double_s(double %0, double %1)
-// LP64-LP64F-LABEL: define{{.*}} [2 x i64] @_Z32double_double_struct_inheritance15child4_double_s([2 x i64] %a.coerce)
-// LP64D-LABEL: define{{.*}} { double, double } @_Z32double_double_struct_inheritance15child4_double_s(double %0, double %1)
+// ILP32-ILP32F-LABEL: define dso_local void @_Z32double_double_struct_inheritance15child4_double_s
+// ILP32-ILP32F-SAME: (ptr noalias sret([[STRUCT_CHILD4_DOUBLE_S:%.*]]) align 8 [[AGG_RESULT:%.*]], ptr noundef [[A:%.*]]) #[[ATTR0]] {
+// ILP32-ILP32F:  entry:
+//
+// ILP32D-LABEL: define dso_local { double, double } @_Z32double_double_struct_inheritance15child4_double_s
+// ILP32D-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
+// ILP32D:  entry:
+//
+// LP64-LP64F-LABEL: define dso_local [2 x i64] @_Z32double_double_struct_inheritance15child4_double_s
+// LP64-LP64F-SAME: ([2 x i64] [[A_COERCE:%.*]]) #[[ATTR0]] {
+// LP64-LP64F:  entry:
+//
+// LP64D-LABEL: define dso_local { double, double } @_Z32double_double_struct_inheritance15child4_double_s
+// LP64D-SAME: (double [[TMP0:%.*]], double [[TMP1:%.*]]) #[[ATTR0]] {
+// LP64D:  entry:
+//
 struct child4_double_s double_double_struct_inheritance(struct child4_double_s a) {
   return a;
 }
@@ -89,8 +129,14 @@
   float f1;
 };
 
-// ILP32-ILP32F-ILP32D-LABEL: define{{.*}} void @_ZN16child5_virtual_sC1EOS_(ptr noundef nonnull align 4 dereferenceable(8) %this, ptr noundef nonnull align 4 dereferenceable(8) %0)
-// LP64-LP64F-LP64D-LABEL: define{{.*}} void @_ZN16child5_virtual_sC1EOS_(ptr noundef nonnull align 8 dereferenceable(12) %this, ptr noundef nonnull align 8 dereferenceable(12) %0)
+// ILP32-ILP32F-ILP32D-LABEL: define dso_local void @_Z38int32_float_virtual_struct_inheritance16child5_virtual_s
+// ILP32-ILP32F-ILP32D-SAME: (ptr noalias sret([[STRUCT_CHILD5_VIRTUAL_S:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef [[A:%.*]]) #[[ATTR0]] {
+// ILP32-ILP32F-ILP32D:  entry:
+//
+// LP64-LP64F-LP64D-LABEL: define dso_local void @_Z38int32_float_virtual_struct_inheritance16child5_virtual_s
+// LP64-LP64F-LP64D-SAME: (ptr noalias sret([[STRUCT_CHILD5_VIRTUAL_S:%.*]]) align 8 [[AGG_RESULT:%.*]], ptr noundef [[A:%.*]]) #[[ATTR0]] {
+// LP64-LP64F-LP64D:  entry:
+//
 struct child5_virtual_s int32_float_virtual_struct_inheritance(struct child5_virtual_s a) {
   return a;
 }
@@ -110,14 +156,25 @@
 struct grandchild_6_s : child6a_s, child6b_s {
 };
 
-// ILP32: define{{.*}} [2 x i32] @_Z38float_float_diamond_struct_inheritance14grandchild_6_s([2 x i32] %a.coerce)
-// ILP32F-ILP64D: define{{.*}} { float, float } @_Z38float_float_diamond_struct_inheritance14grandchild_6_s(float %0, float %1)
-// LP64: define{{.*}} i64 @_Z38float_float_diamond_struct_inheritance14grandchild_6_s(i64 %a.coerce)
-// LP64F-LP64D: define{{.*}} { float, float } @_Z38float_float_diamond_struct_inheritance14grandchild_6_s(float %0, float %1)
+// ILP32-LABEL: define dso_local [2 x i32] @_Z38float_float_diamond_struct_inheritance14grandchild_6_s
+// ILP32-SAME: ([2 x i32] [[A_COERCE:%.*]]) #[[ATTR0]] {
+// ILP32:  entry:
+//
+// ILP32F-ILP32D-LABEL: define dso_local { float, float } @_Z38float_float_diamond_struct_inheritance14grandchild_6_s
+// ILP32F-ILP32D-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
+// ILP32F-ILP32D:  entry:
+//
+// LP64-LABEL: define dso_local i64 @_Z38float_float_diamond_struct_inheritance14grandchild_6_s
+// LP64-SAME: (i64 [[A_COERCE:%.*]]) #[[ATTR0]] {
+// LP64:  entry:
+//
+// LP64F-LP64D-LABEL: define dso_local { float, float } @_Z38float_float_diamond_struct_inheritance14grandchild_6_s
+// LP64F-LP64D-SAME: (float [[TMP0:%.*]], float [[TMP1:%.*]]) #[[ATTR0]] {
+// LP64F-LP64D:  entry:
+//
 struct grandchild_6_s float_float_diamond_struct_inheritance(struct grandchild_6_s a) {
   return a;
 }
-
-// NOTE: These prefixes are unused. Do not add tests below this line:
+//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
 // ILP32F: {{.*}}
 // LP64F: {{.*}}
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to