diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -9472,6 +9472,28 @@ public: SparcV8TargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(std::make_unique(CGT)) {} + + llvm::Value *decodeReturnAddress(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const override { + int Offset; + if (isAggregateTypeForABI(CGF.CurFnInfo->getReturnType())) + Offset = 12; + else + Offset = 8; + return CGF.Builder.CreateGEP(CGF.Int8Ty, Address, + llvm::ConstantInt::get(CGF.Int32Ty, Offset)); + } + + llvm::Value *encodeReturnAddress(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const override { + int Offset; + if (isAggregateTypeForABI(CGF.CurFnInfo->getReturnType())) + Offset = -12; + else + Offset = -8; + return CGF.Builder.CreateGEP(CGF.Int8Ty, Address, + llvm::ConstantInt::get(CGF.Int32Ty, Offset)); + } }; } // end anonymous namespace @@ -9746,6 +9768,18 @@ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; + + llvm::Value *decodeReturnAddress(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const override { + return CGF.Builder.CreateGEP(CGF.Int8Ty, Address, + llvm::ConstantInt::get(CGF.Int32Ty, 8)); + } + + llvm::Value *encodeReturnAddress(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const override { + return CGF.Builder.CreateGEP(CGF.Int8Ty, Address, + llvm::ConstantInt::get(CGF.Int32Ty, -8)); + } }; } // end anonymous namespace diff --git a/clang/test/CodeGen/builtins-sparc.c b/clang/test/CodeGen/builtins-sparc.c --- a/clang/test/CodeGen/builtins-sparc.c +++ b/clang/test/CodeGen/builtins-sparc.c @@ -1,10 +1,29 @@ // REQUIRES: sparc-registered-target // RUN: %clang_cc1 -triple sparc-unknown-unknown -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -triple sparc64-unknown-unknown -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple sparc64-unknown-unknown -emit-llvm %s -o - | FileCheck -check-prefix CHECK-V9 %s void test_eh_return_data_regno(void) { volatile int res; - res = __builtin_eh_return_data_regno(0); // CHECK: store volatile i32 24 - res = __builtin_eh_return_data_regno(1); // CHECK: store volatile i32 25 + res = __builtin_eh_return_data_regno(0); // CHECK,CHECKV9: store volatile i32 24 + res = __builtin_eh_return_data_regno(1); // CHECK,CHECKV9: store volatile i32 25 +} + +void *test_extract_return_address(void) +{ + // CHECK,CHECKV9: getelementptr i8, i8* %0, i32 8 + return __builtin_extract_return_addr(__builtin_return_address(0)); } + +struct s { + void *p; +}; + +struct s test_extract_struct_return_address(void) +{ + struct s s; + // CHECK: getelementptr i8, i8* %0, i32 12 + // CHECK-V9: getelementptr i8, i8* %0, i32 8 + s.p = __builtin_extract_return_addr(__builtin_return_address(0)); + return s; +}