❌

Normale weergave

Apple Seeds Third macOS Golden Gate 27.2 Beta to Developers

5 Oktober 2026 om 20:23
Apple is testing the next macOS Golden Gate update, and developers can download the third ‌macOS Golden Gate‌ 27.2 beta. The third beta comes two weeks after Apple released the second beta.


Registered developers can download ‌macOS Golden Gate‌ 27.2 by opening up the System Settings app, clicking on General, selecting Software Update, and opting into ‌macOS Golden Gate‌ betas.

‌macOS Golden Gate‌ 27.2 introduces Siri AI in new languages and includes new brightness and volume sliders.

We're expecting ‌macOS Golden Gate‌ 27.2 to launch toward the end of October.
Related Roundup: macOS Golden Gate
Related Forum: macOS Golden Gate

This article, "Apple Seeds Third macOS Golden Gate 27.2 Beta to Developers" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Apple Releases Third iOS 27.2 Beta

5 Oktober 2026 om 20:23
Apple today seeded the third beta of an upcoming iOS 27.2 update to developers for testing purposes, with the update coming two weeks after Apple released the second iOS 27.2 beta. Apple also seeded a new iPadOS 27.2 beta.


Registered developers can download the beta updates by opting in under Settings > General > Software Update and selecting the iOS 27 developer beta.

iOS 27.2 includes Apple's redesigned Health app with new Insight and Longevity tabs. It also brings Siri AI in new languages. There are several other new features, with details available in our features guide.

Apple releasing an iOS 27.2 beta ahead of an iOS 27.1 beta was a surprise because the company plans to ship the iPhone Duo with iOS 27.1, but it likely wants to keep some of the iPhone Duo features hidden for longer.

The ‌iPhone Duo‌ will launch on October 23. Apple previously said the new ‌Siri‌ AI languages in iOS 27.2 would be available in October, so it's likely iOS 27.2 will come shortly after the ‌iPhone Duo‌'s release date.
Related Roundups: iOS 27, iPadOS 27
Related Forum: iOS 27

This article, "Apple Releases Third iOS 27.2 Beta" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Apple Releases Third watchOS 27.2, tvOS 27.2 and visionOS 27.2 Betas

5 Oktober 2026 om 20:20
Alongside new betas of iOS 27.2, iPadOS 27.2, and macOS Golden Gate 27.2, Apple has released the third betas of watchOS 27.2, tvOS 27.2, and visionOS 27.2. The betas come two weeks after Apple released the second betas.


Registered developers can download the betas through the Settings app on each device.

With iOS 27.2 and watchOS 27.2, Apple is testing the new Health app that it showed off during its September iPhone event. The updated Health app has new Insights and Longevity tabs with a readiness score that uses information from the new Apple Watch Series 12 and Ultra 4 models.

There's no word on what's being added in visionOS 27.2 and tvOS 27.2, but Apple is expected to introduce a new version of the Apple TV 4K with Siri AI support sometime before the end of the year.
This article, "Apple Releases Third watchOS 27.2, tvOS 27.2 and visionOS 27.2 Betas" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Apple Cash Adds ID Check for Reloads, Teases Bank Funding

5 Oktober 2026 om 20:18
Apple Cash will soon require identity verification to add money. In emails going out to customers, Apple explains that starting on November 9, Green Dot Bank will begin requiring users to verify their identity when reloading their Apple Cash cards.


Identity verification is already required when adding, sending, or receiving over $500 total, but verification for any reload is new. Apple says Green Dot Bank may make it easier to add money to an Apple Cash card by introducing support for transferring funds from a bank or merchant in the future.

Right now, reloading an Apple Cash card can only be done through the Wallet app using a connected debit or prepaid card.

Apple Cash users who have iOS 27 and who live in a state with support for digital driver's licenses can use a license stored in the Wallet app for identity verification.

Customers whose identity can't be verified will not be able to send or receive money or add money to an Apple Cash balance. Money already in an Apple Cash account can still be used for transactions or transferred to a bank account.

Apple says identity verification is required for "fraud protection and regulatory reasons."

Apple Cash is a U.S.-only feature that is available to customers 18 or older, though users under 18 can access Apple Cash through Apple Cash Family.
This article, "Apple Cash Adds ID Check for Reloads, Teases Bank Funding" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Apple Configurator App Updated

5 Oktober 2026 om 19:18
Apple today updated the Apple Configurator app on macOS. The new version 2.21 offers improved reliability for signing in with an Apple Account, plus bug fixes and improvements.

The app is commonly used by IT departments to install apps and profiles on iPhones and iPads for employees.
This article, "Apple Configurator App Updated" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Apple One Just Went Up in Price in These Countries

5 Oktober 2026 om 18:43
Apple has raised the prices of the Apple One Family and Apple One Premier plans in select countries in Europe, with the company notifying affected subscribers via email starting today. The updated prices take effect immediately for new subscribers, while existing subscribers will see the increase applied on their next renewal date.


Apple One Family has gone up in price in the following countries:

  • Belgium

  • Bulgaria

  • Czechia

  • Denmark

  • Hungary

  • Latvia

  • Malta

  • Portugal

  • Slovakia

  • Slovenia

  • Spain

  • Switzerland

Apple One Premier went up in price in three countries only:

  • Portugal

  • Spain

  • Switzerland

In Spain and Portugal, for example, both the Family and Premier plans went up by €2 per month. Increases in other countries and currencies are similar.

Pricing for the Apple One Individual plan has not changed at this time.

Here's what each plan includes:

  • Individual: 50GB of iCloud+ storage, Apple TV, Apple Music, and Apple Arcade

  • Family: 200GB of iCloud+ storage, Apple TV, Apple Music, and Apple Arcade

  • Premier: 2TB of iCloud+ storage, Apple TV, Apple Music, Apple Arcade, Apple Fitness+, and Apple News+

This is at least the third round of Apple One price increases this year, which will benefit Apple's services revenue. Apple One Family and Apple One Premier already went up in price in the U.S., Australia, Canada, the U.K., and select other countries earlier this year, while Apple One Individual went up in U.S., Brazil, Chile, and Mexico.
This article, "Apple One Just Went Up in Price in These Countries" first appeared on MacRumors.com

Discuss this article in our forums

  •  

iPhone 13 Pro vs. iPhone 18 Pro Buyer's Guide: Is It Worth Upgrading?

5 Oktober 2026 om 17:58
Apple released the iPhone 18 Pro and iPhone 18 Pro Max in September 2026, five years after the iPhone 13 Pro and iPhone 13 Pro Max. The 2021 models introduced ProMotion displays, macro photography, a 3x Telephoto camera, and substantially longer battery life than their predecessors. They remain capable phones and support iOS 27, but owners now have five generations of upgrades to consider.


The iPhone 14 Pro brought the Dynamic Island, an Always-On display, a 48-megapixel Main camera, and Emergency SOS via satellite. The iPhone 15 Pro introduced the Action button and USB-C. The iPhone 16 Pro added larger displays, the Camera Control, a 48-megapixel Ultra Wide camera, and expanded video capabilities.

The iPhone 17 Pro adopted an aluminum unibody with vapor chamber cooling and upgraded the Telephoto and front-facing cameras. This year's iPhone 18 Pro adds the A20 Pro chip, a variable-aperture Main camera, a smaller ‌Dynamic Island‌, and further gains in battery life and charging speed. For an iPhone 13 Pro owner, these changes accumulate across nearly every part of the phone.

In the United States, the ‌iPhone 18 Pro‌ starts at $1,199 and the Pro Max at $1,299, each with 256GB of storage. That is $200 more than the corresponding iPhone 13 Pro model's 2021 starting price, although the older phones started with 128GB. Apple no longer sells the iPhone 13 Pro, so anyone buying one now will be looking at a used or refurbished device. Here are the key differences:

Design and Display
































































iPhone 13 Pro (2021) ‌iPhone 18 Pro‌ (2026)
Stainless steel frame Aluminum unibody
Textured matte glass back Ceramic Shield back
Ceramic Shield front Ceramic Shield 2 front
iPhone 13 Pro: 6.1-inch display
iPhone 13 Pro Max: 6.7-inch display
iPhone 18 Pro: 6.3-inch display
iPhone 18 Pro Max: 6.9-inch display
iPhone 13 Pro: 2,532-by-1,170-pixel resolution
iPhone 13 Pro Max: 2,778-by-1,284-pixel resolution
iPhone 18 Pro: 2,622-by-1,206-pixel resolution
iPhone 18 Pro Max: 2,868-by-1,320-pixel resolution
Always-On display
Up to 1,200 nits peak HDR brightness Up to 1,600 nits peak HDR brightness
Up to 3,000 nits peak outdoor brightness
Notch housing the TrueDepth camera Smaller ‌Dynamic Island‌
‌Dynamic Island‌ can show up to three Live Activities at once
Anti-reflective display coating
Ring/Silent switch Customizable Action button
Camera Control
Graphite, Gold, Silver, Sierra Blue, and Alpine Green Black, Silver, Glacier, and Burgundy



Dimensions and Weight





























iPhone 13 Pro (2021) ‌iPhone 18 Pro‌ (2026)
Height Pro: 146.7mm
Pro Max: 160.8mm
Pro: 150.0mm
Pro Max: 163.4mm
Width Pro: 71.5mm
Pro Max: 78.1mm
Pro: 71.9mm
Pro Max: 78.0mm
Thickness 7.65mm 8.75mm
Weight Pro: 204 grams
Pro Max: 240 grams
Pro: 211 grams
Pro Max: 249 grams



Chip, Software, and Connectivity




















































































iPhone 13 Pro (2021) ‌iPhone 18 Pro‌ (2026)
A15 Bionic chip A20 Pro chip
Made with TSMC's 5nm process Made with TSMC's 2nm process
6-core CPU with two performance cores and four efficiency cores 6-core CPU with two super cores and four efficiency cores
5-core GPU 7-core GPU with Neural Accelerators
16-core Neural Engine Dual 16-core Neural Engine
Hardware-accelerated ray tracing
Passive cooling Vapor chamber cooling for improved sustained performance
Apple Intelligence and Siri AI support
Lightning connector USB-C connector
USB 2 transfer speeds up to 480 Mbps USB 3 transfer speeds up to 10Gb/s
Video output up to 1080p using a Lightning adapter DisplayPort video output up to 4K HDR over USB-C
Wi-Fi 6 Wi-Fi 7
Bluetooth 5.0 Bluetooth 6
Thread networking
First-generation Ultra Wideband chip Second-generation Ultra Wideband chip
Emergency SOS via satellite
Messages via satellite
Find My via satellite
Crash Detection



Rear Cameras
















































































































iPhone 13 Pro (2021) ‌iPhone 18 Pro‌ (2026)
12-megapixel Wide camera 48-megapixel Fusion Main camera with a new sensor and computational imaging pipeline
Fixed ƒ/1.5 Main camera aperture Variable Main camera aperture with ƒ/1.48, ƒ/1.8, ƒ/2.8, and ƒ/4.0 settings
Manual aperture control in the Camera app and support for aperture control in third-party apps
Night mode Night mode with faster capture enabled by the variable-aperture Main camera
12-megapixel Ultra Wide camera 48-megapixel Fusion Ultra Wide camera
ƒ/1.8 Ultra Wide aperture ƒ/2.2 Ultra Wide aperture
12-megapixel Telephoto camera 48-megapixel Fusion Telephoto camera
3x Telephoto camera with 77mm focal length 4x Telephoto camera with 100mm focal length
12-megapixel optical-quality 2x photos derived from the Main camera
12-megapixel optical-quality 8x photos derived from the Telephoto camera
6x optical zoom range 16x optical-quality zoom range
Digital zoom up to 15x Digital zoom up to 40x
Sensor-shift optical image stabilization on the Wide camera Second-generation sensor-shift optical image stabilization on the Main camera
Optical image stabilization on the Telephoto camera 3D sensor-shift optical image stabilization on the Telephoto camera
12-megapixel photos from all three rear cameras 24- and 48-megapixel super-high-resolution photos from all three rear cameras
Fixed default Main camera view Customizable default lens for the Fusion Main camera
Macro photography 48-megapixel macro photography
Photonic Engine
Smart HDR 4 Smart HDR 5
Portrait mode with Depth Control Next-generation portraits with Focus and Depth Control
Photographic Styles Photographic Styles 3, with additional tone, color, texture, and grain controls
Pro controls for shutter speed, white balance, and a live histogram
Smart focus tracking
Spatial photo capture
Apple Reference Image capture using the Main camera
True Tone flash with Slow Sync Adaptive True Tone flash



Camera Control


The ‌iPhone 18 Pro‌ adds a dedicated Camera Control that the iPhone 13 Pro lacks. It can be used to:


  • Open the Camera app, take a photo, or press and hold to record video

  • Lock focus and exposure with a light press and hold before reframing

  • Slide to adjust exposure, depth, zoom, camera selection, Photographic Styles, and tone

  • Open Visual Intelligence by pressing and holding, where the feature is available



Front Camera




































iPhone 13 Pro (2021) ‌iPhone 18 Pro‌ (2026)
12-megapixel TrueDepth camera 18-megapixel Center Stage camera with TrueDepth technology
ƒ/2.2 aperture ƒ/1.9 aperture
Autofocus
Center Stage
Portrait and landscape framing without rotating the iPhone
Smart HDR 4 Smart HDR 5
Photographic Styles Photographic Styles 3



Video Recording




















































iPhone 13 Pro (2021) ‌iPhone 18 Pro‌ (2026)
Rear-camera 4K Dolby Vision recording up to 60 fps Rear-camera 4K Dolby Vision recording up to 120 fps
Rear-camera Cinematic mode up to 1080p at 30 fps Rear-camera Cinematic mode up to 4K Dolby Vision at 60 fps
Front-camera Cinematic mode up to 1080p at 30 fps Front-camera Cinematic mode up to 4K Dolby Vision at 30 fps
ProRes recording up to 4K at 30 fps, or 1080p at 30 fps on the 128GB model ProRes recording up to 4K at 120 fps with external storage
Video recording directly to external storage over USB-C
Action mode up to 2.8K Dolby Vision at 60 fps
Spatial video recording at 1080p and 30 fps
Dual Capture using the front and rear cameras simultaneously
ProRes RAW support
Apple Log 2 support
Genlock support



