[Hexagon] Use getSigned() for negative values in va_arg handling (#176115)

This avoids implicit truncation assertions with
https://github.com/llvm/llvm-project/pull/171456. Apparently the
alignment code path was previously untested.

The first commit switches the test to generated check lines.
This commit is contained in:
Nikita Popov
2026-01-15 11:53:54 +01:00
committed by GitHub
parent 222fff827e
commit 8546294db9
2 changed files with 133 additions and 57 deletions

View File

@@ -316,10 +316,10 @@ Address HexagonABIInfo::EmitVAArgForHexagonLinux(CodeGenFunction &CGF,
llvm::ConstantInt::get(CGF.Int32Ty, (ArgAlign - 1)),
"align_current_saved_reg_area_pointer");
__current_saved_reg_area_pointer_int =
CGF.Builder.CreateAnd(__current_saved_reg_area_pointer_int,
llvm::ConstantInt::get(CGF.Int32Ty, -ArgAlign),
"align_current_saved_reg_area_pointer");
__current_saved_reg_area_pointer_int = CGF.Builder.CreateAnd(
__current_saved_reg_area_pointer_int,
llvm::ConstantInt::getSigned(CGF.Int32Ty, -ArgAlign),
"align_current_saved_reg_area_pointer");
__current_saved_reg_area_pointer =
CGF.Builder.CreateIntToPtr(__current_saved_reg_area_pointer_int,
@@ -367,10 +367,10 @@ Address HexagonABIInfo::EmitVAArgForHexagonLinux(CodeGenFunction &CGF,
llvm::ConstantInt::get(CGF.Int32Ty, ArgAlign - 1),
"align_overflow_area_pointer");
__overflow_area_pointer_int =
CGF.Builder.CreateAnd(__overflow_area_pointer_int,
llvm::ConstantInt::get(CGF.Int32Ty, -ArgAlign),
"align_overflow_area_pointer");
__overflow_area_pointer_int = CGF.Builder.CreateAnd(
__overflow_area_pointer_int,
llvm::ConstantInt::getSigned(CGF.Int32Ty, -ArgAlign),
"align_overflow_area_pointer");
__overflow_area_pointer = CGF.Builder.CreateIntToPtr(
__overflow_area_pointer_int, __overflow_area_pointer->getType(),

View File

@@ -1,3 +1,4 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6
// REQUIRES: hexagon-registered-target
// RUN: %clang_cc1 -emit-llvm -triple hexagon-unknown-linux-musl %s -o - | FileCheck %s
#include <stdarg.h>
@@ -9,53 +10,92 @@ struct AAA {
int d;
};
// CHECK: call void @llvm.va_start.p0(ptr %arraydecay)
// CHECK: %arraydecay1 = getelementptr inbounds [1 x %struct.__va_list_tag],
// ptr %ap, i32 0, i32 0
// CHECK: br label %vaarg.maybe_reg
// CHECK: vaarg.maybe_reg: ; preds = %entry
// CHECK: %__current_saved_reg_area_pointer_p = getelementptr inbounds
// %struct.__va_list_tag, ptr %arraydecay2, i32 0, i32 0
// CHECK: %__current_saved_reg_area_pointer = load ptr, ptr
// %__current_saved_reg_area_pointer_p
// CHECK: %__saved_reg_area_end_pointer_p = getelementptr inbounds
// %struct.__va_list_tag, ptr %arraydecay2, i32 0, i32 1
// CHECK: %__saved_reg_area_end_pointer = load ptr, ptr
// %__saved_reg_area_end_pointer_p
// CHECK: %__new_saved_reg_area_pointer = getelementptr i8, ptr
// %__current_saved_reg_area_pointer, i32 4
// CHECK: %0 = icmp sgt ptr %__new_saved_reg_area_pointer,
// %__saved_reg_area_end_pointer
// CHECK: br i1 %0, label %vaarg.on_stack, label %vaarg.in_reg
// CHECK: vaarg.in_reg: ; preds =
// %vaarg.maybe_reg
// CHECK: store ptr %__new_saved_reg_area_pointer, ptr
// %__current_saved_reg_area_pointer_p
// CHECK: br label %vaarg.end
// CHECK: vaarg.on_stack: ; preds =
// %vaarg.maybe_reg
// CHECK: %__overflow_area_pointer_p = getelementptr inbounds
// %struct.__va_list_tag, ptr %arraydecay2, i32 0, i32 2
// CHECK: %__overflow_area_pointer = load ptr, ptr %__overflow_area_pointer_p
// CHECK: %__overflow_area_pointer.next = getelementptr i8, ptr
// %__overflow_area_pointer, i32 4
// CHECK: store ptr %__overflow_area_pointer.next, ptr
// %__overflow_area_pointer_p
// CHECK: store ptr %__overflow_area_pointer.next, ptr
// %__current_saved_reg_area_pointer_p
// CHECK: br label %vaarg.end
// CHECK: vaarg.end: ; preds =
// %vaarg.on_stack, %vaarg.in_reg
// CHECK: %vaarg.addr = phi ptr [ %__current_saved_reg_area_pointer, %vaarg.in_reg ], [ %__overflow_area_pointer, %vaarg.on_stack
// ]
// CHECK: %1 = load i32, ptr %vaarg.addr
struct AAA aaa = {100, 200, 300, 400};
// CHECK-LABEL: define dso_local i32 @foo(
// CHECK-SAME: i32 noundef [[XX:%.*]], ...) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[XX_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[AP:%.*]] = alloca [1 x [[STRUCT___VA_LIST_TAG:%.*]]], align 8
// CHECK-NEXT: [[D:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[RET:%.*]] = alloca i32, align 4
// CHECK-NEXT: [[BBB:%.*]] = alloca [[STRUCT_AAA:%.*]], align 4
// CHECK-NEXT: store i32 [[XX]], ptr [[XX_ADDR]], align 4
// CHECK-NEXT: store i32 0, ptr [[RET]], align 4
// CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [1 x [[STRUCT___VA_LIST_TAG]]], ptr [[AP]], i32 0, i32 0
// CHECK-NEXT: call void @llvm.va_start.p0(ptr [[ARRAYDECAY]])
// CHECK-NEXT: [[ARRAYDECAY1:%.*]] = getelementptr inbounds [1 x [[STRUCT___VA_LIST_TAG]]], ptr [[AP]], i32 0, i32 0
// CHECK-NEXT: br label %[[VAARG_MAYBE_REG:.*]]
// CHECK: [[VAARG_MAYBE_REG]]:
// CHECK-NEXT: [[__CURRENT_SAVED_REG_AREA_POINTER_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 0
// CHECK-NEXT: [[__CURRENT_SAVED_REG_AREA_POINTER:%.*]] = load ptr, ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P]], align 8
// CHECK-NEXT: [[__SAVED_REG_AREA_END_POINTER_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 1
// CHECK-NEXT: [[__SAVED_REG_AREA_END_POINTER:%.*]] = load ptr, ptr [[__SAVED_REG_AREA_END_POINTER_P]], align 4
// CHECK-NEXT: [[__NEW_SAVED_REG_AREA_POINTER:%.*]] = getelementptr i8, ptr [[__CURRENT_SAVED_REG_AREA_POINTER]], i32 4
// CHECK-NEXT: [[TMP0:%.*]] = icmp sgt ptr [[__NEW_SAVED_REG_AREA_POINTER]], [[__SAVED_REG_AREA_END_POINTER]]
// CHECK-NEXT: br i1 [[TMP0]], label %[[VAARG_ON_STACK:.*]], label %[[VAARG_IN_REG:.*]]
// CHECK: [[VAARG_IN_REG]]:
// CHECK-NEXT: store ptr [[__NEW_SAVED_REG_AREA_POINTER]], ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P]], align 8
// CHECK-NEXT: br label %[[VAARG_END:.*]]
// CHECK: [[VAARG_ON_STACK]]:
// CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY1]], i32 0, i32 2
// CHECK-NEXT: [[__OVERFLOW_AREA_POINTER:%.*]] = load ptr, ptr [[__OVERFLOW_AREA_POINTER_P]], align 8
// CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_NEXT:%.*]] = getelementptr i8, ptr [[__OVERFLOW_AREA_POINTER]], i32 4
// CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT]], ptr [[__OVERFLOW_AREA_POINTER_P]], align 8
// CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT]], ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P]], align 8
// CHECK-NEXT: br label %[[VAARG_END]]
// CHECK: [[VAARG_END]]:
// CHECK-NEXT: [[VAARG_ADDR:%.*]] = phi ptr [ [[__CURRENT_SAVED_REG_AREA_POINTER]], %[[VAARG_IN_REG]] ], [ [[__OVERFLOW_AREA_POINTER]], %[[VAARG_ON_STACK]] ]
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[VAARG_ADDR]], align 4
// CHECK-NEXT: store i32 [[TMP1]], ptr [[D]], align 4
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[D]], align 4
// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[RET]], align 4
// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP3]], [[TMP2]]
// CHECK-NEXT: store i32 [[ADD]], ptr [[RET]], align 4
// CHECK-NEXT: [[ARRAYDECAY2:%.*]] = getelementptr inbounds [1 x [[STRUCT___VA_LIST_TAG]]], ptr [[AP]], i32 0, i32 0
// CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_P3:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY2]], i32 0, i32 2
// CHECK-NEXT: [[__OVERFLOW_AREA_POINTER4:%.*]] = load ptr, ptr [[__OVERFLOW_AREA_POINTER_P3]], align 8
// CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_NEXT5:%.*]] = getelementptr i8, ptr [[__OVERFLOW_AREA_POINTER4]], i32 16
// CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT5]], ptr [[__OVERFLOW_AREA_POINTER_P3]], align 8
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[BBB]], ptr align 4 [[__OVERFLOW_AREA_POINTER4]], i32 16, i1 false)
// CHECK-NEXT: [[D6:%.*]] = getelementptr inbounds nuw [[STRUCT_AAA]], ptr [[BBB]], i32 0, i32 3
// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[D6]], align 4
// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[RET]], align 4
// CHECK-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP5]], [[TMP4]]
// CHECK-NEXT: store i32 [[ADD7]], ptr [[RET]], align 4
// CHECK-NEXT: [[ARRAYDECAY8:%.*]] = getelementptr inbounds [1 x [[STRUCT___VA_LIST_TAG]]], ptr [[AP]], i32 0, i32 0
// CHECK-NEXT: br label %[[VAARG_MAYBE_REG9:.*]]
// CHECK: [[VAARG_MAYBE_REG9]]:
// CHECK-NEXT: [[__CURRENT_SAVED_REG_AREA_POINTER_P10:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY8]], i32 0, i32 0
// CHECK-NEXT: [[__CURRENT_SAVED_REG_AREA_POINTER11:%.*]] = load ptr, ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P10]], align 8
// CHECK-NEXT: [[__SAVED_REG_AREA_END_POINTER_P12:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY8]], i32 0, i32 1
// CHECK-NEXT: [[__SAVED_REG_AREA_END_POINTER13:%.*]] = load ptr, ptr [[__SAVED_REG_AREA_END_POINTER_P12]], align 4
// CHECK-NEXT: [[__NEW_SAVED_REG_AREA_POINTER14:%.*]] = getelementptr i8, ptr [[__CURRENT_SAVED_REG_AREA_POINTER11]], i32 4
// CHECK-NEXT: [[TMP6:%.*]] = icmp sgt ptr [[__NEW_SAVED_REG_AREA_POINTER14]], [[__SAVED_REG_AREA_END_POINTER13]]
// CHECK-NEXT: br i1 [[TMP6]], label %[[VAARG_ON_STACK16:.*]], label %[[VAARG_IN_REG15:.*]]
// CHECK: [[VAARG_IN_REG15]]:
// CHECK-NEXT: store ptr [[__NEW_SAVED_REG_AREA_POINTER14]], ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P10]], align 8
// CHECK-NEXT: br label %[[VAARG_END20:.*]]
// CHECK: [[VAARG_ON_STACK16]]:
// CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_P17:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[ARRAYDECAY8]], i32 0, i32 2
// CHECK-NEXT: [[__OVERFLOW_AREA_POINTER18:%.*]] = load ptr, ptr [[__OVERFLOW_AREA_POINTER_P17]], align 8
// CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_NEXT19:%.*]] = getelementptr i8, ptr [[__OVERFLOW_AREA_POINTER18]], i32 4
// CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT19]], ptr [[__OVERFLOW_AREA_POINTER_P17]], align 8
// CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT19]], ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P10]], align 8
// CHECK-NEXT: br label %[[VAARG_END20]]
// CHECK: [[VAARG_END20]]:
// CHECK-NEXT: [[VAARG_ADDR21:%.*]] = phi ptr [ [[__CURRENT_SAVED_REG_AREA_POINTER11]], %[[VAARG_IN_REG15]] ], [ [[__OVERFLOW_AREA_POINTER18]], %[[VAARG_ON_STACK16]] ]
// CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[VAARG_ADDR21]], align 4
// CHECK-NEXT: store i32 [[TMP7]], ptr [[D]], align 4
// CHECK-NEXT: [[TMP8:%.*]] = load i32, ptr [[D]], align 4
// CHECK-NEXT: [[TMP9:%.*]] = load i32, ptr [[RET]], align 4
// CHECK-NEXT: [[ADD22:%.*]] = add nsw i32 [[TMP9]], [[TMP8]]
// CHECK-NEXT: store i32 [[ADD22]], ptr [[RET]], align 4
// CHECK-NEXT: [[ARRAYDECAY23:%.*]] = getelementptr inbounds [1 x [[STRUCT___VA_LIST_TAG]]], ptr [[AP]], i32 0, i32 0
// CHECK-NEXT: call void @llvm.va_end.p0(ptr [[ARRAYDECAY23]])
// CHECK-NEXT: [[TMP10:%.*]] = load i32, ptr [[RET]], align 4
// CHECK-NEXT: ret i32 [[TMP10]]
//
int foo(int xx, ...) {
va_list ap;
int d;
@@ -72,8 +112,44 @@ int foo(int xx, ...) {
return ret;
}
int main(void) {
int x;
x = foo(1, 2, aaa, 4);
return x;
// CHECK-LABEL: define dso_local i64 @test_align(
// CHECK-SAME: ptr noundef [[ARGS:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ARGS_ADDR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: store ptr [[ARGS]], ptr [[ARGS_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[ARGS_ADDR]], align 4
// CHECK-NEXT: br label %[[VAARG_MAYBE_REG:.*]]
// CHECK: [[VAARG_MAYBE_REG]]:
// CHECK-NEXT: [[__CURRENT_SAVED_REG_AREA_POINTER_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG:%.*]], ptr [[TMP0]], i32 0, i32 0
// CHECK-NEXT: [[__CURRENT_SAVED_REG_AREA_POINTER:%.*]] = load ptr, ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P]], align 4
// CHECK-NEXT: [[__SAVED_REG_AREA_END_POINTER_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[TMP0]], i32 0, i32 1
// CHECK-NEXT: [[__SAVED_REG_AREA_END_POINTER:%.*]] = load ptr, ptr [[__SAVED_REG_AREA_END_POINTER_P]], align 4
// CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[__CURRENT_SAVED_REG_AREA_POINTER]] to i32
// CHECK-NEXT: [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER:%.*]] = add i32 [[TMP1]], 7
// CHECK-NEXT: [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER1:%.*]] = and i32 [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER]], -8
// CHECK-NEXT: [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER2:%.*]] = inttoptr i32 [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER1]] to ptr
// CHECK-NEXT: [[__NEW_SAVED_REG_AREA_POINTER:%.*]] = getelementptr i8, ptr [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER2]], i32 8
// CHECK-NEXT: [[TMP2:%.*]] = icmp sgt ptr [[__NEW_SAVED_REG_AREA_POINTER]], [[__SAVED_REG_AREA_END_POINTER]]
// CHECK-NEXT: br i1 [[TMP2]], label %[[VAARG_ON_STACK:.*]], label %[[VAARG_IN_REG:.*]]
// CHECK: [[VAARG_IN_REG]]:
// CHECK-NEXT: store ptr [[__NEW_SAVED_REG_AREA_POINTER]], ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P]], align 4
// CHECK-NEXT: br label %[[VAARG_END:.*]]
// CHECK: [[VAARG_ON_STACK]]:
// CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_P:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[TMP0]], i32 0, i32 2
// CHECK-NEXT: [[__OVERFLOW_AREA_POINTER:%.*]] = load ptr, ptr [[__OVERFLOW_AREA_POINTER_P]], align 4
// CHECK-NEXT: [[TMP3:%.*]] = ptrtoint ptr [[__OVERFLOW_AREA_POINTER]] to i32
// CHECK-NEXT: [[ALIGN_OVERFLOW_AREA_POINTER:%.*]] = add i32 [[TMP3]], 7
// CHECK-NEXT: [[ALIGN_OVERFLOW_AREA_POINTER3:%.*]] = and i32 [[ALIGN_OVERFLOW_AREA_POINTER]], -8
// CHECK-NEXT: [[ALIGN_OVERFLOW_AREA_POINTER4:%.*]] = inttoptr i32 [[ALIGN_OVERFLOW_AREA_POINTER3]] to ptr
// CHECK-NEXT: [[__OVERFLOW_AREA_POINTER_NEXT:%.*]] = getelementptr i8, ptr [[ALIGN_OVERFLOW_AREA_POINTER4]], i32 8
// CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT]], ptr [[__OVERFLOW_AREA_POINTER_P]], align 4
// CHECK-NEXT: store ptr [[__OVERFLOW_AREA_POINTER_NEXT]], ptr [[__CURRENT_SAVED_REG_AREA_POINTER_P]], align 4
// CHECK-NEXT: br label %[[VAARG_END]]
// CHECK: [[VAARG_END]]:
// CHECK-NEXT: [[VAARG_ADDR:%.*]] = phi ptr [ [[ALIGN_CURRENT_SAVED_REG_AREA_POINTER2]], %[[VAARG_IN_REG]] ], [ [[ALIGN_OVERFLOW_AREA_POINTER4]], %[[VAARG_ON_STACK]] ]
// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr [[VAARG_ADDR]], align 8
// CHECK-NEXT: ret i64 [[TMP4]]
//
long long test_align(va_list args) {
return va_arg(args, long long);
}