Re-factor Quick ABI support
Now every architecture must provide a mapper between
VRs parameters and physical registers. Additionally as
a helper function architecture can provide a bulk copy
helper for GenDalvikArgs utility.
All other things becomes a common code stuff:
GetArgMappingToPhysicalReg, GenDalvikArgsNoRange,
GenDalvikArgsRange, FlushIns.
Mapper now uses shorty representation of input
parameters. This is required due to location are not
enough to detect the type of parameter (fp or core).
For the details
see https://android-review.googlesource.com/#/c/113936/.
Change-Id: Ie762b921e0acaa936518ee6b63c9a9d25f83e434
Signed-off-by: Serguei Katkov <serguei.i.katkov@intel.com>
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index 320c0f4..bd88091 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -53,20 +53,14 @@
return res;
}
-void Mir2Lir::LockArg(int in_position, bool wide) {
- RegStorage reg_arg_low = GetArgMappingToPhysicalReg(in_position);
- RegStorage reg_arg_high = wide ? GetArgMappingToPhysicalReg(in_position + 1) :
- RegStorage::InvalidReg();
+void Mir2Lir::LockArg(int in_position, bool) {
+ RegStorage reg_arg = GetArgMappingToPhysicalReg(in_position);
- if (reg_arg_low.Valid()) {
- LockTemp(reg_arg_low);
- }
- if (reg_arg_high.Valid() && reg_arg_low.NotExactlyEquals(reg_arg_high)) {
- LockTemp(reg_arg_high);
+ if (reg_arg.Valid()) {
+ LockTemp(reg_arg);
}
}
-// TODO: simplify when 32-bit targets go hard-float.
RegStorage Mir2Lir::LoadArg(int in_position, RegisterClass reg_class, bool wide) {
ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
int offset = StackVisitor::GetOutVROffset(in_position, cu_->instruction_set);
@@ -87,81 +81,38 @@
offset += sizeof(uint64_t);
}
- if (cu_->target64) {
- RegStorage reg_arg = GetArgMappingToPhysicalReg(in_position);
- if (!reg_arg.Valid()) {
- RegStorage new_reg =
- wide ? AllocTypedTempWide(false, reg_class) : AllocTypedTemp(false, reg_class);
- LoadBaseDisp(TargetPtrReg(kSp), offset, new_reg, wide ? k64 : k32, kNotVolatile);
- return new_reg;
- } else {
- // Check if we need to copy the arg to a different reg_class.
- if (!RegClassMatches(reg_class, reg_arg)) {
- if (wide) {
- RegStorage new_reg = AllocTypedTempWide(false, reg_class);
- OpRegCopyWide(new_reg, reg_arg);
- reg_arg = new_reg;
- } else {
- RegStorage new_reg = AllocTypedTemp(false, reg_class);
- OpRegCopy(new_reg, reg_arg);
- reg_arg = new_reg;
- }
+ RegStorage reg_arg = GetArgMappingToPhysicalReg(in_position);
+
+ // TODO: REVISIT: This adds a spill of low part while we could just copy it.
+ if (reg_arg.Valid() && wide && (reg_arg.GetWideKind() == kNotWide)) {
+ // For wide register we've got only half of it.
+ // Flush it to memory then.
+ StoreBaseDisp(TargetPtrReg(kSp), offset, reg_arg, k32, kNotVolatile);
+ reg_arg = RegStorage::InvalidReg();
+ }
+
+ if (!reg_arg.Valid()) {
+ reg_arg = wide ? AllocTypedTempWide(false, reg_class) : AllocTypedTemp(false, reg_class);
+ LoadBaseDisp(TargetPtrReg(kSp), offset, reg_arg, wide ? k64 : k32, kNotVolatile);
+ } else {
+ // Check if we need to copy the arg to a different reg_class.
+ if (!RegClassMatches(reg_class, reg_arg)) {
+ if (wide) {
+ RegStorage new_reg = AllocTypedTempWide(false, reg_class);
+ OpRegCopyWide(new_reg, reg_arg);
+ reg_arg = new_reg;
+ } else {
+ RegStorage new_reg = AllocTypedTemp(false, reg_class);
+ OpRegCopy(new_reg, reg_arg);
+ reg_arg = new_reg;
}
}
- return reg_arg;
- }
-
- RegStorage reg_arg_low = GetArgMappingToPhysicalReg(in_position);
- RegStorage reg_arg_high = wide ? GetArgMappingToPhysicalReg(in_position + 1) :
- RegStorage::InvalidReg();
-
- // If the VR is wide and there is no register for high part, we need to load it.
- if (wide && !reg_arg_high.Valid()) {
- // If the low part is not in a reg, we allocate a pair. Otherwise, we just load to high reg.
- if (!reg_arg_low.Valid()) {
- RegStorage new_regs = AllocTypedTempWide(false, reg_class);
- LoadBaseDisp(TargetPtrReg(kSp), offset, new_regs, k64, kNotVolatile);
- return new_regs; // The reg_class is OK, we can return.
- } else {
- // Assume that no ABI allows splitting a wide fp reg between a narrow fp reg and memory,
- // i.e. the low part is in a core reg. Load the second part in a core reg as well for now.
- DCHECK(!reg_arg_low.IsFloat());
- reg_arg_high = AllocTemp();
- int offset_high = offset + sizeof(uint32_t);
- Load32Disp(TargetPtrReg(kSp), offset_high, reg_arg_high);
- // Continue below to check the reg_class.
- }
- }
-
- // If the low part is not in a register yet, we need to load it.
- if (!reg_arg_low.Valid()) {
- // Assume that if the low part of a wide arg is passed in memory, so is the high part,
- // thus we don't get here for wide args as it's handled above. Big-endian ABIs could
- // conceivably break this assumption but Android supports only little-endian architectures.
- DCHECK(!wide);
- reg_arg_low = AllocTypedTemp(false, reg_class);
- Load32Disp(TargetPtrReg(kSp), offset, reg_arg_low);
- return reg_arg_low; // The reg_class is OK, we can return.
- }
-
- RegStorage reg_arg = wide ? RegStorage::MakeRegPair(reg_arg_low, reg_arg_high) : reg_arg_low;
- // Check if we need to copy the arg to a different reg_class.
- if (!RegClassMatches(reg_class, reg_arg)) {
- if (wide) {
- RegStorage new_regs = AllocTypedTempWide(false, reg_class);
- OpRegCopyWide(new_regs, reg_arg);
- reg_arg = new_regs;
- } else {
- RegStorage new_reg = AllocTypedTemp(false, reg_class);
- OpRegCopy(new_reg, reg_arg);
- reg_arg = new_reg;
- }
}
return reg_arg;
}
-// TODO: simpilfy when 32-bit targets go hard float.
void Mir2Lir::LoadArgDirect(int in_position, RegLocation rl_dest) {
+ DCHECK_EQ(rl_dest.location, kLocPhysReg);
ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
int offset = StackVisitor::GetOutVROffset(in_position, cu_->instruction_set);
if (cu_->instruction_set == kX86) {
@@ -180,48 +131,23 @@
offset += sizeof(uint64_t);
}
- if (!rl_dest.wide) {
- RegStorage reg = GetArgMappingToPhysicalReg(in_position);
- if (reg.Valid()) {
- OpRegCopy(rl_dest.reg, reg);
- } else {
- Load32Disp(TargetPtrReg(kSp), offset, rl_dest.reg);
- }
+ RegStorage reg_arg = GetArgMappingToPhysicalReg(in_position);
+
+ // TODO: REVISIT: This adds a spill of low part while we could just copy it.
+ if (reg_arg.Valid() && rl_dest.wide && (reg_arg.GetWideKind() == kNotWide)) {
+ // For wide register we've got only half of it.
+ // Flush it to memory then.
+ StoreBaseDisp(TargetPtrReg(kSp), offset, reg_arg, k32, kNotVolatile);
+ reg_arg = RegStorage::InvalidReg();
+ }
+
+ if (!reg_arg.Valid()) {
+ LoadBaseDisp(TargetPtrReg(kSp), offset, rl_dest.reg, rl_dest.wide ? k64 : k32, kNotVolatile);
} else {
- if (cu_->target64) {
- RegStorage reg = GetArgMappingToPhysicalReg(in_position);
- if (reg.Valid()) {
- OpRegCopy(rl_dest.reg, reg);
- } else {
- LoadBaseDisp(TargetPtrReg(kSp), offset, rl_dest.reg, k64, kNotVolatile);
- }
- return;
- }
-
- RegStorage reg_arg_low = GetArgMappingToPhysicalReg(in_position);
- RegStorage reg_arg_high = GetArgMappingToPhysicalReg(in_position + 1);
-
- if (cu_->instruction_set == kX86) {
- // Can't handle double split between reg & memory. Flush reg half to memory.
- if (rl_dest.reg.IsDouble() && (reg_arg_low.Valid() != reg_arg_high.Valid())) {
- DCHECK(reg_arg_low.Valid());
- DCHECK(!reg_arg_high.Valid());
- Store32Disp(TargetPtrReg(kSp), offset, reg_arg_low);
- reg_arg_low = RegStorage::InvalidReg();
- }
- }
-
- if (reg_arg_low.Valid() && reg_arg_high.Valid()) {
- OpRegCopyWide(rl_dest.reg, RegStorage::MakeRegPair(reg_arg_low, reg_arg_high));
- } else if (reg_arg_low.Valid() && !reg_arg_high.Valid()) {
- OpRegCopy(rl_dest.reg, reg_arg_low);
- int offset_high = offset + sizeof(uint32_t);
- Load32Disp(TargetPtrReg(kSp), offset_high, rl_dest.reg.GetHigh());
- } else if (!reg_arg_low.Valid() && reg_arg_high.Valid()) {
- OpRegCopy(rl_dest.reg.GetHigh(), reg_arg_high);
- Load32Disp(TargetPtrReg(kSp), offset, rl_dest.reg.GetLow());
+ if (rl_dest.wide) {
+ OpRegCopyWide(rl_dest.reg, reg_arg);
} else {
- LoadBaseDisp(TargetPtrReg(kSp), offset, rl_dest.reg, k64, kNotVolatile);
+ OpRegCopy(rl_dest.reg, reg_arg);
}
}
}
@@ -1372,4 +1298,35 @@
UNREACHABLE();
}
+void Mir2Lir::InToRegStorageMapping::Initialize(ShortyIterator* shorty,
+ InToRegStorageMapper* mapper) {
+ DCHECK(mapper != nullptr);
+ DCHECK(shorty != nullptr);
+ max_mapped_in_ = -1;
+ has_arguments_on_stack_ = false;
+ while (shorty->Next()) {
+ ShortyArg arg = shorty->GetArg();
+ RegStorage reg = mapper->GetNextReg(arg);
+ if (reg.Valid()) {
+ mapping_.Put(count_, reg);
+ max_mapped_in_ = count_;
+ // If the VR is wide and was mapped as wide then account for it.
+ if (arg.IsWide() && reg.Is64Bit()) {
+ max_mapped_in_++;
+ }
+ } else {
+ has_arguments_on_stack_ = true;
+ }
+ count_ += arg.IsWide() ? 2 : 1;
+ }
+ initialized_ = true;
+}
+
+RegStorage Mir2Lir::InToRegStorageMapping::Get(int in_position) {
+ DCHECK(IsInitialized());
+ DCHECK_LT(in_position, count_);
+ auto res = mapping_.find(in_position);
+ return res != mapping_.end() ? res->second : RegStorage::InvalidReg();
+}
+
} // namespace art