Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(609)

Unified Diff: src/ppc/simulator-ppc.cc

Issue 2754263004: PPC: [Atomics] Make Atomics.exchange a builtin using TF (Closed)
Patch Set: rebased Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/ppc/simulator-ppc.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/ppc/simulator-ppc.cc
diff --git a/src/ppc/simulator-ppc.cc b/src/ppc/simulator-ppc.cc
index c82f9464eea9333ec3e7acc8b3428df29d403404..071b7e4199f7699547d9c65745c13eddf872327c 100644
--- a/src/ppc/simulator-ppc.cc
+++ b/src/ppc/simulator-ppc.cc
@@ -25,6 +25,10 @@ namespace internal {
const auto GetRegConfig = RegisterConfiguration::Crankshaft;
+// static
+base::LazyInstance<Simulator::GlobalMonitor>::type Simulator::global_monitor_ =
+ LAZY_INSTANCE_INITIALIZER;
+
// This macro provides a platform independent use of sscanf. The reason for
// SScanF not being implemented in a platform independent way through
// ::v8::internal::OS in the same way as SNPrintF is that the
@@ -781,9 +785,10 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
last_debugger_input_ = NULL;
}
-
-Simulator::~Simulator() { free(stack_); }
-
+Simulator::~Simulator() {
+ global_monitor_.Pointer()->RemoveProcessor(&global_monitor_processor_);
+ free(stack_);
+}
// When the generated code calls an external reference we need to catch that in
// the simulator. The external reference will be a function compiled for the
@@ -987,44 +992,105 @@ void Simulator::TrashCallerSaveRegisters() {
uint32_t Simulator::ReadWU(intptr_t addr, Instruction* instr) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyLoad(addr);
uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
return *ptr;
}
+uint32_t Simulator::ReadExWU(intptr_t addr, Instruction* instr) {
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyLoadExcl(addr, TransactionSize::Word);
+ global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
+ &global_monitor_processor_);
+ uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
+ return *ptr;
+}
int32_t Simulator::ReadW(intptr_t addr, Instruction* instr) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyLoad(addr);
int32_t* ptr = reinterpret_cast<int32_t*>(addr);
return *ptr;
}
void Simulator::WriteW(intptr_t addr, uint32_t value, Instruction* instr) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyStore(addr);
+ global_monitor_.Pointer()->NotifyStore_Locked(addr,
+ &global_monitor_processor_);
uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
*ptr = value;
return;
}
+int Simulator::WriteExW(intptr_t addr, uint32_t value, Instruction* instr) {
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Word) &&
+ global_monitor_.Pointer()->NotifyStoreExcl_Locked(
+ addr, &global_monitor_processor_)) {
+ uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
+ *ptr = value;
+ return 0;
+ } else {
+ return 1;
+ }
+}
void Simulator::WriteW(intptr_t addr, int32_t value, Instruction* instr) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyStore(addr);
+ global_monitor_.Pointer()->NotifyStore_Locked(addr,
+ &global_monitor_processor_);
int32_t* ptr = reinterpret_cast<int32_t*>(addr);
*ptr = value;
return;
}
-
uint16_t Simulator::ReadHU(intptr_t addr, Instruction* instr) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyLoad(addr);
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
return *ptr;
}
+uint16_t Simulator::ReadExHU(intptr_t addr, Instruction* instr) {
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyLoadExcl(addr, TransactionSize::HalfWord);
+ global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
+ &global_monitor_processor_);
+ uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
+ return *ptr;
+}
int16_t Simulator::ReadH(intptr_t addr, Instruction* instr) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyLoad(addr);
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
return *ptr;
}
void Simulator::WriteH(intptr_t addr, uint16_t value, Instruction* instr) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyStore(addr);
+ global_monitor_.Pointer()->NotifyStore_Locked(addr,
+ &global_monitor_processor_);
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
*ptr = value;
return;
@@ -1032,43 +1098,111 @@ void Simulator::WriteH(intptr_t addr, uint16_t value, Instruction* instr) {
void Simulator::WriteH(intptr_t addr, int16_t value, Instruction* instr) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyStore(addr);
+ global_monitor_.Pointer()->NotifyStore_Locked(addr,
+ &global_monitor_processor_);
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
*ptr = value;
return;
}
+int Simulator::WriteExH(intptr_t addr, uint16_t value, Instruction* instr) {
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::HalfWord) &&
+ global_monitor_.Pointer()->NotifyStoreExcl_Locked(
+ addr, &global_monitor_processor_)) {
+ uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
+ *ptr = value;
+ return 0;
+ } else {
+ return 1;
+ }
+}
uint8_t Simulator::ReadBU(intptr_t addr) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyLoad(addr);
uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
return *ptr;
}
int8_t Simulator::ReadB(intptr_t addr) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyLoad(addr);
int8_t* ptr = reinterpret_cast<int8_t*>(addr);
return *ptr;
}
+uint8_t Simulator::ReadExBU(intptr_t addr) {
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyLoadExcl(addr, TransactionSize::Byte);
+ global_monitor_.Pointer()->NotifyLoadExcl_Locked(addr,
+ &global_monitor_processor_);
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
+ return *ptr;
+}
void Simulator::WriteB(intptr_t addr, uint8_t value) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyStore(addr);
+ global_monitor_.Pointer()->NotifyStore_Locked(addr,
+ &global_monitor_processor_);
uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
*ptr = value;
}
void Simulator::WriteB(intptr_t addr, int8_t value) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyStore(addr);
+ global_monitor_.Pointer()->NotifyStore_Locked(addr,
+ &global_monitor_processor_);
int8_t* ptr = reinterpret_cast<int8_t*>(addr);
*ptr = value;
}
+int Simulator::WriteExB(intptr_t addr, uint8_t value) {
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ if (local_monitor_.NotifyStoreExcl(addr, TransactionSize::Byte) &&
+ global_monitor_.Pointer()->NotifyStoreExcl_Locked(
+ addr, &global_monitor_processor_)) {
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
+ *ptr = value;
+ return 0;
+ } else {
+ return 1;
+ }
+}
intptr_t* Simulator::ReadDW(intptr_t addr) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyLoad(addr);
intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
return ptr;
}
void Simulator::WriteDW(intptr_t addr, int64_t value) {
+ // All supported PPC targets allow unaligned accesses, so we don't need to
+ // check the alignment here.
+ base::LockGuard<base::Mutex> lock_guard(&global_monitor_.Pointer()->mutex);
+ local_monitor_.NotifyStore(addr);
+ global_monitor_.Pointer()->NotifyStore_Locked(addr,
+ &global_monitor_processor_);
int64_t* ptr = reinterpret_cast<int64_t*>(addr);
*ptr = value;
return;
@@ -2262,6 +2396,36 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
}
break;
}
+ case STBCX: {
+ int rs = instr->RSValue();
+ int ra = instr->RAValue();
+ int rb = instr->RBValue();
+ intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+ int8_t rs_val = get_register(rs);
+ intptr_t rb_val = get_register(rb);
+ SetCR0(WriteExB(ra_val + rb_val, rs_val));
+ break;
+ }
+ case STHCX: {
+ int rs = instr->RSValue();
+ int ra = instr->RAValue();
+ int rb = instr->RBValue();
+ intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+ int16_t rs_val = get_register(rs);
+ intptr_t rb_val = get_register(rb);
+ SetCR0(WriteExH(ra_val + rb_val, rs_val, instr));
+ break;
+ }
+ case STWCX: {
+ int rs = instr->RSValue();
+ int ra = instr->RAValue();
+ int rb = instr->RBValue();
+ intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+ int32_t rs_val = get_register(rs);
+ intptr_t rb_val = get_register(rb);
+ SetCR0(WriteExW(ra_val + rb_val, rs_val, instr));
+ break;
+ }
case TW: {
// used for call redirection in simulation mode
SoftwareInterrupt(instr);
@@ -2993,18 +3157,40 @@ void Simulator::ExecuteGeneric(Instruction* instr) {
}
break;
}
- case LHAX:
- case LHAUX: {
+ case LHAX: {
int rt = instr->RTValue();
int ra = instr->RAValue();
int rb = instr->RBValue();
intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
intptr_t rb_val = get_register(rb);
set_register(rt, ReadH(ra_val + rb_val, instr));
- if (opcode == LHAUX) {
- DCHECK(ra != 0 && ra != rt);
- set_register(ra, ra_val + rb_val);
- }
+ break;
+ }
+ case LBARX: {
+ int rt = instr->RTValue();
+ int ra = instr->RAValue();
+ int rb = instr->RBValue();
+ intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+ intptr_t rb_val = get_register(rb);
+ set_register(rt, ReadExBU(ra_val + rb_val) & 0xFF);
+ break;
+ }
+ case LHARX: {
+ int rt = instr->RTValue();
+ int ra = instr->RAValue();
+ int rb = instr->RBValue();
+ intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+ intptr_t rb_val = get_register(rb);
+ set_register(rt, ReadExHU(ra_val + rb_val, instr));
+ break;
+ }
+ case LWARX: {
+ int rt = instr->RTValue();
+ int ra = instr->RAValue();
+ int rb = instr->RBValue();
+ intptr_t ra_val = ra == 0 ? 0 : get_register(ra);
+ intptr_t rb_val = get_register(rb);
+ set_register(rt, ReadExWU(ra_val + rb_val, instr));
break;
}
case DCBF: {
@@ -4073,6 +4259,169 @@ uintptr_t Simulator::PopAddress() {
set_register(sp, current_sp + sizeof(uintptr_t));
return address;
}
+
+Simulator::LocalMonitor::LocalMonitor()
+ : access_state_(MonitorAccess::Open),
+ tagged_addr_(0),
+ size_(TransactionSize::None) {}
+
+void Simulator::LocalMonitor::Clear() {
+ access_state_ = MonitorAccess::Open;
+ tagged_addr_ = 0;
+ size_ = TransactionSize::None;
+}
+
+void Simulator::LocalMonitor::NotifyLoad(int32_t addr) {
+ if (access_state_ == MonitorAccess::Exclusive) {
+ // A load could cause a cache eviction which will affect the monitor. As a
+ // result, it's most strict to unconditionally clear the local monitor on
+ // load.
+ Clear();
+ }
+}
+
+void Simulator::LocalMonitor::NotifyLoadExcl(int32_t addr,
+ TransactionSize size) {
+ access_state_ = MonitorAccess::Exclusive;
+ tagged_addr_ = addr;
+ size_ = size;
+}
+
+void Simulator::LocalMonitor::NotifyStore(int32_t addr) {
+ if (access_state_ == MonitorAccess::Exclusive) {
+ // A store could cause a cache eviction which will affect the
+ // monitor. As a result, it's most strict to unconditionally clear the
+ // local monitor on store.
+ Clear();
+ }
+}
+
+bool Simulator::LocalMonitor::NotifyStoreExcl(int32_t addr,
+ TransactionSize size) {
+ if (access_state_ == MonitorAccess::Exclusive) {
+ if (addr == tagged_addr_ && size_ == size) {
+ Clear();
+ return true;
+ } else {
+ Clear();
+ return false;
+ }
+ } else {
+ DCHECK(access_state_ == MonitorAccess::Open);
+ return false;
+ }
+}
+
+Simulator::GlobalMonitor::Processor::Processor()
+ : access_state_(MonitorAccess::Open),
+ tagged_addr_(0),
+ next_(nullptr),
+ prev_(nullptr) {}
+
+void Simulator::GlobalMonitor::Processor::Clear_Locked() {
+ access_state_ = MonitorAccess::Open;
+ tagged_addr_ = 0;
+}
+void Simulator::GlobalMonitor::Processor::NotifyLoadExcl_Locked(int32_t addr) {
+ access_state_ = MonitorAccess::Exclusive;
+ tagged_addr_ = addr;
+}
+
+void Simulator::GlobalMonitor::Processor::NotifyStore_Locked(
+ int32_t addr, bool is_requesting_processor) {
+ if (access_state_ == MonitorAccess::Exclusive) {
+ // It is possible that a store caused a cache eviction,
+ // which can affect the montior, so conservatively,
+ // we always clear the monitor.
+ Clear_Locked();
+ }
+}
+
+bool Simulator::GlobalMonitor::Processor::NotifyStoreExcl_Locked(
+ int32_t addr, bool is_requesting_processor) {
+ if (access_state_ == MonitorAccess::Exclusive) {
+ if (is_requesting_processor) {
+ if (addr == tagged_addr_) {
+ Clear_Locked();
+ return true;
+ }
+ } else if (addr == tagged_addr_) {
+ Clear_Locked();
+ return false;
+ }
+ }
+ return false;
+}
+
+Simulator::GlobalMonitor::GlobalMonitor() : head_(nullptr) {}
+
+void Simulator::GlobalMonitor::NotifyLoadExcl_Locked(int32_t addr,
+ Processor* processor) {
+ processor->NotifyLoadExcl_Locked(addr);
+ PrependProcessor_Locked(processor);
+}
+
+void Simulator::GlobalMonitor::NotifyStore_Locked(int32_t addr,
+ Processor* processor) {
+ // Notify each processor of the store operation.
+ for (Processor* iter = head_; iter; iter = iter->next_) {
+ bool is_requesting_processor = iter == processor;
+ iter->NotifyStore_Locked(addr, is_requesting_processor);
+ }
+}
+
+bool Simulator::GlobalMonitor::NotifyStoreExcl_Locked(int32_t addr,
+ Processor* processor) {
+ DCHECK(IsProcessorInLinkedList_Locked(processor));
+ if (processor->NotifyStoreExcl_Locked(addr, true)) {
+ // Notify the other processors that this StoreExcl succeeded.
+ for (Processor* iter = head_; iter; iter = iter->next_) {
+ if (iter != processor) {
+ iter->NotifyStoreExcl_Locked(addr, false);
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool Simulator::GlobalMonitor::IsProcessorInLinkedList_Locked(
+ Processor* processor) const {
+ return head_ == processor || processor->next_ || processor->prev_;
+}
+
+void Simulator::GlobalMonitor::PrependProcessor_Locked(Processor* processor) {
+ if (IsProcessorInLinkedList_Locked(processor)) {
+ return;
+ }
+
+ if (head_) {
+ head_->prev_ = processor;
+ }
+ processor->prev_ = nullptr;
+ processor->next_ = head_;
+ head_ = processor;
+}
+
+void Simulator::GlobalMonitor::RemoveProcessor(Processor* processor) {
+ base::LockGuard<base::Mutex> lock_guard(&mutex);
+ if (!IsProcessorInLinkedList_Locked(processor)) {
+ return;
+ }
+
+ if (processor->prev_) {
+ processor->prev_->next_ = processor->next_;
+ } else {
+ head_ = processor->next_;
+ }
+ if (processor->next_) {
+ processor->next_->prev_ = processor->prev_;
+ }
+ processor->prev_ = nullptr;
+ processor->next_ = nullptr;
+}
+
} // namespace internal
} // namespace v8
« no previous file with comments | « src/ppc/simulator-ppc.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698