Skip to content

Commit

Permalink
[nix] refactor test case
Browse files Browse the repository at this point in the history
* cases is now under the ip scope
* replace isFp detect with features abstract layer, so that tests can
  have more extensible way to declare their required emulator type.

Signed-off-by: Avimitin <[email protected]>
  • Loading branch information
Avimitin committed Jul 31, 2024
1 parent 21f7014 commit af30c8f
Show file tree
Hide file tree
Showing 13 changed files with 138 additions and 65 deletions.
36 changes: 25 additions & 11 deletions nix/t1/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
, stdenv
, useMoldLinker
, newScope
, runCommand

, pkgsX86
}:
Expand Down Expand Up @@ -51,16 +52,6 @@ lib.makeScope newScope
elaborateConfigJson = configPath;
elaborateConfig = builtins.fromJSON (lib.readFile configPath);

cases = innerSelf.callPackage ../../tests {
inherit (ip) verilator-emu verilator-emu-trace vcs-emu vcs-emu-trace;
};

# for the convenience to use x86 cases on non-x86 machines, avoiding the extra build time
cases-x86 =
if system == "x86-64-linux"
then self.cases
else pkgsX86.t1."${configName}".cases;

ip = rec {
recurseForDerivations = true;

Expand All @@ -80,8 +71,31 @@ lib.makeScope newScope
"--lowering-options=verifLabels,omitVersionComment,emittedLineLength=240,locationInfoStyle=none"
];
};
omreader = self.omreader-unwrapped.mkWrapper { inherit mlirbc; };

om = innerSelf.callPackage ./om.nix { inherit mlirbc; };
omreader = self.omreader-unwrapped.mkWrapper { inherit mlirbc; };

emu-om = innerSelf.callPackage ./om.nix { inherit emu-mlirbc; };
emu-omreader = self.omreader-unwrapped.mkWrapper { inherit emu-mlirbc; };
omGet = args: lib.fileContents (runCommand "get-${args}" { } ''
${emu-omreader}/bin/omreader ${args} > $out
'');
rtlDesignMetadata = {
march = omGet "march";
extensions = builtins.fromJSON (omGet "extensionsJson");
vlen = omGet "vlen";
dlen = omGet "dlen";
};

cases = innerSelf.callPackage ../../tests {
inherit (ip) verilator-emu verilator-emu-trace vcs-emu vcs-emu-trace;
};

# for the convenience to use x86 cases on non-x86 machines, avoiding the extra build time
cases-x86 =
if system == "x86-64-linux"
then self.cases
else pkgsX86.t1."${configName}".cases;

emu-elaborate = innerSelf.callPackage ./elaborate.nix { target = "ipemu"; };
emu-mlirbc = innerSelf.callPackage ./mlirbc.nix { elaborate = emu-elaborate; };
Expand Down
4 changes: 3 additions & 1 deletion tests/asm/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
, makeBuilder
, findAndBuild
, t1main
, getTestRequiredFeatures
}:

let
Expand All @@ -13,6 +14,7 @@ let

src = sourcePath;

featuresRequired = getTestRequiredFeatures sourcePath;
isFp = lib.pathExists (lib.path.append sourcePath "isFp");

buildPhase = ''
Expand All @@ -29,5 +31,5 @@ let
meta.description = "test case '${caseName}', written in C assembly";
};
in
findAndBuild ./. build
findAndBuild ./. build

1 change: 1 addition & 0 deletions tests/asm/fpsmoke/features-required.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["float"]
Empty file removed tests/asm/fpsmoke/isFp
Empty file.
36 changes: 16 additions & 20 deletions tests/builder.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
{ stdenv
, lib
, jq
, elaborateConfig
, isFp
, vLen
, rtlDesignMetadata

, makeEmuResult
}:
Expand All @@ -28,22 +26,17 @@ let

CC = "${stdenv.targetPlatform.config}-cc";

NIX_CFLAGS_COMPILE =
let
march = (if isFp then "rv32gc_zve32f" else "rv32gc_zve32x")
+ "_zvl${toString (lib.min 1024 vLen)}b";
in
[
"-mabi=ilp32f"
"-march=${march}"
"-mno-relax"
"-static"
"-mcmodel=medany"
"-fvisibility=hidden"
"-fno-PIC"
"-g"
"-O3"
];
NIX_CFLAGS_COMPILE = [
"-mabi=ilp32f"
"-march=${rtlDesignMetadata.march}"
"-mno-relax"
"-static"
"-mcmodel=medany"
"-fvisibility=hidden"
"-fno-PIC"
"-g"
"-O3"
];

