Class: Udb::Z3Solver

Inherits:
Object
  • Object
show all
Extended by:
Forwardable, T::Sig
Defined in:
lib/udb/z3.rb

Overview

Main Z3 solver wrapper for RISC-V architecture validation

This class provides a high-level interface to Z3 for validating RISC-V configurations. It manages:

  • Parameter terms with JSON schema constraints

  • Extension version terms

  • Extension requirement terms

  • Stack-based solver contexts (push/pop)

The solver maintains caches of terms organized in stacks, allowing incremental solving with backtracking via push/pop operations.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeZ3Solver

Returns a new instance of Z3Solver.



1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
# File 'lib/udb/z3.rb', line 1118

def initialize
  if Udb.global_options.parallel_z3
    Z3Solver.configure_parallelization(true)
  else
    Z3Solver.configure_parallelization(false)
  end

  @solver = T.let(Z3::Solver.new, Z3::Solver)

  # Stacks for incremental solving with push/pop
  @ext_vers = T.let([{}], T::Array[T::Hash[String, Z3ExtensionVersion]])
  @ext_reqs = T.let([{}], T::Array[T::Hash[String, Z3ExtensionRequirement]])
  @param_terms = T.let([{}], T::Array[T::Hash[String, Z3ParameterTerm]])

  # Extension version component terms (shared across versions of same extension)
  @ext_majors = T.let([{}], T::Array[T::Hash[String, Z3::IntExpr]])
  @ext_minors = T.let([{}], T::Array[T::Hash[String, Z3::IntExpr]])
  @ext_patches = T.let([{}], T::Array[T::Hash[String, Z3::IntExpr]])
  @ext_pres = T.let([{}], T::Array[T::Hash[String, Z3::BoolExpr]])

  @xlen = T.let(nil, T.nilable(Z3::IntExpr))
end

Instance Attribute Details

#solverObject (readonly)

Returns the value of attribute solver.



1083
1084
1085
# File 'lib/udb/z3.rb', line 1083

def solver
  @solver
end

Class Method Details

.configure_parallelization(desired) ⇒ Object



1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
# File 'lib/udb/z3.rb', line 1101

def configure_parallelization(desired)
  previous = parallel_enabled

  if !previous.nil? && previous != desired
    if desired
      Udb.logger.warn "Z3 parallelization was previously disabled, but is now being enabled"
    else
      Udb.logger.warn "Z3 parallelization was previously enabled, but is now being disabled"
    end
  end

  Z3.set_param("parallel.enable", desired ? "true" : "false")
  self.parallel_enabled = desired
end

.parallel_enabledObject



1091
1092
1093
# File 'lib/udb/z3.rb', line 1091

def parallel_enabled
  @parallel_enabled
end

.parallel_enabled=(value) ⇒ Object



1096
1097
1098
# File 'lib/udb/z3.rb', line 1096

def parallel_enabled=(value)
  @parallel_enabled = value
end

Instance Method Details

#ext_major(name) ⇒ Object



1228
1229
1230
1231
1232
1233
1234
1235
# File 'lib/udb/z3.rb', line 1228

def ext_major(name)
  @ext_majors.reverse_each do |h|
    if h.key?(name)
      return h.fetch(name)
    end
  end
  T.must(@ext_majors.last)[name] ||= Z3.Int("#{name}_major")
end

#ext_minor(name) ⇒ Object



1238
1239
1240
1241
1242
1243
1244
1245
# File 'lib/udb/z3.rb', line 1238

def ext_minor(name)
  @ext_minors.reverse_each do |h|
    if h.key?(name)
      return h.fetch(name)
    end
  end
  T.must(@ext_minors.last)[name] ||= Z3.Int("#{name}_minor")
end

#ext_patch(name) ⇒ Object



1248
1249
1250
1251
1252
1253
1254
1255
# File 'lib/udb/z3.rb', line 1248

def ext_patch(name)
  @ext_patches.reverse_each do |h|
    if h.key?(name)
      return h.fetch(name)
    end
  end
  T.must(@ext_patches.last)[name] ||= Z3.Int("#{name}_patch")
end

#ext_pre(name) ⇒ Object



1258
1259
1260
1261
1262
1263
1264
1265
# File 'lib/udb/z3.rb', line 1258

def ext_pre(name)
  @ext_pres.reverse_each do |h|
    if h.key?(name)
      return h.fetch(name)
    end
  end
  T.must(@ext_pres.last)[name] ||= Z3.Bool("#{name}_pre")
end

#ext_req(name, req, cfg_arch) ⇒ Object



1214
1215
1216
1217
1218
1219
1220
1221
1222
# File 'lib/udb/z3.rb', line 1214

def ext_req(name, req, cfg_arch)
  key = [name, req].hash
  @ext_reqs.reverse_each do |h|
    if h.key?(key)
      return h.fetch(key)
    end
  end
  T.must(@ext_reqs.last)[key] ||= Z3ExtensionRequirement.new(name, req, self, cfg_arch)
end

#ext_ver(name, version, cfg_arch) ⇒ Object



1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
# File 'lib/udb/z3.rb', line 1195

def ext_ver(name, version, cfg_arch)
  version_spec = version.is_a?(VersionSpec) ? version : VersionSpec.new(version)
  key = [name, version_spec].hash
  # Search from most recent context backwards
  @ext_vers.reverse_each do |h|
    if h.key?(key)
      return h.fetch(key)
    end
  end
  # Create new term in current context
  ev = Z3ExtensionVersion.new(name, version_spec, self, cfg_arch)
  T.must(@ext_vers.last)[key] = ev
  ev
end

#param(name, schema_hsh) ⇒ Object



1273
1274
1275
1276
1277
1278
1279
1280
# File 'lib/udb/z3.rb', line 1273

def param(name, schema_hsh)
  @param_terms.reverse_each do |h|
    if h.key?(name)
      return h.fetch(name)
    end
  end
  T.must(@param_terms.last)[name] = Z3ParameterTerm.new(name, self, schema_hsh)
end

#popObject



1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
# File 'lib/udb/z3.rb', line 1146

def pop
  if @ext_vers.size == 1
    Udb.logger.error "Popping solver at base level"
    raise
  end
  @ext_vers.pop
  @ext_reqs.pop
  @param_terms.pop
  @ext_majors.pop
  @ext_minors.pop
  @ext_patches.pop
  @ext_pres.pop
  @solver.pop
end

#pushObject



1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
# File 'lib/udb/z3.rb', line 1166

def push
  @ext_vers.push({})
  @ext_reqs.push({})
  @param_terms.push({})
  @ext_majors.push({})
  @ext_minors.push({})
  @ext_patches.push({})
  @ext_pres.push({})
  @solver.push
end

#xlenObject



1182
1183
1184
1185
1186
1187
1188
# File 'lib/udb/z3.rb', line 1182

def xlen
  unless @xlen
    @xlen = Z3.Int("xlen")
    @solver.assert_as((@xlen == 32) | (@xlen == 64), "_pxlen")
  end
  @xlen
end