From a86650061031c4f0179cc8598e18daabb84b9476 Mon Sep 17 00:00:00 2001 From: JanLJL Date: Wed, 10 Jul 2019 18:25:32 +0200 Subject: [PATCH] added DiGraph creation and more tests --- osaca/data/csl.yml | 133 +++++++++++++++++++------ osaca/data/isa/AArch64.yml | 76 +++++++++++++++ osaca/data/isa/x86.yml | 35 ++++++- osaca/data/vulcan.yml | 140 +++++++++++++++++++++------ osaca/parser/parser_AArch64v81.py | 1 + osaca/parser/parser_x86att.py | 1 + osaca/semantics/hw_model.py | 16 ++- osaca/semantics/kernel_dg.py | 59 +++++++---- osaca/semantics/semanticsAppender.py | 59 +++++++++++ tests/test_parser_AArch64v81.py | 7 ++ tests/test_parser_x86att.py | 4 + tests/test_semantics.py | 64 ++++++++++++ 12 files changed, 511 insertions(+), 84 deletions(-) diff --git a/osaca/data/csl.yml b/osaca/data/csl.yml index a6a55c4..1508fef 100644 --- a/osaca/data/csl.yml +++ b/osaca/data/csl.yml @@ -46,8 +46,8 @@ instruction_forms: - class: "register" name: "xmm" throughput: 0.5 - latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - name: addss operands: - class: "register" @@ -55,8 +55,41 @@ instruction_forms: - class: "register" name: "xmm" throughput: 0.5 - latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + - name: addl + operands: + - class: "register" + name: "xmm" + - class: "immediate" + name: "int" + throughput: 0.25 + latency: ~ # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.25, 0.0, 0.25, 0.0, 0.0, 0.0, 0.25, 0.25, 0.0] + - name: addq + operands: + - class: "register" + name: "xmm" + - class: "immediate" + name: "int" + throughput: 0.25 + latency: ~ # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.25, 0.0, 0.25, 0.0, 0.0, 0.0, 0.25, 0.25, 0.0] + - name: cmpl + operands: + - class: "register" + name: "gpr" + - class: "register" + name: "gpr" + throughput: 0.25 + latency: ~ # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.25, 0.0, 0.25, 0.0, 0.0, 0.0, 0.25, 0.25, 0.0] + - name: ja + operands: + - class: 'identifier' + throughput: 0.0 + latency: 0.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - name: mulsd operands: - class: "register" @@ -64,8 +97,8 @@ instruction_forms: - class: "register" name: "xmm" throughput: 0.5 - latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - name: mulss operands: - class: "register" @@ -73,8 +106,8 @@ instruction_forms: - class: "register" name: "xmm" throughput: 0.5 - latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - name: rcpss operands: - class: "register" @@ -82,8 +115,8 @@ instruction_forms: - class: "register" name: "xmm" throughput: 1.0 - latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - name: sqrtsd operands: - class: "register" @@ -91,8 +124,8 @@ instruction_forms: - class: "register" name: "xmm" throughput: 6.0 - latency: 22.0 # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 22.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [1.0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - name: sqrtss operands: - class: "register" @@ -100,8 +133,8 @@ instruction_forms: - class: "register" name: "xmm" throughput: 3.0 - latency: 16.0 # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [1.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 16.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [1.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - name: vaddsd operands: - class: "register" @@ -111,8 +144,8 @@ instruction_forms: - class: "register" name: "xmm" throughput: 0.5 - latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - name: vaddss operands: - class: "register" @@ -122,8 +155,8 @@ instruction_forms: - class: "register" name: "xmm" throughput: 0.5 - latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - name: vdivsd operands: - class: "register" @@ -133,8 +166,8 @@ instruction_forms: - class: "register" name: "xmm" throughput: 4.0 - latency: 14.0 # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [1.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 14.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [1.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - name: vdivss operands: - class: "register" @@ -144,8 +177,22 @@ instruction_forms: - class: "register" name: "xmm" throughput: 3.0 - latency: 11.0 # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [1.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 11.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [1.0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + - name: vfmadd132pd + operands: + - class: "memory" + base: "gpr" + offset: ~ + index: "gpr" + scale: 1 + - class: "register" + name: "ymm" + - class: "register" + name: "ymm" + throughput: 0.5 + latency: ~ # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.5, 0.0, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.0] - name: vmulsd operands: - class: "register" @@ -155,8 +202,8 @@ instruction_forms: - class: "register" name: "xmm" throughput: 0.5 - latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - name: vmulss operands: - class: "register" @@ -166,8 +213,8 @@ instruction_forms: - class: "register" name: "xmm" throughput: 0.5 - latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 4.0 # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] - name: vmovapd operands: - class: "memory" @@ -178,8 +225,8 @@ instruction_forms: - class: "register" name: "xmm" throughput: 0.5 - latency: ~ # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [0.0, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 0.0] + latency: ~ # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.0, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 0.0] - name: vmovapd operands: - class: "register" @@ -190,5 +237,31 @@ instruction_forms: index: "gpr" scale: 1 throughput: 1.0 - latency: ~ # 0 0DV 1 2 3 4 5 6 7 - port_occupation: [0.0, 0.0, 0.0, 0.5, 0.5, 1.0, 0.0, 0.0, 0.0] + latency: ~ # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.0, 0.0, 0.0, 0.5, 0.5, 1.0, 0.0, 0.0, 0.0] + - name: vmovapd + operands: + - class: "memory" + base: "gpr" + offset: ~ + index: "gpr" + scale: 1 + - class: "register" + name: "ymm" + throughput: 0.5 + latency: ~ # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.0, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 0.0] + - name: vmovapd + operands: + - class: "register" + name: "ymm" + - class: "memory" + base: "gpr" + offset: ~ + index: "gpr" + scale: 1 + throughput: 1.0 + latency: ~ # 0 0DV 1 2 3 4 5 6 7 + port_pressure: [0.0, 0.0, 0.0, 0.5, 0.5, 1.0, 0.0, 0.0, 0.0] + + diff --git a/osaca/data/isa/AArch64.yml b/osaca/data/isa/AArch64.yml index a67171a..66e60df 100644 --- a/osaca/data/isa/AArch64.yml +++ b/osaca/data/isa/AArch64.yml @@ -57,6 +57,25 @@ instruction_forms: pre-indexed: false post-indexed: false source: true + destination: false + - name: "ldp" + operands: + - class: "register" + prefix: "d" + source: false + destination: true + - class: "register" + prefix: "d" + source: false + destination: true + - class: "memory" + base: "x" + offset: ~ + index: ~ + scale: 1 + pre-indexed: false + post-indexed: true + source: true destination: false - name: "ldp" operands: @@ -77,6 +96,44 @@ instruction_forms: post-indexed: false source: true destination: false + - name: "ldp" + operands: + - class: "register" + prefix: "q" + source: false + destination: true + - class: "register" + prefix: "q" + source: false + destination: true + - class: "memory" + base: "x" + offset: ~ + index: ~ + scale: 1 + pre-indexed: false + post-indexed: true + source: true + destination: false + - name: "stp" + operands: + - class: "register" + prefix: "d" + source: true + destination: false + - class: "register" + prefix: "d" + source: true + destination: false + - class: "memory" + base: "x" + offset: ~ + index: ~ + scale: 1 + pre-indexed: false + post-indexed: false + source: false + destination: true - name: "stp" operands: - class: "register" @@ -96,6 +153,25 @@ instruction_forms: post-indexed: false source: false destination: true + - name: "stp" + operands: + - class: "register" + prefix: "q" + source: true + destination: false + - class: "register" + prefix: "q" + source: true + destination: false + - class: "memory" + base: "x" + offset: ~ + index: ~ + scale: 1 + pre-indexed: false + post-indexed: false + source: false + destination: true - name: "stp" operands: - class: "register" diff --git a/osaca/data/isa/x86.yml b/osaca/data/isa/x86.yml index d2f7acf..57f9199 100644 --- a/osaca/data/isa/x86.yml +++ b/osaca/data/isa/x86.yml @@ -1,5 +1,5 @@ osaca_version: 0.3.0 -isa: "x86 AT&T" +isa: "x86" # Contains all operand-irregular instruction forms OSACA supports for x86. # Operand-regular for a x86 AT&T instruction form with N operands in the shape of # mnemonic op1 ... opN @@ -25,6 +25,21 @@ instruction_forms: name: "xmm" source: true destination: false + - name: cmpl + operands: + - class: "register" + name: "gpr" + source: true + destination: false + - class: "register" + name: "gpr" + source: true + destination: false + - name: ja + operands: + - class: "identifier" + source: true + destination: false - name: mulsd operands: - class: "register" @@ -55,3 +70,21 @@ instruction_forms: name: "xmm" source: true destination: false + - name: vfmadd132pd + operands: + - class: "memory" + base: "gpr" + offset: ~ + index: "gpr" + scale: 1 + source: true + destination: false + - class: "register" + name: "ymm" + source: true + destination: false + - class: "register" + name: "ymm" + source: true + destination: true + diff --git a/osaca/data/vulcan.yml b/osaca/data/vulcan.yml index 3643f5d..17f7f9d 100644 --- a/osaca/data/vulcan.yml +++ b/osaca/data/vulcan.yml @@ -33,8 +33,8 @@ instruction_forms: - class: "register" prefix: "x" throughput: 0.33333333 - latency: 1.0 # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.33333333, 0.0, 0.33333333, 0.0, 0.33333333, 0.0, 0.0, 0.0] + latency: 1.0 # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.33333333, 0.0, 0.33333333, 0.0, 0.33333333, 0.0, 0.0, 0.0] - name: "add" operands: - class: "register" @@ -44,8 +44,20 @@ instruction_forms: - class: "immediate" imd: "int" throughput: 0.33333333 - latency: 1.0 # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.33333333, 0.0, 0.33333333, 0.0, 0.33333333, 0.0, 0.0, 0.0] + latency: 1.0 # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.33333333, 0.0, 0.33333333, 0.0, 0.33333333, 0.0, 0.0, 0.0] + - name: "adds" + operands: + - class: "register" + prefix: "x" + - class: "register" + prefix: "x" + - class: "immediate" + imd: "int" + throughput: 0.33333333 + latency: 1.0 # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.33333333, 0.0, 0.33333333, 0.0, 0.33333333, 0.0, 0.0, 0.0] + - name: "fadd" operands: - class: "register" @@ -58,8 +70,8 @@ instruction_forms: prefix: "v" shape: "s" throughput: 0.5 - latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] - name: "fadd" operands: - class: "register" @@ -72,8 +84,8 @@ instruction_forms: prefix: "v" shape: "d" throughput: 0.5 - latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] - name: "fdiv" operands: - class: "register" @@ -86,8 +98,8 @@ instruction_forms: prefix: "v" shape: "s" throughput: 8.5 - latency: 16.0 # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [1.0, 8.5, 1.0, 8.5, 0.0, 0.0, 0.0, 0.0] + latency: 16.0 # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [1.0, 8.5, 1.0, 8.5, 0.0, 0.0, 0.0, 0.0] - name: "fdiv" operands: - class: "register" @@ -100,8 +112,8 @@ instruction_forms: prefix: "v" shape: "d" throughput: 12.0 - latency: 23.0 # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [1.0, 12.5, 1.0, 12.0, 0.0, 0.0, 0.0, 0.0] + latency: 23.0 # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [1.0, 12.5, 1.0, 12.0, 0.0, 0.0, 0.0, 0.0] - name: "fmla" operands: - class: "register" @@ -114,8 +126,8 @@ instruction_forms: prefix: "v" shape: "s" throughput: 0.5 - latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] - name: "fmla" operands: - class: "register" @@ -128,8 +140,8 @@ instruction_forms: prefix: "v" shape: "d" throughput: 0.5 - latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] - name: "fmul" operands: - class: "register" @@ -142,8 +154,8 @@ instruction_forms: prefix: "v" shape: "s" throughput: 0.5 - latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] - name: "fmul" operands: - class: "register" @@ -156,8 +168,8 @@ instruction_forms: prefix: "v" shape: "d" throughput: 0.5 - latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] - name: "fsub" operands: - class: "register" @@ -170,8 +182,8 @@ instruction_forms: prefix: "v" shape: "s" throughput: 0.5 - latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] - name: "fsub" operands: - class: "register" @@ -184,8 +196,8 @@ instruction_forms: prefix: "v" shape: "d" throughput: 0.5 - latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] + latency: 6.0 # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0] - name: "ldp" operands: - class: "register" @@ -200,8 +212,24 @@ instruction_forms: pre-indexed: false post-indexed: false throughput: 1.0 - latency: ~ # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0] + latency: ~ # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0] + - name: "ldp" + operands: + - class: "register" + prefix: "d" + - class: "register" + prefix: "d" + - class: "memory" + base: "x" + offset: "imd" + index: ~ + scale: 1 + pre-indexed: false + post-indexed: true + throughput: 1.0 + latency: ~ # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0] - name: "ldp" operands: - class: "register" @@ -216,8 +244,40 @@ instruction_forms: pre-indexed: false post-indexed: false throughput: 1.0 - latency: ~ # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0] + latency: ~ # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0] + - name: "ldp" + operands: + - class: "register" + prefix: "q" + - class: "register" + prefix: "q" + - class: "memory" + base: "x" + offset: ~ + index: ~ + scale: 1 + pre-indexed: false + post-indexed: true + throughput: 1.0 + latency: ~ # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0] + - name: "stp" + operands: + - class: "register" + prefix: "d" + - class: "register" + prefix: "d" + - class: "memory" + base: "x" + offset: ~ + index: ~ + scale: 1 + pre-indexed: false + post-indexed: false + throughput: 2.0 + latency: ~ # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 0.0] - name: "stp" operands: - class: "register" @@ -232,8 +292,24 @@ instruction_forms: pre-indexed: false post-indexed: false throughput: 2.0 - latency: ~ # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 0.0] + latency: ~ # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 0.0] + - name: "stp" + operands: + - class: "register" + prefix: "q" + - class: "register" + prefix: "q" + - class: "memory" + base: "x" + offset: ~ + index: ~ + scale: 1 + pre-indexed: false + post-indexed: false + throughput: 2.0 + latency: ~ # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 0.0] - name: "stp" operands: - class: "register" @@ -248,5 +324,5 @@ instruction_forms: pre-indexed: false post-indexed: false throughput: 2.0 - latency: ~ # 0 0DV 1 1DV 2 3 4 5 - port_occupation: [0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 0.0] + latency: ~ # 0 0DV 1 1DV 2 3 4 5 + port_pressure: [0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 0.0] diff --git a/osaca/parser/parser_AArch64v81.py b/osaca/parser/parser_AArch64v81.py index ec69491..f47ff8c 100755 --- a/osaca/parser/parser_AArch64v81.py +++ b/osaca/parser/parser_AArch64v81.py @@ -182,6 +182,7 @@ class ParserAArch64v81(BaseParser): self.DIRECTIVE_ID: None, self.COMMENT_ID: None, self.LABEL_ID: None, + 'line': line.strip(), 'line_number': line_number, } ) diff --git a/osaca/parser/parser_x86att.py b/osaca/parser/parser_x86att.py index 3a0d533..0c3b880 100755 --- a/osaca/parser/parser_x86att.py +++ b/osaca/parser/parser_x86att.py @@ -112,6 +112,7 @@ class ParserX86ATT(BaseParser): self.DIRECTIVE_ID: None, self.COMMENT_ID: None, self.LABEL_ID: None, + 'line': line.strip(), 'line_number': line_number, } ) diff --git a/osaca/semantics/hw_model.py b/osaca/semantics/hw_model.py index c7fcf25..bd27ccb 100755 --- a/osaca/semantics/hw_model.py +++ b/osaca/semantics/hw_model.py @@ -1,10 +1,11 @@ #!/usr/bin/env python3 import os -from osaca.parser import ParserX86ATT from ruamel import yaml +from osaca.parser import ParserX86ATT + class MachineModel(object): def __init__(self, arch=None, path_to_yaml=None): @@ -58,6 +59,9 @@ class MachineModel(object): ) except StopIteration: return None + except TypeError: + print('\nname: {}\noperands: {}'.format(name, operands)) + raise TypeError def get_ISA(self): return self._data['isa'] @@ -100,6 +104,8 @@ class MachineModel(object): return i_operand['class'] == 'immediate' and i_operand['imd'] == 'float' if 'double' in operand: return i_operand['class'] == 'immediate' and i_operand['imd'] == 'double' + if 'identifier' in operand: + return i_operand['class'] == 'identifier' # prefetch option if 'prfop' in operand: return i_operand['class'] == 'prfop' @@ -120,6 +126,9 @@ class MachineModel(object): # immediate if 'value' in operand: return i_operand['class'] == 'immediate' and i_operand['imd'] == 'int' + # identifier (e.g., labels) + if 'identifier' in operand: + return i_operand['class'] == 'identifier' def _is_AArch64_reg_type(self, i_reg, reg): if reg['prefix'] != i_reg['prefix']: @@ -190,7 +199,10 @@ class MachineModel(object): or ( mem['offset'] is not None and 'value' in mem['offset'] - and i_mem['offset'] == 'imd' + and ( + i_mem['offset'] == 'imd' + or (i_mem['offset'] is None and mem['offset']['value'] == '0') + ) ) ) # check index diff --git a/osaca/semantics/kernel_dg.py b/osaca/semantics/kernel_dg.py index 13006cd..32102cf 100755 --- a/osaca/semantics/kernel_dg.py +++ b/osaca/semantics/kernel_dg.py @@ -2,14 +2,15 @@ import networkx as nx +from .hw_model import MachineModel + class KernelDG(nx.DiGraph): - def __init__(self, parsed_kernel, parser, hw_model): + def __init__(self, parsed_kernel, parser, hw_model: MachineModel): self.kernel = parsed_kernel self.parser = parser self.model = hw_model - - # self.dag = self.create_DG() + self.dg = self.create_DG() def check_for_loop(self, kernel): raise NotImplementedError @@ -17,26 +18,32 @@ class KernelDG(nx.DiGraph): def create_DG(self): # 1. go through kernel instruction forms (as vertices) # 2. find edges (to dependend further instruction) - # 3. get LT/TP value and set as edge weight - dag = nx.DiGraph() - for i, instruction in enumerate(self.kernel): - throughput = self.model.get_throughput(instruction) - latency = self.model.get_latency(instruction) - for dep in self.find_depending(instruction, self.kernel[i + 1:]): - dag.add_edge( - instruction.line_number, - dep.line_number, - latency=latency, - thorughput=throughput, + # 3. get LT value and set as edge weight + # 4. add instr forms as node attribute + dg = nx.DiGraph() + for i, instruction_form in enumerate(self.kernel): + for dep in self.find_depending(instruction_form, self.kernel[i + 1:]): + dg.add_edge( + instruction_form['line_number'], + dep['line_number'], + latency=instruction_form['latency'], ) + dg.nodes[instruction_form['line_number']]['instruction_form'] = instruction_form + dg.nodes[dep['line_number']]['instruction_form'] = dep + return dg def find_depending(self, instruction_form, kernel): - for dst in instruction_form.operands.destination: + if instruction_form.operands is None: + return + for dst in instruction_form.operands.destination + instruction_form.operands.src_dst: if 'register' in dst: # Check for read of register until overwrite for instr_form in kernel: if self.is_read(dst.register, instr_form): yield instr_form + if self.is_written(dst.register, instr_form): + # operand in src_dst list + break elif self.is_written(dst.register, instr_form): break elif 'memory' in dst: @@ -46,12 +53,26 @@ class KernelDG(nx.DiGraph): for instr_form in kernel: if self.is_read(dst.memory.base, instr_form): yield instr_form + if self.is_written(dst.memory.base, instr_form): + # operand in src_dst list + break elif self.is_written(dst.memory.base, instr_form): break + def get_dependent_instruction_forms(self, instr_form=None, line_number=None): + """ + Returns iterator + """ + if not instr_form and not line_number: + raise ValueError('Either instruction form or line_number required.') + line_number = line_number if line_number else instr_form['line_number'] + if self.dg.has_node(line_number): + return self.dg.successors(line_number) + return iter([]) + def is_read(self, register, instruction_form): is_read = False - for src in instruction_form.operands.source: + for src in instruction_form.operands.source + instruction_form.operands.src_dst: if 'register' in src: is_read = self.parser.is_reg_dependend_of(register, src.register) or is_read if 'memory' in src: @@ -62,7 +83,7 @@ class KernelDG(nx.DiGraph): self.parser.is_reg_dependend_of(register, src.memory.index) or is_read ) # Check also if read in destination memory address - for dst in instruction_form.operands.destination: + for dst in instruction_form.operands.destination + instruction_form.operands.src_dst: if 'memory' in dst: if dst.memory.base is not None: is_read = self.parser.is_reg_dependend_of(register, dst.memory.base) or is_read @@ -74,7 +95,7 @@ class KernelDG(nx.DiGraph): def is_written(self, register, instruction_form): is_written = False - for dst in instruction_form.operands.destination: + for dst in instruction_form.operands.destination + instruction_form.operands.src_dst: if 'register' in dst: is_written = self.parser.is_reg_dependend_of(register, dst.register) or is_written if 'memory' in dst: @@ -83,7 +104,7 @@ class KernelDG(nx.DiGraph): self.parser.is_reg_dependend_of(register, dst.memory.base) or is_written ) # Check also for possible pre- or post-indexing in memory addresses - for src in instruction_form.operands.source: + for src in instruction_form.operands.source + instruction_form.operands.src_dst: if 'memory' in src: if 'pre_indexed' in src.memory or 'post_indexed' in src.memory: is_written = ( diff --git a/osaca/semantics/semanticsAppender.py b/osaca/semantics/semanticsAppender.py index d573218..204a047 100755 --- a/osaca/semantics/semanticsAppender.py +++ b/osaca/semantics/semanticsAppender.py @@ -1,12 +1,23 @@ #!/usr/bin/env python3 import os +import warnings from osaca.parser import AttrDict + from .hw_model import MachineModel class SemanticsAppender(object): + class INSTR_FLAGS: + """ + Flags used for unknown or special instructions + """ + TP_UNKWN = 'tp_unkown' + LT_UNKWN = 'lt_unkown' + NOT_BOUND = 'not_bound' + HIDDEN_LD = 'hidden_load' + def __init__(self, machine_model: MachineModel, path_to_yaml=None): self.machine_model = machine_model self._isa = machine_model.get_ISA() @@ -22,6 +33,54 @@ class SemanticsAppender(object): assert os.path.exists(name) return name + # get parser result and assign throughput and latency value to instruction form + # mark instruction form with semantic flags + def assign_tp_lt(self, instruction_form): + flags = [] + port_number = len(self.machine_model['ports']) + instruction_data = self.machine_model.get_instruction( + instruction_form['instruction'], instruction_form['operands'] + ) + if instruction_data: + # instruction form in DB + throughput = instruction_data['throughput'] + port_pressure = instruction_data['port_pressure'] + try: + assert isinstance(port_pressure, list) + assert len(port_pressure) == port_number + instruction_form['port_pressure'] = port_pressure + except AssertionError: + warnings.warn( + 'Port pressure could not be imported correctly from database. ' + + 'Please check entry for:\n {}'.format(instruction_form) + ) + instruction_form['port_pressure'] = [0.0 for i in range(port_number)] + flags.append(self.INSTR_FLAGS.TP_UNKWN) + if throughput is None: + # assume 0 cy and mark as unknown + throughput = 0.0 + flags.append(self.INSTR_FLAGS.TP_UNKWN) + latency = instruction_data['latency'] + if latency is None: + # assume 0 cy and mark as unknown + latency = 0.0 + flags.append(self.INSTR_FLAGS.LT_UNKWN) + else: + # instruction could not be found in DB + # --> mark as unknown and assume 0 cy for latency/throughput + throughput = 0.0 + latency = 0.0 + instruction_form['port_pressure'] = [0.0 for i in range(port_number)] + flags += [self.INSTR_FLAGS.TP_UNKWN, self.INSTR_FLAGS.LT_UNKWN] + # flatten flag list + flags = list(set(flags)) + if 'flags' not in instruction_form: + instruction_form['flags'] = flags + else: + instruction_form['flags'] += flags + instruction_form['throughput'] = throughput + instruction_form['latency'] = latency + # get parser result and assign operands to # - source # - destination diff --git a/tests/test_parser_AArch64v81.py b/tests/test_parser_AArch64v81.py index c98d926..5927a0a 100755 --- a/tests/test_parser_AArch64v81.py +++ b/tests/test_parser_AArch64v81.py @@ -146,6 +146,7 @@ class TestParserAArch64v81(unittest.TestCase): 'directive': None, 'comment': '-- Begin main', 'label': None, + 'line': '// -- Begin main', 'line_number': 1, } @@ -155,6 +156,7 @@ class TestParserAArch64v81(unittest.TestCase): 'directive': None, 'comment': '=>This Inner Loop Header: Depth=1', 'label': '.LBB0_1', + 'line': '.LBB0_1: // =>This Inner Loop Header: Depth=1', 'line_number': 2, } instruction_form_3 = { @@ -163,6 +165,7 @@ class TestParserAArch64v81(unittest.TestCase): 'directive': {'name': 'cfi_def_cfa', 'parameters': ['w29', '-16']}, 'comment': None, 'label': None, + 'line': '.cfi_def_cfa w29, -16', 'line_number': 3, } instruction_form_4 = { @@ -186,6 +189,7 @@ class TestParserAArch64v81(unittest.TestCase): 'directive': None, 'comment': '= <<2', 'label': None, + 'line': 'ldr s0, [x11, w10, sxtw #2]\t\t// = <<2', 'line_number': 4, } instruction_form_5 = { @@ -204,6 +208,7 @@ class TestParserAArch64v81(unittest.TestCase): 'directive': None, 'comment': 'HPL', 'label': None, + 'line': 'prfm pldl1keep, [x26, #2048] //HPL', 'line_number': 5, } instruction_form_6 = { @@ -224,6 +229,7 @@ class TestParserAArch64v81(unittest.TestCase): 'directive': None, 'comment': None, 'label': None, + 'line': 'stp x29, x30, [sp, #-16]!', 'line_number': 6, } instruction_form_7 = { @@ -244,6 +250,7 @@ class TestParserAArch64v81(unittest.TestCase): 'directive': None, 'comment': None, 'label': None, + 'line': 'ldp q2, q3, [x11], #64', 'line_number': 7, } parsed_1 = self.parser.parse_line(line_comment, 1) diff --git a/tests/test_parser_x86att.py b/tests/test_parser_x86att.py index cee739f..9ec2b67 100755 --- a/tests/test_parser_x86att.py +++ b/tests/test_parser_x86att.py @@ -139,6 +139,7 @@ class TestParserX86ATT(unittest.TestCase): 'directive': None, 'comment': '-- Begin main', 'label': None, + 'line': '# -- Begin main', 'line_number': 1, } instruction_form_2 = { @@ -147,6 +148,7 @@ class TestParserX86ATT(unittest.TestCase): 'directive': None, 'comment': 'Preds ..B1.6', 'label': '..B1.7', + 'line': '..B1.7: # Preds ..B1.6', 'line_number': 2, } instruction_form_3 = { @@ -155,6 +157,7 @@ class TestParserX86ATT(unittest.TestCase): 'directive': {'name': 'quad', 'parameters': ['.2.3_2__kmpc_loc_pack.2']}, 'comment': 'qed', 'label': None, + 'line': '.quad .2.3_2__kmpc_loc_pack.2 #qed', 'line_number': 3, } instruction_form_4 = { @@ -175,6 +178,7 @@ class TestParserX86ATT(unittest.TestCase): 'directive': None, 'comment': '12.9', 'label': None, + 'line': 'lea 2(%rax,%rax), %ecx #12.9', 'line_number': 4, } diff --git a/tests/test_semantics.py b/tests/test_semantics.py index 121f030..efabf25 100755 --- a/tests/test_semantics.py +++ b/tests/test_semantics.py @@ -3,6 +3,7 @@ Unit tests for Semantic Analysis """ +import networkx as nx import os import unittest @@ -44,8 +45,10 @@ class TestSemanticTools(unittest.TestCase): ) for i in range(len(self.kernel_x86)): self.semantics_csl.assign_src_dst(self.kernel_x86[i]) + self.semantics_csl.assign_tp_lt(self.kernel_x86[i]) for i in range(len(self.kernel_AArch64)): self.semantics_tx2.assign_src_dst(self.kernel_AArch64[i]) + self.semantics_tx2.assign_tp_lt(self.kernel_AArch64[i]) ########### # Tests @@ -67,6 +70,67 @@ class TestSemanticTools(unittest.TestCase): self.assertTrue('destination' in instruction_form['operands']) self.assertTrue('src_dst' in instruction_form['operands']) + def test_tp_lt_assignment_x86(self): + port_num = len(self.machine_model_csl['ports']) + for instruction_form in self.kernel_x86: + with self.subTest(instruction_form=instruction_form): + self.assertTrue('throughput' in instruction_form) + self.assertTrue('latency' in instruction_form) + self.assertIsInstance(instruction_form['port_pressure'], list) + self.assertEqual(len(instruction_form['port_pressure']), port_num) + + def test_tp_lt_assignment_AArch64(self): + port_num = len(self.machine_model_tx2['ports']) + for instruction_form in self.kernel_AArch64: + with self.subTest(instruction_form=instruction_form): + self.assertTrue('throughput' in instruction_form) + self.assertTrue('latency' in instruction_form) + self.assertIsInstance(instruction_form['port_pressure'], list) + self.assertEqual(len(instruction_form['port_pressure']), port_num) + + def test_kernelDG_x86(self): + # + # 3 + # \___>5__>6 + # / + # 2 + # 4_______>8 + # + dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csl) + self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg)) + self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=2))), 1) + self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=2)), 5) + self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=3))), 1) + self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=3)), 5) + self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=4))), 1) + self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=4)), 8) + self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=5))), 1) + self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=5)), 6) + self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=6))), 0) + self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=7))), 0) + + def test_kernelDG_AArch64(self): + dg = KernelDG(self.kernel_AArch64, self.parser_AArch64, self.machine_model_tx2) + self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg)) + self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=2)), [6, 7]) + self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=3)), [8, 9]) + self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=4)), [6, 7]) + self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=5)), [8, 9]) + self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=6)), 12) + self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=7)), 13) + self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=8)), 15) + self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=9)), 16) + self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=10)), [12, 13]) + self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=11)), [15, 16]) + self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=12)), 14) + self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=13)), 14) + self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=14))), 0) + self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=15)), 17) + self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=16)), 17) + self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=17))), 0) + self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=18))), 0) + self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=19))), 0) + def test_is_read_is_written_x86(self): # independent form HW model dag = KernelDG(self.kernel_x86, self.parser_x86, None)