SlideShare a Scribd company logo
Min-Yih “Min” Hsu @ LLVM Dev Meeting 2021
Handling inline assembly 

in Clang and LLVM
about:me
“Min” Hsu
• Computer Science PhD Candidate in
University of California, Irvine

• Code owner of M68k LLVM backend

• Author of book “LLVM Techniques,
Tips and Best Practices” (2021)
2
How Inline Assembly is
Processed in Clang & LLVM
3
Inline Assembly
4
Introduction to inline assembly
5
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
5
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
5
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


foo:


pushq %rbp


movq %rsp, %rbp


...


testb $1, -9(%rbp)


je LBB0_2


## InlineAsm Start


movl %eax, %ebx


addl %ebx, %esi


## InlineAsm End


jmp LBB0_3


LBB0_2:


movl -8(%rbp), %eax


addl $87, %eax


movl %eax, -8(%rbp)


LBB0_3:


popq %rbp


retq
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
5
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


foo:


pushq %rbp


movq %rsp, %rbp


...


testb $1, -9(%rbp)


je LBB0_2


## InlineAsm Start


movl %eax, %ebx


addl %ebx, %esi


## InlineAsm End


jmp LBB0_3


LBB0_2:


movl -8(%rbp), %eax


addl $87, %eax


movl %eax, -8(%rbp)


LBB0_3:


popq %rbp


retq
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Why use inline assembly?
6
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Why use inline assembly?
6
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


Performance critical code
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Why use inline assembly?
6
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


Performance critical code
Low-level code

e.g. Kernel, firmware
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Why use inline assembly?
6
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


Performance critical code
Low-level code

e.g. Kernel, firmware
Compiler optimizations “barrier”
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
7
asm (“movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
7
asm (“movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);
Assembly code (template)
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
7
asm (“movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);
Assembly code (template)
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Output operands
8
int out_var;


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %0"


: "=r"(out_var) ::);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Output operands
8
int out_var;


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %0"


: "=r"(out_var) ::);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Output operands
8
int out_var;


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %0"


: "=r"(out_var) ::);
Operand constraints
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Operands constraints
9
int out_var;


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %0"


: "=r"(out_var) ::);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Operands constraints
9
int out_var;


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %0"


: "=r"(out_var) ::);
* x86_64 assembly w/ AT&T syntax
## InlineAsm Start


movl %eax, %ebx


addl %ebx, %esi


## InlineAsm End
Introduction to inline assembly
Operands constraints
9
int out_var;


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %0"


: "=r"(out_var) ::);
* x86_64 assembly w/ AT&T syntax
## InlineAsm Start


movl %eax, %ebx


addl %ebx, %esi


## InlineAsm End
## InlineAsm Start


movl %eax, %ebx


addl %ebx, -8(%ebp)


## InlineAsm End
Operand constraints
10
Operand constraints
10
• ‘r’ : General-purpose register operand

• ‘i’ : Immediate integer operand

• ‘m’ : Memory operand w/ arbitrary addressing mode
Target-independent Constraints
Operand constraints
10
• ‘r’ : General-purpose register operand

• ‘i’ : Immediate integer operand

• ‘m’ : Memory operand w/ arbitrary addressing mode
Target-independent Constraints
• ‘a’ : AL / AH / EAX / RAX

• ‘I’ : Integer constant in the range of [0, 31]

• ‘N’ : Unsigned 8-bit integer constant
X86 Constraints
Operand constraints
10
• ‘r’ : General-purpose register operand

• ‘i’ : Immediate integer operand

• ‘m’ : Memory operand w/ arbitrary addressing mode
Target-independent Constraints
• ‘a’ : AL / AH / EAX / RAX

• ‘I’ : Integer constant in the range of [0, 31]

• ‘N’ : Unsigned 8-bit integer constant
X86 Constraints
• ‘J’ : 16-bit signed integer constant

• “Ci” : Constant integers

• “Cj” : Constant signed integers that do NOT
fi
t in 16 bits
M68k Constraints
Operand constraints
10
• ‘r’ : General-purpose register operand

• ‘i’ : Immediate integer operand

• ‘m’ : Memory operand w/ arbitrary addressing mode
Constraint Modifers
Target-independent Constraints
• ‘=‘ : This is an output operand

• ‘+’ : This is an input / output operand
• ‘a’ : AL / AH / EAX / RAX

• ‘I’ : Integer constant in the range of [0, 31]

• ‘N’ : Unsigned 8-bit integer constant
X86 Constraints
• ‘J’ : 16-bit signed integer constant

• “Ci” : Constant integers

• “Cj” : Constant signed integers that do NOT
fi
t in 16 bits
M68k Constraints
Introduction to inline assembly
Input operands
11
int out_var, in_var;


asm ("movl %1, %%ebxn"


"addl %%ebx, %0"


: “=r"(out_var)


: “r”(in_var) :);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Input operands
11
int out_var, in_var;


asm ("movl %1, %%ebxn"


"addl %%ebx, %0"


: “=r"(out_var)


: “r”(in_var) :);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Input operands
11
int out_var, in_var;


asm ("movl %1, %%ebxn"


"addl %%ebx, %0"


: “=r"(out_var)


: “r”(in_var) :);
Operand constraints
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Clobber operands
12
int out_var, in_var;


asm ("movl %1, %%ebxn"


"addl %%ebx, %0"


: “=r"(out_var)


: “r”(in_var)


: “ebx”);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Clobber operands
12
int out_var, in_var;


asm ("movl %1, %%ebxn"


"addl %%ebx, %0"


: “=r"(out_var)


: “r”(in_var)


: “ebx”);
* x86_64 assembly w/ AT&T syntax
For more inline assembly syntax…
13
https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
Handling inline assembly in Clang & LLVM
Background
14
Handling inline assembly in Clang & LLVM
Background
• Most parts of an inline assembly string are simply copied into the
fi
nal
assembly
fi
le
14
Handling inline assembly in Clang & LLVM
Background
• Most parts of an inline assembly string are simply copied into the
fi
nal
assembly
fi
le
• LLVM needs to “glue” inline assembly operands with the surrounding code
14
Handling inline assembly in Clang & LLVM
Background
• Most parts of an inline assembly string are simply copied into the
fi
nal
assembly
fi
le
• LLVM needs to “glue” inline assembly operands with the surrounding code
• Lots of target-speci
fi
c logics

• In both Clang and the backend
14
Handling inline assembly in Clang & LLVM
Background
• Most parts of an inline assembly string are simply copied into the
fi
nal
assembly
fi
le
• LLVM needs to “glue” inline assembly operands with the surrounding code
• Lots of target-speci
fi
c logics

• In both Clang and the backend
• Target-speci
fi
c callbacks are scattered in the codebase

• Documentation for this part is a little…shy
14
Goals
15
Goals
Learning inline assembly workflow in Clang / LLVM
15
Goals
Learning inline assembly workflow in Clang / LLVM
A simple guide for backend developers to add inline assembly support
15
Outline of target-specific logics in each stage
16
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
Outline of target-specific logics in each stage
16
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
• Simple validation on operand constraints

• Converting constraints
Outline of target-specific logics in each stage
16
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
• Simple validation on operand constraints

• Converting constraints
• Classifying constraints

• Constraint validations

• Lowering the operands
Outline of target-specific logics in each stage
16
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
• Simple validation on operand constraints