Audio Recording
























iPhone 13 Pro (2021) ‌iPhone 18 Pro‌ (2026)
Stereo recording Spatial Audio and stereo recording
Four studio-quality microphones
Wind noise reduction
Audio Mix



Battery and Charging








































iPhone 13 Pro (2021) ‌iPhone 18 Pro‌ (2026)
iPhone 13 Pro: Up to 22 hours of video playback iPhone 18 Pro: Up to 36 hours of video playback
iPhone 13 Pro Max: Up to 28 hours of video playback iPhone 18 Pro Max: Up to 45 hours of video playback
iPhone 13 Pro: Up to 20 hours of streamed video playback iPhone 18 Pro: Up to 33 hours of streamed video playback
iPhone 13 Pro Max: Up to 25 hours of streamed video playback iPhone 18 Pro Max: Up to 40 hours of streamed video playback
Up to 50% charge in around 30 minutes with a 20W adapter or higher Up to 50% charge in around 15 minutes with a compatible 60W adapter or higher
MagSafe wireless charging up to 15W ‌MagSafe‌ wireless charging up to 25W
Qi wireless charging up to 7.5W Qi2 wireless charging up to 25W
Up to 50% charge in around 30 minutes using ‌MagSafe‌ with a compatible 35W adapter or higher



Storage and Pricing
























iPhone 13 Pro (2021) ‌iPhone 18 Pro‌ (2026)
128GB, 256GB, 512GB, or 1TB 256GB, 512GB, 1TB, or 2TB
iPhone 13 Pro: Launched at $999 in the U.S. with 128GB iPhone 18 Pro: Starts at $1,199 in the U.S. with 256GB
iPhone 13 Pro Max: Launched at $1,099 in the U.S. with 128GB iPhone 18 Pro Max: Starts at $1,299 in the U.S. with 256GB
Now discontinued Sold directly by Apple



Is It Worth Upgrading From an iPhone 13 Pro?


For most iPhone 13 Pro and iPhone 13 Pro Max owners ready to replace their phone, the ‌iPhone 18 Pro‌ is a very worthwhile upgrade. Five years of changes bring noticeable improvements to battery life, charging, outdoor display visibility, photography, and connectivity. The iPhone 13 Pro already has ProMotion and a capable three-camera system, but those strengths do not erase the breadth of the newer model's improvements.

Battery life may be the most immediate benefit, especially for an iPhone 13 Pro whose original battery has aged. Faster wired charging and USB-C also make the newer phone easier to live with, particularly if your other devices already use USB-C.

The camera upgrade is substantial across the whole system. All three rear cameras move from 12 to 48 megapixels, while the variable-aperture Main camera adds creative control and the Telephoto camera extends from 3x to 4x, with an additional optical-quality 8x option. The higher-resolution front camera, autofocus, and Center Stage are useful for group photos and video calls. Video creators gain considerably more through higher frame rates, improved Cinematic mode, external recording, and professional formats.

The A20 Pro and vapor chamber make the strongest performance case for demanding games, long recording sessions, and other sustained work. The ‌iPhone 18 Pro‌ also supports ‌Apple Intelligence‌, while the iPhone 13 Pro does not, even though both run ‌iOS 27‌.

The main physical trade-offs are size and weight: both ‌iPhone 18 Pro‌ models are taller, thicker, and slightly heavier. Some users may find the ‌iPhone 18 Pro‌'s aluminum chassis to be more vulnerable to dents and damage, even though the front and rear glass is stronger. U.S. buyers who rely on a physical SIM must also move to eSIM.

If you need to delay a new purchase, replacing an iPhone 13 Pro's battery can extend its usefulness. For owners prepared to buy now, however, the accumulated improvements make upgrading easy to justify.
Related Roundup: iPhone 18 Pro
Related Forum: iPhone

This article, "iPhone 13 Pro vs. iPhone 18 Pro Buyer's Guide: Is It Worth Upgrading?" first appeared on MacRumors.com

Discuss this article in our forums

  •  

iPad Could Get Significantly Thinner Bezels, Leaker Says

5 Oktober 2026 om 17:39
The iPad is set to gain significantly narrower borders around its display, according to the leaker known as "Instant Digital" on Weibo. The post gives no model or timeline; it could refer to the entry-level ‌iPad‌ or to Apple's tablet lineup in general.

Refreshes of the entry-level ‌iPad‌, iPad mini, iPad Air, and iPad Pro are in the pipeline. The next iPad mini is already rumored to gain OLED and slimmer bezels, while the iPad Air is expected to adopt ‌OLED‌ in 2027.
Related Roundups: iPad, iPad Air , iPad Pro, iPad mini
Related Forum: iPad

This article, "iPad Could Get Significantly Thinner Bezels, Leaker Says" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Prime Day Is Not Just Amazon: See the Biggest Competing Deals From Sony, Best Buy, and Walmart

5 Oktober 2026 om 17:21
Amazon Prime Big Deal Days is nearly live, and as usual multiple retailers have introduced their own Prime Day-like sales to compete with Amazon. In this article we're tracking a few sitewide sales from Sony, Walmart, and Best Buy with big discounts on monitors, TVs, headphones, and more.

Best Buy


Note: MacRumors is an affiliate partner with some of these vendors. When you click a link and make a purchase, we may receive a small payment, which helps us keep the site running.

Best Buy recently kicked off a "Techtober" sale, with sitewide sales on everything from home appliances to computers, video games, and more.



One of the best items to buy during Prime Day is always a new TV, and this year the savings are steep on sets from Samsung, Insignia, LG, and more. Best Buy has as much as $1,400 off select TVs during its Techtober event, and we've rounded up a few highlights below.



Walmart




Walmart's Prime Day-like event began today and is set to run through October 11. It's got a lot of the same offers at Best Buy, with solid deals on TVs, computers, and home appliances.



In terms of Apple-related discounts, Walmart has the AirPods 4 at $79.00, down from $129.99, which is just $10 away from the all-time low price. It's been months since we last tracked a deal this steep on the AirPods 4, and this is the model without ANC.

Sony




Sony is hosting a big fall sale with up to 50 percent in savings on the company's best headphones, speakers, sound bars, TVs, photography equipment, and more.



We've collected a few of the most notable products on sale in the lists below, but be sure to head to Sony's website for the full list of deals. Most devices have an option for free pickup if you live near a Best Buy location that offers local pickup.

You can get Sony's WH-1000XM5 Premium Wireless Noise Canceling Headphones for $199.99 during this event, down from $399.99. There are also a few earbuds and soundbars on sale with notable discounts, all of which have been applied automatically and do not require any coupon codes.

Audio



TVs




If you're on the hunt for more discounts, be sure to visit our Apple Deals roundup where we recap the best Apple-related bargains of the past week.




Deals Newsletter


Interested in hearing more about the best deals you can find in 2026? Sign up for our Deals Newsletter and we'll keep you updated so you don't miss the biggest deals of the season!




Related Roundup: Apple Deals

This article, "Prime Day Is Not Just Amazon: See the Biggest Competing Deals From Sony, Best Buy, and Walmart" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Steinar H. Gunderson: Decompilation patterns part 2: do-while

5 Oktober 2026 om 17:00

Continuing our journey on decompilation patterns, here's another common one: Let's say m2c outputs code like this:

loop_151:
  ...
  if (var_s0 > var_s1) goto loop_151;

then the natural change is:

do {
  ...
} while (var_s0 > var_s1);

Fewer gotos are nearly always good, and this is a much more likely pattern than the original one.

m2c often manages to convert gotos to do/while, but not always when they are e.g. nested in some other loop; so often, you may need to apply some other transformation before you get to this point.

Tomorrow, we'll look at another variation over this topic.

  •  

Apple Watch Prime Day Deals Arrive With New All-Time Low Prices for Series 12 and Ultra 4

5 Oktober 2026 om 15:59
Big Apple Watch discounts have started arriving ahead of Prime Big Deal Days, including new low prices on Apple Watch Series 12 and Apple Watch Ultra 4. These deals join some Apple Watch SE 3 discounts that we began tracking over the weekend, alongside other major early Prime Big Deal Days markdowns.

Note: MacRumors is an affiliate partner with Amazon. When you click a link and make a purchase, we may receive a small payment, which helps us keep the site running.

Starting with the Apple Watch Series 12, you can get the 42mm GPS model for $349.99 and the 46mm GPS model for $399.99, both of which are $49 discounts and new all-time low prices. Both of these models have two colors available at these all-time low prices, and you'll find a few cellular options on sale as well.




For the Apple Watch Ultra 4, you can get the Natural model with the Translucent Gray Ocean Band for $699.99, down from $799.00. This is another new all-time low price for Prime Day, and as of writing it's the only color we're tracking at this price. Additionally, there are a few Milanese Loop models on sale for $99 off ahead of Prime Day.




If you're on the hunt for more discounts, be sure to visit our Apple Deals roundup where we recap the best Apple-related bargains of the past week.




Deals Newsletter


Interested in hearing more about the best deals you can find in 2026? Sign up for our Deals Newsletter and we'll keep you updated so you don't miss the biggest deals of the season!




Related Roundup: Apple Deals

This article, "Apple Watch Prime Day Deals Arrive With New All-Time Low Prices for Series 12 and Ultra 4" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Apple's Newest Macs Just Got Their Biggest Price Cuts Yet on Amazon

5 Oktober 2026 om 16:56
Prime Big Deal Days sales are already starting, and have now hit Apple's brand new Mac mini and Mac Studio computers. You can get up to $199 off these 2026 devices with Amazon's latest savings.

Note: MacRumors is an affiliate partner with some of these vendors. When you click a link and make a purchase, we may receive a small payment, which helps us keep the site running.

One of the best deals is on the M5 Max Mac Studio with 36GB RAM and a 512GB SSD, on sale for $2,299.99, down from $2,499.00. Regarding the Mac mini, you can get the 16GB RAM/256GB SSD Mac mini for $779.99, down from $899.00, and the 24GB RAM/512GB SSD model for $1,549.99, down from $1,699.00.





For more of the best early Prime Big Deal Days discounts, be sure to check out our main article with sales on Apple Watch, AirPods, and more. If you're on the hunt for more discounts, be sure to visit our Apple Deals roundup where we recap the best Apple-related bargains of the past week.




Deals Newsletter


Interested in hearing more about the best deals you can find in 2026? Sign up for our Deals Newsletter and we'll keep you updated so you don't miss the biggest deals of the season!




Related Roundup: Apple Deals

This article, "Apple's Newest Macs Just Got Their Biggest Price Cuts Yet on Amazon" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Apple Releases MagSafe 3 Charging Cable Firmware Update

5 Oktober 2026 om 15:13
For the first time since February 2023, Apple has released a firmware update for the MagSafe 3 charging cable for the MacBook Pro and MacBook Air.


Specifically, Apple last week released firmware version 3.2.0 for the USB-C to MagSafe 3 Cable. The previous firmware version for the cable was 3.1.12.

It is unclear what is included in the latest firmware, as Apple does not publish release notes for this. The update will be installed automatically over time when the cable is connected to a Mac and a power adapter. There is no way to manually apply it.

Apple does not expose the MagSafe cable's firmware version in macOS's System Information tool.
This article, "Apple Releases MagSafe 3 Charging Cable Firmware Update" first appeared on MacRumors.com

Discuss this article in our forums

  •  

AirPods Max 2 Drop to $429 in All Colors for Prime Day

5 Oktober 2026 om 14:40
Amazon today has every AirPods Max 2 color on sale for $429.00, down from $549.00, marking one of the best early Prime Day deals yet. This is one of the lowest prices we've ever seen on the AirPods Max 2, and the sale is available in Blue, Midnight, Orange, Purple, and Starlight colors.

Note: MacRumors is an affiliate partner with Amazon. When you click a link and make a purchase, we may receive a small payment, which helps us keep the site running.

AirPods discounts have started to arrive early ahead of Prime Big Deal Days official kickoff tomorrow, and you can also get the AirPods Pro 3 for the all-time low price of $179.00 right now, down from $249.00.



We've been tracking all of the best early Prime Day discounts, also including great deals on MacBook Air, Apple Watch, and more. If you're on the hunt for more discounts, be sure to visit our Apple Deals roundup where we recap the best Apple-related bargains of the past week.




Deals Newsletter


Interested in hearing more about the best deals you can find in 2026? Sign up for our Deals Newsletter and we'll keep you updated so you don't miss the biggest deals of the season!




Related Roundup: Apple Deals

This article, "AirPods Max 2 Drop to $429 in All Colors for Prime Day" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Apple Quietly Triples iCloud Mail Alias Limit to Nine

5 Oktober 2026 om 14:15
Apple appears to have quietly tripled the number of iCloud Mail aliases users can create, increasing the limit from three to nine. The increase was first noticed last week by a Reddit user, and picked up shortly after by a member of the MacRumors forums. MacRumors can confirm the change is live at iCloud.com.

The increased limit has not been mentioned by Apple, so it could conceivably be a test, but that seems unlikely. It's a nice perk to have, but as of this writing, Apple's iCloud User Guide still says the maximum number of aliases allowed is three.
Tag: iCloud

This article, "Apple Quietly Triples iCloud Mail Alias Limit to Nine" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Mac Users Reclaim 12GB+ of Storage With Apple Intelligence Removal Tool

5 Oktober 2026 om 13:12
A new open-source tool is making waves in the Mac community by helping users reclaim valuable storage space taken up by Apple's AI models. Called "RemoveMacAI," the command line tool disables Apple Intelligence on macOS 27, removes its downloaded models, and prevents them from being downloaded again.


