37 #include "src/s390/assembler-s390.h" 42 #if V8_TARGET_ARCH_S390 48 #include "src/base/bits.h" 49 #include "src/base/cpu.h" 50 #include "src/code-stubs.h" 51 #include "src/deoptimizer.h" 52 #include "src/macro-assembler.h" 53 #include "src/s390/assembler-s390-inl.h" 54 #include "src/string-constants.h" 60 static unsigned CpuFeaturesImpliedByCompiler() {
65 static bool supportsCPUFeature(
const char* feature) {
66 static std::set<std::string>& features = *
new std::set<std::string>();
67 static std::set<std::string>& all_available_features =
68 *
new std::set<std::string>({
"iesan3",
"zarch",
"stfle",
"msa",
"ldisp",
69 "eimm",
"dfp",
"etf3eh",
"highgprs",
"te",
71 if (features.empty()) {
75 #define HWCAP_S390_VX 2048 77 #define CHECK_AVAILABILITY_FOR(mask, value) \ 78 if (f & mask) features.insert(value); 81 uint64_t f = getauxval(AT_HWCAP);
82 CHECK_AVAILABILITY_FOR(HWCAP_S390_ESAN3,
"iesan3")
83 CHECK_AVAILABILITY_FOR(HWCAP_S390_ZARCH, "zarch")
84 CHECK_AVAILABILITY_FOR(HWCAP_S390_STFLE, "stfle")
85 CHECK_AVAILABILITY_FOR(HWCAP_S390_MSA, "msa")
86 CHECK_AVAILABILITY_FOR(HWCAP_S390_LDISP, "ldisp")
87 CHECK_AVAILABILITY_FOR(HWCAP_S390_EIMM, "eimm")
88 CHECK_AVAILABILITY_FOR(HWCAP_S390_DFP, "dfp")
89 CHECK_AVAILABILITY_FOR(HWCAP_S390_ETF3EH, "etf3eh")
90 CHECK_AVAILABILITY_FOR(HWCAP_S390_HIGH_GPRS, "highgprs")
91 CHECK_AVAILABILITY_FOR(HWCAP_S390_TE, "te")
92 CHECK_AVAILABILITY_FOR(HWCAP_S390_VX, "vx")
95 features.insert(all_available_features.begin(),
96 all_available_features.end());
99 USE(all_available_features);
100 return features.find(feature) != features.end();
105 static bool supportsSTFLE() {
106 #if V8_HOST_ARCH_S390 107 static bool read_tried =
false;
112 int fd = open(
"/proc/self/auxv", O_RDONLY);
116 #if V8_TARGET_ARCH_S390X 117 static Elf64_auxv_t buffer[16];
118 Elf64_auxv_t* auxv_element;
120 static Elf32_auxv_t buffer[16];
121 Elf32_auxv_t* auxv_element;
124 while (bytes_read >= 0) {
126 bytes_read = read(fd, buffer,
sizeof(buffer));
128 for (auxv_element = buffer;
129 auxv_element +
sizeof(auxv_element) <= buffer + bytes_read &&
130 auxv_element->a_type != AT_NULL;
133 if (auxv_element->a_type == AT_HWCAP) {
135 auxv_hwcap = auxv_element->a_un.a_val;
146 if (0 == auxv_hwcap) {
152 const uint32_t _HWCAP_S390_STFLE = 4;
153 return (auxv_hwcap & _HWCAP_S390_STFLE);
160 void CpuFeatures::ProbeImpl(
bool cross_compile) {
161 supported_ |= CpuFeaturesImpliedByCompiler();
162 icache_line_size_ = 256;
165 if (cross_compile)
return;
171 static bool performSTFLE = supportsSTFLE();
175 #if V8_HOST_ARCH_S390 191 ".insn s,0xb2b00000,%0\n" 192 :
"=Q"(facilities),
"=r"(reg0)
196 uint64_t one =
static_cast<uint64_t
>(1);
198 if (facilities[0] & (one << (63 - 45))) {
199 supported_ |= (1u << DISTINCT_OPS);
202 if (facilities[0] & (one << (63 - 34))) {
203 supported_ |= (1u << GENERAL_INSTR_EXT);
206 if (facilities[0] & (one << (63 - 37))) {
207 supported_ |= (1u << FLOATING_POINT_EXT);
210 if (facilities[2] & (one << (63 - (129 - 128))) &&
211 supportsCPUFeature(
"vx")) {
212 supported_ |= (1u << VECTOR_FACILITY);
215 if (facilities[0] & (1lu << (63 - 58))) {
216 supported_ |= (1u << MISC_INSTR_EXT2);
221 supported_ |= (1u << DISTINCT_OPS);
223 supported_ |= (1u << GENERAL_INSTR_EXT);
224 supported_ |= (1u << FLOATING_POINT_EXT);
225 supported_ |= (1u << MISC_INSTR_EXT2);
227 USE(supportsCPUFeature);
228 supported_ |= (1u << VECTOR_FACILITY);
230 supported_ |= (1u << FPU);
233 void CpuFeatures::PrintTarget() {
234 const char* s390_arch =
nullptr;
236 #if V8_TARGET_ARCH_S390X 242 printf(
"target %s\n", s390_arch);
245 void CpuFeatures::PrintFeatures() {
246 printf(
"FPU=%d\n", CpuFeatures::IsSupported(FPU));
247 printf(
"FPU_EXT=%d\n", CpuFeatures::IsSupported(FLOATING_POINT_EXT));
248 printf(
"GENERAL_INSTR=%d\n", CpuFeatures::IsSupported(GENERAL_INSTR_EXT));
249 printf(
"DISTINCT_OPS=%d\n", CpuFeatures::IsSupported(DISTINCT_OPS));
250 printf(
"VECTOR_FACILITY=%d\n", CpuFeatures::IsSupported(VECTOR_FACILITY));
251 printf(
"MISC_INSTR_EXT2=%d\n", CpuFeatures::IsSupported(MISC_INSTR_EXT2));
254 Register ToRegister(
int num) {
255 DCHECK(num >= 0 && num < kNumRegisters);
256 const Register kRegisters[] = {r0, r1, r2, r3, r4, r5, r6, r7,
257 r8, r9, r10, fp, ip, r13, r14, sp};
258 return kRegisters[num];
264 const int RelocInfo::kApplyMask =
265 RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
266 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE);
268 bool RelocInfo::IsCodedSpecially() {
276 bool RelocInfo::IsInConstantPool() {
return false; }
278 int RelocInfo::GetDeoptimizationId(Isolate* isolate, DeoptimizeKind kind) {
279 DCHECK(IsRuntimeEntry(rmode_));
280 return Deoptimizer::GetDeoptimizationId(isolate, target_address(), kind);
283 uint32_t RelocInfo::wasm_call_tag()
const {
284 DCHECK(rmode_ == WASM_CALL || rmode_ == WASM_STUB_CALL);
286 Assembler::target_address_at(pc_, constant_pool_));
293 Operand::Operand(Handle<HeapObject> handle) {
294 AllowHandleDereference using_location;
296 value_.immediate =
static_cast<intptr_t
>(handle.address());
297 rmode_ = RelocInfo::EMBEDDED_OBJECT;
300 Operand Operand::EmbeddedNumber(
double value) {
302 if (DoubleToSmiInteger(value, &smi))
return Operand(Smi::FromInt(smi));
303 Operand result(0, RelocInfo::EMBEDDED_OBJECT);
304 result.is_heap_object_request_ =
true;
305 result.value_.heap_object_request = HeapObjectRequest(value);
309 Operand Operand::EmbeddedStringConstant(
const StringConstantBase* str) {
310 Operand result(0, RelocInfo::EMBEDDED_OBJECT);
311 result.is_heap_object_request_ =
true;
312 result.value_.heap_object_request = HeapObjectRequest(str);
316 MemOperand::MemOperand(Register rn, int32_t offset)
317 : baseRegister(rn), indexRegister(r0), offset_(offset) {}
319 MemOperand::MemOperand(Register rx, Register rb, int32_t offset)
320 : baseRegister(rb), indexRegister(rx), offset_(offset) {}
322 void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
323 DCHECK_IMPLIES(isolate ==
nullptr, heap_object_requests_.empty());
324 for (
auto& request : heap_object_requests_) {
325 Handle<HeapObject> object;
326 Address pc =
reinterpret_cast<Address
>(buffer_ + request.offset());
327 switch (request.kind()) {
328 case HeapObjectRequest::kHeapNumber: {
330 isolate->factory()->NewHeapNumber(request.heap_number(), TENURED);
331 set_target_address_at(pc, kNullAddress,
object.address(),
335 case HeapObjectRequest::kCodeStub: {
336 request.code_stub()->set_isolate(isolate);
338 Instruction::InstructionBits(reinterpret_cast<const byte*>(pc));
339 int index = instr & 0xFFFFFFFF;
340 UpdateCodeTarget(index, request.code_stub()->GetCode());
343 case HeapObjectRequest::kStringConstant: {
344 const StringConstantBase* str = request.string();
346 set_target_address_at(pc, kNullAddress,
347 str->AllocateStringConstant(isolate).address());
357 Assembler::Assembler(
const AssemblerOptions& options,
void* buffer,
359 : AssemblerBase(options, buffer, buffer_size) {
360 reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
361 ReserveCodeTargetSpace(100);
363 relocations_.reserve(128);
366 void Assembler::GetCode(Isolate* isolate, CodeDesc* desc) {
369 AllocateAndInstallRequestedHeapObjects(isolate);
372 desc->buffer = buffer_;
373 desc->buffer_size = buffer_size_;
374 desc->instr_size = pc_offset();
375 desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
376 desc->constant_pool_size = 0;
378 desc->unwinding_info_size = 0;
379 desc->unwinding_info =
nullptr;
382 void Assembler::Align(
int m) {
383 DCHECK(m >= 4 && base::bits::IsPowerOfTwo(m));
384 while ((pc_offset() & (m - 1)) != 0) {
389 void Assembler::CodeTargetAlign() { Align(8); }
391 Condition Assembler::GetCondition(Instr instr) {
392 switch (instr & kCondMask) {
403 #if V8_TARGET_ARCH_S390X 405 bool Assembler::Is64BitLoadIntoIP(SixByteInstr instr1, SixByteInstr instr2) {
407 return (((instr1 >> 32) == 0xC0C8) && ((instr2 >> 32) == 0xC0C9));
411 bool Assembler::Is32BitLoadIntoIP(SixByteInstr instr) {
413 return ((instr >> 32) == 0xC0C9);
428 const int kEndOfChain = -4;
433 int Assembler::target_at(
int pos) {
434 SixByteInstr instr = instr_at(pos);
436 Opcode opcode = Instruction::S390OpcodeValue(buffer_ + pos);
438 if (BRC == opcode || BRCT == opcode || BRCTG == opcode || BRXH == opcode) {
439 int16_t imm16 = SIGN_EXT_IMM16((instr & kImm16Mask));
441 if (imm16 == 0)
return kEndOfChain;
443 }
else if (LLILF == opcode || BRCL == opcode || LARL == opcode ||
446 static_cast<int32_t
>(instr & (
static_cast<uint64_t
>(0xFFFFFFFF)));
449 if (imm32 == 0)
return kEndOfChain;
451 }
else if (BRXHG == opcode) {
454 int16_t imm16 = SIGN_EXT_IMM16((instr & kImm16Mask));
456 if (imm16 == 0)
return kEndOfChain;
466 void Assembler::target_at_put(
int pos,
int target_pos,
bool* is_branch) {
467 SixByteInstr instr = instr_at(pos);
468 Opcode opcode = Instruction::S390OpcodeValue(buffer_ + pos);
470 if (is_branch !=
nullptr) {
471 *is_branch = (opcode == BRC || opcode == BRCT || opcode == BRCTG ||
472 opcode == BRCL || opcode == BRASL || opcode == BRXH ||
476 if (BRC == opcode || BRCT == opcode || BRCTG == opcode || BRXH == opcode) {
477 int16_t imm16 = target_pos - pos;
479 DCHECK(is_int16(imm16));
480 instr_at_put<FourByteInstr>(pos, instr | (imm16 >> 1));
482 }
else if (BRCL == opcode || LARL == opcode || BRASL == opcode) {
484 int32_t imm32 = target_pos - pos;
485 instr &= (~static_cast<uint64_t>(0xFFFFFFFF));
486 instr_at_put<SixByteInstr>(pos, instr | (imm32 >> 1));
488 }
else if (LLILF == opcode) {
489 DCHECK(target_pos == kEndOfChain || target_pos >= 0);
492 int32_t imm32 = target_pos + (Code::kHeaderSize - kHeapObjectTag);
493 instr &= (~static_cast<uint64_t>(0xFFFFFFFF));
494 instr_at_put<SixByteInstr>(pos, instr | imm32);
496 }
else if (BRXHG == opcode) {
498 int32_t imm16 = target_pos - pos;
499 instr &= (0xFFFF0000FFFF);
503 instr_at_put<SixByteInstr>(pos, instr | (imm16 >> 1));
510 int Assembler::max_reach_from(
int pos) {
511 Opcode opcode = Instruction::S390OpcodeValue(buffer_ + pos);
514 if (BRC == opcode || BRCT == opcode || BRCTG == opcode|| BRXH == opcode ||
517 }
else if (LLILF == opcode || BRCL == opcode || LARL == opcode ||
528 void Assembler::bind_to(Label* L,
int pos) {
529 DCHECK(0 <= pos && pos <= pc_offset());
530 bool is_branch =
false;
531 while (L->is_linked()) {
532 int fixup_pos = L->pos();
534 int32_t offset = pos - fixup_pos;
535 int maxReach = max_reach_from(fixup_pos);
538 DCHECK(is_intn(offset, maxReach));
539 target_at_put(fixup_pos, pos, &is_branch);
545 if (pos > last_bound_pos_) last_bound_pos_ = pos;
548 void Assembler::bind(Label* L) {
549 DCHECK(!L->is_bound());
550 bind_to(L, pc_offset());
553 void Assembler::next(Label* L) {
554 DCHECK(L->is_linked());
555 int link = target_at(L->pos());
556 if (link == kEndOfChain) {
564 bool Assembler::is_near(Label* L, Condition cond) {
565 DCHECK(L->is_bound());
566 if (L->is_bound() ==
false)
return false;
568 int maxReach = ((cond == al) ? 26 : 16);
569 int offset = L->pos() - pc_offset();
571 return is_intn(offset, maxReach);
574 int Assembler::link(Label* L) {
579 if (L->is_linked()) {
586 position = pc_offset();
588 L->link_to(pc_offset());
594 void Assembler::load_label_offset(Register r1, Label* L) {
598 target_pos = L->pos();
599 constant = target_pos + (Code::kHeaderSize - kHeapObjectTag);
601 if (L->is_linked()) {
602 target_pos = L->pos();
608 target_pos = pc_offset();
610 L->link_to(pc_offset());
612 constant = target_pos - pc_offset();
614 llilf(r1, Operand(constant));
618 void Assembler::branchOnCond(Condition c,
int branch_offset,
bool is_bound) {
619 int offset_in_halfwords = branch_offset / 2;
620 if (is_bound && is_int16(offset_in_halfwords)) {
621 brc(c, Operand(offset_in_halfwords));
623 brcl(c, Operand(offset_in_halfwords));
630 void Assembler::stop(
const char* msg, Condition cond, int32_t code,
634 b(NegateCondition(cond), &skip, Label::kNear);
642 void Assembler::bkpt(
uint32_t imm16) {
648 void Assembler::nop(
int type) {
653 case DEBUG_BREAK_NOP:
655 oill(r3, Operand::Zero());
666 void Assembler::larl(Register r1, Label* l) {
667 larl(r1, Operand(branch_offset(l)));
670 void Assembler::EnsureSpaceFor(
int space_needed) {
671 if (buffer_space() <= (kGap + space_needed)) {
672 GrowBuffer(space_needed);
676 void Assembler::call(Handle<Code> target, RelocInfo::Mode rmode) {
677 DCHECK(RelocInfo::IsCodeTarget(rmode));
678 EnsureSpace ensure_space(
this);
680 RecordRelocInfo(rmode);
681 int32_t target_index = AddCodeTarget(target);
682 brasl(r14, Operand(target_index));
685 void Assembler::call(CodeStub* stub) {
686 EnsureSpace ensure_space(
this);
687 RequestHeapObject(HeapObjectRequest(stub));
688 RecordRelocInfo(RelocInfo::CODE_TARGET);
689 int32_t target_index = AddCodeTarget(Handle<Code>());
690 brasl(r14, Operand(target_index));
693 void Assembler::jump(Handle<Code> target, RelocInfo::Mode rmode,
695 DCHECK(RelocInfo::IsCodeTarget(rmode));
696 EnsureSpace ensure_space(
this);
698 RecordRelocInfo(rmode);
699 int32_t target_index = AddCodeTarget(target);
700 brcl(cond, Operand(target_index));
705 bool Assembler::IsNop(SixByteInstr instr,
int type) {
706 DCHECK((0 == type) || (DEBUG_BREAK_NOP == type));
707 if (DEBUG_BREAK_NOP == type) {
708 return ((instr & 0xFFFFFFFF) == 0xA53B0000);
710 return ((instr & 0xFFFF) == 0x1800);
714 void Assembler::dumy(
int r1,
int x2,
int b2,
int d2) {
715 #if defined(USE_SIMULATOR) 717 uint64_t code = (
static_cast<uint64_t
>(op & 0xFF00)) * B32 |
718 (
static_cast<uint64_t
>(r1) & 0xF) * B36 |
719 (
static_cast<uint64_t
>(x2) & 0xF) * B32 |
720 (
static_cast<uint64_t
>(b2) & 0xF) * B28 |
721 (
static_cast<uint64_t
>(d2 & 0x0FFF)) * B16 |
722 (
static_cast<uint64_t
>(d2 & 0x0FF000)) >> 4 |
723 (
static_cast<uint64_t
>(op & 0x00FF));
728 void Assembler::GrowBuffer(
int needed) {
729 if (!own_buffer_) FATAL(
"external code buffer is too small");
733 if (buffer_size_ < 4 * KB) {
734 desc.buffer_size = 4 * KB;
735 }
else if (buffer_size_ < 1 * MB) {
736 desc.buffer_size = 2 * buffer_size_;
738 desc.buffer_size = buffer_size_ + 1 * MB;
740 int space = buffer_space() + (desc.buffer_size - buffer_size_);
741 if (space < needed) {
742 desc.buffer_size += needed - space;
747 if (desc.buffer_size > kMaximalBufferSize) {
748 V8::FatalProcessOutOfMemory(
nullptr,
"Assembler::GrowBuffer");
752 desc.buffer = NewArray<byte>(desc.buffer_size);
755 desc.instr_size = pc_offset();
756 desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
759 intptr_t pc_delta = desc.buffer - buffer_;
761 (desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_);
762 memmove(desc.buffer, buffer_, desc.instr_size);
763 memmove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
767 DeleteArray(buffer_);
768 buffer_ = desc.buffer;
769 buffer_size_ = desc.buffer_size;
771 reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
772 reloc_info_writer.last_pc() + pc_delta);
779 void Assembler::db(uint8_t data) {
781 *
reinterpret_cast<uint8_t*
>(pc_) = data;
782 pc_ +=
sizeof(uint8_t);
787 *
reinterpret_cast<uint32_t*
>(pc_) = data;
791 void Assembler::dq(uint64_t value) {
793 *
reinterpret_cast<uint64_t*
>(pc_) = value;
794 pc_ +=
sizeof(uint64_t);
799 *
reinterpret_cast<uintptr_t*
>(pc_) = data;
803 void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
804 if (!ShouldRecordRelocInfo(rmode))
return;
805 DeferredRelocInfo rinfo(pc_offset(), rmode, data);
806 relocations_.push_back(rinfo);
809 void Assembler::emit_label_addr(Label* label) {
811 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
812 int position = link(label);
813 DCHECK(label->is_bound());
818 void Assembler::EmitRelocations() {
819 EnsureSpaceFor(relocations_.size() * kMaxRelocSize);
821 for (std::vector<DeferredRelocInfo>::iterator it = relocations_.begin();
822 it != relocations_.end(); it++) {
823 RelocInfo::Mode rmode = it->rmode();
824 Address pc =
reinterpret_cast<Address
>(buffer_) + it->position();
825 RelocInfo rinfo(pc, rmode, it->data(), Code());
828 if (RelocInfo::IsInternalReference(rmode)) {
830 Address pos = Memory<Address>(pc);
831 Memory<Address>(pc) = reinterpret_cast<Address>(buffer_) + pos;
832 }
else if (RelocInfo::IsInternalReferenceEncoded(rmode)) {
834 Address pos = target_address_at(pc, 0);
835 set_target_address_at(pc, 0, reinterpret_cast<Address>(buffer_) + pos,
839 reloc_info_writer.Write(&rinfo);
845 #endif // V8_TARGET_ARCH_S390