summaryrefslogtreecommitdiff
path: root/chapter21/docs
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-10-07 10:14:20 -0700
committerGitHub <noreply@github.com>2026-10-07 10:14:20 -0700
commit8a20d5238855de5479d84e7fd8e84561844e2dc4 (patch)
treebbeab7de6ac8b556911d117989ab4bbc0324ecb5 /chapter21/docs
parent81b654d76444d747fdf1d053760e507b50f26e18 (diff)
parentb2862f980f3d78012066ef1cc09d4ad58f886c0f (diff)
downloadSimple-8a20d5238855de5479d84e7fd8e84561844e2dc4.tar.gz
Simple-8a20d5238855de5479d84e7fd8e84561844e2dc4.zip
Merge pull request #262 from com-junkawasaki/docs/japanese-chapters
docs: add Japanese translations for all chapters
Diffstat (limited to 'chapter21/docs')
-rw-r--r--chapter21/docs/18-grammar.md130
-rw-r--r--chapter21/docs/21-grammar.ja.md141
-rw-r--r--chapter21/docs/21-grammar.md141
-rw-r--r--chapter21/docs/encoding-reference.ja.md776
-rw-r--r--chapter21/docs/encoding-reference.md54
5 files changed, 1089 insertions, 153 deletions
diff --git a/chapter21/docs/18-grammar.md b/chapter21/docs/18-grammar.md
deleted file mode 100644
index 7da725e9..00000000
--- a/chapter21/docs/18-grammar.md
+++ /dev/null
@@ -1,130 +0,0 @@
-# Grammar for Chapter 16
-
-```antlrv4
-grammar SimpleLanguage;
-
-program : block EOF ;
-
-block : statement+ ;
-
-
-statement
- : '{' block '}'
- | returnStatement
- | ifStatement
- | whileStatement
- | breakStatement
- | continueStatement
- | structDeclaration
- | expressionStatement
- ;
-
-
-returnStatement : 'return' expression ';' ;
-
-ifStatement : 'if' '(' expression ')' statement ('else' statement)? ;
-
-whileStatement : 'while' '(' expression ')' statement ;
-
-breakStatement : 'break' ';' ;
-
-continueStatement : 'continue' ';' ;
-
-
-structDeclaration : 'struct' IDENTIFIER '{' block '}' ;
-
-expressionStatement
- : type IDENTIFIER ';'
- | type IDENTIFIER '=' expression ';'
- | IDENTIFIER '=' expression ';'
- | expression
- ;
-
-PRIMTYPE
- : 'int'
- | 'i8'
- | 'i16'
- | 'i32'
- | 'i64'
- | 'u8'
- | 'u16'
- | 'u32'
- | 'flt'
- | 'f32'
- | 'f64'
- | 'bool'
- ;
-
-type
- : PRIMTYPE
- | typeName '?'?
- | typeName nestedArray+
- ;
-
-nestedArray : '?'? '[]'* ;
-
-typeName : IDENTIFIER ;
-
-
-expression : bitWiseExpression ;
-
-bitWiseExpression
- : comparisonExpression ( '&' | '|' | '^' ) comparisonExpression)*
- ;
-
-comparisonExpression
- : shiftExpression (('==' | '!='| '>'| '<'| '>='| '<=') shiftExpression)*
- ;
-
-shiftExpression
- : additiveExpression ( '<<' | '>>>' | '>>' ) additiveExpression)*
- ;
-
-additiveExpression
- : multiplicativeExpression (('+' | '-') multiplicativeExpression)*
- ;
-
-multiplicativeExpression
- : unaryExpression (('*' | '/') unaryExpression)*
- ;
-
-unaryExpression
- : ('-') unaryExpression
- | '!' unaryExpression
- | primaryExpression postAssign
- ;
-
-primaryExpression
- : INTEGER_LITERAL
- | FLOAT_LITERAL
- | '(' expression ')'
- | 'true'
- | 'false'
- | 'null'
- | newExpression
- | IDENTIFIER
- ;
-
-newExpression
- : 'new' IDENTIFIER [ '{' block '}' ]
- | 'new' IDENTIFIER '[' expression ']'
- ;
-
-postAssign : postFix [ '=' expression ] | [ '#' ];
-
-postFix
- : '.' IDENTIFIER postFix
- | '[' expression ']' postFix
- ;
-
-
-IDENTIFIER : NON_DIGIT (NON_DIGIT | DIGIT)* ;
-
-INTEGER_LITERAL
- : [1-9]DIGIT*
- | [0]
- ;
-
-NON_DIGIT: [a-zA-Z_];
-DIGIT: [0-9];
-```
diff --git a/chapter21/docs/21-grammar.ja.md b/chapter21/docs/21-grammar.ja.md
new file mode 100644
index 00000000..8cb8f27b
--- /dev/null
+++ b/chapter21/docs/21-grammar.ja.md
@@ -0,0 +1,141 @@
+# 第21章の文法
+
+[English](21-grammar.md) | 日本語
+
+```antlrv4
+grammar SimpleLanguage;
+
+// Name lookup, assignable operands, type compatibility, and access permissions
+// are checked by the compiler in addition to these syntax rules.
+program : statement* EOF ;
+
+block : '{' statement* '}' ;
+
+statement
+ : block
+ | returnStatement
+ | ifStatement
+ | whileStatement
+ | forStatement
+ | breakStatement
+ | continueStatement
+ | structDeclaration
+ | declaration ';'
+ | assignment ';'
+ | ';'
+ ;
+
+returnStatement : 'return' assignment ';' ;
+ifStatement : 'if' '(' assignment ')' statement ('else' statement)? ;
+whileStatement : 'while' '(' assignment ')' statement ;
+breakStatement : 'break' ';' ;
+continueStatement : 'continue' ';' ;
+
+forStatement
+ : 'for' '(' (declaration | assignment)? ';' assignment? ';' assignment? ')' statement
+ ;
+
+structDeclaration : 'struct' IDENTIFIER block ';' ;
+
+declaration : declarationType binding (',' binding)* ;
+declarationType : type | 'var' | 'val' ;
+binding : bindingModifier? IDENTIFIER ('=' initializer)? ;
+bindingModifier : '!' | '~' ;
+initializer : assignment ;
+
+// The prefix qualifies the named struct reference, not an enclosing array.
+// Each [] / [~] suffix qualifies its own array layer. ? requires a reference.
+type
+ : functionType
+ | primitiveType typeSuffix*
+ | accessModifier? typeName typeSuffix*
+ ;
+accessModifier : '!' | '~' ;
+typeSuffix : '?' | '[]' | '[~]' ;
+typeName : IDENTIFIER ;
+
+primitiveType
+ : 'int' | 'i8' | 'i16' | 'i32' | 'i64'
+ | 'u1' | 'u8' | 'u16' | 'u32' | 'byte' | 'bool'
+ | 'flt' | 'f32' | 'f64'
+ ;
+
+assignment : expression (assignmentOperator assignment)? ;
+assignmentOperator
+ : '=' | '+=' | '-=' | '*=' | '/=' | '&=' | '|=' | '^='
+ | '<<=' | '>>=' | '>>>='
+ ;
+
+expression : bitwiseExpression ('?' assignment (':' assignment)?)? ;
+
+bitwiseExpression
+ : comparisonExpression (('&' | '|' | '^') comparisonExpression)*
+ ;
+
+comparisonExpression
+ : shiftExpression (('==' | '!=' | '<' | '<=' | '>' | '>=') shiftExpression)*
+ ;
+
+shiftExpression
+ : additiveExpression (('<<' | '>>' | '>>>') additiveExpression)*
+ ;
+
+additiveExpression
+ : multiplicativeExpression (('+' | '-') multiplicativeExpression)*
+ ;
+
+multiplicativeExpression
+ : unaryExpression (('*' | '/') unaryExpression)*
+ ;
+
+unaryExpression
+ : ('-' | '!') unaryExpression
+ | updateOperator IDENTIFIER
+ | postfixExpression
+ ;
+
+// Prefix updates require a local name; postfix updates also allow fields
+// and array elements. All updates require an assignable operand.
+updateOperator : '++' | '--' ;
+postfixExpression : primaryExpression postfixSuffix* updateOperator? ;
+postfixSuffix : '.' IDENTIFIER | '[' assignment ']' | '#' | callSuffix ;
+
+primaryExpression
+ : INTEGER_LITERAL
+ | FLOAT_LITERAL
+ | 'true'
+ | 'false'
+ | 'null'
+ | IDENTIFIER
+ | '(' assignment ')'
+ | newExpression
+ | functionExpression
+ ;
+
+// A function is an expression bound with an ordinary declaration.
+// Its last statement supplies the implicit result; return can exit earlier.
+functionExpression : '{' parameterList? '->' statement* '}' ;
+parameterList : (parameter ','?)+ ;
+parameter : type bindingModifier? IDENTIFIER ;
+
+// Function types have unnamed, space-separated argument types.
+// {int} is the zero-argument type; its function expression still uses ->.
+functionType
+ : '{' type+ '->' type '}' '?'?
+ | '{' type '}' '?'?
+ ;
+
+callSuffix : '(' argumentList? ')' ;
+argumentList : assignment (',' assignment)* ','? ;
+
+// Struct initialization uses a block; array allocation supplies a length.
+newExpression : 'new' type ('[' assignment ']' | block)? ;
+
+INTEGER_LITERAL : '0' | [1-9] DIGIT* ;
+FLOAT_LITERAL : DIGIT+ ('.' DIGIT* ('e' DIGIT+)? | 'e' '-'? DIGIT+) ;
+IDENTIFIER : NON_DIGIT (NON_DIGIT | DIGIT)* ;
+fragment NON_DIGIT : [a-zA-Z_] ;
+fragment DIGIT : [0-9] ;
+WHITESPACE : [ \t\r\n]+ -> skip ;
+LINE_COMMENT : '//' ~[\r\n]* -> skip ;
+```
diff --git a/chapter21/docs/21-grammar.md b/chapter21/docs/21-grammar.md
new file mode 100644
index 00000000..111957a1
--- /dev/null
+++ b/chapter21/docs/21-grammar.md
@@ -0,0 +1,141 @@
+# Grammar for Chapter 21
+
+English | [日本語](21-grammar.ja.md)
+
+```antlrv4
+grammar SimpleLanguage;
+
+// Name lookup, assignable operands, type compatibility, and access permissions
+// are checked by the compiler in addition to these syntax rules.
+program : statement* EOF ;
+
+block : '{' statement* '}' ;
+
+statement
+ : block
+ | returnStatement
+ | ifStatement
+ | whileStatement
+ | forStatement
+ | breakStatement
+ | continueStatement
+ | structDeclaration
+ | declaration ';'
+ | assignment ';'
+ | ';'
+ ;
+
+returnStatement : 'return' assignment ';' ;
+ifStatement : 'if' '(' assignment ')' statement ('else' statement)? ;
+whileStatement : 'while' '(' assignment ')' statement ;
+breakStatement : 'break' ';' ;
+continueStatement : 'continue' ';' ;
+
+forStatement
+ : 'for' '(' (declaration | assignment)? ';' assignment? ';' assignment? ')' statement
+ ;
+
+structDeclaration : 'struct' IDENTIFIER block ';' ;
+
+declaration : declarationType binding (',' binding)* ;
+declarationType : type | 'var' | 'val' ;
+binding : bindingModifier? IDENTIFIER ('=' initializer)? ;
+bindingModifier : '!' | '~' ;
+initializer : assignment ;
+
+// The prefix qualifies the named struct reference, not an enclosing array.
+// Each [] / [~] suffix qualifies its own array layer. ? requires a reference.
+type
+ : functionType
+ | primitiveType typeSuffix*
+ | accessModifier? typeName typeSuffix*
+ ;
+accessModifier : '!' | '~' ;
+typeSuffix : '?' | '[]' | '[~]' ;
+typeName : IDENTIFIER ;
+
+primitiveType
+ : 'int' | 'i8' | 'i16' | 'i32' | 'i64'
+ | 'u1' | 'u8' | 'u16' | 'u32' | 'byte' | 'bool'
+ | 'flt' | 'f32' | 'f64'
+ ;
+
+assignment : expression (assignmentOperator assignment)? ;
+assignmentOperator
+ : '=' | '+=' | '-=' | '*=' | '/=' | '&=' | '|=' | '^='
+ | '<<=' | '>>=' | '>>>='
+ ;
+
+expression : bitwiseExpression ('?' assignment (':' assignment)?)? ;
+
+bitwiseExpression
+ : comparisonExpression (('&' | '|' | '^') comparisonExpression)*
+ ;
+
+comparisonExpression
+ : shiftExpression (('==' | '!=' | '<' | '<=' | '>' | '>=') shiftExpression)*
+ ;
+
+shiftExpression
+ : additiveExpression (('<<' | '>>' | '>>>') additiveExpression)*
+ ;
+
+additiveExpression
+ : multiplicativeExpression (('+' | '-') multiplicativeExpression)*
+ ;
+
+multiplicativeExpression
+ : unaryExpression (('*' | '/') unaryExpression)*
+ ;
+
+unaryExpression
+ : ('-' | '!') unaryExpression
+ | updateOperator IDENTIFIER
+ | postfixExpression
+ ;
+
+// Prefix updates require a local name; postfix updates also allow fields
+// and array elements. All updates require an assignable operand.
+updateOperator : '++' | '--' ;
+postfixExpression : primaryExpression postfixSuffix* updateOperator? ;
+postfixSuffix : '.' IDENTIFIER | '[' assignment ']' | '#' | callSuffix ;
+
+primaryExpression
+ : INTEGER_LITERAL
+ | FLOAT_LITERAL
+ | 'true'
+ | 'false'
+ | 'null'
+ | IDENTIFIER
+ | '(' assignment ')'
+ | newExpression
+ | functionExpression
+ ;
+
+// A function is an expression bound with an ordinary declaration.
+// Its last statement supplies the implicit result; return can exit earlier.
+functionExpression : '{' parameterList? '->' statement* '}' ;
+parameterList : (parameter ','?)+ ;
+parameter : type bindingModifier? IDENTIFIER ;
+
+// Function types have unnamed, space-separated argument types.
+// {int} is the zero-argument type; its function expression still uses ->.
+functionType
+ : '{' type+ '->' type '}' '?'?
+ | '{' type '}' '?'?
+ ;
+
+callSuffix : '(' argumentList? ')' ;
+argumentList : assignment (',' assignment)* ','? ;
+
+// Struct initialization uses a block; array allocation supplies a length.
+newExpression : 'new' type ('[' assignment ']' | block)? ;
+
+INTEGER_LITERAL : '0' | [1-9] DIGIT* ;
+FLOAT_LITERAL : DIGIT+ ('.' DIGIT* ('e' DIGIT+)? | 'e' '-'? DIGIT+) ;
+IDENTIFIER : NON_DIGIT (NON_DIGIT | DIGIT)* ;
+fragment NON_DIGIT : [a-zA-Z_] ;
+fragment DIGIT : [0-9] ;
+WHITESPACE : [ \t\r\n]+ -> skip ;
+LINE_COMMENT : '//' ~[\r\n]* -> skip ;
+```
diff --git a/chapter21/docs/encoding-reference.ja.md b/chapter21/docs/encoding-reference.ja.md
new file mode 100644
index 00000000..d04fc469
--- /dev/null
+++ b/chapter21/docs/encoding-reference.ja.md
@@ -0,0 +1,776 @@
+# 命令エンコーディングの参考資料
+
+[English](encoding-reference.md) | 日本語
+
+この文書は [Instruction encoding reference](encoding-reference.md) の日本語訳です。
+元の第21章の README から、詳細な説明を残したものです。
+コンパイラのパイプラインと実験については[章の概要](../README.ja.md)を参照してください。
+
+# 目次
+
+1. [命令エンコーディング](#命令エンコーディング)
+2. [基盤](#基盤)
+3. [エンディアン](#エンディアン)
+4. [RISCV](#riscv)
+ - [命令形式](#命令形式)
+ - [浮動小数点数](#浮動小数点数)
+ - [間接参照](#間接参照memop)
+ - [分岐](#分岐)
+ - [即値](#即値)
+ - [関数内の定数](#関数内の定数)
+5. [ARM](#arm)
+ - [レジスタ形式](#レジスタ形式)
+ - [即値シフト](#即値シフト)
+ - [論理演算の即値](#論理演算の即値)
+ - [浮動小数点数](#浮動小数点数-1)
+ - [大きな定数](#大きな定数)
+ - [関数定数](#関数定数)
+ - [条件フラグ](#条件フラグ)
+ - [間接参照](#間接参照memop-1)
+ - [分岐](#分岐-1)
+6. [AMD64 X86-64](#amd64-x86-64)
+ - [REX プレフィックス](#rex-プレフィックス)
+ - [MODR/M](#modrm)
+ - [SIB](#sib)
+ - [変位](#変位)
+ - [即値](#即値-1)
+ - [浮動小数点数](#浮動小数点数-2)
+ - [大きな定数](#大きな定数-1)
+ - [関数定数](#関数定数-1)
+ - [条件フラグ](#条件フラグ-1)
+7. [再配置](#再配置)
+
+この章では命令エンコーディングを追加します。命令エンコーディングとは、
+プロセッサの命令セットアーキテクチャ(ISA)が定義する特定のバイナリ形式で機械命令を表すことです。
+
+命令選択が完了したら、ELF オブジェクトファイルに書き出す前に、命令をエンコードします。
+
+曖昧さを避けるため、命令のエンコードに使う情報の出典を明示します。
+現在、次のアーキテクチャをサポートしています。
+
+### RISC-V:
+
+*riscv* では現在、[RVA23U64](https://msyksphinz-self.github.io/riscv-isadoc/html/) を対象にしています。
+
+### ARMV8/AArch64:
+
+*arm*(aarch64)では、この資料にまとめられた[エンコーディング規則](https://docsmirror.github.io/A64/20a23-06/index.html)を使います。
+*注*:サポートするのは64ビット ARM のエンコーディングだけです。
+
+### AMD64:
+
+*x86-64(amd64)* では、最新の Intel マニュアルの[エンコーディング規則](https://www.felixcloutier.com/x86/)を使います。
+
+--------------------------------
+
+## 命令エンコーディング
+
+## 基盤
+
+命令選択フェーズは、理想ノードから機械向けのノードを作ります。
+これらの機械向けノードには *encoding* 関数があり、CodeGen 内の Encoding ドライバから呼び出します。
+
+```java
+for( CFGNode bb : _code._cfg )
+ for( Node n : bb._outputs )
+ if( n instanceof MachNode mach ) {
+ int off = _bits.size();
+ mach.encoding(this);
+ _opLen[n._nid] = (byte)(_bits.size()-off);
+ }
+```
+
+選んだターゲットに応じて、リトルエンディアンまたはビッグエンディアンのエンコーディングに注意する必要があります。
+これは `add4` が扱い、正しい順序でビットストリームに追加します。
+現時点のビットストリームは、単純な ByteArrayOutputStream です。
+
+```java
+@Override public void encoding( Encoding enc ) {
+ enc.add4(0); // adds 4 bytes to the bitstream
+}
+```
+
+資料がビッグエンディアンでエンコーディングを示す *RISC-V* では、
+この関数がリトルエンディアンへの変換も行います。ほかのアーキテクチャでは変換は不要です。
+
+## エンディアン
+
+実際に使う ARM、RISC-V、x86 はすべてリトルエンディアンで、最下位バイトを先に格納します。
+したがって、命令エンコーディングがリトルエンディアン形式で生成されるようにします。
+
+```java
+// Little endian write of a 32b opcode
+public void add4( int op ) {
+ _bits.write(op );
+ _bits.write(op>> 8);
+ _bits.write(op>>16);
+ _bits.write(op>>24);
+}
+```
+
+たとえば、固定長命令の32ビットのエンコーディング *10110101100111101011001001101101* を考えます。
+
+最下位バイトを最初に追加し、次のバイトを追加していきます。
+```
+_bits.write(op );
+```
+
+`_bits.write()` が追加するのは最下位バイトだけです。
+値を右にシフトすると、次のバイトを最下位の位置へ移動でき、各バイトを順番に書き込めます。
+
+--------------------------------
+
+## RISCV
+
+RISCV の命令はすべて32ビット幅で、常にリトルエンディアンです。
+RISCV は RISC アーキテクチャなので「レジスタ間」の形式を優先し、エンコーディングは非常に規則的です。
+最も単純なエンコーディングであるため、RISCV から説明します。
+
+#### 命令形式
+
+##### R-TYPE
+
+このエンコーディング形式は、`AddRISC`、`MulRISC` などのレジスタ間の演算に使います。
+```java
+public static int r_type(int opcode, int rd, int func3, int rs1, int rs2, int func7) {
+ return (func7 << 25) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (rd << 7) | opcode;
+}
+```
+
+##### I-TYPE
+
+この配置は、`AddIRISC` などの即値形式に使います。
+
+```java
+ public static int i_type(int opcode, int rd, int func3, int rs1, int imm12) {
+ assert opcode >= 0 && rd >=0 && func3 >=0 && rs1 >=0 && imm12 >= 0; // Zero-extend by caller
+ return (imm12 << 20) | (rs1 << 15) | (func3 << 12) | (rd << 7) | opcode;
+ }
+```
+
+##### S-TYPE
+
+このエンコーディング形式は `StoreRISC` に使います。
+
+```java
+public static int s_type(int opcode, int func3, int rs1, int rs2, int imm12) {
+ assert imm12 >= 0; // Masked to high zero bits by caller
+ int imm_lo = imm12 & 0x1F;
+ int imm_hi = imm12 >> 5;
+ return (imm_hi << 25) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (imm_lo << 7) | opcode;
+}
+```
+
+##### B-TYPE
+
+このエンコーディングの配置は `BranchRISC` が使います。
+```java
+ // immf = first imm
+ // immd = second imm
+ // BRANCH
+public static int b_type(int opcode, int immf, int func3, int rs1, int rs2, int immd) {
+ return (immd << 25 ) | (rs2 << 20) | (rs1 << 15) | (func3 << 12) | (immf << 7) | opcode;
+ }
+```
+
+##### U-TYPE
+
+この配置は `AUIPC` と `LUI` に使います(上位即値は20ビットです)。
+
+```java
+ public static int u_type(int opcode, int rd, int imm20) {
+ return (imm20 << 12) | (rd << 7) | opcode;
+ }
+```
+
+##### J-TYPE
+
+無条件ジャンプ(`UJmpRISC`)に使います。
+```java
+ public static int j_type(int opcode, int rd, int imm20) {
+ return imm20 << 12 | rd << 7 | opcode;
+ }
+```
+
+#### 浮動小数点数
+
+浮動小数点定数のロードには、間接メモリロード(PC 相対)を使います。
+```
+AUIPC dst,#hi20_constant_pool
+Load dst,[dst+#low12_constant_pool]
+```
+
+#### 間接参照(MemOp)
+
+[ロード](https://msyksphinz-self.github.io/riscv-isadoc/html/rvi.html#lw):`lw rd,offset(rs1)`
+
+[ストア](https://msyksphinz-self.github.io/riscv-isadoc/html/rvi.html#sw):`sw rs2,offset(rs1)`
+
+#### 分岐
+
+RISC-V は、分岐命令が比較と分岐先を1つの命令に含むという点で特徴的です。
+
+#### 即値
+
+*ALU* 演算では、即値が符号付き12ビットに収まる場合だけ、即値形式をエンコードします。
+それ以外では Load Upper Immediate(上位20ビット)を使うか、両方を使います。
+
+```
+addiw a5,a5,123
+```
+
+これに対して、追加のロードを使う場合は次のようになります。
+```
+addw a5,a5,a4
+```
+
+### 浮動小数点定数
+
+- **定数プール**に格納します。
+- **PC 相対ロード**でアクセスします。
+
+### 整数定数
+
+- **12ビット定数**:`ADDI` を使います。
+- **20ビット定数**:`LUI` を使います。
+- **32ビット定数**:`LUI` と `ADDI` を組み合わせます。
+
+#### 関数内の定数
+
+RISC-V のコードで関数内の定数をロードするときは、現在の PC をレジスタに格納し、
+それを基底として定数へアクセスします。ただし、加算のような単純な算術演算のほうが
+メモリアクセスより速く効率的なので、通常はロードを避けるようにします。
+
+```java
+// auipc t0,0
+// addi t1,t0 + #0
+```
+
+--------------------------------
+
+## ARM
+
+Arm の命令はすべて32ビット幅で、常にリトルエンディアンです。
+Arm は RISC アーキテクチャなので、「レジスタ間」の形式を優先します。
+
+#### レジスタ形式
+
+レジスタ形式は、[シフト付きレジスタ](https://docsmirror.github.io/A64/2023-06/orr_log_shift.html)としてエンコードします。
+```
+orr reg1, reg2
+```
+```
+x0 = x0 | (x1 << 0)
+```
+
+ほかのレジスタ形式にも同じことが当てはまります。
+この共通性によって、レジスタ形式のエンコーディングを共通関数にまとめられます。
+
+```java
+short self = enc.reg(n);
+short reg1 = enc.reg(n.in(1));
+short reg2 = enc.reg(n.in(2));
+int body = r_reg(opcode, 0, reg2, 0, reg1, self);
+enc.add4(body);
+```
+
+レジスタ形式では *imm6* と *shift* は関係しないため、両方を0に設定します。
+
+### 即値シフト
+
+*asri、lsli、lsri* を指します。シフト量が0以上63以下なら、即値シフトとしてエンコードします。
+
+#### ASR(即値)
+
+即値の算術右シフトでは、*immr* をエンコードしたい即値に、imms を `63` = `111111` に設定します。
+これは [asri のエンコーディング](https://docsmirror.github.io/A64/2023-06/asr_sbfm.html)の規則に従っています。
+
+`sf` ビットはオペコードに含まれ、`N` は `imm_shift` 関数の実行後、暗黙にビットストリームへ追加されます。
+```java
+enc.add4(arm.imm_shift(0b100100110,_imm, 0b111111, rn, rd));
+```
+
+#### LSL(即値)
+
+```java
+// UBFM <Xd>, <Xn>, #(-<shift> MOD 64), #(63-<shift>)
+// immr must be (-<shift> MOD 64) = 64 - shift
+enc.add4(arm.imm_shift(0b110100110, 64 - _imm, (64 - _imm) - 1, rn, rd));
+```
+
+`_imm` は負にならず、0〜63の間にあるので、`64 - _imm` を `immr` の値として安全に使えます。
+この形式の即値を64から引いて、ビットを反転します。
+
+*imms* については、条件 *imms + 1 = immr* が成り立たなければなりません。
+値を代入すると、次のようになります。
+
+> imms + 1 = 64 - _imm;
+
+> imms = (64 - _imm) - 1;
+
+したがって、`imms` の値は `(64 - _imm) - 1` です。
+
+#### LSR(即値)
+
+*ASR* と同じです。
+
+#### 論理演算の即値
+
+論理演算の即値は *andi、xori、orri* を指します。
+
+```java
+// Can we encode this in ARM's 12-bit LOGICAL immediate form?
+// Some combination of shifted bit-masks.
+private static int imm12Logical(TypeInteger ti) {
+ if( !ti.isConstant() ) return -1;
+ if( !ti.isConstant() ) return -1;
+ long val = ti.value();
+ if (val == 0 || val == -1) return -1; // Special cases are not allowed
+ int immr = 0;
+ // Rotate until we have 0[...]1
+ while (val < 0 || (val & 1)==0) {
+ val = (val >>> 63) | (val << 1);
+ immr++;
+ }
+ int size = 32;
+ long pattern = val;
+ // Is upper half of pattern the same as the lower?
+ while ((pattern & ((1L<<size)-1)) == (pattern >> size)) {
+ // Then only take one half
+ pattern >>= size;
+ size >>= 1;
+ }
+ size <<= 1;
+ int imms = Long.bitCount(pattern);
+ // Pattern should now be zeros followed by ones 0000011111
+ if (pattern != (1L<<imms)-1) return -1;
+ imms--;
+ if (size == 64) return 0x1000 | immr << 6 | imms;
+ return (32-size)<<1 | immr << 6 | imms;
+}
+```
+
+imm12Logical は、エンコードできる場合は論理演算の12ビットの即値エンコーディングを返し、
+できない場合は -1 を返します。
+```java
+int imm12;
+return and.in(2) instanceof ConstantNode off &&
+off._con instanceof TypeInteger ti && (imm12 = imm12Logical(ti)) != -1
+? new AndIARM(and, imm12)
+```
+```java
+arm.imm_inst(enc,this,0b100100100,_imm);
+```
+
+#### 浮動小数点数
+
+x86 と同じように、*D* レジスタに対応する汎用レジスタ(GPR)のペアを得るために、オフセットを引く必要があります。
+```
+short dst = (short)(enc.reg(this ) - arm.D_OFFSET);
+```
+
+浮動小数点定数をロードするには、`ldr(literal)` 命令を使います。
+オフセットを PC レジスタに加算して、リテラルのアドレスを求めます。
+
+```java
+// Any number that can be expressed as +/-n * 2-r,where n and r are integers, 16 <= n <= 31, 0 <= r <= 7.
+int body = arm.load_pc(0b01011100, 0, dst);
+```
+
+#### 大きな定数
+
+##### 整数:mov(movz、movk、movn)をさまざまに組み合わせて、PC 相対ロードを避けられます。
+
+##### 浮動小数点数:PC 相対の *LDR(immediate, SIMD&FP)* 命令を使います。
+
+#### 関数定数
+
+関数定数をロードするには、現在の PC を x0 に格納し、それを使って定数へアクセスします。
+一般に、加算のほうが速いためロードを避けるようにします。
+```
+adrp x0, 0
+add x0, x0, 0
+```
+
+#### 条件フラグ
+
+arm では比較後に条件フラグを設定します。これは x86 と同じように動作します。
+
+```
+int square(int a) {
+// subs
+// cset w8, eq // eq = none
+bool da = a == 1;
+ // bne
+ if(da == 1) {
+ return 1;
+ }
+ return 2;
+}
+```
+
+arm の比較は `subss` で行い、2つのオペランドの減算とフラグの設定を同時に行います。
+`CSET` はフラグを調べ、その結果をレジスタに保存します。
+
+後で `b.ne` が条件付き分岐を実行しようとするときにも、このフラグに依存します。
+
+#### 間接参照(MemOp)
+
+Arm は次の間接参照形式をサポートします。
+
+[ロード](https://docsmirror.github.io/A64/2023-06/ldr_reg_gen.html):`ldr dst, [base + index]`。base と index はどちらもレジスタです。
+
+[ロード](https://docsmirror.github.io/A64/2023-06/ldr_imm_gen.html):`ldr dst, [base + #offset]`。base はレジスタ、offset は即値です。
+
+[ストア](https://docsmirror.github.io/A64/2023-06/str_reg_gen.html):`str dst, [base + index]`
+
+[ストア](https://docsmirror.github.io/A64/2023-06/strb_imm.html):`str dst, [base + #offset]`
+
+オフセットがレジスタの場合は、即値オフセット形式ではなくレジスタオフセット形式を使います。
+
+#### 分岐
+
+`B.cond` は、PC 相対オフセットのラベルへ[条件付き](https://developer.arm.com/documentation/dui0802/b/A32-and-T32-Instructions/Condition-codes?lang=en)で分岐します。
+
+> cond は標準的な条件のいずれかです。
+
+--------------------------------
+
+## AMD64 X86-64
+
+命令幅が固定の riscv アーキテクチャとは異なり、*x86-64* の命令は可変長です。
+これは *CISC(Complex Instruction Set Computer)* アーキテクチャで一般的であり、
+命令幅は1〜15バイトまで変わります。AMD64 は多くの間接アドレッシングモードをサポートするため、
+*CISC* の一般的な目標は、できるだけ少ないアセンブリの行数で処理を完了することです。
+
+### REX プレフィックス
+
+64ビット版の x86 を対象にしているため、このプレフィックスを扱う必要があります。
+一方、32ビットモードでは通常は不要です。
+
+一般に、次の場合は *REX* プレフィックスをエンコードしなければなりません。
+
+- 拡張レジスタ(R8〜R15、XMM8〜XMM15、YMM8〜YMM15、CR8〜CR15、DR8〜DR15)を使う。
+- オペランドサイズが64ビットで、命令の既定のオペランドサイズが64ビットではない(大部分の ALU 演算)。
+- RSI、RDI、RBP で8ビットのオペランドを使う。
+
+次の場合は *REX* プレフィックスをエンコードしてはなりません。
+
+- 上位バイトのレジスタ AH、CH、BH、DH を使う(現在の Simple では使っていません)。
+
+*注*:SSE 命令のエンコーディングでは、*REX* プレフィックス(0x40)を `SSE` プレフィックスの後に置く必要があります。
+それ以外の場合は無視されます。
+
+Simple では、REX プレフィックスをビットストリームの先頭に追加するだけです
+(SSE の浮動小数点命令を除く)。配置は次のとおりです。
+
+| **フィールド** | **長さ** | **説明** |
+|:---------:|:----------:|---------------------------------------------------------------------------------|
+| `0100` | 4ビット | 固定のビットパターン |
+| `W` | 1ビット | 1なら64ビット、それ以外なら32ビットのオペランドサイズを使う |
+| `R` | 1ビット | **MODRM.reg** フィールドの拡張 |
+| `X` | 1ビット | **SIB.index** フィールドの拡張 |
+| `B` | 1ビット | **MODRM.rm** または **SIB.base** フィールドの拡張 |
+
+```java
+ public static int REX_W = 0x48;
+```
+
+```java
+public static int rex(int reg, int ptr, int idx, boolean wide) {
+ // assuming 64 bit by default so: 0100 1000
+ int rex = wide ? REX_W : REX;
+ if( 8 <= reg && reg <= 15 ) rex |= 0b00000100; // REX.R
+ if( 8 <= ptr && ptr <= 15 ) rex |= 0b00000001; // REX.B
+ if( 8 <= idx && idx <= 15 ) rex |= 0b00000010; // REX.X
+ return rex;
+}
+
+ ...
+ enc.add1(x86_64_v2.rex(dst, src, 0));
+```
+
+`W` ビットを設定すると、`0b01001000 = 0x48;` になります。
+
+#### オペコード
+
+この場合、オペコードは実行する操作を指定する1バイトのフィールドです。
+```
+enc.add1(opcode()); // opcode
+```
+
+#### MODR/M
+
+| **フィールド** | **長さ** | **説明** |
+|:-------------:|:----------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **MODRM.mod** | 2ビット | 一般に、このフィールドが `b11` ならレジスタ直接アドレッシングモード、それ以外ならレジスタ間接アドレッシングモードを使う |
+| **MODRM.reg** | 3ビット | 2種類の値を取れる。<br><br>• 一部の命令が使う3ビットのオペコード拡張。ほかの命令と区別する以上の意味は持たない。<br><br>• 命令によってソースまたは宛先として使う3ビットのレジスタ参照。参照するレジスタは、命令のオペランドサイズと命令自体に依存する。`REX.R`、`VEX.~R`、`XOP.~R` フィールドによって最上位ビットを1つ追加し、合計4ビットに拡張できる |
+| **MODRM.rm** | 3ビット | 直接または間接のレジスタオペランドを指定し、任意で変位を伴う。`REX.B`、`VEX.~B`、`XOP.~B` フィールドによって最上位ビットを1つ追加し、合計4ビットに拡張できる |
+
+MODR/M バイトも同じように扱います。
+
+modrm バイトに最初に必要なのは、2ビットの mod です。
+
+##### mod
+
+mod の配置は次のとおりです。
+```
+public enum MOD {
+ INDIRECT, // [mem]
+ INDIRECT_disp8, // [mem + 0x12]
+ INDIRECT_disp32,// [mem + 0x12345678]
+ DIRECT, // mem
+};
+```
+
+##### reg
+
+reg フィールドは3ビットで、8個のレジスタから1個を選びます。レジスタを指定する場合、
+REX.R によって4ビットに拡張され、16個のレジスタから1個を選べます。
+
+##### r/m
+
+r/m フィールドは3ビットです。レジスタ直接指定モードでは、REX.B によって拡張され、
+16個のレジスタから1個を選べます。メモリ指定モードでは、アドレッシング形式または
+ベースレジスタを選びます。一部の値は SIB バイトや RIP 相対アドレッシングを指定します。
+
+```java
+public static int modrm(MOD mod, int reg, int m_r) {
+ // combine all the bits
+ return (mod.ordinal() << 6) | ((reg & 0x07) << 3) | m_r & 0x07;
+}
+```
+
+`modrm` 関数を使って `ModR/M` バイトを構築します。通常、これはオペコードの後に続きます。
+
+```
+enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src));
+```
+
+レジスタ形式のエンコーディングは、次のようになります。
+```
+short dst = enc.reg(this ); // src1
+short src = enc.reg(in(2)); // src2
+enc.add1(x86_64_v2.rex(dst, src, 0));
+enc.add1(opcode()); // opcode
+enc.add1(x86_64_v2.modrm(x86_64_v2.MOD.DIRECT, dst, src));
+```
+
+#### SIB
+
+SIB バイトには次のフィールドがあります。
+
+| **フィールド** | **長さ** | **説明** |
+|:-------------:|:----------:|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| **SIB.scale** | 2ビット | `SIB.index` のスケーリング係数を示す。表で使う **s** は 2^SIB.scale^ に等しい |
+| **SIB.index** | 3ビット | 使用するインデックスレジスタ。各レジスタの値は Registers を参照。`REX.X`、`VEX.~X`、`XOP.~X` フィールドによって最上位ビットを1つ追加し、合計4ビットに拡張できる |
+| **SIB.base** | 3ビット | 使用するベースレジスタ。各レジスタの値は Registers を参照。`REX.B`、`VEX.~B`、`XOP.~B` フィールドによって最上位ビットを1つ追加し、合計4ビットに拡張できる |
+
+MODR/M バイトと同じ配置です。
+```java
+public static int sib(int scale, int index, int base) {
+ return (scale << 6) | ((index & 0x07) << 3) | base & 0x07;
+}
+```
+
+```java
+enc.add1(x86_64_v2.sib(_scale, idx, x86_64_v2.RBP));
+```
+
+#### 変位
+
+変位には2つの形式があります。
+```java
+public enum MOD {
+INDIRECT, // [mem]
+INDIRECT_disp8, // [mem + 0x12]
+INDIRECT_disp32,// [mem + 0x12345678]
+DIRECT, // mem
+};
+```
+
+```java
+if( mod == MOD.INDIRECT_disp8 ) {
+ enc.add1(offset);
+} else if( mod == MOD.INDIRECT_disp32 ) {
+ enc.add4(offset);
+}
+```
+
+変位は即値の前に置きます。たとえば、次のようになります。
+```
+sub [eax + 2], 4
+```
+```
+bytes.write(0x83);
+bytes.write(modrm(INDIRECT8, 5, 0 /* eax */));
+bytes.write(2); // displcement goes first
+bytes.write(4);
+```
+
+#### 即値
+
+即値のバイト列は `ModR/M` バイトの後に置きます。必要に応じて4バイトの即値をエンコードできます。
+```java
+// immediate(4 bytes) 32 bits or (1 byte)8 bits
+if( x86_64_v2.imm8(_imm) ) enc.add1(_imm);
+else enc.add4(_imm);
+```
+
+#### 間接参照(MemOp)
+
+X86-64 は複数の間接アドレッシングモードをサポートします。
+
+#### 浮動小数点数
+
+浮動小数点演算には、XMM レジスタまたはメモリにあるスカラーの単精度浮動小数点値を操作する
+`SSE SIMD` 命令を使います。
+*注*:ALU 演算で XMM レジスタを使う場合、エンコーディングは非常に似ていますが、
+レジスタ番号から `XMM_OFFSET` を引く必要がある点が異なります。
+レジスタを連続した番号で数えているため、XMM レジスタに対応する GPR のペアを得るには、
+オフセットを引く必要があります。
+
+```java
+short dst = (short)(enc.reg(this ) - x86_64_v2.XMM_OFFSET);
+```
+
+```java
+public static int XMM_OFFSET = 16;
+```
+
+| **X.Reg** | **8ビット GP** | **16ビット GP** | **32ビット GP** | **64ビット GP** | **80ビット x87** | **64ビット MMX** | **128ビット XMM** | **256ビット YMM** | **16ビット Segment** | **32ビット Control** | **32ビット Debug** |
+|:--------:|:------------:|:-------------:|:-------------:|:-------------:|:-------------:|:-------------:|:--------------:|:--------------:|:-----------------:|:-----------------:|:---------------:|
+| `0.000 (0)` | AL | AX | EAX | RAX | ST0 | MMX0 | XMM0 | YMM0 | ES | CR0 | DR0 |
+
+`XMM0` が `RAX` に対応し、以降も同様であることがわかります。
+
+#### 大きな定数
+
+##### 整数:`MOV r64, imm64` 命令形式を使うだけです。
+
+##### 浮動小数点数:再配置を使い、メモリ内の定数を使います。
+
+#### 関数定数
+
+関数定数をロードするには lea を使います。これは、命令ポインタからの相対アドレスを指定したレジスタにロードします。
+`lea rax, [rip+disp32]`
+
+#### 条件フラグ
+
+FLAGS レジスタは、x86 CPU の現在の状態を保持するステータスレジスタです。
+
+条件付きコードのためにエンコードする必要のあるすべての命令を示す、単純な例を考えます。
+
+```
+int square(int a) {
+ // cmp DWORD PTR [rbp-0x8],0x1
+ // `sete al`
+ bool da = a == 1;
+
+ // cmp eax,0x1
+ if(da == 1) {
+ return 1;
+ }
+ return 2;
+}
+```
+
+まず、`a` と1を比較する比較命令が必要です。
+```
+cmp DWORD PTR [rbp-0x8],0x1
+```
+
+この比較命令が条件フラグを設定します。
+
+> 結果に従って CF、OF、SF、ZF、AF、PF フラグを設定します。
+
+続いて `sete` 命令を使い、比較の結果をレジスタへ保存します。
+
+`sete al`
+
+if 条件のために、最初の真偽値の結果に基づく追加の比較を行います。
+```
+ cmp eax,0x1
+```
+
+そして、比較(`a == 1`)が設定したフラグに依存する条件付き分岐を行います。
+```
+jne 1159 <square(int)+0x29>
+```
+
+--------------------------------
+
+## 再配置
+
+再配置によって、コードを新しいコードオフセットへ*移動*できます。
+コードは、ほかのコードやデータを参照することがよくあります。
+`call` 命令はサブルーチンを、`branches` はほかの命令を対象とし、
+大きな定数は多くの場合*定数プール*からロードします。
+
+### 局所的な再配置
+
+局所的な再配置は、局所的または自己参照的なコードを修正します。最も一般的なのは分岐先です。
+`BAOS`(Byte Array Output Stream)に命令を書き込む際、後に続く命令へ向かう前方分岐のオフセットは未知です。
+そのオフセットは、分岐と分岐先の間にあるエンコーディングのサイズに依存します。
+`riscv` と `arm` のターゲットでは簡単に見えます(命令は4バイトなので数えればよい)……。
+しかし、複数の命令を使うエンコーディングもあるため、実際には4バイトとは限りません。
+X86 では命令長が擬似的に不規則に見えるほど多様なので、オペコードの長さを求めること自体が、
+オペコードを書き出すのと同じくらい難しくなります。
+
+X86 には、短形式と長形式の分岐という追加の複雑さもあります。
+分岐先が符号付きバイトの範囲(+/-127)にあるなら2バイトの分岐エンコーディングを、
+それ以外では6バイトのエンコーディングを使います。
+Simple には、分岐を縮め、できるだけ2バイト形式を使うパスがあります。
+ただし、このパスはコードをずらす必要があり、その結果、ほかの分岐オフセットもすべて変わります。
+この「圧縮」パスは実際には、すべての分岐が2バイト形式を使えると楽観的に仮定して始め、
+必要に応じて分岐を拡張します(したがって、実際にはコードを*拡張*します)。
+
+コードの「形」が最終的に決まったら、局所的な再配置パスを実行して自己参照をすべて更新します。
+基本的には、バイト配列内の分岐オフセットを実際の値で上書きします。
+
+このパスの終了時点で、コードはあるオフセット(通常は0)で局所的に正しくなります。
+しかし、これで終わりではありません。別のコンパイルで生成されたコードと*リンク*することが多く、
+その際にもさまざまなオフセットを調整する必要があります。
+
+### 大域的な再配置
+
+あるコンパイル単位のコードから、別のコンパイル単位のコードを呼びたい場合、*大域的な再配置*が必要です。
+よくある例は、*ローダー*が *ELF* ファイルをロードすることです。
+通常は新しいプログラムの実行ごとに起こり、再配置情報をディスク(たとえば ELF ファイル内)に保存しておく必要があります。
+JIT システムでも、異なるコンパイルをまたいで同じことが必要ですが、再配置情報はメモリに保持できます。
+
+#### 再配置の整合性を保つ
+
+再配置をディスクに書き込めるので、ディスク形式、ローダー、「コードの形」がすべて一致しなければなりません。
+あるコンパイル単位から別の単位を呼ぶ場合、たとえばプログラムが `libc` の `malloc` を呼ぶ場合を考えます。
+呼び出し元は Simple の汎用 `CallNode` の機械固有版を使い、呼び出し先は C でコンパイルされたコードです。
+ロード中に、ローダーが `call` と `libc` の配置を決めます。
+2つの異なるコードブロックを何らかの順序で(通常は多くのほかのブロックとともに)メモリに書き込みます。
+そこで、`call` の呼び出し先を、`libc` のコードブロック内の `malloc` に修正する必要があります。
+
+X86 の外部呼び出しは、1バイトのオペコードと4バイトの PC 相対宛先アドレスからなる5バイト命令です。
+必要な修正値は、X86 固有の `call` 命令の*末尾*から `malloc` の先頭までの差であり、
+`call` の最後の4バイトに直接書き込みます。ELF ファイル内のエンコーディングの種類は、これを記述しなければなりません。
+
+RISCV の外部呼び出しは、ビットを分担する2つの4バイト命令でエンコードします。
+`LUI` が宛先の上位20ビットをロードし、`JALR` が下位12ビットを加算します(32ビットの絶対宛先範囲)。
+`LUI` を `AUIPC` に置き換えると、32ビットの PC 相対範囲を得られます。
+修正では、一方の命令の20ビットと、もう一方の命令の12ビットを更新します。
+ここでも ELF ファイルのエンコーディングの種類が、この方法を記述する必要があります。
+X86 式の修正をここに使うと、誤ったビットを壊し、プログラムが動かなくなります。
+
+#### 大きな定数
+
+大きな定数とは、レジスタへ簡単に直接ロードできず、代わりにメモリからロードする定数です。
+セキュリティ上の理由で、*実行*権限ではなく*読み取り専用*権限などを付けた別のアドレス空間に置くことがよくあります。
+そのため、コードに対する最終的な相対アドレスは、配置によって変わります。
+これは、コンパイル単位をまたぐ呼び出しと同じです。
+
+大きな定数は、コンパイル単位間で共有することもできます(HPC コードで `pi` を繰り返し使う場合など)。
+共有すると、キャッシュの占有量を減らせます。
+いずれにせよ、コードと定数の配置が決まったら、正しいオフセットからロードするようにコードを修正する必要があります。
+上の `call` の例のように、ロード命令の種類と修正方法の種類が一致しなければなりません。
+X86 では、その種類によって4バイトまたは8バイトのアドレスを使います。
+RISCV では、おそらく `LUI` と `Load` の何らかの組み合わせで、即値を20/12ビットに分けます。
+また、RISCV では同じ `LUI` で定数プールの上位20ビットを「共有」し、
+同じプールの異なる定数には異なるロードを使いたいでしょう。ARM には、さらに別の方法があります。
diff --git a/chapter21/docs/encoding-reference.md b/chapter21/docs/encoding-reference.md
index e273caec..187a965e 100644
--- a/chapter21/docs/encoding-reference.md
+++ b/chapter21/docs/encoding-reference.md
@@ -1,5 +1,7 @@
# Instruction encoding reference
+English | [日本語](encoding-reference.ja.md)
+
Detailed notes retained from the original Chapter 21 README.
See the [chapter overview](../README.md) for the compiler pipeline and experiments.
@@ -11,37 +13,39 @@ See the [chapter overview](../README.md) for the compiler pipeline and experimen
4. [RISCV](#riscv)
- [Instruction formats](#instruction-formats)
- [Float](#float)
- - [Indirect](#indirectmemop-2)
+ - [Indirect](#indirectmemop)
- [Branch](#branch)
- - [Function Constant](#function-constant)
- - [LUI](#lui)
- - [Large constants](#large-constants)
+ - [Immediates](#immediates)
+ - [Float Constants](#float-constants)
+ - [Int Constants](#int-constants)
+ - [Function Constants](#function-constants)
5. [ARM](#arm)
- [Reg-form](#reg-form)
- [Shift immediates](#shift-immediates)
- - [asri](#asrimmediate)
- - [LSL(immediate)](#lslimmediate)
- - [LSR(immediate)](#lsrimmediate)
-
- [Logical Immediates](#logical-immediates)
- - [Float](#float)
+ - [Float](#float-1)
+ - [Large constants](#large-constants)
- [Function constant](#function-constant)
- - [Immediate](#immediate)
- [Conditional flags](#conditional-flags)
- [Indirect](#indirectmemop-1)
- - [Branching](#branching-)
- - [Rip relative](#rip-relative)
- - [Compare](#compare)
-6. [AMD64](#amd64)
+ - [Branching](#branching)
+6. [AMD64 X86-64](#amd64-x86-64)
- [REX PREFIX](#rex-prefix)
- - [Large constants](#large-constants)
+ - [Opcode](#opcode)
- [MODR/M](#modrm)
- [SIB](#sib)
- [Displacement](#displacement)
- [Immediate](#immediate)
- - [Float](#float)
- - [Indirect](#indirectmemop)
- - [Conditional flags](#conditional-flags)
+ - [Indirect](#indirectmemop-2)
+ - [Float](#float-2)
+ - [Large constants](#large-constants-1)
+ - [Function constant](#function-constant-1)
+ - [Conditional flags](#conditional-flags-1)
+7. [Relocation](#relocation)
+ - [Local Relocation](#local-relocation)
+ - [Global Relocation](#global-relocation)
+ - [Getting Relocations to All Agree](#getting-relocations-to-all-agree)
+ - [Large Constants](#large-constants-2)
This chapter will add instruction encodings. Instruction encoding refers to
@@ -431,7 +435,8 @@ Arm supports the following indirect forms:
[Store](https://docsmirror.github.io/A64/2023-06/strb_imm.html): `str dst, [base + #offset]`
-If the offset is not a con
+For a register offset, use the register-offset form rather than the immediate-offset form.
+
#### Branching
`B.cond` - branch [conditionally](https://developer.arm.com/documentation/dui0802/b/A32-and-T32-Instructions/Condition-codes?lang=en) to a label at a PC-relative offset.
@@ -466,7 +471,7 @@ A *REX* prefix must not be encoded when:
the `SSE` prefix. In all other cases, it is ignored.
In Simple, the REX prefix is just appended to the beginning of the bit stream
-(except SEE float instructions). The layout is the following:
+(except SSE float instructions). The layout is the following:
| **Field** | **Length** | **Description** |
|:---------:|:----------:|---------------------------------------------------------------------------------|
@@ -530,11 +535,14 @@ public enum MOD {
```
##### reg
-The reg field is a 3 bit field capable of encoding 15 different registers.
+The reg field has 3 bits, selecting one of 8 registers. When it names a
+register, REX.R extends it to 4 bits, selecting one of 16 registers.
##### r/m
-The rm field specifies a direct or indirect register operand and is capable of encoding 15 different registers.
+The r/m field has 3 bits. In register-direct mode, REX.B extends it to
+select one of 16 registers. In memory modes, r/m selects the addressing form
+or base register; some values select a SIB byte or RIP-relative addressing.
```java
@@ -622,7 +630,7 @@ X86-64 support multiple indirect addressing modes:
#### Float
-For float operations we use `SEE SIMD` instructions that operate on scalar single precision floating0-point values located in the
+For float operations we use `SSE SIMD` instructions that operate on scalar single precision floating-point values located in the
XMM registers or memory.
*Note*: When using XMM registers for ALU operations, the encoding is really similar with the exception that we need
to subtract the `XMM_OFFSET` from the register number.