{"id":106941,"date":"2022-08-03T07:00:00","date_gmt":"2022-08-03T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106941"},"modified":"2022-11-29T10:16:40","modified_gmt":"2022-11-29T18:16:40","slug":"20220803-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220803-00\/?p=106941","title":{"rendered":"The AArch64 processor (aka arm64), part 7: Bitfield manipulation"},"content":{"rendered":"<p>Recall that the PowerPC had <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180810-00\/?p=99465\"> the magical <code>rlwinm<\/code> instruction which was the Swiss army knife of bit operations<\/a>. Well, AArch64 has its own all-purpose instruction, known as <code>UBFM<\/code>, which stands for <i>unsigned bitfield move<\/i>.<\/p>\n<pre>    ; unsigned bitfield move\r\n    ;\r\n    ; if immr \u2264 imms:\r\n    ;   take bits immr through imms and rotate right by immr\r\n    ;\r\n    ; if immr &gt; imms:\r\n    ;   take imms+1 low bits and rotate right by immr\r\n\r\n    ubfm    Rd\/zr, Rn\/zr, #immr, #imms\r\n<\/pre>\n<p>This instruction hurts my brain. Although the description of the instruction appears to be two unrelated cases, they are handled by the same complex formula internally. It&#8217;s just that the formula produces different results depending on which case you&#8217;re in. The complex formula is the same one that is used to <!-- backref: The AArch64 processor (aka arm64), part 6: Bitwise operations --> generate immediates for logical operations, so I&#8217;ll give the processor designers credit for the clever way they reduced transistor count.<\/p>\n<p>Fortunately, you never see this instruction in the wild. The two cases are split into separate pseudo-instructions, which re-express the <var>immr<\/var> and <var>imms<\/var> values in a more intuitive way.<\/p>\n<pre>    ; unsigned bitfield extract\r\n    ; (used when immr \u2264 imms)\r\n    ; extract w bits starting at position lsb\r\n    ubfx    Rd\/zr, Rn\/zr, #lsb, #w\r\n<\/pre>\n<p>The <code>UBFX<\/code> instruction handles the case of <code>UBFM<\/code> where <var>immr<\/var> \u2264 <var>imms<\/var> and reinterprets it as a bitfield extraction:<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">w<\/td>\n<td>lsb<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; width: 10em;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-right: none; width: 4em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-left: none; width: 3em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; width: 4em;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td colspan=\"1\">\n<table style=\"width: 100%;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td align=\"left\">\u21d8<\/td>\n<td align=\"center\">\u21d8<\/td>\n<td align=\"center\">\u21d8<\/td>\n<td align=\"right\">\u21d8<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none; text-align: right; width: 10em;\">zero-fill<\/td>\n<td style=\"border: 1px gray; border-style: solid none; width: 4em;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-right: none; width: 3em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-left: none; width: 4em; background-color: #ddd;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">w<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Since <var>immr<\/var> \u2264 <var>imms<\/var>, the right-rotation by <var>immr<\/var> is the same as a right-shift by <var>immr<\/var>.<\/p>\n<p>And then we have the other case, where <var>immr<\/var> &gt; <var>imms<\/var>:<\/p>\n<pre>    ; unsigned bitfield insert into zeroes\r\n    ; (used when immr &gt; imms)\r\n    ; extract low-order w bits and shift left by lsb\r\n    ubfiz   Rd\/zr, Rn\/zr, #lsb, #w\r\n<\/pre>\n<p>The <code>UBFIZ<\/code> instruction reinterprets the <code>UBFM<\/code> as a bitfield insertion, and reinterprets the right-rotation as a left-shift. This reinterpretation is valid because <var>immr<\/var> &gt; <var>imms<\/var>, so we are always rotating more bits than we extracted.<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">w<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none; text-align: right; width: 10em;\">\u00a0<\/td>\n<td style=\"border: 1px gray; border-style: solid none; width: 4em;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-right: none; width: 3em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-left: none; width: 4em; background-color: #ddd;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td colspan=\"1\">\n<table style=\"width: 100%;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td align=\"left\">\u21d9<\/td>\n<td align=\"center\">\u21d9<\/td>\n<td align=\"center\">\u21d9<\/td>\n<td align=\"right\">\u21d9<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; width: 10em;\">zero-fill<\/td>\n<td style=\"border: solid 1px gray; border-right: none; width: 4em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-left: none; width: 3em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; width: 4em;\">zero-fill<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">w<\/td>\n<td>lsb<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>There is also a signed version of this instruction:<\/p>\n<pre>    ; signed bitfield move\r\n    ;\r\n    ; if immr \u2264 imms:\r\n    ;   take bits immr through imms and rotate right by immr\r\n    ;   sign-fill upper bits\r\n    ;\r\n    ; if immr &gt; imms:\r\n    ;   take imms+1 low bits and rotate right by immr\r\n    ;   sign-fill upper bits\r\n\r\n    sbfm    Rd\/zr, Rn\/zr, #immr #imms\r\n<\/pre>\n<p>This behaves the same as the unsigned version, except that the upper bits are filled with the sign bit of the bitfield. Like <code>UBFM<\/code>, the <code>SBFM<\/code> instruction is also never seen in the wild; it is always replaced by a pseudo-instruction.<\/p>\n<pre>    ; signed bitfield extract\r\n    ; (used when immr \u2264 imms)\r\n    ; extract w bits starting at position lsb\r\n    ; sign-fill upper bits\r\n    sbfx    Rd\/zr, Rn\/zr, #lsb, #w\r\n\r\n    ; signed bitfield insert into zeroes\r\n    ; (used when immr &gt; imms)\r\n    ; extract low-order w bits and shift left by lsb\r\n    ; sign-fill upper bits\r\n    sbfiz   Rd\/zr, Rn\/zr, #lsb, #w\r\n<\/pre>\n<p>Here is the operation of <code>SBFX<\/code> in pictures:<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">w<\/td>\n<td>lsb<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; width: 10em;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-right: none; width: 4em; text-align: left; background-color: #ddd; color: black;\">S<\/td>\n<td style=\"border: solid 1px gray; border-left: none; width: 3em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; width: 4em;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td colspan=\"1\">\n<table style=\"width: 100%;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td align=\"left\">\u21d8<\/td>\n<td align=\"center\">\u21d8<\/td>\n<td align=\"center\">\u21d8<\/td>\n<td align=\"right\">\u21d8<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none; text-align: right; width: 10em;\">sign-fill<\/td>\n<td style=\"border: 1px gray; border-style: solid none; width: 4em;\">\u21d0\u21d0\u21d0<\/td>\n<td style=\"border: solid 1px gray; border-right: none; width: 3em; text-align: left; background-color: #ddd; color: black;\">S<\/td>\n<td style=\"border: solid 1px gray; border-left: none; width: 4em; background-color: #ddd;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">w<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>And here is <code>SBFIZ<\/code>:<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">w<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none; text-align: right; width: 10em;\">\u00a0<\/td>\n<td style=\"border: 1px gray; border-style: solid none; width: 4em;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-right: none; width: 3em; text-align: left; background-color: #ddd; color: black;\">S<\/td>\n<td style=\"border: solid 1px gray; border-left: none; width: 4em; background-color: #ddd;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td colspan=\"1\">\n<table style=\"width: 100%;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td align=\"left\">\u21d9<\/td>\n<td align=\"center\">\u21d9<\/td>\n<td align=\"center\">\u21d9<\/td>\n<td align=\"right\">\u21d9<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; width: 10em; text-align: right;\">sign-fill \u21d0\u21d0\u21d0<\/td>\n<td style=\"border: solid 1px gray; border-right: none; width: 4em; text-align: left; background-color: #ddd; color: black;\">S<\/td>\n<td style=\"border: solid 1px gray; border-left: none; width: 3em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; width: 4em;\">zero-fill<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">w<\/td>\n<td>lsb<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Note that in the case of <code>SBFIZ<\/code>, the lower bits are still zero-filled.<\/p>\n<p>The last bitfield opcode is <code>BFM<\/code>, which follows the same pattern, but just combines the results differently:<\/p>\n<pre>    ; bitfield move\r\n    ;\r\n    ; if immr \u2264 imms:\r\n    ;   take bits immr through imms and rotate right by immr\r\n    ;   merge with existing bits in destination\r\n    ;\r\n    ; if immr &gt; imms:\r\n    ;   take imms+1 low bits and rotate right by immr\r\n    ;   merge with existing bits in destination\r\n\r\n    bfm     Rd\/zr, Rn\/zr, #immr #imms\r\n<\/pre>\n<p>Again, you will never see this instruction in the wild because it always disassembles as a pseudo-instruction:<\/p>\n<pre>    ; bitfield extract and insert low\r\n    ; (used when immr \u2264 imms)\r\n    ; replace bottom w bits in destination\r\n    ; with w bits of source starting at lsb\r\n    ;\r\n    ; Rd[w-1:0] = Rn[lsb+w-1:lsb]\r\n    ;\r\n    bfxil   Rd\/zr, Rn\/zr, #lsb, #w\r\n<\/pre>\n<p>The <code>BFXIL<\/code> instruction is like the <code>UBFX<\/code> and <code>SBFX<\/code> instructions, but instead of filling the unused bits with zero or sign bits, the original bits of the destination are preserved.<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">w<\/td>\n<td>lsb<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; width: 10em;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-right: none; width: 4em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-left: none; width: 3em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; width: 4em;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td colspan=\"1\">\n<table style=\"width: 100%;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td align=\"left\">\u21d8<\/td>\n<td align=\"center\">\u21d8<\/td>\n<td align=\"center\">\u21d8<\/td>\n<td align=\"right\">\u21d8<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none; text-align: right; width: 10em;\">unchanged<\/td>\n<td style=\"border: 1px gray; border-style: solid none; width: 4em;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-right: none; width: 3em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-left: none; width: 4em; background-color: #ddd;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">w<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<pre>    ; bitfield insert\r\n    ; (used when immr &gt; imms)\r\n    ; replace w bits in destination starting at lsb\r\n    ; with low w bits of source\r\n    ;\r\n    ; Rd[lsb+w-1:lsb] = Rn[w-1:0]\r\n    ;\r\n    bfi     Rd\/zr, Rn\/zr, #lsb, #w\r\n<\/pre>\n<p>The <code>BFI<\/code> instruction is like the <code>UBFIZ<\/code> and <code>SBFIZ<\/code> instructions, but instead of filling the unused bits with zero or sign bits, the original bits of the destination are preserved.<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">w<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; border-right: none; text-align: right; width: 10em;\">\u00a0<\/td>\n<td style=\"border: 1px gray; border-style: solid none; width: 4em;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-right: none; width: 3em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-left: none; width: 4em; background-color: #ddd;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td colspan=\"1\">\n<table style=\"width: 100%;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td align=\"left\">\u21d9<\/td>\n<td align=\"center\">\u21d9<\/td>\n<td align=\"center\">\u21d9<\/td>\n<td align=\"right\">\u21d9<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; width: 10em;\">unchanged<\/td>\n<td style=\"border: solid 1px gray; border-right: none; width: 4em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-left: none; width: 3em; background-color: #ddd;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; width: 4em; font-size: 80%;\">unchanged<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">w<\/td>\n<td>lsb<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<pre>    ; bitfield clear\r\n    ; replace w bits in destination starting at lsb\r\n    ; with zero\r\n    ;\r\n    ; Rd[lsb+w-1:lsb] = 0\r\n    ;\r\n    bfc     Rd\/zr, #lsb, #w     ; bfi Rd\/zr, zr, #lsb, #w\r\n<\/pre>\n<p>The <code>BFC<\/code> instruction just inserts zeroes.<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px gray; width: 10em;\">unchanged<\/td>\n<td style=\"border: solid 1px gray; width: 7em; background-color: #ddd; color: black;\">zero-fill<\/td>\n<td style=\"border: solid 1px gray; width: 4em; font-size: 80%;\">unchanged<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>w<\/td>\n<td>lsb<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The last instruction in the bitfield manipulation category is word\/doubleword extraction.<\/p>\n<pre>    ; extract a register from a pair of registers\r\n    ;\r\n    ; Wd = ((Wn &lt;&lt; 32) | Wm)[lsb+31:lsb]\r\n    ; Xd = ((Xn &lt;&lt; 64) | Xm)[lsb+63:lsb]\r\n    ;\r\n    extr    Rd\/zr, Rn\/zr, Rm\/zr, #lsb\r\n<\/pre>\n<p>The <i>extract register<\/i> instruction treats its inputs as a register pair and extracts a register-sized stretch of bits from them. This can be used to synthesize multiword shifts.<\/p>\n<table style=\"border-collapse: collapse; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"border: 1px gray; border-style: solid solid none solid;\" colspan=\"2\">size<\/td>\n<td style=\"border: 1px gray; border-style: solid solid none solid;\">shift<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px gray; border-right-style: dashed; width: 5em; position: relative;\">\n<div style=\"position: absolute; width: 7em; top: 0; left: 0; text-align: center;\">Rn<\/div>\n<\/td>\n<td style=\"border: solid 1px gray; border-left-style: dashed; width: 2em; background-color: #ddd; position: relative;\">\u00a0<\/td>\n<td style=\"border: solid 1px gray; border-right-style: dashed; width: 5em; position: relative; background-color: #ddd; color: black;\">\n<div style=\"position: absolute; width: 7em; top: 0; left: 0; text-align: center;\">Rm<\/div>\n<\/td>\n<td style=\"border: solid 1px gray; border-left-style: dashed; width: 2em;\">\u00a0<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td colspan=\"2\">\n<table style=\"width: 100%;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td align=\"center\">\u21d3<\/td>\n<td align=\"center\">\u21d3<\/td>\n<td align=\"center\">\u21d3<\/td>\n<td align=\"center\">\u21d3<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px gray; text-align: center; background-color: #ddd; color: black;\" colspan=\"2\">Rd<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Note that the two input registers are concatenated in big-endian order.<\/p>\n<p>It turns out that a lot of other operations can be reinterpreted as bitfield extractions. We&#8217;ll look at some of them next time.<\/p>\n<p><b>Bonus chatter<\/b>: AArch32 also had instructions <code>bfi<\/code>, <code>bfc<\/code>, <code>ubfx<\/code>, and <code>sbfx<\/code>, but each was treated as a unique instruction. AArch64 generalizes them to cover additional scenarios, leaving the classic instructions as special cases of the generalized instructions.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Peeking inside the words.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[2],"class_list":["post-106941","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-history"],"acf":[],"blog_post_summary":"<p>Peeking inside the words.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106941","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=106941"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106941\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=106941"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106941"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106941"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}