• Converting constraints
• Classifying constraints

• Constraint validations

• Lowering the operands
Print out di
ff
erent types of operands
Outline of target-specific logics in each stage
17
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
• Simple validation on operand constraints

• Converting constraints
• Classifying constraints

• Constraint validations

• Lowering the operands
Print out di
ff
erent types of operands
Operand constraint validations in Clang
18
bool TargetInfo::validateAsmConstraint(const char *&, ConstraintInfo &) const;
Operand constraint validations in Clang
18
bool TargetInfo::validateAsmConstraint(const char *&, ConstraintInfo &) const;
bool M68kTargetInfo::validateAsmConstraint(const char *&Name, ConstraintInfo &info) const {


switch (*Name) {


case 'a': // address register


info.setAllowsRegister();


return true;


}


…


}
Operand constraint validations in Clang
19
bool TargetInfo::validateAsmConstraint(const char *&, ConstraintInfo &) const;
bool M68kTargetInfo::validateAsmConstraint(const char *&Name, ConstraintInfo &info) const {


switch (*Name) {


case 'a': // address register


info.setAllowsRegister();


return true;


case 'J': // constant signed 16-bit integer


info.setRequiresImmediate(std::numeric_limits<int16_t>::min(),


std::numeric_limits<int16_t>::max());


return true;


}


…


}
Operand constraint validations in Clang
Limitation on immediate value validations
20
void foo() {


int32_t x;


asm ("move.l %0, %%d1" : : "J" (x));


}
* M68k assembly w/ Motorola syntax
Operand constraint validations in Clang
Limitation on immediate value validations
20
void foo() {


int32_t x;


asm ("move.l %0, %%d1" : : "J" (x));


}
Constant signed 16-bit integer
* M68k assembly w/ Motorola syntax
Operand constraint validations in Clang
Limitation on immediate value validations
20
void foo() {


int32_t x;


asm ("move.l %0, %%d1" : : "J" (x));


}
$ clang -target m68k -fsyntax-only foo.c


# No error


$ clang -target m68k -emit-llvm foo.c


# No error
Constant signed 16-bit integer
* M68k assembly w/ Motorola syntax
Operand constraint validations in Clang
Limitation on immediate value validations
20
void foo() {


int32_t x;


asm ("move.l %0, %%d1" : : "J" (x));


}
$ clang -target m68k -fsyntax-only foo.c


# No error


$ clang -target m68k -emit-llvm foo.c


# No error
Constant signed 16-bit integer
$ clang -target m68k -S foo.c


error: constraint 'J' expects an integer constant expression
* M68k assembly w/ Motorola syntax
Inline assembly in LLVM IR
21
void foo() {


const int x = 87;


asm ("move.l %0, %%d1" : : "Ci" (x) : "d1");


}
C/C++
* M68k assembly w/ Motorola syntax
Inline assembly in LLVM IR
21
void foo() {


const int x = 87;


asm ("move.l %0, %%d1" : : "Ci" (x) : "d1");


}
C/C++
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
LLVM IR
* M68k assembly w/ Motorola syntax
Inline assembly in LLVM IR
21
void foo() {


const int x = 87;


asm ("move.l %0, %%d1" : : "Ci" (x) : "d1");


}
C/C++
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
LLVM IR
* M68k assembly w/ Motorola syntax
Inline assembly in LLVM IR
21
void foo() {


const int x = 87;


asm ("move.l %0, %%d1" : : "Ci" (x) : "d1");


}
C/C++
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
LLVM IR
* M68k assembly w/ Motorola syntax
Inline assembly in LLVM IR
21
void foo() {


const int x = 87;


asm ("move.l %0, %%d1" : : "Ci" (x) : "d1");


}
C/C++
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
LLVM IR
* M68k assembly w/ Motorola syntax
Inline assembly in LLVM IR
21
void foo() {


const int x = 87;


asm ("move.l %0, %%d1" : : "Ci" (x) : "d1");


}
C/C++
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
LLVM IR
* M68k assembly w/ Motorola syntax
Outline of target-specific logics in each stage
22
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
• Simple validation on operand constraints

• Converting constraints
• Classifying constraints

• Constraint validations

• Lowering the operands
Print out di
ff
erent types of operands
23
LLVM IR call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
23
LLVM IR
SelectionDAG
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
t2: ch,glue = inlineasm ... "move.l $0, %d1", ...,


TargetConstant:i32<87>, Register:i16 $d1
23
LLVM IR
SelectionDAG
Machine IR
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
t2: ch,glue = inlineasm ... "move.l $0, %d1", ...,


TargetConstant:i32<87>, Register:i16 $d1
23
LLVM IR
SelectionDAG
Machine IR
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
t2: ch,glue = inlineasm ... "move.l $0, %d1", ...,


TargetConstant:i32<87>, Register:i16 $d1
Constraint classification
24
TargetLowering::ConstraintType


M68kTargetLowering::getConstraintType(StringRef Constraint) const;
Constraint classification
24
TargetLowering::ConstraintType


M68kTargetLowering::getConstraintType(StringRef Constraint) const;
Return:
Constraint classification
24
TargetLowering::ConstraintType


M68kTargetLowering::getConstraintType(StringRef Constraint) const;
• C_RegisterClass
Return:
Ex: ’r’
Constraint classification
24
TargetLowering::ConstraintType


M68kTargetLowering::getConstraintType(StringRef Constraint) const;
• C_RegisterClass
• C_Immediate
Return:
Ex: ’r’
Ex: ‘i’
Constraint classification
24
TargetLowering::ConstraintType


M68kTargetLowering::getConstraintType(StringRef Constraint) const;
• C_RegisterClass
• C_Immediate
• C_Memory
Return:
Ex: ’r’
Ex: ‘i’
Ex: ‘m’, ‘Q’ (AArch64)
Constraint classification
24
TargetLowering::ConstraintType


M68kTargetLowering::getConstraintType(StringRef Constraint) const;
• C_RegisterClass
• C_Immediate
• C_Memory
• C_Other
Return:
Ex: ’r’
Ex: ‘i’
Ex: ‘m’, ‘Q’ (AArch64)
Lowering operands
25
getConstraintType
Method in XXXTargetLowering
Method in XXXISelDAGToDAG
Will be invoked
Lowering operands
25
getConstraintType
getRegForInlineAsmConstraint
C_RegisterClass
Method in XXXTargetLowering
Method in XXXISelDAGToDAG
Will be invoked
Lowering operands
25
getConstraintType
getRegForInlineAsmConstraint
LowerAsmOperandForConstraint
C_RegisterClass
C_Immediate / C_Other
Method in XXXTargetLowering
Method in XXXISelDAGToDAG
Will be invoked
Lowering operands
25
getConstraintType
getRegForInlineAsmConstraint
getInlineAsmMemConstraint
LowerAsmOperandForConstraint
C_RegisterClass
C_Immediate / C_Other
C_Memory
Method in XXXTargetLowering
Method in XXXISelDAGToDAG
Will be invoked
Lowering operands
25
getConstraintType
getRegForInlineAsmConstraint
getInlineAsmMemConstraint
LowerAsmOperandForConstraint
SelectInlineAsmMemoryOperand
C_RegisterClass
C_Immediate / C_Other
C_Memory
Method in XXXTargetLowering
Method in XXXISelDAGToDAG
Will be invoked
Lowering register operands
26
std::pair<unsigned, const TargetRegisterClass *>


TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,


StringRef Constraint,


MVT VT) const;
Lowering register operands
26
std::pair<unsigned, const TargetRegisterClass *>


TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,


StringRef Constraint,


MVT VT) const;
A speci
fi
c register or 0 if not applicable
Lowering register operands
26
std::pair<unsigned, const TargetRegisterClass *>


TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,


StringRef Constraint,


MVT VT) const;
A speci
fi
c register or 0 if not applicable Valid register class to select from
Lowering register operands
M68k Example
27
std::pair<unsigned, const TargetRegisterClass *>


M68kTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *,


StringRef Constraint,


MVT VT) const {


switch (Constraint[0]) {


case 'a':


switch (VT.SimpleTy) {


case MVT::i16:


return std::make_pair(0U, &M68k::AR16RegClass);


}


}


}
Lowering register operands
M68k Example
27
std::pair<unsigned, const TargetRegisterClass *>


M68kTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *,


StringRef Constraint,


MVT VT) const {


switch (Constraint[0]) {


case 'a':


switch (VT.SimpleTy) {


case MVT::i16:


return std::make_pair(0U, &M68k::AR16RegClass);


}


}


}
Lowering register operands
X86 Example
28
std::pair<unsigned, const TargetRegisterClass *>


X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *,


StringRef Constraint,


MVT VT) const {


...


if (Constraint == "Yz") {


// First SSE register (%xmm0).


switch (VT.SimpleTy) {


case MVT::f32:


case MVT::i32:


return std::make_pair(X86::XMM0, &X86::FR32RegClass);


}


}


}
Lowering register operands
X86 Example
28
std::pair<unsigned, const TargetRegisterClass *>


X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *,


StringRef Constraint,


MVT VT) const {


...


if (Constraint == "Yz") {


// First SSE register (%xmm0).


switch (VT.SimpleTy) {


case MVT::f32:


case MVT::i32:


return std::make_pair(X86::XMM0, &X86::FR32RegClass);


}


}


}
Lowering immediate / other operands
29
void TargetLowering::


LowerAsmOperandForConstraint(SDValue Op,


std::string &Constraint,


std::vector<SDValue> &Ops,


SelectionDAG &DAG) const;
Lowering immediate / other operands
M68k Example
30
void M68kTargetLowering::LowerAsmOperandForConstraint(SDValue Op,


std::string &Constraint,


std::vector<SDValue> &Ops,


SelectionDAG &DAG) const {


switch (Constraint[0]) {


case 'J': { // constant signed 16-bit integer


}


}


}
Lowering immediate / other operands
M68k Example
31
void M68kTargetLowering::LowerAsmOperandForConstraint(SDValue Op,


std::string &Constraint,


std::vector<SDValue> &Ops,


SelectionDAG &DAG) const {


switch (Constraint[0]) {


case 'J': { // constant signed 16-bit integer


if (auto *C = dyn_cast<ConstantSDNode>(Op)) {


int64_t Val = C->getSExtValue();


}


}


}


}
Lowering immediate / other operands
M68k Example
32
void M68kTargetLowering::LowerAsmOperandForConstraint(SDValue Op,


std::string &Constraint,


std::vector<SDValue> &Ops,


SelectionDAG &DAG) const {


switch (Constraint[0]) {


case 'J': { // constant signed 16-bit integer


if (auto *C = dyn_cast<ConstantSDNode>(Op)) {


int64_t Val = C->getSExtValue();


if (isInt<16>(Val)) {


Ops.push_back(Op);


return;


}


}


}


}


}
Lowering memory operands
Memory constraint classi
fi
cation
33
unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const;
Lowering memory operands
Memory constraint classi
fi
cation
33
unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const;
Return:
Lowering memory operands
Memory constraint classi
fi
cation
33
unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const;
• InlineAsm::Constraint_m


• InlineAsm::Constraint_o


• InlineAsm::Constraint_v
Return:
Generic memory constraints
Lowering memory operands
Memory constraint classi
fi
cation
33
unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const;
• InlineAsm::Constraint_m


• InlineAsm::Constraint_o


• InlineAsm::Constraint_v
Return:
• InlineAsm::Constraint_A


• InlineAsm::Constraint_Q
Generic memory constraints
Target-speci
fi
c constraints!
Lowering memory operands
Memory constraint classi
fi
cation — RISCV Example
34
unsigned RISCVTargetLowering::


getInlineAsmMemConstraint(StringRef ConstraintCode) const {


switch (ConstraintCode[0]) {


case 'A':


return InlineAsm::Constraint_A;


...


}


...


}
Lowering memory operands
35
bool


SelectionDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,


unsigned ConstraintID,


std::vector<SDValue> &OutOps);
Lowering memory operands
RISCV Example
36
bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand(


const SDValue &Op, unsigned ConstraintID,


std::vector<SDValue> &OutOps) {


switch (ConstraintID) {


case InlineAsm::Constraint_A:


OutOps.push_back(Op);


return false;


default:


break;


}




return true;


}
Lowering memory operands
Complex addressing mode — X86 Example
37
bool X86DAGToDAGISel::


SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,


std::vector<SDValue> &OutOps) {


SDValue Op0, Op1, Op2, Op3, Op4;




switch (ConstraintID) {


case InlineAsm::Constraint_m: // memory


if (!selectAddr(nullptr, Op, Op0, Op1, Op2, Op3, Op4))


return true;


break;


}


OutOps.insert(OutOps.end(), {Op0, Op1, Op2, Op3, Op4});


return false;


}
Lowering memory operands
Complex addressing mode — X86 Example
37
bool X86DAGToDAGISel::


SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,


std::vector<SDValue> &OutOps) {


SDValue Op0, Op1, Op2, Op3, Op4;




switch (ConstraintID) {


case InlineAsm::Constraint_m: // memory


if (!selectAddr(nullptr, Op, Op0, Op1, Op2, Op3, Op4))


return true;


break;


}


OutOps.insert(OutOps.end(), {Op0, Op1, Op2, Op3, Op4});


return false;


}
Outline of target-specific logics in each stage
38
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
• Simple validation on operand constraints

• Converting constraints
• Classifying constraints

• Constraint validations

• Lowering the operands
Print out di
ff
erent types of operands
39
Machine IR
INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
39
Machine IR
INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
39
Machine IR
INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
move.l #87, %d1
39
Machine IR
INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
move.l 87, %d1
move.l #87, %d1
Printing asm operands
40
bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,


const char *, raw_ostream &O);


bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,


const char *, raw_ostream &O);
Printing non-memory asm operands
M68k Example
41
void M68kAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,


raw_ostream &OS) {


const MachineOperand &MO = MI->getOperand(OpNum);


switch (MO.getType()) {


case MachineOperand::MO_Register:


OS << "%" << M68kInstPrinter::getRegisterName(MO.getReg());


break;


case MachineOperand::MO_Immediate:


OS << '#' << MO.getImm();


break;


...


}


}
Printing non-memory asm operands
M68k Example
41
void M68kAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,


raw_ostream &OS) {


const MachineOperand &MO = MI->getOperand(OpNum);


switch (MO.getType()) {


case MachineOperand::MO_Register:


OS << "%" << M68kInstPrinter::getRegisterName(MO.getReg());


break;


case MachineOperand::MO_Immediate:


OS << '#' << MO.getImm();


break;


...


}


}
Printing non-memory asm operands
M68k Example
41
void M68kAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,