In macOS 27, Apple removed the toggle to disable Apple Intelligence wholesale, and simply disabling individual features doesn't remove the models from your Mac's drive. As explained by the developer, RemoveMacAI gets around this by using a configuration profile to switch off Apple's own asset management service and remove the models.

It then configures the system so attempts to download the removed models are redirected to a closed local port, preventing them from immediately coming back. And it does all this without disabling System Integrity Protection (SIP) or manually deleting files from protected system locations, unlike some older tools have.

The tool can free up roughly 12GB of space depending on which models are present on your Mac. That said, some users are reporting cases of Apple Intelligence models having taken up a lot more space, which they've now reclaimed.

With the Apple models gone, you lose all Siri-related AI features, Writing Tools, Genmoji, Image Playground, ChatGPT integration, summaries, smart replies, inline predictions, Photos Clean Up, Spatial Photos, and Xcode predictive completion. Even so, plenty of users appear happy to make the sacrifice to free up space, especially on non-upgradeable Macs with 256GB of storage. The profile reportedly persists across updates. And if you're wondering, dictation still works. There's also a revert command to restore everything AI-related.

The project has attracted hundreds of GitHub stars since its release last week, and there's lots of discussion on Reddit and Hacker News about the need for such a tool. Just be aware that MacRumors isn't endorsing RemoveMacAI, and anyone using it does so at their own risk.

The developer has mentioned one caveat, and it's that some of the configuration-profile restriction keys that the tool relies on were deprecated by Apple in macOS 26.4. While they still work in macOS 27.0.1, a future version could always change that. Something to keep in mind.
This article, "Mac Users Reclaim 12GB+ of Storage With Apple Intelligence Removal Tool" first appeared on MacRumors.com

Discuss this article in our forums

  •  

iPhone Duo Makes Focus Modes Easier to Toggle From the Lock Screen

5 Oktober 2026 om 12:18
Code explorer pdfu has shared a new feature tidbit for the upcoming iPhone Duo. Apple is reportedly introducing new Focus mode controls on the device's Lock Screen.

focus mode
When a Focus mode is active, a new button appears above the bottom controls that lets you toggle it off and on while you remain on the Lock Screen. The active Focus also appears in the status bar above the clock when you unlock the device.

Apple has rebuilt iOS 27 to adapt in real time to the company's first foldable iPhone, reshaping the interface as the device folds, unfolds, and switches between its two displays.

New on iPhone Duo: redesigned Focus controls on the Lock Screen.

When a Focus mode is active, a button above the bottom controls lets you turn Focus off and back on until you leave the Lock Screen.

Your active Focus also appears in the status bar above the clock. https://t.co/Z0vFRLRAAR

— pdfu (@itspdfu) October 4, 2026



Pre-orders for ‌iPhone Duo‌ open at 5 a.m. Pacific Time on Friday, October 16, with availability beginning Friday, October 23.
Related Roundup: iPhone Duo
Tag: pdfu
Related Forum: iPhone

This article, "iPhone Duo Makes Focus Modes Easier to Toggle From the Lock Screen" first appeared on MacRumors.com

Discuss this article in our forums

  •  

EU iPhone and iPad Users Could Still Face Months-Long Wait for Siri AI

5 Oktober 2026 om 11:51
Apple's upgraded Siri AI could remain unavailable in the European Union for several months yet, according to Bloomberg's Mark Gurman. In his latest Power On newsletter, Gurman said a delay of around five months would be the "absolute best-case scenario," with European users potentially facing an even longer wait while Apple negotiates its compliance with the bloc's digital rules.

Gurman reckons Apple is withholding the upgrade to pressure the European Commission, hoping that frustrated customers will push for changes to its approach, and he compared the situation with Apple Intelligence's delayed EU rollout. Note that Siri AI is not available in the EU on iPhone or iPad, but EU users have access to it on Mac. ‌
This article, "EU iPhone and iPad Users Could Still Face Months-Long Wait for Siri AI" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Today Marks the 15th Anniversary of Steve Jobs' Death

5 Oktober 2026 om 11:12
15 years ago today, Steve Jobs passed away from pancreatic cancer at the age of 56. It was the day after Apple executives introduced the iPhone 4s at a media event on the company's Infinite Loop headquarters campus.

Image Credit: Matt Yohe / CC BY 2.0

In the days following his passing, Apple began posting comments from fans on its "Remembering Steve" webpage. Apple continues to maintain the page, highlighting some of the over one million submissions from people around the world who "shared their memories, thoughts, and feelings about Steve."

The company marked the first anniversary of his passing with a photo and audio slideshow on its website, and we are expecting something similar this anniversary. Throughout his tenure as Apple CEO, Tim Cook traditionally shared words of remembrance on social media and with Apple staff on this day. In his new role as executive chairman, he is continuing that tradition.

There are people who leave a mark on the world, and then there are people who change it entirely. Steve changed the world and so many lives in the process. He certainly changed my life forever. His spirit lives on in everything he created and everyone he inspired. https://t.co/8p08BcSlTS

— Tim Cook (@tim_cook) October 5, 2026


This year we have also seen a tribute from the new chief executive, John Ternus.

The way Steve taught us to care about every detail, every experience, every person, still guides our work today. Forever grateful.

— John Ternus (@johnternus) October 5, 2026


This article, "Today Marks the 15th Anniversary of Steve Jobs' Death" first appeared on MacRumors.com

Discuss this article in our forums

  •  

iPhone 18 Pro's Triple Live Activity Support Comes With a Catch

5 Oktober 2026 om 10:25
On iPhone 18 Pro models, Apple slimmed down the cutout where the Dynamic Island lives, allowing the latter to support up to three simultaneous Live Activities. But it turns out there's a catch.

As noted by code explorer pdfu, the third Live Activity in iOS 27 is only ever a system activity, such as Now Playing or navigation – it can't be another app. So if you own a new iPhone 18 Pro and were wondering why you hadn't seen as many Live Activities in the Dynamic Island as perhaps you were expecting, that's why.
Related Roundup: iPhone 18 Pro
Related Forum: iPhone

This article, "iPhone 18 Pro's Triple Live Activity Support Comes With a Catch" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Maytham Alsudany: A Brief Explanation of DNS and Nameservers

28 September 2026 om 02:00

The Domain Name System (DNS) is a fundamental piece of technology behind the modern internet. Thanks to its introduction in 1983, you're able to enter domain names like aezign.com.au instead of raw IP addresses in your browser's address bar and when sending emails. This article explains what it is, how it works, and how you can inspect your own website's DNS and ensure it is set up correctly.

DNS in a nutshell

A well-used analogy is a phonebook; when you have someone's name and need to find their phone number, you look through the phonebook. Overall, DNS does the same thing: when you enter an address like example.com, your browser will contact a DNS server (the "phonebook") to determine its IP addresses. On Linux (or MacOS) systems, you can use dig on the command line to perform a DNS lookup and see what this looks like:

$ dig example.com

; <<>> DiG 9.20.29-1-Debian <<>> example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 42782
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;example.com.                   IN      A

;; ANSWER SECTION:
example.com.            221     IN      A       104.20.23.154
example.com.            221     IN      A       172.66.147.243

;; Query time: 20 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
;; WHEN: Sun Sep 27 21:07:50 AWST 2026
;; MSG SIZE  rcvd: 72

