https://github.com/andreisfr updated https://github.com/llvm/llvm-project/pull/225216
>From fef16b4e6dfb79a39c618d37a66b4da6413e2284 Mon Sep 17 00:00:00 2001 From: Andrei Safronov <[email protected]> Date: Tue, 22 Sep 2026 01:29:35 +0300 Subject: [PATCH 1/3] [Clang][CodeGen][Xtensa] Implement Xtensa ABI. Implement initial version of the Xtensa ABI with test. --- clang/lib/CodeGen/CMakeLists.txt | 1 + clang/lib/CodeGen/CodeGenModule.cpp | 2 + clang/lib/CodeGen/TargetInfo.h | 3 + clang/lib/CodeGen/Targets/Xtensa.cpp | 249 +++++++++++++++ clang/test/CodeGen/Xtensa/xtensa-abi.c | 413 +++++++++++++++++++++++++ 5 files changed, 668 insertions(+) create mode 100644 clang/lib/CodeGen/Targets/Xtensa.cpp create mode 100644 clang/test/CodeGen/Xtensa/xtensa-abi.c diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt index d3986ddecfe124..5a226dab33cfff 100644 --- a/clang/lib/CodeGen/CMakeLists.txt +++ b/clang/lib/CodeGen/CMakeLists.txt @@ -160,6 +160,7 @@ add_clang_library(clangCodeGen Targets/WebAssembly.cpp Targets/X86.cpp Targets/XCore.cpp + Targets/Xtensa.cpp TrapReasonBuilder.cpp VarBypassDetector.cpp diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 70445dd65ea2bc..fbd4c62121ff7c 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -337,6 +337,8 @@ createTargetCodeGenInfo(CodeGenModule &CGM) { return createLoongArchTargetCodeGenInfo( CGM, Target.getPointerWidth(LangAS::Default), ABIFRLen); } + case llvm::Triple::xtensa: + return createXtensaTargetCodeGenInfo(CGM); } } diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index fae32068b1570a..2c91986e9a14a7 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -652,6 +652,9 @@ createWinX86_64TargetCodeGenInfo(CodeGenModule &CGM, X86AVXABILevel AVXLevel); std::unique_ptr<TargetCodeGenInfo> createXCoreTargetCodeGenInfo(CodeGenModule &CGM); +std::unique_ptr<TargetCodeGenInfo> +createXtensaTargetCodeGenInfo(CodeGenModule &CGM); + } // namespace CodeGen } // namespace clang diff --git a/clang/lib/CodeGen/Targets/Xtensa.cpp b/clang/lib/CodeGen/Targets/Xtensa.cpp new file mode 100644 index 00000000000000..13417f33381d79 --- /dev/null +++ b/clang/lib/CodeGen/Targets/Xtensa.cpp @@ -0,0 +1,249 @@ +//===- Xtensa.cpp ---------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ABIInfoImpl.h" +#include "TargetInfo.h" + +using namespace clang; +using namespace clang::CodeGen; +//===----------------------------------------------------------------------===// +// Xtensa ABI Implementation +//===----------------------------------------------------------------------===// + +namespace { +class XtensaABIInfo : public DefaultABIInfo { +private: + static const int MaxNumArgGPRs = 6; + static const int MaxNumRetGPRs = 4; + +public: + XtensaABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} + + // DefaultABIInfo's classifyReturnType and classifyArgumentType are + // non-virtual, but computeInfo is virtual, so we overload it. + void computeInfo(CGFunctionInfo &FI) const override; + + ABIArgInfo classifyArgumentType(QualType Ty, int &ArgGPRsLeft) const; + + ABIArgInfo classifyReturnType(QualType RetTy) const; + + RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, + AggValueSlot Slot) const override; + + ABIArgInfo extendType(QualType Ty) const; +}; +} // end anonymous namespace + +void XtensaABIInfo::computeInfo(CGFunctionInfo &FI) const { + QualType RetTy = FI.getReturnType(); + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(RetTy); + + int ArgGPRsLeft = MaxNumArgGPRs; + for (auto &ArgInfo : FI.arguments()) { + ArgInfo.info = classifyArgumentType(ArgInfo.type, ArgGPRsLeft); + } +} + +ABIArgInfo XtensaABIInfo::classifyArgumentType(QualType Ty, + int &ArgGPRsLeft) const { + assert(ArgGPRsLeft <= MaxNumArgGPRs && "Arg GPR tracking underflow"); + Ty = useFirstFieldIfTransparentUnion(Ty); + // Structures with either a non-trivial destructor or a non-trivial + // copy constructor are always passed indirectly. + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { + if (ArgGPRsLeft) + ArgGPRsLeft -= 1; + return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(), + /*ByVal=*/RAA == + CGCXXABI::RAA_DirectInMemory); + } + + // Ignore empty structs/unions. + if (isEmptyRecord(getContext(), Ty, true)) + return ABIArgInfo::getIgnore(); + + uint64_t Size = getContext().getTypeSize(Ty); + uint64_t NeededAlign = getContext().getTypeAlign(Ty); + bool MustUseStack = false; + int NeededArgGPRs = (Size + 31) / 32; + + if (NeededAlign == (2 * 32)) + NeededArgGPRs += (ArgGPRsLeft % 2); + + // Put on stack objects which are not fit to 6 registers, + // also on stack object which alignment more then 16 bytes and + // object with 16-byte alignment if it isn't the first argument. + if ((NeededArgGPRs > ArgGPRsLeft) || (NeededAlign > (4 * 32)) || + ((ArgGPRsLeft < 6) && (NeededAlign == (4 * 32)))) { + MustUseStack = true; + NeededArgGPRs = ArgGPRsLeft; + } + ArgGPRsLeft -= NeededArgGPRs; + + if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType() && !MustUseStack) { + // Treat an enum type as its underlying type. + if (const auto *ED = Ty->getAsEnumDecl()) + Ty = ED->getIntegerType(); + // All integral types are promoted to XLen width, unless passed on the + // stack. + if (Size < 32 && Ty->isIntegralOrEnumerationType() && !MustUseStack) { + return extendType(Ty); + } + // Assume that type has 32, 64 or 128 bits + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); + } + + // Aggregates which are <= 6*32 will be passed in registers if possible, + // so coerce to integers. + if ((Size <= (MaxNumArgGPRs * 32)) && (!MustUseStack)) { + if (Size <= 32) { + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 32)); + } else if (NeededAlign == (2 * 32)) { + return ABIArgInfo::getDirect(llvm::ArrayType::get( + llvm::IntegerType::get(getVMContext(), 64), NeededArgGPRs / 2)); + } else if (NeededAlign == (4 * 32)) { + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 128)); + } else { + return ABIArgInfo::getDirect(llvm::ArrayType::get( + llvm::IntegerType::get(getVMContext(), 32), NeededArgGPRs)); + } + } +#undef MAX_STRUCT_IN_REGS_SIZE + return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(), + /*ByVal=*/true); +} + +ABIArgInfo XtensaABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) + return ABIArgInfo::getIgnore(); + + int ArgGPRsLeft = MaxNumRetGPRs; + auto RetSize = llvm::alignTo(getContext().getTypeSize(RetTy), 32) / 32; + + // The rules for return and argument with type size more then 4 bytes + // are the same, so defer to classifyArgumentType. + if (RetSize > 1) + return classifyArgumentType(RetTy, ArgGPRsLeft); + + return DefaultABIInfo::classifyReturnType(RetTy); +} + +RValue XtensaABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty, AggValueSlot Slot) const { + // The va_list structure memory layout: + // struct __va_list_tag { + // int32_t *va_stk; + // int32_t *va_reg; + // int32_t va_ndx; + // }; + CGBuilderTy &Builder = CGF.Builder; + + Address OverflowAreaPtr = Builder.CreateStructGEP(VAListAddr, 0, "__va_stk"); + Address OverflowArea = Address(Builder.CreateLoad(OverflowAreaPtr, ""), + CGF.Int32Ty, CharUnits::fromQuantity(4)); + Address RegSaveAreaPtr = Builder.CreateStructGEP(VAListAddr, 1, "__va_reg"); + Address RegSaveArea = Address(Builder.CreateLoad(RegSaveAreaPtr, ""), + CGF.Int32Ty, CharUnits::fromQuantity(4)); + Address ARAreaPtr = Builder.CreateStructGEP(VAListAddr, 2, "__va_ndx"); + llvm::Value *ARIndex = Builder.CreateLoad(ARAreaPtr, ""); + + ARIndex = Builder.CreateLShr(ARIndex, Builder.getInt32(2)); + + unsigned Align = getContext().getTypeAlign(Ty) / 32; + unsigned Size = (getContext().getTypeSize(Ty) + 31) / 32; + + if (Align > 1) { + ARIndex = Builder.CreateAdd(ARIndex, Builder.getInt32(Align - 1)); + ARIndex = + Builder.CreateAnd(ARIndex, Builder.getInt32((uint32_t) ~(Align - 1))); + } + + llvm::Value *ARIndexNext = Builder.CreateAdd(ARIndex, Builder.getInt32(Size)); + Builder.CreateStore(Builder.CreateShl(ARIndexNext, Builder.getInt32(2)), + ARAreaPtr); + + const unsigned OverflowLimit = 6; + llvm::Value *CC = Builder.CreateICmpULE( + ARIndexNext, Builder.getInt32(OverflowLimit), "cond"); + + llvm::BasicBlock *UsingRegSaveArea = + CGF.createBasicBlock("using_regsavearea"); + llvm::BasicBlock *UsingOverflow = CGF.createBasicBlock("using_overflow"); + llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); + + Builder.CreateCondBr(CC, UsingRegSaveArea, UsingOverflow); + + llvm::Type *DirectTy = CGF.ConvertType(Ty); + + // Case 1: consume registers. + Address RegAddr = Address::invalid(); + { + CGF.EmitBlock(UsingRegSaveArea); + + CharUnits RegSize = CharUnits::fromQuantity(4); + RegSaveArea = + Address(Builder.CreateInBoundsGEP( + CGF.Int32Ty, RegSaveArea.emitRawPointer(CGF), ARIndex), + CGF.Int32Ty, + RegSaveArea.getAlignment().alignmentOfArrayElement(RegSize)); + RegAddr = RegSaveArea.withElementType(DirectTy); + CGF.EmitBranch(Cont); + } + + // Case 2: consume space in the overflow area. + Address MemAddr = Address::invalid(); + { + CGF.EmitBlock(UsingOverflow); + llvm::Value *CC1 = Builder.CreateICmpULE( + ARIndex, Builder.getInt32(OverflowLimit), "cond_overflow"); + + llvm::Value *ARIndexOff = Builder.CreateSelect( + CC1, Builder.CreateSub(Builder.getInt32(8), ARIndex), + Builder.getInt32(0)); + + llvm::Value *ARIndexCorr = Builder.CreateAdd(ARIndex, ARIndexOff); + llvm::Value *ARIndexNextCorr = Builder.CreateAdd(ARIndexNext, ARIndexOff); + Builder.CreateStore(Builder.CreateShl(ARIndexNextCorr, Builder.getInt32(2)), + ARAreaPtr); + + CharUnits RegSize = CharUnits::fromQuantity(4); + OverflowArea = + Address(Builder.CreateInBoundsGEP( + CGF.Int32Ty, OverflowArea.emitRawPointer(CGF), ARIndexCorr), + CGF.Int32Ty, + OverflowArea.getAlignment().alignmentOfArrayElement(RegSize)); + MemAddr = OverflowArea.withElementType(DirectTy); + CGF.EmitBranch(Cont); + } + + CGF.EmitBlock(Cont); + + // Merge the cases with a phi. + Address Result = + emitMergePHI(CGF, RegAddr, UsingRegSaveArea, MemAddr, UsingOverflow, ""); + + return CGF.EmitLoadOfAnyValue(CGF.MakeAddrLValue(Result, Ty), Slot); +} + +ABIArgInfo XtensaABIInfo::extendType(QualType Ty) const { + return ABIArgInfo::getExtend(Ty); +} + +namespace { +class XtensaTargetCodeGenInfo : public TargetCodeGenInfo { +public: + XtensaTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) + : TargetCodeGenInfo(std::make_unique<XtensaABIInfo>(CGT)) {} +}; +} // namespace + +std::unique_ptr<TargetCodeGenInfo> +CodeGen::createXtensaTargetCodeGenInfo(CodeGenModule &CGM) { + return std::make_unique<XtensaTargetCodeGenInfo>(CGM.getTypes()); +} diff --git a/clang/test/CodeGen/Xtensa/xtensa-abi.c b/clang/test/CodeGen/Xtensa/xtensa-abi.c new file mode 100644 index 00000000000000..947ea96a9ed6ba --- /dev/null +++ b/clang/test/CodeGen/Xtensa/xtensa-abi.c @@ -0,0 +1,413 @@ +// RUN: %clang_cc1 -triple xtensa -O0 -emit-llvm %s -o - | FileCheck %s + +#include <stddef.h> +#include <stdint.h> + +// Test scalar arguments + +// CHECK-LABEL: define dso_local zeroext i1 @f_scalar_i1( +// CHECK-SAME: i1 noundef zeroext [[X:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[STOREDV:%.*]] = zext i1 [[X]] to i8 +// CHECK-NEXT: store i8 [[STOREDV]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[LOADEDV:%.*]] = icmp ne i8 [[TMP0]], 0 +// CHECK-NEXT: ret i1 [[LOADEDV]] +// +_Bool f_scalar_i1(_Bool x) { return x; } + +// CHECK-LABEL: define dso_local signext i8 @f_scalar_i8( +// CHECK-SAME: i8 noundef signext [[X:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store i8 [[X]], ptr [[X_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[X_ADDR]], align 1 +// CHECK-NEXT: ret i8 [[TMP0]] +// +int8_t f_scalar_i8(int8_t x) { return x; } + +// CHECK-LABEL: define dso_local zeroext i8 @f_scalar_i16( +// CHECK-SAME: i16 noundef signext [[X:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i16, align 2 +// CHECK-NEXT: store i16 [[X]], ptr [[X_ADDR]], align 2 +// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[X_ADDR]], align 2 +// CHECK-NEXT: [[CONV:%.*]] = trunc i16 [[TMP0]] to i8 +// CHECK-NEXT: ret i8 [[CONV]] +// +uint8_t f_scalar_i16(int16_t x) { return x; } + +// CHECK-LABEL: define dso_local i32 @f_scalar_i32( +// CHECK-SAME: i32 noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4 +// CHECK-NEXT: ret i32 [[TMP0]] +// +int32_t f_scalar_i32(int32_t x) { return x; } + +// CHECK-LABEL: define dso_local i64 @f_scalar_i64( +// CHECK-SAME: i64 noundef [[X:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: store i64 [[X]], ptr [[X_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[X_ADDR]], align 8 +// CHECK-NEXT: ret i64 [[TMP0]] +// +int64_t f_scalar_i64(int64_t x) { return x; } + +// CHECK-LABEL: define dso_local float @f_scalar_float( +// CHECK-SAME: i32 noundef [[X_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X:%.*]] = alloca float, align 4 +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca float, align 4 +// CHECK-NEXT: store i32 [[X_COERCE]], ptr [[X]], align 4 +// CHECK-NEXT: [[X1:%.*]] = load float, ptr [[X]], align 4 +// CHECK-NEXT: store float [[X1]], ptr [[X_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[X_ADDR]], align 4 +// CHECK-NEXT: ret float [[TMP0]] +// +float f_scalar_float(float x) { return x; } + +// CHECK-LABEL: define dso_local i64 @f_scalar_double( +// CHECK-SAME: i64 noundef [[X_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[RETVAL:%.*]] = alloca double, align 8 +// CHECK-NEXT: [[X:%.*]] = alloca double, align 8 +// CHECK-NEXT: [[X_ADDR:%.*]] = alloca double, align 8 +// CHECK-NEXT: store i64 [[X_COERCE]], ptr [[X]], align 8 +// CHECK-NEXT: [[X1:%.*]] = load double, ptr [[X]], align 8 +// CHECK-NEXT: store double [[X1]], ptr [[X_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[X_ADDR]], align 8 +// CHECK-NEXT: store double [[TMP0]], ptr [[RETVAL]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[RETVAL]], align 8 +// CHECK-NEXT: ret i64 [[TMP1]] +// +double f_scalar_double(double x) { return x; } + +// Test aggregate arguments + +struct S16 { int a[4]; } __attribute__ ((aligned (16))); + +// CHECK-LABEL: define dso_local void @callee_struct_a16b_1( +// CHECK-SAME: i128 [[A_COERCE:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[A:%.*]] = alloca [[STRUCT_S16:%.*]], align 16 +// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_S16]], ptr [[A]], i32 0, i32 0 +// CHECK-NEXT: store i128 [[A_COERCE]], ptr [[COERCE_DIVE]], align 16 +// CHECK-NEXT: ret void +// +void callee_struct_a16b_1(struct S16 a) {} + + +// CHECK-LABEL: define dso_local void @callee_struct_a16b_2( +// CHECK-SAME: i128 [[A_COERCE:%.*]], i32 noundef [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[A:%.*]] = alloca [[STRUCT_S16:%.*]], align 16 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_S16]], ptr [[A]], i32 0, i32 0 +// CHECK-NEXT: store i128 [[A_COERCE]], ptr [[COERCE_DIVE]], align 16 +// CHECK-NEXT: store i32 [[B]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: ret void +// +void callee_struct_a16b_2(struct S16 a, int b) {} + + +// CHECK-LABEL: define dso_local void @callee_struct_a16b_3( +// CHECK-SAME: i32 noundef [[A:%.*]], ptr noundef byval([[STRUCT_S16:%.*]]) align 16 [[B:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: ret void +// +void callee_struct_a16b_3(int a, struct S16 b) {} + +// Test variable arguments +int f_va_callee(int, ...); + +// CHECK-LABEL: define dso_local void @f_va_caller( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_S16:%.*]], align 16 +// CHECK-NEXT: [[COERCE:%.*]] = alloca double, align 8 +// CHECK-NEXT: [[BYVAL_TEMP:%.*]] = alloca double, align 8 +// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_S16]], ptr [[DOTCOMPOUNDLITERAL]], i32 0, i32 0 +// CHECK-NEXT: store i32 6, ptr [[A]], align 4 +// CHECK-NEXT: [[ARRAYINIT_ELEMENT:%.*]] = getelementptr inbounds i32, ptr [[A]], i32 1 +// CHECK-NEXT: store i32 7, ptr [[ARRAYINIT_ELEMENT]], align 4 +// CHECK-NEXT: [[ARRAYINIT_ELEMENT1:%.*]] = getelementptr inbounds i32, ptr [[A]], i32 2 +// CHECK-NEXT: store i32 8, ptr [[ARRAYINIT_ELEMENT1]], align 4 +// CHECK-NEXT: [[ARRAYINIT_ELEMENT2:%.*]] = getelementptr inbounds i32, ptr [[A]], i32 3 +// CHECK-NEXT: store i32 9, ptr [[ARRAYINIT_ELEMENT2]], align 4 +// CHECK-NEXT: store double 4.000000e+00, ptr [[COERCE]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[COERCE]], align 8 +// CHECK-NEXT: store double 5.000000e+00, ptr [[BYVAL_TEMP]], align 8 +// CHECK-NEXT: [[CALL:%.*]] = call i32 (i32, ...) @f_va_callee(i32 noundef 1, i32 noundef 2, i64 noundef 3, i64 noundef [[TMP0]], ptr noundef byval(double) align 8 [[BYVAL_TEMP]], ptr noundef byval([[STRUCT_S16]]) align 16 [[DOTCOMPOUNDLITERAL]]) +// CHECK-NEXT: ret void +// +void f_va_caller(void) { + f_va_callee(1, 2, 3LL, 4.0f, 5.0, (struct S16){6, 7, 8, 9}); +} + +// CHECK-LABEL: define dso_local i32 @f_va_1( +// CHECK-SAME: i32 noundef [[FMT_COERCE:%.*]], ...) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[FMT:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[FMT_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[VA:%.*]] = alloca [[STRUCT___VA_LIST_TAG:%.*]], align 4 +// CHECK-NEXT: [[V:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[COERCE_VAL_IP:%.*]] = inttoptr i32 [[FMT_COERCE]] to ptr +// CHECK-NEXT: store ptr [[COERCE_VAL_IP]], ptr [[FMT]], align 4 +// CHECK-NEXT: [[FMT1:%.*]] = load ptr, ptr [[FMT]], align 4 +// CHECK-NEXT: store ptr [[FMT1]], ptr [[FMT_ADDR]], align 4 +// CHECK-NEXT: call void @llvm.va_start.p0(ptr [[VA]]) +// CHECK-NEXT: [[__VA_STK:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 0 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__VA_STK]], align 4 +// CHECK-NEXT: [[__VA_REG:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 1 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[__VA_REG]], align 4 +// CHECK-NEXT: [[__VA_NDX:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 2 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[__VA_NDX]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[TMP2]], 2 +// CHECK-NEXT: [[TMP4:%.*]] = add i32 [[TMP3]], 1 +// CHECK-NEXT: [[TMP5:%.*]] = shl i32 [[TMP4]], 2 +// CHECK-NEXT: store i32 [[TMP5]], ptr [[__VA_NDX]], align 4 +// CHECK-NEXT: [[COND:%.*]] = icmp ule i32 [[TMP4]], 6 +// CHECK-NEXT: br i1 [[COND]], label %[[USING_REGSAVEAREA:.*]], label %[[USING_OVERFLOW:.*]] +// CHECK: [[USING_REGSAVEAREA]]: +// CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i32 [[TMP3]] +// CHECK-NEXT: br label %[[CONT:.*]] +// CHECK: [[USING_OVERFLOW]]: +// CHECK-NEXT: [[COND_OVERFLOW:%.*]] = icmp ule i32 [[TMP3]], 6 +// CHECK-NEXT: [[TMP7:%.*]] = sub i32 8, [[TMP3]] +// CHECK-NEXT: [[TMP8:%.*]] = select i1 [[COND_OVERFLOW]], i32 [[TMP7]], i32 0 +// CHECK-NEXT: [[TMP9:%.*]] = add i32 [[TMP3]], [[TMP8]] +// CHECK-NEXT: [[TMP10:%.*]] = add i32 [[TMP4]], [[TMP8]] +// CHECK-NEXT: [[TMP11:%.*]] = shl i32 [[TMP10]], 2 +// CHECK-NEXT: store i32 [[TMP11]], ptr [[__VA_NDX]], align 4 +// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i32 [[TMP9]] +// CHECK-NEXT: br label %[[CONT]] +// CHECK: [[CONT]]: +// CHECK-NEXT: [[TMP13:%.*]] = phi ptr [ [[TMP6]], %[[USING_REGSAVEAREA]] ], [ [[TMP12]], %[[USING_OVERFLOW]] ] +// CHECK-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4 +// CHECK-NEXT: store i32 [[TMP14]], ptr [[V]], align 4 +// CHECK-NEXT: call void @llvm.va_end.p0(ptr [[VA]]) +// CHECK-NEXT: [[TMP15:%.*]] = load i32, ptr [[V]], align 4 +// CHECK-NEXT: ret i32 [[TMP15]] +// +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; +} + +// CHECK-LABEL: define dso_local i64 @f_va_2( +// CHECK-SAME: i32 noundef [[FMT_COERCE:%.*]], ...) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[RETVAL:%.*]] = alloca double, align 8 +// CHECK-NEXT: [[FMT:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[FMT_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[VA:%.*]] = alloca [[STRUCT___VA_LIST_TAG:%.*]], align 4 +// CHECK-NEXT: [[V:%.*]] = alloca double, align 8 +// CHECK-NEXT: [[COERCE_VAL_IP:%.*]] = inttoptr i32 [[FMT_COERCE]] to ptr +// CHECK-NEXT: store ptr [[COERCE_VAL_IP]], ptr [[FMT]], align 4 +// CHECK-NEXT: [[FMT1:%.*]] = load ptr, ptr [[FMT]], align 4 +// CHECK-NEXT: store ptr [[FMT1]], ptr [[FMT_ADDR]], align 4 +// CHECK-NEXT: call void @llvm.va_start.p0(ptr [[VA]]) +// CHECK-NEXT: [[__VA_STK:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 0 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__VA_STK]], align 4 +// CHECK-NEXT: [[__VA_REG:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 1 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[__VA_REG]], align 4 +// CHECK-NEXT: [[__VA_NDX:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 2 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[__VA_NDX]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[TMP2]], 2 +// CHECK-NEXT: [[TMP4:%.*]] = add i32 [[TMP3]], 1 +// CHECK-NEXT: [[TMP5:%.*]] = and i32 [[TMP4]], -2 +// CHECK-NEXT: [[TMP6:%.*]] = add i32 [[TMP5]], 2 +// CHECK-NEXT: [[TMP7:%.*]] = shl i32 [[TMP6]], 2 +// CHECK-NEXT: store i32 [[TMP7]], ptr [[__VA_NDX]], align 4 +// CHECK-NEXT: [[COND:%.*]] = icmp ule i32 [[TMP6]], 6 +// CHECK-NEXT: br i1 [[COND]], label %[[USING_REGSAVEAREA:.*]], label %[[USING_OVERFLOW:.*]] +// CHECK: [[USING_REGSAVEAREA]]: +// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i32 [[TMP5]] +// CHECK-NEXT: br label %[[CONT:.*]] +// CHECK: [[USING_OVERFLOW]]: +// CHECK-NEXT: [[COND_OVERFLOW:%.*]] = icmp ule i32 [[TMP5]], 6 +// CHECK-NEXT: [[TMP9:%.*]] = sub i32 8, [[TMP5]] +// CHECK-NEXT: [[TMP10:%.*]] = select i1 [[COND_OVERFLOW]], i32 [[TMP9]], i32 0 +// CHECK-NEXT: [[TMP11:%.*]] = add i32 [[TMP5]], [[TMP10]] +// CHECK-NEXT: [[TMP12:%.*]] = add i32 [[TMP6]], [[TMP10]] +// CHECK-NEXT: [[TMP13:%.*]] = shl i32 [[TMP12]], 2 +// CHECK-NEXT: store i32 [[TMP13]], ptr [[__VA_NDX]], align 4 +// CHECK-NEXT: [[TMP14:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i32 [[TMP11]] +// CHECK-NEXT: br label %[[CONT]] +// CHECK: [[CONT]]: +// CHECK-NEXT: [[TMP15:%.*]] = phi ptr [ [[TMP8]], %[[USING_REGSAVEAREA]] ], [ [[TMP14]], %[[USING_OVERFLOW]] ] +// CHECK-NEXT: [[TMP16:%.*]] = load double, ptr [[TMP15]], align 4 +// CHECK-NEXT: store double [[TMP16]], ptr [[V]], align 8 +// CHECK-NEXT: call void @llvm.va_end.p0(ptr [[VA]]) +// CHECK-NEXT: [[TMP17:%.*]] = load double, ptr [[V]], align 8 +// CHECK-NEXT: store double [[TMP17]], ptr [[RETVAL]], align 8 +// CHECK-NEXT: [[TMP18:%.*]] = load i64, ptr [[RETVAL]], align 8 +// CHECK-NEXT: ret i64 [[TMP18]] +// +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; +} + +// CHECK-LABEL: define dso_local i64 @f_va_3( +// CHECK-SAME: i32 noundef [[FMT_COERCE:%.*]], ...) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[RETVAL:%.*]] = alloca double, align 8 +// CHECK-NEXT: [[FMT:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[FMT_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[VA:%.*]] = alloca [[STRUCT___VA_LIST_TAG:%.*]], 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: [[COERCE_VAL_IP:%.*]] = inttoptr i32 [[FMT_COERCE]] to ptr +// CHECK-NEXT: store ptr [[COERCE_VAL_IP]], ptr [[FMT]], align 4 +// CHECK-NEXT: [[FMT1:%.*]] = load ptr, ptr [[FMT]], align 4 +// CHECK-NEXT: store ptr [[FMT1]], ptr [[FMT_ADDR]], align 4 +// CHECK-NEXT: call void @llvm.va_start.p0(ptr [[VA]]) +// CHECK-NEXT: [[__VA_STK:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 0 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[__VA_STK]], align 4 +// CHECK-NEXT: [[__VA_REG:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 1 +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[__VA_REG]], align 4 +// CHECK-NEXT: [[__VA_NDX:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 2 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[__VA_NDX]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = lshr i32 [[TMP2]], 2 +// CHECK-NEXT: [[TMP4:%.*]] = add i32 [[TMP3]], 1 +// CHECK-NEXT: [[TMP5:%.*]] = and i32 [[TMP4]], -2 +// CHECK-NEXT: [[TMP6:%.*]] = add i32 [[TMP5]], 2 +// CHECK-NEXT: [[TMP7:%.*]] = shl i32 [[TMP6]], 2 +// CHECK-NEXT: store i32 [[TMP7]], ptr [[__VA_NDX]], align 4 +// CHECK-NEXT: [[COND:%.*]] = icmp ule i32 [[TMP6]], 6 +// CHECK-NEXT: br i1 [[COND]], label %[[USING_REGSAVEAREA:.*]], label %[[USING_OVERFLOW:.*]] +// CHECK: [[USING_REGSAVEAREA]]: +// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i32 [[TMP5]] +// CHECK-NEXT: br label %[[CONT:.*]] +// CHECK: [[USING_OVERFLOW]]: +// CHECK-NEXT: [[COND_OVERFLOW:%.*]] = icmp ule i32 [[TMP5]], 6 +// CHECK-NEXT: [[TMP9:%.*]] = sub i32 8, [[TMP5]] +// CHECK-NEXT: [[TMP10:%.*]] = select i1 [[COND_OVERFLOW]], i32 [[TMP9]], i32 0 +// CHECK-NEXT: [[TMP11:%.*]] = add i32 [[TMP5]], [[TMP10]] +// CHECK-NEXT: [[TMP12:%.*]] = add i32 [[TMP6]], [[TMP10]] +// CHECK-NEXT: [[TMP13:%.*]] = shl i32 [[TMP12]], 2 +// CHECK-NEXT: store i32 [[TMP13]], ptr [[__VA_NDX]], align 4 +// CHECK-NEXT: [[TMP14:%.*]] = getelementptr inbounds i32, ptr [[TMP0]], i32 [[TMP11]] +// CHECK-NEXT: br label %[[CONT]] +// CHECK: [[CONT]]: +// CHECK-NEXT: [[TMP15:%.*]] = phi ptr [ [[TMP8]], %[[USING_REGSAVEAREA]] ], [ [[TMP14]], %[[USING_OVERFLOW]] ] +// CHECK-NEXT: [[TMP16:%.*]] = load double, ptr [[TMP15]], align 4 +// CHECK-NEXT: store double [[TMP16]], ptr [[V]], align 8 +// CHECK-NEXT: [[__VA_STK2:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 0 +// CHECK-NEXT: [[TMP17:%.*]] = load ptr, ptr [[__VA_STK2]], align 4 +// CHECK-NEXT: [[__VA_REG3:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 1 +// CHECK-NEXT: [[TMP18:%.*]] = load ptr, ptr [[__VA_REG3]], align 4 +// CHECK-NEXT: [[__VA_NDX4:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 2 +// CHECK-NEXT: [[TMP19:%.*]] = load i32, ptr [[__VA_NDX4]], align 4 +// CHECK-NEXT: [[TMP20:%.*]] = lshr i32 [[TMP19]], 2 +// CHECK-NEXT: [[TMP21:%.*]] = add i32 [[TMP20]], 1 +// CHECK-NEXT: [[TMP22:%.*]] = shl i32 [[TMP21]], 2 +// CHECK-NEXT: store i32 [[TMP22]], ptr [[__VA_NDX4]], align 4 +// CHECK-NEXT: [[COND5:%.*]] = icmp ule i32 [[TMP21]], 6 +// CHECK-NEXT: br i1 [[COND5]], label %[[USING_REGSAVEAREA6:.*]], label %[[USING_OVERFLOW7:.*]] +// CHECK: [[USING_REGSAVEAREA6]]: +// CHECK-NEXT: [[TMP23:%.*]] = getelementptr inbounds i32, ptr [[TMP18]], i32 [[TMP20]] +// CHECK-NEXT: br label %[[CONT9:.*]] +// CHECK: [[USING_OVERFLOW7]]: +// CHECK-NEXT: [[COND_OVERFLOW8:%.*]] = icmp ule i32 [[TMP20]], 6 +// CHECK-NEXT: [[TMP24:%.*]] = sub i32 8, [[TMP20]] +// CHECK-NEXT: [[TMP25:%.*]] = select i1 [[COND_OVERFLOW8]], i32 [[TMP24]], i32 0 +// CHECK-NEXT: [[TMP26:%.*]] = add i32 [[TMP20]], [[TMP25]] +// CHECK-NEXT: [[TMP27:%.*]] = add i32 [[TMP21]], [[TMP25]] +// CHECK-NEXT: [[TMP28:%.*]] = shl i32 [[TMP27]], 2 +// CHECK-NEXT: store i32 [[TMP28]], ptr [[__VA_NDX4]], align 4 +// CHECK-NEXT: [[TMP29:%.*]] = getelementptr inbounds i32, ptr [[TMP17]], i32 [[TMP26]] +// CHECK-NEXT: br label %[[CONT9]] +// CHECK: [[CONT9]]: +// CHECK-NEXT: [[TMP30:%.*]] = phi ptr [ [[TMP23]], %[[USING_REGSAVEAREA6]] ], [ [[TMP29]], %[[USING_OVERFLOW7]] ] +// CHECK-NEXT: [[TMP31:%.*]] = load i32, ptr [[TMP30]], align 4 +// CHECK-NEXT: store i32 [[TMP31]], ptr [[W]], align 4 +// CHECK-NEXT: [[__VA_STK10:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 0 +// CHECK-NEXT: [[TMP32:%.*]] = load ptr, ptr [[__VA_STK10]], align 4 +// CHECK-NEXT: [[__VA_REG11:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 1 +// CHECK-NEXT: [[TMP33:%.*]] = load ptr, ptr [[__VA_REG11]], align 4 +// CHECK-NEXT: [[__VA_NDX12:%.*]] = getelementptr inbounds nuw [[STRUCT___VA_LIST_TAG]], ptr [[VA]], i32 0, i32 2 +// CHECK-NEXT: [[TMP34:%.*]] = load i32, ptr [[__VA_NDX12]], align 4 +// CHECK-NEXT: [[TMP35:%.*]] = lshr i32 [[TMP34]], 2 +// CHECK-NEXT: [[TMP36:%.*]] = add i32 [[TMP35]], 1 +// CHECK-NEXT: [[TMP37:%.*]] = and i32 [[TMP36]], -2 +// CHECK-NEXT: [[TMP38:%.*]] = add i32 [[TMP37]], 2 +// CHECK-NEXT: [[TMP39:%.*]] = shl i32 [[TMP38]], 2 +// CHECK-NEXT: store i32 [[TMP39]], ptr [[__VA_NDX12]], align 4 +// CHECK-NEXT: [[COND13:%.*]] = icmp ule i32 [[TMP38]], 6 +// CHECK-NEXT: br i1 [[COND13]], label %[[USING_REGSAVEAREA14:.*]], label %[[USING_OVERFLOW15:.*]] +// CHECK: [[USING_REGSAVEAREA14]]: +// CHECK-NEXT: [[TMP40:%.*]] = getelementptr inbounds i32, ptr [[TMP33]], i32 [[TMP37]] +// CHECK-NEXT: br label %[[CONT17:.*]] +// CHECK: [[USING_OVERFLOW15]]: +// CHECK-NEXT: [[COND_OVERFLOW16:%.*]] = icmp ule i32 [[TMP37]], 6 +// CHECK-NEXT: [[TMP41:%.*]] = sub i32 8, [[TMP37]] +// CHECK-NEXT: [[TMP42:%.*]] = select i1 [[COND_OVERFLOW16]], i32 [[TMP41]], i32 0 +// CHECK-NEXT: [[TMP43:%.*]] = add i32 [[TMP37]], [[TMP42]] +// CHECK-NEXT: [[TMP44:%.*]] = add i32 [[TMP38]], [[TMP42]] +// CHECK-NEXT: [[TMP45:%.*]] = shl i32 [[TMP44]], 2 +// CHECK-NEXT: store i32 [[TMP45]], ptr [[__VA_NDX12]], align 4 +// CHECK-NEXT: [[TMP46:%.*]] = getelementptr inbounds i32, ptr [[TMP32]], i32 [[TMP43]] +// CHECK-NEXT: br label %[[CONT17]] +// CHECK: [[CONT17]]: +// CHECK-NEXT: [[TMP47:%.*]] = phi ptr [ [[TMP40]], %[[USING_REGSAVEAREA14]] ], [ [[TMP46]], %[[USING_OVERFLOW15]] ] +// CHECK-NEXT: [[TMP48:%.*]] = load double, ptr [[TMP47]], align 4 +// CHECK-NEXT: store double [[TMP48]], ptr [[X]], align 8 +// CHECK-NEXT: call void @llvm.va_end.p0(ptr [[VA]]) +// CHECK-NEXT: [[TMP49:%.*]] = load double, ptr [[V]], align 8 +// CHECK-NEXT: [[TMP50:%.*]] = load double, ptr [[X]], align 8 +// CHECK-NEXT: [[ADD:%.*]] = fadd double [[TMP49]], [[TMP50]] +// CHECK-NEXT: store double [[ADD]], ptr [[RETVAL]], align 8 +// CHECK-NEXT: [[TMP51:%.*]] = load i64, ptr [[RETVAL]], align 8 +// CHECK-NEXT: ret i64 [[TMP51]] +// +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; +} + +#define __malloc_like __attribute__((__malloc__)) + +char *bufalloc () __malloc_like ;//__result_use_check; +extern void* malloc (unsigned size); + +// CHECK: define dso_local noalias ptr @bufalloc() #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[BUF:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[CALL:%.*]] = call ptr @malloc(i32 noundef 1024) +// CHECK-NEXT: store ptr [[CALL]], ptr [[BUF]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[BUF]], align 4 +// CHECK-NEXT: ret ptr [[TMP0]] +// +char *bufalloc () +{ + char* buf = malloc(1024); + + return buf; +} >From 3b36a95ea112275ae9fab6ec6d6b564974e54e6a Mon Sep 17 00:00:00 2001 From: Andrei Safronov <[email protected]> Date: Tue, 22 Sep 2026 21:45:40 +0300 Subject: [PATCH 2/3] [Clang][CodeGen][Xtensa] Minor fixes in Xtensa ABI implementation. --- clang/lib/CodeGen/Targets/Xtensa.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/Targets/Xtensa.cpp b/clang/lib/CodeGen/Targets/Xtensa.cpp index 13417f33381d79..b9e7520dc9b910 100644 --- a/clang/lib/CodeGen/Targets/Xtensa.cpp +++ b/clang/lib/CodeGen/Targets/Xtensa.cpp @@ -45,8 +45,8 @@ void XtensaABIInfo::computeInfo(CGFunctionInfo &FI) const { FI.getReturnInfo() = classifyReturnType(RetTy); int ArgGPRsLeft = MaxNumArgGPRs; - for (auto &ArgInfo : FI.arguments()) { - ArgInfo.info = classifyArgumentType(ArgInfo.type, ArgGPRsLeft); + for (auto &[Type, Info] : FI.arguments()) { + Info = classifyArgumentType(Type, ArgGPRsLeft); } } @@ -161,7 +161,7 @@ RValue XtensaABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, if (Align > 1) { ARIndex = Builder.CreateAdd(ARIndex, Builder.getInt32(Align - 1)); ARIndex = - Builder.CreateAnd(ARIndex, Builder.getInt32((uint32_t) ~(Align - 1))); + Builder.CreateAnd(ARIndex, Builder.getInt32((uint32_t)~(Align - 1))); } llvm::Value *ARIndexNext = Builder.CreateAdd(ARIndex, Builder.getInt32(Size)); >From aa26b22d4c2b59d5bc2876ae33e51ca1f0e22784 Mon Sep 17 00:00:00 2001 From: Andrei Safronov <[email protected]> Date: Wed, 23 Sep 2026 00:01:26 +0300 Subject: [PATCH 3/3] [Clang][CodeGen][Xtensa] Fix Xtensa ABI test. --- clang/test/CodeGen/Xtensa/xtensa-abi.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/clang/test/CodeGen/Xtensa/xtensa-abi.c b/clang/test/CodeGen/Xtensa/xtensa-abi.c index 947ea96a9ed6ba..12333b3bc63be5 100644 --- a/clang/test/CodeGen/Xtensa/xtensa-abi.c +++ b/clang/test/CodeGen/Xtensa/xtensa-abi.c @@ -1,7 +1,9 @@ // RUN: %clang_cc1 -triple xtensa -O0 -emit-llvm %s -o - | FileCheck %s -#include <stddef.h> -#include <stdint.h> +typedef signed char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int int64_t; // Test scalar arguments @@ -27,16 +29,15 @@ _Bool f_scalar_i1(_Bool x) { return x; } // int8_t f_scalar_i8(int8_t x) { return x; } -// CHECK-LABEL: define dso_local zeroext i8 @f_scalar_i16( +// CHECK-LABEL: define dso_local signext i16 @f_scalar_i16( // CHECK-SAME: i16 noundef signext [[X:%.*]]) #[[ATTR0]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[X_ADDR:%.*]] = alloca i16, align 2 // CHECK-NEXT: store i16 [[X]], ptr [[X_ADDR]], align 2 // CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[X_ADDR]], align 2 -// CHECK-NEXT: [[CONV:%.*]] = trunc i16 [[TMP0]] to i8 -// CHECK-NEXT: ret i8 [[CONV]] +// CHECK-NEXT: ret i16 [[TMP0]] // -uint8_t f_scalar_i16(int16_t x) { return x; } +int16_t f_scalar_i16(int16_t x) { return x; } // CHECK-LABEL: define dso_local i32 @f_scalar_i32( // CHECK-SAME: i32 noundef [[X:%.*]]) #[[ATTR0]] { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