raw_ostream &OS) {


const MachineOperand &MO = MI->getOperand(OpNum);


switch (MO.getType()) {


case MachineOperand::MO_Register:


OS << "%" << M68kInstPrinter::getRegisterName(MO.getReg());


break;


case MachineOperand::MO_Immediate:


OS << '#' << MO.getImm();


break;


...


}


}
Epilogue
Advanced topics
Converting constraints in Clang

Asm dialects

Operand modifiers

Multi-alternative constraints

Constraint weights

Turn (simple) inline asm into LLVM code
43
Thank you!
44
GitHub: mshockwave

Email: minyihh@uci.edu 

25% book discount code: 25MINLLVM
Redeem:
Nov 15 ~ Nov 20, 2021
Appendix
Converting constraints in Clang
46
An operand constraint is assumed to have only a single character by default
Converting constraints in Clang
46
An operand constraint is assumed to have only a single character by default
Example: “Ci”
Converting constraints in Clang
46
An operand constraint is assumed to have only a single character by default
Example: “Ci” -> “^Ci”
Converting constraints in Clang
46
std::string


M68kTargetInfo::convertConstraint(const char *&Constraint) const override {


if (*Constraint == 'C')


// Two-character constraint; add "^" hint for later parsing


return std::string("^") + std::string(Constraint++, 2);


return std::string(1, *Constraint);


}
An operand constraint is assumed to have only a single character by default
Example: “Ci” -> “^Ci”
Operand constraint validations in Clang
Limitation on immediate value validations (cont’d)
47
bool M68kTargetInfo::validateAsmConstraint(const char *&Name, ConstraintInfo &info) const {


switch (*Name) {


…


case 'C':


++Name;


switch (*Name) {


case 'i': // constant integer


case 'j': // integer constant that doesn't fit in 16 bits


info.setRequiresImmediate();


return true;


}


break;


}


…


}

More Related Content

What's hot (20)

PDF
Linux kernel debugging
libfetion
 
PDF
Golang workshop
Victor S. Recio
 
PDF
llvm basic porting for risc v
Tsung-Chun Lin
 
PDF
Introduction to Perf
Wang Hsiangkai
 
PPTX
Understanding eBPF in a Hurry!
Ray Jenkins
 
PPTX
QEMU - Binary Translation
Jiann-Fuh Liaw
 
PDF
Toolchain
Anil Kumar Pugalia
 
PPTX
GCC RTL and Machine Description
Priyatham Bollimpalli
 
PDF
The Linux Block Layer - Built for Fast Storage
Kernel TLV
 
PDF
LinuxCon 2015 Linux Kernel Networking Walkthrough
Thomas Graf
 
PPTX
Linux Kernel Module - For NLKB
shimosawa
 
PDF
from Binary to Binary: How Qemu Works
Zhen Wei
 
PPT
U boot porting guide for SoC
Macpaul Lin
 
PPTX
LLVM Instruction Selection
Shiva Chen
 
PPTX
Linux Initialization Process (2)
shimosawa
 
PDF
Linux Performance Profiling and Monitoring
Georg Schönberger
 
PDF
OSSNA 2017 Performance Analysis Superpowers with Linux BPF
Brendan Gregg
 
ODP
eBPF maps 101
SUSE Labs Taipei
 
PDF
Linux Networking Explained
Thomas Graf
 
PPTX
Linux Device Tree
艾鍗科技
 
Linux kernel debugging
libfetion
 
Golang workshop
Victor S. Recio
 
llvm basic porting for risc v
Tsung-Chun Lin
 
Introduction to Perf
Wang Hsiangkai
 
Understanding eBPF in a Hurry!
Ray Jenkins
 
QEMU - Binary Translation
Jiann-Fuh Liaw
 
GCC RTL and Machine Description
Priyatham Bollimpalli
 
The Linux Block Layer - Built for Fast Storage
Kernel TLV
 
LinuxCon 2015 Linux Kernel Networking Walkthrough
Thomas Graf
 
Linux Kernel Module - For NLKB
shimosawa
 
from Binary to Binary: How Qemu Works
Zhen Wei
 
U boot porting guide for SoC
Macpaul Lin
 
LLVM Instruction Selection
Shiva Chen
 
Linux Initialization Process (2)
shimosawa
 
Linux Performance Profiling and Monitoring
Georg Schönberger
 
OSSNA 2017 Performance Analysis Superpowers with Linux BPF
Brendan Gregg
 
eBPF maps 101
SUSE Labs Taipei
 
Linux Networking Explained
Thomas Graf
 
Linux Device Tree
艾鍗科技
 

Similar to Handling inline assembly in Clang and LLVM (20)

PDF
"Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ...
PVS-Studio
 
PPTX
Price of an Error
Andrey Karpov
 
PDF
PVS-Studio Meets Octave
PVS-Studio
 
PPTX
Static analysis and writing C/C++ of high quality code for embedded systems
Andrey Karpov
 
PDF
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
PVS-Studio
 
PDF
Shellcoding in linux
Ajin Abraham
 
PPT
Writing Metasploit Plugins
amiable_indian
 
PDF
SFO15-500: VIXL
Linaro
 
PDF
Why Windows 8 drivers are buggy
Andrey Karpov
 
PPTX
Search for Vulnerabilities Using Static Code Analysis
Andrey Karpov
 
PPTX
200 Open Source Projects Later: Source Code Static Analysis Experience
Andrey Karpov
 
PDF
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
PVS-Studio
 
PDF
E yantra robot abstractions
Akshar Desai
 
PDF
XPDS16: Xen Live Patching - Updating Xen Without Rebooting - Konrad Wilk, Ora...
The Linux Foundation
 
PDF
zkStudyClub: CirC and Compiling Programs to Circuits
Alex Pruden
 
PDF
Assembly language part I
Mohammed A. Imran
 
PDF
Assembly language part I
n|u - The Open Security Community
 
PPTX
Java Jit. Compilation and optimization by Andrey Kovalenko
Valeriia Maliarenko
 
PPTX
04 - I love my OS, he protects me (sometimes, in specific circumstances)
Alexandre Moneger
 
PDF
Errors detected in the Visual C++ 2012 libraries
PVS-Studio
 
"Why is there no artificial intelligence yet?" Or, analysis of CNTK tool kit ...
PVS-Studio
 
Price of an Error
Andrey Karpov
 
PVS-Studio Meets Octave
PVS-Studio
 
Static analysis and writing C/C++ of high quality code for embedded systems
Andrey Karpov
 
Analysis of Haiku Operating System (BeOS Family) by PVS-Studio. Part 2
PVS-Studio
 
Shellcoding in linux
Ajin Abraham
 
Writing Metasploit Plugins
amiable_indian
 
SFO15-500: VIXL
Linaro
 
Why Windows 8 drivers are buggy
Andrey Karpov
 
Search for Vulnerabilities Using Static Code Analysis
Andrey Karpov
 
200 Open Source Projects Later: Source Code Static Analysis Experience
Andrey Karpov
 
Comparing the general static analysis in Visual Studio 2010 and PVS-Studio by...
PVS-Studio
 
E yantra robot abstractions
Akshar Desai
 
XPDS16: Xen Live Patching - Updating Xen Without Rebooting - Konrad Wilk, Ora...
The Linux Foundation
 
