1 //===-- ABISysV_s390x.cpp -------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "ABISysV_s390x.h"
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/TargetParser/Triple.h"
14 #include "lldb/Core/Module.h"
15 #include "lldb/Core/PluginManager.h"
16 #include "lldb/Core/Value.h"
17 #include "lldb/Core/ValueObjectConstResult.h"
18 #include "lldb/Core/ValueObjectMemory.h"
19 #include "lldb/Core/ValueObjectRegister.h"
20 #include "lldb/Symbol/UnwindPlan.h"
21 #include "lldb/Target/Process.h"
22 #include "lldb/Target/RegisterContext.h"
23 #include "lldb/Target/StackFrame.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Target/Thread.h"
26 #include "lldb/Utility/ConstString.h"
27 #include "lldb/Utility/DataExtractor.h"
28 #include "lldb/Utility/LLDBLog.h"
29 #include "lldb/Utility/Log.h"
30 #include "lldb/Utility/RegisterValue.h"
31 #include "lldb/Utility/Status.h"
35 using namespace lldb_private
;
37 LLDB_PLUGIN_DEFINE_ADV(ABISysV_s390x
, ABISystemZ
)
40 // General Purpose Registers
57 // Floating Point Registers / Vector Registers 0-15
75 dwarf_acr0_s390x
= 48,
91 // Program Status Word
92 dwarf_pswm_s390x
= 64,
94 // Vector Registers 16-31
113 // RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB
115 #define DEFINE_REG(name, size, alt, generic) \
117 #name, alt, size, 0, eEncodingUint, eFormatHex, \
118 {dwarf_##name##_s390x, dwarf_##name##_s390x, generic, \
119 LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, \
120 nullptr, nullptr, nullptr, \
123 static const RegisterInfo g_register_infos
[] = {
124 DEFINE_REG(r0
, 8, nullptr, LLDB_INVALID_REGNUM
),
125 DEFINE_REG(r1
, 8, nullptr, LLDB_INVALID_REGNUM
),
126 DEFINE_REG(r2
, 8, nullptr, LLDB_REGNUM_GENERIC_ARG1
),
127 DEFINE_REG(r3
, 8, nullptr, LLDB_REGNUM_GENERIC_ARG2
),
128 DEFINE_REG(r4
, 8, nullptr, LLDB_REGNUM_GENERIC_ARG3
),
129 DEFINE_REG(r5
, 8, nullptr, LLDB_REGNUM_GENERIC_ARG4
),
130 DEFINE_REG(r6
, 8, nullptr, LLDB_REGNUM_GENERIC_ARG5
),
131 DEFINE_REG(r7
, 8, nullptr, LLDB_INVALID_REGNUM
),
132 DEFINE_REG(r8
, 8, nullptr, LLDB_INVALID_REGNUM
),
133 DEFINE_REG(r9
, 8, nullptr, LLDB_INVALID_REGNUM
),
134 DEFINE_REG(r10
, 8, nullptr, LLDB_INVALID_REGNUM
),
135 DEFINE_REG(r11
, 8, nullptr, LLDB_REGNUM_GENERIC_FP
),
136 DEFINE_REG(r12
, 8, nullptr, LLDB_INVALID_REGNUM
),
137 DEFINE_REG(r13
, 8, nullptr, LLDB_INVALID_REGNUM
),
138 DEFINE_REG(r14
, 8, nullptr, LLDB_INVALID_REGNUM
),
139 DEFINE_REG(r15
, 8, "sp", LLDB_REGNUM_GENERIC_SP
),
140 DEFINE_REG(acr0
, 4, nullptr, LLDB_INVALID_REGNUM
),
141 DEFINE_REG(acr1
, 4, nullptr, LLDB_INVALID_REGNUM
),
142 DEFINE_REG(acr2
, 4, nullptr, LLDB_INVALID_REGNUM
),
143 DEFINE_REG(acr3
, 4, nullptr, LLDB_INVALID_REGNUM
),
144 DEFINE_REG(acr4
, 4, nullptr, LLDB_INVALID_REGNUM
),
145 DEFINE_REG(acr5
, 4, nullptr, LLDB_INVALID_REGNUM
),
146 DEFINE_REG(acr6
, 4, nullptr, LLDB_INVALID_REGNUM
),
147 DEFINE_REG(acr7
, 4, nullptr, LLDB_INVALID_REGNUM
),
148 DEFINE_REG(acr8
, 4, nullptr, LLDB_INVALID_REGNUM
),
149 DEFINE_REG(acr9
, 4, nullptr, LLDB_INVALID_REGNUM
),
150 DEFINE_REG(acr10
, 4, nullptr, LLDB_INVALID_REGNUM
),
151 DEFINE_REG(acr11
, 4, nullptr, LLDB_INVALID_REGNUM
),
152 DEFINE_REG(acr12
, 4, nullptr, LLDB_INVALID_REGNUM
),
153 DEFINE_REG(acr13
, 4, nullptr, LLDB_INVALID_REGNUM
),
154 DEFINE_REG(acr14
, 4, nullptr, LLDB_INVALID_REGNUM
),
155 DEFINE_REG(acr15
, 4, nullptr, LLDB_INVALID_REGNUM
),
156 DEFINE_REG(pswm
, 8, nullptr, LLDB_REGNUM_GENERIC_FLAGS
),
157 DEFINE_REG(pswa
, 8, nullptr, LLDB_REGNUM_GENERIC_PC
),
158 DEFINE_REG(f0
, 8, nullptr, LLDB_INVALID_REGNUM
),
159 DEFINE_REG(f1
, 8, nullptr, LLDB_INVALID_REGNUM
),
160 DEFINE_REG(f2
, 8, nullptr, LLDB_INVALID_REGNUM
),
161 DEFINE_REG(f3
, 8, nullptr, LLDB_INVALID_REGNUM
),
162 DEFINE_REG(f4
, 8, nullptr, LLDB_INVALID_REGNUM
),
163 DEFINE_REG(f5
, 8, nullptr, LLDB_INVALID_REGNUM
),
164 DEFINE_REG(f6
, 8, nullptr, LLDB_INVALID_REGNUM
),
165 DEFINE_REG(f7
, 8, nullptr, LLDB_INVALID_REGNUM
),
166 DEFINE_REG(f8
, 8, nullptr, LLDB_INVALID_REGNUM
),
167 DEFINE_REG(f9
, 8, nullptr, LLDB_INVALID_REGNUM
),
168 DEFINE_REG(f10
, 8, nullptr, LLDB_INVALID_REGNUM
),
169 DEFINE_REG(f11
, 8, nullptr, LLDB_INVALID_REGNUM
),
170 DEFINE_REG(f12
, 8, nullptr, LLDB_INVALID_REGNUM
),
171 DEFINE_REG(f13
, 8, nullptr, LLDB_INVALID_REGNUM
),
172 DEFINE_REG(f14
, 8, nullptr, LLDB_INVALID_REGNUM
),
173 DEFINE_REG(f15
, 8, nullptr, LLDB_INVALID_REGNUM
),
176 static const uint32_t k_num_register_infos
= std::size(g_register_infos
);
178 const lldb_private::RegisterInfo
*
179 ABISysV_s390x::GetRegisterInfoArray(uint32_t &count
) {
180 count
= k_num_register_infos
;
181 return g_register_infos
;
184 size_t ABISysV_s390x::GetRedZoneSize() const { return 0; }
189 ABISysV_s390x::CreateInstance(lldb::ProcessSP process_sp
, const ArchSpec
&arch
) {
190 if (arch
.GetTriple().getArch() == llvm::Triple::systemz
) {
191 return ABISP(new ABISysV_s390x(std::move(process_sp
), MakeMCRegisterInfo(arch
)));
196 bool ABISysV_s390x::PrepareTrivialCall(Thread
&thread
, addr_t sp
,
197 addr_t func_addr
, addr_t return_addr
,
198 llvm::ArrayRef
<addr_t
> args
) const {
199 Log
*log
= GetLog(LLDBLog::Expressions
);
203 s
.Printf("ABISysV_s390x::PrepareTrivialCall (tid = 0x%" PRIx64
204 ", sp = 0x%" PRIx64
", func_addr = 0x%" PRIx64
205 ", return_addr = 0x%" PRIx64
,
206 thread
.GetID(), (uint64_t)sp
, (uint64_t)func_addr
,
207 (uint64_t)return_addr
);
209 for (size_t i
= 0; i
< args
.size(); ++i
)
210 s
.Printf(", arg%" PRIu64
" = 0x%" PRIx64
, static_cast<uint64_t>(i
+ 1),
213 log
->PutString(s
.GetString());
216 RegisterContext
*reg_ctx
= thread
.GetRegisterContext().get();
220 const RegisterInfo
*pc_reg_info
=
221 reg_ctx
->GetRegisterInfo(eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_PC
);
222 const RegisterInfo
*sp_reg_info
=
223 reg_ctx
->GetRegisterInfo(eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_SP
);
224 const RegisterInfo
*ra_reg_info
= reg_ctx
->GetRegisterInfoByName("r14", 0);
225 ProcessSP
process_sp(thread
.GetProcess());
227 // Allocate a new stack frame and space for stack arguments if necessary
230 if (args
.size() > 5) {
231 sp
-= 8 * (args
.size() - 5);
239 for (size_t i
= 0; i
< args
.size(); ++i
) {
241 const RegisterInfo
*reg_info
= reg_ctx
->GetRegisterInfo(
242 eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_ARG1
+ i
);
243 LLDB_LOGF(log
, "About to write arg%" PRIu64
" (0x%" PRIx64
") into %s",
244 static_cast<uint64_t>(i
+ 1), args
[i
], reg_info
->name
);
245 if (!reg_ctx
->WriteRegisterFromUnsigned(reg_info
, args
[i
]))
249 LLDB_LOGF(log
, "About to write arg%" PRIu64
" (0x%" PRIx64
") onto stack",
250 static_cast<uint64_t>(i
+ 1), args
[i
]);
251 if (!process_sp
->WritePointerToMemory(arg_pos
, args
[i
], error
))
257 // %r14 is set to the return address
259 LLDB_LOGF(log
, "Writing RA: 0x%" PRIx64
, (uint64_t)return_addr
);
261 if (!reg_ctx
->WriteRegisterFromUnsigned(ra_reg_info
, return_addr
))
264 // %r15 is set to the actual stack value.
266 LLDB_LOGF(log
, "Writing SP: 0x%" PRIx64
, (uint64_t)sp
);
268 if (!reg_ctx
->WriteRegisterFromUnsigned(sp_reg_info
, sp
))
271 // %pc is set to the address of the called function.
273 LLDB_LOGF(log
, "Writing PC: 0x%" PRIx64
, (uint64_t)func_addr
);
275 if (!reg_ctx
->WriteRegisterFromUnsigned(pc_reg_info
, func_addr
))
281 static bool ReadIntegerArgument(Scalar
&scalar
, unsigned int bit_width
,
282 bool is_signed
, Thread
&thread
,
283 uint32_t *argument_register_ids
,
284 unsigned int ¤t_argument_register
,
285 addr_t
¤t_stack_argument
) {
287 return false; // Scalar can't hold large integer arguments
289 if (current_argument_register
< 5) {
290 scalar
= thread
.GetRegisterContext()->ReadRegisterAsUnsigned(
291 argument_register_ids
[current_argument_register
], 0);
292 current_argument_register
++;
294 scalar
.SignExtend(bit_width
);
296 uint32_t byte_size
= (bit_width
+ (8 - 1)) / 8;
298 if (thread
.GetProcess()->ReadScalarIntegerFromMemory(
299 current_stack_argument
+ 8 - byte_size
, byte_size
, is_signed
,
301 current_stack_argument
+= 8;
309 bool ABISysV_s390x::GetArgumentValues(Thread
&thread
, ValueList
&values
) const {
310 unsigned int num_values
= values
.GetSize();
311 unsigned int value_index
;
313 // Extract the register context so we can read arguments from registers
315 RegisterContext
*reg_ctx
= thread
.GetRegisterContext().get();
320 // Get the pointer to the first stack argument so we have a place to start
323 addr_t sp
= reg_ctx
->GetSP(0);
328 addr_t current_stack_argument
= sp
+ 160;
330 uint32_t argument_register_ids
[5];
332 argument_register_ids
[0] =
333 reg_ctx
->GetRegisterInfo(eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_ARG1
)
334 ->kinds
[eRegisterKindLLDB
];
335 argument_register_ids
[1] =
336 reg_ctx
->GetRegisterInfo(eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_ARG2
)
337 ->kinds
[eRegisterKindLLDB
];
338 argument_register_ids
[2] =
339 reg_ctx
->GetRegisterInfo(eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_ARG3
)
340 ->kinds
[eRegisterKindLLDB
];
341 argument_register_ids
[3] =
342 reg_ctx
->GetRegisterInfo(eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_ARG4
)
343 ->kinds
[eRegisterKindLLDB
];
344 argument_register_ids
[4] =
345 reg_ctx
->GetRegisterInfo(eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_ARG5
)
346 ->kinds
[eRegisterKindLLDB
];
348 unsigned int current_argument_register
= 0;
350 for (value_index
= 0; value_index
< num_values
; ++value_index
) {
351 Value
*value
= values
.GetValueAtIndex(value_index
);
356 // We currently only support extracting values with Clang QualTypes. Do we
357 // care about others?
358 CompilerType compiler_type
= value
->GetCompilerType();
359 std::optional
<uint64_t> bit_size
= compiler_type
.GetBitSize(&thread
);
364 if (compiler_type
.IsIntegerOrEnumerationType(is_signed
)) {
365 ReadIntegerArgument(value
->GetScalar(), *bit_size
, is_signed
, thread
,
366 argument_register_ids
, current_argument_register
,
367 current_stack_argument
);
368 } else if (compiler_type
.IsPointerType()) {
369 ReadIntegerArgument(value
->GetScalar(), *bit_size
, false, thread
,
370 argument_register_ids
, current_argument_register
,
371 current_stack_argument
);
378 Status
ABISysV_s390x::SetReturnValueObject(lldb::StackFrameSP
&frame_sp
,
379 lldb::ValueObjectSP
&new_value_sp
) {
382 error
.SetErrorString("Empty value object for return value.");
386 CompilerType compiler_type
= new_value_sp
->GetCompilerType();
387 if (!compiler_type
) {
388 error
.SetErrorString("Null clang type for return value.");
392 Thread
*thread
= frame_sp
->GetThread().get();
398 RegisterContext
*reg_ctx
= thread
->GetRegisterContext().get();
400 bool set_it_simple
= false;
401 if (compiler_type
.IsIntegerOrEnumerationType(is_signed
) ||
402 compiler_type
.IsPointerType()) {
403 const RegisterInfo
*reg_info
= reg_ctx
->GetRegisterInfoByName("r2", 0);
407 size_t num_bytes
= new_value_sp
->GetData(data
, data_error
);
408 if (data_error
.Fail()) {
409 error
.SetErrorStringWithFormat(
410 "Couldn't convert return value to raw data: %s",
411 data_error
.AsCString());
414 lldb::offset_t offset
= 0;
415 if (num_bytes
<= 8) {
416 uint64_t raw_value
= data
.GetMaxU64(&offset
, num_bytes
);
418 if (reg_ctx
->WriteRegisterFromUnsigned(reg_info
, raw_value
))
419 set_it_simple
= true;
421 error
.SetErrorString("We don't support returning longer than 64 bit "
422 "integer values at present.");
424 } else if (compiler_type
.IsFloatingPointType(count
, is_complex
)) {
426 error
.SetErrorString(
427 "We don't support returning complex values at present");
429 std::optional
<uint64_t> bit_width
=
430 compiler_type
.GetBitSize(frame_sp
.get());
432 error
.SetErrorString("can't get type size");
435 if (*bit_width
<= 64) {
436 const RegisterInfo
*f0_info
= reg_ctx
->GetRegisterInfoByName("f0", 0);
437 RegisterValue f0_value
;
440 size_t num_bytes
= new_value_sp
->GetData(data
, data_error
);
441 if (data_error
.Fail()) {
442 error
.SetErrorStringWithFormat(
443 "Couldn't convert return value to raw data: %s",
444 data_error
.AsCString());
448 unsigned char buffer
[8];
449 ByteOrder byte_order
= data
.GetByteOrder();
451 data
.CopyByteOrderedData(0, num_bytes
, buffer
, 8, byte_order
);
452 f0_value
.SetBytes(buffer
, 8, byte_order
);
453 reg_ctx
->WriteRegister(f0_info
, f0_value
);
454 set_it_simple
= true;
456 // FIXME - don't know how to do long doubles yet.
457 error
.SetErrorString(
458 "We don't support returning float values > 64 bits at present");
463 if (!set_it_simple
) {
464 // Okay we've got a structure or something that doesn't fit in a simple
465 // register. We should figure out where it really goes, but we don't
467 error
.SetErrorString("We only support setting simple integer and float "
468 "return types at present.");
474 ValueObjectSP
ABISysV_s390x::GetReturnValueObjectSimple(
475 Thread
&thread
, CompilerType
&return_compiler_type
) const {
476 ValueObjectSP return_valobj_sp
;
479 if (!return_compiler_type
)
480 return return_valobj_sp
;
482 // value.SetContext (Value::eContextTypeClangType, return_value_type);
483 value
.SetCompilerType(return_compiler_type
);
485 RegisterContext
*reg_ctx
= thread
.GetRegisterContext().get();
487 return return_valobj_sp
;
489 const uint32_t type_flags
= return_compiler_type
.GetTypeInfo();
490 if (type_flags
& eTypeIsScalar
) {
491 value
.SetValueType(Value::ValueType::Scalar
);
493 bool success
= false;
494 if (type_flags
& eTypeIsInteger
) {
495 // Extract the register context so we can read arguments from registers.
496 std::optional
<uint64_t> byte_size
=
497 return_compiler_type
.GetByteSize(&thread
);
499 return return_valobj_sp
;
500 uint64_t raw_value
= thread
.GetRegisterContext()->ReadRegisterAsUnsigned(
501 reg_ctx
->GetRegisterInfoByName("r2", 0), 0);
502 const bool is_signed
= (type_flags
& eTypeIsSigned
) != 0;
503 switch (*byte_size
) {
507 case sizeof(uint64_t):
509 value
.GetScalar() = (int64_t)(raw_value
);
511 value
.GetScalar() = (uint64_t)(raw_value
);
515 case sizeof(uint32_t):
517 value
.GetScalar() = (int32_t)(raw_value
& UINT32_MAX
);
519 value
.GetScalar() = (uint32_t)(raw_value
& UINT32_MAX
);
523 case sizeof(uint16_t):
525 value
.GetScalar() = (int16_t)(raw_value
& UINT16_MAX
);
527 value
.GetScalar() = (uint16_t)(raw_value
& UINT16_MAX
);
531 case sizeof(uint8_t):
533 value
.GetScalar() = (int8_t)(raw_value
& UINT8_MAX
);
535 value
.GetScalar() = (uint8_t)(raw_value
& UINT8_MAX
);
539 } else if (type_flags
& eTypeIsFloat
) {
540 if (type_flags
& eTypeIsComplex
) {
541 // Don't handle complex yet.
543 std::optional
<uint64_t> byte_size
=
544 return_compiler_type
.GetByteSize(&thread
);
545 if (byte_size
&& *byte_size
<= sizeof(long double)) {
546 const RegisterInfo
*f0_info
= reg_ctx
->GetRegisterInfoByName("f0", 0);
547 RegisterValue f0_value
;
548 if (reg_ctx
->ReadRegister(f0_info
, f0_value
)) {
550 if (f0_value
.GetData(data
)) {
551 lldb::offset_t offset
= 0;
552 if (*byte_size
== sizeof(float)) {
553 value
.GetScalar() = (float)data
.GetFloat(&offset
);
555 } else if (*byte_size
== sizeof(double)) {
556 value
.GetScalar() = (double)data
.GetDouble(&offset
);
558 } else if (*byte_size
== sizeof(long double)) {
559 // Don't handle long double yet.
568 return_valobj_sp
= ValueObjectConstResult::Create(
569 thread
.GetStackFrameAtIndex(0).get(), value
, ConstString(""));
570 } else if (type_flags
& eTypeIsPointer
) {
572 reg_ctx
->GetRegisterInfoByName("r2", 0)->kinds
[eRegisterKindLLDB
];
574 (uint64_t)thread
.GetRegisterContext()->ReadRegisterAsUnsigned(r2_id
, 0);
575 value
.SetValueType(Value::ValueType::Scalar
);
576 return_valobj_sp
= ValueObjectConstResult::Create(
577 thread
.GetStackFrameAtIndex(0).get(), value
, ConstString(""));
580 return return_valobj_sp
;
583 ValueObjectSP
ABISysV_s390x::GetReturnValueObjectImpl(
584 Thread
&thread
, CompilerType
&return_compiler_type
) const {
585 ValueObjectSP return_valobj_sp
;
587 if (!return_compiler_type
)
588 return return_valobj_sp
;
590 ExecutionContext
exe_ctx(thread
.shared_from_this());
591 return_valobj_sp
= GetReturnValueObjectSimple(thread
, return_compiler_type
);
592 if (return_valobj_sp
)
593 return return_valobj_sp
;
595 RegisterContextSP reg_ctx_sp
= thread
.GetRegisterContext();
597 return return_valobj_sp
;
599 if (return_compiler_type
.IsAggregateType()) {
600 // FIXME: This is just taking a guess, r2 may very well no longer hold the
601 // return storage location.
602 // If we are going to do this right, when we make a new frame we should
603 // check to see if it uses a memory return, and if we are at the first
604 // instruction and if so stash away the return location. Then we would
605 // only return the memory return value if we know it is valid.
608 reg_ctx_sp
->GetRegisterInfoByName("r2", 0)->kinds
[eRegisterKindLLDB
];
609 lldb::addr_t storage_addr
=
610 (uint64_t)thread
.GetRegisterContext()->ReadRegisterAsUnsigned(r2_id
, 0);
611 return_valobj_sp
= ValueObjectMemory::Create(
612 &thread
, "", Address(storage_addr
, nullptr), return_compiler_type
);
615 return return_valobj_sp
;
618 bool ABISysV_s390x::CreateFunctionEntryUnwindPlan(UnwindPlan
&unwind_plan
) {
620 unwind_plan
.SetRegisterKind(eRegisterKindDWARF
);
622 UnwindPlan::RowSP
row(new UnwindPlan::Row
);
624 // Our Call Frame Address is the stack pointer value + 160
625 row
->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r15_s390x
, 160);
627 // The previous PC is in r14
628 row
->SetRegisterLocationToRegister(dwarf_pswa_s390x
, dwarf_r14_s390x
, true);
630 // All other registers are the same.
631 unwind_plan
.AppendRow(row
);
632 unwind_plan
.SetSourceName("s390x at-func-entry default");
633 unwind_plan
.SetSourcedFromCompiler(eLazyBoolNo
);
637 bool ABISysV_s390x::CreateDefaultUnwindPlan(UnwindPlan
&unwind_plan
) {
638 // There's really no default way to unwind on s390x. Trust the .eh_frame CFI,
639 // which should always be good.
643 bool ABISysV_s390x::GetFallbackRegisterLocation(
644 const RegisterInfo
*reg_info
,
645 UnwindPlan::Row::RegisterLocation
&unwind_regloc
) {
646 // If a volatile register is being requested, we don't want to forward the
647 // next frame's register contents up the stack -- the register is not
648 // retrievable at this frame.
649 if (RegisterIsVolatile(reg_info
)) {
650 unwind_regloc
.SetUndefined();
657 bool ABISysV_s390x::RegisterIsVolatile(const RegisterInfo
*reg_info
) {
658 return !RegisterIsCalleeSaved(reg_info
);
661 bool ABISysV_s390x::RegisterIsCalleeSaved(const RegisterInfo
*reg_info
) {
663 // Preserved registers are :
667 const char *name
= reg_info
->name
;
668 if (name
[0] == 'r') {
674 return name
[2] == '\0';
676 case '1': // r10, r11, r12, r13, r15
677 if ((name
[2] >= '0' && name
[2] <= '3') || name
[2] == '5')
678 return name
[3] == '\0';
685 if (name
[0] == 'f') {
689 return name
[2] == '\0';
691 case '1': // r10, r11, r12, r13, r14, r15
692 if (name
[2] >= '0' && name
[2] <= '5')
693 return name
[3] == '\0';
701 // Accept shorter-variant versions
702 if (name
[0] == 's' && name
[1] == 'p' && name
[2] == '\0') // sp
704 if (name
[0] == 'f' && name
[1] == 'p' && name
[2] == '\0') // fp
706 if (name
[0] == 'p' && name
[1] == 'c' && name
[2] == '\0') // pc
712 void ABISysV_s390x::Initialize() {
713 PluginManager::RegisterPlugin(
714 GetPluginNameStatic(), "System V ABI for s390x targets", CreateInstance
);
717 void ABISysV_s390x::Terminate() {
718 PluginManager::UnregisterPlugin(CreateInstance
);