installPhase = ''
runHook preInstall
Expand All @@ -63,7 +56,10 @@ let

dontFixup = true;

passthru.emu-result = makeEmuResult caseDrv;
passthru = {
inherit rtlDesignMetadata;
emu-result = makeEmuResult caseDrv;
};

} // overrides);
in
Expand Down
38 changes: 24 additions & 14 deletions tests/codegen/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@
, linkerScript
, rvv-codegen
, makeBuilder
, xLen
, vLen
, isFp
# Instead of testing feature is supported on TOP level,
# codegen case are always generated with supported code.
, currentFeatures
}:

let
builder = makeBuilder { casePrefix = "codegen"; };
makeCaseName = lib.replaceStrings [ "." ] [ "_" ];
extraValueFromFeatures = pattern:
lib.last
(lib.splitString ":"
(lib.head
(lib.filter
(lib.hasPrefix pattern)
currentFeatures)));
vlen = extraValueFromFeatures "vlen";
xlen = extraValueFromFeatures "xlen";

build = { rawCaseName, isFp }:
build = { rawCaseName, passthru }:
builder rec {
caseName = makeCaseName rawCaseName;

Expand All @@ -22,14 +31,14 @@ let

dontUnpack = true;

inherit isFp;
inherit passthru;

buildPhase = ''
runHook preBuild
${rvv-codegen}/bin/single \
-VLEN "${toString vLen}" \
-XLEN "${toString xLen}" \
-VLEN "${vlen}" \
-XLEN "${xlen}" \
-repeat 16 \
-testfloat3level 2 \
-configfile ${rvv-codegen}/configs/${rawCaseName}.toml \
Expand All @@ -50,7 +59,7 @@ let
meta.description = "test case '${caseName}' generated by codegen";
};

buildTestsFromFile = file: { isFp ? false }:
buildTestsFromFile = file: passthru:
with lib;
let
rawCaseNames = lib.splitString "\n" (lib.fileContents file);
Expand All @@ -59,17 +68,18 @@ let
(map
(rawCaseName: nameValuePair
(makeCaseName rawCaseName)
(build { inherit rawCaseName isFp; })
(build { inherit rawCaseName passthru; })
)
rawCaseNames));

commonTests = buildTestsFromFile ./common.txt { };
fpTests = buildTestsFromFile ./fp.txt { isFp = true; };

fpTests = buildTestsFromFile ./fp.txt { featuresRequired = [ "float" ]; };
zvbbTests = buildTestsFromFile ./zvbb.txt { featuresRequired = [ "zvbb" ]; };
hasFeature = feat: lib.any (f: feat == f) currentFeatures;
in
lib.recurseIntoAttrs (
if isFp
then commonTests // fpTests
else commonTests
commonTests //
lib.optionalAttrs (hasFeature "float") fpTests //
lib.optionalAttrs (hasFeature "zvbb") zvbbTests
)

16 changes: 16 additions & 0 deletions tests/codegen/zvbb.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
vandn.vv
vandn.vx
vbrev.v
vbreav8.v
vclz.v
vcpop.v
vctz.v
vrev8.v
vrol.vv
vrol.vx
vror.vi
vror.vv
vror.vx
vwsll.vi
vwsll.vv
vwsll.vx
62 changes: 47 additions & 15 deletions tests/default.nix
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{ lib
, configName
, elaborateConfig
, rtlDesignMetadata
, newScope
, rv32-stdenv
, runCommand
Expand All @@ -11,23 +11,43 @@
}:

let
extension = lib.head elaborateConfig.parameter.extensions;
xLen = if lib.hasInfix "ve32" extension then 32 else 64;
isFp = lib.hasInfix "f" extension;
vLen = let vLen = elaborateConfig.parameter.vLen; in
assert builtins.bitAnd vLen (vLen - 1) == 0; # vLen should be power of 2
assert vLen >= 32;
vLen;
hasExt = cmp: lib.any (ext: cmp == (lib.toLower ext)) rtlDesignMetadata.extensions;

# Add an extra abstract layer between test case and RTL design, so that we can have clean and organized way
# for developer to specify their required features without the need to parse ISA string themselves.
currentFeatures = [
"vlen:${rtlDesignMetadata.vlen}"
"dlen:${rtlDesignMetadata.dlen}"
"xlen:${if (lib.hasPrefix "rv32" rtlDesignMetadata.march) then "32" else "64"}"
]
++ lib.optionals (hasExt "zve32f") [ "float" ]
++ lib.optionals (hasExt "zvbb") [ "zvbb" ];

