diff --git a/clang/docs/ShadowCallStack.rst b/clang/docs/ShadowCallStack.rst --- a/clang/docs/ShadowCallStack.rst +++ b/clang/docs/ShadowCallStack.rst @@ -57,24 +57,27 @@ the operating system should be preferred since otherwise all thread creation and destruction would need to be intercepted by the application. -The instrumentation makes use of the platform register ``x18``. On some -platforms, ``x18`` is reserved, and on others, it is designated as a scratch -register. This generally means that any code that may run on the same thread -as code compiled with ShadowCallStack must either target one of the platforms -whose ABI reserves ``x18`` (currently Android, Darwin, Fuchsia and Windows) -or be compiled with the flag ``-ffixed-x18``. If absolutely necessary, code -compiled without ``-ffixed-x18`` may be run on the same thread as code that -uses ShadowCallStack by saving the register value temporarily on the stack -(`example in Android`_) but this should be done with care since it risks -leaking the shadow call stack address. +The instrumentation makes use of the platform register ``x18`` on AArch64 and +``x3`` (``gp``) on RISC-V. For simplicity we will refer to this as the +``SCSReg``. On some platforms, ``SCSReg`` is reserved, and on others, it is +designated as a scratch register. This generally means that any code that may +run on the same thread as code compiled with ShadowCallStack must either target +one of the platforms whose ABI reserves ``SCSReg`` (currently Android, Darwin, +Fuchsia and Windows) or be compiled with a flag to reserve that register (e.g., +``-ffixed-x18``). If absolutely necessary, code compiled without reserving the +register may be run on the same thread as code that uses ShadowCallStack by +saving the register value temporarily on the stack (`example in Android`_) but +this should be done with care since it risks leaking the shadow call stack +address. .. _`example in Android`: https://android-review.googlesource.com/c/platform/frameworks/base/+/803717 -Because of the use of register ``x18``, the ShadowCallStack feature is -incompatible with any other feature that may use ``x18``. However, there -is no inherent reason why ShadowCallStack needs to use register ``x18`` -specifically; in principle, a platform could choose to reserve and use another -register for ShadowCallStack, but this would be incompatible with the AAPCS64. +Because it requires a dedicated register, the ShadowCallStack feature is +incompatible with any other feature that may use ``SCSReg``. However, there is +no inherent reason why ShadowCallStack needs to use a specific register; in +principle, a platform could choose to reserve and use another register for +ShadowCallStack, but this would be incompatible with the ABI standards +published in AAPCS64 and the RISC-V psABI. Special unwind information is required on functions that are compiled with ShadowCallStack and that may be unwound, i.e. functions compiled with @@ -91,7 +94,7 @@ ``-fstack-protector``. It protects from non-linear overflows and arbitrary memory writes to the return address slot. -The instrumentation makes use of the ``x18`` register to reference the shadow +The instrumentation makes use of the ``SCSReg`` register to reference the shadow call stack, meaning that references to the shadow call stack do not have to be stored in memory. This makes it possible to implement a runtime that avoids exposing the address of the shadow call stack to attackers that can @@ -120,11 +123,11 @@ The runtime will need the address of the shadow call stack in order to deallocate it when destroying the thread. If the entire program is compiled -with ``-ffixed-x18``, this is trivial: the address can be derived from the -value stored in ``x18`` (e.g. by masking out the lower bits). If a guard +with ``SCSReg`` reserved, this is trivial: the address can be derived from the +value stored in ``SCSReg`` (e.g. by masking out the lower bits). If a guard region is used, the address of the start of the guard region could then be stored at the start of the shadow call stack itself. But if it is possible -for code compiled without ``-ffixed-x18`` to run on a thread managed by the +for code compiled without reserving ``SCSReg`` to run on a thread managed by the runtime, which is the case on Android for example, the address must be stored somewhere else instead. On Android we store the address of the start of the guard region in TLS and deallocate the entire guard region including the @@ -133,7 +136,7 @@ One way in which the address of the shadow call stack could leak is in the ``jmp_buf`` data structure used by ``setjmp`` and ``longjmp``. The Android -runtime `avoids this`_ by only storing the low bits of ``x18`` in the +runtime `avoids this`_ by only storing the low bits of ``SCSReg`` in the ``jmp_buf``, which requires the address of the shadow call stack to be aligned to its size. @@ -146,9 +149,11 @@ Usage ===== -To enable ShadowCallStack, just pass the ``-fsanitize=shadow-call-stack`` -flag to both compile and link command lines. On aarch64, you also need to pass -``-ffixed-x18`` unless your target already reserves ``x18``. +To enable ShadowCallStack, just pass the ``-fsanitize=shadow-call-stack`` flag +to both compile and link command lines. On aarch64, you also need to pass +``-ffixed-x18`` unless your target already reserves ``x18``. On RISC-V, ``x3`` +(``gp``) is always reserved. It is, however, important to disable GP relaxation +in the linker. This can be done with the ``--no-relax-gp`` flag in GNU ld. Low-level API ------------- diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -13,6 +13,7 @@ #include "clang/Driver/Options.h" #include "clang/Driver/ToolChain.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Path.h" #include "llvm/Support/SpecialCaseList.h" @@ -543,11 +544,8 @@ << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; } - if ((Kinds & SanitizerKind::ShadowCallStack) && - ((TC.getTriple().isAArch64() && - !llvm::AArch64::isX18ReservedByDefault(TC.getTriple())) || - (TC.getTriple().isRISCV() && - !llvm::RISCV::isX18ReservedByDefault(TC.getTriple()))) && + if ((Kinds & SanitizerKind::ShadowCallStack) && TC.getTriple().isAArch64() && + !llvm::AArch64::isX18ReservedByDefault(TC.getTriple()) && !Args.hasArg(options::OPT_ffixed_x18) && DiagnoseErrors) { D.Diag(diag::err_drv_argument_only_allowed_with) << lastArgumentForMask(D, Args, Kinds & SanitizerKind::ShadowCallStack) diff --git a/clang/test/Driver/sanitizer-ld.c b/clang/test/Driver/sanitizer-ld.c --- a/clang/test/Driver/sanitizer-ld.c +++ b/clang/test/Driver/sanitizer-ld.c @@ -736,12 +736,12 @@ // RUN: %clang -fsanitize=shadow-call-stack -### %s 2>&1 \ // RUN: --target=riscv32-unknown-elf -fuse-ld=ld \ // RUN: | FileCheck --check-prefix=CHECK-SHADOWCALLSTACK-ELF-RISCV32 %s -// CHECK-SHADOWCALLSTACK-ELF-RISCV32: '-fsanitize=shadow-call-stack' only allowed with '-ffixed-x18' +// CHECK-SHADOWCALLSTACK-ELF-RISCV32-NOT: error: // RUN: %clang -fsanitize=shadow-call-stack -### %s 2>&1 \ // RUN: --target=riscv64-unknown-linux -fuse-ld=ld \ // RUN: | FileCheck --check-prefix=CHECK-SHADOWCALLSTACK-LINUX-RISCV64 %s -// CHECK-SHADOWCALLSTACK-LINUX-RISCV64: '-fsanitize=shadow-call-stack' only allowed with '-ffixed-x18' +// CHECK-SHADOWCALLSTACK-LINUX-RISCV64-NOT: error: // RUN: %clang -target riscv64-linux-android -fsanitize=shadow-call-stack %s -### 2>&1 \ // RUN: | FileCheck %s --check-prefix=CHECK-SHADOWCALLSTACK-ANDROID-RISCV64 diff --git a/compiler-rt/test/shadowcallstack/lit.cfg.py b/compiler-rt/test/shadowcallstack/lit.cfg.py --- a/compiler-rt/test/shadowcallstack/lit.cfg.py +++ b/compiler-rt/test/shadowcallstack/lit.cfg.py @@ -19,5 +19,5 @@ scs_arch_cflags += ' -ffixed-x18 ' config.substitutions.append( ("%clang_scs ", config.clang + ' -O0 -fsanitize=shadow-call-stack ' + scs_arch_cflags + ' ') ) -if config.host_os not in ['Linux'] or config.target_arch not in ['aarch64']: +if config.host_os not in ['Linux'] or config.target_arch not in ['aarch64','riscv64']: config.unsupported = True diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst --- a/llvm/docs/ReleaseNotes.rst +++ b/llvm/docs/ReleaseNotes.rst @@ -161,6 +161,11 @@ * I, F, D, and A extension versions have been update to the 20191214 spec versions. New version I2.1, F2.2, D2.2, A2.1. This should not impact code generation. Immpacts versions accepted in ``-march`` and reported in ELF attributes. +* Changed the ShadowCallStack register from ``x18`` (``s2``) to ``x3`` + (``gp``). Note this breaks the existing non-standard ABI for ShadowCallStack + on RISC-V, but conforms with the new "platform register" defined in the + RISC-V psABI (for more details see the + `psABI discussion `_). Changes to the WebAssembly Backend ---------------------------------- diff --git a/llvm/include/llvm/TargetParser/RISCVTargetParser.h b/llvm/include/llvm/TargetParser/RISCVTargetParser.h --- a/llvm/include/llvm/TargetParser/RISCVTargetParser.h +++ b/llvm/include/llvm/TargetParser/RISCVTargetParser.h @@ -40,8 +40,6 @@ void fillValidCPUArchList(SmallVectorImpl &Values, bool IsRV64); void fillValidTuneCPUArchList(SmallVectorImpl &Values, bool IsRV64); -bool isX18ReservedByDefault(const Triple &TT); - } // namespace RISCV } // namespace llvm diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp @@ -98,7 +98,7 @@ MCRegister getBPReg() { return RISCV::X9; } // Returns the register holding shadow call stack pointer. -MCRegister getSCSPReg() { return RISCV::X18; } +MCRegister getSCSPReg() { return RISCV::X3; } } // namespace RISCVABI diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -27,8 +27,8 @@ using namespace llvm; -// For now we use x18, a.k.a s2, as pointer to shadow call stack. -// User should explicitly set -ffixed-x18 and not use x18 in their asm. +// For now we use x3, a.k.a gp, as pointer to shadow call stack. +// User should not use x3 in their asm. static void emitSCSPrologue(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const DebugLoc &DL) { @@ -48,27 +48,12 @@ Register SCSPReg = RISCVABI::getSCSPReg(); - auto &Ctx = MF.getFunction().getContext(); - if (!STI.isRegisterReservedByUser(SCSPReg)) { - Ctx.diagnose(DiagnosticInfoUnsupported{ - MF.getFunction(), "x18 not reserved by user for Shadow Call Stack."}); - return; - } - - const auto *RVFI = MF.getInfo(); - if (RVFI->useSaveRestoreLibCalls(MF)) { - Ctx.diagnose(DiagnosticInfoUnsupported{ - MF.getFunction(), - "Shadow Call Stack cannot be combined with Save/Restore LibCalls."}); - return; - } - const RISCVInstrInfo *TII = STI.getInstrInfo(); bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit); int64_t SlotSize = STI.getXLen() / 8; // Store return address to shadow call stack - // s[w|d] ra, 0(s2) - // addi s2, s2, [4|8] + // s[w|d] ra, 0(gp) + // addi gp, gp, [4|8] BuildMI(MBB, MI, DL, TII->get(IsRV64 ? RISCV::SD : RISCV::SW)) .addReg(RAReg) .addReg(SCSPReg) @@ -83,7 +68,7 @@ // Emit a CFI instruction that causes SlotSize to be subtracted from the value // of the shadow stack pointer when unwinding past this frame. char DwarfSCSReg = TRI->getDwarfRegNum(SCSPReg, /*IsEH*/ true); - assert(DwarfSCSReg < 32 && "SCS Register should be < 32 (X18)."); + assert(DwarfSCSReg < 32 && "SCS Register should be < 32 (X3)."); char Offset = static_cast(-SlotSize) & 0x7f; const char CFIInst[] = { @@ -118,27 +103,12 @@ Register SCSPReg = RISCVABI::getSCSPReg(); - auto &Ctx = MF.getFunction().getContext(); - if (!STI.isRegisterReservedByUser(SCSPReg)) { - Ctx.diagnose(DiagnosticInfoUnsupported{ - MF.getFunction(), "x18 not reserved by user for Shadow Call Stack."}); - return; - } - - const auto *RVFI = MF.getInfo(); - if (RVFI->useSaveRestoreLibCalls(MF)) { - Ctx.diagnose(DiagnosticInfoUnsupported{ - MF.getFunction(), - "Shadow Call Stack cannot be combined with Save/Restore LibCalls."}); - return; - } - const RISCVInstrInfo *TII = STI.getInstrInfo(); bool IsRV64 = STI.hasFeature(RISCV::Feature64Bit); int64_t SlotSize = STI.getXLen() / 8; // Load return address from shadow call stack - // l[w|d] ra, -[4|8](s2) - // addi s2, s2, -[4|8] + // l[w|d] ra, -[4|8](gp) + // addi gp, gp, -[4|8] BuildMI(MBB, MI, DL, TII->get(IsRV64 ? RISCV::LD : RISCV::LW)) .addReg(RAReg, RegState::Define) .addReg(SCSPReg) diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp --- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp +++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp @@ -83,9 +83,6 @@ FrameLowering( initializeSubtargetDependencies(TT, CPU, TuneCPU, FS, ABIName)), InstrInfo(*this), RegInfo(getHwMode()), TLInfo(TM, *this) { - if (RISCV::isX18ReservedByDefault(TT)) - UserReservedRegister.set(RISCV::X18); - CallLoweringInfo.reset(new RISCVCallLowering(*getTargetLowering())); Legalizer.reset(new RISCVLegalizerInfo(*this)); diff --git a/llvm/lib/TargetParser/RISCVTargetParser.cpp b/llvm/lib/TargetParser/RISCVTargetParser.cpp --- a/llvm/lib/TargetParser/RISCVTargetParser.cpp +++ b/llvm/lib/TargetParser/RISCVTargetParser.cpp @@ -85,10 +85,5 @@ #include "llvm/TargetParser/RISCVTargetParserDef.inc" } -bool isX18ReservedByDefault(const Triple &TT) { - // X18 is reserved for the ShadowCallStack ABI (even when not enabled). - return TT.isOSFuchsia() || TT.isAndroid(); -} - } // namespace RISCV } // namespace llvm diff --git a/llvm/test/CodeGen/RISCV/reserved-regs.ll b/llvm/test/CodeGen/RISCV/reserved-regs.ll --- a/llvm/test/CodeGen/RISCV/reserved-regs.ll +++ b/llvm/test/CodeGen/RISCV/reserved-regs.ll @@ -57,9 +57,6 @@ ; RUN: llc -mtriple=riscv32 -mattr=+reserve-x31 -verify-machineinstrs < %s | FileCheck %s -check-prefix=X31 ; RUN: llc -mtriple=riscv64 -mattr=+reserve-x31 -verify-machineinstrs < %s | FileCheck %s -check-prefix=X31 -; RUN: llc -mtriple=riscv64-fuchsia -verify-machineinstrs < %s | FileCheck %s -check-prefix=X18 -; RUN: llc -mtriple=riscv64-linux-android -verify-machineinstrs < %s | FileCheck %s -check-prefix=X18 - ; This program is free to use all registers, but needs a stack pointer for ; spill values, so do not test for reserving the stack pointer. diff --git a/llvm/test/CodeGen/RISCV/saverestore-scs.ll b/llvm/test/CodeGen/RISCV/saverestore-scs.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/saverestore-scs.ll @@ -0,0 +1,40 @@ +;; Check that shadow call stack doesn't interfere with save/restore + +; RUN: llc -mtriple=riscv32 < %s | FileCheck %s -check-prefix=RV32I +; RUN: llc -mtriple=riscv64 < %s | FileCheck %s -check-prefix=RV64I +; RUN: llc -mtriple=riscv32 -mattr=+save-restore < %s | FileCheck %s -check-prefix=RV32I-SR +; RUN: llc -mtriple=riscv64 -mattr=+save-restore < %s | FileCheck %s -check-prefix=RV64I-SR +; RUN: llc -mtriple=riscv32 -mattr=+f,+save-restore -target-abi=ilp32f < %s | FileCheck %s -check-prefix=RV32I-FP-SR +; RUN: llc -mtriple=riscv64 -mattr=+f,+d,+save-restore -target-abi=lp64d < %s | FileCheck %s -check-prefix=RV64I-FP-SR + +@var2 = global [30 x i32] zeroinitializer + +define void @callee_scs() nounwind shadowcallstack { +; RV32I-LABEL: callee_scs: +; RV32I-NOT: call t0, __riscv_save +; RV32I-NOT: tail __riscv_restore +; +; RV64I-LABEL: callee_scs: +; RV64I-NOT: call t0, __riscv_save +; RV64I-NOT: tail __riscv_restore +; +; RV32I-SR-LABEL: callee_scs: +; RV32I-SR: call t0, __riscv_save_12 +; RV32I-SR: tail __riscv_restore_12 +; +; RV64I-SR-LABEL: callee_scs: +; RV64I-SR: call t0, __riscv_save_12 +; RV64I-SR: tail __riscv_restore_12 +; +; RV32I-FP-SR-LABEL: callee_scs: +; RV32I-FP-SR: call t0, __riscv_save_12 +; RV32I-FP-SR: tail __riscv_restore_12 +; +; RV64I-FP-SR-LABEL: callee_scs: +; RV64I-FP-SR: call t0, __riscv_save_12 +; RV64I-FP-SR: tail __riscv_restore_12 + %val = load [30 x i32], ptr @var2 + store volatile [30 x i32] %val, ptr @var2 + ret void +} + diff --git a/llvm/test/CodeGen/RISCV/shadowcallstack.ll b/llvm/test/CodeGen/RISCV/shadowcallstack.ll --- a/llvm/test/CodeGen/RISCV/shadowcallstack.ll +++ b/llvm/test/CodeGen/RISCV/shadowcallstack.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc -mtriple=riscv32 -mattr=+reserve-x18 -verify-machineinstrs < %s \ +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \ ; RUN: | FileCheck %s --check-prefix=RV32 -; RUN: llc -mtriple=riscv64 -mattr=+reserve-x18 -verify-machineinstrs < %s \ +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ ; RUN: | FileCheck %s --check-prefix=RV64 define void @f1() shadowcallstack { @@ -34,9 +34,9 @@ define i32 @f3() shadowcallstack { ; RV32-LABEL: f3: ; RV32: # %bb.0: -; RV32-NEXT: sw ra, 0(s2) -; RV32-NEXT: addi s2, s2, 4 -; RV32-NEXT: .cfi_escape 0x16, 0x12, 0x02, 0x82, 0x7c # +; RV32-NEXT: sw ra, 0(gp) +; RV32-NEXT: addi gp, gp, 4 +; RV32-NEXT: .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x7c # ; RV32-NEXT: addi sp, sp, -16 ; RV32-NEXT: .cfi_def_cfa_offset 16 ; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill @@ -44,16 +44,16 @@ ; RV32-NEXT: call bar@plt ; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload ; RV32-NEXT: addi sp, sp, 16 -; RV32-NEXT: lw ra, -4(s2) -; RV32-NEXT: addi s2, s2, -4 -; RV32-NEXT: .cfi_restore s2 +; RV32-NEXT: lw ra, -4(gp) +; RV32-NEXT: addi gp, gp, -4 +; RV32-NEXT: .cfi_restore gp ; RV32-NEXT: ret ; ; RV64-LABEL: f3: ; RV64: # %bb.0: -; RV64-NEXT: sd ra, 0(s2) -; RV64-NEXT: addi s2, s2, 8 -; RV64-NEXT: .cfi_escape 0x16, 0x12, 0x02, 0x82, 0x78 # +; RV64-NEXT: sd ra, 0(gp) +; RV64-NEXT: addi gp, gp, 8 +; RV64-NEXT: .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x78 # ; RV64-NEXT: addi sp, sp, -16 ; RV64-NEXT: .cfi_def_cfa_offset 16 ; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill @@ -61,9 +61,9 @@ ; RV64-NEXT: call bar@plt ; RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload ; RV64-NEXT: addi sp, sp, 16 -; RV64-NEXT: ld ra, -8(s2) -; RV64-NEXT: addi s2, s2, -8 -; RV64-NEXT: .cfi_restore s2 +; RV64-NEXT: ld ra, -8(gp) +; RV64-NEXT: addi gp, gp, -8 +; RV64-NEXT: .cfi_restore gp ; RV64-NEXT: ret %res = call i32 @bar() %res1 = add i32 %res, 1 @@ -73,72 +73,72 @@ define i32 @f4() shadowcallstack { ; RV32-LABEL: f4: ; RV32: # %bb.0: -; RV32-NEXT: sw ra, 0(s2) -; RV32-NEXT: addi s2, s2, 4 -; RV32-NEXT: .cfi_escape 0x16, 0x12, 0x02, 0x82, 0x7c # +; RV32-NEXT: sw ra, 0(gp) +; RV32-NEXT: addi gp, gp, 4 +; RV32-NEXT: .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x7c # ; RV32-NEXT: addi sp, sp, -16 ; RV32-NEXT: .cfi_def_cfa_offset 16 ; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill ; RV32-NEXT: sw s0, 8(sp) # 4-byte Folded Spill ; RV32-NEXT: sw s1, 4(sp) # 4-byte Folded Spill -; RV32-NEXT: sw s3, 0(sp) # 4-byte Folded Spill +; RV32-NEXT: sw s2, 0(sp) # 4-byte Folded Spill ; RV32-NEXT: .cfi_offset ra, -4 ; RV32-NEXT: .cfi_offset s0, -8 ; RV32-NEXT: .cfi_offset s1, -12 -; RV32-NEXT: .cfi_offset s3, -16 +; RV32-NEXT: .cfi_offset s2, -16 ; RV32-NEXT: call bar@plt ; RV32-NEXT: mv s0, a0 ; RV32-NEXT: call bar@plt ; RV32-NEXT: mv s1, a0 ; RV32-NEXT: call bar@plt -; RV32-NEXT: mv s3, a0 +; RV32-NEXT: mv s2, a0 ; RV32-NEXT: call bar@plt ; RV32-NEXT: add s0, s0, s1 -; RV32-NEXT: add a0, s3, a0 +; RV32-NEXT: add a0, s2, a0 ; RV32-NEXT: add a0, s0, a0 ; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload ; RV32-NEXT: lw s0, 8(sp) # 4-byte Folded Reload ; RV32-NEXT: lw s1, 4(sp) # 4-byte Folded Reload -; RV32-NEXT: lw s3, 0(sp) # 4-byte Folded Reload +; RV32-NEXT: lw s2, 0(sp) # 4-byte Folded Reload ; RV32-NEXT: addi sp, sp, 16 -; RV32-NEXT: lw ra, -4(s2) -; RV32-NEXT: addi s2, s2, -4 -; RV32-NEXT: .cfi_restore s2 +; RV32-NEXT: lw ra, -4(gp) +; RV32-NEXT: addi gp, gp, -4 +; RV32-NEXT: .cfi_restore gp ; RV32-NEXT: ret ; ; RV64-LABEL: f4: ; RV64: # %bb.0: -; RV64-NEXT: sd ra, 0(s2) -; RV64-NEXT: addi s2, s2, 8 -; RV64-NEXT: .cfi_escape 0x16, 0x12, 0x02, 0x82, 0x78 # +; RV64-NEXT: sd ra, 0(gp) +; RV64-NEXT: addi gp, gp, 8 +; RV64-NEXT: .cfi_escape 0x16, 0x03, 0x02, 0x73, 0x78 # ; RV64-NEXT: addi sp, sp, -32 ; RV64-NEXT: .cfi_def_cfa_offset 32 ; RV64-NEXT: sd ra, 24(sp) # 8-byte Folded Spill ; RV64-NEXT: sd s0, 16(sp) # 8-byte Folded Spill ; RV64-NEXT: sd s1, 8(sp) # 8-byte Folded Spill -; RV64-NEXT: sd s3, 0(sp) # 8-byte Folded Spill +; RV64-NEXT: sd s2, 0(sp) # 8-byte Folded Spill ; RV64-NEXT: .cfi_offset ra, -8 ; RV64-NEXT: .cfi_offset s0, -16 ; RV64-NEXT: .cfi_offset s1, -24 -; RV64-NEXT: .cfi_offset s3, -32 +; RV64-NEXT: .cfi_offset s2, -32 ; RV64-NEXT: call bar@plt ; RV64-NEXT: mv s0, a0 ; RV64-NEXT: call bar@plt ; RV64-NEXT: mv s1, a0 ; RV64-NEXT: call bar@plt -; RV64-NEXT: mv s3, a0 +; RV64-NEXT: mv s2, a0 ; RV64-NEXT: call bar@plt ; RV64-NEXT: add s0, s0, s1 -; RV64-NEXT: add a0, s3, a0 +; RV64-NEXT: add a0, s2, a0 ; RV64-NEXT: addw a0, s0, a0 ; RV64-NEXT: ld ra, 24(sp) # 8-byte Folded Reload ; RV64-NEXT: ld s0, 16(sp) # 8-byte Folded Reload ; RV64-NEXT: ld s1, 8(sp) # 8-byte Folded Reload -; RV64-NEXT: ld s3, 0(sp) # 8-byte Folded Reload +; RV64-NEXT: ld s2, 0(sp) # 8-byte Folded Reload ; RV64-NEXT: addi sp, sp, 32 -; RV64-NEXT: ld ra, -8(s2) -; RV64-NEXT: addi s2, s2, -8 -; RV64-NEXT: .cfi_restore s2 +; RV64-NEXT: ld ra, -8(gp) +; RV64-NEXT: addi gp, gp, -8 +; RV64-NEXT: .cfi_restore gp ; RV64-NEXT: ret %res1 = call i32 @bar() %res2 = call i32 @bar() @@ -153,28 +153,28 @@ define i32 @f5() shadowcallstack nounwind { ; RV32-LABEL: f5: ; RV32: # %bb.0: -; RV32-NEXT: sw ra, 0(s2) -; RV32-NEXT: addi s2, s2, 4 +; RV32-NEXT: sw ra, 0(gp) +; RV32-NEXT: addi gp, gp, 4 ; RV32-NEXT: addi sp, sp, -16 ; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill ; RV32-NEXT: call bar@plt ; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload ; RV32-NEXT: addi sp, sp, 16 -; RV32-NEXT: lw ra, -4(s2) -; RV32-NEXT: addi s2, s2, -4 +; RV32-NEXT: lw ra, -4(gp) +; RV32-NEXT: addi gp, gp, -4 ; RV32-NEXT: ret ; ; RV64-LABEL: f5: ; RV64: # %bb.0: -; RV64-NEXT: sd ra, 0(s2) -; RV64-NEXT: addi s2, s2, 8 +; RV64-NEXT: sd ra, 0(gp) +; RV64-NEXT: addi gp, gp, 8 ; RV64-NEXT: addi sp, sp, -16 ; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill ; RV64-NEXT: call bar@plt ; RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload ; RV64-NEXT: addi sp, sp, 16 -; RV64-NEXT: ld ra, -8(s2) -; RV64-NEXT: addi s2, s2, -8 +; RV64-NEXT: ld ra, -8(gp) +; RV64-NEXT: addi gp, gp, -8 ; RV64-NEXT: ret %res = call i32 @bar() %res1 = add i32 %res, 1