Skip to content

Commit 98d6f59

Browse files
author
Robert Marsh
committed
C++: Treat asmStmt operands as input/output in IR
1 parent 66d1efd commit 98d6f59

File tree

11 files changed

+174
-27
lines changed

11 files changed

+174
-27
lines changed

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ module InstructionSanity {
7373
operand.getOperandTag() = tag) and
7474
not expectsOperand(instr, tag) and
7575
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
76-
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag)
76+
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag) and
77+
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
7778
}
7879

7980
/**

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ module InstructionSanity {
7373
operand.getOperandTag() = tag) and
7474
not expectsOperand(instr, tag) and
7575
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
76-
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag)
76+
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag) and
77+
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
7778
}
7879

7980
/**

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,13 @@ newtype TInstructionTag =
8484
} or
8585
InitializerElementDefaultValueStoreTag(int elementIndex) {
8686
elementIsInitialized(elementIndex)
87-
}
87+
} or
88+
AsmTag() or
89+
AsmInputTag(int elementIndex) {
90+
exists(AsmStmt asm |
91+
exists(asm.getChild(elementIndex))
92+
)
93+
}
8894

8995
class InstructionTag extends TInstructionTag {
9096
final string toString() {
@@ -161,5 +167,9 @@ string getInstructionTagId(TInstructionTag tag) {
161167
tag = InitializerElementDefaultValueStoreTag(index) and tagName = "InitElemDefValStore"
162168
) and
163169
result = tagName + "(" + index + ")"
170+
) or
171+
tag = AsmTag() and result = "Asm" or
172+
exists(int index |
173+
tag = AsmInputTag(index) and result = "AsmInputTag(" + index + ")"
164174
)
165175
}

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ private predicate ignoreExprAndDescendants(Expr expr) {
6464
// represent them.
6565
newExpr.getInitializer().getFullyConverted() = expr
6666
) or
67-
// Ignore descendants of asm statements, since we can't differentiate inputs and outputs
67+
// Do not translate input/output variables in GNU asm statements
6868
getRealParent(expr) instanceof AsmStmt or
6969
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
7070
}

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -819,36 +819,69 @@ class TranslatedAsmStmt extends TranslatedStmt {
819819
}
820820

821821
override Instruction getFirstInstruction() {
822-
result = getInstruction(OnlyInstructionTag())
822+
if exists(stmt.getChild(0))
823+
then result = getInstruction(AsmInputTag(0))
824+
else result = getInstruction(AsmTag())
823825
}
824826

825827
override predicate hasInstruction(Opcode opcode, InstructionTag tag,
826828
Type resultType, boolean isGLValue) {
827-
tag = OnlyInstructionTag() and
829+
tag = AsmTag() and
828830
opcode instanceof Opcode::InlineAsm and
829831
resultType instanceof UnknownType and
830832
isGLValue = false
833+
or
834+
exists(int index, VariableAccess va |
835+
tag = AsmInputTag(index) and
836+
stmt.getChild(index) = va and
837+
opcode instanceof Opcode::VariableAddress and
838+
resultType = va.getType().getUnspecifiedType() and
839+
isGLValue = true
840+
)
841+
}
842+
843+
override IRVariable getInstructionVariable(InstructionTag tag) {
844+
exists(int index |
845+
tag = AsmInputTag(index) and
846+
result = getIRUserVariable(stmt.getEnclosingFunction(), stmt.getChild(index).(VariableAccess).getTarget())
847+
)
831848
}
832849

833850
override Instruction getInstructionOperand(InstructionTag tag,
834851
OperandTag operandTag) {
835-
tag = OnlyInstructionTag() and
852+
tag = AsmTag() and
836853
operandTag instanceof SideEffectOperandTag and
837854
result = getTranslatedFunction(stmt.getEnclosingFunction()).getUnmodeledDefinitionInstruction()
855+
or
856+
exists(int index |
857+
tag = AsmTag() and
858+
operandTag = asmOperand(index) and
859+
result = getInstruction(AsmInputTag(index))
860+
)
838861
}
839862

840863
override final Type getInstructionOperandType(InstructionTag tag,
841864
TypedOperandTag operandTag) {
842-
tag = OnlyInstructionTag() and
865+
tag = AsmTag() and
843866
operandTag instanceof SideEffectOperandTag and
844867
result instanceof UnknownType
845868
}
846869

847870
override Instruction getInstructionSuccessor(InstructionTag tag,
848871
EdgeKind kind) {
849-
tag = OnlyInstructionTag() and
872+
tag = AsmTag() and
850873
result = getParent().getChildSuccessor(this) and
851874
kind instanceof GotoEdge
875+
or
876+
exists(int index |
877+
tag = AsmInputTag(index) and
878+
kind instanceof GotoEdge and
879+
if exists(stmt.getChild(index + 1))
880+
then
881+
result = getInstruction(AsmInputTag(index + 1))
882+
else
883+
result = getInstruction(AsmTag())
884+
)
852885
}
853886

854887
override Instruction getChildSuccessor(TranslatedElement child) {

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ module InstructionSanity {
7373
operand.getOperandTag() = tag) and
7474
not expectsOperand(instr, tag) and
7575
not (instr instanceof CallInstruction and tag instanceof ArgumentOperandTag) and
76-
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag)
76+
not (instr instanceof BuiltInInstruction and tag instanceof PositionalArgumentOperandTag) and
77+
not (instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag)
7778
}
7879

7980
/**

cpp/ql/src/semmle/code/cpp/ir/internal/OperandTag.qll

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ private newtype TOperandTag =
2828
)
2929
} or
3030
TChiTotalOperand() or
31-
TChiPartialOperand()
31+
TChiPartialOperand() or
32+
TAsmOperand(int index) {
33+
exists(AsmStmt asm |
34+
exists(asm.getChild(index))
35+
)
36+
}
3237

3338
/**
3439
* Identifies the kind of operand on an instruction. Each `Instruction` has at
@@ -362,3 +367,27 @@ class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand {
362367
ChiPartialOperandTag chiPartialOperand() {
363368
result = TChiPartialOperand()
364369
}
370+
371+
class AsmOperandTag extends RegisterOperandTag, TAsmOperand {
372+
int index;
373+
374+
AsmOperandTag() {
375+
this = TAsmOperand(index)
376+
}
377+
378+
override final string toString() {
379+
result = "AsmOperand(" + index + ")"
380+
}
381+
382+
override final int getSortOrder() {
383+
result = 15 + index
384+
}
385+
386+
override final string getLabel() {
387+
result = index.toString() + ":"
388+
}
389+
}
390+
391+
AsmOperandTag asmOperand(int index) {
392+
result = TAsmOperand(index)
393+
}

cpp/ql/test/library-tests/ir/ir/raw_ir.expected

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5018,19 +5018,23 @@ ir.cpp:
50185018

50195019
# 1104| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&)
50205020
# 1104| Block 0
5021-
# 1104| v0_0(void) = EnterFunction :
5022-
# 1104| mu0_1(unknown) = AliasedDefinition :
5023-
# 1104| mu0_2(unknown) = UnmodeledDefinition :
5024-
# 1104| r0_3(glval<unsigned int &>) = VariableAddress[a] :
5025-
# 1104| mu0_4(unsigned int &) = InitializeParameter[a] : &:r0_3
5026-
# 1104| r0_5(glval<unsigned int &>) = VariableAddress[b] :
5027-
# 1104| mu0_6(unsigned int &) = InitializeParameter[b] : &:r0_5
5028-
# 1104| r0_7(glval<unsigned int &>) = VariableAddress[c] :
5029-
# 1104| mu0_8(unsigned int &) = InitializeParameter[c] : &:r0_7
5030-
# 1104| r0_9(glval<unsigned int &>) = VariableAddress[d] :
5031-
# 1104| mu0_10(unsigned int &) = InitializeParameter[d] : &:r0_9
5032-
# 1107| mu0_11(unknown) = InlineAsm : ~mu0_2
5033-
# 1118| v0_12(void) = NoOp :
5034-
# 1104| v0_13(void) = ReturnVoid :
5035-
# 1104| v0_14(void) = UnmodeledUse : mu*
5036-
# 1104| v0_15(void) = ExitFunction :
5021+
# 1104| v0_0(void) = EnterFunction :
5022+
# 1104| mu0_1(unknown) = AliasedDefinition :
5023+
# 1104| mu0_2(unknown) = UnmodeledDefinition :
5024+
# 1104| r0_3(glval<unsigned int &>) = VariableAddress[a] :
5025+
# 1104| mu0_4(unsigned int &) = InitializeParameter[a] : &:r0_3
5026+
# 1104| r0_5(glval<unsigned int &>) = VariableAddress[b] :
5027+
# 1104| mu0_6(unsigned int &) = InitializeParameter[b] : &:r0_5
5028+
# 1104| r0_7(glval<unsigned int &>) = VariableAddress[c] :
5029+
# 1104| mu0_8(unsigned int &) = InitializeParameter[c] : &:r0_7
5030+
# 1104| r0_9(glval<unsigned int &>) = VariableAddress[d] :
5031+
# 1104| mu0_10(unsigned int &) = InitializeParameter[d] : &:r0_9
5032+
# 1107| r0_11(glval<unsigned int &>) = VariableAddress[a] :
5033+
# 1107| r0_12(glval<unsigned int &>) = VariableAddress[b] :
5034+
# 1107| r0_13(glval<unsigned int &>) = VariableAddress[c] :
5035+
# 1107| r0_14(glval<unsigned int &>) = VariableAddress[d] :
5036+
# 1107| mu0_15(unknown) = InlineAsm : ~mu0_2, 0:r0_11, 1:r0_12, 2:r0_13, 3:r0_14
5037+
# 1118| v0_16(void) = NoOp :
5038+
# 1104| v0_17(void) = ReturnVoid :
5039+
# 1104| v0_18(void) = UnmodeledUse : mu*
5040+
# 1104| v0_19(void) = ExitFunction :

cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,3 +730,31 @@ ssa.cpp:
730730
# 179| v0_13(void) = ReturnValue : &:r0_12, m0_11
731731
# 179| v0_14(void) = UnmodeledUse : mu*
732732
# 179| v0_15(void) = ExitFunction :
733+
734+
# 184| void AsmStmtWithOutputs(unsigned int&, unsigned int&, unsigned int&, unsigned int&)
735+
# 184| Block 0
736+
# 184| v0_0(void) = EnterFunction :
737+
# 184| m0_1(unknown) = AliasedDefinition :
738+
# 184| mu0_2(unknown) = UnmodeledDefinition :
739+
# 184| r0_3(glval<unsigned int &>) = VariableAddress[a] :
740+
# 184| m0_4(unsigned int &) = InitializeParameter[a] : &:r0_3
741+
# 184| m0_5(unknown) = Chi : total:m0_1, partial:m0_4
742+
# 184| r0_6(glval<unsigned int &>) = VariableAddress[b] :
743+
# 184| m0_7(unsigned int &) = InitializeParameter[b] : &:r0_6
744+
# 184| m0_8(unknown) = Chi : total:m0_5, partial:m0_7
745+
# 184| r0_9(glval<unsigned int &>) = VariableAddress[c] :
746+
# 184| m0_10(unsigned int &) = InitializeParameter[c] : &:r0_9
747+
# 184| m0_11(unknown) = Chi : total:m0_8, partial:m0_10
748+
# 184| r0_12(glval<unsigned int &>) = VariableAddress[d] :
749+
# 184| m0_13(unsigned int &) = InitializeParameter[d] : &:r0_12
750+
# 184| m0_14(unknown) = Chi : total:m0_11, partial:m0_13
751+
# 187| r0_15(glval<unsigned int &>) = VariableAddress[a] :
752+
# 187| r0_16(glval<unsigned int &>) = VariableAddress[b] :
753+
# 187| r0_17(glval<unsigned int &>) = VariableAddress[c] :
754+
# 187| r0_18(glval<unsigned int &>) = VariableAddress[d] :
755+
# 187| m0_19(unknown) = InlineAsm : ~mu0_2, 0:r0_15, 1:r0_16, 2:r0_17, 3:r0_18
756+
# 187| m0_20(unknown) = Chi : total:m0_14, partial:m0_19
757+
# 199| v0_21(void) = NoOp :
758+
# 184| v0_22(void) = ReturnVoid :
759+
# 184| v0_23(void) = UnmodeledUse : mu*
760+
# 184| v0_24(void) = ExitFunction :

cpp/ql/test/library-tests/ir/ssa/ssa.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,20 @@ int AsmStmt(int *p) {
180180
__asm__("");
181181
return *p;
182182
}
183+
184+
static void AsmStmtWithOutputs(unsigned int& a, unsigned int& b, unsigned int& c, unsigned int& d)
185+
{
186+
#if defined(__GNUC__)
187+
__asm__ __volatile__
188+
(
189+
"cpuid\n\t"
190+
: "+a" (a), "+b" (b)
191+
: "c" (c), "d" (d)
192+
);
193+
#else
194+
a++;
195+
b++;
196+
c++;
197+
d++;
198+
#endif
199+
}

0 commit comments

Comments
 (0)