# isSubSetOf m n: n is subset of m
isSubsetOf = m: n: lib.all (x: lib.elem x m) n;

scope = lib.recurseIntoAttrs (lib.makeScope newScope (casesSelf: {
recurseForDerivations = true;

inherit xLen vLen isFp verilator-emu verilator-emu-trace vcs-emu vcs-emu-trace;
inherit verilator-emu verilator-emu-trace vcs-emu vcs-emu-trace rtlDesignMetadata currentFeatures;

makeEmuResult = casesSelf.callPackage ./make-emu-result.nix { };

makeBuilder = casesSelf.callPackage ./builder.nix { };

# Read casePath/features-required.json to get extra feature information.
# Like the requirement of zve32f, or requirement for higher vlen.
# Empty list means no extra requirement for RTL design, then the baseline zve32x will be used.
#
# TODO: check user specified features are correct or not
getTestRequiredFeatures = sourcePath:
let
extraFeatures = lib.path.append sourcePath "features-required.json";
in
if lib.pathExists extraFeatures then
builtins.fromJSON (lib.fileContents extraFeatures)
else [ ];

findAndBuild = dir: build:
lib.recurseIntoAttrs (lib.pipe (builtins.readDir dir) [
# filter out all non-directory entrires and underscore-prefixed directories
Expand All @@ -43,7 +63,10 @@ let
inherit caseName sourcePath;
})
)
(lib.filterAttrs (caseName: caseDrv: assert caseDrv ? isFp; caseDrv.isFp -> isFp))
(lib.filterAttrs (caseName: caseDrv:
assert caseDrv ? featuresRequired;
# Test the case required extensions is supported by rtl design
isSubsetOf currentFeatures caseDrv.featuresRequired))
]);
t1main = ./t1_main.S;
linkerScript = ./t1.ld;
Expand All @@ -69,10 +92,12 @@ let
# This allows Nix to resolve the path only once, while still pulling all tests into the local Nix store.
_allEmuResult =
let
testPlan = builtins.fromJSON (lib.readFile ../.github/cases/${configName}/default.json);
testPlan = builtins.fromJSON
(lib.readFile ../.github/cases/${configName}/default.json);
# flattern the attr set to a list of test case derivations
# AttrSet (AttrSet Derivation) -> List Derivation
allCases = lib.filter (val: lib.isDerivation val && lib.hasAttr val.pname testPlan)
allCases = lib.filter
(val: lib.isDerivation val && lib.hasAttr val.pname testPlan)
(lib.concatLists (map lib.attrValues (lib.attrValues scopeStripped)));
script = ''
mkdir -p $out
Expand All @@ -86,7 +111,10 @@ let
'')
allCases);
in
runCommand "catch-${configName}-all-emu-result-for-ci" { } script;
runCommand
"catch-${configName}-all-emu-result-for-ci"
{ }
script;

_allVCSEmuResult =
let
Expand All @@ -109,7 +137,8 @@ let

all =
let
allCases = lib.filter lib.isDerivation
allCases = lib.filter
lib.isDerivation
(lib.concatLists (map lib.attrValues (lib.attrValues scopeStripped)));
script = ''
mkdir -p $out/configs
Expand All @@ -121,6 +150,9 @@ let
'')
allCases);
in
runCommand "build-all-testcases" { } script;
runCommand
"build-all-testcases"
{ }
script;
in
lib.recurseIntoAttrs (scopeStripped // { inherit all _allEmuResult _allVCSEmuResult; })
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["float"]
Empty file.
1 change: 1 addition & 0 deletions tests/intrinsic/softmax/features-required.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["float"]
Empty file removed tests/intrinsic/softmax/isFp
Empty file.
8 changes: 4 additions & 4 deletions tests/mlir/default.nix
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{ lib
, linkerScript
{ linkerScript
, buddy-mlir
, makeBuilder
, findAndBuild
, getTestRequiredFeatures
, t1main
}:

Expand All @@ -14,7 +14,7 @@ let

src = sourcePath;

isFp = lib.pathExists (lib.path.append sourcePath "isFp");
featuresRequired = getTestRequiredFeatures sourcePath;

nativeBuildInputs = [ buddy-mlir ];

Expand Down Expand Up @@ -60,4 +60,4 @@ let
meta.description = "testcase '${caseName}', written in MLIR";
};
in
findAndBuild ./. build
findAndBuild ./. build

0 comments on commit af30c8f

Please sign in to comment.