zkStudyClub: CirC and Compiling Programs to Circuits
Alex Pruden
 
Assembly language part I
Mohammed A. Imran
 
Assembly language part I
n|u - The Open Security Community
 
Java Jit. Compilation and optimization by Andrey Kovalenko
Valeriia Maliarenko
 
04 - I love my OS, he protects me (sometimes, in specific circumstances)
Alexandre Moneger
 
Errors detected in the Visual C++ 2012 libraries
PVS-Studio
 
Ad

More from Min-Yih Hsu (14)

PDF
Debug Information And Where They Come From
Min-Yih Hsu
 
PDF
MCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
Min-Yih Hsu
 
PDF
How to write a TableGen backend
Min-Yih Hsu
 
PDF
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
Min-Yih Hsu
 
PDF
[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...
Min-Yih Hsu
 
PDF
Paper Study - Demand-Driven Computation of Interprocedural Data Flow
Min-Yih Hsu
 
PDF
Paper Study - Incremental Data-Flow Analysis Algorithms by Ryder et al
Min-Yih Hsu
 
PDF
Souper-Charging Peepholes with Target Machine Info
Min-Yih Hsu
 
PDF
From V8 to Modern Compilers
Min-Yih Hsu
 
PDF
Introduction to Khronos SYCL
Min-Yih Hsu
 
PDF
Trace Scheduling
Min-Yih Hsu
 
PDF
Polymer Start-Up (SITCON 2016)
Min-Yih Hsu
 
PDF
War of Native Speed on Web (SITCON2016)
Min-Yih Hsu
 
PDF
From Android NDK To AOSP
Min-Yih Hsu
 
Debug Information And Where They Come From
Min-Yih Hsu
 
MCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
Min-Yih Hsu
 
How to write a TableGen backend
Min-Yih Hsu
 
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
Min-Yih Hsu
 
[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...
Min-Yih Hsu
 
Paper Study - Demand-Driven Computation of Interprocedural Data Flow
Min-Yih Hsu
 
Paper Study - Incremental Data-Flow Analysis Algorithms by Ryder et al
Min-Yih Hsu
 
Souper-Charging Peepholes with Target Machine Info
Min-Yih Hsu
 
From V8 to Modern Compilers
Min-Yih Hsu
 
Introduction to Khronos SYCL
Min-Yih Hsu
 
Trace Scheduling
Min-Yih Hsu
 
Polymer Start-Up (SITCON 2016)
Min-Yih Hsu
 
War of Native Speed on Web (SITCON2016)
Min-Yih Hsu
 
From Android NDK To AOSP
Min-Yih Hsu
 
Ad

Recently uploaded (20)

PDF
Capcut Pro Crack For PC Latest Version {Fully Unlocked} 2025
hashhshs786
 
PDF
Digger Solo: Semantic search and maps for your local files
seanpedersen96
 
PDF
Understanding the Need for Systemic Change in Open Source Through Intersectio...
Imma Valls Bernaus
 
PPTX
Comprehensive Guide: Shoviv Exchange to Office 365 Migration Tool 2025
Shoviv Software
 
PDF
Alarm in Android-Scheduling Timed Tasks Using AlarmManager in Android.pdf
Nabin Dhakal
 
PPTX
Engineering the Java Web Application (MVC)
abhishekoza1981
 
PDF
Thread In Android-Mastering Concurrency for Responsive Apps.pdf
Nabin Dhakal
 
PDF
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pdf
Varsha Nayak
 
PDF
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 
PDF
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
PPTX
Human Resources Information System (HRIS)
Amity University, Patna
 
DOCX
Import Data Form Excel to Tally Services
Tally xperts
 
PDF
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
PPTX
MailsDaddy Outlook OST to PST converter.pptx
abhishekdutt366
 
PDF
HiHelloHR – Simplify HR Operations for Modern Workplaces
HiHelloHR
 
PDF
Revenue streams of the Wazirx clone script.pdf
aaronjeffray
 
PPT
MergeSortfbsjbjsfk sdfik k
RafishaikIT02044
 
PDF
Beyond Binaries: Understanding Diversity and Allyship in a Global Workplace -...
Imma Valls Bernaus
 
PDF
Streamline Contractor Lifecycle- TECH EHS Solution
TECH EHS Solution
 
PPTX
MiniTool Power Data Recovery Full Crack Latest 2025
muhammadgurbazkhan
 
Capcut Pro Crack For PC Latest Version {Fully Unlocked} 2025
hashhshs786
 
Digger Solo: Semantic search and maps for your local files
seanpedersen96
 
Understanding the Need for Systemic Change in Open Source Through Intersectio...
Imma Valls Bernaus
 
Comprehensive Guide: Shoviv Exchange to Office 365 Migration Tool 2025
Shoviv Software
 
Alarm in Android-Scheduling Timed Tasks Using AlarmManager in Android.pdf
Nabin Dhakal
 
Engineering the Java Web Application (MVC)
abhishekoza1981
 
Thread In Android-Mastering Concurrency for Responsive Apps.pdf
Nabin Dhakal
 
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pdf
Varsha Nayak
 
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
Human Resources Information System (HRIS)
Amity University, Patna
 
Import Data Form Excel to Tally Services
Tally xperts
 
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
MailsDaddy Outlook OST to PST converter.pptx
abhishekdutt366
 
HiHelloHR – Simplify HR Operations for Modern Workplaces
HiHelloHR
 
Revenue streams of the Wazirx clone script.pdf
aaronjeffray
 
MergeSortfbsjbjsfk sdfik k
RafishaikIT02044
 
Beyond Binaries: Understanding Diversity and Allyship in a Global Workplace -...
Imma Valls Bernaus
 
Streamline Contractor Lifecycle- TECH EHS Solution
TECH EHS Solution
 
MiniTool Power Data Recovery Full Crack Latest 2025
muhammadgurbazkhan
 

Handling inline assembly in Clang and LLVM

  • 1. Min-Yih “Min” Hsu @ LLVM Dev Meeting 2021 Handling inline assembly 
 in Clang and LLVM
  • 2. about:me “Min” Hsu • Computer Science PhD Candidate in University of California, Irvine • Code owner of M68k LLVM backend • Author of book “LLVM Techniques, Tips and Best Practices” (2021) 2
  • 3. How Inline Assembly is Processed in Clang & LLVM 3
  • 5. Introduction to inline assembly 5 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } * x86_64 assembly w/ AT&T syntax
  • 6. Introduction to inline assembly 5 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } * x86_64 assembly w/ AT&T syntax
  • 7. Introduction to inline assembly 5 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } foo: pushq %rbp movq %rsp, %rbp ... testb $1, -9(%rbp) je LBB0_2 ## InlineAsm Start movl %eax, %ebx addl %ebx, %esi ## InlineAsm End jmp LBB0_3 LBB0_2: movl -8(%rbp), %eax addl $87, %eax movl %eax, -8(%rbp) LBB0_3: popq %rbp retq * x86_64 assembly w/ AT&T syntax
  • 8. Introduction to inline assembly 5 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } foo: pushq %rbp movq %rsp, %rbp ... testb $1, -9(%rbp) je LBB0_2 ## InlineAsm Start movl %eax, %ebx addl %ebx, %esi ## InlineAsm End jmp LBB0_3 LBB0_2: movl -8(%rbp), %eax addl $87, %eax movl %eax, -8(%rbp) LBB0_3: popq %rbp retq * x86_64 assembly w/ AT&T syntax
  • 9. Introduction to inline assembly Why use inline assembly? 6 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } * x86_64 assembly w/ AT&T syntax
  • 10. Introduction to inline assembly Why use inline assembly? 6 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } Performance critical code * x86_64 assembly w/ AT&T syntax
  • 11. Introduction to inline assembly Why use inline assembly? 6 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } Performance critical code Low-level code e.g. Kernel, firmware * x86_64 assembly w/ AT&T syntax
  • 12. Introduction to inline assembly Why use inline assembly? 6 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } Performance critical code Low-level code e.g. Kernel, firmware Compiler optimizations “barrier” * x86_64 assembly w/ AT&T syntax
  • 13. Introduction to inline assembly 7 asm (“movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); * x86_64 assembly w/ AT&T syntax
  • 14. Introduction to inline assembly 7 asm (“movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); Assembly code (template) * x86_64 assembly w/ AT&T syntax
  • 15. Introduction to inline assembly 7 asm (“movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); Assembly code (template) * x86_64 assembly w/ AT&T syntax
  • 16. Introduction to inline assembly Output operands 8 int out_var; asm ("movl %%eax, %%ebxn" "addl %%ebx, %0" : "=r"(out_var) ::); * x86_64 assembly w/ AT&T syntax
  • 17. Introduction to inline assembly Output operands 8 int out_var; asm ("movl %%eax, %%ebxn" "addl %%ebx, %0" : "=r"(out_var) ::); * x86_64 assembly w/ AT&T syntax
  • 18. Introduction to inline assembly Output operands 8 int out_var; asm ("movl %%eax, %%ebxn" "addl %%ebx, %0" : "=r"(out_var) ::); Operand constraints * x86_64 assembly w/ AT&T syntax
  • 19. Introduction to inline assembly Operands constraints 9 int out_var; asm ("movl %%eax, %%ebxn" "addl %%ebx, %0" : "=r"(out_var) ::); * x86_64 assembly w/ AT&T syntax
  • 20. Introduction to inline assembly Operands constraints 9 int out_var; asm ("movl %%eax, %%ebxn" "addl %%ebx, %0" : "=r"(out_var) ::); * x86_64 assembly w/ AT&T syntax ## InlineAsm Start movl %eax, %ebx addl %ebx, %esi ## InlineAsm End
  • 21. Introduction to inline assembly Operands constraints 9 int out_var; asm ("movl %%eax, %%ebxn" "addl %%ebx, %0" : "=r"(out_var) ::); * x86_64 assembly w/ AT&T syntax ## InlineAsm Start movl %eax, %ebx addl %ebx, %esi ## InlineAsm End ## InlineAsm Start movl %eax, %ebx addl %ebx, -8(%ebp) ## InlineAsm End
  • 23. Operand constraints 10 • ‘r’ : General-purpose register operand • ‘i’ : Immediate integer operand • ‘m’ : Memory operand w/ arbitrary addressing mode Target-independent Constraints
  • 24. Operand constraints 10 • ‘r’ : General-purpose register operand • ‘i’ : Immediate integer operand • ‘m’ : Memory operand w/ arbitrary addressing mode Target-independent Constraints • ‘a’ : AL / AH / EAX / RAX • ‘I’ : Integer constant in the range of [0, 31] • ‘N’ : Unsigned 8-bit integer constant X86 Constraints
  • 25. Operand constraints 10 • ‘r’ : General-purpose register operand • ‘i’ : Immediate integer operand • ‘m’ : Memory operand w/ arbitrary addressing mode Target-independent Constraints • ‘a’ : AL / AH / EAX / RAX • ‘I’ : Integer constant in the range of [0, 31] • ‘N’ : Unsigned 8-bit integer constant X86 Constraints • ‘J’ : 16-bit signed integer constant • “Ci” : Constant integers • “Cj” : Constant signed integers that do NOT fi t in 16 bits M68k Constraints
  • 26. Operand constraints 10 • ‘r’ : General-purpose register operand • ‘i’ : Immediate integer operand • ‘m’ : Memory operand w/ arbitrary addressing mode Constraint Modifers Target-independent Constraints • ‘=‘ : This is an output operand • ‘+’ : This is an input / output operand • ‘a’ : AL / AH / EAX / RAX • ‘I’ : Integer constant in the range of [0, 31] • ‘N’ : Unsigned 8-bit integer constant X86 Constraints • ‘J’ : 16-bit signed integer constant • “Ci” : Constant integers • “Cj” : Constant signed integers that do NOT fi t in 16 bits M68k Constraints
  • 27. Introduction to inline assembly Input operands 11 int out_var, in_var; asm ("movl %1, %%ebxn" "addl %%ebx, %0" : “=r"(out_var) : “r”(in_var) :); * x86_64 assembly w/ AT&T syntax
  • 28. Introduction to inline assembly Input operands 11 int out_var, in_var; asm ("movl %1, %%ebxn" "addl %%ebx, %0" : “=r"(out_var) : “r”(in_var) :); * x86_64 assembly w/ AT&T syntax
  • 29. Introduction to inline assembly Input operands 11 int out_var, in_var; asm ("movl %1, %%ebxn" "addl %%ebx, %0" : “=r"(out_var) : “r”(in_var) :); Operand constraints * x86_64 assembly w/ AT&T syntax
  • 30. Introduction to inline assembly Clobber operands 12 int out_var, in_var; asm ("movl %1, %%ebxn" "addl %%ebx, %0" : “=r"(out_var) : “r”(in_var) : “ebx”); * x86_64 assembly w/ AT&T syntax
  • 31. Introduction to inline assembly Clobber operands 12 int out_var, in_var; asm ("movl %1, %%ebxn" "addl %%ebx, %0" : “=r"(out_var) : “r”(in_var) : “ebx”); * x86_64 assembly w/ AT&T syntax
  • 32. For more inline assembly syntax… 13 https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
  • 33. Handling inline assembly in Clang & LLVM Background 14
  • 34. Handling inline assembly in Clang & LLVM Background • Most parts of an inline assembly string are simply copied into the fi nal assembly fi le 14
  • 35. Handling inline assembly in Clang & LLVM Background • Most parts of an inline assembly string are simply copied into the fi nal assembly fi le • LLVM needs to “glue” inline assembly operands with the surrounding code 14
  • 36. Handling inline assembly in Clang & LLVM Background • Most parts of an inline assembly string are simply copied into the fi nal assembly fi le • LLVM needs to “glue” inline assembly operands with the surrounding code • Lots of target-speci fi c logics • In both Clang and the backend 14
  • 37. Handling inline assembly in Clang & LLVM Background • Most parts of an inline assembly string are simply copied into the fi nal assembly fi le • LLVM needs to “glue” inline assembly operands with the surrounding code • Lots of target-speci fi c logics • In both Clang and the backend • Target-speci fi c callbacks are scattered in the codebase • Documentation for this part is a little…shy 14
  • 39. Goals Learning inline assembly workflow in Clang / LLVM 15
  • 40. Goals Learning inline assembly workflow in Clang / LLVM A simple guide for backend developers to add inline assembly support 15
  • 41. Outline of target-specific logics in each stage 16 Clang Lowering LLVM IR Machine IR AsmPrinter
  • 42. Outline of target-specific logics in each stage 16 Clang Lowering LLVM IR Machine IR AsmPrinter • Simple validation on operand constraints • Converting constraints
  • 43. Outline of target-specific logics in each stage 16 Clang Lowering LLVM IR Machine IR AsmPrinter • Simple validation on operand constraints • Converting constraints • Classifying constraints • Constraint validations • Lowering the operands
  • 44. Outline of target-specific logics in each stage 16 Clang Lowering LLVM IR Machine IR AsmPrinter • Simple validation on operand constraints • Converting constraints • Classifying constraints • Constraint validations • Lowering the operands Print out di ff erent types of operands
  • 45. Outline of target-specific logics in each stage 17 Clang Lowering LLVM IR Machine IR AsmPrinter • Simple validation on operand constraints • Converting constraints • Classifying constraints • Constraint validations • Lowering the operands Print out di ff erent types of operands
  • 46. Operand constraint validations in Clang 18 bool TargetInfo::validateAsmConstraint(const char *&, ConstraintInfo &) const;
  • 47. Operand constraint validations in Clang 18 bool TargetInfo::validateAsmConstraint(const char *&, ConstraintInfo &) const; bool M68kTargetInfo::validateAsmConstraint(const char *&Name, ConstraintInfo &info) const { switch (*Name) { case 'a': // address register info.setAllowsRegister(); return true; } … }
  • 48. Operand constraint validations in Clang 19 bool TargetInfo::validateAsmConstraint(const char *&, ConstraintInfo &) const; bool M68kTargetInfo::validateAsmConstraint(const char *&Name, ConstraintInfo &info) const { switch (*Name) { case 'a': // address register info.setAllowsRegister(); return true; case 'J': // constant signed 16-bit integer info.setRequiresImmediate(std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max()); return true; } … }
  • 49. Operand constraint validations in Clang Limitation on immediate value validations 20 void foo() { int32_t x; asm ("move.l %0, %%d1" : : "J" (x)); } * M68k assembly w/ Motorola syntax
  • 50. Operand constraint validations in Clang Limitation on immediate value validations 20 void foo() { int32_t x; asm ("move.l %0, %%d1" : : "J" (x)); } Constant signed 16-bit integer * M68k assembly w/ Motorola syntax
  • 51. Operand constraint validations in Clang Limitation on immediate value validations 20 void foo() { int32_t x; asm ("move.l %0, %%d1" : : "J" (x)); } $ clang -target m68k -fsyntax-only foo.c # No error $ clang -target m68k -emit-llvm foo.c # No error Constant signed 16-bit integer * M68k assembly w/ Motorola syntax
  • 52. Operand constraint validations in Clang Limitation on immediate value validations 20 void foo() { int32_t x; asm ("move.l %0, %%d1" : : "J" (x)); } $ clang -target m68k -fsyntax-only foo.c # No error $ clang -target m68k -emit-llvm foo.c # No error Constant signed 16-bit integer $ clang -target m68k -S foo.c error: constraint 'J' expects an integer constant expression * M68k assembly w/ Motorola syntax
  • 53. Inline assembly in LLVM IR 21 void foo() { const int x = 87; asm ("move.l %0, %%d1" : : "Ci" (x) : "d1"); } C/C++ * M68k assembly w/ Motorola syntax
  • 54. Inline assembly in LLVM IR 21 void foo() { const int x = 87; asm ("move.l %0, %%d1" : : "Ci" (x) : "d1"); } C/C++ call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) LLVM IR * M68k assembly w/ Motorola syntax
  • 55. Inline assembly in LLVM IR 21 void foo() { const int x = 87; asm ("move.l %0, %%d1" : : "Ci" (x) : "d1"); } C/C++ call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) LLVM IR * M68k assembly w/ Motorola syntax
  • 56. Inline assembly in LLVM IR 21 void foo() { const int x = 87; asm ("move.l %0, %%d1" : : "Ci" (x) : "d1"); } C/C++ call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) LLVM IR * M68k assembly w/ Motorola syntax
  • 57. Inline assembly in LLVM IR 21 void foo() { const int x = 87; asm ("move.l %0, %%d1" : : "Ci" (x) : "d1"); } C/C++ call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) LLVM IR * M68k assembly w/ Motorola syntax
  • 58. Inline assembly in LLVM IR 21 void foo() { const int x = 87; asm ("move.l %0, %%d1" : : "Ci" (x) : "d1"); } C/C++ call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) LLVM IR * M68k assembly w/ Motorola syntax
  • 59. Outline of target-specific logics in each stage 22 Clang Lowering LLVM IR Machine IR AsmPrinter • Simple validation on operand constraints • Converting constraints • Classifying constraints • Constraint validations • Lowering the operands Print out di ff erent types of operands
  • 60. 23 LLVM IR call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
  • 61. 23 LLVM IR SelectionDAG call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) t2: ch,glue = inlineasm ... "move.l $0, %d1", ..., TargetConstant:i32<87>, Register:i16 $d1
  • 62. 23 LLVM IR SelectionDAG Machine IR call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1 t2: ch,glue = inlineasm ... "move.l $0, %d1", ..., TargetConstant:i32<87>, Register:i16 $d1
  • 63. 23 LLVM IR SelectionDAG Machine IR call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1 t2: ch,glue = inlineasm ... "move.l $0, %d1", ..., TargetConstant:i32<87>, Register:i16 $d1
  • 68. Constraint classification 24 TargetLowering::ConstraintType M68kTargetLowering::getConstraintType(StringRef Constraint) const; • C_RegisterClass • C_Immediate • C_Memory Return: Ex: ’r’ Ex: ‘i’ Ex: ‘m’, ‘Q’ (AArch64)
  • 69. Constraint classification 24 TargetLowering::ConstraintType M68kTargetLowering::getConstraintType(StringRef Constraint) const; • C_RegisterClass • C_Immediate • C_Memory • C_Other Return: Ex: ’r’ Ex: ‘i’ Ex: ‘m’, ‘Q’ (AArch64)
  • 70. Lowering operands 25 getConstraintType Method in XXXTargetLowering Method in XXXISelDAGToDAG Will be invoked
  • 71. Lowering operands 25 getConstraintType getRegForInlineAsmConstraint C_RegisterClass Method in XXXTargetLowering Method in XXXISelDAGToDAG Will be invoked
  • 75. Lowering register operands 26 std::pair<unsigned, const TargetRegisterClass *> TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const;
  • 76. Lowering register operands 26 std::pair<unsigned, const TargetRegisterClass *> TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const; A speci fi c register or 0 if not applicable
  • 77. Lowering register operands 26 std::pair<unsigned, const TargetRegisterClass *> TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const; A speci fi c register or 0 if not applicable Valid register class to select from
  • 78. Lowering register operands M68k Example 27 std::pair<unsigned, const TargetRegisterClass *> M68kTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *, StringRef Constraint, MVT VT) const { switch (Constraint[0]) { case 'a': switch (VT.SimpleTy) { case MVT::i16: return std::make_pair(0U, &M68k::AR16RegClass); } } }
  • 79. Lowering register operands M68k Example 27 std::pair<unsigned, const TargetRegisterClass *> M68kTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *, StringRef Constraint, MVT VT) const { switch (Constraint[0]) { case 'a': switch (VT.SimpleTy) { case MVT::i16: return std::make_pair(0U, &M68k::AR16RegClass); } } }
  • 80. Lowering register operands X86 Example 28 std::pair<unsigned, const TargetRegisterClass *> X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *, StringRef Constraint, MVT VT) const { ... if (Constraint == "Yz") { // First SSE register (%xmm0). switch (VT.SimpleTy) { case MVT::f32: case MVT::i32: return std::make_pair(X86::XMM0, &X86::FR32RegClass); } } }
  • 81. Lowering register operands X86 Example 28 std::pair<unsigned, const TargetRegisterClass *> X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *, StringRef Constraint, MVT VT) const { ... if (Constraint == "Yz") { // First SSE register (%xmm0). switch (VT.SimpleTy) { case MVT::f32: case MVT::i32: return std::make_pair(X86::XMM0, &X86::FR32RegClass); } } }
  • 82. Lowering immediate / other operands 29 void TargetLowering:: LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops, SelectionDAG &DAG) const;
  • 83. Lowering immediate / other operands M68k Example 30 void M68kTargetLowering::LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops, SelectionDAG &DAG) const { switch (Constraint[0]) { case 'J': { // constant signed 16-bit integer } } }
  • 84. Lowering immediate / other operands M68k Example 31 void M68kTargetLowering::LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops, SelectionDAG &DAG) const { switch (Constraint[0]) { case 'J': { // constant signed 16-bit integer if (auto *C = dyn_cast<ConstantSDNode>(Op)) { int64_t Val = C->getSExtValue(); } } } }
  • 85. Lowering immediate / other operands M68k Example 32 void M68kTargetLowering::LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops, SelectionDAG &DAG) const { switch (Constraint[0]) { case 'J': { // constant signed 16-bit integer if (auto *C = dyn_cast<ConstantSDNode>(Op)) { int64_t Val = C->getSExtValue(); if (isInt<16>(Val)) { Ops.push_back(Op); return; } } } } }
  • 86. Lowering memory operands Memory constraint classi fi cation 33 unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const;
  • 87. Lowering memory operands Memory constraint classi fi cation 33 unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const; Return:
  • 88. Lowering memory operands Memory constraint classi fi cation 33 unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const; • InlineAsm::Constraint_m • InlineAsm::Constraint_o • InlineAsm::Constraint_v Return: Generic memory constraints
  • 89. Lowering memory operands Memory constraint classi fi cation 33 unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const; • InlineAsm::Constraint_m • InlineAsm::Constraint_o • InlineAsm::Constraint_v Return: • InlineAsm::Constraint_A • InlineAsm::Constraint_Q Generic memory constraints Target-speci fi c constraints!
  • 90. Lowering memory operands Memory constraint classi fi cation — RISCV Example 34 unsigned RISCVTargetLowering:: getInlineAsmMemConstraint(StringRef ConstraintCode) const { switch (ConstraintCode[0]) { case 'A': return InlineAsm::Constraint_A; ... } ... }
  • 91. Lowering memory operands 35 bool SelectionDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps);
  • 92. Lowering memory operands RISCV Example 36 bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand( const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { switch (ConstraintID) { case InlineAsm::Constraint_A: OutOps.push_back(Op); return false; default: break; } return true; }
  • 93. Lowering memory operands Complex addressing mode — X86 Example 37 bool X86DAGToDAGISel:: SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { SDValue Op0, Op1, Op2, Op3, Op4; switch (ConstraintID) { case InlineAsm::Constraint_m: // memory if (!selectAddr(nullptr, Op, Op0, Op1, Op2, Op3, Op4)) return true; break; } OutOps.insert(OutOps.end(), {Op0, Op1, Op2, Op3, Op4}); return false; }
  • 94. Lowering memory operands Complex addressing mode — X86 Example 37 bool X86DAGToDAGISel:: SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { SDValue Op0, Op1, Op2, Op3, Op4; switch (ConstraintID) { case InlineAsm::Constraint_m: // memory if (!selectAddr(nullptr, Op, Op0, Op1, Op2, Op3, Op4)) return true; break; } OutOps.insert(OutOps.end(), {Op0, Op1, Op2, Op3, Op4}); return false; }
  • 95. Outline of target-specific logics in each stage 38 Clang Lowering LLVM IR Machine IR AsmPrinter • Simple validation on operand constraints • Converting constraints • Classifying constraints • Constraint validations • Lowering the operands Print out di ff erent types of operands
  • 96. 39 Machine IR INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
  • 97. 39 Machine IR INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
  • 98. 39 Machine IR INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1 move.l #87, %d1
  • 99. 39 Machine IR INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1 move.l 87, %d1 move.l #87, %d1
  • 100. Printing asm operands 40 bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *, raw_ostream &O); bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *, raw_ostream &O);
  • 101. Printing non-memory asm operands M68k Example 41 void M68kAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, raw_ostream &OS) { const MachineOperand &MO = MI->getOperand(OpNum); switch (MO.getType()) { case MachineOperand::MO_Register: OS << "%" << M68kInstPrinter::getRegisterName(MO.getReg()); break; case MachineOperand::MO_Immediate: OS << '#' << MO.getImm(); break; ... } }
  • 102. Printing non-memory asm operands M68k Example 41 void M68kAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, raw_ostream &OS) { const MachineOperand &MO = MI->getOperand(OpNum); switch (MO.getType()) { case MachineOperand::MO_Register: OS << "%" << M68kInstPrinter::getRegisterName(MO.getReg()); break; case MachineOperand::MO_Immediate: OS << '#' << MO.getImm(); break; ... } }
  • 103. Printing non-memory asm operands M68k Example 41 void M68kAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, raw_ostream &OS) { const MachineOperand &MO = MI->getOperand(OpNum); switch (MO.getType()) { case MachineOperand::MO_Register: OS << "%" << M68kInstPrinter::getRegisterName(MO.getReg()); break; case MachineOperand::MO_Immediate: OS << '#' << MO.getImm(); break; ... } }
  • 105. Advanced topics Converting constraints in Clang Asm dialects Operand modifiers Multi-alternative constraints Constraint weights Turn (simple) inline asm into LLVM code 43
  • 106. Thank you! 44 GitHub: mshockwave Email: [email protected] 25% book discount code: 25MINLLVM Redeem: Nov 15 ~ Nov 20, 2021
  • 108. Converting constraints in Clang 46 An operand constraint is assumed to have only a single character by default
  • 109. Converting constraints in Clang 46 An operand constraint is assumed to have only a single character by default Example: “Ci”
  • 110. Converting constraints in Clang 46 An operand constraint is assumed to have only a single character by default Example: “Ci” -> “^Ci”
  • 111. Converting constraints in Clang 46 std::string M68kTargetInfo::convertConstraint(const char *&Constraint) const override { if (*Constraint == 'C') // Two-character constraint; add "^" hint for later parsing return std::string("^") + std::string(Constraint++, 2); return std::string(1, *Constraint); } An operand constraint is assumed to have only a single character by default Example: “Ci” -> “^Ci”
  • 112. Operand constraint validations in Clang Limitation on immediate value validations (cont’d) 47 bool M68kTargetInfo::validateAsmConstraint(const char *&Name, ConstraintInfo &info) const { switch (*Name) { … case 'C': ++Name; switch (*Name) { case 'i': // constant integer case 'j': // integer constant that doesn't fit in 16 bits info.setRequiresImmediate(); return true; } break; } … }