Skip to content

Commit 5c38386

Browse files
Joshua ZhuTobiHartmann
authored andcommitted
8326541: [AArch64] ZGC C2 load barrier stub should consider the length of live registers when spilling registers
Reviewed-by: eosterlund, rcastanedalo
1 parent 438e643 commit 5c38386

File tree

7 files changed

+702
-65
lines changed

7 files changed

+702
-65
lines changed

src/hotspot/cpu/aarch64/aarch64.ad

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,10 @@ extern RegMask _NO_SPECIAL_REG32_mask;
11261126
extern RegMask _NO_SPECIAL_REG_mask;
11271127
extern RegMask _NO_SPECIAL_PTR_REG_mask;
11281128

1129+
// Figure out which register class each belongs in: rc_int, rc_float or
1130+
// rc_stack.
1131+
enum RC { rc_bad, rc_int, rc_float, rc_predicate, rc_stack };
1132+
11291133
class CallStubImpl {
11301134

11311135
//--------------------------------------------------------------
@@ -1900,10 +1904,6 @@ const Pipeline * MachEpilogNode::pipeline() const {
19001904

19011905
//=============================================================================
19021906

1903-
// Figure out which register class each belongs in: rc_int, rc_float or
1904-
// rc_stack.
1905-
enum RC { rc_bad, rc_int, rc_float, rc_predicate, rc_stack };
1906-
19071907
static enum RC rc_class(OptoReg::Name reg) {
19081908

19091909
if (reg == OptoReg::Bad) {

src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.cpp

Lines changed: 154 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1081,14 +1081,43 @@ void ZBarrierSetAssembler::generate_c1_store_barrier_runtime_stub(StubAssembler*
10811081

10821082
#ifdef COMPILER2
10831083

1084+
OptoReg::Name ZBarrierSetAssembler::encode_float_vector_register_size(const Node* node, OptoReg::Name opto_reg) {
1085+
switch (node->ideal_reg()) {
1086+
case Op_RegF:
1087+
// No need to refine. The original encoding is already fine to distinguish.
1088+
assert(opto_reg % 4 == 0, "Float register should only occupy a single slot");
1089+
break;
1090+
// Use different encoding values of the same fp/vector register to help distinguish different sizes.
1091+
// Such as V16. The OptoReg::name and its corresponding slot value are
1092+
// "V16": 64, "V16_H": 65, "V16_J": 66, "V16_K": 67.
1093+
case Op_RegD:
1094+
case Op_VecD:
1095+
opto_reg &= ~3;
1096+
opto_reg |= 1;
1097+
break;
1098+
case Op_VecX:
1099+
opto_reg &= ~3;
1100+
opto_reg |= 2;
1101+
break;
1102+
case Op_VecA:
1103+
opto_reg &= ~3;
1104+
opto_reg |= 3;
1105+
break;
1106+
default:
1107+
assert(false, "unexpected ideal register");
1108+
ShouldNotReachHere();
1109+
}
1110+
return opto_reg;
1111+
}
1112+
10841113
OptoReg::Name ZBarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) {
10851114
if (!OptoReg::is_reg(opto_reg)) {
10861115
return OptoReg::Bad;
10871116
}
10881117

10891118
const VMReg vm_reg = OptoReg::as_VMReg(opto_reg);
10901119
if (vm_reg->is_FloatRegister()) {
1091-
return opto_reg & ~1;
1120+
opto_reg = encode_float_vector_register_size(node, opto_reg);
10921121
}
10931122

10941123
return opto_reg;
@@ -1099,28 +1128,82 @@ OptoReg::Name ZBarrierSetAssembler::refine_register(const Node* node, OptoReg::N
10991128

11001129
class ZSaveLiveRegisters {
11011130
private:
1131+
struct RegisterData {
1132+
VMReg _reg;
1133+
int _slots; // slots occupied once pushed into stack
1134+
1135+
// Used by GrowableArray::find()
1136+
bool operator == (const RegisterData& other) {
1137+
return _reg == other._reg;
1138+
}
1139+
};
1140+
11021141
MacroAssembler* const _masm;
11031142
RegSet _gp_regs;
11041143
FloatRegSet _fp_regs;
1144+
FloatRegSet _neon_regs;
1145+
FloatRegSet _sve_regs;
11051146
PRegSet _p_regs;
11061147

11071148
public:
11081149
void initialize(ZBarrierStubC2* stub) {
1109-
// Record registers that needs to be saved/restored
1150+
int index = -1;
1151+
GrowableArray<RegisterData> registers;
1152+
VMReg prev_vm_reg = VMRegImpl::Bad();
1153+
11101154
RegMaskIterator rmi(stub->live());
11111155
while (rmi.has_next()) {
1112-
const OptoReg::Name opto_reg = rmi.next();
1113-
if (OptoReg::is_reg(opto_reg)) {
1114-
const VMReg vm_reg = OptoReg::as_VMReg(opto_reg);
1115-
if (vm_reg->is_Register()) {
1116-
_gp_regs += RegSet::of(vm_reg->as_Register());
1117-
} else if (vm_reg->is_FloatRegister()) {
1156+
OptoReg::Name opto_reg = rmi.next();
1157+
VMReg vm_reg = OptoReg::as_VMReg(opto_reg);
1158+
1159+
if (vm_reg->is_Register()) {
1160+
// GPR may have one or two slots in regmask
1161+
// Determine whether the current vm_reg is the same physical register as the previous one
1162+
if (is_same_register(vm_reg, prev_vm_reg)) {
1163+
registers.at(index)._slots++;
1164+
} else {
1165+
RegisterData reg_data = { vm_reg, 1 };
1166+
index = registers.append(reg_data);
1167+
}
1168+
} else if (vm_reg->is_FloatRegister()) {
1169+
// We have size encoding in OptoReg of stub->live()
1170+
// After encoding, float/neon/sve register has only one slot in regmask
1171+
// Decode it to get the actual size
1172+
VMReg vm_reg_base = vm_reg->as_FloatRegister()->as_VMReg();
1173+
int slots = decode_float_vector_register_size(opto_reg);
1174+
RegisterData reg_data = { vm_reg_base, slots };
1175+
index = registers.append(reg_data);
1176+
} else if (vm_reg->is_PRegister()) {
1177+
// PRegister has only one slot in regmask
1178+
RegisterData reg_data = { vm_reg, 1 };
1179+
index = registers.append(reg_data);
1180+
} else {
1181+
assert(false, "Unknown register type");
1182+
ShouldNotReachHere();
1183+
}
1184+
prev_vm_reg = vm_reg;
1185+
}
1186+
1187+
// Record registers that needs to be saved/restored
1188+
for (GrowableArrayIterator<RegisterData> it = registers.begin(); it != registers.end(); ++it) {
1189+
RegisterData reg_data = *it;
1190+
VMReg vm_reg = reg_data._reg;
1191+
int slots = reg_data._slots;
1192+
if (vm_reg->is_Register()) {
1193+
assert(slots == 1 || slots == 2, "Unexpected register save size");
1194+
_gp_regs += RegSet::of(vm_reg->as_Register());
1195+
} else if (vm_reg->is_FloatRegister()) {
1196+
if (slots == 1 || slots == 2) {
11181197
_fp_regs += FloatRegSet::of(vm_reg->as_FloatRegister());
1119-
} else if (vm_reg->is_PRegister()) {
1120-
_p_regs += PRegSet::of(vm_reg->as_PRegister());
1198+
} else if (slots == 4) {
1199+
_neon_regs += FloatRegSet::of(vm_reg->as_FloatRegister());
11211200
} else {
1122-
fatal("Unknown register type");
1201+
assert(slots == Matcher::scalable_vector_reg_size(T_FLOAT), "Unexpected register save size");
1202+
_sve_regs += FloatRegSet::of(vm_reg->as_FloatRegister());
11231203
}
1204+
} else {
1205+
assert(vm_reg->is_PRegister() && slots == 1, "Unknown register type");
1206+
_p_regs += PRegSet::of(vm_reg->as_PRegister());
11241207
}
11251208
}
11261209

@@ -1130,27 +1213,84 @@ class ZSaveLiveRegisters {
11301213
} else {
11311214
_gp_regs -= RegSet::range(r19, r30) + RegSet::of(r8, r9);
11321215
}
1216+
1217+
// Remove C-ABI SOE fp registers
1218+
_fp_regs -= FloatRegSet::range(v8, v15);
1219+
}
1220+
1221+
static enum RC rc_class(VMReg reg) {
1222+
if (reg->is_reg()) {
1223+
if (reg->is_Register()) {
1224+
return rc_int;
1225+
} else if (reg->is_FloatRegister()) {
1226+
return rc_float;
1227+
} else if (reg->is_PRegister()) {
1228+
return rc_predicate;
1229+
}
1230+
}
1231+
if (reg->is_stack()) {
1232+
return rc_stack;
1233+
}
1234+
return rc_bad;
1235+
}
1236+
1237+
static bool is_same_register(VMReg reg1, VMReg reg2) {
1238+
if (reg1 == reg2) {
1239+
return true;
1240+
}
1241+
if (rc_class(reg1) == rc_class(reg2)) {
1242+
if (reg1->is_Register()) {
1243+
return reg1->as_Register() == reg2->as_Register();
1244+
} else if (reg1->is_FloatRegister()) {
1245+
return reg1->as_FloatRegister() == reg2->as_FloatRegister();
1246+
} else if (reg1->is_PRegister()) {
1247+
return reg1->as_PRegister() == reg2->as_PRegister();
1248+
}
1249+
}
1250+
return false;
1251+
}
1252+
1253+
static int decode_float_vector_register_size(OptoReg::Name opto_reg) {
1254+
switch (opto_reg & 3) {
1255+
case 0:
1256+
return 1;
1257+
case 1:
1258+
return 2;
1259+
case 2:
1260+
return 4;
1261+
case 3:
1262+
return Matcher::scalable_vector_reg_size(T_FLOAT);
1263+
default:
1264+
ShouldNotReachHere();
1265+
return 0;
1266+
}
11331267
}
11341268

11351269
ZSaveLiveRegisters(MacroAssembler* masm, ZBarrierStubC2* stub)
11361270
: _masm(masm),
11371271
_gp_regs(),
11381272
_fp_regs(),
1273+
_neon_regs(),
1274+
_sve_regs(),
11391275
_p_regs() {
11401276

11411277
// Figure out what registers to save/restore
11421278
initialize(stub);
11431279

11441280
// Save registers
11451281
__ push(_gp_regs, sp);
1146-
__ push_fp(_fp_regs, sp);
1282+
__ push_fp(_fp_regs, sp, MacroAssembler::PushPopFp);
1283+
__ push_fp(_neon_regs, sp, MacroAssembler::PushPopNeon);
1284+
__ push_fp(_sve_regs, sp, MacroAssembler::PushPopSVE);
11471285
__ push_p(_p_regs, sp);
11481286
}
11491287

11501288
~ZSaveLiveRegisters() {
11511289
// Restore registers
11521290
__ pop_p(_p_regs, sp);
1153-
__ pop_fp(_fp_regs, sp);
1291+
__ pop_fp(_sve_regs, sp, MacroAssembler::PushPopSVE);
1292+
__ pop_fp(_neon_regs, sp, MacroAssembler::PushPopNeon);
1293+
__ pop_fp(_fp_regs, sp, MacroAssembler::PushPopFp);
11541294

11551295
// External runtime call may clobber ptrue reg
11561296
__ reinitialize_ptrue();

src/hotspot/cpu/aarch64/gc/z/zBarrierSetAssembler_aarch64.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -187,6 +187,9 @@ class ZBarrierSetAssembler : public ZBarrierSetAssemblerBase {
187187
#endif // COMPILER1
188188

189189
#ifdef COMPILER2
190+
OptoReg::Name encode_float_vector_register_size(const Node* node,
191+
OptoReg::Name opto_reg);
192+
190193
OptoReg::Name refine_register(const Node* node,
191194
OptoReg::Name opto_reg);
192195

0 commit comments

Comments
 (0)