Here, you can see the DNS server being used is 1.1.1.1 (Cloudflare's DNS server), and that it found the IPs 104.20.23.154 and 172.66.147.243 associated with the domain name example.com. Your browser will then contact these IP addresses directly to load the website you are trying to open.

Configuring DNS servers

You can configure DNS servers through your operating system's network settings, and for some applications such as Firefox, with the application itself. If you don't manually set a DNS server, your computer will use the ones provided by your modem. If those are not configured, the default defined by the modem manufacturer or your ISP will be used.

The most well-used and reliable DNS servers you can use are Cloudflare's (1.1.1.1 and 1.0.0.1) and Google's (8.8.8.8 and 8.8.4.4). Having more than one DNS server means that if the first one in the list doesn't work or doesn't find the matching IPs for a domain name, it will move to the next one in the list, a backup DNS server.

DNS servers must be configured as IP addresses. If your computer tried to use a DNS server at a domain name, then where would your computer find the IP address for that domain name? It wouldn't be able to, as this is the exact gap that DNS servers fulfill.

Records

DNS is not used only to find IPs for a domain, but a whole host of other things. Collectively they are referred to as "records" (or "DNS records"). Each record is associated to a domain (e.g. example.com) or a subdomain (e.g. bar.example.com, foo.bar.example.com) Here are some of the most common and important types:

  • A - Map to an IPv4 address (e.g. 104.20.23.154).

    This is the fundamental function of DNS: to map from a domain name to a server's IP address. Multiple A records leads to load balancing, where browsers will randomly select one of the returned IP addresses such that traffic is evenly split between them.

  • AAAA - Map to an IPv6 address (e.g. 2606:4700:10::6814:179a).

    This serves the same purpose as A records but for IPv6. Multiple AAAA records results in the same load balancing behaviour. All modern websites should have both an A record for legacy compatibility, and an AAAA record to future-proof for the gradual shift towards IPv6 addresses.

  • CNAME - Alias to another domain name (e.g. example.com).

    DNS servers will recursively lookup records for the aliased domain name until they reach an IP address (in an A or AAAA record).

  • MX - Specify a Mail Exchange server (e.g. mail.example.com).

    This record tells email SMTP servers where to direct emails to. For instance, the MX record for aezign.com.au is mail.aezign.au; this directs SMTP servers like Gmail and Outlook to send emails to the mailserver running at mail.aezign.au. This also allows specifying a priority field, so that you can define multiple MX records (such as a main and a backup) and consumers will try to connect to the listed mailservers from lowest priority to highest.

  • TXT - Store arbitrary text data

    This is most commonly used for site verification (for instance, to link your website to Google Search Console) and for email security measures like DKIM, DMARC, and SPF.

  • NS - Specify the nameservers for a domain (e.g. zeus.ns.cloudflare.com).

    These authoritative nameservers are responsible for providing all the other record types when needed.

dig lets you query each of these. For instance, to list the MX records against aezign.com.au:

$ dig MX aezign.com.au

; <<>> DiG 9.20.29-1-Debian <<>> MX aezign.com.au
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28213
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;aezign.com.au.                 IN      MX

;; ANSWER SECTION:
aezign.com.au.          300     IN      MX      10 mail.aezign.au.

;; Query time: 104 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
;; WHEN: Sun Sep 27 22:04:58 AWST 2026
;; MSG SIZE  rcvd: 70

Here you can see there is only one mailserver configured for aezign.com.au, which is mail.aezign.au, and it has a priority of 10.

If you compare this against something like gmail.com:

$ dig MX gmail.com

; <<>> DiG 9.20.29-1-Debian <<>> MX gmail.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16538
;; flags: qr rd ra; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;gmail.com.                     IN      MX

;; ANSWER SECTION:
gmail.com.              2497    IN      MX      40 alt4.gmail-smtp-in.l.google.com.
gmail.com.              2497    IN      MX      20 alt2.gmail-smtp-in.l.google.com.
gmail.com.              2497    IN      MX      5 gmail-smtp-in.l.google.com.
gmail.com.              2497    IN      MX      10 alt1.gmail-smtp-in.l.google.com.
gmail.com.              2497    IN      MX      30 alt3.gmail-smtp-in.l.google.com.

;; Query time: 120 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
;; WHEN: Sun Sep 27 22:06:04 AWST 2026
;; MSG SIZE  rcvd: 161

You can see that gmail.com has several mailservers configured as redundancies due to the Gmail's sheer scale. gmail-smtp-in.l.google.com has the highest priority of 5, so SMTP servers will attempt to contact that mailserver first, followed by alt1.gmail-smtp-in.l.google.com and so on.

Nameservers

Now there needs to be somewhere for DNS records against a domain name to be defined, right? This is where nameservers come in.

Nameservers are DNS servers that answer queries about the domains they are authoritative for i.e. the domains they are in charge of. For example, the authoritative nameservers for example.com are hera.ns.cloudflare.com and elliott.ns.cloudflare.com, which means Cloudflare's nameservers are the source of truth when looking up DNS records for example.com. You can check this with dig:

$ dig NS example.com

; <<>> DiG 9.20.29-1-Debian <<>> NS example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37717
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;example.com.                   IN      NS

;; ANSWER SECTION:
example.com.            81837   IN      NS      hera.ns.cloudflare.com.
example.com.            81837   IN      NS      elliott.ns.cloudflare.com.

;; Query time: 140 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
;; WHEN: Sun Sep 27 23:27:19 AWST 2026
;; MSG SIZE  rcvd: 95

Nameservers are configured with your domain name's registrar. The nameserver you set dictates where your remaining DNS records will live. For example.com, this means you would configure all your records on Cloudflare's dashboard, since they are responsible for the domain's DNS records.

Recursive resolution

The DNS servers that our computers use follow a recursive resolution process behind-the-scenes to find the authoritative nameservers for a domain, followed by the records you are querying.

Finding the root nameservers

Due to the recursive nature of the resolution process, there needs to be a starting point: the root (.) nameservers. The resolver uses a fixed list of root nameservers called root hints issued by IANA (named.root), to locate and contact the root nameservers. Resolvers will have this provided to them initially, and can dynamically update it themselves by querying one of the root nameservers for the root NS records to obtain a fresh list. For instance, we can query 198.41.0.4 (a.root-servers.net) to obtain a new list of root nameservers:

$ dig @198.41.0.4 NS .

; <<>> DiG 9.20.29-1-Debian <<>> @198.41.0.4 NS .
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43677
;; flags: qr aa rd; QUERY: 1, ANSWER: 13, AUTHORITY: 0, ADDITIONAL: 27
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;.				IN	NS

;; ANSWER SECTION:
.			518400	IN	NS	l.root-servers.net.
.			518400	IN	NS	j.root-servers.net.
.			518400	IN	NS	f.root-servers.net.
.			518400	IN	NS	h.root-servers.net.
.			518400	IN	NS	d.root-servers.net.
.			518400	IN	NS	b.root-servers.net.
.			518400	IN	NS	k.root-servers.net.
.			518400	IN	NS	i.root-servers.net.
.			518400	IN	NS	m.root-servers.net.
.			518400	IN	NS	e.root-servers.net.
.			518400	IN	NS	g.root-servers.net.
.			518400	IN	NS	c.root-servers.net.
.			518400	IN	NS	a.root-servers.net.

;; ADDITIONAL SECTION:
l.root-servers.net.	518400	IN	A	199.7.83.42
l.root-servers.net.	518400	IN	AAAA	2001:500:9f::42
j.root-servers.net.	518400	IN	A	192.58.128.30
j.root-servers.net.	518400	IN	AAAA	2001:503:c27::2:30
f.root-servers.net.	518400	IN	A	192.5.5.241
f.root-servers.net.	518400	IN	AAAA	2001:500:2f::f
h.root-servers.net.	518400	IN	A	198.97.190.53
h.root-servers.net.	518400	IN	AAAA	2001:500:1::53
d.root-servers.net.	518400	IN	A	199.7.91.13
d.root-servers.net.	518400	IN	AAAA	2001:500:2d::d
b.root-servers.net.	518400	IN	A	170.247.170.2
b.root-servers.net.	518400	IN	AAAA	2801:1b8:10::b
k.root-servers.net.	518400	IN	A	193.0.14.129
k.root-servers.net.	518400	IN	AAAA	2001:7fd::1
i.root-servers.net.	518400	IN	A	192.36.148.17
i.root-servers.net.	518400	IN	AAAA	2001:7fe::53
m.root-servers.net.	518400	IN	A	202.12.27.33
m.root-servers.net.	518400	IN	AAAA	2001:dc3::35
e.root-servers.net.	518400	IN	A	192.203.230.10
e.root-servers.net.	518400	IN	AAAA	2001:500:a8::e
g.root-servers.net.	518400	IN	A	192.112.36.4
g.root-servers.net.	518400	IN	AAAA	2001:500:12::d0d
c.root-servers.net.	518400	IN	A	192.33.4.12
c.root-servers.net.	518400	IN	AAAA	2001:500:2::c
a.root-servers.net.	518400	IN	A	198.41.0.4
a.root-servers.net.	518400	IN	AAAA	2001:503:ba3e::2:30

;; Query time: 476 msec
;; SERVER: 198.41.0.4#53(198.41.0.4) (UDP)
;; WHEN: Mon Sep 28 00:01:08 AWST 2026
;; MSG SIZE  rcvd: 811

Querying the root nameservers

For example.com, the first step is to query the root (.) nameservers to find the nameservers for the .com top-level domain (TLD). Using a.root-servers.net again:

$ dig @198.41.0.4 NS com

; <<>> DiG 9.20.29-1-Debian <<>> @198.41.0.4 NS com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 22528
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 13, ADDITIONAL: 27
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;com.				IN	NS

;; AUTHORITY SECTION:
com.			172800	IN	NS	l.gtld-servers.net.
com.			172800	IN	NS	j.gtld-servers.net.
com.			172800	IN	NS	h.gtld-servers.net.
com.			172800	IN	NS	d.gtld-servers.net.
com.			172800	IN	NS	b.gtld-servers.net.
com.			172800	IN	NS	f.gtld-servers.net.
com.			172800	IN	NS	k.gtld-servers.net.
com.			172800	IN	NS	m.gtld-servers.net.
com.			172800	IN	NS	i.gtld-servers.net.
com.			172800	IN	NS	g.gtld-servers.net.
com.			172800	IN	NS	a.gtld-servers.net.
com.			172800	IN	NS	c.gtld-servers.net.
com.			172800	IN	NS	e.gtld-servers.net.

;; ADDITIONAL SECTION:
l.gtld-servers.net.	172800	IN	A	192.41.162.30
l.gtld-servers.net.	172800	IN	AAAA	2001:500:d937::30
j.gtld-servers.net.	172800	IN	A	192.48.79.30
j.gtld-servers.net.	172800	IN	AAAA	2001:502:7094::30
h.gtld-servers.net.	172800	IN	A	192.54.112.30
h.gtld-servers.net.	172800	IN	AAAA	2001:502:8cc::30
d.gtld-servers.net.	172800	IN	A	192.31.80.30
d.gtld-servers.net.	172800	IN	AAAA	2001:500:856e::30
b.gtld-servers.net.	172800	IN	A	192.33.14.30
b.gtld-servers.net.	172800	IN	AAAA	2001:503:231d::2:30
f.gtld-servers.net.	172800	IN	A	192.35.51.30
f.gtld-servers.net.	172800	IN	AAAA	2001:503:d414::30
k.gtld-servers.net.	172800	IN	A	192.52.178.30
k.gtld-servers.net.	172800	IN	AAAA	2001:503:d2d::30
m.gtld-servers.net.	172800	IN	A	192.55.83.30
m.gtld-servers.net.	172800	IN	AAAA	2001:501:b1f9::30
i.gtld-servers.net.	172800	IN	A	192.43.172.30
i.gtld-servers.net.	172800	IN	AAAA	2001:503:39c1::30
g.gtld-servers.net.	172800	IN	A	192.42.93.30
g.gtld-servers.net.	172800	IN	AAAA	2001:503:eea3::30
a.gtld-servers.net.	172800	IN	A	192.5.6.30
a.gtld-servers.net.	172800	IN	AAAA	2001:503:a83e::2:30
c.gtld-servers.net.	172800	IN	A	192.26.92.30
c.gtld-servers.net.	172800	IN	AAAA	2001:503:83eb::30
e.gtld-servers.net.	172800	IN	A	192.12.94.30
e.gtld-servers.net.	172800	IN	AAAA	2001:502:1ca1::30

;; Query time: 772 msec
;; SERVER: 198.41.0.4#53(198.41.0.4) (UDP)
;; WHEN: Mon Sep 28 00:09:25 AWST 2026
;; MSG SIZE  rcvd: 828

Querying the TLD nameservers

Now the resolver has .com nameservers and their IPs. We can use one of these, such as 192.5.6.30 (a.gtld-servers.net) to find the nameservers for example.com:

$ dig @192.5.6.30 NS example.com

; <<>> DiG 9.20.29-1-Debian <<>> @192.5.6.30 NS example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37419
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 2, ADDITIONAL: 13
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;example.com.                   IN      NS

;; AUTHORITY SECTION:
example.com.            172800  IN      NS      hera.ns.cloudflare.com.
example.com.            172800  IN      NS      elliott.ns.cloudflare.com.

;; ADDITIONAL SECTION:
hera.ns.cloudflare.com. 172800  IN      A       108.162.192.162
hera.ns.cloudflare.com. 172800  IN      A       172.64.32.162
hera.ns.cloudflare.com. 172800  IN      A       173.245.58.162
hera.ns.cloudflare.com. 172800  IN      AAAA    2606:4700:50::adf5:3aa2
hera.ns.cloudflare.com. 172800  IN      AAAA    2803:f800:50::6ca2:c0a2
hera.ns.cloudflare.com. 172800  IN      AAAA    2a06:98c1:50::ac40:20a2
elliott.ns.cloudflare.com. 172800 IN    A       108.162.195.228
elliott.ns.cloudflare.com. 172800 IN    A       162.159.44.228
elliott.ns.cloudflare.com. 172800 IN    A       172.64.35.228
elliott.ns.cloudflare.com. 172800 IN    AAAA    2606:4700:58::a29f:2ce4
elliott.ns.cloudflare.com. 172800 IN    AAAA    2803:f800:50::6ca2:c3e4
elliott.ns.cloudflare.com. 172800 IN    AAAA    2a06:98c1:50::ac40:23e4

;; Query time: 80 msec
;; SERVER: 192.5.6.30#53(192.5.6.30) (UDP)
;; WHEN: Mon Sep 28 00:12:19 AWST 2026
;; MSG SIZE  rcvd: 359

Finding the domain's nameserver

The response tells the resolver that the nameservers for example.com are hera.ns.cloudflare.com and elliott.ns.cloudflare.com. Now since these Cloudflare nameservers are also .com domains and Cloudflare is so commonly used, the .com nameserver provides optional sibling glue records as defined in RFC 9471 to prevent further roundtrips and optimize the process.

If we ignore the sibling glue records provided, the resolver would have to ask the .com nameservers for the nameservers for cloudflare.com:

$ dig @192.5.6.30 NS cloudflare.com

; <<>> DiG 9.20.29-1-Debian <<>> @192.5.6.30 NS cloudflare.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40307
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 5, ADDITIONAL: 21
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;cloudflare.com.                        IN      NS

;; AUTHORITY SECTION:
cloudflare.com.         172800  IN      NS      ns3.cloudflare.com.
cloudflare.com.         172800  IN      NS      ns5.cloudflare.com.
cloudflare.com.         172800  IN      NS      ns4.cloudflare.com.
cloudflare.com.         172800  IN      NS      ns6.cloudflare.com.
cloudflare.com.         172800  IN      NS      ns7.cloudflare.com.

;; ADDITIONAL SECTION:
ns3.cloudflare.com.     172800  IN      A       162.159.0.33
ns3.cloudflare.com.     172800  IN      A       162.159.7.226
ns3.cloudflare.com.     172800  IN      AAAA    2400:cb00:2049:1::a29f:21
ns3.cloudflare.com.     172800  IN      AAAA    2400:cb00:2049:1::a29f:7e2
ns5.cloudflare.com.     172800  IN      A       162.159.2.9
ns5.cloudflare.com.     172800  IN      A       162.159.9.55
ns5.cloudflare.com.     172800  IN      AAAA    2400:cb00:2049:1::a29f:209
ns5.cloudflare.com.     172800  IN      AAAA    2400:cb00:2049:1::a29f:937
ns4.cloudflare.com.     172800  IN      A       162.159.1.33
ns4.cloudflare.com.     172800  IN      A       162.159.8.55
ns4.cloudflare.com.     172800  IN      AAAA    2400:cb00:2049:1::a29f:121
ns4.cloudflare.com.     172800  IN      AAAA    2400:cb00:2049:1::a29f:837
ns6.cloudflare.com.     172800  IN      A       162.159.3.11
ns6.cloudflare.com.     172800  IN      A       162.159.5.6
ns6.cloudflare.com.     172800  IN      AAAA    2400:cb00:2049:1::a29f:30b
ns6.cloudflare.com.     172800  IN      AAAA    2400:cb00:2049:1::a29f:506
ns7.cloudflare.com.     172800  IN      A       162.159.4.8
ns7.cloudflare.com.     172800  IN      A       162.159.6.6
ns7.cloudflare.com.     172800  IN      AAAA    2400:cb00:2049:1::a29f:408
ns7.cloudflare.com.     172800  IN      AAAA    2400:cb00:2049:1::a29f:606

;; Query time: 163 msec
;; SERVER: 192.5.6.30#53(192.5.6.30) (UDP)
;; WHEN: Mon Sep 28 00:26:53 AWST 2026
;; MSG SIZE  rcvd: 573

Here, the .com nameserver provides in-domain glue records for cloudflare.com's nameservers. Without these, there would be a circular dependency, since the nameserver named is a subdomain of the domain being queried for. This is because nameservers are always defined by name, which means that in order to actually contact the nameserver, your computer needs to obtain its IP address with another DNS lookup.

Next, we'd use one of these nameservers, say ns3.cloudflare.com, to obtain the IP for hera.ns.cloudflare.com:

$ dig @162.159.0.33 hera.ns.cloudflare.com

; <<>> DiG 9.20.29-1-Debian <<>> @162.159.0.33 hera.ns.cloudflare.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 16801
;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;hera.ns.cloudflare.com.                IN      A

;; ANSWER SECTION:
hera.ns.cloudflare.com. 86353   IN      A       108.162.192.162
hera.ns.cloudflare.com. 86353   IN      A       173.245.58.162
hera.ns.cloudflare.com. 86353   IN      A       172.64.32.162

;; Query time: 123 msec
;; SERVER: 162.159.0.33#53(162.159.0.33) (UDP)
;; WHEN: Mon Sep 28 01:11:37 AWST 2026
;; MSG SIZE  rcvd: 99

Querying the domain's authoritative nameserver

Now we've reached the authoritative nameserver for example.com! The last thing to do is to fetch the A record for example.com to obtain its server's IP address:

$ dig @108.162.192.162 example.com

; <<>> DiG 9.20.29-1-Debian <<>> @108.162.192.162 example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43082
;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;example.com.                   IN      A

;; ANSWER SECTION:
example.com.            300     IN      A       104.20.23.154
example.com.            300     IN      A       172.66.147.243

;; Query time: 123 msec
;; SERVER: 108.162.192.162#53(108.162.192.162) (UDP)
;; WHEN: Mon Sep 28 01:13:47 AWST 2026
;; MSG SIZE  rcvd: 72

At last, we've determined that the IP addresses of the servers behind example.com are 104.20.23.154 and 172.66.147.243. This matches our earlier lookup directly against your computer's configured DNS server.

The DNS servers your computer uses employ this recursive resolution technique behind the scenes, so that your computer only needs to make one round trip, and the servers can use their much faster data center connections and caching to optimize the process and make the query as fast as possible.

Verify your DNS records

To check your website's records, the first thing you'll want to do is ensure your domain name is pointed at the correct nameserver. For instance, aezign.com.au is supposed to use Cloudflare, since that is where all the DNS records have been set up. We can verify this using dig, (or alternatively with online tools like dnschecker.org):

$ dig NS aezign.com.au

; <<>> DiG 9.20.29-1-Debian <<>> NS aezign.com.au
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 44172
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;aezign.com.au.                 IN      NS

;; ANSWER SECTION:
aezign.com.au.          86400   IN      NS      rosalie.ns.cloudflare.com.
aezign.com.au.          86400   IN      NS      zeus.ns.cloudflare.com.

;; Query time: 92 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
;; WHEN: Mon Sep 28 01:39:22 AWST 2026
;; MSG SIZE  rcvd: 100

If this is not set correctly, the DNS records you configure will not work, as resolvers will be fetching records from somewhere else. In most cases, you can update this in your domain registrar's settings. This is especially common for new domain names, which default to the registrar's nameservers; unless you plan to use their built-in DNS management, you'll need to point them to your chosen provider.

Now we can check that the DNS records you've configured match those your DNS server returns. For aezign.com.au, these are the MX and TXT records configured on Cloudflare.

Extract of Cloudflare's DNS record listing showing the MX record and TXT records for aezign.com.au.

The MX record and some TXT records configured for aezign.com.au on Cloudflare's dashboard.

We can check these using dig, and using the +short option to show only the content of the records.

$ dig MX aezign.com.au +short

10 mail.aezign.au.

$ dig TXT aezign.com.au +short

"google-site-verification=KFqTU5xH8fFf6OtszEL4oudfxple29Tm-TvxVtCWkAM"
"v=spf1 mx a:mail.aezign.au -all"

$ dig TXT _dmarc.aezign.com.au +short

"v=DMARC1;p=quarantine;sp=quarantine;adkim=r;aspf=r"

$ dig TXT aezign.com.au-2026._domainkey.aezign.com.au +short

"v=DKIM1; h=sha256; k=rsa; s=email; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzL04yXZgB72YkoxS+tLK//aWx65TS4UA3F0qJ7el68SEuD4ehmg+61Ta9iS31H6U074dnjyoPDeaiGBa7ToTNCtiIts4/ghD/8nrENROE6hQAwRmTK18ODDHrRDW73hWe6Dg4cK5vmXi82/wWRZU9SDKbme28IE9uCVir3lCkKYLs1" "j16gR1Sjqr6a2+3o+EeVXnLJ4wXmJMm7KCIdn7zv0t9Z1eYcw672PdpYPAMpGb8uUsgaDBsNSpTcupPkz4SWj6TrOB80CPHjWseVY8EOJeRsNKQ/8LFoQEBl4Rxtb3HAmu4UIxSZ4QMVOLnXz67e85mA5XjcNIsVMzaWaowwIDAQAB"

As we can see, this matches, which means that the nameservers for aezign.com.au are correct and the DNS records are what we intend them to be.

Note that if you've recently changed the nameserver or DNS records for your domain, it can take anywhere between 10 seconds and 24 hours for the changes to take effect and propagate across the different DNS servers worldwide. Tools like dnschecker.org can check your records on different DNS servers worldwide to see if they're reflecting your changes. The reason for this is caching: DNS servers like 1.1.1.1 will cache results so it doesn't have to do the full resolution process every time, and uses the Time-To-Live (TTL) you configure in your DNS records as a guideline for caching duration.

  •  

Apple's New CEO John Ternus is Making Product Design a 'Major Priority'

5 Oktober 2026 om 04:35
Since becoming Apple's CEO last month, John Ternus has made product design a "major priority," according to Bloomberg's Mark Gurman.


"Ternus already had some involvement with the design studio as Apple's head of hardware engineering, given the close coordination required between the two functions," he said, in his Power On newsletter today. "Since becoming CEO, however, he has immersed himself in the industrial design and human interface teams."

Ternus goes "hands-on" in Apple's design studio "several times a week, sometimes visiting multiple times in a single day," whereas Apple's former CEO Tim Cook typically visited the studio for "about an hour once a month, at most," according to Gurman.

Unlike Cook, who is better known as a supply chain expert, Ternus comes from an engineering background. As such, Gurman said that Ternus is largely leaving Apple's finances to financial chief Kevan Parekh and its supply chain to operations chief Sabih Khan, giving him more time to focus on engineering and design.

All in all, Apple now has a product person running the show.
This article, "Apple's New CEO John Ternus is Making Product Design a 'Major Priority'" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Apple Hiring 'iCup' Specialist

5 Oktober 2026 om 04:11
Apple recently posted a job listing for an "iCup Supply Specialist" who would be responsible for ensuring that "all Apple employees have access to freshly brewed coffee in their break room."

MacRumors contributor Aaron Perris highlighted the job listing this weekend, but it turns out that Apple has been using the "iCup" name since at least 2014. The individual hired will be required to drive between locations and "sanitize, clean, restock, and manage up to 90 bean-to-cup coffee machines."
This article, "Apple Hiring 'iCup' Specialist" first appeared on MacRumors.com

Discuss this article in our forums

  •  

MacBook Pro With OLED Display Rumored to Be 'Significantly Lighter'

5 Oktober 2026 om 03:22
Bloomberg's Mark Gurman today said the new MacBook Pro models with OLED displays will be "significantly lighter" than the existing MacBook Pro models.


"Apple has reengineered the machine's interior, miniaturizing parts and rearranging components to make the computer much easier to carry," he said, in his Power On newsletter. Currently, the MacBook Pro weighs up to 4.7 pounds, while the MacBook Air weighs up to 3.3 pounds and the MacBook Neo weighs 2.7 pounds.

With this newly-reported detail, the new models are now rumored to have six new features:
  • OLED display

  • Touch-screen capabilities

  • Dynamic Island instead of a notch

  • M5 Pro and M5 Max chips

  • Thinner design

  • "Significantly lighter" design
Thinner and lighter go hand in hand.

Apple plans to release the MacBook Pro models with OLED displays in October or November this year, according to Gurman. In his newsletter, he reiterated that Apple is testing the laptops with macOS 27.2, which is currently in beta.

The OLED models are expected to be higher-end, higher-priced models that sit above the existing MacBook Pro models in Apple's lineup.
Related Roundup: MacBook Pro
Buyer's Guide: MacBook Pro (Caution)
Related Forum: MacBook Pro

This article, "MacBook Pro With OLED Display Rumored to Be 'Significantly Lighter'" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Apple Event Reportedly Planned for October 13

5 Oktober 2026 om 02:07
Last week, Bloomberg's Mark Gurman reported that Apple plans to unveil an all-new smart home hub, a new HomePod mini, and a new Apple TV 4K on Tuesday, October 13.

In his Power On newsletter today, Gurman specified that "Apple is planning to hold an event" that day.
This article, "Apple Event Reportedly Planned for October 13" first appeared on MacRumors.com

Discuss this article in our forums

  •  

DistroWatch Weekly, Issue 1193

5 Oktober 2026 om 02:01
The DistroWatch news feed is brought to you by TUXEDO COMPUTERS. This week in DistroWatch Weekly:
Review: fu11m00n 2.64
News: The Dutch government creates NixOS-based distro, GhostBSD starts work on own desktop, openSUSE discusses month of security fixes
Questions and answers: Breaking Linux to learn Linux?
Released last week: Emmabuntüs DE6-1.03, Kodachi OS 10.0.3, OpenMandriva Lx 26.09 "ROME", Nitrux 7.0.0, umbrelOS 2.0.0,....
  •  

Distribution Release: Besgnulinux 1.0 "Openbox"

4 Oktober 2026 om 21:17
The DistroWatch news feed is brought to you by TUXEDO COMPUTERS. The Besgnulinux team has announced the release of a new edition of its Debian-based Linux distribution - Besgnulinux 1.0 which features the Openbox window manager: "It had been a long time since I last tested Openbox. I initially created this version for testing purposes. However, once it turned....
  •  

Amazon Launches Early Prime Day Discounts on AirPods, iPad, MacBook Air, and More

4 Oktober 2026 om 18:15
Earlier this week, we began tracking early Prime Day deals on Apple-related accessories, and now Amazon has introduced major early deals on Apple products as well. This includes AirPods, iPads, MacBooks, and more, all available at some of the lowest prices of the year so far.

Note: MacRumors is an affiliate partner with Amazon. When you click a link and make a purchase, we may receive a small payment, which helps us keep the site running.

As is typical for Prime Day deals, these markdowns are very time sensitive, so sales listed below may disappear fast, and new ones may appear even faster. With this in mind, we'll keep this article updated throughout the event, and keep an eye on the MacRumors front page as we'll be posting particularly great deals in separate articles this week.



Lastly, and perhaps most importantly, Amazon Prime Day requires you to have an Amazon Prime membership to take advantage of the discounts. Amazon Prime costs $14.99 per month or $139.00 per year, and it comes with a 30-day free trial for new subscribers.

AirPods




The best AirPods discount so far this Prime Day is on the AirPods Pro 3, available for the record low price of $179.00, down from $249.00. We haven't seen a deal this good since over the summer, during the first Prime Day event in June.



MacBook Air




Amazon is taking $200 off nearly every M5 MacBook Air model for Prime Big Deal Days, including both 13-inch and 15-inch models. These are the best prices we've seen on the M5 MacBook Air in the wake of Apple's summertime price hikes.

In terms of 13-inch models, Amazon has the 16GB/512GB 13-inch MacBook Air for $1,099.00, down from $1,299.00. This one is available in three colors on Amazon, and it's accompanied by the 16GB/1TB and 24GB/1TB model for $200 off as well.





For the 15-inch M5 MacBook Air models, prices start with the 16GB/512GB model for $1,299.00, down from $1,499.00. You can also get the 16GB/1TB model for $1,599.00, down from $1,799.00, all $200 off and the best prices we've seen in months.




Apple Watch




Rare deals have hit the Apple Watch SE 3 for Prime Big Deal Days, with prices now starting at $199.00 for the 40mm GPS model and increasing to $229.00 for the 44mm GPS model. Both of these are $50 discounts and matches for the record low prices on each device.




For the Apple Watch Series 12, you can get the 42mm GPS model for $349.99 and the 46mm GPS model for $399.99, both of which are $49 discounts and new all-time low prices. Both of these models have two colors available at these all-time low prices, and you'll find a few cellular options on sale as well.




For the Apple Watch Ultra 4, you can get the Natural model with the Translucent Gray Ocean Band for $699.99, down from $799.00. This is another new all-time low price for Prime Day, and as of writing it's the only color we're tracking at this price. Additionally, there are a few Milanese Loop models on sale for $99 off ahead of Prime Day.



M4 iPad Air




Amazon this week has multiple discounts on the M4 iPad Air, providing up to $149 off these 2026 models. These remain the best prices we've seen in the wake of Apple's summer price hikes, and many deals are being matched at Best Buy.




The new iPad Air features the M4 chip, C1X modem, and N1 networking chip, which brings support for Wi-Fi 7 and Bluetooth 6. In terms of design, the 2026 models are identical to the 2025 iPad Air tablets, with an edge-to-edge display, slim bezels, and aluminum chassis.

11-inch M4 iPad Air



13-inch M4 iPad Air



iPad Mini 7




Amazon has low prices on every Wi-Fi model of the iPad mini 7, starting at $499.00 for the 128GB Wi-Fi tablet, down from $599.00. You'll also find a few deals on cellular models during this early Prime Day sale.





If you're on the hunt for more discounts, be sure to visit our Apple Deals roundup where we recap the best Apple-related bargains of the past week.




Deals Newsletter


Interested in hearing more about the best deals you can find in 2026? Sign up for our Deals Newsletter and we'll keep you updated so you don't miss the biggest deals of the season!




Related Roundup: Apple Deals

This article, "Amazon Launches Early Prime Day Discounts on AirPods, iPad, MacBook Air, and More" first appeared on MacRumors.com

Discuss this article in our forums

  •  

AirPods Pro 3 Hit Record Low $179 Price During Early Prime Day Sale

4 Oktober 2026 om 17:33
Amazon has the AirPods Pro 3 available for $179.00 this week, down from $249.00. This is a match of the all-time low price on the AirPods Pro 3, which we haven't tracked since around June.

Note: MacRumors is an affiliate partner with some of these vendors. When you click a link and make a purchase, we may receive a small payment, which helps us keep the site running.

This model of the AirPods Pro launched in September 2025 and has 2x better Active Noise Cancellation than the previous generation, better audio quality, a revised fit that's meant to improve comfort and stability, Live Translation for in-person conversations, and heart rate sensing for workouts.



Head to our full Deals Roundup to get caught up with all of the latest deals and discounts that we've been tracking over the past week.




Deals Newsletter


Interested in hearing more about the best deals you can find in 2026? Sign up for our Deals Newsletter and we'll keep you updated so you don't miss the biggest deals of the season!




Related Roundup: Apple Deals

This article, "AirPods Pro 3 Hit Record Low $179 Price During Early Prime Day Sale" first appeared on MacRumors.com

Discuss this article in our forums

  •  

Vincent Bernat: Hacking the Go compiler to efficiently map IPv4 to IPv6

4 Oktober 2026 om 16:12

netip.Addr features an Unmap() method returning the unwrapped IPv4 contained in an IPv4-mapped IPv6 address: from ::ffff:203.0.113.10 or ::ffff:cb00:710a, it returns 203.0.113.10.1 There is no Map() or To6() method for the reverse direction. Such a method is trivial to implement, but Go maintainers have rejected it on the grounds that users should write netip.AddrFrom16(ip.As16()) and let the compiler optimize it.2 Today, this pattern is eight times slower than a native method. How can we teach the compiler to optimize this sequence?

The alternatives

Let’s explore three ways to implement the map semantics for netip.Addr. My favorite is to add it to the Go standard library. Go maintainers prefer a small external helper chaining netip.AddrFrom16() and netip.Addr.As16(), hoping the compiler eventually optimizes it. The unsafe package opens a third path, with the same performance as the first solution.

Modifying the Go standard library

Internally, netip.Addr stores any IP address as a 128-bit value with an extra field z to encode the family and the zone:

type Addr struct {
    addr uint128
    z unique.Handle[addrDetail]
}

type addrDetail struct {
    isV6   bool   // IPv4 is false, IPv6 is true.
    zoneV6 string // != "" only if IsV6 is true.
}

var (
    z0    unique.Handle[addrDetail]
    z4    = unique.Make(addrDetail{})
    z6noz = unique.Make(addrDetail{isV6: true})
)

AddrFrom4() encodes an IPv4 address as an IPv4-mapped IPv6 address and sets z to the unique value z4:

// AddrFrom4 returns the address of the IPv4 address given by the bytes in addr.
func AddrFrom4(addr [4]byte) Addr {
    return Addr{
        addr: uint128{
            0,
            0xffff00000000 |
                uint64(addr[0])<<24 | uint64(addr[1])<<16 |
                uint64(addr[2])<<8 | uint64(addr[3])},
        z: z4,
    }
}

Unmap() turns an IPv4-mapped IPv6 address into an IPv4 address by setting the z field to z4:

func (ip Addr) Unmap() Addr {
    if ip.Is4In6() {
        ip.z = z4
    }
    return ip
}

Implementing the reverse direction inside the Go standard library is trivial: we set the z field to z6noz if the address is IPv4.

// To6 maps an IPv4 address to an IPv4-mapped IPv6 address. It returns an
// IPv6 address unmodified.
func (ip Addr) To6() Addr {
    if ip.Is4() {
        ip.z = z6noz
    }
    return ip
}

Update (2026-10)

Instead of patching Go, we can use the -overlay flag of go build to hijack any package, including the standard library. In our case, it can add To6() to net/netip. Yet it is cumbersome:3 the flag expects a JSON file mapping absolute paths in GOROOT to replacement files, and you need to add it to every go command.

As a helper

We can’t access the z field from outside the net/netip package. Instead, we build a small helper around the netip.AddrFrom16(ip.As16()) pattern:

// AddrTo6 maps an IPv4 address to an IPv4-mapped IPv6 address. It returns an
// IPv6 address unmodified.
func AddrTo6(ip netip.Addr) netip.Addr {
    if ip.Is4() {
        ip = netip.AddrFrom16(ip.As16())
    }
    return ip
}

As an unsafe function

Another solution uses the unsafe package to alter the Addr struct through a proxy with the same memory layout:4

// addrProxy has the same memory layout as netip.Addr.
type addrProxy struct {
    addr [2]uint64      // netip.uint128
    z    unsafe.Pointer // unique.Handle[netip.addrDetail]
}

var (
    anyIPv6    = netip.IPv6Unspecified()
    netipZ6noz = (*addrProxy)(unsafe.Pointer(&anyIPv6)).z
)

// AddrTo6 maps an IPv4 address to an IPv4-mapped IPv6 address. It returns an
// IPv6 address unmodified.
func AddrTo6(ip netip.Addr) netip.Addr {
    if !ip.Is4() {
        return ip
    }
    (*addrProxy)(unsafe.Pointer(&ip)).z = netipZ6noz
    return ip
}

Benchmarks

On my computer, with Go 1.27.1, the standard library solution costs 0.88 ns per operation, while the solution favored by Go maintainers costs 7.14 ns. The unsafe solution matches the performance of the first one.

goos: linux
goarch: amd64
pkg: github.com/vincentbernat/go-netip-addrto6
cpu: AMD Ryzen 5 5600X 6-Core Processor
                   │     sec/op     │
AddrTo6/safe            7.137n ± 0%
AddrTo6/unsafe         0.8682n ± 2%
AddrTo6/builtin        0.8775n ± 2%

Assembly code

Let’s check the assembly code the compiler generates for each solution.5 The one built into the standard library looks like this:6

// AX = input.addr.hi, BX = input.addr.lo, CX = input.z
 CMPQ  net/netip·z4(SB), CX     ; check "z" if this is an IPv4 address
 JNE   end                      ; if not, stop here
 MOVQ  net/netip·z6noz(SB), CX  ; CX = netip.z6noz
end:
 RET
// return value = Addr{hi: AX, lo: BX, z: CX}

Go’s assembly language is not a direct representation of the underlying machine language: it operates on a semi-abstract instruction set derived from Plan 9’s assembler. It has four pseudo-registers: FP (frame pointer for function arguments), PC (program counter), SB (static base pointer for global symbols), and SP (stack pointer). It also has architecture-specific registers like AX, CX, DX, BX, SI, DI, and R8 to R15. Instructions storing data use their last argument as the destination. Instructions can carry an explicit size suffix: MOVB moves a byte, MOVW 16 bits, MOVL 32 bits, and MOVQ 64 bits. In the example above, the first instruction compares the 64-bit value z4 with the CX register.

The unsafe solution looks almost the same:

// AX = input.addr.hi, BX = input.addr.lo, CX = input.z
 CMPQ  net/netip·z4(SB), CX  ; check "z" if this is an IPv4 address
 JNE   end                   ; if not, stop here
 MOVQ  netipZ6noz(SB), CX    ; CX = netip.z6noz
end:
 RET
// return value = Addr{hi: AX, lo: BX, z: CX}

The helper solution has far more instructions. To understand why, let’s look at the code for As16() and AddrFrom16(). They are short enough for the compiler to inline them.

func (ip Addr) As16() (a16 [16]byte) {
    byteorder.BEPutUint64(a16[:8], ip.addr.hi)
    byteorder.BEPutUint64(a16[8:], ip.addr.lo)
    return a16
}

func AddrFrom16(addr [16]byte) Addr {
    return Addr{
        addr: uint128{
            byteorder.BEUint64(addr[:8]),
            byteorder.BEUint64(addr[8:]),
        },
        z: z6noz,
    }
}

We can already guess the pattern to optimize: the code packs the IP address into an array, copies it, then unpacks it. If we inline the Go code by hand, we get:

func AddrTo6(input netip.Addr) netip.Addr {
    if !input.Is4() {
        return input
    }

    var a16 [16]byte
    byteorder.BEPutUint64(a16[:8], input.addr.hi)
    byteorder.BEPutUint64(a16[8:], input.addr.lo)

    addr := a16

    var output netip.Addr
    output.addr.hi = byteorder.BEUint64(addr[:8])
    output.addr.lo = byteorder.BEUint64(addr[8:])
    output.z = netip.z6noz
    return output
}

As humans, we can mentally derive the optimized form:

func AddrTo6(input netip.Addr) netip.Addr {
    if !input.Is4() {
        return input
    }
    var output netip.Addr
    output.addr.hi = input.addr.hi
    output.addr.lo = input.addr.lo
    output.z = netip.z6noz
    return output
}

Unfortunately, as of Go 1.26.8, the compiler is not smart enough to do the same:

// AX = input.addr.hi, BX = input.addr.lo, CX = input.z
; Push the stack (32 bytes):
;    0(SP) addr netip.uint128
;   16(SP) a16 [16]byte
 PUSHQ   BP
 MOVQ    SP, BP
 SUBQ    $32, SP

 CMPQ    net/netip·z4(SB), CX  ; check "z" if this is an IPv4 address
 JNE     end                   ; if not, stop here

; Pack: byteorder.BEPutUint64(a16[:8], input.addr.hi)
;       byteorder.BEPutUint64(a16[8:], input.addr.lo)
 MOVBEQ  AX, net/netip·a16+16(SP)
 MOVBEQ  BX, net/netip·a16+24(SP)

; addr = a16, 16 bytes at once through the vector register X0
 MOVUPS  net/netip·a16+16(SP), X0
 MOVUPS  X0, net/netip·addr(SP)

; CX = netip.z6noz
 MOVQ    net/netip·z6noz(SB), CX
; Unpack: output.addr.hi = byteorder.BEUint64(addr[:8])
;         output.addr.lo = byteorder.BEUint64(addr[8:])
 MOVBEQ  net/netip·addr(SP), AX
 MOVBEQ  net/netip·addr+8(SP), BX

end:
 ADDQ    $32, SP
 POPQ    BP
 RET
// return value = Addr{hi: AX, lo: BX, z: CX}

The compiler does a decent job on the byte shuffling: the eight byte stores of BEPutUint64() become a single MOVBEQ, which stores a register byte-swapped. The eight byte loads of BEUint64() become a single MOVBEQ the other way round.7 Three groups of instructions remain: a pack, a copy, and an unpack.

Hacking the Go compiler

The Go compiler has several phases:

Parsing
The compiler tokenizes and parses the source code. It builds a syntax tree for each source file.
Type checking
The compiler maps each identifier to the object it denotes, folds constants, and infers the type of every expression.
IR construction
The compiler converts the syntax tree and its types into its own intermediate representation (IR). This process, called “noding,” goes through a serialization format named unified IR.
Middle end
The compiler performs several optimization passes on the IR, such as devirtualization, function call inlining, and escape analysis.
Walk
This phase runs two steps: order of evaluation decomposes complex statements into simpler ones, and desugaring transforms higher-level Go constructs, like switch or channels, into more primitive instructions or calls to the runtime.
Generic SSA
The compiler converts the IR into Static Single Assignment (SSA) form, a lower-level intermediate representation suited for machine-independent optimizations and rewrite rules.
Machine code generation
The compiler rewrites the SSA form into machine-specific variants, allocates registers, and applies more optimization passes. At the end, the assembler turns the generated instructions into machine code.

The hammer

My first idea is to replace occurrences of netip.AddrFrom16(ip.As16()) with netip.Addr{addr: ip.addr, z: netip.z6noz} as early as possible, during the “noding” process. Before that, the type checking phase prevents us from accessing unexported struct fields.

Go 1.27 introduced a convenient debug option to dump the IR of a function at interesting points during compilation:

$ GOTOOLCHAIN=go1.27.1 GOAMD64=v3 go build -a -gcflags="-d=astdump=AddrTo6Safe" .
Writing text ast output for AddrTo6Safe to AddrTo6Safe.ast
Writing html ast output for AddrTo6Safe to AddrTo6Safe.html
Writing html syntax output for AddrTo6Safe to AddrTo6Safe.syntax.html

In the HTML file, the first column shows the IR as it comes out of noding:

DCLFUNC addrto6.AddrTo6Safe ABI:ABIInternal FUNC-func(netip.Addr) netip.Addr
DCLFUNC-Dcl
. NAME-addrto6.ip Class:PPARAM Offset:0 OnStack Used netip.Addr
. NAME-addrto6.~r0 Class:PPARAMOUT Offset:0 OnStack netip.Addr
DCLFUNC-body
. IF # ipv6_safe.go:11:2
. IF-Cond
. . CALLFUNC bool
. . CALLFUNC-Fun
. . . METHEXPR addrto6.Is4 FUNC-func(netip.Addr) bool
. . . . TYPE netip.Addr Class:PEXTERN Offset:0 type netip.Addr
. . CALLFUNC-Args
. . . NAME-addrto6.ip Class:PPARAM Offset:0 OnStack Used netip.Addr
. IF-Body
. . AS # ipv6_safe.go:12:6
. . . NAME-addrto6.ip Class:PPARAM Offset:0 OnStack Used netip.Addr
. . . CALLFUNC netip.Addr
. . . CALLFUNC-Fun
. . . . NAME-netip.AddrFrom16 Class:PFUNC Offset:0 Used FUNC-func([16]byte) netip.Addr
. . . CALLFUNC-Args
. . . . CALLFUNC ARRAY-[16]byte
. . . . CALLFUNC-Fun
. . . . . METHEXPR addrto6.As16 FUNC-func(netip.Addr) [16]byte
. . . . . . TYPE netip.Addr Class:PEXTERN Offset:0 type netip.Addr
. . . . CALLFUNC-Args
. . . . . NAME-addrto6.ip Class:PPARAM Offset:0 OnStack Used netip.Addr
. RETURN # ipv6_safe.go:14:2
. RETURN-Results
. . NAME-addrto6.ip Class:PPARAM Offset:0 OnStack Used netip.Addr

In the body of the if statement, we spot the calls to the method netip.Addr.As16() and to the function netip.AddrFrom16(). Our goal is to patch them with a struct literal:

IF-Body
. AS # ipv6_safe.go:12:6
. . NAME-addrto6.ip Class:PPARAM Offset:0 OnStack Used netip.Addr
. . STRUCTLIT netip.Addr
. . STRUCTLIT-List
. . . STRUCTKEY netip.addr
. . . . DOT netip.addr netip.uint128
. . . . . NAME-addrto6.ip Class:PPARAM Offset:0 OnStack Used netip.Addr
. . . STRUCTKEY netip.z
. . . . NAME-netip.z6noz Class:PEXTERN Offset:0 unique.Handle[net/netip.addrDetail]

In noder’s reader.go, the expr() method builds the IR tree for an expression. At the end of the exprCall case, we add a call to a rewriteAddrFrom16As16() function. It takes the current node and returns the struct literal on success, or nil if the rewrite is not possible. First, we check that we have the expected pattern: a call to the netip.AddrFrom16() function with a call to the netip.Addr.As16() method as its only argument:

func rewriteAddrFrom16As16(n ir.Node) ir.Node {
    call, ok := n.(*ir.CallExpr)
    if !ok || call.Op() != ir.OCALLFUNC ||
        len(call.Args) != 1 || len(call.Init()) != 0 ||
        !isNetipFunc(call.Fun, "AddrFrom16") {
        return nil
    }
    inner, ok := call.Args[0].(*ir.CallExpr)
    if !ok || inner.Op() != ir.OCALLFUNC ||
        len(inner.Args) != 1 || len(inner.Init()) != 0 ||
        !isNetipFunc(inner.Fun, "Addr.As16") {
        return nil
    }
    x := inner.Args[0]
    // [...]
}

Then, we fetch netip.z6noz:

z6noz, err := lookupVar(ir.StaticCalleeName(call.Fun).Sym().Pkg, "z6noz")
if err != nil {
    return nil
}

And we build the struct literal:

typ := call.Type()
pos := call.Pos()
var list []ir.Node
for i, f := range typ.Fields() {
    var value ir.Node
    switch f.Sym.Name {
    case "addr":
        value = typecheck.DotField(pos, x, i)
    case "z":
        value = z6noz
    default:
        return nil
    }
    list = append(list, ir.NewStructKeyExpr(pos, f, value))
}
lit := ir.NewCompLitExpr(pos, ir.OSTRUCTLIT, typ, list)
lit.SetTypecheck(1)
return lit

Have a look at the complete patch.8 We can test it with the following commands:

$ cd src
$ ./make.bash
Building Go cmd/dist using /usr/lib/go-1.27. (go1.27.1 linux/amd64)
Building Go toolchain1 and bootstrap cmd/go (go_bootstrap) using /usr/lib/go-1.27.
Building Go toolchain2 using go_bootstrap and Go toolchain1.
Building Go toolchain3 and commands using go_bootstrap and Go toolchain2.
Checking command staleness for linux/amd64.
---
Installed Go for linux/amd64 in /home/bernat/code/free/go
Installed commands in /home/bernat/code/free/go/bin
*** You need to add /home/bernat/code/free/go/bin to your PATH.
$ export PATH=$PWD/../bin:$PATH
$ go version
go version go1.28-devel_9834516e20 Sat Sep 12 08:23:11 2026 -0700 linux/amd64
$ go test net/netip/...
ok      net/netip   0.224s
$ cd ../../go-netip-addrto6
$ go test .
ok      github.com/vincentbernat/go-netip-addrto6   0.062s

The generated code for the helper is now the shortest possible version!

// AX = input.addr.hi, BX = input.addr.lo, CX = input.z
 CMPQ    net/netip·z4(SB), CX     ; check "z" if this is an IPv4 address
 JNE     end                      ; if not, stop here
 MOVQ    net/netip·z6noz(SB), CX  ; CX = netip.z6noz
end:
 RET
// return value = Addr{hi: AX, lo: BX, z: CX}

Go maintainers are unlikely to accept this change. It relies on the internal structure of net/netip.Addr. It’s an ugly hack in the noder, whose job is to faithfully translate the type-checked AST into the IR. And it’s harder to maintain than adding a To6() method.

The screwdriver

The right place for such an optimization is the generic SSA phase. One of the last machine-independent passes is memcombine. With the appropriate debug flag, the compiler dumps the SSA form after this pass:9

$ GOTOOLCHAIN=go1.26.8 GOAMD64=v3 \
> go build -a -gcflags='-d=ssa/memcombine/dump=AddrTo6Safe' .
$ head -5 AddrTo6Safe_01__memcombine.dump
AddrTo6Safe func(netip.Addr) netip.Addr
  b2:
    (?) v1 = InitMem <mem>
    (?) v2 = SP <uintptr>
    (?) v3 = SB <uintptr>

The result of the memcombine pass follows the same structure as the assembly code for AddrTo6Safe() we looked at earlier: two stores, one move, and two loads we would like to optimize away.

; […]
  v502 = ArgIntReg <uint64> {ip+0} [0]              ; input.addr.hi
  v490 = ArgIntReg <uint64> {ip+8} [1]              ; input.addr.lo
  v466 = ArgIntReg <*netip.addrDetail> {ip+16} [2]  ; input.z
; […]
  v22 = LocalAddr <*[16]byte> {netip.a16} v2 v1     ; &a16
  v173 = OffPtr <*byte> [8] v22                     ; &a16[8]
  v442 = Bswap64 <uint64> v490                      ; bswap(input.addr.lo)
  v542 = Bswap64 <uint64> v502                      ; bswap(input.addr.hi)
  v161 = Store <mem> {uint64} v22 v542 v23          ; a16[:8] = bswap(hi)
  v282 = Store <mem> {uint64} v173 v442 v161        ; a16[8:] = bswap(lo)

  v285 = LocalAddr <*[16]byte> {netip.addr} v2 v282 ; &addr
  v286 = Move <mem> {[16]byte} [16] v285 v22 v282   ; addr = a16

  v415 = OffPtr <*byte> [8] v285                    ; &addr[8]
  v416 = Load <uint64> v285 v286                    ; addr[:8]
  v299 = Bswap64 <uint64> v416                      ; output.addr.hi
  v174 = Load <uint64> v415 v286                    ; addr[8:]
  v39  = Bswap64 <uint64> v174                      ; output.addr.lo
; […]

Each line features a value identifier (v442), an operation with its type (Bswap64 <uint64>), and its arguments (v490).10 Values are the basic building blocks of SSA and are defined exactly once. Square brackets enclose integer parameters ([8]) and curly braces contain auxiliary arguments ({netip.addr}). Operations writing to memory produce a new memory state. Every memory operation takes the current state as its last argument, which keeps them in order.

On paper

Let’s focus on output.addr.lo, aka v39:

  v490 = ArgIntReg <uint64> {ip+8} [1]              ; input.addr.lo
  v22 = LocalAddr <*[16]byte> {netip.a16} v2 v1     ; &a16
  v173 = OffPtr <*byte> [8] v22                     ; &a16[8]
  v442 = Bswap64 <uint64> v490                      ; bswap(input.addr.lo)
  v282 = Store <mem> {uint64} v173 v442 v161        ; a16[8:] = bswap(lo)
  v285 = LocalAddr <*[16]byte> {netip.addr} v2 v282 ; &addr
  v286 = Move <mem> {[16]byte} [16] v285 v22 v282   ; addr = a16
  v415 = OffPtr <*byte> [8] v285                    ; &addr[8]
  v174 = Load <uint64> v415 v286                    ; addr[8:]
  v39  = Bswap64 <uint64> v174                      ; output.addr.lo

To simplify this code, we could apply three rewriting rules:

  1. The first one adds a shortcut when loading through a move: (Load (OffPtr [o] p) (Move p src mem)) => (Load (OffPtr [o] src) mem). This matches v174 with its arguments v415 and v286 and creates a new value v600:

      v490 = ArgIntReg <uint64> {ip+8} [1]              ; input.addr.lo
      v22 = LocalAddr <*[16]byte> {netip.a16} v2 v1     ; &a16
      v173 = OffPtr <*byte> [8] v22                     ; &a16[8]
      v442 = Bswap64 <uint64> v490                      ; bswap(input.addr.lo)
      v282 = Store <mem> {uint64} v173 v442 v161        ; a16[8:] = bswap(lo)
      v285 = LocalAddr <*[16]byte> {netip.addr} v2 v282 ; &addr
      v286 = Move <mem> {[16]byte} [16] v285 v22 v282   ; addr = a16
      v415 = OffPtr <*byte> [8] v285                    ; &addr[8]
      v600 = OffPtr <*byte> [8] v22                     ; &a16[8]
      v174 = Load <uint64> v600 v282                    ; a16[8:]
      v39  = Bswap64 <uint64> v174                      ; output.addr.lo
    
  2. The second one simplifies a load following a store: (Load p (Store p x _)) => x. The load is forwarded: the stored value replaces it and no memory access remains. It matches v174. It notices that v600 and v173 are the same address and replaces v174 with a copy of v442:

      v490 = ArgIntReg <uint64> {ip+8} [1]              ; input.addr.lo
      v22 = LocalAddr <*[16]byte> {netip.a16} v2 v1     ; &a16
      v173 = OffPtr <*byte> [8] v22                     ; &a16[8]
      v442 = Bswap64 <uint64> v490                      ; bswap(input.addr.lo)
      v282 = Store <mem> {uint64} v173 v442 v161        ; a16[8:] = bswap(lo)
      v285 = LocalAddr <*[16]byte> {netip.addr} v2 v282 ; &addr
      v286 = Move <mem> {[16]byte} [16] v285 v22 v282   ; addr = a16
      v415 = OffPtr <*byte> [8] v285                    ; &addr[8]
      v600 = OffPtr <*byte> [8] v22                     ; &a16[8]
      v174 = Copy <uint64> v442                         ; bswap(input.addr.lo)
      v39  = Bswap64 <uint64> v174                      ; output.addr.lo
    
  3. The last step cancels the two byte swaps: (Bswap64 (Bswap64 x)) => x. v39 becomes a copy of v490:

      v490 = ArgIntReg <uint64> {ip+8} [1]              ; input.addr.lo
      v22 = LocalAddr <*[16]byte> {netip.a16} v2 v1     ; &a16
      v173 = OffPtr <*byte> [8] v22                     ; &a16[8]
      v442 = Bswap64 <uint64> v490                      ; bswap(input.addr.lo)
      v282 = Store <mem> {uint64} v173 v442 v161        ; a16[8:] = bswap(lo)
      v285 = LocalAddr <*[16]byte> {netip.addr} v2 v282 ; &addr
      v286 = Move <mem> {[16]byte} [16] v285 v22 v282   ; addr = a16
      v415 = OffPtr <*byte> [8] v285                    ; &addr[8]
      v600 = OffPtr <*byte> [8] v22                     ; &a16[8]
      v174 = Copy <uint64> v442                         ; bswap(input.addr.lo)
      v39  = Copy <uint64> v490                         ; output.addr.lo = input.addr.lo
    

If we ignore the values not needed to compute v39, only this SSA form remains:

  v490 = ArgIntReg <uint64> {ip+8} [1]  ; input.addr.lo
  v39  = Copy <uint64> v490             ; output.addr.lo = input.addr.lo

Let’s switch to output.addr.hi, aka v299:

  v502 = ArgIntReg <uint64> {ip+0} [0]              ; input.addr.hi
  v22 = LocalAddr <*[16]byte> {netip.a16} v2 v1     ; &a16
  v173 = OffPtr <*byte> [8] v22                     ; &a16[8]
  v542 = Bswap64 <uint64> v502                      ; bswap(input.addr.hi)
  v161 = Store <mem> {uint64} v22 v542 v23          ; a16[:8] = bswap(hi)
  v282 = Store <mem> {uint64} v173 v442 v161        ; a16[8:] = bswap(lo)
  v285 = LocalAddr <*[16]byte> {netip.addr} v2 v282 ; &addr
  v286 = Move <mem> {[16]byte} [16] v285 v22 v282   ; addr = a16
  v416 = Load <uint64> v285 v286                    ; addr[:8]
  v299 = Bswap64 <uint64> v416                      ; output.addr.hi

To optimize it away, we also apply three rewriting rules:

  1. The first one also adds a shortcut when loading through a move, but without an offset: (Load p (Move p src mem)) => (Load src mem). This rewrites v416 to use arguments from v286:

      v502 = ArgIntReg <uint64> {ip+0} [0]              ; input.addr.hi
      v22 = LocalAddr <*[16]byte> {netip.a16} v2 v1     ; &a16
      v173 = OffPtr <*byte> [8] v22                     ; &a16[8]
      v542 = Bswap64 <uint64> v502                      ; bswap(input.addr.hi)
      v161 = Store <mem> {uint64} v22 v542 v23          ; a16[:8] = bswap(hi)
      v282 = Store <mem> {uint64} v173 v442 v161        ; a16[8:] = bswap(lo)
      v285 = LocalAddr <*[16]byte> {netip.addr} v2 v282 ; &addr
      v286 = Move <mem> {[16]byte} [16] v285 v22 v282   ; addr = a16
      v416 = Load <uint64> v22 v282                     ; a16[:8]
      v299 = Bswap64 <uint64> v416                      ; output.addr.hi
    
  2. The second rule forwards a value stored one step earlier, skipping over a store to another address: (Load p (Store q _ (Store p x _))) => x. This matches v416: x is v542, p is v22 (&a16), q is v173 (&a16[8]), and p and q do not overlap for uint64.

      v502 = ArgIntReg <uint64> {ip+0} [0]              ; input.addr.hi
      v22 = LocalAddr <*[16]byte> {netip.a16} v2 v1     ; &a16
      v173 = OffPtr <*byte> [8] v22                     ; &a16[8]
      v542 = Bswap64 <uint64> v502                      ; bswap(input.addr.hi)
      v161 = Store <mem> {uint64} v22 v542 v23          ; a16[:8] = bswap(hi)
      v282 = Store <mem> {uint64} v173 v442 v161        ; a16[8:] = bswap(lo)
      v285 = LocalAddr <*[16]byte> {netip.addr} v2 v282 ; &addr
      v286 = Move <mem> {[16]byte} [16] v285 v22 v282   ; addr = a16
      v416 = Copy <uint64> v542                         ; bswap(input.addr.hi)
      v299 = Bswap64 <uint64> v416                      ; output.addr.hi
    
  3. The third rule cancels two byte swaps: (Bswap64 (Bswap64 x)) => x. v299 becomes a copy of v502:

      v502 = ArgIntReg <uint64> {ip+0} [0]              ; input.addr.hi
      v22 = LocalAddr <*[16]byte> {netip.a16} v2 v1     ; &a16
      v173 = OffPtr <*byte> [8] v22                     ; &a16[8]
      v542 = Bswap64 <uint64> v502                      ; bswap(input.addr.hi)
      v161 = Store <mem> {uint64} v22 v542 v23          ; a16[:8] = bswap(hi)
      v282 = Store <mem> {uint64} v173 v442 v161        ; a16[8:] = bswap(lo)
      v285 = LocalAddr <*[16]byte> {netip.addr} v2 v282 ; &addr
      v286 = Move <mem> {[16]byte} [16] v285 v22 v282   ; addr = a16
      v416 = Copy <uint64> v542                         ; bswap(input.addr.hi)
      v299 = Copy <uint64> v502                         ; output.addr.hi = input.addr.hi
    

If we remove the values not used to compute v299, we get this SSA form:

  v502 = ArgIntReg <uint64> {ip+0} [0] ; input.addr.hi
  v299 = Copy <uint64> v502            ; output.addr.hi = input.addr.hi

In practice

Most of these rules already exist in generic.rules. They use conditions to validate their context: ssa.IsSamePtr() for the same address, ssa.Disjoint() for addresses that do not overlap. The rule forwarding a stored value to a load already exists with three variants looking through several other stores. Here are the two we need:

(Load <t1> p1 (Store {t2} p2 x _))
    && ssa.IsSamePtr(p1, p2)
    && copyCompatibleType(t1, x.Type)
    && t1.Size() == t2.Size()
    => x
(Load <t1> p1 (Store {t2} p2 _ (Store {t3} p3 x _)))
    && ssa.IsSamePtr(p1, p3)
    && copyCompatibleType(t1, x.Type)
    && t1.Size() == t3.Size()
    && ssa.Disjoint(p3, t3, p2, t2)
    => x

Go 1.27 added the rule loading through a move with CL 748200 to fix issue #77720:

(Load <t1> op1:(OffPtr [o1] p1) move:(Move [n] p2 src mem))
    && o1 >= 0 && o1+t1.Size() <= n && ssa.IsSamePtr(p1, p2)
    && !ssa.IsVolatile(src)
    => @move.Block (Load <t1> (OffPtr <op1.Type> [o1] src) mem)

It lacks a variant without an offset:

(Load <t1> p1 move:(Move [n] p2 src mem))
    && p1.Op != ssaop.OpOffPtr
    && t1.Size() <= n && ssa.IsSamePtr(p1, p2)
    && !ssa.IsVolatile(src)
    => @move.Block (Load <t1> (OffPtr <p1.Type> [0] src) mem)

There is no generic rule to cancel two byte swaps, but the AMD64 lowering pass includes this rule:

(BSWAP(Q|L) (BSWAP(Q|L) p)) => p

After switching to Go’s development branch and adding the missing rule, the generated assembly code is worse than with Go 1.26.8, even though our additional rule slightly improves the situation at the end:

// AX = input.addr.hi, BX = input.addr.lo, CX = input.z
; Push the stack (16 bytes):
;    0(SP) a16 [16]byte
 PUSHQ   BP
 MOVQ    SP, BP
 SUBQ    $16, SP

 CMPQ    net/netip·z4(SB), CX       ; check "z" if this is an IPv4 address
 JNE     end                        ; if not, stop here

; The four forwarded bytes: the low half of input.addr.lo is taken apart and
; put back together in registers
 MOVQ    BX, DX                     ; DX = input.addr.lo
 SHRQ    $24, BX                    ; BX = input.addr.lo >> 24
 MOVQ    DX, SI                     ; SI = input.addr.lo
 SHRQ    $16, DX                    ; DX = input.addr.lo >> 16
 MOVQ    SI, DI                     ; DI = input.addr.lo, kept for the pack
 SHRQ    $8, SI                     ; SI = input.addr.lo >> 8
 MOVBLZX DIB, R8                    ; R8 = byte(input.addr.lo)
 MOVBLZX SIB, SI                    ; SI = byte(input.addr.lo >> 8)
 SHLQ    $8, SI
 ORQ     R8, SI                     ; SI = two low bytes of input.addr.lo
 MOVBLZX DL, DX                     ; DX = byte(input.addr.lo >> 16)
 SHLQ    $16, DX
 ORQ     SI, DX
 MOVBLZX BL, BX                     ; BX = byte(input.addr.lo >> 24)
 SHLQ    $24, BX
 ORQ     DX, BX                     ; BX = input.addr.lo & 0xffffffff

; Pack: byteorder.BEPutUint64(a16[:8], input.addr.hi)
;       byteorder.BEPutUint64(a16[8:], input.addr.lo)
 MOVBEQ  AX, net/netip·a16(SP)
 MOVBEQ  DI, net/netip·a16+8(SP)

; The four other bytes of input.addr.lo, read one by one from a16
 MOVBLZX net/netip·a16+11(SP), DX   ; a16[11]
 SHLQ    $32, DX
 ORQ     DX, BX
 MOVBLZX net/netip·a16+10(SP), DX   ; a16[10]
 SHLQ    $40, DX
 ORQ     DX, BX
 MOVBLZX net/netip·a16+9(SP), DX    ; a16[9]
 SHLQ    $48, DX
 ORQ     DX, BX
 MOVBLZX net/netip·a16+8(SP), DX    ; a16[8]
 SHLQ    $56, DX

; output.z = netip.z6noz
 MOVQ    net/netip·z6noz(SB), CX
; output.addr.hi = byteorder.BEUint64(a16[:8])
 MOVBEQ  net/netip·a16(SP), AX
; output.addr.lo assembled from the previous steps
 ORQ     DX, BX

end:
 LEAVEQ
 RET
// return value = Addr{hi: AX, lo: BX, z: CX}

The rule loading through a move, added in Go 1.27, introduced this regression.

Out of order

Let’s not give up now! In reality, the rewriting rules run before memcombine, notably in the late opt pass. At this point, the inlined versions of BEPutUint64() and BEUint64() still expand to sixteen byte stores and sixteen byte loads, matching their source code:

func BEUint64(b []byte) uint64 {
    _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
    return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
        uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
}

Let’s follow two bytes of output.addr.lo: addr[15] and addr[11]. Here is a simplified SSA form before late opt:

  v273 = Trunc64to8 <byte> v490                     ; byte(input.addr.lo)
  v226 = Trunc64to8 <byte> v225                     ; byte(input.addr.lo >> 32)
; […]
  v235 = Store <mem> {byte} v233 v226 v223          ; a16[11] = byte(lo >> 32)
  v247 = Store <mem> {byte} v245 v238 v235          ; a16[12] = …
  v259 = Store <mem> {byte} v257 v250 v247          ; a16[13] = …
  v271 = Store <mem> {byte} v269 v262 v259          ; a16[14] = …
  v282 = Store <mem> {byte} v280 v273 v271          ; a16[15] = byte(lo)
  v285 = LocalAddr <*[16]byte> {netip.addr} v2 v282 ; &addr
  v286 = Move <mem> {[16]byte} [16] v285 v22 v282   ; addr = a16
; […]
  v433 = OffPtr <*byte> [15] v285                   ; &addr[15]
  v435 = Load <byte> v433 v286                      ; addr[15]
  v479 = OffPtr <*byte> [11] v285                   ; &addr[11]
  v481 = Load <byte> v479 v286                      ; addr[11]

The first rule loads through the move: (Load (OffPtr [o] p) (Move p src mem)) => (Load (OffPtr [o] src) mem). It matches both loads, which now read a16 with the memory state before the copy:

  v600 = OffPtr <*byte> [15] v22 ; &a16[15]
  v435 = Load <byte> v600 v282   ; a16[15]
  v601 = OffPtr <*byte> [11] v22 ; &a16[11]
  v481 = Load <byte> v601 v282   ; a16[11]

The second rule shortcuts a load following a store: (Load p (Store p x _)) => x. It matches v435, as v282 stores a16[15]. It does not match v481: v235 stores a16[11] four stores earlier in the chain, while the variants of this rule look through three stores at most.

  v435 = Copy <byte> v273        ; byte(input.addr.lo)
  v601 = OffPtr <*byte> [11] v22 ; &a16[11]
  v481 = Load <byte> v601 v282   ; a16[11]

The same happens to the other bytes: the rule forwards the four bytes stored last, a16[12] to a16[15]. The twelve other loads now read a16 instead of addr.

BEUint64() becomes a chain of Or64, each one adding a byte shifted into place. memcombine is a pass written in Go, not a set of rewrite rules. It starts from the last Or64 of the chain and collects up to eight terms. If each term is a byte load, extended to 64 bits and shifted, and if the eight loads read consecutive addresses from the same pointer with the same memory state, it replaces the whole chain with a single 64-bit load and a byte swap. Otherwise, it tries again with four, then two terms, and from each intermediate Or64. Here is the loop checking each term in a simplified version of combineLoads():

for i := int64(0); i < n; i++ {
    v := a[i]
    shift := int64(0)
    if v.Op == shiftOp {
        v, shift = peelShift(v)
    }
    if v.Op != extOp {
        return false
    }
    load := v.Args[0]
    if load.Op != ssaop.OpLoad {
        return false
    }
    if load.Args[1] != mem {
        return false
    }
    p, off := splitPtr(load.Args[0])
    if p != base {
        return false
    }
    r[i] = LoadRecord{load: load, offset: off, shift: shift}
}

For output.addr.hi, the eight loads read a16 with the same memory state v282:

  v13  = Load <byte> v22 v282               ; a16[0]
  v530 = Load <byte> v14 v282               ; a16[1]
  v488 = Load <byte> v504 v282              ; a16[2]
  v405 = Load <byte> v537 v282              ; a16[3]
  v385 = Load <byte> v397 v282              ; a16[4]
  v361 = Load <byte> v373 v282              ; a16[5]
  v196 = Load <byte> v63 v282               ; a16[6]
  v432 = Load <byte> v315 v282              ; a16[7]
  v319 = ZeroExt8to64 <uint64> v432         ; uint64(a16[7])
  v329 = ZeroExt8to64 <uint64> v196         ; uint64(a16[6])
  v330 = Lsh64x64 <uint64> [true] v329 v138 ; uint64(a16[6]) << 8
  v331 = Or64 <uint64> v319 v330            ; a16[7] | a16[6] << 8
; […] same for a16[5] to a16[1]
  v401 = ZeroExt8to64 <uint64> v13          ; uint64(a16[0])
  v402 = Lsh64x64 <uint64> [true] v401 v55  ; uint64(a16[0]) << 56
  v403 = Or64 <uint64> v402 v391            ; | a16[0] << 56 = output.addr.hi

memcombine merges them into one load and a swap:

  v286 = Load <uint64> v22 v282   ; a16[:8]
  v285 = Bswap64 <uint64> v286    ; output.addr.hi

For output.addr.lo, here is the chain memcombine sees after late opt:

  v436 = ZeroExt8to64 <uint64> v273 ; addr[15], forwarded
  v448 = Or64 <uint64> v436 v447    ; | addr[14] << 8, forwarded
  v460 = Or64 <uint64> v459 v448    ; | addr[13] << 16, forwarded
  v472 = Or64 <uint64> v471 v460    ; | addr[12] << 24, forwarded
  v484 = Or64 <uint64> v483 v472    ; | a16[11] << 32, loaded
  v496 = Or64 <uint64> v495 v484    ; | a16[10] << 40, loaded
  v508 = Or64 <uint64> v507 v496    ; | a16[9] << 48, loaded
  v520 = Or64 <uint64> v519 v508    ; | a16[8] << 56, loaded

From v520, four of the eight terms are forwarded bytes, not loads from memory, and memcombine can’t combine them. It doesn’t merge the four remaining loads either, as they sit on top of the forwarded bytes.

Back in order

In summary, the rewriting rules run too early to be effective. A quick workaround exists: run an earlier round of memcombine before late opt. After this change, the generated code for the helper is back to the shortest possible version:

// AX = input.addr.hi, BX = input.addr.lo, CX = input.z
 CMPQ    net/netip·z4(SB), CX     ; check "z" if this is an IPv4 address
 JNE     end                      ; if not, stop here
 MOVQ    net/netip·z6noz(SB), CX  ; CX = netip.z6noz
end:
 RET
// return value = Addr{hi: AX, lo: BX, z: CX}

And the benchmark confirms it! ✌️

goos: linux
goarch: amd64
pkg: github.com/vincentbernat/go-netip-addrto6
cpu: AMD Ryzen 5 5600X 6-Core Processor
                   │   Go 1.26.8    │             Our branch              │
                   │     sec/op     │    sec/op     vs base               │
AddrTo6/safe          6.5470n ±  0%   0.8944n ± 4%  -86.34% (p=0.002 n=6)
AddrTo6/unsafe        0.9071n ±  3%   0.8682n ± 1%   -4.28% (p=0.002 n=6)
AddrTo6/builtin       0.8871n ±  2%   0.8785n ± 1%        ~ (p=0.310 n=6)

Next steps

I think Go maintainers would reject this change because of the additional memcombine pass. Instead, I plan to publish this blog post and bring up the subject again as a follow-up to issue #54365. Either the sheer complexity and the Go 1.27 regression convince the maintainers that adding a To6() method is simpler and more efficient, or they advise me on how to move forward. Either way, digging into this subject taught me a lot about the Go compiler! ⚙️

Update (2026-10)

I opened issue #81994 to propose Addr.To6(). Give it a 👍 if you want it in Go!


  1. IPv4-mapped IPv6 addresses let you handle only IPv6 addresses in your code and keep conversions at a few well-defined boundaries. I use them in Akvorado. ↩

  2. This is not strictly equivalent. The zero value becomes :: while it would make more sense to leave it untouched. ↩

  3. I suppose Go maintainers keep it inconvenient on purpose: they don’t want random packages to patch the standard library or other packages. ↩

  4. To avoid catastrophic bugs when netip.Addr’s layout changes, you must add tests to detect it. This is more dangerous if you put this code in a package. Either ask users to run the tests themselves, or detect the change at run time and panic. Hiding this optimization behind a build tag would make users aware of this potential trap. ↩

  5. I produced the assembly code with GOTOOLCHAIN=go1.26.8 GOAMD64=v3 ./go-asm '\.asm' from the companion repository, then edited it a bit to keep this article from turning into an endless rabbit hole. Due to an unfortunate sequence of events, we switch between versions: Go 1.27 introduced a regression that blurs the point of this article. ↩

  6. The function is short enough for the compiler to inline it, so the assembly code may vary depending on the surrounding code. ↩

  7. MOVBEQ requires GOAMD64=v3, matching the x86-64-v3 microarchitecture from 2013. Otherwise, the compiler translates BEPutUint64() to BSWAPQ+MOVQ and BEUint64() to MOVQ+BSWAPQ. ↩

  8. When the call is used as a statement, a struct literal alone is invalid. The patch then turns it into _ = netip.Addr{…}. ↩

  9. The compiler can also write an HTML file with the result of each pass:

    $ GOSSAFUNC=AddrTo6Safe \
    > GOTOOLCHAIN=go1.26.8 \
    > GOAMD64=v3 go build -a .
    dumped SSA for AddrTo6Safe,1 to ./ssa.html
    

    ↩

  10. Source line numbers in parentheses follow value identifiers, but I removed them from the examples. The SSA form also features branches, but we don’t need them to understand our optimizations. ↩

  •  
❌